LOG指令
处理流程
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 | |
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 | ||||
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
cnt | vers_24 |
---|---|
1 | len_lo_inv |
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 |