Browse Source

Merge branch 'develop' of github.com:ethereum/cpp-ethereum into develop

cl-refactor
Gav Wood 10 years ago
parent
commit
6e9f20ff46
  1. 4
      evmjit/libevmjit-cpp/JitVM.cpp
  2. 2
      evmjit/libevmjit-cpp/JitVM.h
  3. 2
      libdevcrypto/Common.cpp
  4. 2
      libdevcrypto/Common.h
  5. 3
      libethereum/Client.cpp
  6. 65
      libethereum/Executive.cpp
  7. 15
      libethereum/Executive.h
  8. 1
      libethereum/ExtVM.cpp
  9. 55
      libethereum/Precompiled.cpp
  10. 2
      libethereum/Precompiled.h
  11. 4
      libethereum/State.cpp
  12. 17
      libethereum/Transaction.h
  13. 4
      libevm/SmartVM.cpp
  14. 2
      libevm/SmartVM.h
  15. 9
      libevm/VM.cpp
  16. 2
      libevm/VM.h
  17. 18
      libevm/VMFace.h
  18. 4
      libevmasm/CommonSubexpressionEliminator.cpp
  19. 5
      libsolidity/ArrayUtils.cpp
  20. 2
      libsolidity/Compiler.cpp
  21. 11
      libsolidity/CompilerUtils.cpp
  22. 2
      libsolidity/ExpressionCompiler.cpp
  23. 26
      libsolidity/LValue.cpp
  24. 5
      mix/MixClient.cpp
  25. 2
      solc/CommandLineInterface.cpp
  26. 4
      test/fuzzTesting/checkRandomVMTest.cpp
  27. 2
      test/fuzzTesting/createRandomVMTest.cpp
  28. 4
      test/libevm/vm.cpp
  29. 4
      test/libsolidity/solidityExecutionFramework.h

4
evmjit/libevmjit-cpp/JitVM.cpp

