Browse Source

Change the way execution results are collected.

Changes handling ExecutionResult by Executive. From now execution results are collected on if a storage for results (ExecutionResult) is provided to an Executiove instance up front. This change allow better output management for calls - VM interface improved.
cl-refactor
Paweł Bylica 10 years ago
parent
commit
72856a8af6
  1. 2
      evmjit/libevmjit-cpp/JitVM.h
  2. 3
      libethereum/Client.cpp
  3. 60
      libethereum/Executive.cpp
  4. 14
      libethereum/Executive.h
  5. 1
      libethereum/ExtVM.cpp
  6. 4
      libethereum/State.cpp
  7. 17
      libethereum/Transaction.h
  8. 2
      libevm/SmartVM.h
  9. 2
      libevm/VM.h
  10. 12
      libevm/VMFace.h
  11. 5
      mix/MixClient.cpp
  12. 4
      test/libsolidity/solidityExecutionFramework.h

2
evmjit/libevmjit-cpp/JitVM.h

@ -11,7 +11,7 @@ namespace eth
class JitVM: public VMFace
{
public:
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final;
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) override final;
private:
jit::RuntimeData m_data;

3
libethereum/Client.cpp

@ -440,9 +440,10 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256
temp = m_postMine;
temp.addBalance(_from, _value + _gasPrice * _gas);
Executive e(temp, LastHashes(), 0);
e.setResultRef(ret);
if (!e.call(_dest, _from, _value, _gasPrice, &_data, _gas))
e.go();
ret = e.executionResult();
e.finalize();
}
catch (...)
{

60
libethereum/Executive.cpp

@ -44,11 +44,6 @@ u256 Executive::gasUsed() const
return m_t.gas() - m_gas;
}
ExecutionResult Executive::executionResult() const
{
return ExecutionResult(gasUsed(), m_excepted, m_newAddress, out(), m_codeDeposit, m_ext ? m_ext->sub.refunds : 0, m_depositSize, m_gasForDeposit);
}
void Executive::accrueSubState(SubState& _parentContext)
{
if (m_ext)
@ -145,7 +140,8 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co
else
{
m_gas = (u256)(_p.gas - g);
m_out = it->second.exec(_p.data);
auto out = it->second.exec(_p.data); // FIXME: Avoid double copy
bytesConstRef{&out}.copyTo(_p.out);
}
}
else
@ -153,7 +149,7 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co
m_gas = _p.gas;
if (m_s.addressHasCode(_p.codeAddress))
{
m_vm = VMFactory::create();
m_outRef = _p.out; // Save ref to expected output buffer to be used in go()
bytes const& c = m_s.code(_p.codeAddress);
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth);
}
@ -175,10 +171,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
// Execute _init.
if (!_init.empty())
{
m_vm = VMFactory::create();
m_ext = make_shared<ExtVM>(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth);
}
m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress), Account::ContractConception);
m_s.transferBalance(_sender, m_newAddress, _endowment);
@ -211,30 +204,47 @@ OnOpFunc Executive::simpleTrace()
bool Executive::go(OnOpFunc const& _onOp)
{
if (m_vm)
if (m_ext)
{
#if ETH_TIMED_EXECUTIONS
boost::timer t;
#endif
try
{
m_out = m_vm->exec(m_gas, *m_ext, _onOp);
auto vm = VMFactory::create();
if (m_isCreation)
{
m_gasForDeposit = m_gas;
m_depositSize = m_out.size();
if (m_out.size() * c_createDataGas <= m_gas)
auto out = vm->exec(m_gas, *m_ext, _onOp);
if (m_res)
{
m_res->gasForDeposit = m_gas;
m_res->depositSize = out.size();
}
if (out.size() * c_createDataGas <= m_gas)
{
m_codeDeposit = CodeDeposit::Success;
m_gas -= m_out.size() * c_createDataGas;
if (m_res)
m_res->codeDeposit = CodeDeposit::Success;
m_gas -= out.size() * c_createDataGas;
}
else
{
m_codeDeposit = CodeDeposit::Failed;
m_out.clear();
if (m_res)
m_res->codeDeposit = CodeDeposit::Failed;
out.clear();
}
m_s.m_cache[m_newAddress].setCode(std::move(m_out));
if (m_res)
m_res->output = out; // copy output to execution result
m_s.m_cache[m_newAddress].setCode(std::move(out)); // FIXME: Set only if Success?
}
else
{
if (m_res)
{
m_res->output = vm->exec(m_gas, *m_ext, _onOp); // take full output
bytesConstRef{&m_res->output}.copyTo(m_outRef);
}
else
vm->exec(m_gas, *m_ext, m_outRef, _onOp); // take only expected output
}
}
catch (StepsDone const&)
@ -293,4 +303,12 @@ void Executive::finalize()
// Logs..
if (m_ext)
m_logs = m_ext->sub.logs;
if (m_res) // Collect results
{
m_res->gasUsed = gasUsed();
m_res->excepted = m_excepted; // TODO: m_except is used only in ExtVM::call
m_res->newAddress = m_newAddress;
m_res->gasRefunded = m_ext ? m_ext->sub.refunds : 0;
}
}

14
libethereum/Executive.h

@ -108,29 +108,25 @@ public:
/// @returns gas remaining after the transaction/operation. Valid after the transaction has been executed.
u256 gas() const { return m_gas; }
/// @returns output data of the transaction/operation.
bytesConstRef out() const { return {m_out.data(), m_out.size()}; }
/// @returns the new address for the created contract in the CREATE operation.
h160 newAddress() const { return m_newAddress; }
/// @returns true iff the operation ended with a VM exception.
bool excepted() const { return m_excepted != TransactionException::None; }
/// Get the above in an amalgamated fashion.
ExecutionResult executionResult() const;
/// Collect execution results in the result storage provided.
void setResultRef(ExecutionResult& _res) { m_res = &_res; }
private:
State& m_s; ///< The state to which this operation/transaction is applied.
LastHashes m_lastHashes;
std::shared_ptr<ExtVM> m_ext; ///< The VM externality object for the VM execution or null if no VM is required.
std::unique_ptr<VMFace> m_vm; ///< The VM object or null if no VM is required.
bytes m_out; ///< The VM execution output.
bytesRef m_outRef; ///< Reference to "expected output" buffer.
ExecutionResult* m_res = nullptr; ///< Optional storage for execution results.
Address m_newAddress; ///< The address of the created contract in the case of create() being called.
unsigned m_depth = 0; ///< The context's call-depth.
bool m_isCreation = false; ///< True if the transaction creates a contract, or if create() is called.
unsigned m_depositSize = 0; ///< Amount of code of the creation's attempted deposit.
u256 m_gasForDeposit; ///< Amount of gas remaining for the code deposit phase.
CodeDeposit m_codeDeposit = CodeDeposit::None; ///< True if an attempted deposit failed due to lack of gas.
TransactionException m_excepted = TransactionException::None; ///< Details if the VM's execution resulted in an exception.
u256 m_gas = 0; ///< The gas for EVM code execution. Initial amount before go() execution, final amount after go() execution.

1
libethereum/ExtVM.cpp

@ -35,7 +35,6 @@ bool ExtVM::call(CallParameters& _p)
e.accrueSubState(sub);
}
_p.gas = e.gas();
e.out().copyTo(_p.out);
return !e.excepted();
}

