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
};
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;
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())
clientName += "/";
@ -460,16 +475,8 @@ int main(int argc, char** argv)
miners
);
if (initDAG != NoDAGInit)
{
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;
}
if (initDAG == LatestBlock || initDAG == PendingBlock)
doInitDAG(web3.ethereum()->blockChain().number() + (initDAG == PendingBlock ? 30000 : 0));
web3.setIdealPeerCount(peers);
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;
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 remove(bytes const& _key) { remove(&_key); }
void remove(bytesConstRef _key);
bool contains(bytes const& _key) { return contains(&_key); }
bool contains(bytesConstRef _key) { return !at(_key).empty(); }
class iterator

30
libethcore/BlockInfo.cpp

@ -40,7 +40,7 @@ BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _h)
populate(_block, _s, _h);
}
void BlockInfo::setEmpty()
void BlockInfo::clear()
{
parentHash = h256();
sha3Uncles = EmptyListSHA3;
@ -105,8 +105,9 @@ h256 BlockInfo::headerHash(bytesConstRef _block)
void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const& _h)
{
// m_hash = dev::sha3(_header.data());
m_hash = _h;
if (_h)
assert(_h == dev::sha3(_header.data()));
m_seedHash = h256();
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()));
}
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
{
RLP root(_block);
u256 mgp = (u256)-1;
OverlayDB db;
/*OverlayDB db;
GenericTrieDB<OverlayDB> t(&db);
t.init();
unsigned i = 0;
@ -186,12 +195,13 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
{
bytes k = rlp(i);
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;
}
if (transactionsRoot != t.root())
BOOST_THROW_EXCEPTION(InvalidTransactionsHash() << HashMismatchError(t.root(), transactionsRoot));
if (transactionsRoot != t.root())*/
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()))
BOOST_THROW_EXCEPTION(InvalidUnclesHash());
@ -199,7 +209,7 @@ void BlockInfo::verifyInternals(bytesConstRef _block) const
void BlockInfo::populateFromParent(BlockInfo const& _parent)
{
m_hash = m_seedHash = h256();
noteDirty();
stateRoot = _parent.stateRoot;
parentHash = _parent.hash();
number = _parent.number + 1;

4
libethcore/BlockInfo.h

@ -116,9 +116,9 @@ public:
}
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 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;
}
#endif
auto newHash = BlockInfo::headerHash(_block);
// 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());
}
// Work out its number as the parent's number + 1
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.
BOOST_THROW_EXCEPTION(UnknownParent());
}
@ -413,12 +412,12 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
// Check it's not crazy
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.
BOOST_THROW_EXCEPTION(FutureTime());
}
clog(BlockChainNote) << "Attempting import of " << newHash.abridged() << "...";
clog(BlockChainNote) << "Attempting import of " << bi.hash().abridged() << "...";
#if ETH_TIMED_IMPORTS
preliminaryChecks = t.elapsed();
@ -463,16 +462,16 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
details(bi.parentHash);
WriteGuard l(x_details);
m_details[newHash] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {});
m_details[bi.parentHash].children.push_back(newHash);
m_details[bi.hash()] = BlockDetails((unsigned)pd.number + 1, td, bi.parentHash, {});
m_details[bi.parentHash].children.push_back(bi.hash());
}
{
WriteGuard l(x_logBlooms);
m_logBlooms[newHash] = blb;
m_logBlooms[bi.hash()] = blb;
}
{
WriteGuard l(x_receipts);
m_receipts[newHash] = br;
m_receipts[bi.hash()] = br;
}
#if ETH_TIMED_IMPORTS
@ -484,11 +483,11 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
ReadGuard l2(x_details);
ReadGuard l4(x_receipts);
ReadGuard l5(x_logBlooms);
m_blocksDB->Put(m_writeOptions, toSlice(newHash), (ldb::Slice)ref(_block));
m_extrasDB->Put(m_writeOptions, toSlice(newHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[newHash].rlp()));
m_blocksDB->Put(m_writeOptions, toSlice(bi.hash()), (ldb::Slice)ref(_block));
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(newHash, ExtraLogBlooms), (ldb::Slice)dev::ref(m_logBlooms[newHash].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(), ExtraLogBlooms), (ldb::Slice)dev::ref(m_logBlooms[bi.hash()].rlp()));
m_extrasDB->Put(m_writeOptions, toSlice(bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(m_receipts[bi.hash()].rlp()));
}
#if ETH_TIMED_IMPORTS
@ -535,13 +534,13 @@ pair<h256s, h256> BlockChain::import(bytes const& _block, OverlayDB const& _db,
if (td > details(last).totalDifficulty)
{
unsigned commonIndex;
tie(route, common, commonIndex) = treeRoute(last, newHash);
tie(route, common, commonIndex) = treeRoute(last, bi.hash());
{
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
if (common != last)

39
libethereum/State.cpp

@ -99,7 +99,7 @@ State::State(OverlayDB const& _db, BaseState _bs, Address _coinbaseAddress):
m_previousBlock = CanonBlockChain::genesis();
}
else
m_previousBlock.setEmpty();
m_previousBlock.clear();
resetCurrent();
@ -190,6 +190,8 @@ State& State::operator=(State const& _s)
m_blockReward = _s.m_blockReward;
m_lastTx = _s.m_lastTx;
paranoia("after state cloning (assignment op)", true);
m_committedToMine = false;
return *this;
}
@ -276,8 +278,8 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
{
bool ret = false;
// BLOCK
BlockInfo bi = _bi;
if (!bi)
BlockInfo bi = _bi ? _bi : _bc.info(_block);
/* if (!bi)
while (1)
{
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 << _e.what() << endl;
}
}
}*/
if (bi == m_currentBlock)
{
// We mined the last block.
@ -364,7 +366,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
#endif
// Check family:
BlockInfo biParent(_bc.block(_bi.parentHash));
BlockInfo biParent = _bc.info(_bi.parentHash);
_bi.verifyParent(biParent);
#if ETH_TIMED_ENACTMENTS
@ -374,7 +376,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const
BlockInfo biGrandParent;
if (biParent.number)
biGrandParent.populate(_bc.block(biParent.parentHash));
biGrandParent = _bc.info(biParent.parentHash);
#if ETH_TIMED_ENACTMENTS
populateGrand = t.elapsed();
@ -434,6 +436,8 @@ void State::resetCurrent()
m_lastTx = m_db;
m_state.setRoot(m_previousBlock.stateRoot);
m_committedToMine = false;
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.
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
assert(m_previousBlock.hash() == 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.
m_currentBlock = bi;
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 << m_state;
@ -620,6 +631,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
// Initialise total difficulty calculation.
u256 tdIncrease = m_currentBlock.difficulty;
// Check uncles & apply their rewards to state.
if (rlp[2].itemCount() > 2)
BOOST_THROW_EXCEPTION(TooManyUncles());
@ -646,6 +658,7 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, bool _checkNonce)
tdIncrease += uncle.difficulty;
rewarded.push_back(uncle);
}
applyRewards(rewarded);
// 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)));
}
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;
}
@ -687,6 +705,9 @@ void State::cleanup(bool _fullCommit)
paranoia("immediately after database commit", true);
m_previousBlock = m_currentBlock;
m_currentBlock.populateFromParent(m_previousBlock);
cdebug << "finalising enactment. current -> previous, hash is" << m_previousBlock.hash().abridged();
}
else
m_db.rollback();
@ -696,7 +717,7 @@ void State::cleanup(bool _fullCommit)
void State::uncommitToMine()
{
if (m_currentBlock.sha3Uncles)
if (m_committedToMine)
{
m_cache.clear();
if (!m_transactions.size())
@ -705,7 +726,7 @@ void State::uncommitToMine()
m_state.setRoot(m_receipts.back().stateRoot());
m_db = m_lastTx;
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.stateRoot = m_state.root();
m_currentBlock.parentHash = m_previousBlock.hash();
m_committedToMine = true;
}
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_currentBlock; ///< The current block's information.
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_currentUncles; ///< The RLP-encoded block of uncles.

Loading…
Cancel
Save