Browse Source

Fix and clean up of State class.

Fixed #1541
cl-refactor
Gav Wood 10 years ago
parent
commit
e3aa60c445
  1. 27
      eth/main.cpp
  2. 6
      libdevcrypto/TrieDB.h
  3. 30
      libethcore/BlockInfo.cpp
  4. 4
      libethcore/BlockInfo.h
  5. 33
      libethereum/BlockChain.cpp
  6. 39
      libethereum/State.cpp
  7. 1
      libethereum/State.h

27
eth/main.cpp

@ -200,6 +200,15 @@ enum class NodeMode
Full Full
}; };
void doInitDAG(unsigned _n)
{
BlockInfo bi;
bi.number = _n;
cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl;
Ethasher::get()->full(bi);
exit(0);
}
static const unsigned NoDAGInit = (unsigned)-3; static const unsigned NoDAGInit = (unsigned)-3;
int main(int argc, char** argv) int main(int argc, char** argv)
@ -440,6 +449,12 @@ int main(int argc, char** argv)
} }
} }
// Two codepaths is necessary since named block require database, but numbered
// blocks are superuseful to have when database is already open in another process.
if (initDAG < NoDAGInit)
doInitDAG(initDAG);
if (!clientName.empty()) if (!clientName.empty())
clientName += "/"; clientName += "/";
@ -460,16 +475,8 @@ int main(int argc, char** argv)
miners miners
); );
if (initDAG != NoDAGInit) if (initDAG == LatestBlock || initDAG == PendingBlock)
{ doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0));
BlockInfo bi;
bi.number = (initDAG == LatestBlock || initDAG == PendingBlock) ?
web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0) :
initDAG;
cout << "Initializing DAG for epoch beginning #" << (bi.number / 30000 * 30000) << " (seedhash " << bi.seedHash().abridged() << "). This will take a while." << endl;
Ethasher::get()->full(bi);
return 0;
}
web3.setIdealPeerCount(peers); web3.setIdealPeerCount(peers);
std::shared_ptr<eth::BasicGasPricer> gasPricer = make_shared<eth::BasicGasPricer>(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); std::shared_ptr<eth::BasicGasPricer> gasPricer = make_shared<eth::BasicGasPricer>(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));

6
libdevcrypto/TrieDB.h

@ -161,9 +161,15 @@ public:
} }
} }
std::string at(bytes const& _key) const { return at(&_key); }
std::string at(bytesConstRef _key) const; std::string at(bytesConstRef _key) const;
void insert(bytes const& _key, bytes const& _value) { insert(&_key, &_value); }
void insert(bytesConstRef _key, bytes const& _value) { insert(_key, &_value); }
void insert(bytes const& _key, bytesConstRef _value) { insert(&_key, _value); }
void insert(bytesConstRef _key, bytesConstRef _value); void insert(bytesConstRef _key, bytesConstRef _value);
void remove(bytes const& _key) { remove(&_key); }
void remove(bytesConstRef _key); void remove(bytesConstRef _key);
bool contains(bytes const& _key) { return contains(&_key); }
bool contains(bytesConstRef _key) { return !at(_key).empty(); } bool contains(bytesConstRef _key) { return !at(_key).empty(); }
class iterator class iterator

30
libethcore/BlockInfo.cpp