@ -18,7 +18,7 @@ namespace eth
extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below extern "C" void env_sload(); // fake declaration for linker symbol stripping workaround, see a call below
bytesConstRef JitVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _step) bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
{ {
using namespace jit; using namespace jit;
@ -33,7 +33,7 @@ bytesConstRef JitVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, ui
{ {
cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter"; cwarn << "Execution rejected by EVM JIT (gas limit: " << io_gas << "), executing with interpreter";
m_fallbackVM = VMFactory::create(VMKind::Interpreter); m_fallbackVM = VMFactory::create(VMKind::Interpreter);
return m_fallbackVM->go(io_gas, _ext, _onOp, _step); return m_fallbackVM->execImpl(io_gas, _ext, _onOp);
} }
m_data.gas = static_cast<decltype(m_data.gas)>(io_gas); m_data.gas = static_cast<decltype(m_data.gas)>(io_gas);

2
evmjit/libevmjit-cpp/JitVM.h

@ -11,7 +11,7 @@ namespace eth
class JitVM: public VMFace class JitVM: public VMFace
{ {
public: public:
virtual bytesConstRef go(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) override final;
private: private:
jit::RuntimeData m_data; jit::RuntimeData m_data;

2
libdevcrypto/Common.cpp

@ -37,7 +37,7 @@ using namespace dev::crypto;
static Secp256k1 s_secp256k1; static Secp256k1 s_secp256k1;
bool dev::SignatureStruct::isValid() const bool dev::SignatureStruct::isValid() const noexcept
{ {
if (v > 1 || if (v > 1 ||
r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") || r >= h256("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") ||

2
libdevcrypto/Common.h

@ -51,7 +51,7 @@ struct SignatureStruct
operator Signature() const { return *(h520 const*)this; } operator Signature() const { return *(h520 const*)this; }
/// @returns true if r,s,v values are valid, otherwise false /// @returns true if r,s,v values are valid, otherwise false
bool isValid() const; bool isValid() const noexcept;
h256 r; h256 r;
h256 s; h256 s;

3
libethereum/Client.cpp

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

65
libethereum/Executive.cpp

@ -45,11 +45,6 @@ u256 Executive::gasUsed() const
return m_t.gas() - m_gas; return m_t.gas() - m_gas;
} }
ExecutionResult Executive::executionResult() const
{
return ExecutionResult(gasUsed(), m_excepted, m_newAddress, m_out, m_codeDeposit, m_ext ? m_ext->sub.refunds : 0, m_depositSize, m_gasForDeposit);
}
void Executive::accrueSubState(SubState& _parentContext) void Executive::accrueSubState(SubState& _parentContext)
{ {
if (m_ext) if (m_ext)
@ -146,8 +141,7 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co
else else
{ {
m_gas = (u256)(_p.gas - g); m_gas = (u256)(_p.gas - g);
m_precompiledOut = it->second.exec(_p.data); it->second.exec(_p.data, _p.out);
m_out = &m_precompiledOut;
} }
} }
else else
@ -155,7 +149,7 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co
m_gas = _p.gas; m_gas = _p.gas;
if (m_s.addressHasCode(_p.codeAddress)) 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); 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); m_ext = make_shared<ExtVM>(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth);
} }
@ -177,10 +171,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g
// Execute _init. // Execute _init.
if (!_init.empty()) 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_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.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress), Account::ContractConception);
m_s.transferBalance(_sender, m_newAddress, _endowment); m_s.transferBalance(_sender, m_newAddress, _endowment);
@ -231,36 +222,48 @@ OnOpFunc Executive::standardTrace(ostream& o_output)
bool Executive::go(OnOpFunc const& _onOp) bool Executive::go(OnOpFunc const& _onOp)
{ {
if (m_vm) if (m_ext)
{ {
#if ETH_TIMED_EXECUTIONS #if ETH_TIMED_EXECUTIONS
boost::timer t; boost::timer t;
#endif #endif
try try
{ {
m_out = m_vm->go(m_gas, *m_ext, _onOp); auto vm = VMFactory::create();
if (m_isCreation) if (m_isCreation)
{ {
m_gasForDeposit = m_gas; auto out = vm->exec(m_gas, *m_ext, _onOp);
m_depositSize = m_out.size(); if (m_res)
if (m_out.size() * c_createDataGas <= m_gas)
{ {
m_codeDeposit = CodeDeposit::Success; m_res->gasForDeposit = m_gas;
m_gas -= m_out.size() * c_createDataGas; m_res->depositSize = out.size();
}
if (out.size() * c_createDataGas <= m_gas)
{
if (m_res)
m_res->codeDeposit = CodeDeposit::Success;
m_gas -= out.size() * c_createDataGas;
} }
else else
{ {
if (m_res)
m_codeDeposit = CodeDeposit::Failed; m_res->codeDeposit = CodeDeposit::Failed;
m_out.reset(); out.clear();
} }
m_s.m_cache[m_newAddress].setCode(m_out.toBytes()); 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&)
{
return false;
} }
catch (VMException const& _e) catch (VMException const& _e)
{ {
@ -314,4 +317,12 @@ void Executive::finalize()
// Logs.. // Logs..
if (m_ext) if (m_ext)
m_logs = m_ext->sub.logs; 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;
}
} }

15
libethereum/Executive.h

@ -112,30 +112,25 @@ public:
/// @returns gas remaining after the transaction/operation. Valid after the transaction has been executed. /// @returns gas remaining after the transaction/operation. Valid after the transaction has been executed.
u256 gas() const { return m_gas; } u256 gas() const { return m_gas; }
/// @returns output data of the transaction/operation.
bytesConstRef out() const { return m_out; }
/// @returns the new address for the created contract in the CREATE operation. /// @returns the new address for the created contract in the CREATE operation.
h160 newAddress() const { return m_newAddress; } h160 newAddress() const { return m_newAddress; }
/// @returns true iff the operation ended with a VM exception. /// @returns true iff the operation ended with a VM exception.
bool excepted() const { return m_excepted != TransactionException::None; } bool excepted() const { return m_excepted != TransactionException::None; }
/// Get the above in an amalgamated fashion. /// Collect execution results in the result storage provided.
ExecutionResult executionResult() const; void setResultRecipient(ExecutionResult& _res) { m_res = &_res; }
private: private:
State& m_s; ///< The state to which this operation/transaction is applied. State& m_s; ///< The state to which this operation/transaction is applied.
LastHashes m_lastHashes; 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::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. bytesRef m_outRef; ///< Reference to "expected output" buffer.
bytes m_precompiledOut; ///< Used for the output when there is no VM for a contract (i.e. precompiled). ExecutionResult* m_res = nullptr; ///< Optional storage for execution results.
bytesConstRef m_out; ///< The copyable output.
Address m_newAddress; ///< The address of the created contract in the case of create() being called. 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. 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. 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. 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. 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); e.accrueSubState(sub);
} }
_p.gas = e.gas(); _p.gas = e.gas();
e.out().copyTo(_p.out);
return !e.excepted(); return !e.excepted();
} }

55
libethereum/Precompiled.cpp

@ -31,7 +31,10 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::eth; using namespace dev::eth;
static bytes ecrecoverCode(bytesConstRef _in) namespace
{
void ecrecoverCode(bytesConstRef _in, bytesRef _out)
{ {
struct inType struct inType
{ {
@ -44,47 +47,49 @@ static bytes ecrecoverCode(bytesConstRef _in)
memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); memcpy(&in, _in.data(), min(_in.size(), sizeof(in)));
h256 ret; h256 ret;
u256 v = (u256)in.v;
if ((u256)in.v > 28) if (v >= 27 && v <= 28)
return ret.asBytes();
SignatureStruct sig(in.r, in.s, (byte)((int)(u256)in.v - 27));
if (!sig.isValid())
return ret.asBytes();
try
{ {
ret = dev::sha3(recover(sig, in.hash)); SignatureStruct sig(in.r, in.s, (byte)((int)v - 27));
if (sig.isValid())
{
try
{
ret = sha3(recover(sig, in.hash));
}
catch (...) {}
}
} }
catch (...) {}
memset(ret.data(), 0, 12); memset(ret.data(), 0, 12);
return ret.asBytes(); ret.ref().copyTo(_out);
} }
static bytes sha256Code(bytesConstRef _in) void sha256Code(bytesConstRef _in, bytesRef _out)
{ {
return sha256(_in).asBytes(); sha256(_in).ref().copyTo(_out);
} }
static bytes ripemd160Code(bytesConstRef _in) void ripemd160Code(bytesConstRef _in, bytesRef _out)
{ {
return h256(ripemd160(_in), h256::AlignRight).asBytes(); h256(ripemd160(_in), h256::AlignRight).ref().copyTo(_out);
} }
static bytes identityCode(bytesConstRef _in) void identityCode(bytesConstRef _in, bytesRef _out)
{ {
return _in.toBytes(); _in.copyTo(_out);
} }
static const std::unordered_map<unsigned, PrecompiledAddress> c_precompiled = }
{
{ 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }},
{ 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }},
{ 3, { [](bytesConstRef i) -> bigint { return c_ripemd160Gas + (i.size() + 31) / 32 * c_ripemd160WordGas; }, ripemd160Code }},
{ 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }}
};
std::unordered_map<unsigned, PrecompiledAddress> const& dev::eth::precompiled() std::unordered_map<unsigned, PrecompiledAddress> const& dev::eth::precompiled()
{ {
static const std::unordered_map<unsigned, PrecompiledAddress> c_precompiled =
{
{ 1, { [](bytesConstRef) -> bigint { return c_ecrecoverGas; }, ecrecoverCode }},
{ 2, { [](bytesConstRef i) -> bigint { return c_sha256Gas + (i.size() + 31) / 32 * c_sha256WordGas; }, sha256Code }},
{ 3, { [](bytesConstRef i) -> bigint { return c_ripemd160Gas + (i.size() + 31) / 32 * c_ripemd160WordGas; }, ripemd160Code }},
{ 4, { [](bytesConstRef i) -> bigint { return c_identityGas + (i.size() + 31) / 32 * c_identityWordGas; }, identityCode }}
};
return c_precompiled; return c_precompiled;
} }

