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

Commit

Permalink
Move m_storageOverlay and m_storageOriginal caches management into Ac…
Browse files Browse the repository at this point in the history
…count.
  • Loading branch information
gumb0 committed Aug 30, 2018
1 parent 9512da7 commit ac80201
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 79 deletions.
16 changes: 16 additions & 0 deletions libethereum/Account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
*/

#include "Account.h"
#include "SecureTrieDB.h"
#include "ValidationSchemes.h"
#include <libdevcore/JsonUtils.h>
#include <libdevcore/OverlayDB.h>
#include <libethcore/ChainOperationParams.h>
#include <libethcore/Precompiled.h>

Expand All @@ -39,6 +41,20 @@ void Account::setCode(bytes&& _code)
m_codeHash = sha3(m_codeCache);
}

u256 Account::originalStorageValue(u256 const& _key, OverlayDB const& _db) const
{
auto it = m_storageOriginal.find(_key);
if (it != m_storageOriginal.end())
return it->second;

// Not in the original values cache - go to the DB.
SecureTrieDB<h256, OverlayDB> const memdb(const_cast<OverlayDB*>(&_db), m_storageRoot);
std::string const payload = memdb.at(_key);
auto const value = payload.size() ? RLP(payload).toInt<u256>() : 0;
m_storageOriginal[_key] = value;
return value;
}

namespace js = json_spirit;

namespace
Expand Down
47 changes: 21 additions & 26 deletions libethereum/Account.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@
#pragma once

#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/TrieDB.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/TrieCommon.h>
#include <libethcore/Common.h>

#include <boost/filesystem/path.hpp>

