From 7b1afe3b10fa574ebc4afa46922a5f428b7a2388 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 27 Oct 2014 18:17:01 +0100 Subject: [PATCH] LOG instructions. --- libethereum/State.cpp | 2 +- libethereum/State.h | 3 ++- libevm/ExtVMFace.h | 7 ++++++- libevm/VM.h | 27 +++++++++++++++++++++++++++ libevmface/Instruction.cpp | 10 ++++++++++ libevmface/Instruction.h | 6 ++++++ 6 files changed, 52 insertions(+), 3 deletions(-) diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 40fac4883..7e2489f4d 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -1114,7 +1114,7 @@ u256 State::execute(bytesConstRef _rlp, bytes* o_output, bool _commit) // TODO: CHECK TRIE after level DB flush to make sure exactly the same. // Add to the user-originated transactions that we've executed. - m_transactions.push_back(TransactionReceipt(e.t(), rootHash(), startGasUsed + e.gasUsed(), ms)); + m_transactions.push_back(TransactionReceipt(e.t(), rootHash(), startGasUsed + e.gasUsed(), ms, e.logs())); m_transactionSet.insert(e.t().sha3()); return e.gasUsed(); } diff --git a/libethereum/State.h b/libethereum/State.h index 776fb80e7..d6087fc01 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -54,7 +54,7 @@ struct StateDetail: public LogChannel { static const char* name() { return "/S/" struct TransactionReceipt { - TransactionReceipt(Transaction const& _t, h256 _root, u256 _gasUsed, Manifest const& _ms): transaction(_t), stateRoot(_root), gasUsed(_gasUsed), changes(_ms) {} + TransactionReceipt(Transaction const& _t, h256 _root, u256 _gasUsed, Manifest const& _ms, LogEntries const& _logs): transaction(_t), stateRoot(_root), gasUsed(_gasUsed), changes(_ms), logs(_logs) {} // Manifest const& changes() const { return changes; } @@ -69,6 +69,7 @@ struct TransactionReceipt h256 stateRoot; u256 gasUsed; Manifest changes; + LogEntries logs; }; struct PrecompiledAddress diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index b57818907..4aa3ee122 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -36,8 +36,10 @@ namespace eth struct LogEntry { + LogEntry() {} + LogEntry(Address const& _f, h256s&& _ts, bytes&& _d): from(_f), topics(std::move(_ts)), data(std::move(_d)) {} Address from; - h256 topics; + h256s topics; bytes data; }; @@ -104,6 +106,9 @@ public: /// Make a new message call. virtual bool call(Address, u256, bytesConstRef, u256*, bytesRef, OnOpFunc const&, Address, Address) { return false; } + /// Revert any changes made (by any of the other calls). + virtual void log(h256s&& _topics, bytesConstRef _data) { sub.logs.push_back(LogEntry(myAddress, std::move(_topics), _data.toBytes())); } + /// Revert any changes made (by any of the other calls). virtual void revert() {} diff --git a/libevm/VM.h b/libevm/VM.h index f3c82c714..7e39623e1 100644 --- a/libevm/VM.h +++ b/libevm/VM.h @@ -172,6 +172,18 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con runGas = c_balanceGas; break; + case Instruction::LOG0: + case Instruction::LOG1: + case Instruction::LOG2: + case Instruction::LOG3: + case Instruction::LOG4: + { + unsigned n = (unsigned)inst - (unsigned)Instruction::LOG0; + require(n + 2); + newTempSize = memNeed(m_stack[m_stack.size() - 1 - n], m_stack[m_stack.size() - 2 - n]); + break; + } + case Instruction::CALL: case Instruction::CALLCODE: require(7); @@ -691,6 +703,21 @@ template dev::bytesConstRef dev::eth::VM::go(Ext& _ext, OnOpFunc con break; case Instruction::JUMPDEST: break; + case Instruction::LOG0: + _ext.log({}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 1], (unsigned)m_stack[m_stack.size() - 2])); + break; + case Instruction::LOG1: + _ext.log({m_stack[m_stack.size() - 1]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 2], (unsigned)m_stack[m_stack.size() - 3])); + break; + case Instruction::LOG2: + _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 3], (unsigned)m_stack[m_stack.size() - 4])); + break; + case Instruction::LOG3: + _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 4], (unsigned)m_stack[m_stack.size() - 5])); + break; + case Instruction::LOG4: + _ext.log({m_stack[m_stack.size() - 1], m_stack[m_stack.size() - 2], m_stack[m_stack.size() - 3], m_stack[m_stack.size() - 4]}, bytesConstRef(m_temp.data() + (unsigned)m_stack[m_stack.size() - 5], (unsigned)m_stack[m_stack.size() - 6])); + break; case Instruction::CREATE: { u256 endowment = m_stack.back(); diff --git a/libevmface/Instruction.cpp b/libevmface/Instruction.cpp index c9b6ea2ce..2c2af8eb0 100644 --- a/libevmface/Instruction.cpp +++ b/libevmface/Instruction.cpp @@ -149,6 +149,11 @@ const std::map dev::eth::c_instructions = { "SWAP14", Instruction::SWAP14 }, { "SWAP15", Instruction::SWAP15 }, { "SWAP16", Instruction::SWAP16 }, + { "LOG0", Instruction::LOG0 }, + { "LOG1", Instruction::LOG1 }, + { "LOG2", Instruction::LOG2 }, + { "LOG3", Instruction::LOG3 }, + { "LOG4", Instruction::LOG4 }, { "CREATE", Instruction::CREATE }, { "CALL", Instruction::CALL }, { "CALLCODE", Instruction::CALLCODE }, @@ -277,6 +282,11 @@ static const std::map c_instructionInfo = { Instruction::SWAP14, { "SWAP14", 0, 15, 15 } }, { Instruction::SWAP15, { "SWAP15", 0, 16, 16 } }, { Instruction::SWAP16, { "SWAP16", 0, 17, 17 } }, + { Instruction::LOG0, { "LOG0", 0, 1, 0 } }, + { Instruction::LOG1, { "LOG1", 0, 2, 0 } }, + { Instruction::LOG2, { "LOG2", 0, 3, 0 } }, + { Instruction::LOG3, { "LOG3", 0, 4, 0 } }, + { Instruction::LOG4, { "LOG4", 0, 5, 0 } }, { Instruction::CREATE, { "CREATE", 0, 3, 1 } }, { Instruction::CALL, { "CALL", 0, 7, 1 } }, { Instruction::CALLCODE, { "CALLCODE", 0, 7, 1 } }, diff --git a/libevmface/Instruction.h b/libevmface/Instruction.h index faad50fb2..ea355fab1 100644 --- a/libevmface/Instruction.h +++ b/libevmface/Instruction.h @@ -162,6 +162,12 @@ enum class Instruction: uint8_t SWAP15, ///< swaps the highest and 16th highest value on the stack SWAP16, ///< swaps the highest and 17th highest value on the stack + LOG0 = 0xa0, ///< Makes a log entry; no topics. + LOG1, ///< Makes a log entry; 1 topic. + LOG2, ///< Makes a log entry; 2 topics. + LOG3, ///< Makes a log entry; 3 topics. + LOG4, ///< Makes a log entry; 4 topics. + CREATE = 0xf0, ///< create a new account with associated code CALL, ///< message-call into an account RETURN, ///< halt execution returning output data