Browse Source

Transaction manifest.

cl-refactor
Gav Wood 10 years ago
parent
commit
cc31ebd40b
  1. 2
      libethcore/BlockInfo.h
  2. 9
      libethential/FixedHash.h
  3. 52
      libethereum/BlockChain.cpp
  4. 11
      libethereum/BlockChain.h
  5. 14
      libethereum/Executive.cpp
  6. 19
      libethereum/Executive.h
  7. 22
      libethereum/ExtVM.h
  8. 45
      libethereum/State.cpp
  9. 10
      libethereum/State.h

2
libethcore/BlockInfo.h

@ -70,6 +70,7 @@ public:
h256 nonce;
BlockInfo();
explicit BlockInfo(bytes const& _block): BlockInfo(&_block) {}
explicit BlockInfo(bytesConstRef _block);
static BlockInfo fromHeader(bytesConstRef _block);
@ -96,6 +97,7 @@ public:
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); }
void verifyInternals(bytesConstRef _block) const;
void verifyParent(BlockInfo const& _parent) const;
void populateFromParent(BlockInfo const& parent);

9
libethential/FixedHash.h

@ -137,6 +137,15 @@ public:
}
};
inline FixedHash<32> bloom() const
{
FixedHash<32> ret;
for (auto i: m_data)
ret[i / 8] |= 1 << (i % 8);
return ret;
}
private:
std::array<byte, N> m_data; ///< The binary data.
};

52
libethereum/BlockChain.cpp

@ -284,6 +284,7 @@ void BlockChain::import(bytes const& _block, OverlayDB const& _db)
void BlockChain::checkConsistency()
{
lock_guard<mutex> l(m_lock);
m_details.clear();
ldb::Iterator* it = m_detailsDB->NewIterator(m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next())
@ -302,19 +303,23 @@ void BlockChain::checkConsistency()
delete it;
}
bytesConstRef BlockChain::block(h256 _hash) const
bytes BlockChain::block(h256 _hash) const
{
if (_hash == m_genesisHash)
return &m_genesisBlock;
return m_genesisBlock;
lock_guard<mutex> l(m_lock);
auto it = m_cache.find(_hash);
if (it != m_cache.end())
return it->second;
string d;
m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d);
{
lock_guard<mutex> l(m_lock);
swap(m_cache[_hash], d);
return bytesConstRef(&m_cache[_hash]);
}
m_cache[_hash].resize(d.size());
memcpy(m_cache[_hash].data(), d.data(), d.size());
return m_cache[_hash];
}
eth::uint BlockChain::number(h256 _hash) const
@ -331,29 +336,24 @@ h256 BlockChain::numberHash(unsigned _n) const
return ret;
}
BlockDetails const& BlockChain::details(h256 _h) const
BlockDetails BlockChain::details(h256 _h) const
{
BlockDetailsHash::const_iterator it;
bool fetchRequired;
lock_guard<mutex> l(m_lock);
BlockDetailsHash::const_iterator it = m_details.find(_h);
if (it != m_details.end())
return it->second;
std::string s;
m_detailsDB->Get(m_readOptions, ldb::Slice((char const*)&_h, 32), &s);
if (s.empty())
{
lock_guard<mutex> l(m_lock);
it = m_details.find(_h);
fetchRequired = (it == m_details.end());
// cout << "Not found in DB: " << _h << endl;
return NullBlockDetails;
}
if (fetchRequired)
{
std::string s;
m_detailsDB->Get(m_readOptions, ldb::Slice((char const*)&_h, 32), &s);
if (s.empty())
{
// cout << "Not found in DB: " << _h << endl;
return NullBlockDetails;
}
{
lock_guard<mutex> l(m_lock);
bool ok;
tie(it, ok) = m_details.insert(std::make_pair(_h, BlockDetails(RLP(s))));
}
bool ok;
tie(it, ok) = m_details.insert(std::make_pair(_h, BlockDetails(RLP(s))));
}
return it->second;
}

11
libethereum/BlockChain.h

