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()); + } +} + }