makeLog指令函数如何在以太坊虚拟机中运行
How does makeLog instruction function works in Ethereum virtual machine
以下代码片段是 geth 中 instructions.go 文件的组成部分。
// make log instruction function
func makeLog(size int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
topics := make([]common.Hash, size)
stack := scope.Stack
mStart, mSize := stack.pop(), stack.pop()
for i := 0; i < size; i++ {
addr := stack.pop()
topics[i] = addr.Bytes32()
}
d := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64()))
interpreter.evm.StateDB.AddLog(&types.Log{
Address: scope.Contract.Address(),
Topics: topics,
Data: d,
// This is a non-consensus field, but assigned here because
// core/state doesn't know the current block number.
BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(),
})
return nil, nil
}
}
问题是,log0、log1、Log2 等操作码是如何工作的,它们在以太坊虚拟机中的用途是什么?
LOG<n>
操作码用于发出事件日志。
<n>
值取决于事件的索引和 non-indexed 主题的数量。由于 <n>
值有限(当前为 4),每个事件定义的最大索引主题也有限制(当前为 3,因此也可以处理同一事件的未索引主题)。
Solidity 中的示例:
event MyEmptyEvent();
event MyEvent(bool indexed, bool indexed, bool, bool);
function foo() external {
// Produces the `LOG0` opcode as there are no topics
emit MyEmptyEvent();
// Produces the `LOG3` opcode
// as the 2 indexed topics are stored separately
// but the unindexed topics are stored as 1 topic with concatenated value
emit MyEvent(true, true, true, true);
}
在一个交易被包含在一个挖掘的区块中之后,产生的事件日志与其他状态变化(例如存储值和地址余额)一起被广播。
有一个很棒的 article 更深入地描述了细节。
以下代码片段是 geth 中 instructions.go 文件的组成部分。
// make log instruction function
func makeLog(size int) executionFunc {
return func(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
if interpreter.readOnly {
return nil, ErrWriteProtection
}
topics := make([]common.Hash, size)
stack := scope.Stack
mStart, mSize := stack.pop(), stack.pop()
for i := 0; i < size; i++ {
addr := stack.pop()
topics[i] = addr.Bytes32()
}
d := scope.Memory.GetCopy(int64(mStart.Uint64()), int64(mSize.Uint64()))
interpreter.evm.StateDB.AddLog(&types.Log{
Address: scope.Contract.Address(),
Topics: topics,
Data: d,
// This is a non-consensus field, but assigned here because
// core/state doesn't know the current block number.
BlockNumber: interpreter.evm.Context.BlockNumber.Uint64(),
})
return nil, nil
}
}
问题是,log0、log1、Log2 等操作码是如何工作的,它们在以太坊虚拟机中的用途是什么?
LOG<n>
操作码用于发出事件日志。
<n>
值取决于事件的索引和 non-indexed 主题的数量。由于 <n>
值有限(当前为 4),每个事件定义的最大索引主题也有限制(当前为 3,因此也可以处理同一事件的未索引主题)。
Solidity 中的示例:
event MyEmptyEvent();
event MyEvent(bool indexed, bool indexed, bool, bool);
function foo() external {
// Produces the `LOG0` opcode as there are no topics
emit MyEmptyEvent();
// Produces the `LOG3` opcode
// as the 2 indexed topics are stored separately
// but the unindexed topics are stored as 1 topic with concatenated value
emit MyEvent(true, true, true, true);
}
在一个交易被包含在一个挖掘的区块中之后,产生的事件日志与其他状态变化(例如存储值和地址余额)一起被广播。
有一个很棒的 article 更深入地描述了细节。