2
libethereum/Precompiled.h

@ -34,7 +34,7 @@ namespace eth
struct PrecompiledAddress struct PrecompiledAddress
{ {
std::function<bigint(bytesConstRef)> gas; std::function<bigint(bytesConstRef)> gas;
std::function<bytes(bytesConstRef)> exec; std::function<void(bytesConstRef, bytesRef)> exec;
}; };
/// Info on precompiled contract accounts baked into the protocol. /// Info on precompiled contract accounts baked into the protocol.

4
libethereum/State.cpp

@ -1171,6 +1171,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 // Create and initialize the executive. This will throw fairly cheaply and quickly if the
// transaction is bad in any way. // transaction is bad in any way.
Executive e(*this, _lh, 0); Executive e(*this, _lh, 0);
ExecutionResult res;
e.setResultRecipient(res);
e.initialize(_t); e.initialize(_t);
// Uncommitting is a non-trivial operation - only do it once we've verified as much of the // Uncommitting is a non-trivial operation - only do it once we've verified as much of the
@ -1230,7 +1232,7 @@ ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Per
m_transactionSet.insert(e.t().sha3()); m_transactionSet.insert(e.t().sha3());
} }
return e.executionResult(); return res;
} }
State State::fromPending(unsigned _i) const 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. /// Description of the result of executing a transaction.
struct ExecutionResult 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; u256 gasUsed = 0;
TransactionException excepted = TransactionException::Unknown; TransactionException excepted = TransactionException::Unknown;
Address newAddress; Address newAddress;
bytes output; bytes output;
CodeDeposit codeDeposit = CodeDeposit::None; CodeDeposit codeDeposit = CodeDeposit::None; ///< Failed if an attempted deposit failed due to lack of gas.
u256 gasRefunded = 0; u256 gasRefunded = 0;
unsigned depositSize = 0; unsigned depositSize = 0; ///< Amount of code of the creation's attempted deposit.
u256 gasForDeposit; u256 gasForDeposit; ///< Amount of gas remaining for the code deposit phase.
}; };
std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er); std::ostream& operator<<(std::ostream& _out, ExecutionResult const& _er);

