defdecode(input:bytes)->int:size_prefix=input[0]>>6ifsize_prefix==0:returninput[0]&0x3felifsize_prefix==1:return(input[0]&0x3f)<<8|input[1]elifsize_prefix==2:return(input[0]&0x3f)<<16|(input[1]<<8)|input[2]# Do not support case 3
assert(False)
# The same table as in EIP-3670
# 与 EIP-3670 中相同的表格
valid_opcodes=...# Remove JUMPDEST from the list of valid opcodes
# 从有效操作码列表中删除 JUMPDEST
valid_opcodes.remove(0x5b)# This helper decodes a single unsigned LEB128 encoded value
# 此助手解码单个无符号 LEB128 编码的值
# This will abort on truncated (short) input
# 这将在截断(短)输入时中止
defleb128u_decode(input:bytes)->(int,int):ret=0shift=0consumed_bytes=0whileTrue:# Check for truncated input
# 检查截断的输入
assert(consumed_bytes<len(input))# Only allow up to 4-byte long leb128 encodings
# 仅允许最长 4 字节的 leb128 编码
assert(consumed_bytes<=3)input_byte=input[consumed_bytes]consumed_bytes+=1ret|=(input_byte&0x7f)<<shiftif(input_byte&0x80)==0:# Do not allow additional leading zero bits.
# 不允许额外的先导零位。
assert(input_byte!=0||consumed_bytes==0)breakshift+=7return(ret,consumed_bytes)# This helper parses the jumpdest table into a list of relative offsets
# 此助手将 jumpdest 表解析为相对偏移量列表
# This will abort on truncated (short) input
# 这将在截断(短)输入时中止
defparse_table(input:bytes)->list[int]:jumpdests=[]pos=0whilepos<len(input):value,consumed_bytes=leb128u_decode(input[pos:])jumpdests.append(value)pos+=consumed_bytesreturnjumpdests# This helper translates the delta offsets into absolute ones
# 此助手将 delta 偏移量转换为绝对偏移量
# This will abort on invalid 0-value entries
# 这将中止无效的 0 值条目
defprocess_jumpdests(delta:list[int])->list[int]:jumpdests=[]partial_sum=0first=Truefordindelta:iffirst:first=Falseelse:assert(d!=0)partial_sum+=djumpdests.append(partial_sum)returnjumpdests# Fails with assertion on invalid code
# 如果代码无效,则断言失败
# Expects list of absolute jumpdest offsets
# 期望绝对 jumpdest 偏移量的列表
defvalidate_code(code:bytes,jumpdests:list[int]):pos=0whilepos<len(code):# Ensure the opcode is valid
# 确保操作码有效
opcode=code[pos]pos+=1assert(opcodeinvalid_opcodes)# Remove touched offset
# 删除已触摸的偏移量
try:jumpdests.remove(pos)exceptValueError:pass# Skip pushdata
# 跳过 pushdata
ifopcode>=0x60andopcode<=0x7f:pos+=opcode-0x60+1# Ensure last PUSH doesn't go over code end
# 确保最后一个 PUSH 不会超出代码结尾
assert(pos==len(code))# The table is invalid if there are untouched locations
# 如果存在未触摸的位置,则该表无效
assert(len(jumpdests)==0)