Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Commit

Permalink
Implement effects of emptiness change.
Browse files Browse the repository at this point in the history
  • Loading branch information
chriseth committed Oct 27, 2016
1 parent 4f62f97 commit 2c8757b
Show file tree
Hide file tree
Showing 12 changed files with 56 additions and 20 deletions.
2 changes: 1 addition & 1 deletion libethashseal/Ethash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ EVMSchedule const& Ethash::evmSchedule(EnvInfo const& _envInfo) const
{
if (_envInfo.number() >= chainParams().u256Param("EIP158ForkBlock"))
return EIP158Schedule;
if (_envInfo.number() >= chainParams().u256Param("EIP150ForkBlock"))
else if (_envInfo.number() >= chainParams().u256Param("EIP150ForkBlock"))
return EIP150Schedule;
else if (_envInfo.number() >= chainParams().u256Param("homsteadForkBlock"))
return HomesteadSchedule;
Expand Down
3 changes: 3 additions & 0 deletions libethereum/Account.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ class Account
/// @returns true if the account is unchanged from creation.
bool isDirty() const { return !m_isUnchanged; }

/// @returns true if the nonce, balance and code is zero / empty. Code is considered empty
/// during creation phase.
bool isEmpty() const { return nonce() == 0 && balance() == 0 && ((isFreshCode() && code().empty()) || codeHash() == EmptySHA3); }

/// @returns the balance of this account. Can be altered in place.
u256& balance() { return m_balance; }
Expand Down
9 changes: 6 additions & 3 deletions libethereum/Block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,9 @@ u256 Block::enact(VerifiedBlockRef const& _block, BlockChain const& _bc)
applyRewards(rewarded, _bc.chainParams().blockReward);

// Commit all cached state changes to the state trie.
bool killEmptyAccounts = m_currentBlock.number() >= _bc.chainParams().u256Param("EIP158ForkBlock");
DEV_TIMED_ABOVE("commit", 500)
m_state.commit();
m_state.commit(killEmptyAccounts);

// Hash the state trie and check against the state_root hash in m_currentBlock.
if (m_currentBlock.stateRoot() != m_previousBlock.stateRoot() && m_currentBlock.stateRoot() != rootHash())
Expand Down Expand Up @@ -688,7 +689,7 @@ void Block::performIrregularModifications()
Addresses allDAOs = childDaos();
for (Address const& dao: allDAOs)
m_state.transferBalance(dao, recipient, m_state.balance(dao));
m_state.commit();
m_state.commit(false);
}
}

Expand Down Expand Up @@ -768,7 +769,9 @@ void Block::commitToSeal(BlockChain const& _bc, bytes const& _extraData)
applyRewards(uncleBlockHeaders, _bc.chainParams().blockReward);

// Commit any and all changes to the trie that are in the cache, then update the state root accordingly.
m_state.commit();
bool killEmptyAccounts = m_currentBlock.number() >= _bc.chainParams().u256Param("EIP158ForkBlock");
DEV_TIMED_ABOVE("commit", 500)
m_state.commit(killEmptyAccounts);