@ -71,6 +71,7 @@ std::map<Address, AddressState> const& genesisState();
/**
* @brief Implements the blockchain database. All data this gives is disk-backed.
* @todo Make thread-safe.
* @todo Make not memory hog.
*/
class BlockChain
{
@ -90,12 +91,12 @@ public:
void import(bytes const& _block, OverlayDB const& _stateDB);
/// Get the number of the last block of the longest chain.
BlockDetails const& details(h256 _hash) const;
BlockDetails const& details() const { return details(currentHash()); }
BlockDetails details(h256 _hash) const;
BlockDetails details() const { return details(currentHash()); }
/// Get a given block (RLP format). Thread-safe.
bytesConstRef block(h256 _hash) const;
bytesConstRef block() const { return block(currentHash()); }
bytes block(h256 _hash) const;
bytes block() const { return block(currentHash()); }
uint number(h256 _hash) const;
uint number() const { return number(currentHash()); }
@ -121,7 +122,7 @@ private:
/// Get fully populated from disk DB.
mutable BlockDetailsHash m_details;
mutable std::map<h256, std::string> m_cache;
mutable std::map<h256, bytes> m_cache;
mutable std::mutex m_lock;
/// The queue of transactions that have happened that we're interested in.

14
libethereum/Executive.cpp

@ -94,6 +94,13 @@ bool Executive::setup(bytesConstRef _rlp)
// cnote << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas << "gas at" << formatBalance(m_t.gasPrice) << ")";
m_s.subBalance(m_sender, cost);
if (m_ms)
{
m_ms->from = m_sender;
m_ms->to = m_t.receiveAddress;
m_ms->input = m_t.data;
}
if (m_t.isCreation())
return create(m_sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, m_sender);
else
@ -109,7 +116,7 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu
{
m_vm = new VM(_gas);
bytes const& c = m_s.code(_receiveAddress);
m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c);
m_ext = new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c, m_ms);
}
else
m_endGas = _gas;
@ -129,7 +136,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
// Execute _init.
m_vm = new VM(_gas);
m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init);
m_ext = new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_ms);
return _init.empty();
}
@ -230,6 +237,9 @@ void Executive::finalize()
// cnote << "Transferring" << formatBalance(gasSpent) << "to miner.";
m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned);
if (m_ms)
m_ms->output = m_out.toBytes();
// Suicides...
if (m_ext)
for (auto a: m_ext->suicides)

19
libethereum/Executive.h

@ -34,10 +34,26 @@ class State;
struct VMTraceChannel: public LogChannel { static const char* name() { return "EVM"; } static const int verbosity = 11; };
struct Manifest;
using Manifests = std::vector<Manifest>;
/**
* @brief A record of the state-interaction of a transaction/call/create.
*/
struct Manifest
{
Address from;
Address to;
u256s altered;
bytes input;
bytes output;
Manifests internal;
};
class Executive
{
public:
Executive(State& _s): m_s(_s) {}
Executive(State& _s, Manifest* o_ms = nullptr): m_s(_s), m_ms(o_ms) {}
~Executive();
bool setup(bytesConstRef _transaction);
@ -62,6 +78,7 @@ private:
State& m_s;
ExtVM* m_ext = nullptr; // TODO: make safe.
VM* m_vm = nullptr;
Manifest* m_ms = nullptr;
bytesConstRef m_out;
Address m_newAddress;

22
libethereum/ExtVM.h

@ -36,8 +36,8 @@ class ExtVM: public ExtVMFace
{
public:
/// Full constructor.
ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code):
ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock), m_s(_s), m_origCache(_s.m_cache)
ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, Manifest* o_ms):
ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code, _s.m_previousBlock, _s.m_currentBlock), m_s(_s), m_origCache(_s.m_cache), m_ms(o_ms)
{
m_s.ensureCached(_myAddress, true, true);
}
@ -46,20 +46,28 @@ public:
u256 store(u256 _n) { return m_s.storage(myAddress, _n); }
/// Write a value in storage.
void setStore(u256 _n, u256 _v) { m_s.setStorage(myAddress, _n, _v); }
void setStore(u256 _n, u256 _v) { m_s.setStorage(myAddress, _n, _v); if (m_ms) m_ms->altered.push_back(_n); }
/// Create a new contract.
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code)
{
// Increment associated nonce for sender.
m_s.noteSending(myAddress);
return m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides);
m_ms->internal.resize(m_ms->internal.size() + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, &(m_ms->internal.back()));
if (!m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;
}
/// Create a new message call.
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out)
{
return m_s.call(_receiveAddress, myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides);
m_ms->internal.resize(m_ms->internal.size() + 1);
auto ret = m_s.call(_receiveAddress, myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, &(m_ms->internal.back()));
if (!m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;
}
/// Read address's balance.
@ -79,11 +87,13 @@ public:
}
/// Revert any changes made (by any of the other calls).
void revert() { m_s.m_cache = m_origCache; }
/// @TODO check call site for the parent manifest being discarded.
void revert() { if (m_ms) *m_ms = Manifest(); m_s.m_cache = m_origCache; }
private:
State& m_s; ///< A reference to the base state.
std::map<Address, AddressState> m_origCache; ///< The cache of the address states (i.e. the externalities) as-was prior to the execution.
Manifest* m_ms;
};
}

45
libethereum/State.cpp