4
libethereum/State.cpp

@ -1125,6 +1125,8 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
// Create and initialize the executive. This will throw fairly cheaply and quickly if the
// transaction is bad in any way.
Executive e(*this, _lh, 0);
ExecutionResult res;
e.setResultRef(res);
e.initialize(_t);
// Uncommitting is a non-trivial operation - only do it once we've verified as much of the
@ -1181,7 +1183,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
m_transactionSet.insert(e.t().sha3());
}
return e.executionResult();
return res;
}
State State::fromPending(unsigned _i) const

17
libethereum/Transaction.h

@ -74,25 +74,14 @@ TransactionException toTransactionException(VMException const& _e);
/// Description of the result of executing a transaction.
struct ExecutionResult
{
ExecutionResult() = default;
ExecutionResult(u256 const& _gasUsed, TransactionException _excepted, Address const& _newAddress, bytesConstRef _output, CodeDeposit _codeDeposit, u256 const& _gasRefund, unsigned _depositSize, u256 const& _gasForDeposit):
gasUsed(_gasUsed),
excepted(_excepted),
newAddress(_newAddress),
output(_output.toBytes()),
codeDeposit(_codeDeposit),
gasRefunded(_gasRefund),
depositSize(_depositSize),
gasForDeposit(_gasForDeposit)
{}
u256 gasUsed = 0;
TransactionException excepted = TransactionException::Unknown;
Address newAddress;
bytes output;
CodeDeposit codeDeposit = CodeDeposit::None;
CodeDeposit codeDeposit = CodeDeposit::None; ///< Failed if an attempted deposit failed due to lack of gas.
u256 gasRefunded = 0;
unsigned depositSize = 0;
u256 gasForDeposit;
unsigned depositSize = 0; ///< Amount of code of the creation's attempted deposit.
u256 gasForDeposit; ///< Amount of gas remaining for the code deposit phase.
};
std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er);