clog(StateDetail) << "Post-reward stateRoot:" << m_state.rootHash();
clog(StateDetail) << m_state;
Expand Down
2 changes: 1 addition & 1 deletion libethereum/ExtVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class ExtVM: public ExtVMFace
virtual bool exists(Address _a) override final
{
if (evmSchedule().emptinessIsNonexistence())
return m_s.accountNonemptyOrExisting(_a);
return m_s.accountNonemptyAndExisting(_a);
else
return m_s.addressInUse(_a);
}
Expand Down
26 changes: 23 additions & 3 deletions libethereum/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ 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_unchangedCacheEntries(_s.m_unchangedCacheEntries),
m_touched(_s.m_touched),
m_accountStartNonce(_s.m_accountStartNonce)
{
Expand Down Expand Up @@ -116,7 +117,7 @@ OverlayDB State::openDB(std::string const& _basePath, h256 const& _genesisHash,
void State::populateFrom(AccountMap const& _map)
{
eth::commit(_map, m_state);
commit();
commit(false);
}

u256 const& State::requireAccountStartNonce() const
Expand All @@ -134,6 +135,13 @@ void State::noteAccountStartNonce(u256 const& _actual)
BOOST_THROW_EXCEPTION(IncorrectAccountStartNonceInState());
}

void State::killEmptyAccounts()
{
for (auto& i: m_cache)
if (i.second.isDirty() && i.second.isEmpty())
i.second.kill();
}

void State::paranoia(std::string const& _when, bool _enforceRefs) const
{
#if ETH_PARANOIA && !ETH_FATDB
Expand All @@ -158,6 +166,7 @@ State& State::operator=(State const& _s)
m_db = _s.m_db;
m_state.open(&m_db, _s.m_state.root(), Verification::Skip);
m_cache = _s.m_cache;
m_unchangedCacheEntries = _s.m_unchangedCacheEntries;
m_touched = _s.m_touched;
m_accountStartNonce = _s.m_accountStartNonce;
paranoia("after state cloning (assignment op)", true);
Expand Down Expand Up @@ -266,8 +275,10 @@ void State::clearCacheIfTooLarge() const
}
}

void State::commit()
void State::commit(bool _killEmptyAccounts)
{
if (_killEmptyAccounts)
killEmptyAccounts();
m_touched += dev::eth::commit(m_cache, m_state);
m_cache.clear();
}
Expand Down Expand Up @@ -301,6 +312,14 @@ bool State::addressInUse(Address const& _id) const
return !!account(_id);
}

bool State::accountNonemptyAndExisting(Address const& _address) const
{
if (Account const* a = account(_address))
return !a->isEmpty();
else
return false;
}

