最近要實現(xiàn)Etherscan的合約認證的功能 類似這個這個頁面
大概實現(xiàn)思路是這樣
- 1.用戶在頁面輸入合約代碼,以及編譯時的參數(shù)信息谭羔,和被認證的合約地址
- 2.提交信息到webServer华糖,服務端使用提交的參數(shù)信息,調(diào)用編譯器進行編譯獲得字節(jié)碼
- 3.通過eth_getCode() 獲取被驗證合約的鏈上合約字節(jié)碼與提交的合約字節(jié)碼進行匹配如果一致則認為驗證成功
解決的問題
1. bytecode尾部與鏈上的bytecode不同
bytecode尾部是一個部署合約元數(shù)據(jù)的Hash稱為 AUXDATA 瘟裸,不同環(huán)境下編譯會產(chǎn)生不同的hash(即使使用相同版本編譯器)客叉,在校對時候需要移除尾部的32字節(jié)Hash值
2.bytecode首部與鏈上的bytecode不同
在編譯完成后bytecode首部的一段代碼稱為部署代碼,這一部分在部署完成后通過eth_getCode 是無法獲取到的话告,所以在比對時需要將它移除出去兼搏,那么怎么確定哪一部分是屬于部署代碼的呢?
經(jīng)過觀察發(fā)現(xiàn)沙郭,部署代碼的最后一個指令都會以STOP結(jié)尾(不一定正確)佛呻,在編譯合約時同時生成opcodes,編譯完成后將opcodes讀取進入病线,截取出opcodes第一個STOP指令前所有的指令吓著,計算出這些指令對應的bytecode,然后將其移除出去送挑,由此又衍生出關于opcodes轉(zhuǎn)bytecode的第三個問題3.opcdoes轉(zhuǎn)bytecode的問題
- 指令轉(zhuǎn)換問題
發(fā)現(xiàn)通過opcodes計算的bytecode有時候?qū)τ袝r候不對绑莺,問題出現(xiàn)在PUSH指令上,PUSH1 到PUSH32 分別表示操作1到32個字節(jié)的數(shù)據(jù)让虐,那么后面的數(shù)據(jù)如果不滿足PUSH指令的數(shù)據(jù)長度紊撕,需要在高位補充0- 源代碼指令不夠問題
由于部署代碼部分需要自己進行計算,所以需要收集所有的opcodes赡突,以太坊源碼 中指定的opcodes在實際使用過程中發(fā)現(xiàn)并不完整对扶,經(jīng)過核對有INVALID区赵,KECCAK256 操作碼并沒有在該源碼文件中,手動錄入- 庫合約字節(jié)碼被替換問題
庫合約部署完成后浪南,bytecode開頭(已經(jīng)去除了部署代碼)使用了PUSH20指令后面緊隨合約地址笼才,編譯器剛編譯完成后當然是不知道合約地址的所以PUSH20指令后面跟隨的是空值也就是 0000000000000000000000000000000000000000,檢測到后需要替換為真實合約地址
參考文檔
http://www.reibang.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"
}