diff --git a/libdevcrypto/SHA3.cpp b/libdevcrypto/SHA3.cpp index 4c5ee9fae..58d5329ef 100644 --- a/libdevcrypto/SHA3.cpp +++ b/libdevcrypto/SHA3.cpp @@ -58,6 +58,22 @@ void sha3(bytesConstRef _input, bytesRef _output) ctx.Final(_output.data()); } +void ripemd160(bytesConstRef _input, bytesRef _output) +{ + CryptoPP::RIPEMD160 ctx; + ctx.Update((byte*)_input.data(), _input.size()); + assert(_output.size() >= 32); + ctx.Final(_output.data()); +} + +void sha256(bytesConstRef _input, bytesRef _output) +{ + CryptoPP::SHA256 ctx; + ctx.Update((byte*)_input.data(), _input.size()); + assert(_output.size() >= 32); + ctx.Final(_output.data()); +} + bytes sha3Bytes(bytesConstRef _input) { bytes ret(32); diff --git a/libdevcrypto/SHA3.h b/libdevcrypto/SHA3.h index f3837fcc9..caadfeaf9 100644 --- a/libdevcrypto/SHA3.h +++ b/libdevcrypto/SHA3.h @@ -60,7 +60,13 @@ inline h256 sha3(std::string const& _input) { return sha3(bytesConstRef(_input)) extern h256 EmptySHA3; +// Other crypto convenience routines + bytes aesDecrypt(bytesConstRef _cipher, std::string const& _password, unsigned _rounds = 2000, bytesConstRef _salt = bytesConstRef()); +void sha256(bytesConstRef _input, bytesRef _output); + +void ripemd160(bytesConstRef _input, bytesRef _output); + } } diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index fda4a1a02..61d179ed8 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -218,15 +218,12 @@ u256 Executive::gas() const return m_vm ? m_vm->gas() : m_endGas; } -void Executive::finalize(OnOpFunc const& _onOp) +void Executive::finalize(OnOpFunc const&) { if (m_t.isCreation() && m_newAddress && m_out.size()) // non-reverted creation - put code in place. m_s.m_cache[m_newAddress].setCode(m_out); - if (m_ext) - m_endGas += m_ext->doPosts(_onOp); - // cnote << "Refunding" << formatBalance(m_endGas * m_ext->gasPrice) << "to origin (=" << m_endGas << "*" << formatBalance(m_ext->gasPrice) << ")"; m_s.addBalance(m_sender, m_endGas * m_t.gasPrice); diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index b4db1975e..3b4b7161f 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, &posts, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1); + auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 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, &posts, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 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, level + 1); if (m_ms && !m_ms->internal.back().from) m_ms->internal.pop_back(); return ret; @@ -98,20 +98,6 @@ public: /// @TODO check call site for the parent manifest being discarded. void revert() { if (m_ms) *m_ms = Manifest(); m_s.m_cache = m_origCache; } - /// Execute any posts we have left. - u256 doPosts(OnOpFunc const& _onOp = OnOpFunc()) - { - u256 ret; - while (posts.size()) - { - Post& p = posts.front(); - call(p.to, p.value, &p.data, &p.gas, bytesRef(), _onOp, p.from); - ret += p.gas; - posts.pop_front(); - } - return ret; - } - State& state() const { return m_s; } /// @note not a part of the main API; just for use by tracing/debug stuff. diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 13cd48f92..047b9dcd5 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -41,6 +41,50 @@ using namespace dev::eth; static const u256 c_blockReward = 1500 * finney; +void ecrecoverCode(bytesConstRef _in, bytesRef _out) +{ + struct inType + { + h256 hash; + h256 v; + h256 r; + h256 s; + } in; + + h256 ret; + + memcpy(&in, _in.data(), min(_in.size(), sizeof(in))); + + byte pubkey[65]; + int pubkeylen = 65; + secp256k1_start(); + if (secp256k1_ecdsa_recover_compact(in.hash.data(), 32, in.r.data(), pubkey, &pubkeylen, 0, (int)(u256)in.v - 27)) + ret = dev::eth::sha3(bytesConstRef(&(pubkey[1]), 64)); + + memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret))); +} + +void sha256Code(bytesConstRef _in, bytesRef _out) +{ + h256 ret; + sha256(_in, bytesRef(ret.data(), 32)); + memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret))); +} + +void ripemd160Code(bytesConstRef _in, bytesRef _out) +{ + h256 ret; + ripemd160(_in, bytesRef(ret.data(), 32)); + memcpy(_out.data(), &ret, min(_out.size(), sizeof(ret))); +} + +const std::map State::c_precompiled = +{ + { 1, { 500, ecrecoverCode }}, + { 2, { 100, sha256Code }}, + { 3, { 100, ripemd160Code }} +}; + OverlayDB State::openDB(std::string _path, bool _killExisting) { if (_path.empty()) @@ -1061,7 +1105,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, PostList* o_posts, 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, std::set
* o_suicides, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) { if (!_originAddress) _originAddress = _senderAddress; @@ -1077,7 +1121,16 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA o_ms->input = _data.toBytes(); } - if (addressHasCode(_codeAddress)) + auto it = !(_codeAddress & ~h160(0xffffffff)) ? c_precompiled.find((unsigned)(u160)_codeAddress) : c_precompiled.end(); + if (it != c_precompiled.end()) + { + if (*_gas >= it->second.gas) + { + *_gas -= it->second.gas; + it->second.exec(_data, _out); + } + } + else if (addressHasCode(_codeAddress)) { VM vm(*_gas); ExtVM evm(*this, _receiveAddress, _senderAddress, _originAddress, _value, _gasPrice, _data, &code(_codeAddress), o_ms, _level); @@ -1090,9 +1143,6 @@ bool State::call(Address _receiveAddress, Address _codeAddress, Address _senderA if (o_suicides) for (auto i: evm.suicides) o_suicides->insert(i); - if (o_posts) - for (auto i: evm.posts) - o_posts->push_back(i); if (o_ms) o_ms->output = out.toBytes(); } @@ -1125,7 +1175,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, PostList* o_posts, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) +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) { if (!_origin) _origin = _sender; @@ -1157,9 +1207,6 @@ h160 State::create(Address _sender, u256 _endowment, u256 _gasPrice, u256* _gas, if (o_suicides) for (auto i: evm.suicides) o_suicides->insert(i); - if (o_posts) - for (auto i: evm.posts) - o_posts->push_back(i); } catch (OutOfGas const& /*_e*/) { diff --git a/libethereum/State.h b/libethereum/State.h index a716eb610..a28d8155c 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -69,6 +69,12 @@ struct TransactionReceipt Manifest changes; }; +struct PrecompiledAddress +{ + unsigned gas; + std::function exec; +}; + /** * @brief Model of the current state of the ledger. * Maintains current ledger (m_current) as a fast hash-map. This is hashed only when required (i.e. to create or verify a block). @@ -277,12 +283,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, PostList* o_posts = 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(), std::set
* o_suicides = 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, PostList* o_posts = 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(), std::set
* o_suicides = 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(); @@ -321,6 +327,8 @@ private: static std::string c_defaultPath; + static const std::map c_precompiled; + friend std::ostream& operator<<(std::ostream& _out, State const& _s); }; diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 2fe6b9c18..f78cb82cb 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -42,8 +42,6 @@ struct Post u256 gas; }; -using PostList = std::list; - using OnOpFunc = std::function; /** @@ -88,15 +86,9 @@ public: /// Make a new message call. bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; } - /// Post a new message call. - void post(Address _to, u256 _value, bytesConstRef _data, u256 _gas) { posts.push_back(Post({myAddress, _to, _value, _data.toBytes(), _gas})); } - /// Revert any changes made (by any of the other calls). void revert() {} - /// Execute any posts that may exist, including those that are incurred as a result of earlier posts. - void doPosts() {} - Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be). Address caller; ///< Address which sent the message (either equal to origin or a contract). Address origin; ///< Original transactor. @@ -107,7 +99,6 @@ public: BlockInfo previousBlock; ///< The previous block's information. BlockInfo currentBlock; ///< The current block's information. std::set
suicides; ///< Any accounts that have suicided. - std::list posts; ///< Any posts that have been made. }; } diff --git a/test/vm.cpp b/test/vm.cpp index 0f9073719..a90b122e2 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, &posts, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); + auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); @@ -83,7 +83,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.create(myAddress, 0, gasPrice, _gas, init, origin, &suicides, &posts, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); + auto na = m_s.create(myAddress, 0, gasPrice, _gas, init, origin, &suicides, &m_ms ? &(m_ms.internal.back()) : nullptr, OnOpFunc(), 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); if (!m_s.addresses().count(_receiveAddress)) @@ -96,7 +96,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, Address() ? Address() : _receiveAddress, Address() ? Address() : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &posts, &(m_ms.internal.back()), OnOpFunc(), 1); + auto ret = m_s.call(_receiveAddress, Address() ? Address() : _receiveAddress, Address() ? Address() : myAddress, _value, gasPrice, _data, _gas, _out, origin, &suicides, &(m_ms.internal.back()), OnOpFunc(), 1); if (!m_ms.internal.back().from) m_ms.internal.pop_back(); if (!ret)