@ -40,7 +40,7 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h)
populate(_block, _s, _h); populate(_block, _s, _h);
} }
void BlockInfo::setEmpty() void BlockInfo::clear()
{ {
parentHash = h256(); parentHash = h256();
sha3Uncles = EmptyListSHA3; sha3Uncles = EmptyListSHA3;
@ -105,8 +105,9 @@ h256 BlockInfo::headerHash(bytesConstRef _block)
void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h) void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h)
{ {
// m_hash = dev::sha3(_header.data());
m_hash = _h; m_hash = _h;
if (_h)
assert(_h == dev::sha3(_header.data()));
m_seedHash = h256(); m_seedHash = h256();
int field = 0; int field = 0;
@ -172,13 +173,21 @@ void BlockInfo::populate(bytesConstRef _block, Strictness _s, h256 const& _h)
BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString())); BOOST_THROW_EXCEPTION(InvalidBlockFormat() << errinfo_comment("block uncles need to be a list") << BadFieldError(2, root[2].data().toString()));
} }
template <class T, class U> h256 trieRootOver(unsigned _itemCount, T const& _getKey, U const& _getValue)
{
MemoryDB db;
GenericTrieDB<MemoryDB> t(&db);
t.init();
for (unsigned i = 0; i < _itemCount; ++i)
t.insert(_getKey(i), _getValue(i));
return t.root();
}
void BlockInfo::verifyInternals(bytesConstRef _block) const void BlockInfo::verifyInternals(bytesConstRef _block) const
{ {
RLP root(_block); RLP root(_block);
u256 mgp = (u256)-1; /*OverlayDB db;
OverlayDB db;
GenericTrieDB<OverlayDB> t(&db); GenericTrieDB<OverlayDB> t(&db);
t.init(); t.init();
unsigned i = 0; unsigned i = 0;
@ -186,12 +195,13 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
{ {
bytes k = rlp(i); bytes k = rlp(i);
t.insert(&k, tr.data()); t.insert(&k, tr.data());
u256 gasprice = tr[1].toInt<u256>();
mgp = min(mgp, gasprice); // the minimum gas price is not used for anything //TODO delete?
++i; ++i;
} }
if (transactionsRoot != t.root()) if (transactionsRoot != t.root())*/
BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(t.root(), transactionsRoot)); auto txList = root[1];
auto expectedRoot = trieRootOver(txList.itemCount(), [&](unsigned i){ return rlp(i); }, [&](unsigned i){ return txList[i].data(); });
if (transactionsRoot != expectedRoot)
BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(expectedRoot, transactionsRoot));
if (sha3Uncles != sha3(root[2].data())) if (sha3Uncles != sha3(root[2].data()))
BOOST_THROW_EXCEPTION(InvalidUnclesHash()); BOOST_THROW_EXCEPTION(InvalidUnclesHash());
@ -199,7 +209,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
void BlockInfo::populateFromParent(BlockInfo const& _parent) void BlockInfo::populateFromParent(BlockInfo const& _parent)
{ {
m_hash = m_seedHash = h256(); noteDirty();
stateRoot = _parent.stateRoot; stateRoot = _parent.stateRoot;
parentHash = _parent.hash(); parentHash = _parent.hash();
number = _parent.number + 1; number = _parent.number + 1;

4
libethcore/BlockInfo.h

@ -116,9 +116,9 @@ public:
} }
bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); } bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); }
void setEmpty(); void clear();
void noteDirty() const { m_hash = m_seedHash= h256(); } void noteDirty() const { m_hash = m_seedHash = h256(); }
void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populateFromHeader(RLP const& _header, Strictness _s = IgnoreNonce, h256 const& _h = h256());
void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256()); void populate(bytesConstRef _block, Strictness _s = IgnoreNonce, h256 const& _h = h256());

33
libethereum/BlockChain.cpp

@ -384,19 +384,18 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
throw; throw;
} }
#endif #endif
auto newHash = BlockInfo::headerHash(_block);
// Check block doesn't already exist first! // Check block doesn't already exist first!
if (isKnown(newHash) && !_force) if (isKnown(bi.hash()) && !_force)
{ {
clog(BlockChainNote) << newHash << ": Not new."; clog(BlockChainNote) << bi.hash() << ": Not new.";
BOOST_THROW_EXCEPTION(AlreadyHaveBlock()); BOOST_THROW_EXCEPTION(AlreadyHaveBlock());
} }
// Work out its number as the parent's number + 1 // Work out its number as the parent's number + 1
if (!isKnown(bi.parentHash)) if (!isKnown(bi.parentHash))
{ {
clog(BlockChainNote) << newHash << ": Unknown parent " << bi.parentHash; clog(BlockChainNote) << bi.hash() << ": Unknown parent " << bi.parentHash;
// We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on.
BOOST_THROW_EXCEPTION(UnknownParent()); BOOST_THROW_EXCEPTION(UnknownParent());
} }
@ -413,12 +412,12 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
// Check it's not crazy // Check it's not crazy
if (bi.timestamp > (u256)time(0)) if (bi.timestamp > (u256)time(0))
{ {
clog(BlockChainNote) << newHash << ": Future time " << bi.timestamp << " (now at " << time(0) << ")"; clog(BlockChainNote) << bi.hash() << ": Future time " << bi.timestamp << " (now at " << time(0) << ")";
// Block has a timestamp in the future. This is no good. // Block has a timestamp in the future. This is no good.
BOOST_THROW_EXCEPTION(FutureTime()); BOOST_THROW_EXCEPTION(FutureTime());
} }
clog(BlockChainNote) << "Attempting import of " << newHash.abridged() << "..."; clog(BlockChainNote) << "Attempting import of " << bi.hash().abridged() << "...";
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS
preliminaryChecks = t.elapsed(); preliminaryChecks = t.elapsed();
@ -463,16 +462,16 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
details(bi.parentHash); details(bi.parentHash);
WriteGuard l(x_details); WriteGuard l(x_details);
m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {}); m_details[bi.hash()] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {});
m_details[bi.parentHash].children.push_back(newHash); m_details[bi.parentHash].children.push_back(bi.hash());
} }
{ {
WriteGuard l(x_logBlooms); WriteGuard l(x_logBlooms);
m_logBlooms[newHash] = blb; m_logBlooms[bi.hash()] = blb;
} }
{ {
WriteGuard l(x_receipts); WriteGuard l(x_receipts);
m_receipts[newHash] = br; m_receipts[bi.hash()] = br;
} }
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS
@ -484,11 +483,11 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
ReadGuard l2(x_details); ReadGuard l2(x_details);
ReadGuard l4(x_receipts); ReadGuard l4(x_receipts);
ReadGuard l5(x_logBlooms); ReadGuard l5(x_logBlooms);
m_blocksDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block)); m_blocksDB->Put(m_writeOptions, toSlice(bi.hash()), (ldb::Slice)ref(_block));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.hash()].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[bi.parentHash].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraLogBlooms), (ldb::Slice)dev::ref(m_logBlooms[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(m_logBlooms[bi.hash()].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraReceipts), (ldb::Slice)dev::ref(m_receipts[newHash].rlp())); m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(m_receipts[bi.hash()].rlp()));
} }
#if ETH_TIMED_IMPORTS #if ETH_TIMED_IMPORTS
@ -535,13 +534,13 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
if (td > details(last).totalDifficulty) if (td > details(last).totalDifficulty)
{ {
unsigned commonIndex; unsigned commonIndex;
tie(route, common, commonIndex) = treeRoute(last, newHash); tie(route, common, commonIndex) = treeRoute(last, bi.hash());
{ {
WriteGuard l(x_lastBlockHash); WriteGuard l(x_lastBlockHash);
m_lastBlockHash = newHash; m_lastBlockHash = bi.hash();
} }
m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&newHash, 32)); m_extrasDB->Put(m_writeOptions, ldb::Slice("best"), ldb::Slice((char const*)&(bi.hash()), 32));
// Most of the time these two will be equal - only when we're doing a chain revert will they not be // Most of the time these two will be equal - only when we're doing a chain revert will they not be
if (common != last) if (common != last)

