diff --git a/libethereum/BlockInfo.cpp b/libethereum/BlockInfo.cpp
index 78059c42f..ea28a2971 100644
--- a/libethereum/BlockInfo.cpp
+++ b/libethereum/BlockInfo.cpp
@@ -23,6 +23,7 @@
#include "Dagger.h"
#include "Exceptions.h"
#include "RLP.h"
+#include "State.h"
#include "BlockInfo.h"
using namespace std;
using namespace eth;
@@ -42,7 +43,20 @@ bytes BlockInfo::createGenesisBlock()
{
RLPStream block(3);
auto sha3EmptyList = sha3(RLPEmptyList);
- block.appendList(9) << h256() << sha3EmptyList << h160() << h256() << sha3EmptyList << c_genesisDifficulty << (uint)0 << string() << (uint)0;
+
+ h256 stateRoot;
+ {
+ BasicMap db;
+ TrieDB
state(&db);
+ state.init();
+ eth::commit(genesisState(), db, state);
+ stateRoot = state.root();
+ cout << "--- Genesis state_root=" << stateRoot << endl;
+ clog << state;
+ clog << db;
+ }
+
+ block.appendList(9) << h256() << sha3EmptyList << h160() << stateRoot << sha3EmptyList << c_genesisDifficulty << (uint)0 << string() << (uint)0;
block.appendRaw(RLPEmptyList);
block.appendRaw(RLPEmptyList);
return block.out();
diff --git a/libethereum/Common.cpp b/libethereum/Common.cpp
index 60b897253..989e34937 100644
--- a/libethereum/Common.cpp
+++ b/libethereum/Common.cpp
@@ -36,11 +36,26 @@
using namespace std;
using namespace eth;
-#if NDEBUG
-u256 const eth::c_genesisDifficulty = (u256)1 << 22;
-#else
-u256 const eth::c_genesisDifficulty = (u256)1 << 22;
-#endif
+// Logging
+bool eth::g_debugEnabled[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, true, true, true, true, true, true};
+char const* g_debugName[256] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ">>>", "<<<", "LOG", "---", "***", "!!!"};
+
+void eth::simpleDebugOut(std::string const& _s, unsigned char _id)
+{
+ // TODO: Time & thread.
+ if (g_debugEnabled[_id])
+ std::cout << (g_debugName[_id] ? g_debugName[_id] : " ") << " " << _s << std::endl << std::flush;
+}
+
+std::function eth::g_debugPost = simpleDebugOut;
+std::function eth::g_syslogPost =
+ [](char _c, string const& _s)
+ {
+ if (_c == 'C')
+ simpleDebugOut(_s, LogChannel);
+ else
+ simpleDebugOut("", LogChannel);
+ };
std::string eth::escaped(std::string const& _s, bool _all)
{
diff --git a/libethereum/Common.h b/libethereum/Common.h
index 65adbdf93..13511bd06 100644
--- a/libethereum/Common.h
+++ b/libethereum/Common.h
@@ -61,8 +61,6 @@ using u160s = std::vector;
using u256Set = std::set;
using u160Set = std::set;
-extern const u256 c_genesisDifficulty;
-
template inline void toBigEndian(T _val, Out& o_out);
template inline T fromBigEndian(In const& _bytes);
@@ -139,6 +137,84 @@ using HexMap = std::map;
static const u256 Invalid256 = ~(u256)0;
static const bytes NullBytes;
+
+/// Logging
+class NullOutputStream
+{
+public:
+ template NullOutputStream& operator<<(T const&) { return *this; }
+};
+
+extern bool g_debugEnabled[256];
+static const uint8_t WarnChannel = 255;
+static const uint8_t NoteChannel = 254;
+static const uint8_t DebugChannel = 253;
+static const uint8_t LogChannel = 252;
+static const uint8_t LeftChannel = 251;
+static const uint8_t RightChannel = 250;
+// Unused for now.
+/*template struct LogName { static const char constexpr* name = " "; };
+template <> struct LogName { static const char constexpr* name = "<<<"; };
+template <> struct LogName { static const char constexpr* name = ">>>"; };
+template <> struct LogName { static const char constexpr* name = "!!!"; };
+template <> struct LogName { static const char constexpr* name = "***"; };
+template <> struct LogName { static const char constexpr* name = "---"; };
+template <> struct LogName { static const char constexpr* name = "LOG"; };*/
+
+extern std::function g_debugPost;
+extern std::function g_syslogPost;
+
+void simpleDebugOut(std::string const&, unsigned char);
+
+template
+class DebugOutputStream
+{
+public:
+ DebugOutputStream(char const* _start = " ") { sstr << _start; }
+ ~DebugOutputStream() { g_debugPost(sstr.str(), _Id); }
+ template DebugOutputStream& operator<<(T const& _t) { if (_AutoSpacing && sstr.str().size() && sstr.str().back() != ' ') sstr << " "; sstr << _t; return *this; }
+ std::stringstream sstr;
+};
+
+template
+class SysLogOutputStream
+{
+public:
+ SysLogOutputStream() {}
+ ~SysLogOutputStream() { if (sstr.str().size()) g_syslogPost('C', sstr.str()); }
+ template SysLogOutputStream& operator<<(T const& _t) { if (_AutoSpacing && sstr.str().size() && sstr.str().back() != ' ') sstr << " "; sstr << _t; return *this; }
+ static void write(char _type, std::string const& _s) { g_syslogPost(_type, _s); }
+ template static void writePod(char _type, _T const& _s) { char const* begin = (char const*)&_s; char const* end = (char const*)&_s + sizeof(_T); g_syslogPost(_type, std::string(begin, end)); }
+ std::stringstream sstr;
+};
+
+// Dirties the global namespace, but oh so convenient...
+#define cnote eth::DebugOutputStream()
+#define cwarn eth::DebugOutputStream()
+
+#define nbug(X) if (true) {} else eth::NullOutputStream()
+#define nsbug(X) if (true) {} else eth::NullOutputStream()
+#define ndebug if (true) {} else eth::NullOutputStream()
+
+#if NDEBUG
+#define cbug(X) nbug(X)
+#define csbug(X) nsbug(X)
+#define cdebug ndebug
+#else
+#define cbug(X) eth::DebugOutputStream()
+#define csbug(X) eth::DebugOutputStream()
+#define cdebug eth::DebugOutputStream()
+#endif
+
+#define clog eth::SysLogOutputStream()
+
+
+
+
+
+
+
+
/// Converts arbitrary value to string representation using std::stringstream.
template
std::string toString(_T const& _t)
diff --git a/libethereum/State.cpp b/libethereum/State.cpp
index c6fa0ee33..1865a18c3 100644
--- a/libethereum/State.cpp
+++ b/libethereum/State.cpp
@@ -53,6 +53,24 @@ u256 const State::c_newContractFee = 60000;
u256 const State::c_txFee = 0;
u256 const State::c_blockReward = 1000000000;
+#if NDEBUG
+u256 const eth::c_genesisDifficulty = (u256)1 << 22;
+#else
+u256 const eth::c_genesisDifficulty = (u256)1 << 22;
+#endif
+
+std::map const& eth::genesisState()
+{
+ static std::map s_ret;
+ if (s_ret.empty())
+ {
+ // Initialise.
+ s_ret[Address(fromUserHex("812413ae7e515a3bcaf7b3444116527bce958c02"))] = AddressState(u256(1) << 200, 0);
+ s_ret[Address(fromUserHex("93658b04240e4bd4046fd2d6d417d20f146f4b43"))] = AddressState(u256(1) << 200, 0);
+ }
+ return s_ret;
+}
+
Overlay State::openDB(std::string _path, bool _killExisting)
{
if (_path.empty())
@@ -71,9 +89,16 @@ Overlay State::openDB(std::string _path, bool _killExisting)
State::State(Address _coinbaseAddress, Overlay const& _db): m_db(_db), m_state(&m_db), m_ourAddress(_coinbaseAddress)
{
secp256k1_start();
+
+ // Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly.
m_state.init();
+ eth::commit(genesisState(), m_db, m_state);
+ cout << "State::State: state root initialised to " << m_state.root() << endl;
+
m_previousBlock = BlockInfo::genesis();
resetCurrent();
+
+ assert(m_state.root() == m_previousBlock.stateRoot);
}
void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const
@@ -112,29 +137,7 @@ void State::ensureCached(Address _a, bool _requireMemory, bool _forceCreate) con
void State::commit()
{
- for (auto const& i: m_cache)
- if (i.second.type() == AddressType::Dead)
- m_state.remove(i.first);
- else
- {
- RLPStream s(i.second.type() == AddressType::Contract ? 3 : 2);
- s << i.second.balance() << i.second.nonce();
- if (i.second.type() == AddressType::Contract)
- {
- if (i.second.haveMemory())
- {
- TrieDB memdb(&m_db);
- memdb.init();
- for (auto const& j: i.second.memory())
- if (j.second)
- memdb.insert(j.first, rlp(j.second));
- s << memdb.root();
- }
- else
- s << i.second.oldRoot();
- }
- m_state.insert(i.first, &s.out());
- }
+ eth::commit(m_cache, m_db, m_state);
m_cache.clear();
}
diff --git a/libethereum/State.h b/libethereum/State.h
index d939b1c13..4bb81edea 100644
--- a/libethereum/State.h
+++ b/libethereum/State.h
@@ -39,6 +39,9 @@ namespace eth
class BlockChain;
+extern const u256 c_genesisDifficulty;
+std::map const& genesisState();
+
/**
* @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
@@ -158,7 +161,7 @@ private:
/// exist in the DB.
void ensureCached(Address _a, bool _requireMemory, bool _forceCreate) const;
- /// Commit all changes waiting in the address cache.
+ /// Commit all changes waiting in the address cache to the DB.
void commit();
/// Execute the given block on our previous block. This will set up m_currentBlock first, then call the other playback().
@@ -235,6 +238,34 @@ inline std::ostream& operator<<(std::ostream& _out, State const& _s)
return _out;
}
+template
+void commit(std::map const& _cache, DB& _db, TrieDB& _state)
+{
+ for (auto const& i: _cache)
+ if (i.second.type() == AddressType::Dead)
+ _state.remove(i.first);
+ else
+ {
+ RLPStream s(i.second.type() == AddressType::Contract ? 3 : 2);
+ s << i.second.balance() << i.second.nonce();
+ if (i.second.type() == AddressType::Contract)
+ {
+ if (i.second.haveMemory())
+ {
+ TrieDB memdb(&_db);
+ memdb.init();
+ for (auto const& j: i.second.memory())
+ if (j.second)
+ memdb.insert(j.first, rlp(j.second));
+ s << memdb.root();
+ }
+ else
+ s << i.second.oldRoot();
+ }
+ _state.insert(i.first, &s.out());
+ }
+}
+
}