Uniswap
部署依赖Istanbul
中的chainid
,从君士坦丁堡升级到YoloV1
最新版本,就可以在链上正常部署。本文讲粗略讲一下升级涉及功能和问题的定位解决。
**YoloV1升级**
* `2315`的`subroutines`,包含如下opcode `BEGINSUB`,`RETURNSUB`,`JUMPSUB`
**功能点**
整合`gas`各个版本的升级,删除了`params`的`gas_table`
不同版本更新`opcode`的`gas`费用,提高了状态加载和存储的费用如`SLOAD` `BALANCE` `EXTCODEHASH`
常量`gas`费从`opcode`对应的函数中移除,赋值给`constantGas`
操作数`big.Int`类型为`uint256.Int`,提高`25%`执行效率
整合`内存拷贝`和`内存创建`的`gas计算`和`溢出检查`
减少`zk`使用的`bn256` gas费,添加`blake2F`和`bls预编译合约`
增加`ReturnStack`可返回`错误结果`方便`debug`
> `SLOAD` `BALANCE` `EXTCODEHASH` 存储访问操作码,16年因为`EXTCODESIZE`被dos攻击,状态读取和存储异常耗时,需要提高gas费。
### 错误输出
之前合约执行错误只会输出`execution reverted`,现在可以打印哪里报错
“`
execution reverted: TransferHelper: TRANSFER_FROM_FAILED
“`
在`sol`里面找到如下报错,为对方`Approve`金额较低导致。
“`
require(success && (data.length == 0 || abi.decode(data, (bool))), ‘TransferHelper: TRANSFER_FROM_FAILED’);
“`
### 容易出错的地方
* `opcode`中`gas`费计算错误
* `constantGas` 常量已从`gas_table`中移除,直接在代码中根据解析器分支使用不同的`opcode gas`费
* `dynamicGas` 计算在内存占用费用
### Evm测试TraceLog
* 跟旧版本是否兼容,需要重新同步旧的历史块
* 功能是否完善,Uniswap应用是否可部署成功
### 合约解析器
下面规定了不同的分叉使用的`EVMInterpreter`解析器是不一样的。
“`
// NewEVMInterpreter returns a new instance of the Interpreter.
func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
// We use the STOP instruction whether to see
// the jump table was initialised. If it was not
// we’ll set the default jump table.
if cfg.JumpTable[STOP] == nil {
var jt JumpTable
switch {
case evm.chainRules.IsYoloV1:
jt = yoloV1InstructionSet
case evm.chainRules.IsIstanbul:
jt = istanbulInstructionSet
case evm.chainRules.IsConstantinople:
jt = constantinopleInstructionSet
case evm.chainRules.IsByzantium:
jt = byzantiumInstructionSet
default:
jt = frontierInstructionSet
}
cfg.JumpTable = jt
}
return &EVMInterpreter{
evm: evm,
cfg: cfg,
}
}
“`
### 预编译合约
不同的升级使用的`PrecompiledContract`预编译合约也不一样的,预编译合约主要是处理一些复杂的数学计算,这类计算evm执行起来较慢,所以以预编译合约的形式加入到evm里面,合约执行的过程不是汇编执行而是具体代码
“`
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
var precompiles map[common.Address]PrecompiledContract
switch {
case evm.chainRules.IsYoloV1:
precompiles = PrecompiledContractsYoloV1
case evm.chainRules.IsIstanbul:
precompiles = PrecompiledContractsIstanbul
case evm.chainRules.IsByzantium:
precompiles = PrecompiledContractsByzantium
default:
precompiles = PrecompiledContractsHomestead
}
p, ok := precompiles[addr]
return p, ok
}
“`
这是升级中加的一些预编译合约,很多是支持零知识证明的,椭圆配对曲线称为BLS12-381,为过渡eth2.0提供基础,该预编译使精简客户端成为可能。
“`
// PrecompiledContractsYoloV1 contains the default set of pre-compiled Ethereum
// contracts used in the Yolo v1 test release.
var PrecompiledContractsYoloV1 = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{10}): &bls12381G1Add{},
common.BytesToAddress([]byte{11}): &bls12381G1Mul{},
common.BytesToAddress([]byte{12}): &bls12381G1MultiExp{},
common.BytesToAddress([]byte{13}): &bls12381G2Add{},
common.BytesToAddress([]byte{14}): &bls12381G2Mul{},
common.BytesToAddress([]byte{15}): &bls12381G2MultiExp{},
common.BytesToAddress([]byte{16}): &bls12381Pairing{},
common.BytesToAddress([]byte{17}): &bls12381MapG1{},
common.BytesToAddress([]byte{18}): &bls12381MapG2{},
}
“`
### 新旧版本问题
合约执行中如果计算的`gas`不一致,区块验证就会报错。这个问题相当严重
#### 问题查找
抓取合约执行过程的`Trace log`分析不同点,截取了如下日志。
“`
{“pc”:2373,”op”:84,”gas”:”0xeddb6″,”gasCost”:”0x320″,”memory”:”0x000000000000000000000000735bce5ecc8455eb9bf8270aa138ce05e069b4c1656502bc70f67e407a17d7e0cba13a8b062e13793501bed56cecc8aee887bd7d0000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[“0x1bf73a65″,”0x181″,”0x2de96ad91d62a796c4ba80e0a862520f9c8a7805″,”0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1″,”0x0″,”0x0″,”0x47f37265329d36000″,”0x1″,”0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1″,”0x0″,”0x1137c4082672bb033743321bcc426da68e2052bc996d994df96a0e1cd48b5b60″],”returnStack”:[],”returnData”:null,”depth”:1,”refund”:0,”opName”:”SLOAD”,”error”:””}
{“pc”:2374,”op”:144,”gas”:”0xeda96″,”gasCost”:”0x3″,”memory”:”0x000000000000000000000000735bce5ecc8455eb9bf8270aa138ce05e069b4c1656502bc70f67e407a17d7e0cba13a8b062e13793501bed56cecc8aee887bd7d0000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[“0x1bf73a65″,”0x181″,”0x2de96ad91d62a796c4ba80e0a862520f9c8a7805″,”0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1″,”0x0″,”0x0″,”0x47f37265329d36000″,”0x1″,”0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1″,”0x0″,”0x1″],”returnStack”:[],”returnData”:null,”depth”:1,”refund”:0,”opName”:”SWAP1″,”error”:””}
“`
将上面的`0xeddb6`和`0xeda96`相减是`800`十六进制为`0x320`
“`
{“pc”:2373,”op”:84,”gas”:”0xeddb6″,”gasCost”:”0xc8″,”memory”:”0x000000000000000000000000735bce5ecc8455eb9bf8270aa138ce05e069b4c1656502bc70f67e407a17d7e0cba13a8b062e13793501bed56cecc8aee887bd7d0000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[“0x1bf73a65″,”0x181″,”0x2de96ad91d62a796c4ba80e0a862520f9c8a7805″,”0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1″,”0x0″,”0x0″,”0x47f37265329d36000″,”0x1″,”0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1″,”0x0″,”0x1137c4082672bb033743321bcc426da68e2052bc996d994df96a0e1cd48b5b60″],”depth”:1,”refund”:0,”opName”:”SLOAD”,”error”:””}
{“pc”:2374,”op”:144,”gas”:”0xedcee”,”gasCost”:”0xc8″,”memory”:”0x000000000000000000000000735bce5ecc8455eb9bf8270aa138ce05e069b4c1656502bc70f67e407a17d7e0cba13a8b062e13793501bed56cecc8aee887bd7d0000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[“0x1bf73a65″,”0x181″,”0x2de96ad91d62a796c4ba80e0a862520f9c8a7805″,”0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1″,”0x0″,”0x0″,”0x47f37265329d36000″,”0x1″,”0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1″,”0x0″,”0x1″],”depth”:1,”refund”:0,”opName”:”SWAP1″,”error”:””}
“`
这个是升级前的日志,相减得`200`十六进制为`0xc8`
查询`84`的`opcode`是`0x54` `SLOAD`在`Istanbul`后`SloadGasEIP1884`调节到了`800`,这个由于分叉高度设置太低导致使用`yoloV1InstructionSet`解析器,其实是没问题的,调节`YoloV1Block`高度即可
“`
“YOLOv1”: {
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
YoloV1Block: big.NewInt(0),
},
“`
### 功能不完善问题
eth部署合约正确的指令流程
“`
{“pc”:23,”op”:96,”gas”:”0x278abc”,”gasCost”:”0x3″,”memory”:”0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[],”returnStack”:[],”returnData”:null,”depth”:3,”refund”:0,”opName”:”PUSH1″,”error”:””}
{“pc”:25,”op”:81,”gas”:”0x278ab9″,”gasCost”:”0x3″,”memory”:”0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[“0x40″],”returnStack”:[],”returnData”:null,”depth”:3,”refund”:0,”opName”:”MLOAD”,”error”:””}
{“pc”:26,”op”:70,”gas”:”0x278ab6″,”gasCost”:”0x2″,”memory”:”0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[“0x80″],”returnStack”:[],”returnData”:null,”depth”:3,”refund”:0,”opName”:”CHAINID”,”error”:””}
{“pc”:27,”op”:144,”gas”:”0x278ab4″,”gasCost”:”0x3″,”memory”:”0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[“0x80″,”0x539″],”returnStack”:[],”returnData”:null,”depth”:3,”refund”:0,”opName”:”SWAP1″,”error”:””}
“`
升级后evm的流程
“`
{“pc”:23,”op”:96,”gas”:”0x5c54030″,”gasCost”:”0x3″,”memory”:”0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[],”returnStack”:[],”returnData”:null,”depth”:3,”refund”:0,”opName”:”PUSH1″,”error”:””}
{“pc”:25,”op”:81,”gas”:”0x5c5402d”,”gasCost”:”0x3″,”memory”:”0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[“0x40″],”returnStack”:[],”returnData”:null,”depth”:3,”refund”:0,”opName”:”MLOAD”,”error”:””}
{“pc”:26,”op”:70,”gas”:”0x5c5402a”,”gasCost”:”0x3″,”memory”:”0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080″,”memSize”:96,”stack”:[“0x80″],”returnStack”:[],”returnData”:null,”depth”:3,”refund”:0,”opName”:”CHAINID”,”error”:”invalid opcode: CHAINID”}
{“pc”:1507,”op”:96,”gas”:”0x17740a”,”gasCost”:”0x3″,”memory”:””,”memSize”:11904,”stack”:[“0xc9c65396″,”0x95″,”0x537e697c7ab75a26f9ecf0ce810e3154dfcaaf44″,”0x3a220f351252089d385b29beca14e27f204c296a”,”0x0″,”0x3a220f351252089d385b29beca14e27f204c296a”,”0x537e697c7ab75a26f9ecf0ce810e3154dfcaaf44″,”0x80″,”0xb81ff3c7140db37a05a85068ea614a23c0d72ec176588a2f45c5dd53550b6c88″,”0x0″],”returnStack”:[],”returnData”:null,”depth”:2,”refund”:0,”opName”:”PUSH1″,”error”:””}
“`
从`pc`指针可以看`操作码70`后结果开始不一样了,`70`对于的`opcode`是`CHAINID`,而`CHAINID`是`Istanbul`后加入的,由于`IstanbulBlock`高度设置较高,功能为开启,所以跳转不一样。
`trace log`也有报错`”opName”:”CHAINID”,”error”:”invalid opcode: CHAINID”`。
#### 总结
两个问题都是`YoloV1Block`未正确设置导致加载的`EVMInterpreter`解析器不对导致
Istanbul升级
1344中
添加chainid
的opcode
获取链的当前chainid1884
中添加balance
的opcede
查询调用方余额2200
中状态加载和存储的gas
费增加更新
YoloV1升级
2315
的subroutines
,包含如下opcodeBEGINSUB
,RETURNSUB
,JUMPSUB
功能点
整合gas
各个版本的升级,删除了params
的gas_table
不同版本更新opcode
的gas
费用,提高了状态加载和存储的费用如SLOAD
BALANCE
EXTCODEHASH
常量gas
费从opcode
对应的函数中移除,赋值给constantGas
操作数big.Int
类型为uint256.Int
,提高25%
执行效率 整合内存拷贝
和内存创建
的gas计算
和溢出检查
减少zk
使用的bn256
gas费,添加blake2F
和bls预编译合约
增加ReturnStack
可返回错误结果
方便debug
SLOAD
BALANCE
EXTCODEHASH
存储访问操作码,16年因为EXTCODESIZE
被dos攻击,状态读取和存储异常耗时,需要提高gas费。
错误输出
之前合约执行错误只会输出execution reverted
,现在可以打印哪里报错
execution reverted: TransferHelper: TRANSFER_FROM_FAILED
在sol
里面找到如下报错,为对方Approve
金额较低导致。
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED');
容易出错的地方
opcode
中gas
费计算错误constantGas
常量已从gas_table
中移除,直接在代码中根据解析器分支使用不同的opcode gas
费dynamicGas
计算在内存占用费用
Evm测试TraceLog
- 跟旧版本是否兼容,需要重新同步旧的历史块
- 功能是否完善,Uniswap应用是否可部署成功
合约解析器
下面规定了不同的分叉使用的EVMInterpreter
解析器是不一样的。
// NewEVMInterpreter returns a new instance of the Interpreter.
func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
// We use the STOP instruction whether to see
// the jump table was initialised. If it was not
// we'll set the default jump table.
if cfg.JumpTable[STOP] == nil {
var jt JumpTable
switch {
case evm.chainRules.IsYoloV1:
jt = yoloV1InstructionSet
case evm.chainRules.IsIstanbul:
jt = istanbulInstructionSet
case evm.chainRules.IsConstantinople:
jt = constantinopleInstructionSet
case evm.chainRules.IsByzantium:
jt = byzantiumInstructionSet
default:
jt = frontierInstructionSet
}
cfg.JumpTable = jt
}
return &EVMInterpreter{
evm: evm,
cfg: cfg,
}
}
预编译合约
不同的升级使用的PrecompiledContract
预编译合约也不一样的,预编译合约主要是处理一些复杂的数学计算,这类计算evm执行起来较慢,所以以预编译合约的形式加入到evm里面,合约执行的过程不是汇编执行而是具体代码
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
var precompiles map[common.Address]PrecompiledContract
switch {
case evm.chainRules.IsYoloV1:
precompiles = PrecompiledContractsYoloV1
case evm.chainRules.IsIstanbul:
precompiles = PrecompiledContractsIstanbul
case evm.chainRules.IsByzantium:
precompiles = PrecompiledContractsByzantium
default:
precompiles = PrecompiledContractsHomestead
}
p, ok := precompiles[addr]
return p, ok
}
这是升级中加的一些预编译合约,很多是支持零知识证明的,椭圆配对曲线称为BLS12-381,为过渡eth2.0提供基础,该预编译使精简客户端成为可能。
// PrecompiledContractsYoloV1 contains the default set of pre-compiled Ethereum
// contracts used in the Yolo v1 test release.
var PrecompiledContractsYoloV1 = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
common.BytesToAddress([]byte{4}): &dataCopy{},
common.BytesToAddress([]byte{5}): &bigModExp{},
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{10}): &bls12381G1Add{},
common.BytesToAddress([]byte{11}): &bls12381G1Mul{},
common.BytesToAddress([]byte{12}): &bls12381G1MultiExp{},
common.BytesToAddress([]byte{13}): &bls12381G2Add{},
common.BytesToAddress([]byte{14}): &bls12381G2Mul{},
common.BytesToAddress([]byte{15}): &bls12381G2MultiExp{},
common.BytesToAddress([]byte{16}): &bls12381Pairing{},
common.BytesToAddress([]byte{17}): &bls12381MapG1{},
common.BytesToAddress([]byte{18}): &bls12381MapG2{},
}
新旧版本问题
合约执行中如果计算的gas
不一致,区块验证就会报错。这个问题相当严重
问题查找
抓取合约执行过程的Trace log
分析不同点,截取了如下日志。
{"pc":2373,"op":84,"gas":"0xeddb6","gasCost":"0x320","memory":"0x000000000000000000000000735bce5ecc8455eb9bf8270aa138ce05e069b4c1656502bc70f67e407a17d7e0cba13a8b062e13793501bed56cecc8aee887bd7d0000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":["0x1bf73a65","0x181","0x2de96ad91d62a796c4ba80e0a862520f9c8a7805","0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1","0x0","0x0","0x47f37265329d36000","0x1","0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1","0x0","0x1137c4082672bb033743321bcc426da68e2052bc996d994df96a0e1cd48b5b60"],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"SLOAD","error":""}
{"pc":2374,"op":144,"gas":"0xeda96","gasCost":"0x3","memory":"0x000000000000000000000000735bce5ecc8455eb9bf8270aa138ce05e069b4c1656502bc70f67e407a17d7e0cba13a8b062e13793501bed56cecc8aee887bd7d0000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":["0x1bf73a65","0x181","0x2de96ad91d62a796c4ba80e0a862520f9c8a7805","0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1","0x0","0x0","0x47f37265329d36000","0x1","0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1","0x0","0x1"],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"SWAP1","error":""}
将上面的0xeddb6
和0xeda96
相减是800
十六进制为0x320
{"pc":2373,"op":84,"gas":"0xeddb6","gasCost":"0xc8","memory":"0x000000000000000000000000735bce5ecc8455eb9bf8270aa138ce05e069b4c1656502bc70f67e407a17d7e0cba13a8b062e13793501bed56cecc8aee887bd7d0000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":["0x1bf73a65","0x181","0x2de96ad91d62a796c4ba80e0a862520f9c8a7805","0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1","0x0","0x0","0x47f37265329d36000","0x1","0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1","0x0","0x1137c4082672bb033743321bcc426da68e2052bc996d994df96a0e1cd48b5b60"],"depth":1,"refund":0,"opName":"SLOAD","error":""}
{"pc":2374,"op":144,"gas":"0xedcee","gasCost":"0xc8","memory":"0x000000000000000000000000735bce5ecc8455eb9bf8270aa138ce05e069b4c1656502bc70f67e407a17d7e0cba13a8b062e13793501bed56cecc8aee887bd7d0000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":["0x1bf73a65","0x181","0x2de96ad91d62a796c4ba80e0a862520f9c8a7805","0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1","0x0","0x0","0x47f37265329d36000","0x1","0x735bce5ecc8455eb9bf8270aa138ce05e069b4c1","0x0","0x1"],"depth":1,"refund":0,"opName":"SWAP1","error":""}
这个是升级前的日志,相减得200
十六进制为0xc8
查询84
的opcode
是0x54
SLOAD
在Istanbul
后SloadGasEIP1884
调节到了800
,这个由于分叉高度设置太低导致使用yoloV1InstructionSet
解析器,其实是没问题的,调节YoloV1Block
高度即可
"YOLOv1": {
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
YoloV1Block: big.NewInt(0),
},
功能不完善问题
eth部署合约正确的指令流程
{"pc":23,"op":96,"gas":"0x278abc","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":[],"returnStack":[],"returnData":null,"depth":3,"refund":0,"opName":"PUSH1","error":""}
{"pc":25,"op":81,"gas":"0x278ab9","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":["0x40"],"returnStack":[],"returnData":null,"depth":3,"refund":0,"opName":"MLOAD","error":""}
{"pc":26,"op":70,"gas":"0x278ab6","gasCost":"0x2","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":["0x80"],"returnStack":[],"returnData":null,"depth":3,"refund":0,"opName":"CHAINID","error":""}
{"pc":27,"op":144,"gas":"0x278ab4","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":["0x80","0x539"],"returnStack":[],"returnData":null,"depth":3,"refund":0,"opName":"SWAP1","error":""}
升级后evm的流程
{"pc":23,"op":96,"gas":"0x5c54030","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":[],"returnStack":[],"returnData":null,"depth":3,"refund":0,"opName":"PUSH1","error":""}
{"pc":25,"op":81,"gas":"0x5c5402d","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":["0x40"],"returnStack":[],"returnData":null,"depth":3,"refund":0,"opName":"MLOAD","error":""}
{"pc":26,"op":70,"gas":"0x5c5402a","gasCost":"0x3","memory":"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080","memSize":96,"stack":["0x80"],"returnStack":[],"returnData":null,"depth":3,"refund":0,"opName":"CHAINID","error":"invalid opcode: CHAINID"}
{"pc":1507,"op":96,"gas":"0x17740a","gasCost":"0x3","memory":"","memSize":11904,"stack":["0xc9c65396","0x95","0x537e697c7ab75a26f9ecf0ce810e3154dfcaaf44","0x3a220f351252089d385b29beca14e27f204c296a","0x0","0x3a220f351252089d385b29beca14e27f204c296a","0x537e697c7ab75a26f9ecf0ce810e3154dfcaaf44","0x80","0xb81ff3c7140db37a05a85068ea614a23c0d72ec176588a2f45c5dd53550b6c88","0x0"],"returnStack":[],"returnData":null,"depth":2,"refund":0,"opName":"PUSH1","error":""}
从pc
指针可以看操作码70
后结果开始不一样了,70
对于的opcode
是CHAINID
,而CHAINID
是Istanbul
后加入的,由于IstanbulBlock
高度设置较高,功能为开启,所以跳转不一样。 trace log
也有报错"opName":"CHAINID","error":"invalid opcode: CHAINID"
。
总结
两个问题都是YoloV1Block
未正确设置导致加载的EVMInterpreter
解析器不对导致
本文参与区块链开发网写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。
- 发表于 2020-08-26 23:59
- 阅读 ( 1594 )
- 学分 ( 18 )
- 分类:以太坊