2
libevm/SmartVM.h

@ -31,7 +31,7 @@ namespace eth
class SmartVM: public VMFace
{
public:
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final;
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) override final;
private:
std::unique_ptr<VMFace> m_selectedVM;

2
libevm/VM.h

@ -52,7 +52,7 @@ inline u256 fromAddress(Address _a)
class VM: public VMFace
{
public:
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final;
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) override final;
u256 curPC() const { return m_curPC; }

12
libevm/VMFace.h

@ -43,12 +43,22 @@ public:
VMFace(VMFace const&) = delete;
VMFace& operator=(VMFace const&) = delete;
/// Execute EVM code by VM.
///
/// @param _out Expected output
void exec(u256& io_gas, ExtVMFace& _ext, bytesRef _out, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1)
{
execImpl(io_gas, _ext, _onOp, _steps).copyTo(_out);
}
/// The same as above but returns a copy of full output.
bytes exec(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1)
{
return execImpl(io_gas, _ext, _onOp, _steps).toVector();
}
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0;
/// VM implementation
virtual bytesConstRef execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) = 0;
};
}

5
mix/MixClient.cpp

@ -130,7 +130,9 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
State execState = _state;
execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation
eth::ExecutionResult er;
Executive execution(execState, lastHashes, 0);
execution.setResultRef(er);
execution.initialize(t);
execution.execute();
std::vector<MachineState> machineStates;
@ -186,7 +188,6 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
execution.go(onOp);
execution.finalize();
dev::eth::ExecutionResult er = execution.executionResult();
switch (er.excepted)
{
@ -213,7 +214,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c
};
ExecutionResult d;
d.result = execution.executionResult();
d.result = er;
d.machineStates = machineStates;
d.executionCode = std::move(codes);
d.transactionData = std::move(data);

4
test/libsolidity/solidityExecutionFramework.h

@ -135,6 +135,8 @@ protected:
{
m_state.addBalance(m_sender, _value); // just in case
eth::Executive executive(m_state, eth::LastHashes(), 0);
eth::ExecutionResult res;
executive.setResultRef(res);
eth::Transaction t = _isCreation ? eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec())
: eth::Transaction(_value, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec());
bytes transactionRLP = t.rlp();
@ -161,7 +163,7 @@ protected:
m_state.noteSending(m_sender);
executive.finalize();
m_gasUsed = executive.gasUsed();
m_output = executive.out().toVector();
m_output = std::move(res.output); // FIXME: Looks like Framework needs ExecutiveResult embedded
m_logs = executive.logs();
}

Loading…
Cancel
Save