Browse Source

Move suicides into SubState and include logs and refunds.

Refund gas from zero-resetting SSTOREs.
cl-refactor
Gav Wood 10 years ago
parent
commit
52e385905e
  1. 30
      libdevcore/CommonData.h
  2. 4
      libethereum/Executive.cpp
  3. 3
      libethereum/Executive.h
  4. 4
      libethereum/ExtVM.h
  5. 16
      libethereum/State.cpp
  6. 4
      libethereum/State.h
  7. 28
      libevm/ExtVMFace.h
  8. 4
      libevm/FeeStructure.cpp
  9. 4
      libevm/FeeStructure.h
  10. 7
      libevm/VM.h
  11. 24
      test/vm.cpp
  12. 2
      test/vm.h

30
libdevcore/CommonData.h

@ -190,7 +190,7 @@ void pushFront(_T& _t, _U _e)
_t[0] = _e;
}
/// Concatenate two vectors of elements. _T must be POD.
/// Concatenate two vectors of elements of POD types.
template <class _T>
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b)
{
@ -201,30 +201,38 @@ inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<std::is_p
}
/// Concatenate two vectors of elements. _T must be POD.
/// Concatenate two vectors of elements.
template <class _T>
inline std::vector<_T> operator+(std::vector<typename std::enable_if<std::is_pod<_T>::value, _T>::type> const& _a, std::vector<_T> const& _b)
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<!std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b)
{
_a.reserve(_a.size() + _b.size());
for (auto& i: _b)
_a.push_back(i);
return _a;
}
/// Concatenate two vectors of elements.
template <class _T>
inline std::vector<_T> operator+(std::vector<_T> const& _a, std::vector<_T> const& _b)
{
std::vector<_T> ret(_a);
return ret += _b;
}
/// Concatenate two vectors of elements. _T must be POD.
/// Merge two sets of elements.
template <class _T>
inline std::vector<_T>& operator+=(std::vector<typename std::enable_if<!std::is_pod<_T>::value, _T>::type>& _a, std::vector<_T> const& _b)
inline std::set<_T>& operator+=(std::set<_T>& _a, std::set<_T> const& _b)
{
_a.reserve(_a.size() + _b.size());
for (auto& i: _b)
_a.push_back(i);
_a.insert(i);
return _a;
}
/// Concatenate two vectors of elements. _T must be POD.
/// Merge two sets of elements.
template <class _T>
inline std::vector<_T> operator+(std::vector<typename std::enable_if<!std::is_pod<_T>::value, _T>::type> const& _a, std::vector<_T> const& _b)
inline std::set<_T> operator+(std::set<_T> const& _a, std::set<_T> const& _b)
{
std::vector<_T> ret(_a);
std::set<_T> ret(_a);
return ret += _b;
}

4
libethereum/Executive.cpp

@ -172,6 +172,8 @@ bool Executive::go(OnOpFunc const& _onOp)
try
{
m_out = m_vm->go(*m_ext, _onOp);
if (m_ext)
m_endGas += min((m_t.gas - m_endGas) / 2, m_ext->sub.refunds);
m_endGas = m_vm->gas();
}
catch (StepsDone const&)
@ -236,6 +238,6 @@ void Executive::finalize(OnOpFunc const&)
// Suicides...
if (m_ext)
for (auto a: m_ext->suicides)
for (auto a: m_ext->sub.suicides)
m_s.m_cache[a].kill();
}

3
libethereum/Executive.h

@ -61,6 +61,7 @@ public:
bytesConstRef out() const { return m_out; }
h160 newAddress() const { return m_newAddress; }
LogEntries const& logs() const { return m_logs; }
VM const& vm() const { return *m_vm; }
State const& state() const { return m_s; }
@ -77,6 +78,8 @@ private:
Transaction m_t;
Address m_sender;
u256 m_endGas;
LogEntries m_logs;
};
}

4
libethereum/ExtVM.h

