最近要实现Etherscan的合约认证的功能 类似这个这个页面
大概实现思路是这样
- 1.用户在页面输入合约代码,以及编译时的参数信息,和被认证的合约地址
- 2.提交信息到webServer,服务端使用提交的参数信息,调用编译器进行编译获得字节码
- 3.通过eth_getCode() 获取被验证合约的链上合约字节码与提交的合约字节码进行匹配如果一致则认为验证成功
解决的问题
1. bytecode尾部与链上的bytecode不同
bytecode尾部是一个部署合约元数据的Hash称为 AUXDATA ,不同环境下编译会产生不同的hash(即使使用相同版本编译器),在校对时候需要移除尾部的32字节Hash值
2.bytecode首部与链上的bytecode不同
在编译完成后bytecode首部的一段代码称为部署代码,这一部分在部署完成后通过eth_getCode 是无法获取到的,所以在比对时需要将它移除出去,那么怎么确定哪一部分是属于部署代码的呢?
经过观察发现,部署代码的最后一个指令都会以STOP结尾(不一定正确),在编译合约时同时生成opcodes,编译完成后将opcodes读取进入,截取出opcodes第一个STOP指令前所有的指令,计算出这些指令对应的bytecode,然后将其移除出去,由此又衍生出关于opcodes转bytecode的第三个问题3.opcdoes转bytecode的问题
- 指令转换问题
发现通过opcodes计算的bytecode有时候对有时候不对,问题出现在PUSH指令上,PUSH1 到PUSH32 分别表示操作1到32个字节的数据,那么后面的数据如果不满足PUSH指令的数据长度,需要在高位补充0- 源代码指令不够问题
由于部署代码部分需要自己进行计算,所以需要收集所有的opcodes,以太坊源码 中指定的opcodes在实际使用过程中发现并不完整,经过核对有INVALID,KECCAK256 操作码并没有在该源码文件中,手动录入- 库合约字节码被替换问题
库合约部署完成后,bytecode开头(已经去除了部署代码)使用了PUSH20指令后面紧随合约地址,编译器刚编译完成后当然是不知道合约地址的所以PUSH20指令后面跟随的是空值也就是 0000000000000000000000000000000000000000,检测到后需要替换为真实合约地址
参考文档
https://www.jianshu.com/p/1969f3761208
solidity历史版本下载 nightly版本不知道在哪儿下载,有知道还望的告知一下
附所有opcodes
{
"STOP": "00",
"ADD": "01",
"MUL": "02",
"SUB": "03",
"DIV": "04",
"SDIV": "05",
"MOD": "06",
"SMOD": "07",
"ADDMOD": "08",
"MULMOD": "09",
"EXP": "0a",
"SIGNEXTEND": "0b",
"LT": "10",
"GT": "11",
"SLT": "12",
"SGT": "13",
"EQ": "14",
"ISZERO": "15",
"AND": "16",
"OR": "17",
"XOR": "18",
"NOT": "19",
"BYTE": "1a",
"SHA3": "20",
"ADDRESS": "30",
"BALANCE": "31",
"ORIGIN": "32",
"CALLER": "33",
"CALLVALUE": "34",
"CALLDATALOAD": "35",
"CALLDATASIZE": "36",
"CALLDATACOPY": "37",
"CODESIZE": "38",
"CODECOPY": "39",
"GASPRICE": "3a",
"EXTCODESIZE": "3b",
"EXTCODECOPY": "3c",
"BLOCKHASH": "40",
"COINBASE": "41",
"TIMESTAMP": "42",
"NUMBER": "43",
"DIFFICULTY": "44",
"GASLIMIT": "45",
"POP": "50",
"MLOAD": "51",
"MSTORE": "52",
"MSTORE8": "53",
"SLOAD": "54",
"SSTORE": "55",
"JUMP": "56",
"JUMPI": "57",
"PC": "58",
"MSIZE": "59",
"GAS": "5a",
"JUMPDEST": "5b",
"PUSH1": "60",
"PUSH2": "61",
"PUSH3": "62",
"PUSH4": "63",
"PUSH5": "64",
"PUSH6": "65",
"PUSH7": "66",
"PUSH8": "67",
"PUSH9": "68",
"PUSH10": "69",
"PUSH11": "6a",
"PUSH12": "6b",
"PUSH13": "6c",
"PUSH14": "6d",
"PUSH15": "6e",
"PUSH16": "6f",
"PUSH17": "70",
"PUSH18": "71",
"PUSH19": "72",
"PUSH20": "73",
"PUSH21": "74",
"PUSH22": "75",
"PUSH23": "76",
"PUSH24": "77",
"PUSH25": "78",
"PUSH26": "79",
"PUSH27": "7a",
"PUSH28": "7b",
"PUSH29": "7c",
"PUSH30": "7d",
"PUSH31": "7e",
"PUSH32": "7f",
"DUP1": "80",
"DUP2": "81",
"DUP3": "82",
"DUP4": "83",
"DUP5": "84",
"DUP6": "85",
"DUP7": "86",
"DUP8": "87",
"DUP9": "88",
"DUP10": "89",
"DUP11": "8a",
"DUP12": "8b",
"DUP13": "8c",
"DUP14": "8d",
"DUP15": "8e",
"DUP16": "8f",
"SWAP1": "90",
"SWAP2": "91",
"SWAP3": "92",
"SWAP4": "93",
"SWAP5": "94",
"SWAP6": "95",
"SWAP7": "96",
"SWAP8": "97",
"SWAP9": "98",
"SWAP10": "99",
"SWAP11": "9a",
"SWAP12": "9b",
"SWAP13": "9c",
"SWAP14": "9d",
"SWAP15": "9e",
"SWAP16": "9f",
"LOG0": "a0",
"LOG1": "a1",
"LOG2": "a2",
"LOG3": "a3",
"LOG4": "a4",
"PUSH": "b0",
"DUP": "b1",
"SWAP": "b2",
"CREATE": "f0",
"CALL": "f1",
"CALLCODE": "f2",
"RETURN": "f3",
"DELEGATECALL": "f4",
"SELFDESTRUCT": "ff",
"REVERT": "fd",
"INVALID": "fe",
"KECCAK256": "20",
"SHL": "1b",
"SHR": "1c",
"SAR": "1d",
"RETURNDATASIZE": "3d",
"RETURNDATACOPY": "3e",
"EXTCODEHASH": "3f",
"CREATE2": "f5",
"STATICCALL": "fa"
}
网友评论