+
POA

以太坊私链世界状态不一致如何解决

以太坊私链遇到 invalid merkle root (remote  x local  x) 如何去着手调查原因

Posted by 咕🎨 on 2023-03-06
Words 719 and Reading Time 2 Minutes
Viewed Times

这篇文章是建立在poa共识的基础上, pos和pow应该是同理

好多论坛关于这个问题都是让升级客户端版本, 说是缓存导致的, 但是大部分情况下还是本地数据或者程序逻辑除了问题,导致计算的结果不匹配

首先要解决这个问题, 首先我们要清楚什么是世界状态

世界状态是以太坊区块链中的数据存储状态的一种结果hash表现, 是由所有截至当前区块的所有账户(余额,nonce,code,storage,…)等账户合约的基本属性和值来决定的, 一旦出现了世界状态不匹配, 那么肯定是节点和同步节点的账户的基本属性值不统一了, 要解决这个问题, 就需要找到具体是那些数据不统一了, 找到这些数据,造成这些数据不统一的原因, 然后就可以解决这个问题.

现在的世界状态不一致,将会在这里抛出错误:

1
2
3
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root)
}

首先通过报错原因, 我们可以知道具体的不一致区块(注意, 这里是全节点同步方式, sync=full):

1
2
BAD Block
# 111

那这个时候, 我们就需要查询这个区块和前一个区块的数据.

对比两个区块有那些账户变动,这将输出所有相关账户属性变动的账户和合约地址,包括矿工手续费账户,矿工验证账户,转账账户, 相关合约账户

1
debug.getModifiedAccountsByNumber(110,111)

查询这些账户是否符合预期(这里的预期值得是你清楚,大部分都是和链的共识相关)
我这里查询是因为我的链是poa,然后我设置的手续费账户和节点验证账户不一致,导致出现了这个问题, 具体可以看我前一章说的问题,这个主要还是以太坊poa共识的实现不是很完善, 才会出现这个问题.
具体解决办法, 就是将设置的coinbase加在获取手续费账户的那里

1
2
3
4
5
6
7
8
9
10
func (beacon *Beacon) Author(header *types.Header) (common.Address, error) {
if header.Number.Int64() >= 111 && header.Number.Int64() < 11114 {
//header.Coinbase = common.HexToAddress("0xEa8943f4c47Ab8602eCCD3ed5087512f75C14E60")
return common.HexToAddress("0xEa8943f4c47Ab8602eCCD3ed5087512f75C14E60"), nil
}
if !beacon.IsPoSHeader(header) {
return beacon.ethone.Author(header)
}
return header.Coinbase, nil
}

到这里就结束了, 解决方式还是挺简单的, 主要难点在于你要熟悉节点的共识,以及他每一步会做那些事情, 这些逻辑要清楚.

这里我被这个问题困扰了一周, 如果你感觉这个对你有用的话, 不妨请我喝杯咖啡.


...

...

00:00
00:00