Browse Source

Demonstration of how to create a completely custom state for execution

of transactions.
cl-refactor
Gav Wood 10 years ago
parent
commit
0cd39343eb
  1. 13
      exp/main.cpp
  2. 19
      libethcore/BlockInfo.cpp
  3. 2
      libethcore/BlockInfo.h
  4. 1
      libethereum/ExtVM.h
  5. 39
      libethereum/State.cpp
  6. 7
      libethereum/State.h

13
exp/main.cpp

@ -29,6 +29,7 @@
#include <libdevcore/RangeMask.h>
#include <libethereum/DownloadMan.h>
#include <libethereum/All.h>
#include <liblll/All.h>
#include <libwhisper/WhisperPeer.h>
#include <libwhisper/WhisperHost.h>
using namespace std;
@ -79,11 +80,19 @@ int main()
KeyPair u = KeyPair::create();
KeyPair cb = KeyPair::create();
OverlayDB db;
State s(cb.address(), db);
State s(cb.address(), db, BaseState::Empty);
cnote << s.rootHash();
s.addBalance(u.address(), 1000 * ether);
s.addBalance(u.address(), 1 * ether);
Address c = s.newContract(1000 * ether, compileLLL("(suicide (caller))"));
s.commit();
cnote << s.rootHash();
State before = s;
cnote << s;
Transaction t(0, 10000, 10000, c, bytes(), 0, u.secret());
cnote << s.balance(c);
s.execute(t.rlp());
cnote << before.diff(s);
cnote << s;
}
#endif

19
libethcore/BlockInfo.cpp

@ -40,6 +40,25 @@ BlockInfo::BlockInfo(bytesConstRef _block, bool _checkNonce)
populate(_block, _checkNonce);
}
void BlockInfo::setEmpty()
{
parentHash = h256();
sha3Uncles = EmptyListSHA3;
coinbaseAddress = Address();
stateRoot = EmptyTrie;
transactionsRoot = EmptyTrie;
receiptsRoot = EmptyTrie;
logBloom = LogBloom();
difficulty = 0;
number = 0;
gasLimit = 0;
gasUsed = 0;
timestamp = 0;
extraData.clear();
nonce = h256();
hash = headerHash(WithNonce);
}
BlockInfo BlockInfo::fromHeader(bytesConstRef _block)
{
BlockInfo ret;

2
libethcore/BlockInfo.h

@ -108,6 +108,8 @@ public:
}
bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); }
void setEmpty();
void populateFromHeader(RLP const& _header, bool _checkNonce = true);
void populate(bytesConstRef _block, bool _checkNonce = true);
void populate(bytes const& _block, bool _checkNonce = true) { populate(&_block, _checkNonce); }

1
libethereum/ExtVM.h

@ -73,6 +73,7 @@ public:
virtual void suicide(Address _a) override final
{
m_s.addBalance(_a, m_s.balance(myAddress));
m_s.subBalance(myAddress, m_s.balance(myAddress));
ExtVMFace::suicide(_a);
}

39
libethereum/State.cpp

@ -63,7 +63,7 @@ OverlayDB State::openDB(std::string _path, bool _killExisting)
return OverlayDB(db);
}
State::State(Address _coinbaseAddress, OverlayDB const& _db):
State::State(Address _coinbaseAddress, OverlayDB const& _db, BaseState _bs):
m_db(_db),
m_state(&m_db),
m_ourAddress(_coinbaseAddress),
@ -74,12 +74,19 @@ State::State(Address _coinbaseAddress, OverlayDB const& _db):
paranoia("beginning of normal construction.", true);
dev::eth::commit(genesisState(), m_db, m_state);
m_db.commit();
if (_bs == BaseState::Genesis)
{
dev::eth::commit(genesisState(), m_db, m_state);
m_db.commit();
paranoia("after DB commit of normal construction.", true);
paranoia("after DB commit of normal construction.", true);
m_previousBlock = BlockChain::genesis();
}
else
{
m_previousBlock.setEmpty();
}
m_previousBlock = BlockChain::genesis();
resetCurrent();
assert(m_state.root() == m_previousBlock.stateRoot);
@ -857,6 +864,23 @@ void State::subBalance(Address _id, bigint _amount)
it->second.addBalance(-_amount);
}
Address State::newContract(u256 _balance, bytes const& _code)
{
auto h = sha3(_code);
m_db.insert(h, &_code);
while (true)
{
Address ret = Address::random();
ensureCached(ret, false, false);
auto it = m_cache.find(ret);
if (it == m_cache.end())
{
m_cache[ret] = Account(0, _balance, EmptyTrie, h);
return ret;
}
}
}
u256 State::transactionsFrom(Address _id) const
{
ensureCached(_id, false, false);
@ -993,8 +1017,11 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
ctrace << "Executing" << e.t() << "on" << h;
ctrace << toHex(e.t().rlp());
#endif
#if ETH_TRACE
e.go(e.simpleTrace());
#else
e.go();
#endif
e.finalize();
#if ETH_PARANOIA

7
libethereum/State.h

@ -53,6 +53,8 @@ struct StateTrace: public LogChannel { static const char* name() { return "=S=";
struct StateDetail: public LogChannel { static const char* name() { return "/S/"; } static const int verbosity = 14; };
struct StateSafeExceptions: public LogChannel { static const char* name() { return "(S)"; } static const int verbosity = 21; };
enum class BaseState { Empty, Genesis };
/**
* @brief Model of the current state of the ledger.
* Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block).
@ -66,7 +68,7 @@ class State
public:
/// Construct state object.
State(Address _coinbaseAddress = Address(), OverlayDB const& _db = OverlayDB());
State(Address _coinbaseAddress = Address(), OverlayDB const& _db = OverlayDB(), BaseState _bs = BaseState::Genesis);
/// Construct state object from arbitrary point in blockchain.
State(OverlayDB const& _db, BlockChain const& _bc, h256 _hash);
@ -183,6 +185,9 @@ public:
/// Set the value of a storage position of an account.
void setStorage(Address _contract, u256 _location, u256 _value) { m_cache[_contract].setStorage(_location, _value); }
/// Create a new contract.
Address newContract(u256 _balance, bytes const& _code);
/// Get the storage of an account.
/// @note This is expensive. Don't use it unless you need to.
/// @returns std::map<u256, u256> if no account exists at that address.

Loading…
Cancel
Save