4
libevm/SmartVM.cpp

@ -41,7 +41,7 @@ namespace
} }
} }
bytesConstRef SmartVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) bytesConstRef SmartVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
{ {
auto codeHash = sha3(_ext.code); auto codeHash = sha3(_ext.code);
auto vmKind = VMKind::Interpreter; // default VM auto vmKind = VMKind::Interpreter; // default VM
@ -68,7 +68,7 @@ bytesConstRef SmartVM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp,
// TODO: Selected VM must be kept only because it returns reference to its internal memory. // TODO: Selected VM must be kept only because it returns reference to its internal memory.
// VM implementations should be stateless, without escaping memory reference. // VM implementations should be stateless, without escaping memory reference.
m_selectedVM = VMFactory::create(vmKind); m_selectedVM = VMFactory::create(vmKind);
return m_selectedVM->go(io_gas, _ext, _onOp, _steps); return m_selectedVM->execImpl(io_gas, _ext, _onOp);
} }
} }

2
libevm/SmartVM.h

@ -31,7 +31,7 @@ namespace eth
class SmartVM: public VMFace class SmartVM: public VMFace
{ {
public: public:
virtual bytesConstRef go(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) override final;
private: private:
std::unique_ptr<VMFace> m_selectedVM; std::unique_ptr<VMFace> m_selectedVM;

9
libevm/VM.cpp

@ -45,7 +45,7 @@ static array<InstructionMetric, 256> metrics()
return s_ret; return s_ret;
} }
bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) bytesConstRef VM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
{ {
// Reset leftovers from possible previous run // Reset leftovers from possible previous run
m_curPC = 0; m_curPC = 0;
@ -73,8 +73,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6
i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1; i += _ext.code[i] - (unsigned)Instruction::PUSH1 + 1;
} }
u256 nextPC = m_curPC + 1; u256 nextPC = m_curPC + 1;
auto osteps = _steps; for (uint64_t steps = 0; true; m_curPC = nextPC, nextPC = m_curPC + 1, ++steps)
for (bool stopped = false; !stopped && _steps--; m_curPC = nextPC, nextPC = m_curPC + 1)
{ {
// INSTRUCTION... // INSTRUCTION...
Instruction inst = (Instruction)_ext.getCode(m_curPC); Instruction inst = (Instruction)_ext.getCode(m_curPC);
@ -97,7 +96,7 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6
auto onOperation = [&]() auto onOperation = [&]()
{ {
if (_onOp) if (_onOp)
_onOp(osteps - _steps - 1, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, io_gas, this, &_ext); _onOp(steps, inst, newTempSize > m_temp.size() ? (newTempSize - m_temp.size()) / 32 : bigint(0), runGas, io_gas, this, &_ext);
}; };
switch (inst) switch (inst)
@ -670,7 +669,5 @@ bytesConstRef VM::go(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp, uint6
} }
} }
if (_steps == (uint64_t)-1)
BOOST_THROW_EXCEPTION(StepsDone());
return bytesConstRef(); return bytesConstRef();
} }