@ -61,7 +61,7 @@ public:
m_s.noteSending(myAddress);
if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &sub, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;
@ -72,7 +72,7 @@ public:
{
if (m_ms)
m_ms->internal.resize(m_ms->internal.size() + 1);
auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
auto ret = m_s.call(_receiveAddress, _codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &sub, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, depth + 1);
if (m_ms && !m_ms->internal.back().from)
m_ms->internal.pop_back();
return ret;

16
libethereum/State.cpp

@ -1119,7 +1119,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit)
return e.gasUsed();
}
bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderAddress, u256 _value, u256 _gasPrice, bytesConstRef _data, u256* _gas, bytesRef _out, Address _originAddress, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{
if (!_originAddress)
_originAddress = _senderAddress;
@ -1154,9 +1154,8 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
{
auto out = vm.go(evm, _onOp);
memcpy(_out.data(), out.data(), std::min(out.size(), _out.size()));
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
if (o_sub)
*o_sub += evm.sub;
if (o_ms)
o_ms->output = out.toBytes();
}
@ -1189,7 +1188,7 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA
return true;
}
h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{
if (!_origin)
_origin = _sender;
@ -1218,9 +1217,8 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas,
out = vm.go(evm, _onOp);
if (o_ms)
o_ms->output = out.toBytes();
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
if (o_sub)
*o_sub += evm.sub;
}
catch (OutOfGas const& /*_e*/)
{
@ -1240,7 +1238,7 @@ 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.)
// TODO: CHECK: AUDIT: 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)

4
libethereum/State.h

