Browse Source

Fix for state race condition.

cl-refactor
Gav Wood 11 years ago
parent
commit
c164e4bcc7
  1. 1
      libethereum/Client.cpp
  2. 29
      libethereum/State.cpp
  3. 20
      libethereum/State.h
  4. 6
      test/state.cpp

1
libethereum/Client.cpp

@ -267,6 +267,7 @@ void Client::work()
{
// Import block.
lock_guard<recursive_mutex> l(m_lock);
m_postMine.completeMine();
m_bc.attemptImport(m_postMine.blockData(), m_stateDB);
m_changed = true;
}

29
libethereum/State.cpp

@ -750,8 +750,15 @@ MineInfo State::mine(uint _msTimeout)
m_currentBlock.difficulty = m_currentBlock.calculateDifficulty(m_previousBlock);
// TODO: Miner class that keeps dagger between mine calls (or just non-polling mining).
MineInfo ret = m_dagger.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout);
if (ret.completed)
auto ret = m_dagger.mine(/*out*/m_currentBlock.nonce, m_currentBlock.headerHashWithoutNonce(), m_currentBlock.difficulty, _msTimeout);
if (!ret.completed)
m_currentBytes.clear();
return ret;
}
void State::completeMine()
{
// Got it!
@ -768,11 +775,6 @@ MineInfo State::mine(uint _msTimeout)
m_currentBlock.hash = sha3(m_currentBytes);
cnote << "Mined " << m_currentBlock.hash << "(parent: " << m_currentBlock.parentHash << ")";
}
else
m_currentBytes.clear();
return ret;
}
bool State::addressInUse(Address _id) const
{
@ -943,9 +945,18 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
return true;
}
// TODO: kill temp nodes automatically in TrieDB
// TODO: run this often.
// POSSIBLE RACE CONDITION: check if mining clears intermediate nodes in trie before clearing pending.
// HOW DID TRIE NODES GO BUT PENDING STAY?
void State::checkPendingInTrie() const
{
bool x = true;
assert(x);
}
// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
// TODO: TransactionReceipt trie should be MemoryDB and built as necessary
u256 State::execute(bytesConstRef _rlp)
{

20
libethereum/State.h

@ -149,11 +149,26 @@ public:
void commitToMine(BlockChain const& _bc);
/// Attempt to find valid nonce for block that this state represents.
/// This function is thread-safe. You can safely have other interactions with this object while it is happening.
/// @param _msTimeout Timeout before return in milliseconds.
/// @returns a non-empty byte array containing the block if it got lucky. In this case, call blockData()
/// to get the block if you need it later.
/// @returns Information on the mining.
MineInfo mine(uint _msTimeout = 1000);
/** Commit to DB and build the final block if the previous call to mine()'s result is completion.
* Typically looks like:
* @code
* // lock
* commitToMine(blockchain);
* // unlock
* MineInfo info;
* for (info.complete = false; !info.complete; info = mine()) {}
* // lock
* completeMine();
* // unlock
* @endcode
*/
void completeMine();
/// Get the complete current block, including valid nonce.
/// Only valid after mine() returns true.
bytes const& blockData() const { return m_currentBytes; }
@ -309,6 +324,7 @@ private:
bool isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const;
void paranoia(std::string const& _when, bool _enforceRefs = false) const;
void checkPendingInTrie() const;
OverlayDB m_db; ///< Our overlay for the state tree.
TrieDB<Address, OverlayDB> m_state; ///< Our state tree, as an OverlayDB DB.

6
test/state.cpp

@ -51,7 +51,8 @@ int stateTest()
// Mine to get some ether!
s.commitToMine(bc);
while (s.mine(100).completed) {}
while (!s.mine(100).completed) {}
s.completeMine();
bc.attemptImport(s.blockData(), stateDB);
cout << bc;
@ -77,7 +78,8 @@ int stateTest()
// Mine to get some ether and set in stone.
s.commitToMine(bc);
while (s.mine(100).completed) {}
while (!s.mine(100).completed) {}
s.completeMine();
bc.attemptImport(s.blockData(), stateDB);
cout << bc;

Loading…
Cancel
Save