From bb0f5358bfa86184d7a4f4a30c04ce4bc8fde26b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 1 Mar 2015 00:52:51 +0100 Subject: [PATCH] New SecureTrie. --- libdevcrypto/TrieDB.h | 48 +++++++++++++++++++++++ libethcore/CommonEth.cpp | 2 +- libethereum/CachedAddressState.cpp | 6 +-- libethereum/CachedAddressState.h | 3 ++ libethereum/CanonBlockChain.cpp | 2 +- libethereum/State.cpp | 63 +++++++++++++----------------- libethereum/State.h | 9 ++--- mix/MixClient.cpp | 2 +- 8 files changed, 88 insertions(+), 47 deletions(-) diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index f5b7ff9c9..c08199e06 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -325,6 +325,54 @@ std::ostream& operator<<(std::ostream& _out, TrieDB const& _db) return _out; } +template +class SecureGenericTrieDB: private TrieDB +{ + using Super = TrieDB; + +public: + SecureGenericTrieDB(DB* _db): Super(_db) {} + SecureGenericTrieDB(DB* _db, h256 _root): Super(_db, _root) {} + + using Super::open; + using Super::init; + using Super::setRoot; + using Super::haveRoot; + + /// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node). + using Super::isNull; + /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). + using Super::isEmpty; + + using Super::root; + + using Super::leftOvers; + using Super::check; + + std::string at(bytesConstRef _key) const { return Super::at(sha3(_key)); } + void insert(bytesConstRef _key, bytesConstRef _value) { Super::insert(sha3(_key), _value); } + void remove(bytesConstRef _key) { Super::remove(sha3(_key)); } + bool contains(bytesConstRef _key) { return Super::contains(sha3(_key)); } +}; + +template +class SecureTrieDB: public SecureGenericTrieDB +{ + using Super = SecureGenericTrieDB; + +public: + SecureTrieDB(DB* _db): Super(_db) {} + SecureTrieDB(DB* _db, h256 _root): Super(_db, _root) {} + + std::string operator[](KeyType _k) const { return at(_k); } + + bool contains(KeyType _k) const { return Super::contains(bytesConstRef((byte const*)&_k, sizeof(KeyType))); } + std::string at(KeyType _k) const { return Super::at(bytesConstRef((byte const*)&_k, sizeof(KeyType))); } + void insert(KeyType _k, bytesConstRef _value) { Super::insert(bytesConstRef((byte const*)&_k, sizeof(KeyType)), _value); } + void insert(KeyType _k, bytes const& _value) { insert(_k, bytesConstRef(&_value)); } + void remove(KeyType _k) { Super::remove(bytesConstRef((byte const*)&_k, sizeof(KeyType))); } +}; + } // Template implementations... diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 2264e6ec9..8facdf0f1 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -32,7 +32,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 54; +const unsigned c_protocolVersion = 55; const unsigned c_databaseVersion = 5; vector> const& units() diff --git a/libethereum/CachedAddressState.cpp b/libethereum/CachedAddressState.cpp index 5f9be6944..e2fadc8b5 100644 --- a/libethereum/CachedAddressState.cpp +++ b/libethereum/CachedAddressState.cpp @@ -56,9 +56,9 @@ std::map CachedAddressState::storage() const std::map ret; if (m_r) { - TrieDB memdb(const_cast(m_o), m_r[2].toHash()); // promise we won't alter the overlay! :) - for (auto const& j: memdb) - ret[j.first] = RLP(j.second).toInt(); + SecureTrieDB memdb(const_cast(m_o), m_r[2].toHash()); // promise we won't alter the overlay! :) +// for (auto const& j: memdb) +// ret[j.first] = RLP(j.second).toInt(); } if (m_s) for (auto const& j: m_s->storageOverlay()) diff --git a/libethereum/CachedAddressState.h b/libethereum/CachedAddressState.h index 301f54338..8a3c3a607 100644 --- a/libethereum/CachedAddressState.h +++ b/libethereum/CachedAddressState.h @@ -45,7 +45,10 @@ public: u256 balance() const; u256 nonce() const; bytes code() const; + + // TODO: DEPRECATE. std::map storage() const; + AccountDiff diff(CachedAddressState const& _c); private: diff --git a/libethereum/CanonBlockChain.cpp b/libethereum/CanonBlockChain.cpp index b0fe90a78..29fdc9acc 100644 --- a/libethereum/CanonBlockChain.cpp +++ b/libethereum/CanonBlockChain.cpp @@ -76,7 +76,7 @@ bytes CanonBlockChain::createGenesisBlock() h256 stateRoot; { MemoryDB db; - TrieDB state(&db); + SecureTrieDB state(&db); state.init(); dev::eth::commit(genesisState(), db, state); stateRoot = state.root(); diff --git a/libethereum/State.cpp b/libethereum/State.cpp index fad9112db..512dfd792 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -169,18 +169,6 @@ State::~State() { } -Address State::nextActiveAddress(Address _a) const -{ - auto it = m_state.lower_bound(_a); - if ((*it).first == _a) - ++it; - if (it == m_state.end()) - // exchange comments if we want to wraparound -// it = m_state.begin(); - return Address(); - return (*it).first; -} - StateDiff State::diff(State const& _c) const { StateDiff ret; @@ -189,13 +177,14 @@ StateDiff State::diff(State const& _c) const std::set
trieAds; std::set
trieAdsD; - auto trie = TrieDB(const_cast(&m_db), rootHash()); - auto trieD = TrieDB(const_cast(&_c.m_db), _c.rootHash()); + auto trie = SecureTrieDB(const_cast(&m_db), rootHash()); + auto trieD = SecureTrieDB(const_cast(&_c.m_db), _c.rootHash()); - for (auto i: trie) - ads.insert(i.first), trieAds.insert(i.first); - for (auto i: trieD) - ads.insert(i.first), trieAdsD.insert(i.first); + // TODO: fix +// for (auto i: trie) +// ads.insert(i.first), trieAds.insert(i.first); +// for (auto i: trieD) +// ads.insert(i.first), trieAdsD.insert(i.first); for (auto i: m_cache) ads.insert(i.first); for (auto i: _c.m_cache) @@ -357,9 +346,10 @@ map State::addresses() const for (auto i: m_cache) if (i.second.isAlive()) ret[i.first] = i.second.balance(); - for (auto const& i: m_state) - if (m_cache.find(i.first) == m_cache.end()) - ret[i.first] = RLP(i.second)[1].toInt(); + // TODO: fix. +// for (auto const& i: m_state) +// if (m_cache.find(i.first) == m_cache.end()) +// ret[i.first] = RLP(i.second)[1].toInt(); return ret; } @@ -592,9 +582,10 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce) { cwarn << "Bad state root!"; cnote << "Given to be:" << m_currentBlock.stateRoot; - cnote << TrieDB(&m_db, m_currentBlock.stateRoot); + // TODO: Fix +// cnote << SecureTrieDB(&m_db, m_currentBlock.stateRoot); cnote << "Calculated to be:" << rootHash(); - cnote << m_state; +// cnote << m_state; cnote << *this; // Rollback the trie. m_db.rollback(); @@ -939,7 +930,7 @@ u256 State::storage(Address _id, u256 _memory) const return mit->second; // Not in the storage cache - go to the DB. - TrieDB memdb(const_cast(&m_db), it->second.baseRoot()); // promise we won't change the overlay! :) + SecureTrieDB memdb(const_cast(&m_db), it->second.baseRoot()); // promise we won't change the overlay! :) string payload = memdb.at(_memory); u256 ret = payload.size() ? RLP(payload).toInt() : 0; it->second.setStorage(_memory, ret); @@ -957,9 +948,10 @@ map State::storage(Address _id) const // Pull out all values from trie storage. if (it->second.baseRoot()) { - TrieDB memdb(const_cast(&m_db), it->second.baseRoot()); // promise we won't alter the overlay! :) - for (auto const& i: memdb) - ret[i.first] = RLP(i.second).toInt(); + // TODO: fix +// SecureTrieDB memdb(const_cast(&m_db), it->second.baseRoot()); // promise we won't alter the overlay! :) +// for (auto const& i: memdb) +// ret[i.first] = RLP(i.second).toInt(); } // Then merge cached storage over the top. @@ -1010,24 +1002,24 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const cwarn << "LEFTOVERS" << (e ? "[enforced" : "[unenforced") << "refs]"; cnote << "Left:" << lo; cnote << "Keys:" << m_db.keys(); - m_state.debugStructure(cerr); +// m_state.debugStructure(cerr); return false; } // TODO: Enable once fixed. - for (auto const& i: m_state) +/* for (auto const& i: m_state) { RLP r(i.second); - TrieDB storageDB(const_cast(&m_db), r[2].toHash()); // promise not to alter OverlayDB. + SecureTrieDB storageDB(const_cast(&m_db), r[2].toHash()); // promise not to alter OverlayDB. for (auto const& j: storageDB) { (void)j; } if (!e && r[3].toHash() != EmptySHA3 && m_db.lookup(r[3].toHash()).empty()) return false; - } + }*/ } catch (InvalidTrie const&) { cwarn << "BAD TRIE" << (e ? "[enforced" : "[unenforced") << "refs]"; cnote << m_db.keys(); - m_state.debugStructure(cerr); +// m_state.debugStructure(cerr); return false; } return true; @@ -1194,9 +1186,10 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) std::set cached; if (r) { - TrieDB memdb(const_cast(&_s.m_db), r[2].toHash()); // promise we won't alter the overlay! :) - for (auto const& j: memdb) - mem[j.first] = RLP(j.second).toInt(), back.insert(j.first); + SecureTrieDB memdb(const_cast(&_s.m_db), r[2].toHash()); // promise we won't alter the overlay! :) + // TODO: fix +// for (auto const& j: memdb) +// mem[j.first] = RLP(j.second).toInt(), back.insert(j.first); } if (cache) for (auto const& j: cache->storageOverlay()) diff --git a/libethereum/State.h b/libethereum/State.h index 813141d17..37af0cf0e 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -94,9 +94,6 @@ public: /// @returns the set containing all addresses currently in use in Ethereum. std::map addresses() const; - /// @returns the address b such that b > @a _a . - Address nextActiveAddress(Address _a) const; - /// Get the header information on the present block. BlockInfo const& info() const { return m_currentBlock; } @@ -299,7 +296,7 @@ private: void paranoia(std::string const& _when, bool _enforceRefs = false) const; OverlayDB m_db; ///< Our overlay for the state tree. - TrieDB m_state; ///< Our state tree, as an OverlayDB DB. + SecureTrieDB m_state; ///< Our state tree, as an OverlayDB DB. Transactions m_transactions; ///< The current list of transactions that we've included in the state. TransactionReceipts m_receipts; ///< The corresponding list of transaction receipts. std::set m_transactionSet; ///< The set of transaction hashes that we've included in the state. @@ -328,7 +325,7 @@ private: std::ostream& operator<<(std::ostream& _out, State const& _s); template -void commit(std::map const& _cache, DB& _db, TrieDB& _state) +void commit(std::map const& _cache, DB& _db, SecureTrieDB& _state) { for (auto const& i: _cache) if (!i.second.isAlive()) @@ -345,7 +342,7 @@ void commit(std::map const& _cache, DB& _db, TrieDB storageDB(&_db, i.second.baseRoot()); + SecureTrieDB storageDB(&_db, i.second.baseRoot()); for (auto const& j: i.second.storageOverlay()) if (j.second) storageDB.insert(j.first, rlp(j.second)); diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index aaa37a8bb..2ce9455cf 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -81,7 +81,7 @@ void MixClient::resetState(std::map _accounts) m_watches.clear(); m_stateDB = OverlayDB(); - TrieDB accountState(&m_stateDB); + SecureTrieDB accountState(&m_stateDB); accountState.init(); std::map genesisState;