@ -288,12 +288,12 @@ private:
// 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, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
h160 create(Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = Address(), SubState* o_sub = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// 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 _codeAddress, 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, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
bool call(Address _myAddress, Address _codeAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256* _gas, bytesRef _out, Address _originAddress = Address(), SubState* o_sub = nullptr, Manifest* o_ms = nullptr, OnOpFunc const& _onOp = OnOpFunc(), unsigned _level = 0);
/// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock).
void resetCurrent();

28
libevm/ExtVMFace.h

@ -24,6 +24,7 @@
#include <set>
#include <functional>
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libevmface/Instruction.h>
#include <libethcore/CommonEth.h>
#include <libethcore/BlockInfo.h>
@ -33,13 +34,28 @@ namespace dev
namespace eth
{
struct Post
struct LogEntry
{
Address from;
Address to;
u256 value;
h256 topics;
bytes data;
u256 gas;
};
using LogEntries = std::vector<LogEntry>;
struct SubState
{
std::set<Address> suicides; ///< Any accounts that have suicided.
LogEntries logs; ///< Any logs.
u256 refunds; ///< Refund counter of SSTORE nonzero->zero.
SubState& operator+=(SubState const& _s)
{
suicides += _s.suicides;
refunds += _s.refunds;
suicides += _s.suicides;
return *this;
}
};
using OnOpFunc = std::function<void(uint64_t /*steps*/, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, void/*VM*/*, void/*ExtVM*/ const*)>;
@ -80,7 +96,7 @@ public:
virtual u256 txCount(Address) { return 0; }
/// Suicide the associated contract and give proceeds to the given address.
virtual void suicide(Address) { suicides.insert(myAddress); }
virtual void suicide(Address) { sub.suicides.insert(myAddress); }
/// Create a new (contract) account.
virtual h160 create(u256, u256*, bytesConstRef, OnOpFunc const&) { return h160(); }
@ -103,7 +119,7 @@ public:
bytesConstRef code; ///< Current code that is executing.
BlockInfo previousBlock; ///< The previous block's information.
BlockInfo currentBlock; ///< The current block's information.
std::set<Address> suicides; ///< Any accounts that have suicided.
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
unsigned depth; ///< Depth of the present call.
};

4
libevm/FeeStructure.cpp

@ -29,7 +29,9 @@ u256 const dev::eth::c_stepGas = 1;
u256 const dev::eth::c_balanceGas = 20;
u256 const dev::eth::c_sha3Gas = 20;
u256 const dev::eth::c_sloadGas = 20;
u256 const dev::eth::c_sstoreGas = 100;
u256 const dev::eth::c_sstoreSetGas = 300;
u256 const dev::eth::c_sstoreResetGas = 100;
u256 const dev::eth::c_sstoreRefundGas = 100;
u256 const dev::eth::c_createGas = 100;
u256 const dev::eth::c_callGas = 20;
u256 const dev::eth::c_memoryGas = 1;

4
libevm/FeeStructure.h

@ -32,7 +32,9 @@ extern u256 const c_stepGas; ///< Once per operation, except for SSTORE, SLOAD
extern u256 const c_balanceGas; ///< Once per BALANCE operation.
extern u256 const c_sha3Gas; ///< Once per SHA3 operation.
extern u256 const c_sloadGas; ///< Once per SLOAD operation.
extern u256 const c_sstoreGas; ///< Once per non-zero storage element in a CREATE call/transaction. Also, once/twice per SSTORE operation depending on whether the zeroness changes (twice iff it changes from zero; nothing at all if to zero) or doesn't (once).
extern u256 const c_sstoreSetGas; ///< Once per SSTORE operation if the zeroness changes from zero.
extern u256 const c_sstoreResetGas; ///< Once per SSTORE operation if the zeroness doesn't change.
extern u256 const c_sstoreRefundGas; ///< Refunded gas, once per SSTORE operation if the zeroness changes to zero.
extern u256 const c_createGas; ///< Once per CREATE operation & contract-creation transaction.
extern u256 const c_callGas; ///< Once per CALL operation & message call transaction.
extern u256 const c_memoryGas; ///< Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.

7
libevm/VM.h

@ -117,11 +117,14 @@ template <class Ext> dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con
case Instruction::SSTORE:
require(2);
if (!_ext.store(m_stack.back()) && m_stack[m_stack.size() - 2])
runGas = c_sstoreGas * 2;
runGas = c_sstoreSetGas;
else if (_ext.store(m_stack.back()) && !m_stack[m_stack.size() - 2])
{
runGas = 0;
_ext.sub.refunds += c_sstoreRefundGas;
}
else
runGas = c_sstoreGas;
runGas = c_sstoreResetGas;
break;
case Instruction::SLOAD:

24
test/vm.cpp

@ -45,7 +45,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun
m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1);
auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1);
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
@ -91,7 +91,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!m_s.addresses().count(myAddress))
{
m_ms.internal.resize(m_ms.internal.size() + 1);
auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1);
auto na = m_s.createNewAddress(myAddress, myAddress, balance(myAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, {}, 1);
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
if (na != myAddress)
@ -116,7 +116,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
{
m_s.noteSending(myAddress);
m_ms.internal.resize(m_ms.internal.size() + 1);
auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
auto na = m_s.createNewAddress(_codeAddressOverride ? _codeAddressOverride : _receiveAddress, myAddress, balance(_codeAddressOverride ? _codeAddressOverride : _receiveAddress), gasPrice, &contractgas, init, origin, &sub, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1);
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
@ -131,7 +131,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
m_ms.internal.resize(m_ms.internal.size() + 1);
auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &(m_ms.internal.back()), OnOpFunc(), 1);
auto ret = m_s.call(_receiveAddress,_codeAddressOverride ? _codeAddressOverride : _receiveAddress, _myAddressOverride ? _myAddressOverride : myAddress, _value, gasPrice, _data, _gas, _out, origin, &sub, &(m_ms.internal.back()), OnOpFunc(), 1);
if (!m_ms.internal.back().from)
m_ms.internal.pop_back();
@ -146,12 +146,15 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data,
if (!ret)
return false;
// TODO: @CJentzsch refund SSTORE stuff.
// TODO: @CJentzsch test logs.
// do suicides
for (auto const& f: suicides)
for (auto const& f: sub.suicides)
addresses.erase(f);
// get storage
if ((get<0>(addresses[myAddress]) >= _value) && (suicides.find(_receiveAddress) == suicides.end()))
if ((get<0>(addresses[myAddress]) >= _value) && (sub.suicides.find(_receiveAddress) == sub.suicides.end()))
{
for (auto const& j: m_s.storage(_receiveAddress))
{
@ -419,8 +422,11 @@ void FakeExtVM::importCallCreates(mArray& _callcreates)
}
}
h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set<Address>* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
// THIS IS BROKEN AND NEEDS TO BE REMOVED.
h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, SubState* o_sub, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level)
{
(void)o_sub;
if (!_origin)
_origin = _sender;
@ -446,9 +452,7 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end
out = vm.go(evm, _onOp);
if (o_ms)
o_ms->output = out.toBytes();
if (o_suicides)
for (auto i: evm.suicides)
o_suicides->insert(i);
// TODO: deal with evm.sub
}
catch (OutOfGas const& /*_e*/)
{

2
test/vm.h

@ -44,7 +44,7 @@ class FakeState: public eth::State
{
public:
/// Execute a contract-creation transaction.
h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, std::set<Address>* o_suicides = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0);
h160 createNewAddress(Address _newAddress, Address _txSender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _originAddress = {}, eth::SubState* o_suicides = nullptr, eth::Manifest* o_ms = nullptr, eth::OnOpFunc const& _onOp = {}, unsigned _level = 0);
};
class FakeExtVM: public eth::ExtVMFace

Loading…
Cancel
Save