39
libethereum/State.cpp

@ -99,7 +99,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress):
m_previousBlock = CanonBlockChain::genesis(); m_previousBlock = CanonBlockChain::genesis();
} }
else else
m_previousBlock.setEmpty(); m_previousBlock.clear();
resetCurrent(); resetCurrent();
@ -190,6 +190,8 @@ State& State::operator=(State const& _s)
m_blockReward = _s.m_blockReward; m_blockReward = _s.m_blockReward;
m_lastTx = _s.m_lastTx; m_lastTx = _s.m_lastTx;
paranoia("after state cloning (assignment op)", true); paranoia("after state cloning (assignment op)", true);
m_committedToMine = false;
return *this; return *this;
} }
@ -276,8 +278,8 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
{ {
bool ret = false; bool ret = false;
// BLOCK // BLOCK
BlockInfo bi = _bi; BlockInfo bi = _bi ? _bi : _bc.info(_block);
if (!bi) /* if (!bi)
while (1) while (1)
{ {
try try
@ -299,7 +301,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl; cerr << "ERROR: Corrupt block-chain! Delete your block-chain DB and restart." << endl;
cerr << _e.what() << endl; cerr << _e.what() << endl;
} }
} }*/
if (bi == m_currentBlock) if (bi == m_currentBlock)
{ {
// We mined the last block. // We mined the last block.
@ -364,7 +366,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
#endif #endif
// Check family: // Check family:
BlockInfo biParent(_bc.block(_bi.parentHash)); BlockInfo biParent = _bc.info(_bi.parentHash);
_bi.verifyParent(biParent); _bi.verifyParent(biParent);
#if ETH_TIMED_ENACTMENTS #if ETH_TIMED_ENACTMENTS
@ -374,7 +376,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
BlockInfo biGrandParent; BlockInfo biGrandParent;
if (biParent.number) if (biParent.number)
biGrandParent.populate(_bc.block(biParent.parentHash)); biGrandParent = _bc.info(biParent.parentHash);
#if ETH_TIMED_ENACTMENTS #if ETH_TIMED_ENACTMENTS
populateGrand = t.elapsed(); populateGrand = t.elapsed();
@ -434,6 +436,8 @@ void State::resetCurrent()
m_lastTx = m_db; m_lastTx = m_db;
m_state.setRoot(m_previousBlock.stateRoot); m_state.setRoot(m_previousBlock.stateRoot);
m_committedToMine = false;
paranoia("begin resetCurrent", true); paranoia("begin resetCurrent", true);
} }
@ -539,6 +543,9 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
// m_currentBlock is assumed to be prepopulated and reset. // m_currentBlock is assumed to be prepopulated and reset.
BlockInfo bi(_block, _checkNonce ? CheckEverything : IgnoreNonce); BlockInfo bi(_block, _checkNonce ? CheckEverything : IgnoreNonce);
cdebug << "enacting" << BlockInfo::headerHash(_block).abridged() << "==" << bi.hash().abridged() << "on" << m_previousBlock.hash().abridged();
cdebug << m_currentBlock;
#if !ETH_RELEASE #if !ETH_RELEASE
assert(m_previousBlock.hash() == bi.parentHash); assert(m_previousBlock.hash() == bi.parentHash);
assert(m_currentBlock.parentHash == bi.parentHash); assert(m_currentBlock.parentHash == bi.parentHash);
@ -551,6 +558,10 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
// Populate m_currentBlock with the correct values. // Populate m_currentBlock with the correct values.
m_currentBlock = bi; m_currentBlock = bi;
m_currentBlock.verifyInternals(_block); m_currentBlock.verifyInternals(_block);
m_currentBlock.noteDirty();
cdebug << "populated and verified. incoming block hash is" << m_currentBlock.hash().abridged();
cdebug << m_currentBlock;
// cnote << "playback begins:" << m_state.root(); // cnote << "playback begins:" << m_state.root();
// cnote << m_state; // cnote << m_state;
@ -620,6 +631,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
// Initialise total difficulty calculation. // Initialise total difficulty calculation.
u256 tdIncrease = m_currentBlock.difficulty; u256 tdIncrease = m_currentBlock.difficulty;
// Check uncles & apply their rewards to state. // Check uncles & apply their rewards to state.
if (rlp[2].itemCount() > 2) if (rlp[2].itemCount() > 2)
BOOST_THROW_EXCEPTION(TooManyUncles()); BOOST_THROW_EXCEPTION(TooManyUncles());
@ -646,6 +658,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
tdIncrease += uncle.difficulty; tdIncrease += uncle.difficulty;
rewarded.push_back(uncle); rewarded.push_back(uncle);
} }
applyRewards(rewarded); applyRewards(rewarded);
// Commit all cached state changes to the state trie. // Commit all cached state changes to the state trie.
@ -673,6 +686,11 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed)));
} }
cdebug << m_currentBlock;
auto hh = m_currentBlock.hash();
m_currentBlock.noteDirty();
cdebug << "done enacting. new stateroot is" << m_currentBlock.stateRoot.abridged() << ", hash is" << m_currentBlock.hash().abridged() << " = " << hh;
return tdIncrease; return tdIncrease;
} }
@ -687,6 +705,9 @@ void State::cleanup(bool _fullCommit)
paranoia("immediately after database commit", true); paranoia("immediately after database commit", true);
m_previousBlock = m_currentBlock; m_previousBlock = m_currentBlock;
m_currentBlock.populateFromParent(m_previousBlock);
cdebug << "finalising enactment. current -> previous, hash is" << m_previousBlock.hash().abridged();
} }
else else
m_db.rollback(); m_db.rollback();
@ -696,7 +717,7 @@ void State::cleanup(bool _fullCommit)
void State::uncommitToMine() void State::uncommitToMine()
{ {
if (m_currentBlock.sha3Uncles) if (m_committedToMine)
{ {
m_cache.clear(); m_cache.clear();
if (!m_transactions.size()) if (!m_transactions.size())
@ -705,7 +726,7 @@ void State::uncommitToMine()
m_state.setRoot(m_receipts.back().stateRoot()); m_state.setRoot(m_receipts.back().stateRoot());
m_db = m_lastTx; m_db = m_lastTx;
paranoia("Uncommited to mine", true); paranoia("Uncommited to mine", true);
m_currentBlock.sha3Uncles = h256(); m_committedToMine = false;
} }
} }
@ -842,6 +863,8 @@ void State::commitToMine(BlockChain const& _bc)
m_currentBlock.gasUsed = gasUsed(); m_currentBlock.gasUsed = gasUsed();
m_currentBlock.stateRoot = m_state.root(); m_currentBlock.stateRoot = m_state.root();
m_currentBlock.parentHash = m_previousBlock.hash(); m_currentBlock.parentHash = m_previousBlock.hash();
m_committedToMine = true;
} }
MineInfo State::mine(unsigned _msTimeout, bool _turbo) MineInfo State::mine(unsigned _msTimeout, bool _turbo)

1
libethereum/State.h

@ -363,6 +363,7 @@ private:
BlockInfo m_previousBlock; ///< The previous block's information. BlockInfo m_previousBlock; ///< The previous block's information.
BlockInfo m_currentBlock; ///< The current block's information. BlockInfo m_currentBlock; ///< The current block's information.
bytes m_currentBytes; ///< The current block. bytes m_currentBytes; ///< The current block.
bool m_committedToMine = false; ///< Have we committed to mine on the present m_currentBlock?
bytes m_currentTxs; ///< The RLP-encoded block of transactions. bytes m_currentTxs; ///< The RLP-encoded block of transactions.
bytes m_currentUncles; ///< The RLP-encoded block of uncles. bytes m_currentUncles; ///< The RLP-encoded block of uncles.

Loading…
Cancel
Save