From b902b3e701f7a06059e5290fb6b2f5edcd49c72f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 23 Aug 2014 19:30:46 +0200 Subject: [PATCH] POST for PoC-6 --- alethzero/MainWin.cpp | 1 + eth/main.cpp | 15 +++++++++------ libethereum/Client.cpp | 6 +++--- libethereum/Executive.cpp | 12 +++++------- libethereum/Executive.h | 2 +- libethereum/ExtVM.h | 18 ++++++++++++++++-- libethereum/Miner.h | 10 +++++----- libethereum/PeerSession.cpp | 2 +- libethereum/State.cpp | 10 ++++++++-- libethereum/State.h | 5 ++--- libevm/ExtVMFace.h | 17 +++++++++++++++++ libevm/VM.h | 29 +++++++++++++++++++++++++++++ libevmface/Instruction.cpp | 2 ++ libevmface/Instruction.h | 1 + 14 files changed, 100 insertions(+), 30 deletions(-) diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 3110ca700..f499f38b9 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -1247,6 +1247,7 @@ void Main::populateDebugger(eth::bytesConstRef _r) m_history.append(WorldState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(), lastHash, lastDataHash, vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels})); }; m_currentExecution->go(onOp); + m_currentExecution->finalize(onOp); initDebugger(); updateDebugger(); } diff --git a/eth/main.cpp b/eth/main.cpp index f0af271d0..d6c49c867 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -597,8 +597,9 @@ int main(int argc, char** argv) bytes r = t.rlp(); e.setup(&r); + OnOpFunc oof; if (format == "pretty") - e.go([&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM) + oof = [&](uint64_t steps, Instruction instr, bigint newMemSize, bigint gasCost, void* vvm, void const* vextVM) { eth::VM* vm = (VM*)vvm; eth::ExtVM const* ext = (ExtVM const*)vextVM; @@ -610,16 +611,16 @@ int main(int argc, char** argv) for (auto const& i: ext->state().storage(ext->myAddress)) f << showbase << hex << i.first << ": " << i.second << endl; f << dec << ext->level << " | " << ext->myAddress << " | #" << steps << " | " << hex << setw(4) << setfill('0') << vm->curPC() << " : " << c_instructionInfo.at(instr).name << " | " << dec << vm->gas() << " | -" << dec << gasCost << " | " << newMemSize << "x32"; - }); + }; else if (format == "standard") - e.go([&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM) + oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM) { eth::VM* vm = (VM*)vvm; eth::ExtVM const* ext = (ExtVM const*)vextVM; f << ext->myAddress << " " << hex << toHex(eth::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(eth::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(eth::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; - }); + }; else if (format == "standard+") - e.go([&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM) + oof = [&](uint64_t, Instruction instr, bigint, bigint, void* vvm, void const* vextVM) { eth::VM* vm = (VM*)vvm; eth::ExtVM const* ext = (ExtVM const*)vextVM; @@ -627,7 +628,9 @@ int main(int argc, char** argv) for (auto const& i: ext->state().storage(ext->myAddress)) f << toHex(eth::toCompactBigEndian(i.first, 1)) << " " << toHex(eth::toCompactBigEndian(i.second, 1)) << endl; f << ext->myAddress << " " << hex << toHex(eth::toCompactBigEndian(vm->curPC(), 1)) << " " << hex << toHex(eth::toCompactBigEndian((int)(byte)instr, 1)) << " " << hex << toHex(eth::toCompactBigEndian((uint64_t)vm->gas(), 1)) << endl; - }); + }; + e.go(oof); + e.finalize(oof); } } else if (cmd == "inspect") diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 7d0eb7d9c..738beb9be 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -115,7 +115,7 @@ void Client::clearPending() appendFromNewPending(m_postMine.bloom(i), changeds); changeds.insert(PendingChangedFilter); m_postMine = m_preMine; - m_miner.restart(); + m_miner.noteStateChange(); noteChanged(changeds); } @@ -425,7 +425,7 @@ void Client::work() changeds.insert(ChainChangedFilter); //changeds.insert(PendingChangedFilter); // if we mined the new block, then we've probably reset the pending transactions. } - m_miner.restart(); + m_miner.noteStateChange(); } // Synchronise state to block chain. @@ -476,7 +476,7 @@ void Client::work() } if (rsm) - m_miner.restart(); + m_miner.noteStateChange(); } cwork << "noteChanged" << changeds.size() << "items"; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 6562a0cf8..699837701 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -217,21 +217,19 @@ u256 Executive::gas() const return m_vm ? m_vm->gas() : m_endGas; } -void Executive::finalize() +void Executive::finalize(OnOpFunc const& _onOp) { 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); - u256 gasSpentInEth = (m_t.gas - m_endGas) * m_t.gasPrice; -/* unsigned c_feesKept = 8; - u256 feesEarned = gasSpentInEth - (gasSpentInEth / c_feesKept); - cnote << "Transferring" << (100.0 - 100.0 / c_feesKept) << "% of" << formatBalance(gasSpent) << "=" << formatBalance(feesEarned) << "to miner (" << formatBalance(gasSpentInEth - feesEarned) << "is burnt)."; -*/ - u256 feesEarned = gasSpentInEth; + u256 feesEarned = (m_t.gas - m_endGas) * m_t.gasPrice; // cnote << "Transferring" << formatBalance(gasSpent) << "to miner."; m_s.addBalance(m_s.m_currentBlock.coinbaseAddress, feesEarned); diff --git a/libethereum/Executive.h b/libethereum/Executive.h index 0d3a5288f..e7ba44223 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -48,7 +48,7 @@ public: bool create(Address _txSender, u256 _endowment, u256 _gasPrice, u256 _gas, bytesConstRef _code, Address _originAddress); bool call(Address _myAddress, Address _txSender, u256 _txValue, u256 _gasPrice, bytesConstRef _txData, u256 _gas, Address _originAddress); bool go(OnOpFunc const& _onOp = OnOpFunc()); - void finalize(); + void finalize(OnOpFunc const& _onOp = OnOpFunc()); u256 gasUsed() const; static OnOpFunc simpleTrace(); diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index b980d6f01..737e003dd 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -56,7 +56,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, level + 1); + auto ret = m_s.create(myAddress, _endowment, gasPrice, _gas, _code, origin, &suicides, &posts, 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; @@ -67,7 +67,7 @@ public: { if (m_ms) m_ms->internal.resize(m_ms->internal.size() + 1); - auto ret = m_s.call(_receiveAddress, myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, m_ms ? &(m_ms->internal.back()) : nullptr, _onOp, level + 1); + auto ret = m_s.call(_receiveAddress, myAddress, _txValue, gasPrice, _txData, _gas, _out, origin, &suicides, &posts, 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; @@ -93,6 +93,20 @@ 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); + 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/Miner.h b/libethereum/Miner.h index ca4eca8a3..7ddd54ea6 100644 --- a/libethereum/Miner.h +++ b/libethereum/Miner.h @@ -61,7 +61,7 @@ public: /** * @brief Implements Miner. - * To begin mining, use start() & stop(). restart() can be used to reset the mining and set up the + * To begin mining, use start() & stop(). noteStateChange() can be used to reset the mining and set up the * State object according to the host. Use isRunning() to determine if the miner has been start()ed. * Use isComplete() to determine if the miner has finished mining. * @@ -69,7 +69,7 @@ public: * * Information on the mining can be queried through miningProgress() and miningHistory(). * @threadsafe - * @todo signal from child->parent thread to wait on exit; refactor redundant dagger/miner stats + * @todo Signal Miner to restart once with condition variables. */ class Miner { @@ -86,8 +86,8 @@ public: /// Stop mining. void stop(); - /// Restart mining (and start if not already running). - void restart() { start(); m_miningStatus = Preparing; } + /// Call to notify Miner of a state change. + void noteStateChange() { m_miningStatus = Preparing; } /// @returns true iff the mining has been start()ed. It may still not be actually mining, depending on the host's turbo() & force(). bool isRunning() { return !!m_work; } @@ -109,7 +109,7 @@ private: void work(); MinerHost* m_host; ///< Our host. - unsigned m_id; ///< Our identity; + unsigned m_id; ///< Our identity. std::mutex x_work; ///< Mutex protecting the creation of the work thread. std::unique_ptr m_work; ///< The work thread. diff --git a/libethereum/PeerSession.cpp b/libethereum/PeerSession.cpp index 393353b63..b095745f7 100644 --- a/libethereum/PeerSession.cpp +++ b/libethereum/PeerSession.cpp @@ -184,7 +184,7 @@ bool PeerSession::interpret(RLP const& _r) if (isPrivateAddress(peerAddress)) goto CONTINUE; - clogS(NetAllDetail) << "Checking: " << ep << "(" << toHex(id.ref().cropped(0, 4)) << ")"; + clogS(NetAllDetail) << "Checking: " << ep << "(" << id.abridged() << ")"; // check that it's not us or one we already know: if (id && (m_server->m_key.pub() == id || m_server->havePeer(id) || m_server->m_incomingPeers.count(id))) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 332a3c920..5efb03b1f 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1024,7 +1024,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) return e.gasUsed(); } -bool State::call(Address _receiveAddress, 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 _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) { if (!_originAddress) _originAddress = _senderAddress; @@ -1053,6 +1053,9 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u 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(); } @@ -1085,7 +1088,7 @@ bool State::call(Address _receiveAddress, Address _senderAddress, u256 _value, u 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, std::set
* o_suicides, PostList* o_posts, Manifest* o_ms, OnOpFunc const& _onOp, unsigned _level) { if (!_origin) _origin = _sender; @@ -1119,6 +1122,9 @@ 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 80380149f..519bb5349 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -307,12 +307,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(), std::set
* o_suicides = nullptr, PostList* o_posts = 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 _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 _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); /// Sets m_currentBlock to a clean state, (i.e. no change from m_previousBlock). void resetCurrent(); @@ -332,7 +332,6 @@ private: TrieDB m_state; ///< Our state tree, as an OverlayDB DB. std::vector m_transactions; ///< The current list of transactions that we've included in the state. std::set m_transactionSet; ///< The set of transaction hashes that we've included in the state. -// GenericTrieDB m_transactionManifest; ///< The transactions trie; saved from the last commitToMine, or invalid/empty if commitToMine was never called. OverlayDB m_lastTx; mutable std::map m_cache; ///< Our address cache. This stores the states of each address that has (or at least might have) been changed. diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index e53d90734..3fe7bea5a 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -29,6 +29,16 @@ namespace eth { +struct Post +{ + Address to; + u256 value; + bytes data; + u256 gas; +}; + +using PostList = std::list; + /** * @brief A null implementation of the class for specifying VM externalities. */ @@ -68,9 +78,15 @@ public: /// Make a new message call. bool call(Address, u256, bytesConstRef, u256*, bytesRef) { return false; } + /// Post a new message call. + void post(Address _to, u256 _value, bytesConstRef _data, u256 _gas) { posts.push_back(Post({_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. @@ -81,6 +97,7 @@ 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. }; typedef std::function OnOpFunc; diff --git a/libevm/VM.h b/libevm/VM.h index 7a3c6f6e1..3e271dae0 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -164,6 +164,12 @@ template eth::bytesConstRef eth::VM::go(Ext& _ext, OnOpFunc const& _ newTempSize = std::max(m_stack[m_stack.size() - 6] + m_stack[m_stack.size() - 7], m_stack[m_stack.size() - 4] + m_stack[m_stack.size() - 5]); break; + case Instruction::POST: + require(5); + runGas = c_callGas + m_stack[m_stack.size() - 1]; + newTempSize = m_stack[m_stack.size() - 4] + m_stack[m_stack.size() - 5]; + break; + case Instruction::CREATE: { require(3); @@ -622,6 +628,29 @@ template eth::bytesConstRef eth::VM::go(Ext& _ext, OnOpFunc const& _ } case Instruction::STOP: return bytesConstRef(); + case Instruction::POST: + { + require(5); + + u256 gas = m_stack.back(); + m_stack.pop_back(); + u160 receiveAddress = asAddress(m_stack.back()); + m_stack.pop_back(); + u256 value = m_stack.back(); + m_stack.pop_back(); + + unsigned inOff = (unsigned)m_stack.back(); + m_stack.pop_back(); + unsigned inSize = (unsigned)m_stack.back(); + m_stack.pop_back(); + + if (_ext.balance(_ext.myAddress) >= value) + { + _ext.subBalance(value); + _ext.post(receiveAddress, value, bytesConstRef(m_temp.data() + inOff, inSize), gas); + } + break; + } default: throw BadInstruction(); } diff --git a/libevmface/Instruction.cpp b/libevmface/Instruction.cpp index b42244c3e..c31194475 100644 --- a/libevmface/Instruction.cpp +++ b/libevmface/Instruction.cpp @@ -145,6 +145,7 @@ const std::map eth::c_instructions = { "CREATE", Instruction::CREATE }, { "CALL", Instruction::CALL }, { "RETURN", Instruction::RETURN }, + { "POST", Instruction::POST }, { "SUICIDE", Instruction::SUICIDE } }; @@ -268,6 +269,7 @@ const std::map eth::c_instructionInfo = { Instruction::CREATE, { "CREATE", 0, 3, 1 } }, { Instruction::CALL, { "CALL", 0, 7, 1 } }, { Instruction::RETURN, { "RETURN", 0, 2, 0 } }, + { Instruction::POST, { "POST", 0, 5, 0 } }, { Instruction::SUICIDE, { "SUICIDE", 0, 1, 0} } }; diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index bf107a860..1afe930aa 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -162,6 +162,7 @@ enum class Instruction: uint8_t CREATE = 0xf0, CALL, RETURN, + POST, SUICIDE = 0xff };