/* This file is part of cpp-ethereum. cpp-ethereum is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. cpp-ethereum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ /** @file State.cpp * @author Gav Wood * @date 2014 */ #include "State.h" #include #include #include #include #include #include #include #include #include #include #include #include "BlockChain.h" #include "Defaults.h" #include "ExtVM.h" #include "Executive.h" #include "CachedAddressState.h" #include "CanonBlockChain.h" #include "TransactionQueue.h" using namespace std; using namespace dev; using namespace dev::eth; namespace fs = boost::filesystem; #define ctrace clog(StateTrace) #define ETH_TIMED_ENACTMENTS 0 const char* StateSafeExceptions::name() { return EthViolet "⚙" EthBlue " ℹ"; } const char* StateDetail::name() { return EthViolet "⚙" EthWhite " ◌"; } const char* StateTrace::name() { return EthViolet "⚙" EthGray " ◎"; } const char* StateChat::name() { return EthViolet "⚙" EthWhite " ◌"; } State::State(OverlayDB const& _db, BaseState _bs): m_db(_db), m_state(&m_db) { if (_bs != BaseState::PreExisting) // Initialise to the state entailed by the genesis block; this guarantees the trie is built correctly. m_state.init(); paranoia("end of normal construction.", true); } State::State(State const& _s): m_db(_s.m_db), m_state(&m_db, _s.m_state.root(), Verification::Skip), m_cache(_s.m_cache), m_touched(_s.m_touched) { paranoia("after state cloning (copy cons).", true); } OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash, WithExisting _we) { std::string path = _basePath.empty() ? Defaults::get()->m_dbPath : _basePath; if (_we == WithExisting::Kill) { cnote << "Killing state database (WithExisting::Kill)."; boost::filesystem::remove_all(path + "/state"); } path += "/" + toHex(_genesisHash.ref().cropped(0, 4)) + "/" + toString(c_databaseVersion); boost::filesystem::create_directories(path); DEV_IGNORE_EXCEPTIONS(fs::permissions(path, fs::owner_all)); ldb::Options o; o.max_open_files = 256; o.create_if_missing = true; ldb::DB* db = nullptr; ldb::Status status = ldb::DB::Open(o, path + "/state", &db); if (!status.ok() || !db) { if (boost::filesystem::space(path + "/state").available < 1024) { cwarn << "Not enough available space found on hard drive. Please free some up and then re-run. Bailing."; BOOST_THROW_EXCEPTION(NotEnoughAvailableSpace()); } else { cwarn << status.ToString(); cwarn << "Database " << (path + "/state") << "already open. You appear to have another instance of ethereum running. Bailing."; BOOST_THROW_EXCEPTION(DatabaseAlreadyOpen()); } } cnote << "Opened state DB."; return OverlayDB(db); } void State::populateFrom(AccountMap const& _map) { eth::commit(_map, m_state); commit(); } void State::paranoia(std::string const& _when, bool _enforceRefs) const { #if ETH_PARANOIA && !ETH_FATDB // TODO: variable on context; just need to work out when there should be no leftovers // [in general this is hard since contract alteration will result in nodes in the DB that are no directly part of the state DB]. if (!isTrieGood(_enforceRefs, false)) { cwarn << "BAD TRIE" << _when; BOOST_THROW_EXCEPTION(InvalidTrie()); } #else (void)_when; (void)_enforceRefs; #endif } State& State::operator=(State const& _s) { if (&_s == this) return *this; m_db = _s.m_db; m_state.open(&m_db, _s.m_state.root(), Verification::Skip); m_cache = _s.m_cache; m_touched = _s.m_touched; paranoia("after state cloning (assignment op)", true); return *this; } StateDiff State::diff(State const& _c, bool _quick) const { StateDiff ret; std::unordered_set
ads; std::unordered_set
trieAds; std::unordered_set
trieAdsD; auto trie = SecureTrieDB(const_cast(&m_db), rootHash()); auto trieD = SecureTrieDB(const_cast(&_c.m_db), _c.rootHash()); if (_quick) { trieAds = m_touched; trieAdsD = _c.m_touched; (ads += m_touched) += _c.m_touched; } else { for (auto const& i: trie) ads.insert(i.first), trieAds.insert(i.first); for (auto const& i: trieD) ads.insert(i.first), trieAdsD.insert(i.first); } for (auto const& i: m_cache) ads.insert(i.first); for (auto const& i: _c.m_cache) ads.insert(i.first); for (auto const& i: ads) { auto it = m_cache.find(i); auto itD = _c.m_cache.find(i); CachedAddressState source(trieAds.count(i) ? trie.at(i) : "", it != m_cache.end() ? &it->second : nullptr, &m_db); CachedAddressState dest(trieAdsD.count(i) ? trieD.at(i) : "", itD != _c.m_cache.end() ? &itD->second : nullptr, &_c.m_db); AccountDiff acd = source.diff(dest); if (acd.changed()) ret.accounts[i] = acd; } return ret; } void State::ensureCached(Address const& _a, bool _requireCode, bool _forceCreate) const { ensureCached(m_cache, _a, _requireCode, _forceCreate); } void State::ensureCached(std::unordered_map& _cache, const Address& _a, bool _requireCode, bool _forceCreate) const { auto it = _cache.find(_a); if (it == _cache.end()) { // populate basic info. string stateBack = m_state.at(_a); if (stateBack.empty() && !_forceCreate) return; RLP state(stateBack); Account s; if (state.isNull()) s = Account(0, Account::NormalCreation); else s = Account(state[0].toInt(), state[1].toInt(), state[2].toHash(), state[3].toHash(), Account::Unchanged); bool ok; tie(it, ok) = _cache.insert(make_pair(_a, s)); } if (_requireCode && it != _cache.end() && !it->second.isFreshCode() && !it->second.codeCacheValid()) it->second.noteCode(it->second.codeHash() == EmptySHA3 ? bytesConstRef() : bytesConstRef(m_db.lookup(it->second.codeHash()))); } void State::commit() { m_touched += dev::eth::commit(m_cache, m_state); m_cache.clear(); } unordered_map State::addresses() const { #if ETH_FATDB unordered_map ret; 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(); return ret; #else BOOST_THROW_EXCEPTION(InterfaceNotSupported("State::addresses()")); #endif } void State::setRoot(h256 const& _r) { m_cache.clear(); // m_touched.clear(); m_state.setRoot(_r); paranoia("begin setRoot", true); } bool State::addressInUse(Address const& _id) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); if (it == m_cache.end()) return false; return true; } bool State::addressHasCode(Address const& _id) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); if (it == m_cache.end()) return false; return it->second.isFreshCode() || it->second.codeHash() != EmptySHA3; } u256 State::balance(Address const& _id) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); if (it == m_cache.end()) return 0; return it->second.balance(); } void State::noteSending(Address const& _id) { ensureCached(_id, false, false); auto it = m_cache.find(_id); if (asserts(it != m_cache.end())) { cwarn << "Sending from non-existant account. How did it pay!?!"; // this is impossible. but we'll continue regardless... m_cache[_id] = Account(1, 0); } else it->second.incNonce(); } void State::addBalance(Address const& _id, u256 const& _amount) { ensureCached(_id, false, false); auto it = m_cache.find(_id); if (it == m_cache.end()) m_cache[_id] = Account(_amount, Account::NormalCreation); else it->second.addBalance(_amount); } void State::subBalance(Address const& _id, bigint const& _amount) { ensureCached(_id, false, false); auto it = m_cache.find(_id); if (it == m_cache.end() || (bigint)it->second.balance() < _amount) BOOST_THROW_EXCEPTION(NotEnoughCash()); else it->second.addBalance(-_amount); } Address State::newContract(u256 const& _balance, bytes const& _code) { auto h = sha3(_code); m_db.insert(h, &_code); while (true) { Address ret = Address::random(); ensureCached(ret, false, false); auto it = m_cache.find(ret); if (it == m_cache.end()) { m_cache[ret] = Account(0, _balance, EmptyTrie, h, Account::Changed); return ret; } } } u256 State::transactionsFrom(Address const& _id) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); if (it == m_cache.end()) return 0; else return it->second.nonce(); } u256 State::storage(Address const& _id, u256 const& _memory) const { ensureCached(_id, false, false); auto it = m_cache.find(_id); // Account doesn't exist - exit now. if (it == m_cache.end()) return 0; // See if it's in the account's storage cache. auto mit = it->second.storageOverlay().find(_memory); if (mit != it->second.storageOverlay().end()) return mit->second; // Not in the storage cache - go to the DB. 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); return ret; } unordered_map State::storage(Address const& _id) const { unordered_map ret; ensureCached(_id, false, false); auto it = m_cache.find(_id); if (it != m_cache.end()) { // Pull out all values from trie storage. if (it->second.baseRoot()) { 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. for (auto const& i: it->second.storageOverlay()) if (i.second) ret[i.first] = i.second; else ret.erase(i.first); } return ret; } h256 State::storageRoot(Address const& _id) const { string s = m_state.at(_id); if (s.size()) { RLP r(s); return r[2].toHash(); } return EmptyTrie; } bytes const& State::code(Address const& _contract) const { if (!addressHasCode(_contract)) return NullBytes; ensureCached(_contract, true, false); return m_cache[_contract].code(); } h256 State::codeHash(Address const& _contract) const { if (!addressHasCode(_contract)) return EmptySHA3; if (m_cache[_contract].isFreshCode()) return sha3(code(_contract)); return m_cache[_contract].codeHash(); } bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const { for (int e = 0; e < (_enforceRefs ? 2 : 1); ++e) try { EnforceRefs r(m_db, !!e); auto lo = m_state.leftOvers(); if (!lo.empty() && _requireNoLeftOvers) { cwarn << "LEFTOVERS" << (e ? "[enforced" : "[unenforced") << "refs]"; cnote << "Left:" << lo; cnote << "Keys:" << m_db.keys(); m_state.debugStructure(cerr); return false; } // TODO: Enable once fixed. /* for (auto const& i: m_state) { RLP r(i.second); 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); return false; } return true; } std::pair State::execute(EnvInfo const& _envInfo, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) { auto onOp = _onOp; #if ETH_VMTRACE if (isChannelVisible()) onOp = Executive::simpleTrace(); // override tracer #endif #if ETH_PARANOIA paranoia("start of execution.", true); State old(*this); auto h = rootHash(); #endif // Create and initialize the executive. This will throw fairly cheaply and quickly if the // transaction is bad in any way. Executive e(*this, _envInfo); ExecutionResult res; e.setResultRecipient(res); e.initialize(_t); // OK - transaction looks valid - execute. u256 startGasUsed = _envInfo.gasUsed(); #if ETH_PARANOIA ctrace << "Executing" << e.t() << "on" << h; ctrace << toHex(e.t().rlp()); #endif if (!e.execute()) e.go(onOp); e.finalize(); #if ETH_PARANOIA ctrace << "Ready for commit;"; ctrace << old.diff(*this); #endif if (_p == Permanence::Reverted) m_cache.clear(); else { commit(); #if ETH_PARANOIA && !ETH_FATDB ctrace << "Executed; now" << rootHash(); ctrace << old.diff(*this); paranoia("after execution commit.", true); if (e.t().receiveAddress()) { EnforceRefs r(m_db, true); if (storageRoot(e.t().receiveAddress()) && m_db.lookup(storageRoot(e.t().receiveAddress())).empty()) { cwarn << "TRIE immediately after execution; no node for receiveAddress"; BOOST_THROW_EXCEPTION(InvalidTrie()); } } #endif // TODO: CHECK TRIE after level DB flush to make sure exactly the same. } return make_pair(res, TransactionReceipt(rootHash(), startGasUsed + e.gasUsed(), e.logs())); } std::ostream& dev::eth::operator<<(std::ostream& _out, State const& _s) { _out << "--- " << _s.rootHash() << std::endl; std::set
d; std::set
dtr; auto trie = SecureTrieDB(const_cast(&_s.m_db), _s.rootHash()); for (auto i: trie) d.insert(i.first), dtr.insert(i.first); for (auto i: _s.m_cache) d.insert(i.first); for (auto i: d) { auto it = _s.m_cache.find(i); Account* cache = it != _s.m_cache.end() ? &it->second : nullptr; string rlpString = dtr.count(i) ? trie.at(i) : ""; RLP r(rlpString); assert(cache || r); if (cache && !cache->isAlive()) _out << "XXX " << i << std::endl; else { string lead = (cache ? r ? " * " : " + " : " "); if (cache && r && cache->nonce() == r[0].toInt() && cache->balance() == r[1].toInt()) lead = " . "; stringstream contout; if ((cache && cache->codeBearing()) || (!cache && r && (h256)r[3] != EmptySHA3)) { std::map mem; std::set back; std::set delta; std::set cached; if (r) { SecureTrieDB 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); } if (cache) for (auto const& j: cache->storageOverlay()) { if ((!mem.count(j.first) && j.second) || (mem.count(j.first) && mem.at(j.first) != j.second)) mem[j.first] = j.second, delta.insert(j.first); else if (j.second) cached.insert(j.first); } if (!delta.empty()) lead = (lead == " . ") ? "*.* " : "*** "; contout << " @:"; if (!delta.empty()) contout << "???"; else contout << r[2].toHash(); if (cache && cache->isFreshCode()) contout << " $" << toHex(cache->code()); else contout << " $" << (cache ? cache->codeHash() : r[3].toHash()); for (auto const& j: mem) if (j.second) contout << std::endl << (delta.count(j.first) ? back.count(j.first) ? " * " : " + " : cached.count(j.first) ? " . " : " ") << std::hex << nouppercase << std::setw(64) << j.first << ": " << std::setw(0) << j.second ; else contout << std::endl << "XXX " << std::hex << nouppercase << std::setw(64) << j.first << ""; } else contout << " [SIMPLE]"; _out << lead << i << ": " << std::dec << (cache ? cache->nonce() : r[0].toInt()) << " #:" << (cache ? cache->balance() : r[1].toInt()) << contout.str() << std::endl; } } return _out; }