namespace dev
{
class OverlayDB;

namespace eth
{

Expand All @@ -45,20 +48,6 @@ namespace eth
* in the overlay, stored in this class and retrieved with storageOverlay(). setStorage allows the overlay
* to be altered.
*
* The code handling explicitly supports a two-stage commit model needed for contract-creation. When creating
* a contract (running the initialisation code), the code of the account is considered empty. The attribute
* of emptiness can be retrieved with codeBearing(). After initialisation one must set the code accordingly;
* the code of the Account can be set with setCode(). To validate a setCode() call, this class records the
* state of being in contract-creation (and thus in a state where setCode may validly be called). It can be
* determined through isFreshCode().
*
* The code can be retrieved through code(), and its hash through codeHash(). codeHash() is only valid when
* the account is not in the contract-creation phase (i.e. when isFreshCode() returns false). This class
* supports populating code on-demand from the state database. To determine if the code has been prepopulated
* call codeCacheValid(). To populate the code, look it up with codeHash() and populate with noteCode().
*
* @todo: need to make a noteCodeCommitted().
*
* The constructor allows you to create an one of a number of "types" of accounts. The default constructor
* makes a dead account (this is ignored by State when writing out the Trie). Another three allow a basic
* or contract account to be specified along with an initial balance. The fina two allow either a basic or
Expand Down Expand Up @@ -132,16 +121,28 @@ class Account
/// the account.
void setNonce(u256 const& _nonce) { m_nonce = _nonce; changed(); }


/// @returns the root of the trie (whose nodes are stored in the state db externally to this class)
/// which encodes the base-state of the account's storage (upon which the storage is overlaid).
h256 baseRoot() const { assert(m_storageRoot); return m_storageRoot; }

/// @returns account's storage value corresponding to the @_key
/// taking into account overlayed modifications
u256 storageValue(u256 const& _key, OverlayDB const& _db) const
{
auto mit = m_storageOverlay.find(_key);
if (mit != m_storageOverlay.end())
return mit->second;

return originalStorageValue(_key, _db);
}

/// @returns account's original storage value corresponding to the @_key
/// not taking into account overlayed modifications
u256 originalStorageValue(u256 const& _key, OverlayDB const& _db) const;

/// @returns the storage overlay as a simple hash map.
std::unordered_map<u256, u256> const& storageOverlay() const { return m_storageOverlay; }

std::unordered_map<u256, u256> const& storageOriginal() const { return m_storageOriginal; }

/// Set a key/value pair in the account's storage. This actually goes into the overlay, for committing
/// to the trie later.
void setStorage(u256 _p, u256 _v) { m_storageOverlay[_p] = _v; changed(); }
Expand All @@ -152,12 +153,6 @@ class Account
/// Set the storage root. Used when clearStorage() is reverted.
void setStorageRoot(h256 const& _root) { m_storageOverlay.clear(); m_storageRoot = _root; changed(); }

/// Set a key/value pair in the account's storage to a value that is already present inside the
/// database.
void setStorageCache(u256 _p, u256 _v) const { m_storageOverlay[_p] = _v; }

void setStorageOriginal(u256 _p, u256 _v) const { m_storageOriginal[_p] = _v; }

/// @returns the hash of the account's code.
h256 codeHash() const { return m_codeHash; }

Expand Down Expand Up @@ -210,7 +205,7 @@ class Account
/// The map with is overlaid onto whatever storage is implied by the m_storageRoot in the trie.
mutable std::unordered_map<u256, u256> m_storageOverlay;

/// The original values of the modified storage slots stored in m_storageOverlay.
/// The cache of unmodifed storage items
mutable std::unordered_map<u256, u256> m_storageOriginal;

/// The associated code for this account. The SHA3 of this should be equal to m_codeHash unless
Expand Down
35 changes: 35 additions & 0 deletions libethereum/SecureTrieDB.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
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 <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <libdevcore/TrieDB.h>

namespace dev
{
namespace eth
{
#if ETH_FATDB
template <class KeyType, class DB>
using SecureTrieDB = SpecificTrieDB<FatGenericTrieDB<DB>, KeyType>;
#else
template <class KeyType, class DB>
using SecureTrieDB = SpecificTrieDB<HashedGenericTrieDB<DB>, KeyType>;
#endif

} // namespace eth
} // namespace dev
33 changes: 3 additions & 30 deletions libethereum/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,48 +418,21 @@ u256 State::getNonce(Address const& _addr) const
u256 State::storage(Address const& _id, u256 const& _key) const
{
if (Account const* a = account(_id))
{
auto mit = a->storageOverlay().find(_key);
if (mit != a->storageOverlay().end())
return mit->second;

// Not in the storage cache - go to the DB.
SecureTrieDB<h256, OverlayDB> memdb(const_cast<OverlayDB*>(&m_db), a->baseRoot()); // promise we won't change the overlay! :)
string payload = memdb.at(_key);
u256 ret = payload.size() ? RLP(payload).toInt<u256>() : 0;
a->setStorageCache(_key, ret);
a->setStorageOriginal(_key, ret);
return ret;
}
return a->storageValue(_key, m_db);
else
return 0;
}

void State::setStorage(Address const& _contract, u256 const& _key, u256 const& _value)
{
m_changeLog.emplace_back(_contract, _key, storage(_contract, _key));
Account& a = m_cache[_contract];
a.setStorage(_key, _value);
if (a.storageOriginal().find(_key) == a.storageOriginal().end())
{
SecureTrieDB<h256, OverlayDB> memdb(const_cast<OverlayDB*>(&m_db), a.baseRoot());
string payload = memdb.at(_key);
u256 original = payload.size() ? RLP(payload).toInt<u256>() : 0;
a.setStorageOriginal(_key, original);
}
m_cache[_contract].setStorage(_key, _value);
}

u256 State::originalStorageValue(Address const& _contract, u256 const& _key) const
{
if (Account const* a = account(_contract))
{
auto it = a->storageOriginal().find(_key);
if (it != a->storageOriginal().end())
return it->second;

assert(a->storageOverlay().find(_key) == a->storageOverlay().end());
return storage(_contract, _key);
}
return a->originalStorageValue(_key, m_db);
else
return 0;
}
Expand Down
47 changes: 24 additions & 23 deletions libethereum/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@

#pragma once

#include <array>
#include <unordered_map>
#include "Account.h"
#include "GasPricer.h"
#include "SecureTrieDB.h"
#include "Transaction.h"
#include "TransactionReceipt.h"
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/TrieDB.h>
#include <libdevcore/OverlayDB.h>
#include <libethcore/Exceptions.h>
#include <libdevcore/RLP.h>
#include <libethcore/BlockHeader.h>
#include <libethcore/Exceptions.h>
#include <libethereum/CodeSizeCache.h>
#include <libevm/ExtVMFace.h>
#include "Account.h"
#include "Transaction.h"
#include "TransactionReceipt.h"
#include "GasPricer.h"
#include <array>
#include <unordered_map>

namespace dev
{
Expand Down Expand Up @@ -73,15 +73,9 @@ enum class Permanence
{
Reverted,
Committed,
Uncommitted ///< Uncommitted state for change log readings in tests.
Uncommitted ///< Uncommitted state for change log readings in tests.
};

#if ETH_FATDB
template <class KeyType, class DB> using SecureTrieDB = SpecificTrieDB<FatGenericTrieDB<DB>, KeyType>;
#else
template <class KeyType, class DB> using SecureTrieDB = SpecificTrieDB<HashedGenericTrieDB<DB>, KeyType>;
#endif

DEV_SIMPLE_EXCEPTION(InvalidAccountStartNonceInState);
DEV_SIMPLE_EXCEPTION(IncorrectAccountStartNonceInState);

Expand Down Expand Up @@ -327,7 +321,7 @@ class State
u256 const& requireAccountStartNonce() const;
void noteAccountStartNonce(u256 const& _actual);

/// Create a savepoint in the state changelog. ///
/// Create a savepoint in the state changelog.
/// @return The savepoint index that can be used in rollback() function.
size_t savepoint() const;

Expand Down Expand Up @@ -357,12 +351,19 @@ class State
/// exception occurred.
bool executeTransaction(Executive& _e, Transaction const& _t, OnOpFunc const& _onOp);

OverlayDB m_db; ///< Our overlay for the state tree.
SecureTrieDB<Address, OverlayDB> m_state; ///< Our state tree, as an OverlayDB DB.
mutable std::unordered_map<Address, Account> m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed.
mutable std::vector<Address> m_unchangedCacheEntries; ///< Tracks entries in m_cache that can potentially be purged if it grows too large.
mutable std::set<Address> m_nonExistingAccountsCache; ///< Tracks addresses that are known to not exist.
AddressHash m_touched; ///< Tracks all addresses touched so far.
/// Our overlay for the state tree.
OverlayDB m_db;
/// Our state tree, as an OverlayDB DB.
SecureTrieDB<Address, OverlayDB> m_state;
/// Our address cache. This stores the states of each address that has (or at least might have)
/// been changed.
mutable std::unordered_map<Address, Account> m_cache;
/// Tracks entries in m_cache that can potentially be purged if it grows too large.
mutable std::vector<Address> m_unchangedCacheEntries;
/// Tracks addresses that are known to not exist.
mutable std::set<Address> m_nonExistingAccountsCache;
/// Tracks all addresses touched so far.
AddressHash m_touched;

u256 m_accountStartNonce;

Expand Down

0 comments on commit ac80201

Please sign in to comment.