diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 674509b53..227f739ce 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1784,6 +1784,7 @@ void Main::on_debug_clicked() t.gasPrice = gasPrice(); t.gas = ui->gas->value(); t.data = m_data; + t.type = isCreation() ? Transaction::ContractCreation : Transaction::MessageCall; t.receiveAddress = isCreation() ? Address() : fromString(ui->destination->currentText()); t.sign(s); auto r = t.rlp(); diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index 11850fa69..5f14f38f8 100644 --- a/libdevcore/CommonData.h +++ b/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 inline std::vector<_T>& operator+=(std::vector::value, _T>::type>& _a, std::vector<_T> const& _b) { @@ -201,30 +201,38 @@ inline std::vector<_T>& operator+=(std::vector -inline std::vector<_T> operator+(std::vector::value, _T>::type> const& _a, std::vector<_T> const& _b) +inline std::vector<_T>& operator+=(std::vector::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 +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 -inline std::vector<_T>& operator+=(std::vector::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 -inline std::vector<_T> operator+(std::vector::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; } diff --git a/libdevcrypto/SHA3.cpp b/libdevcrypto/SHA3.cpp index b3a6e5955..eaabae0ff 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcrypto/SHA3.cpp @@ -20,8 +20,9 @@ */ #include "SHA3.h" -#include "CryptoPP.h" +#include +#include "CryptoPP.h" using namespace std; using namespace dev; @@ -29,6 +30,7 @@ namespace dev { h256 EmptySHA3 = sha3(bytesConstRef()); +h256 ZeroRLPSHA3 = sha3(rlp(bytesConstRef())); std::string sha3(std::string const& _input, bool _hex) { diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index fc2cfcfc3..5948cb3bd 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -57,6 +57,7 @@ inline h256 sha3(bytes const& _input) { return sha3(bytesConstRef((bytes*)&_inpu inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)); } extern h256 EmptySHA3; +extern h256 ZeroRLPSHA3; // Other crypto convenience routines diff --git a/libdevcrypto/TrieDB.h b/libdevcrypto/TrieDB.h index 1fca92294..0ca0b9d98 100644 --- a/libdevcrypto/TrieDB.h +++ b/libdevcrypto/TrieDB.h @@ -74,7 +74,7 @@ public: void init(); void setRoot(h256 _root) { - m_root = _root == h256() ? c_shaNull : _root; + m_root = _root; if (m_root == c_shaNull && !m_db->exists(m_root)) init(); @@ -82,14 +82,14 @@ public: if (!node(m_root).size()) BOOST_THROW_EXCEPTION(RootNotFound()); } - bool haveRoot(h256 _root, bool _enforceRefs = true) { return _root == h256() ? true : m_db->lookup(_root, _enforceRefs).size(); } + bool haveRoot(h256 _root, bool _enforceRefs = true) { return _root == c_shaNull ? true : m_db->lookup(_root, _enforceRefs).size(); } /// True if the trie is uninitialised (i.e. that the DB doesn't contain the root node). bool isNull() const { return !node(m_root).size(); } /// True if the trie is initialised but empty (i.e. that the DB contains the root node which is empty). bool isEmpty() const { return m_root == c_shaNull && node(m_root).size(); } - h256 root() const { assert(node(m_root).size()); h256 ret = (m_root == c_shaNull ? h256() : m_root); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return ret; } // patch the root in the case of the empty trie. TODO: handle this properly. + h256 root() const { assert(node(m_root).size()); /*std::cout << "Returning root as " << ret << " (really " << m_root << ")" << std::endl;*/ return m_root; } // patch the root in the case of the empty trie. TODO: handle this properly. void debugPrint() {} diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 4c9e2bef7..6e4af247f 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -60,11 +60,9 @@ auto static const c_sha3EmptyList = sha3(RLPEmptyList); void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const { - _s.appendList(_nonce ? 13 : 12) << parentHash; - _s.append(sha3Uncles == c_sha3EmptyList ? h256() : sha3Uncles, false, true); - _s << coinbaseAddress; - _s.append(stateRoot, false, true).append(transactionsRoot, false, true); - _s << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData; + _s.appendList(_nonce ? 13 : 12) + << parentHash << sha3Uncles << coinbaseAddress << stateRoot << transactionsRoot + << difficulty << number << minGasPrice << gasLimit << gasUsed << timestamp << extraData; if (_nonce) _s << nonce; } @@ -83,8 +81,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, bool _checkNonce) { parentHash = _header[field = 0].toHash(); sha3Uncles = _header[field = 1].toHash(); - if (sha3Uncles == h256()) - sha3Uncles = c_sha3EmptyList; coinbaseAddress = _header[field = 2].toHash
(); stateRoot = _header[field = 3].toHash(); transactionsRoot = _header[field = 4].toHash(); diff --git a/libethcore/CommonEth.cpp b/libethcore/CommonEth.cpp index 5f989689c..44ebe19c5 100644 --- a/libethcore/CommonEth.cpp +++ b/libethcore/CommonEth.cpp @@ -34,7 +34,7 @@ namespace dev namespace eth { -const unsigned c_protocolVersion = 36; +const unsigned c_protocolVersion = 37; const unsigned c_databaseVersion = 3; static const vector> g_units = diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 7b7b8a9e5..b08179f9e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -101,8 +101,8 @@ bytes BlockChain::createGenesisBlock() stateRoot = state.root(); } - block.appendList(13) << h256() << bytes() << h160(); - block.append(stateRoot, false, true) << bytes() << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); + block.appendList(13) + << h256() << c_shaNull << h160() << stateRoot << c_shaNull << c_genesisDifficulty << 0 << 0 << 1000000 << 0 << (unsigned)0 << string() << sha3(bytes(1, 42)); block.appendRaw(RLPEmptyList); block.appendRaw(RLPEmptyList); return block.out(); diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index ecce7406d..dc36957ee 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -325,6 +325,7 @@ void Client::transact(Secret _secret, u256 _value, Address _dest, bytes const& _ t.value = _value; t.gasPrice = _gasPrice; t.gas = _gas; + t.type = Transaction::MessageCall; t.receiveAddress = _dest; t.data = _data; t.sign(_secret); @@ -348,6 +349,7 @@ bytes Client::call(Secret _secret, u256 _value, Address _dest, bytes const& _dat t.value = _value; t.gasPrice = _gasPrice; t.gas = _gas; + t.type = Transaction::ContractCreation; t.receiveAddress = _dest; t.data = _data; t.sign(_secret); @@ -373,6 +375,7 @@ Address Client::transact(Secret _secret, u256 _endowment, bytes const& _init, u2 t.value = _endowment; t.gasPrice = _gasPrice; t.gas = _gas; + t.type = Transaction::ContractCreation; t.receiveAddress = Address(); t.data = _init; t.sign(_secret); diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 193010cfa..840287ca9 100644 --- a/libethereum/Executive.cpp +++ b/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(); } diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 82b7df7e9..cdfe23966 100644 --- a/libethereum/Executive.h +++ b/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; }; } diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index fc76d56b0..59b6eb2ab 100644 --- a/libethereum/ExtVM.h +++ b/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; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 931ee2cf6..40fac4883 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -353,9 +353,9 @@ void State::ensureCached(std::map& _cache, Address _a, bo RLP state(stateBack); AddressState s; if (state.isNull()) - s = AddressState(0, 0, h256(), EmptySHA3); + s = AddressState(0, 0, ZeroRLPSHA3, EmptySHA3); else - s = AddressState(state[0].toInt(), state[1].toInt(), state[2].toHash(), state[3].isEmpty() ? EmptySHA3 : state[3].toHash()); + s = AddressState(state[0].toInt(), state[1].toInt(), state[2].toHash(), state[3].toHash()); bool ok; tie(it, ok) = _cache.insert(make_pair(_a, s)); } @@ -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
* 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
* 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) diff --git a/libethereum/State.h b/libethereum/State.h index dd6043c73..776fb80e7 100644 --- a/libethereum/State.h +++ b/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
* 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
* 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(); @@ -367,16 +367,10 @@ void commit(std::map const& _cache, DB& _db, TrieDB(); gasPrice = rlp[field = 1].toInt(); gas = rlp[field = 2].toInt(); + type = rlp[field = 3].isEmpty() ? ContractCreation : MessageCall; receiveAddress = rlp[field = 3].toHash
(); value = rlp[field = 4].toInt(); data = rlp[field = 5].toBytes(); @@ -88,7 +89,7 @@ void Transaction::fillStream(RLPStream& _s, bool _sig) const { _s.appendList((_sig ? 3 : 0) + 6); _s << nonce << gasPrice << gas; - if (receiveAddress) + if (type == MessageCall) _s << receiveAddress; else _s << ""; diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index eb40c5fcb..ca73ba06a 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -32,13 +32,20 @@ namespace eth struct Transaction { + enum Type + { + ContractCreation, + MessageCall + }; + Transaction() {} Transaction(bytesConstRef _rlp, bool _checkSender = false); Transaction(bytes const& _rlp, bool _checkSender = false): Transaction(&_rlp, _checkSender) {} - bool operator==(Transaction const& _c) const { return receiveAddress == _c.receiveAddress && value == _c.value && data == _c.data; } + bool operator==(Transaction const& _c) const { return type == _c.type && (type == ContractCreation || receiveAddress == _c.receiveAddress) && value == _c.value && data == _c.data; } bool operator!=(Transaction const& _c) const { return !operator==(_c); } + Type type; ///< True if this is a contract-creation transaction. F u256 nonce; ///< The transaction-count of the sender. u256 value; ///< The amount of ETH to be transferred by this transaction. Called 'endowment' for contract-creation transactions. Address receiveAddress; ///< The receiving address of the transaction. diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 67fec9321..b57818907 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -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; + +struct SubState +{ + std::set
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; @@ -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
suicides; ///< Any accounts that have suicided. + SubState sub; ///< Sub-band VM state (suicides, refund counter, logs). unsigned depth; ///< Depth of the present call. }; diff --git a/libevm/FeeStructure.cpp b/libevm/FeeStructure.cpp index d29b9fef9..47236b506 100644 --- a/libevm/FeeStructure.cpp +++ b/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; diff --git a/libevm/FeeStructure.h b/libevm/FeeStructure.h index 76be9a398..84a2551d9 100644 --- a/libevm/FeeStructure.h +++ b/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. diff --git a/libevm/VM.h b/libevm/VM.h index eed1988bb..f3c82c714 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -117,11 +117,14 @@ template 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: @@ -236,7 +239,7 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::PUSH31: case Instruction::PUSH32: break; - case Instruction::NEG: + case Instruction::BNOT: case Instruction::NOT: case Instruction::CALLDATALOAD: case Instruction::EXTCODESIZE: @@ -261,8 +264,8 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con case Instruction::OR: case Instruction::XOR: case Instruction::BYTE: - case Instruction::SIGNEXTEND: case Instruction::JUMPI: + case Instruction::SIGNEXTEND: require(2); break; case Instruction::ADDMOD: @@ -369,8 +372,8 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.back() = (u256)boost::multiprecision::powm((bigint)base, (bigint)expon, bigint(2) << 256); break; } - case Instruction::NEG: - m_stack.back() = ~(m_stack.back() - 1); + case Instruction::BNOT: + m_stack.back() = ~m_stack.back(); break; case Instruction::LT: m_stack[m_stack.size() - 2] = m_stack.back() < m_stack[m_stack.size() - 2] ? 1 : 0; @@ -422,18 +425,21 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con m_stack.pop_back(); break; case Instruction::SIGNEXTEND: - if (m_stack.back() < 31) + { + unsigned k = m_stack[m_stack.size() - 2]; + if (k > 31) + m_stack[m_stack.size() - 2] = m_stack.back(); + else { - unsigned const testBit(m_stack.back() * 8 + 7); - u256& number = m_stack[m_stack.size() - 2]; - u256 mask = ((u256(1) << testBit) - 1); - if (boost::multiprecision::bit_test(number, testBit)) - number |= ~mask; - else - number &= mask; + u256 b = m_stack.back(); + if ((b >> (k * 8)) & 0x80) + for (int i = 31; i > k; --i) + b |= (u256(0xff) << i); + m_stack[m_stack.size() - 2] = b; } m_stack.pop_back(); break; + } case Instruction::SHA3: { unsigned inOff = (unsigned)m_stack.back(); diff --git a/libevmface/Instruction.cpp b/libevmface/Instruction.cpp index 238b21512..c9b6ea2ce 100644 --- a/libevmface/Instruction.cpp +++ b/libevmface/Instruction.cpp @@ -39,7 +39,7 @@ const std::map dev::eth::c_instructions = { "MOD", Instruction::MOD }, { "SMOD", Instruction::SMOD }, { "EXP", Instruction::EXP }, - { "NEG", Instruction::NEG }, + { "BNOT", Instruction::BNOT }, { "LT", Instruction::LT }, { "GT", Instruction::GT }, { "SLT", Instruction::SLT }, @@ -167,7 +167,7 @@ static const std::map c_instructionInfo = { Instruction::MOD, { "MOD", 0, 2, 1 } }, { Instruction::SMOD, { "SMOD", 0, 2, 1 } }, { Instruction::EXP, { "EXP", 0, 2, 1 } }, - { Instruction::NEG, { "NEG", 0, 1, 1 } }, + { Instruction::BNOT, { "BNOT", 0, 1, 1 } }, { Instruction::LT, { "LT", 0, 2, 1 } }, { Instruction::GT, { "GT", 0, 2, 1 } }, { Instruction::SLT, { "SLT", 0, 2, 1 } }, diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index ce587dfaf..faad50fb2 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -44,7 +44,7 @@ enum class Instruction: uint8_t MOD, ///< modulo remainder operation SMOD, ///< signed modulo remainder operation EXP, ///< exponential operation - NEG, ///< negation operation + BNOT, ///< bitwise not LT, ///< less-than comparision GT, ///< greater-than comparision SLT, ///< signed less-than comparision @@ -58,7 +58,7 @@ enum class Instruction: uint8_t BYTE, ///< retrieve single byte from word ADDMOD, ///< unsigned modular addition MULMOD, ///< unsigned modular multiplication - SIGNEXTEND, ///< perform sign extension starting at given bit + SIGNEXTEND, ///< extend length of signed integer SHA3 = 0x20, ///< compute SHA3-256 hash ADDRESS = 0x30, ///< get address of currently executing account diff --git a/test/MemTrie.cpp b/test/MemTrie.cpp index 4879f2674..c3a44e1e5 100644 --- a/test/MemTrie.cpp +++ b/test/MemTrie.cpp @@ -437,12 +437,12 @@ MemTrie::~MemTrie() h256 MemTrie::hash256() const { - return m_root ? m_root->hash256() : h256(); + return m_root ? m_root->hash256() : sha3(dev::rlp(bytesConstRef())); } bytes MemTrie::rlp() const { - return m_root ? m_root->rlp() : bytes(); + return m_root ? m_root->rlp() : dev::rlp(bytesConstRef()); } void MemTrie::debugPrint() diff --git a/test/TrieHash.cpp b/test/TrieHash.cpp index af32e870d..ee4f2e87d 100644 --- a/test/TrieHash.cpp +++ b/test/TrieHash.cpp @@ -162,7 +162,7 @@ h256 hash256(StringMap const& _s) { // build patricia tree. if (_s.empty()) - return h256(); + return sha3(rlp("")); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) hexMap[asNibbles(i->first)] = i->second; @@ -175,7 +175,7 @@ bytes rlp256(StringMap const& _s) { // build patricia tree. if (_s.empty()) - return bytes(); + return rlp(""); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) hexMap[asNibbles(i->first)] = i->second; @@ -188,7 +188,7 @@ h256 hash256(u256Map const& _s) { // build patricia tree. if (_s.empty()) - return h256(); + return sha3(rlp("")); HexMap hexMap; for (auto i = _s.rbegin(); i != _s.rend(); ++i) hexMap[asNibbles(toBigEndianString(i->first))] = asString(rlp(i->second)); diff --git a/test/crypto.cpp b/test/crypto.cpp index 0d3b6202f..67286bfca 100644 --- a/test/crypto.cpp +++ b/test/crypto.cpp @@ -341,6 +341,7 @@ BOOST_AUTO_TEST_CASE(eth_keypairs) { eth::Transaction t; t.nonce = 0; + t.type = eth::Transaction::MessageCall; t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.value = 1000; auto rlp = t.rlp(false); @@ -369,6 +370,7 @@ int cryptoTest() { eth::Transaction t; t.nonce = 0; + t.type = eth::Transaction::MessageCall; t.receiveAddress = h160(fromHex("944400f4b88ac9589a0f17ed4671da26bddb668b")); t.value = 1000; auto rlp = t.rlp(false); @@ -397,6 +399,7 @@ int cryptoTest() Transaction t; t.nonce = 0; t.value = 1; // 1 wei. + t.type = eth::Transaction::MessageCall; t.receiveAddress = toAddress(sha3("123")); bytes sig64 = toBigEndian(t.vrs.r) + toBigEndian(t.vrs.s); diff --git a/test/state.cpp b/test/state.cpp index 99ce30957..b0f279bac 100644 --- a/test/state.cpp +++ b/test/state.cpp @@ -68,6 +68,7 @@ int stateTest() Transaction t; t.nonce = s.transactionsFrom(myMiner.address()); t.value = 1000; // 1e3 wei. + t.type = eth::Transaction::MessageCall; t.receiveAddress = me.address(); t.sign(myMiner.secret()); assert(t.sender() == myMiner.address()); diff --git a/test/vm.cpp b/test/vm.cpp index 13efa18e3..f035bd1b0 100644 --- a/test/vm.cpp +++ b/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(); @@ -56,7 +56,7 @@ h160 FakeExtVM::create(u256 _endowment, u256* _gas, bytesConstRef _init, OnOpFun get<3>(addresses[ret]) = m_s.code(ret); } - t.receiveAddress = Address(); + t.type = eth::Transaction::ContractCreation; callcreates.push_back(t); return ret; } @@ -71,6 +71,7 @@ bool FakeExtVM::call(Address _receiveAddress, u256 _value, bytesConstRef _data, t.gasPrice = gasPrice; t.gas = *_gas; t.data = _data.toVector(); + t.type = eth::Transaction::MessageCall; t.receiveAddress = _receiveAddress; callcreates.push_back(t); @@ -91,7 +92,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 +117,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 +132,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()), Executive::simpleTrace(), 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 +147,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)) { @@ -384,7 +388,7 @@ mArray FakeExtVM::exportCallCreates() for (Transaction const& tx: callcreates) { mObject o; - o["destination"] = toString(tx.receiveAddress); + o["destination"] = tx.type == Transaction::ContractCreation ? "" : toString(tx.receiveAddress); push(o, "gasLimit", tx.gas); push(o, "value", tx.value); o["data"] = "0x" + toHex(tx.data); @@ -403,6 +407,7 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) BOOST_REQUIRE(tx.count("destination") > 0); BOOST_REQUIRE(tx.count("gasLimit") > 0); Transaction t; + t.type = tx["destination"].get_str().empty() ? Transaction::ContractCreation : Transaction::MessageCall; t.receiveAddress = Address(tx["destination"].get_str()); t.value = toInt(tx["value"]); t.gas = toInt(tx["gasLimit"]); @@ -418,28 +423,11 @@ void FakeExtVM::importCallCreates(mArray& _callcreates) } } -OnOpFunc FakeExtVM::simpleTrace() +// 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) { - return [](uint64_t steps, Instruction inst, bigint newMemSize, bigint gasCost, void* voidVM, void const* voidExt) - { - FakeExtVM const& ext = *(FakeExtVM const*)voidExt; - VM& vm = *(VM*)voidVM; - - ostringstream o; - o << endl << " STACK" << endl; - for (auto i: vm.stack()) - o << (h256)i << endl; - o << " MEMORY" << endl << memDump(vm.memory()); - o << " STORAGE" << endl; - for (auto const& i: ext.state().storage(ext.myAddress)) - o << showbase << hex << i.first << ": " << i.second << endl; - dev::LogOutputStream(true) << o.str(); - dev::LogOutputStream(false) << " | " << dec << ext.depth << " | " << ext.myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm.curPC() << " : " << instructionInfo(inst).name << " | " << dec << vm.gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32" << " ]"; - }; -} + (void)o_sub; -h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, bytesConstRef _code, Address _origin, std::set
* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) -{ if (!_origin) _origin = _sender; @@ -465,9 +453,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*/) { @@ -504,7 +490,6 @@ h160 FakeState::createNewAddress(Address _newAddress, Address _sender, u256 _end - namespace dev { namespace test { void doTests(json_spirit::mValue& v, bool _fillin) @@ -536,7 +521,7 @@ void doTests(json_spirit::mValue& v, bool _fillin) VM vm(fev.gas); try { - output = vm.go(fev, fev.simpleTrace()).toVector(); + output = vm.go(fev).toVector(); } catch (Exception const& _e) { @@ -772,30 +757,3 @@ BOOST_AUTO_TEST_CASE(vmSystemOperationsTest) { dev::test::executeTests("vmSystemOperationsTest"); } - -BOOST_AUTO_TEST_CASE(userDefinedFile) -{ - - if (boost::unit_test::framework::master_test_suite().argc == 2) - { - string filename = boost::unit_test::framework::master_test_suite().argv[1]; - g_logVerbosity = 12; - try - { - cnote << "Testing VM..." << "user defined test"; - json_spirit::mValue v; - string s = asString(contents(filename)); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); - json_spirit::read_string(s, v); - dev::test::doTests(v, false); - } - catch (Exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << diagnostic_information(_e)); - } - catch (std::exception const& _e) - { - BOOST_ERROR("Failed VM Test with Exception: " << _e.what()); - } - } -} diff --git a/test/vm.h b/test/vm.h index baf5986bc..bf44c4b42 100644 --- a/test/vm.h +++ b/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
* 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