bool State::addressHasCode(Address const& _id) const
{
if (auto a = account(_id))
Expand Down Expand Up @@ -542,7 +561,8 @@ std::pair<ExecutionResult, TransactionReceipt> State::execute(EnvInfo const& _en
m_cache.clear();
else
{
commit();
bool killEmptyAccounts = _envInfo.number() >= _sealEngine->chainParams().u256Param("EIP158ForkBlock");
commit(killEmptyAccounts);

#if ETH_PARANOIA && !ETH_FATDB
ctrace << "Executed; now" << rootHash();
Expand Down
10 changes: 7 additions & 3 deletions libethereum/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ class State
/// Check if the address is in use.
bool addressInUse(Address const& _address) const;

/// Check if the account does not exist in the state or is empty (nonce == 0, balance == 0, code empty).
/// Check if the account exists in the state and is non empty (nonce > 0 || balance > 0 || code nonempty).
/// These two notions are equivalent after EIP158.
bool accountNonemptyOrExisting(Address const& _address) const;
bool accountNonemptyAndExisting(Address const& _address) const;

/// Check if the address contains executable code.
bool addressHasCode(Address const& _address) const;
Expand Down Expand Up @@ -243,7 +243,8 @@ class State
StateDiff diff(State const& _c, bool _quick = false) const;

/// Commit all changes waiting in the address cache to the DB.
void commit();
/// @param _killEmptyAccounts if true, will remove all "touched" empty accounts from the state.
void commit(bool _killEmptyAccounts);

/// Resets any uncommitted changes to the cache.
void setRoot(h256 const& _root);
Expand All @@ -254,6 +255,9 @@ class State
void noteAccountStartNonce(u256 const& _actual);

private:
/// Turns all "touched" empty accounts into non-alive accounts.
void killEmptyAccounts();

/// @returns the account at the given address or a null pointer if it does not exist.
/// The pointer is valid until the next access to the state or account.
Account const* account(Address const& _a, bool _requireCode = false) const;
Expand Down
10 changes: 6 additions & 4 deletions libevm/VM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,12 @@ void VM::interpretCases()
m_runGas = toUint64(m_schedule->suicideGas);
Address dest = asAddress(*m_sp);

// After EIP150 hard fork charge additional cost of sending
// ethers to non-existing account.
if (m_schedule->suicideChargesNewAccountGas() && !m_ext->exists(dest))
m_runGas += m_schedule->callNewAccountGas;
// After EIP158 zero-value suicides do not have to pay account creation gas.
if (m_ext->balance(m_ext->myAddress) > 0 || m_schedule->zeroValueTransferChargesNewAccountGas())
// After EIP150 hard fork charge additional cost of sending
// ethers to non-existing account.
if (m_schedule->suicideChargesNewAccountGas() && !m_ext->exists(dest))
m_runGas += m_schedule->callNewAccountGas;

onOperation();
updateIOGas();
Expand Down
3 changes: 2 additions & 1 deletion libevm/VMCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ bool VM::caseCallSetup(CallParameters *callParams)
m_runGas = toUint64(m_schedule->callGas);

if (m_op == Instruction::CALL && !m_ext->exists(asAddress(*(m_sp - 1))))
m_runGas += toUint64(m_schedule->callNewAccountGas);
if (*(m_sp - 2) > 0 || m_schedule->zeroValueTransferChargesNewAccountGas())
m_runGas += toUint64(m_schedule->callNewAccountGas);

if (m_op != Instruction::DELEGATECALL && *(m_sp - 2) > 0)
m_runGas += toUint64(m_schedule->callValueTransferGas);
Expand Down
1 change: 1 addition & 0 deletions libevmcore/EVMSchedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ struct EVMSchedule
bool staticCallDepthLimit() const { return !eip150Mode; }
bool suicideChargesNewAccountGas() const { return eip150Mode; }
bool emptinessIsNonexistence() const { return eip158Mode; }
bool zeroValueTransferChargesNewAccountGas() const { return !eip158Mode; }
};

static const EVMSchedule DefaultSchedule = EVMSchedule();
Expand Down
2 changes: 1 addition & 1 deletion test/BlockChainHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ TestBlock::TestBlock(mObject const& _blockObj, mObject const& _stateObj):

m_state = std::unique_ptr<State>(new State(0, OverlayDB(State::openDB(m_tempDirState.get()->path(), h256{}, WithExisting::Kill)), BaseState::Empty));
ImportTest::importState(_stateObj, *m_state.get());
m_state.get()->commit();
m_state.get()->commit(false);

json_spirit::mObject state = _stateObj;
dev::test::replaceLLLinState(state);
Expand Down
6 changes: 4 additions & 2 deletions test/TestHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,10 @@ bytes ImportTest::executeTest(eth::Network _sealEngineNetwork)
{
ExecutionResult res;
eth::State tmpState = m_statePre;
unique_ptr<SealEngineFace> se;
try
{
unique_ptr<SealEngineFace> se(ChainParams(genesisInfo(_sealEngineNetwork)).createSealEngine());
se.reset(ChainParams(genesisInfo(_sealEngineNetwork)).createSealEngine());
std::pair<ExecutionResult, TransactionReceipt> execOut = m_statePre.execute(m_envInfo, se.get(), m_transaction);
res = execOut.first;
m_logs = execOut.second.log();
Expand All @@ -182,7 +183,8 @@ bytes ImportTest::executeTest(eth::Network _sealEngineNetwork)
cnote << "state execution exception: " << _e.what();
}

m_statePre.commit();
bool killEmptyAccounts = m_envInfo.number() >= se->chainParams().u256Param("EIP158ForkBlock");
m_statePre.commit(killEmptyAccounts);
m_statePost = m_statePre;
m_statePre = tmpState;

Expand Down
2 changes: 1 addition & 1 deletion test/TestUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void ClientBaseFixture::enumerateClients(std::function<void(Json::Value const&,
enumerateBlockchains([&callback](Json::Value const& _json, BlockChain const& _bc, State _state) -> void
{
cerr << "void ClientBaseFixture::enumerateClients. FixedClient now accepts block not sate!" << endl;
_state.commit(); //unused variable. remove this line
_state.commit(false); //unused variable. remove this line
eth::Block b(Block::Null);
b.noteChain(_bc);
FixedClient client(_bc, b);
Expand Down

0 comments on commit 2c8757b

Please sign in to comment.