diff --git a/alethzero/MainWin.h b/alethzero/MainWin.h index 50b9df413..fffc5843f 100644 --- a/alethzero/MainWin.h +++ b/alethzero/MainWin.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 2546d484f..007896d75 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include "Interface.h" #include "Executive.h" @@ -32,10 +33,6 @@ using namespace dev::eth; #define ETH_VMTRACE 1 -Executive::~Executive() -{ -} - u256 Executive::gasUsed() const { return m_t.gas() - m_endGas; @@ -114,9 +111,9 @@ bool Executive::call(Address _receiveAddress, Address _senderAddress, u256 _valu } else if (m_s.addressHasCode(_receiveAddress)) { - m_vm = make_shared(_gas); + m_vm = VMFactory::create(_gas); bytes const& c = m_s.code(_receiveAddress); - m_ext = make_shared(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c); + m_ext.reset(new ExtVM(m_s, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &c)); } else m_endGas = _gas; @@ -133,8 +130,8 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress) + _endowment, Account::ContractConception); // Execute _init. - m_vm = make_shared(_gas); - m_ext = make_shared(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init); + m_vm = VMFactory::create(_gas); + m_ext.reset(new ExtVM(m_s, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init)); return _init.empty(); } diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 1b2f3ad75..9e47bbfbf 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -25,26 +25,27 @@ #include #include #include -#include +#include #include "Transaction.h" -#include "Manifest.h" +#include "ExtVM.h" namespace dev { namespace eth { -class VM; -class ExtVM; class State; +struct Manifest; struct VMTraceChannel: public LogChannel { static const char* name() { return "EVM"; } static const int verbosity = 11; }; class Executive { public: - Executive(State& _s): m_s(_s){} - ~Executive(); + Executive(State& _s): m_s(_s) {} + ~Executive() = default; + Executive(Executive const&) = delete; + void operator=(Executive) = delete; bool setup(bytesConstRef _transaction); bool create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress); @@ -63,14 +64,14 @@ public: h160 newAddress() const { return m_newAddress; } LogEntries const& logs() const { return m_logs; } - VM const& vm() const { return *m_vm; } + VMFace const& vm() const { return *m_vm; } State const& state() const { return m_s; } ExtVM const& ext() const { return *m_ext; } private: State& m_s; - std::shared_ptr m_ext; - std::shared_ptr m_vm; + std::unique_ptr m_ext; + std::unique_ptr m_vm; bytesConstRef m_out; Address m_newAddress; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index d5c71efe3..1d6ad3480 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -29,10 +29,11 @@ #include #include #include -#include +#include #include "BlockChain.h" #include "Defaults.h" #include "ExtVM.h" +#include "Executive.h" using namespace std; using namespace dev; using namespace dev::eth; @@ -1093,7 +1094,7 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const return false; } } - catch (InvalidTrie) + catch (InvalidTrie const&) { cwarn << "BAD TRIE" << (e ? "[enforced" : "[unenforced") << "refs]"; cnote << m_db.keys(); @@ -1196,15 +1197,15 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA } else if (addressHasCode(_codeAddress)) { - VM vm(*_gas); + auto vm = VMFactory::create(*_gas); ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), _level); try { - auto out = vm.go(evm, _onOp); + auto out = vm->go(evm, _onOp); memcpy(_out.data(), out.data(), std::min(out.size(), _out.size())); if (o_sub) *o_sub += evm.sub; - *_gas = vm.gas(); + *_gas = vm->gas(); // Write state out only in the case of a non-excepted transaction. return true; } @@ -1244,16 +1245,16 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, m_cache[newAddress] = Account(balance(newAddress) + _endowment, Account::ContractConception); // Execute init code. - VM vm(*_gas); + auto vm = VMFactory::create(*_gas); ExtVM evm(*this, newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _code, _level); bytesConstRef out; try { - out = vm.go(evm, _onOp); + out = vm->go(evm, _onOp); if (o_sub) *o_sub += evm.sub; - *_gas = vm.gas(); + *_gas = vm->gas(); if (out.size() * c_createDataGas <= *_gas) *_gas -= out.size() * c_createDataGas; diff --git a/libethereum/State.h b/libethereum/State.h index 05e10df3e..10d73f671 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -36,7 +36,6 @@ #include "Account.h" #include "Transaction.h" #include "TransactionReceipt.h" -#include "Executive.h" #include "AccountDiff.h" namespace dev diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 206128e76..24c7dfcda 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -153,7 +153,7 @@ public: BlockInfo previousBlock; ///< The previous block's information. BlockInfo currentBlock; ///< The current block's information. SubState sub; ///< Sub-band VM state (suicides, refund counter, logs). - unsigned depth; ///< Depth of the present call. + unsigned depth = 0; ///< Depth of the present call. }; } diff --git a/libevm/VM.cpp b/libevm/VM.cpp index bded9a10d..b8452e4f5 100644 --- a/libevm/VM.cpp +++ b/libevm/VM.cpp @@ -20,14 +20,14 @@ */ #include "VM.h" +#include -using namespace std; using namespace dev; using namespace dev::eth; -void VM::reset(u256 _gas) +void VM::reset(u256 _gas) noexcept { - m_gas = _gas; + VMFace::reset(_gas); m_curPC = 0; m_jumpDests.clear(); } diff --git a/libevm/VM.h b/libevm/VM.h index fad9392f6..6f3229920 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -28,21 +28,13 @@ #include #include #include "FeeStructure.h" -#include "ExtVMFace.h" +#include "VMFace.h" namespace dev { namespace eth { -struct VMException: virtual Exception {}; -struct StepsDone: virtual VMException {}; -struct BreakPointHit: virtual VMException {}; -struct BadInstruction: virtual VMException {}; -struct BadJumpDestination: virtual VMException {}; -struct OutOfGas: virtual VMException {}; -struct StackTooSmall: virtual public VMException {}; - // Convert from a 256-bit integer stack/memory entry into a 160-bit Address hash. // Currently we just pull out the right (low-order in BE) 160-bits. inline Address asAddress(u256 _item) @@ -57,28 +49,27 @@ inline u256 fromAddress(Address _a) /** */ -class VM +class VM: public VMFace { public: - /// Construct VM object. - explicit VM(u256 _gas = 0) { reset(_gas); } - - void reset(u256 _gas = 0); + virtual void reset(u256 _gas = 0) noexcept override final; - template - bytesConstRef go(Ext& _ext, OnOpFunc const& _onOp = OnOpFunc(), uint64_t _steps = (uint64_t)-1); + virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) override final; void require(u256 _n) { if (m_stack.size() < _n) { if (m_onFail) m_onFail(); BOOST_THROW_EXCEPTION(StackTooSmall() << RequirementError((bigint)_n, (bigint)m_stack.size())); } } void requireMem(unsigned _n) { if (m_temp.size() < _n) { m_temp.resize(_n); } } - u256 gas() const { return m_gas; } u256 curPC() const { return m_curPC; } bytes const& memory() const { return m_temp; } u256s const& stack() const { return m_stack; } private: - u256 m_gas = 0; + friend class VMFactory; + + /// Construct VM object. + explicit VM(u256 _gas): VMFace(_gas) {} + u256 m_curPC = 0; bytes m_temp; u256s m_stack; @@ -86,10 +77,8 @@ private: std::function m_onFail; }; -} - -// INLINE: -template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc const& _onOp, uint64_t _steps) +// TODO: Move it to cpp file. Not done to make review easier. +inline bytesConstRef VM::go(ExtVMFace& _ext, OnOpFunc const& _onOp, uint64_t _steps) { auto memNeed = [](dev::u256 _offset, dev::u256 _size) { return _size ? (bigint)_offset + _size : (bigint)0; }; @@ -164,7 +153,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::SLOAD: require(1); - runGas = c_sloadGas; + runGas = c_sloadGas; break; // These all operate on memory and therefore potentially expand it: @@ -412,7 +401,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.pop_back(); break; case Instruction::SDIV: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0; + m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) / u2s(m_stack[m_stack.size() - 2])) : 0; m_stack.pop_back(); break; case Instruction::MOD: @@ -420,7 +409,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.pop_back(); break; case Instruction::SMOD: - m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0; + m_stack[m_stack.size() - 2] = m_stack[m_stack.size() - 2] ? s2u(u2s(m_stack.back()) % u2s(m_stack[m_stack.size() - 2])) : 0; m_stack.pop_back(); break; case Instruction::EXP: @@ -443,11 +432,11 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.pop_back(); break; case Instruction::SLT: - m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; + m_stack[m_stack.size() - 2] = u2s(m_stack.back()) < u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; m_stack.pop_back(); break; case Instruction::SGT: - m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; + m_stack[m_stack.size() - 2] = u2s(m_stack.back()) > u2s(m_stack[m_stack.size() - 2]) ? 1 : 0; m_stack.pop_back(); break; case Instruction::EQ: @@ -870,4 +859,6 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con BOOST_THROW_EXCEPTION(StepsDone()); return bytesConstRef(); } + +} } diff --git a/libevm/VMFace.h b/libevm/VMFace.h new file mode 100644 index 000000000..44ae03868 --- /dev/null +++ b/libevm/VMFace.h @@ -0,0 +1,55 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +#pragma once + +#include +#include +#include "ExtVMFace.h" + +namespace dev +{ +namespace eth +{ + +struct VMException: virtual Exception {}; +struct StepsDone: virtual VMException {}; +struct BreakPointHit: virtual VMException {}; +struct BadInstruction: virtual VMException {}; +struct BadJumpDestination: virtual VMException {}; +struct OutOfGas: virtual VMException {}; +struct StackTooSmall: virtual VMException {}; + +/// EVM Virtual Machine interface +class VMFace +{ +public: + explicit VMFace(u256 _gas): m_gas(_gas) {} + virtual ~VMFace() = default; + VMFace(VMFace const&) = delete; + void operator=(VMFace const&) = delete; + + virtual void reset(u256 _gas = 0) noexcept { m_gas = _gas; } + u256 gas() const noexcept { return m_gas; } + + virtual bytesConstRef go(ExtVMFace& _ext, OnOpFunc const& _onOp = {}, uint64_t _steps = (uint64_t)-1) = 0; + +protected: + u256 m_gas = 0; +}; + +} +} diff --git a/libevm/VMFactory.cpp b/libevm/VMFactory.cpp new file mode 100644 index 000000000..af37ec710 --- /dev/null +++ b/libevm/VMFactory.cpp @@ -0,0 +1,42 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ + +#include "VMFactory.h" +#include "VM.h" + +namespace dev +{ +namespace eth +{ +namespace +{ + VMKind g_kind = VMKind::Interpreter; +} + +void VMFactory::setKind(VMKind _kind) +{ + g_kind = _kind; +} + +std::unique_ptr VMFactory::create(u256 _gas) +{ + asserts(g_kind == VMKind::Interpreter && "Only interpreter supported for now"); + return std::unique_ptr(new VM(_gas)); +} + +} +} diff --git a/libevm/VMFactory.h b/libevm/VMFactory.h new file mode 100644 index 000000000..d0d02e0c4 --- /dev/null +++ b/libevm/VMFactory.h @@ -0,0 +1,42 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +#pragma once + +#include "VMFace.h" + +namespace dev +{ +namespace eth +{ + +enum class VMKind: bool +{ + Interpreter, + JIT +}; + +class VMFactory +{ +public: + VMFactory() = delete; + + static std::unique_ptr create(u256 _gas); + static void setKind(VMKind _kind); +}; + +} +} diff --git a/test/createRandomTest.cpp b/test/createRandomTest.cpp index caeeb6b67..a11688457 100644 --- a/test/createRandomTest.cpp +++ b/test/createRandomTest.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include "vm.h" using namespace std; @@ -142,14 +142,14 @@ void doMyTests(json_spirit::mValue& v) } bytes output; - eth::VM vm(fev.gas); + auto vm = eth::VMFactory::create(fev.gas); u256 gas; bool vmExceptionOccured = false; try { - output = vm.go(fev, fev.simpleTrace()).toBytes(); - gas = vm.gas(); + output = vm->go(fev, fev.simpleTrace()).toBytes(); + gas = vm->gas(); } catch (eth::VMException const& _e) { diff --git a/test/vm.cpp b/test/vm.cpp index 8fe378cef..d8e85383c 100644 --- a/test/vm.cpp +++ b/test/vm.cpp @@ -21,6 +21,8 @@ */ #include +#include +#include #include "vm.h" using namespace std; @@ -298,14 +300,14 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) } bytes output; - VM vm(fev.gas); + auto vm = eth::VMFactory::create(fev.gas); u256 gas; bool vmExceptionOccured = false; try { - output = vm.go(fev, fev.simpleTrace()).toBytes(); - gas = vm.gas(); + output = vm->go(fev, fev.simpleTrace()).toBytes(); + gas = vm->gas(); } catch (VMException const& _e) { diff --git a/windows/LibEthereum.vcxproj b/windows/LibEthereum.vcxproj index 06f868023..cbacd51b5 100644 --- a/windows/LibEthereum.vcxproj +++ b/windows/LibEthereum.vcxproj @@ -368,6 +368,7 @@ true true + @@ -568,4 +569,4 @@ - + \ No newline at end of file diff --git a/windows/LibEthereum.vcxproj.filters b/windows/LibEthereum.vcxproj.filters index 114364008..76201d823 100644 --- a/windows/LibEthereum.vcxproj.filters +++ b/windows/LibEthereum.vcxproj.filters @@ -190,18 +190,14 @@ libdevcrypto - - libdevcrypto - - - libdevcrypto - libethereum libevmcore + + @@ -438,6 +434,9 @@ libevmcore + + libevm +