预备知识:
- bytecode=initcode + runtime code + auxdata
- deployedBytecode = runtime code + auxdata
- inputdata = bytecode + constructordata
注:后续,不定期完善文章技术细节
目标: 验证节点收到合约部署的inputdata时,没有将inputdata反解析为 bytecode + constructordata两部分,而是将完整的inputdata传至evm进行合约部署以及初始化操作。
下面,分两部分进行:
Part 1 ,在vm/evm.go文件中找到create方法,并添加日志打印:
// create creates a new contract using code as deployment code.
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) {
...
contract := NewContract(caller, AccountRef(address), value, gas)
contract.SetCodeOptionalHash(&address, codeAndHash)
...
log.Trace("zxl:create():", "contract.Code=", contract.Code)
ret, err := run(evm, contract, nil, false)
//ret, err :evm.interpreter.Run( contract, nil, false) #就版本
log.Trace("zxl:create():", "ret=", ret)
...
evm.StateDB.SetCode(address, ret)
...
}
Part 2 ,编译节点 -> 运行 ->执行部署合约操作,日志明细如下:
合约部署信息(inputdata=bytecode+constructordata)
0x608060405234801561001057600080fd5b506040516101dc3803806101dc83398181016040528101906100329190610054565b806000819055505061009e565b60008151905061004e81610087565b92915050565b60006020828403121561006657600080fd5b60006100748482850161003f565b91505092915050565b6000819050919050565b6100908161007d565b811461009b57600080fd5b50565b61012f806100ad6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80632e64cec11460375780636057361d146051575b600080fd5b603d6069565b6040516048919060c2565b60405180910390f35b6067600480360381019060639190608f565b6072565b005b60008054905090565b8060008190555050565b60008135905060898160e5565b92915050565b60006020828403121560a057600080fd5b600060ac84828501607c565b91505092915050565b60bc8160db565b82525050565b600060208201905060d5600083018460b5565b92915050565b6000819050919050565b60ec8160db565b811460f657600080fd5b5056fea2646970667358221220bf97ccb086bbee86f58889aa1f4540fdfc1be786fc7e0254b186443c42790e1e64736f6c634300080300330000000000000000000000000000000000000000000000000000000000000001
节点日志信息
## inputdata
TRACE[04-06|07:25:13.007] zxl:create(): contract.Code="[96 128 96 64 82 52 128 21 97 0 16 87 96 0 128 253 91 80 96 64 81 97 1 220 56 3 128 97 1 220 131 57 129 129 1 96 64 82 129 1 144 97 0 50 145 144 97 0 84 86 91 128 96 0 129 144 85 80 80 97 0 158 86 91 96 0 129 81 144 80 97 0 78 129 97 0 135 86 91 146 145 80 80 86 91 96 0 96 32 130 132 3 18 21 97 0 102 87 96 0 128 253 91 96 0 97 0 116 132 130 133 1 97 0 63 86 91 145 80 80 146 145 80 80 86 91 96 0 129 144 80 145 144 80 86 91 97 0 144 129 97 0 125 86 91 129 20 97 0 155 87 96 0 128 253 91 80 86 91 97 1 47 128 97 0 173 96 0 57 96 0 243 254 96 128 96 64 82 52 128 21 96 15 87 96 0 128 253 91 80 96 4 54 16 96 50 87 96 0 53 96 224 28 128 99 46 100 206 193 20 96 55 87 128 99 96 87 54 29 20 96 81 87 91 96 0 128 253 91 96 61 96 105 86 91 96 64 81 96 72 145 144 96 194 86 91 96 64 81 128 145 3 144 243 91 96 103 96 4 128 54 3 129 1 144 96 99 145 144 96 143 86 91 96 114 86 91 0 91 96 0 128 84 144 80 144 86 91 128 96 0 129 144 85 80 80 86 91 96 0 129 53 144 80 96 137 129 96 229 86 91 146 145 80 80 86 91 96 0 96 32 130 132 3 18 21 96 160 87 96 0 128 253 91 96 0 96 172 132 130 133 1 96 124 86 91 145 80 80 146 145 80 80 86 91 96 188 129 96 219 86 91 130 82 80 80 86 91 96 0 96 32 130 1 144 80 96 213 96 0 131 1 132 96 181 86 91 146 145 80 80 86 91 96 0 129 144 80 145 144 80 86 91 96 236 129 96 219 86 91 129 20 96 246 87 96 0 128 253 91 80 86 254 162 100 105 112 102 115 88 34 18 32 191 151 204 176 134 187 238 134 245 136 137 170 31 69 64 253 252 27 231 134 252 126 2 84 177 134 68 60 66 121 14 30 100 115 111 108 99 67 0 8 3 0 51 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]"
## run返回的结果信息,即deployedBytecode
TRACE[04-06|07:25:13.007]zxl:create(): ret="[96 128 96 64 82 52 128 21 96 15 87 96 0 128 253 91 80 96 4 54 16 96 50 87 96 0 53 96 224 28 128 99 46 100 206 193 20 96 55 87 128 99 96 87 54 29 20 96 81 87 91 96 0 128 253 91 96 61 96 105 86 91 96 64 81 96 72 145 144 96 194 86 91 96 64 81 128 145 3 144 243 91 96 103 96 4 128 54 3 129 1 144 96 99 145 144 96 143 86 91 96 114 86 91 0 91 96 0 128 84 144 80 144 86 91 128 96 0 129 144 85 80 80 86 91 96 0 129 53 144 80 96 137 129 96 229 86 91 146 145 80 80 86 91 96 0 96 32 130 132 3 18 21 96 160 87 96 0 128 253 91 96 0 96 172 132 130 133 1 96 124 86 91 145 80 80 146 145 80 80 86 91 96 188 129 96 219 86 91 130 82 80 80 86 91 96 0 96 32 130 1 144 80 96 213 96 0 131 1 132 96 181 86 91 146 145 80 80 86 91 96 0 129 144 80 145 144 80 86 91 96 236 129 96 219 86 91 129 20 96 246 87 96 0 128 253 91 80 86 254 162 100 105 112 102 115 88 34 18 32 191 151 204 176 134 187 238 134 245 136 137 170 31 69 64 253 252 27 231 134 252 126 2 84 177 134 68 60 66 121 14 30 100 115 111 108 99 67 0 8 3 0 51]"
TRACE[04-06|07:25:13.007] Decrease miner recommit interval from=3s to=3s
通过上述contract.Code
打印信息,以及后续代码evm.StateDB.SetCode(address, ret)
,可以看出部署合约的流程为:将完整的inputdata(bytecode+constructor data)输入至evm.run方法,方法内部进行合约参数的初始化并返回真正的合约代码(runtime code),然后将合约代码放到链上供后续使用。
其它,也可以通过evm程序直接执行inputdata然后获取合约代码(deployedBytecode),如下:
./evm --code "0x608060405234801561001057600080fd5b506040516102063803806102068339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b610150806100b66000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea2646970667358221220cac7b3b4790dc4b26fbeff92940ab21eaaad12d09c5c7a4a0b470f1c1832b62f64736f6c634300081200330000000000000000000000000000000000000000000000000000000000000001" run
结果:
0x608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100a1565b60405180910390f35b610073600480360381019061006e91906100ed565b61007e565b005b60008054905090565b8060008190555050565b6000819050919050565b61009b81610088565b82525050565b60006020820190506100b66000830184610092565b92915050565b600080fd5b6100ca81610088565b81146100d557600080fd5b50565b6000813590506100e7816100c1565b92915050565b600060208284031215610103576101026100bc565b5b6000610111848285016100d8565b9150509291505056fea2646970667358221220cac7b3b4790dc4b26fbeff92940ab21eaaad12d09c5c7a4a0b470f1c1832b62f64736f6c63430008120033
另外,通过./solc --asm
查看合约代码的汇编指令以及auxdata
[root@localhost bin]# ./solc-static-linux-0.8.18 --asm ./storage.sol
======= storage.sol:Storage =======
EVM assembly:
/* "storage.sol":199:617 contract Storage {... */
mstore(0x40, 0x80)
/* "storage.sol":248:301 constructor(uint256 num){... */
callvalue
dup1
iszero
tag_1
jumpi
0x00
...
...
swap2
pop
pop
jump // out
auxdata: 0xa264697066735822122093c5cdbdc06d1cfee5be32f251d2b5328f062666a86d139563953d11b8200aaa64736f6c63430008120033
}
参考资料
- 深入了解以太坊虚拟机第5部分——一个新合约被创建后会发生什么: https://www.jianshu.com/p/d9137e87c9d3
- 死磕以太坊源码分析之EVM指令集:https://www.bbsmax.com/A/A2dmD7Bx5e/
- 以太坊Transaction中的三种Payload解析以及bytecode和deployedbytecode:http://events.jianshu.io/p/996869b3785d
4.剖析Solidity合约创建EVM bytecode: https://blog.csdn.net/mutourend/article/details/127365619 - 以太坊黄皮书:https://ethereum.github.io/yellowpaper/paper.pdf
网友评论