/*
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;
}