2
libevm/VM.h

@ -52,7 +52,7 @@ inline u256 fromAddress(Address _a)
class VM: public VMFace class VM: public VMFace
{ {
public: public:
virtual bytesConstRef go(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) override final;
u256 curPC() const { return m_curPC; } u256 curPC() const { return m_curPC; }

18
libevm/VMFace.h

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

4
libevmasm/CommonSubexpressionEliminator.cpp

@ -437,7 +437,7 @@ void CSECodeGenerator::appendDup(int _fromPosition, SourceLocation const& _locat
{ {
assertThrow(_fromPosition != c_invalidPosition, OptimizerException, ""); assertThrow(_fromPosition != c_invalidPosition, OptimizerException, "");
int instructionNum = 1 + m_stackHeight - _fromPosition; int instructionNum = 1 + m_stackHeight - _fromPosition;
assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables.");
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
appendItem(AssemblyItem(dupInstruction(instructionNum), _location)); appendItem(AssemblyItem(dupInstruction(instructionNum), _location));
m_stack[m_stackHeight] = m_stack[_fromPosition]; m_stack[m_stackHeight] = m_stack[_fromPosition];
@ -450,7 +450,7 @@ void CSECodeGenerator::appendOrRemoveSwap(int _fromPosition, SourceLocation cons
if (_fromPosition == m_stackHeight) if (_fromPosition == m_stackHeight)
return; return;
int instructionNum = m_stackHeight - _fromPosition; int instructionNum = m_stackHeight - _fromPosition;
assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep."); assertThrow(instructionNum <= 16, StackTooDeepException, "Stack too deep, try removing local variables.");
assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access."); assertThrow(1 <= instructionNum, OptimizerException, "Invalid stack access.");
appendItem(AssemblyItem(swapInstruction(instructionNum), _location)); appendItem(AssemblyItem(swapInstruction(instructionNum), _location));

5
libsolidity/ArrayUtils.cpp

@ -168,7 +168,10 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons
else else
solAssert(false, "Copying of unknown type requested: " + sourceBaseType->toString()); solAssert(false, "Copying of unknown type requested: " + sourceBaseType->toString());
// stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] <source_value>... // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] <source_value>...
solAssert(2 + byteOffsetSize + sourceBaseType->getSizeOnStack() <= 16, "Stack too deep."); solAssert(
2 + byteOffsetSize + sourceBaseType->getSizeOnStack() <= 16,
"Stack too deep, try removing local variables."
);
// fetch target storage reference // fetch target storage reference
m_context << eth::dupInstruction(2 + byteOffsetSize + sourceBaseType->getSizeOnStack()); m_context << eth::dupInstruction(2 + byteOffsetSize + sourceBaseType->getSizeOnStack());
if (haveByteOffsetTarget) if (haveByteOffsetTarget)

2
libsolidity/Compiler.cpp

@ -367,7 +367,7 @@ bool Compiler::visit(FunctionDefinition const& _function)
stackLayout.push_back(i); stackLayout.push_back(i);
stackLayout += vector<int>(c_localVariablesSize, -1); stackLayout += vector<int>(c_localVariablesSize, -1);
solAssert(stackLayout.size() <= 17, "Stack too deep."); solAssert(stackLayout.size() <= 17, "Stack too deep, try removing local variables.");
while (stackLayout.back() != int(stackLayout.size() - 1)) while (stackLayout.back() != int(stackLayout.size() - 1))
if (stackLayout.back() < 0) if (stackLayout.back() < 0)
{ {

11
libsolidity/CompilerUtils.cpp

@ -142,22 +142,25 @@ void CompilerUtils::moveToStackVariable(VariableDeclaration const& _variable)
solAssert(stackPosition >= size, "Variable size and position mismatch."); solAssert(stackPosition >= size, "Variable size and position mismatch.");
// move variable starting from its top end in the stack // move variable starting from its top end in the stack
if (stackPosition - size + 1 > 16) if (stackPosition - size + 1 > 16)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_variable.getLocation()) BOOST_THROW_EXCEPTION(
<< errinfo_comment("Stack too deep.")); CompilerError() <<
errinfo_sourceLocation(_variable.getLocation()) <<
errinfo_comment("Stack too deep, try removing local variables.")
);
for (unsigned i = 0; i < size; ++i) for (unsigned i = 0; i < size; ++i)
m_context << eth::swapInstruction(stackPosition - size + 1) << eth::Instruction::POP; m_context << eth::swapInstruction(stackPosition - size + 1) << eth::Instruction::POP;
} }
void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize) void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
{ {
solAssert(_stackDepth <= 16, "Stack too deep."); solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables.");
for (unsigned i = 0; i < _itemSize; ++i) for (unsigned i = 0; i < _itemSize; ++i)
m_context << eth::dupInstruction(_stackDepth); m_context << eth::dupInstruction(_stackDepth);
} }
void CompilerUtils::moveToStackTop(unsigned _stackDepth) void CompilerUtils::moveToStackTop(unsigned _stackDepth)
{ {
solAssert(_stackDepth <= 15, "Stack too deep."); solAssert(_stackDepth <= 15, "Stack too deep, try removing local variables.");
for (unsigned i = 0; i < _stackDepth; ++i) for (unsigned i = 0; i < _stackDepth; ++i)
m_context << eth::swapInstruction(1 + i); m_context << eth::swapInstruction(1 + i);
} }

2
libsolidity/ExpressionCompiler.cpp

@ -263,7 +263,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType()); appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType());
if (lvalueSize > 0) if (lvalueSize > 0)
{ {
solAssert(itemSize + lvalueSize <= 16, "Stack too deep."); solAssert(itemSize + lvalueSize <= 16, "Stack too deep, try removing local variables.");
// value [lvalue_ref] updated_value // value [lvalue_ref] updated_value
for (unsigned i = 0; i < itemSize; ++i) for (unsigned i = 0; i < itemSize; ++i)
m_context << eth::swapInstruction(itemSize + lvalueSize) << eth::Instruction::POP; m_context << eth::swapInstruction(itemSize + lvalueSize) << eth::Instruction::POP;

26
libsolidity/LValue.cpp

@ -42,8 +42,11 @@ void StackVariable::retrieveValue(SourceLocation const& _location, bool) const
{ {
unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset); unsigned stackPos = m_context.baseToCurrentStackOffset(m_baseStackOffset);
if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(
<< errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); CompilerError() <<
errinfo_sourceLocation(_location) <<
errinfo_comment("Stack too deep, try removing local variables.")
);
for (unsigned i = 0; i < m_size; ++i) for (unsigned i = 0; i < m_size; ++i)
m_context << eth::dupInstruction(stackPos + 1); m_context << eth::dupInstruction(stackPos + 1);
} }
@ -52,8 +55,11 @@ void StackVariable::storeValue(Type const&, SourceLocation const& _location, boo
{ {
unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1; unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset) - m_size + 1;
if (stackDiff > 16) if (stackDiff > 16)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(
<< errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); CompilerError() <<
errinfo_sourceLocation(_location) <<
errinfo_comment("Stack too deep, try removing local variables.")
);
else if (stackDiff > 0) else if (stackDiff > 0)
for (unsigned i = 0; i < m_size; ++i) for (unsigned i = 0; i < m_size; ++i)
m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP; m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP;
@ -65,8 +71,11 @@ void StackVariable::setToZero(SourceLocation const& _location, bool) const
{ {
unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset); unsigned stackDiff = m_context.baseToCurrentStackOffset(m_baseStackOffset);
if (stackDiff > 16) if (stackDiff > 16)
BOOST_THROW_EXCEPTION(CompilerError() BOOST_THROW_EXCEPTION(
<< errinfo_sourceLocation(_location) << errinfo_comment("Stack too deep.")); CompilerError() <<
errinfo_sourceLocation(_location) <<
errinfo_comment("Stack too deep, try removing local variables.")
);
solAssert(stackDiff >= m_size - 1, ""); solAssert(stackDiff >= m_size - 1, "");
for (unsigned i = 0; i < m_size; ++i) for (unsigned i = 0; i < m_size; ++i)
m_context << u256(0) << eth::swapInstruction(stackDiff + 1 - i) m_context << u256(0) << eth::swapInstruction(stackDiff + 1 - i)
@ -204,7 +213,10 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
// stack: source_ref source_off target_ref target_off member_slot_offset member_byte_offset source_member_ref source_member_off // stack: source_ref source_off target_ref target_off member_slot_offset member_byte_offset source_member_ref source_member_off
StorageItem(m_context, *memberType).retrieveValue(_location, true); StorageItem(m_context, *memberType).retrieveValue(_location, true);
// stack: source_ref source_off target_ref target_off member_offset source_value... // stack: source_ref source_off target_ref target_off member_offset source_value...
solAssert(4 + memberType->getSizeOnStack() <= 16, "Stack too deep."); solAssert(
4 + memberType->getSizeOnStack() <= 16,
"Stack too deep, try removing local varibales."
);
m_context m_context
<< eth::dupInstruction(4 + memberType->getSizeOnStack()) << eth::dupInstruction(4 + memberType->getSizeOnStack())
<< eth::dupInstruction(3 + memberType->getSizeOnStack()) << eth::Instruction::ADD << eth::dupInstruction(3 + memberType->getSizeOnStack()) << eth::Instruction::ADD

5
mix/MixClient.cpp

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

2
solc/CommandLineInterface.cpp

@ -412,8 +412,6 @@ bool CommandLineInterface::processInput()
// TODO: Perhaps we should not compile unless requested // TODO: Perhaps we should not compile unless requested
bool optimize = m_args["optimize"].as<bool>(); bool optimize = m_args["optimize"].as<bool>();
unsigned runs = m_args["optimize-runs"].as<unsigned>(); unsigned runs = m_args["optimize-runs"].as<unsigned>();
if (m_args.count("optimize-runs"))
optimize = true;
m_compiler->compile(optimize, runs); m_compiler->compile(optimize, runs);
} }
catch (ParserError const& _exception) catch (ParserError const& _exception)

4
test/fuzzTesting/checkRandomVMTest.cpp

@ -98,9 +98,9 @@ bool doVMTest(mValue& _v)
try try
{ {
auto vm = eth::VMFactory::create(); auto vm = eth::VMFactory::create();
output = vm->go(fev.gas, fev, fev.simpleTrace()).toBytes(); output = vm->exec(fev.gas, fev, fev.simpleTrace());
} }
catch (eth::VMException) catch (eth::VMException const&)
{ {
cnote << "Safe VM Exception"; cnote << "Safe VM Exception";
vmExceptionOccured = true; vmExceptionOccured = true;

2
test/fuzzTesting/createRandomVMTest.cpp

@ -160,7 +160,7 @@ void doMyTests(json_spirit::mValue& _v)
bool vmExceptionOccured = false; bool vmExceptionOccured = false;
try try
{ {
output = vm->go(fev.gas, fev, fev.simpleTrace()).toBytes(); output = vm->exec(fev.gas, fev, fev.simpleTrace());
} }
catch (eth::VMException const& _e) catch (eth::VMException const& _e)
{ {

4
test/libevm/vm.cpp

@ -330,12 +330,10 @@ void doVMTests(json_spirit::mValue& v, bool _fillin)
{ {
auto vm = eth::VMFactory::create(); auto vm = eth::VMFactory::create();
auto vmtrace = Options::get().vmtrace ? fev.simpleTrace() : OnOpFunc{}; auto vmtrace = Options::get().vmtrace ? fev.simpleTrace() : OnOpFunc{};
auto outputRef = bytesConstRef{};
{ {
Listener::ExecTimeGuard guard{i.first}; Listener::ExecTimeGuard guard{i.first};
outputRef = vm->go(fev.gas, fev, vmtrace); output = vm->exec(fev.gas, fev, vmtrace);
} }
output = outputRef.toBytes();
} }
catch (VMException const&) catch (VMException const&)
{ {

4
test/libsolidity/solidityExecutionFramework.h

@ -148,6 +148,8 @@ protected:
{ {
m_state.addBalance(m_sender, _value); // just in case m_state.addBalance(m_sender, _value); // just in case
eth::Executive executive(m_state, eth::LastHashes(), 0); eth::Executive executive(m_state, eth::LastHashes(), 0);
eth::ExecutionResult res;
executive.setResultRecipient(res);
eth::Transaction t = eth::Transaction t =
_isCreation ? _isCreation ?
eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) : eth::Transaction(_value, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec()) :
@ -176,7 +178,7 @@ protected:
m_state.noteSending(m_sender); m_state.noteSending(m_sender);
executive.finalize(); executive.finalize();
m_gasUsed = executive.gasUsed(); 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(); m_logs = executive.logs();
} }

Loading…
Cancel
Save