@ -104,7 +104,7 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h):
m_ourAddress = bi.coinbaseAddress;
sync(_bc, bi.parentHash, bip);
enact(b);
enact(&b);
}
State::State(State const& _s):
@ -362,7 +362,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi)
for (auto it = chain.rbegin(); it != chain.rend(); ++it)
{
auto b = _bc.block(*it);
enact(b);
enact(&b);
cleanup(true);
}
}
@ -954,7 +954,7 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const
// TODO: maintain node overlay revisions for stateroots -> each commit gives a stateroot + OverlayDB; allow overlay copying for rewind operations.
u256 State::execute(bytesConstRef _rlp)
u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit, Manifest* o_ms)
{
#ifndef ETH_RELEASE
commit(); // get an updated hash
@ -967,7 +967,7 @@ u256 State::execute(bytesConstRef _rlp)
auto h = rootHash();
#endif
Executive e(*this);
Executive e(*this, o_ms);
e.setup(_rlp);
u256 startGasUsed = gasUsed();
@ -985,6 +985,15 @@ u256 State::execute(bytesConstRef _rlp)
ctrace << old.diff(*this);
#endif
if (o_output)
*o_output = e.out().toBytes();
if (!_commit)
{
m_cache.clear();
return e.gasUsed();
}
commit();
#if ETH_PARANOIA
@ -1012,7 +1021,7 @@ u256 State::execute(bytesConstRef _rlp)
return e.gasUsed();
}
bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, std::set<Address>* o_suicides)
bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, std::set<Address>* o_suicides, Manifest* o_ms)
{
if (!_originAddress)
_originAddress = _senderAddress;
@ -1020,10 +1029,17 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u
// cnote << "Transferring" << formatBalance(_value) << "to receiver.";
addBalance(_receiveAddress, _value);
if (o_ms)
{
o_ms->from = _senderAddress;
o_ms->to = _receiveAddress;
o_ms->input = _data.toBytes();
}
if (addressHasCode(_receiveAddress))
{
VM vm(*_gas);
ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_receiveAddress));
ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_receiveAddress), o_ms);
bool revert = false;
try
@ -1033,6 +1049,8 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
if (o_ms)
o_ms->output = out.toBytes();
}
catch (OutOfGas const& /*_e*/)
{
@ -1063,11 +1081,18 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u
return true;
}
h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides)
h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides, Manifest* o_ms)
{
if (!_origin)
_origin = _sender;
if (o_ms)
{
o_ms->from = _sender;
o_ms->to = Address();
o_ms->input = _code.toBytes();
}
Address newAddress = right160(sha3(rlpList(_sender, transactionsFrom(_sender) - 1)));
while (addressInUse(newAddress))
newAddress = (u160)newAddress + 1;
@ -1077,13 +1102,15 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
// Execute init code.
VM vm(*_gas);
ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code);
ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, o_ms);
bool revert = false;
bytesConstRef out;
try
{
out = vm.go(evm);
if (o_ms)
o_ms->output = out.toBytes();
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
@ -1106,6 +1133,8 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
clog(StateChat) << "std::exception in VM: " << _e.what();
}
// TODO: CHECK: IS THIS CORRECT?! (esp. given account created prior to revertion init.)
// Write state out only in the case of a non-out-of-gas transaction.
if (revert)
evm.revert();

10
libethereum/State.h

@ -184,8 +184,8 @@ public:
/// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly.
u256 execute(bytes const& _rlp) { return execute(&_rlp); }
u256 execute(bytesConstRef _rlp);
u256 execute(bytes const& _rlp, bytes* o_output = nullptr, bool _commit = true, Manifest* o_ms = nullptr) { return execute(&_rlp, o_output, _commit, o_ms); }
u256 execute(bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true, Manifest* o_ms = nullptr);
/// Check if the address is in use.
bool addressInUse(Address _address) const;
@ -300,16 +300,16 @@ private:
/// Throws on failure.
u256 enact(bytesConstRef _block, BlockInfo const& _grandParent = BlockInfo(), bool _checkNonce = true);
// Two priviledged entry points for transaction processing used by the VM (these don't get added to the Transaction lists):
// Two priviledged entry points for the VM (these don't get added to the Transaction lists):
// We assume all instrinsic fees are paid up before this point.
/// Execute a contract-creation transaction.
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr);
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, Manifest* o_ms = nullptr);
/// Execute a call.
/// @a _gas points to the amount of gas to use for the call, and will lower it accordingly.
/// @returns false if the call ran out of gas before completion. true otherwise.
bool call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr);
bool call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), std::set<Address>* o_suicides = nullptr, Manifest* o_ms = nullptr);
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent();

Loading…
Cancel
Save