Browse Source

Transaction manifest.

cl-refactor
Gav Wood 11 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; h256 nonce;
BlockInfo(); BlockInfo();
explicit BlockInfo(bytes const& _block): BlockInfo(&_block) {}
explicit BlockInfo(bytesConstRef _block); explicit BlockInfo(bytesConstRef _block);
static BlockInfo fromHeader(bytesConstRef _block); static BlockInfo fromHeader(bytesConstRef _block);
@ -96,6 +97,7 @@ public:
void populateFromHeader(RLP const& _header, bool _checkNonce = true); void populateFromHeader(RLP const& _header, bool _checkNonce = true);
void populate(bytesConstRef _block, 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 verifyInternals(bytesConstRef _block) const;
void verifyParent(BlockInfo const& _parent) const; void verifyParent(BlockInfo const& _parent) const;
void populateFromParent(BlockInfo const& parent); 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: private:
std::array<byte, N> m_data; ///< The binary data. 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() void BlockChain::checkConsistency()
{ {
lock_guard<mutex> l(m_lock);
m_details.clear(); m_details.clear();
ldb::Iterator* it = m_detailsDB->NewIterator(m_readOptions); ldb::Iterator* it = m_detailsDB->NewIterator(m_readOptions);
for (it->SeekToFirst(); it->Valid(); it->Next()) for (it->SeekToFirst(); it->Valid(); it->Next())
@ -302,19 +303,23 @@ void BlockChain::checkConsistency()
delete it; delete it;
} }
bytesConstRef BlockChain::block(h256 _hash) const bytes BlockChain::block(h256 _hash) const
{ {
if (_hash == m_genesisHash) 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; string d;
m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d); m_db->Get(m_readOptions, ldb::Slice((char const*)&_hash, 32), &d);
{ m_cache[_hash].resize(d.size());
lock_guard<mutex> l(m_lock); memcpy(m_cache[_hash].data(), d.data(), d.size());
swap(m_cache[_hash], d); return m_cache[_hash];
return bytesConstRef(&m_cache[_hash]);
}
} }
eth::uint BlockChain::number(h256 _hash) const eth::uint BlockChain::number(h256 _hash) const
@ -331,29 +336,24 @@ h256 BlockChain::numberHash(unsigned _n) const
return ret; return ret;
} }
BlockDetails const& BlockChain::details(h256 _h) const BlockDetails BlockChain::details(h256 _h) const
{ {
BlockDetailsHash::const_iterator it; lock_guard<mutex> l(m_lock);
bool fetchRequired;
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); // cout << "Not found in DB: " << _h << endl;
it = m_details.find(_h); return NullBlockDetails;
fetchRequired = (it == m_details.end());
} }
if (fetchRequired)
{ {
std::string s; bool ok;
m_detailsDB->Get(m_readOptions, ldb::Slice((char const*)&_h, 32), &s); tie(it, ok) = m_details.insert(std::make_pair(_h, BlockDetails(RLP(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))));
}
} }
return it->second; 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. * @brief Implements the blockchain database. All data this gives is disk-backed.
* @todo Make thread-safe. * @todo Make thread-safe.
* @todo Make not memory hog.
*/ */
class BlockChain class BlockChain
{ {
@ -90,12 +91,12 @@ public:
void import(bytes const& _block, OverlayDB const& _stateDB); void import(bytes const& _block, OverlayDB const& _stateDB);
/// Get the number of the last block of the longest chain. /// Get the number of the last block of the longest chain.
BlockDetails const& details(h256 _hash) const; BlockDetails details(h256 _hash) const;
BlockDetails const& details() const { return details(currentHash()); } BlockDetails details() const { return details(currentHash()); }
/// Get a given block (RLP format). Thread-safe. /// Get a given block (RLP format). Thread-safe.
bytesConstRef block(h256 _hash) const; bytes block(h256 _hash) const;
bytesConstRef block() const { return block(currentHash()); } bytes block() const { return block(currentHash()); }
uint number(h256 _hash) const; uint number(h256 _hash) const;
uint number() const { return number(currentHash()); } uint number() const { return number(currentHash()); }
@ -121,7 +122,7 @@ private:
/// Get fully populated from disk DB. /// Get fully populated from disk DB.
mutable BlockDetailsHash m_details; mutable BlockDetailsHash m_details;
mutable std::map<h256, std::string> m_cache; mutable std::map<h256, bytes> m_cache;
mutable std::mutex m_lock; mutable std::mutex m_lock;
/// The queue of transactions that have happened that we're interested in. /// 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) << ")"; // cnote << "Paying" << formatBalance(cost) << "from sender (includes" << m_t.gas << "gas at" << formatBalance(m_t.gasPrice) << ")";
m_s.subBalance(m_sender, cost); 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()) if (m_t.isCreation())
return create(m_sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, m_sender); return create(m_sender, m_t.value, m_t.gasPrice, m_t.gas - gasCost, &m_t.data, m_sender);
else else
@ -109,7 +116,7 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu
{ {
m_vm = new VM(_gas); m_vm = new VM(_gas);
bytes const& c = m_s.code(_receiveAddress); 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 else
m_endGas = _gas; m_endGas = _gas;
@ -129,7 +136,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
// Execute _init. // Execute _init.
m_vm = new VM(_gas); 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(); return _init.empty();
} }
@ -230,6 +237,9 @@ void Executive::finalize()
// cnote << "Transferring" << formatBalance(gasSpent) << "to miner."; // cnote << "Transferring" << formatBalance(gasSpent) << "to miner.";
m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned);
if (m_ms)
m_ms->output = m_out.toBytes();
// Suicides... // Suicides...
if (m_ext) if (m_ext)
for (auto a: m_ext->suicides) 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 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 class Executive
{ {
public: public:
Executive(State& _s): m_s(_s) {} Executive(State& _s, Manifest* o_ms = nullptr): m_s(_s), m_ms(o_ms) {}
~Executive(); ~Executive();
bool setup(bytesConstRef _transaction); bool setup(bytesConstRef _transaction);
@ -62,6 +78,7 @@ private:
State& m_s; State& m_s;
ExtVM* m_ext = nullptr; // TODO: make safe. ExtVM* m_ext = nullptr; // TODO: make safe.
VM* m_vm = nullptr; VM* m_vm = nullptr;
Manifest* m_ms = nullptr;
bytesConstRef m_out; bytesConstRef m_out;
Address m_newAddress; Address m_newAddress;

22
libethereum/ExtVM.h

@ -36,8 +36,8 @@ class ExtVM: public ExtVMFace
{ {
public: public:
/// Full constructor. /// Full constructor.
ExtVM(State& _s, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code): 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) 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); m_s.ensureCached(_myAddress, true, true);
} }
@ -46,20 +46,28 @@ public:
u256 store(u256 _n) { return m_s.storage(myAddress, _n); } u256 store(u256 _n) { return m_s.storage(myAddress, _n); }
/// Write a value in storage. /// 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. /// Create a new contract.
h160 create(u256 _endowment, u256* _gas, bytesConstRef _code) h160 create(u256 _endowment, u256* _gas, bytesConstRef _code)
{ {
// Increment associated nonce for sender. // Increment associated nonce for sender.
m_s.noteSending(myAddress); 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. /// Create a new message call.
bool call(Address _receiveAddress, u256 _txValue, bytesConstRef _txData, u256* _gas, bytesRef _out) 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. /// Read address's balance.
@ -79,11 +87,13 @@ public:
} }
/// Revert any changes made (by any of the other calls). /// 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: private:
State& m_s; ///< A reference to the base state. 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. 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; m_ourAddress = bi.coinbaseAddress;
sync(_bc, bi.parentHash, bip); sync(_bc, bi.parentHash, bip);
enact(b); enact(&b);
} }
State::State(State const& _s): 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) for (auto it = chain.rbegin(); it != chain.rend(); ++it)
{ {
auto b = _bc.block(*it); auto b = _bc.block(*it);
enact(b); enact(&b);
cleanup(true); 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. // 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 #ifndef ETH_RELEASE
commit(); // get an updated hash commit(); // get an updated hash
@ -967,7 +967,7 @@ u256 State::execute(bytesConstRef _rlp)
auto h = rootHash(); auto h = rootHash();
#endif #endif
Executive e(*this); Executive e(*this, o_ms);
e.setup(_rlp); e.setup(_rlp);
u256 startGasUsed = gasUsed(); u256 startGasUsed = gasUsed();
@ -985,6 +985,15 @@ u256 State::execute(bytesConstRef _rlp)
ctrace << old.diff(*this); ctrace << old.diff(*this);
#endif #endif
if (o_output)
*o_output = e.out().toBytes();
if (!_commit)
{
m_cache.clear();
return e.gasUsed();
}
commit(); commit();
#if ETH_PARANOIA #if ETH_PARANOIA
@ -1012,7 +1021,7 @@ u256 State::execute(bytesConstRef _rlp)
return e.gasUsed(); 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) if (!_originAddress)
_originAddress = _senderAddress; _originAddress = _senderAddress;
@ -1020,10 +1029,17 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u
// cnote << "Transferring" << formatBalance(_value) << "to receiver."; // cnote << "Transferring" << formatBalance(_value) << "to receiver.";
addBalance(_receiveAddress, _value); addBalance(_receiveAddress, _value);
if (o_ms)
{
o_ms->from = _senderAddress;
o_ms->to = _receiveAddress;
o_ms->input = _data.toBytes();
}
if (addressHasCode(_receiveAddress)) if (addressHasCode(_receiveAddress))
{ {
VM vm(*_gas); 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; bool revert = false;
try try
@ -1033,6 +1049,8 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u
if (o_suicides) if (o_suicides)
for (auto i: evm.suicides) for (auto i: evm.suicides)
o_suicides->insert(i); o_suicides->insert(i);
if (o_ms)
o_ms->output = out.toBytes();
} }
catch (OutOfGas const& /*_e*/) catch (OutOfGas const& /*_e*/)
{ {
@ -1063,11 +1081,18 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u
return true; 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) if (!_origin)
_origin = _sender; _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))); Address newAddress = right160(sha3(rlpList(_sender, transactionsFrom(_sender) - 1)));
while (addressInUse(newAddress)) while (addressInUse(newAddress))
newAddress = (u160)newAddress + 1; newAddress = (u160)newAddress + 1;
@ -1077,13 +1102,15 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
// Execute init code. // Execute init code.
VM vm(*_gas); 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; bool revert = false;
bytesConstRef out; bytesConstRef out;
try try
{ {
out = vm.go(evm); out = vm.go(evm);
if (o_ms)
o_ms->output = out.toBytes();
if (o_suicides) if (o_suicides)
for (auto i: evm.suicides) for (auto i: evm.suicides)
o_suicides->insert(i); 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(); 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. // Write state out only in the case of a non-out-of-gas transaction.
if (revert) if (revert)
evm.revert(); evm.revert();

10
libethereum/State.h

@ -184,8 +184,8 @@ public:
/// Execute a given transaction. /// Execute a given transaction.
/// This will append @a _t to the transaction list and change the state accordingly. /// This will append @a _t to the transaction list and change the state accordingly.
u256 execute(bytes const& _rlp) { return execute(&_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); u256 execute(bytesConstRef _rlp, bytes* o_output = nullptr, bool _commit = true, Manifest* o_ms = nullptr);
/// Check if the address is in use. /// Check if the address is in use.
bool addressInUse(Address _address) const; bool addressInUse(Address _address) const;
@ -300,16 +300,16 @@ private:
/// Throws on failure. /// Throws on failure.
u256 enact(bytesConstRef _block, BlockInfo const& _grandParent = BlockInfo(), bool _checkNonce = true); 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. // We assume all instrinsic fees are paid up before this point.
/// Execute a contract-creation transaction. /// 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. /// Execute a call.
/// @a _gas points to the amount of gas to use for the call, and will lower it accordingly. /// @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. /// @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). /// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent(); void resetCurrent();

Loading…
Cancel
Save