Last edited by 桂忠
EVM-LOG指令定义
参考:https://ethervm.io/#LOG0
uint8 |
Mnemonic |
Stack Input |
Stack Output |
Expression |
Notes |
A0 |
LOG0 |
offset,length |
- |
LOG0(memory[offset:offset+length]) |
fires an event |
A1 |
LOG1 |
offset,length,topic0 |
- |
LOG1(memory[offset:offset+length], topic0) |
fires an event |
A2 |
LOG2 |
offset,length,topic0,topic1 |
- |
LOG2(memory[offset:offset+length], topic0, topic1) |
fires an event |
A3 |
LOG3 |
offset,length,topic0,topic1,topic2 |
- |
LOG3(memory[offset:offset+length], topic0,topic1,topic2) |
fires an event |
A4 |
LOG4 |
offset,length,topic0,topic1,topic2,topic3 |
- |
LOG4(memory[offset:offset+length], topic0, topic1,topic2,topic3) |
fires an event |
处理流程
LOG0
flowchart LR
LogBytes --> MEMORY_GAS --> LOG_GAS --> LogTopicNumAddr
LOG1-LOG4
flowchart LR
LogBytes --> MEMORY_GAS --> LOG_GAS --> LogTopicNumAddr --> LogTopic:topic0 --> LogTopic:topic1 --> ...
- LogBytes: 处理Log数据拷贝(Copy Lookup Memory->PublicLog)和数据长度记录(Public Lookup)
- Memory_gas: 计算Log操作需要的memory gas花费;
- Log_gas: 计算Log操作最终的gas花费;
- LogTopicNumAddr: 处理Log数据地址(Public Lookup)
- LogTopic: 处理每一个TopicHash处理(Public Lookup)
主要约束及状态变化
LOG0为例:
指令 |
状态 |
State参数 |
约束 |
gen witness 状态变化 |
LOG0 |
LogBytes |
state1=offset |
state_stamp = pre + 2 |
|
|
|
state2=length |
log_stamp = pre |
|
|
|
|
next_pc = pc |
|
|
|
|
|
|
|
memory_gas |
|
memory_gas = GasCost::MEMORY_EXPANSION_LINEAR_COEFF.expr() * (next_word_size - memory_chunk_prev) * (next_quad_memory_cost - curr_quad_memory_cost) |
|
|
|
|
|
|
|
log_gas |
|
gas_cost = memory_gas_cost + GasCost::LOG.expr() + topic_gas + length * GasCost::LOG_DATA_GAS.expr() |
|
|
|
|
|
|
|
LogTopicNumAddr |
- |
state_stamp = pre |
根据opcode 切换值state.topic_left |
|
|
|
log_stamp = pre + (1*topic_left_0) |
topic_left==0时log_stamp+1 |
|
|
|
next_pc = pc + (1*topic_left_0) |
|
LOG1为例:
指令 |
状态 |
State参数 |
约束 |
gen witness 状态变化 |
LOG1 |
LogBytes |
state1=offset |
state_stamp = pre + 2 log_ |
|
|
|
state2=length |
stamp = pre |
|
|
|
|
next_pc = pc |
|
|
|
|
|
|
|
memory_gas |
|
memory_gas = GasCost::MEMORY_EXPANSION_LINEAR_COEFF.expr() * (next_word_size - memory_chunk_prev) * (next_quad_memory_cost - curr_quad_memory_cost) |
|
|
|
|
|
|
|
log_gas |
|
gas_cost = memory_gas_cost + GasCost::LOG.expr() + topic_gas + length * GasCost::LOG_DATA_GAS.expr() |
|
|
|
|
|
|
|
|
|
|
|
|
LogTopicNumAddr |
- |
state_stamp = pre |
根据opcode切换值state.topic_left |
|
|
|
log_stamp = pre + (1*topic_left_0) |
topic_left==0时log_stamp+1 |
|
|
|
next_pc = pc |
|
|
|
|
|
|
|
LogTopic |
state1=cur_topic_hash |
state_stamp = pre+1 |
state.topic_left -=1 |
|
|
|
log_stamp = pre + (1*topic_left_0) |
topic_left==0时log_stamp+1 |
具体Gadget设计
LogBytesGadget设计
处理memory[offset:offset+length],数据从Memory拷贝到PulbicLog
主要约束:
- state_stamp = pre + 2
- log_stamp = pre
- next_pc = pc
gen_witness状态变化
cnt |
|
|
|
|
2 |
COPY(9) |
- |
- |
PUBLIC(6) |
1 |
STATE1(8) |
STATE2(8) |
- |
LO_INV(1) |
0 |
DYNA_SELECTOR(20) |
AUX(7) |
- |
- |
CoreRow2-COPY(9) vers_0~vers_8,负责Copy Lookup(处理Log数据拷贝)
cnt |
vers_0 |
vers_1 |
vers_2 |
vers_3 |
vers_4 |
vers_5 |
vers_6 |
vers_7 |
vers_8 |
2 |
src_type=Memory |
src_id=self.call_id |
src_pointer=1 |
src_stamp=2 |
dst_type=PublicLog |
dst_id=self.tx_idx |
dst_pointer=0(PublicLogIndex) |
dst_stamp=log_stamp |
len=length |
CoreRow2-PUBlIC(6) vers_24~vers_31,负责Public Lookup(处理Log数据长度)
cnt |
vers_26 |
vers_27 |
vers_28 |
vers_29 |
vers_30 |
vers_31 |
2 |
tag=TxLog |
tx_idx=self.tx_idx |
log_index=self.log_stamp |
log_tag=DataSize |
0 |
data_len=length |
CoreRow1-STATE1(8) vers_0~vers_7,负责从栈中取出的offset
cnt |
vers_0 |
vers_1 |
vers_2 |
vers_3 |
vers_4 |
vers_5 |
vers_6 |
vers_7 |
1 |
tag=Stack |
stamp |
value_hi=0 |
value_lo=offset |
call_id_contract_addr=self.call_id |
- |
pointer_lo |
is_write=0 |
CoreRow1-STATE2(8) vers_8~vers_15,负责从栈中取出的length
cnt |
vers_0 |
vers_1 |
vers_2 |
vers_3 |
vers_4 |
vers_5 |
vers_6 |
vers_7 |
1 |
tag=Stack |
stamp |
value_hi=0 |
value_lo=length |
call_id_contract_addr=self.call_id |
- |
pointer_lo |
is_write=0 |
CoreRow1-LO_INV(1) vers_24
MEMORY_GAS
cnt |
|
|
|
|
|
|
|
1 |
MEMORY_EXPANSION(2..6) |
U64DIV(7..11) |
U64DIV(12..16) |
SELECTOR(17..30) |
|
|
|
0 |
DYNAMIC(0..17) |
AUX(18..24) |
|
MEMORY_GAS(26) |
NEXT_IS_LOG_GAS(29) |
NEXT_IS_PURE_MEMORY_GAS(30) |
NEXT_IS_MEMORY_COPIER_GAS(31) |
主要约束:
- memory_gas = GasCost::MEMORY_EXPANSION_LINEAR_COEFF.expr() * (next_word_size - memory_chunk_prev) * (next_quad_memory_cost - curr_quad_memory_cost)
- next_word_size = (new_memory_size + 31) / 32,new_memory_size是通过stack中的offset+length;
- next_quad_memory_cost = next_word_size * next_word_size / 512;
cnt = 0行:
- 预留vers_26为计算出的memory_gas,提供给下一个状态使用,vers_29, vers_30, vers_31 为下一个状态约束需要的条件。
cnt = 1行:
- MEMORY_EXPANSION为
Max(cur_memory_size, memory_size)
- 第一个U64Div为
cur_memory_size * cur_memory_size / 512 = curr_quad_memory_cost
- 第二个U64Div为
next_memory_size * next_memory_size / 512 = next_quad_memory_cost
- SELECTOR为opcode选择器。
LOG_GAS
cnt |
|
|
1 |
U64OVERFLOW |
SELECTOR(7..11) |
0 |
DYNAMIC(0..17) |
AUX(18..24) |
主要约束:
- gas_cost = memory_gas_cost + GasCost::LOG.expr() + topic_gas + length * GasCost::LOG_DATA_GAS.expr(),其中:
- topic_gas = n * GasCost::LOG.expr(), n为LOG_n;
- length 为 stack中的参数;
cnt = 1 行:
- U64OVERFLOW 为gas_left u64的约束;
- SELECTOR为LOG0-4的选择器。
LogTopicNumAddrGadget设计
主要约束:
- state_stamp = pre
- log_stamp = pre + (1 * topic_left_0)
- next_pc = pc + (1 * topic_left_0)
gen_witness状态变化
- 根据opcode初始化state.topic_left
- state.topic_left==0时 log_stamp += 1
cnt |
|
|
|
|
2 |
- |
- |
- |
PUBLIC(6) |
1 |
- |
LOG_LEFT_X(5) |
- |
- |
0 |
DYNA_SELECTOR(20) |
AUX(7) |
- |
- |
CoreRow2-PUBlIC(6) vers_24~vers_31,负责Public Lookup(处理Topic数目和地址)
cnt |
vers_26 |
vers_27 |
vers_28 |
vers_29 |
vers_30 |
vers_31 |
2 |
tag=TxLog |
tx_idx=self.tx_idx |
log_index=self.log_stamp |
topic_log_tag=AddrWithLogX |
address[..4] |
address[4..] |
CoreRow1-LOG_LEFT_X(5) vers_8~vers_12,选择器LOG_LEFT_4~LOG_LEFT_0
cnt |
vers_8 |
vers_9 |
vers_10 |
vers_11 |
vers_12 |
1 |
LOG_LEFT_4 |
LOG_LEFT_3 |
LOG_LEFT_2 |
LOG_LEFT_1 |
LOG_LEFT_0 |
LogTopicGadget设计
主要约束:
- state_stamp = pre
- log_stamp = pre + (1 * topic_left_0)
- next_pc = pc + (1 * topic_left_0)
gen_witness状态变化
- state.topic_left -= 1
- state.topic_left==0时 log_stamp += 1
cnt |
|
|
|
|
2 |
- |
- |
- |
PUBLIC(6) |
1 |
STATE1(8) |
LOG_LEFT_X(5) |
- |
- |
0 |
DYNA_SELECTOR(20) |
AUX(7) |
- |
- |
CoreRow2-PUBlIC(6) vers_24~vers_31,负责Public Lookup(处理Topic哈希数据)
cnt |
vers_26 |
vers_27 |
vers_28 |
vers_29 |
vers_30 |
vers_31 |
2 |
tag=TxLog |
tx_idx=self.tx_idx |
log_index=self.log_stamp |
topic_log_tag=TopicX |
topic hash[..16] |
topic hash[16..] |
CoreRow1-STATE1(8) vers_0~vers_7,负责从栈中取出的topic_hash
cnt |
vers_0 |
vers_1 |
vers_2 |
vers_3 |
vers_4 |
vers_5 |
vers_6 |
vers_7 |
1 |
tag=Stack |
stamp=0 |
value_hi=0 |
value_lo=topic_hash |
call_id_contract_addr=self.call_id |
- |
pointer_lo=2 |
is_write=0 |
CoreRow1-LOG_LEFT_X(5) vers_8~vers_12,选择器LOG_LEFT_4~LOG_LEFT_0
cnt |
vers_8 |
vers_9 |
vers_10 |
vers_11 |
vers_12 |
1 |
LOG_LEFT_4 |
LOG_LEFT_3 |
LOG_LEFT_2 |
LOG_LEFT_1 |
LOG_LEFT_0 |