• geth共识替换方法


    geth共识替换方法

    本文档基于geth v1.9.25 stable。目前内容基于代码阅读,还没有实际应用来检验。未来可能会进行修补。

    创世块

    在创世块中,config中的一个字段指示了链所用的共识算法,以及该算法所需的参数:

    {
    	"config": {
    	  "chainId": 114514,
    	  "clique": {
    		"period": 5,
    		"epoch": 30000
    	  },
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    创世块的config字段会被解析为在params/config.go中定义的ChainConfig

    为了支持在创世块中配置新的共识算法,需要在该类中增加属性,并通过标签指示和JSON字段的对应关系,如:

    MyBft         *MyBFTConfig         `json:"mybft,omitempty"`
    
    • 1

    在上面的例子中,MyBFTConfig为一个我们自己定义的类,其中包含我们要实现的共识所需的属性

    共识算法判断

    在读取创世块配置后,一个指向params.ChainConfig的指针会被传到eth/backend.go中的CreateConsensusEngine方法

    // CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service
    func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, config *ethash.Config, notify []string, noverify bool, db ethdb.Database) consensus.Engine {
    	// If proof-of-authority is requested, set it up
    	if chainConfig.Clique != nil {
    		return clique.New(chainConfig.Clique, db)
    	}
    	// Otherwise assume proof-of-work
        ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该方法需要根据传入的链配置,返回一个实现了consensus.Engine接口的对象。我们在其中增加一个if,构造自己实现的对象即可。关于该接口的细节详见下文

    consensus.Engine

    共识的核心接口,包含了有关提出区块、验证区块等的各种方法。新的共识算法需要实现下面的全部方法。

    对于实现接口的包如何组织文件,并没有要求

    提出本地区块

    Prepare

    在向新区块中添加交易前,会被调用,来向Header中填充交易无关的已知字段

    FinalizeAndAssemble

    区块塞满交易后会被调用。若区块中的交易除了本身的转账和合约运行外,还通过其他方式(比如blockDAG中的区块奖励)对状态有影响,应该在这里更新状态数据库。在此之后,将不完整的区块头和区块交易列表等组装为待Seal的区块并返回

    如果我们并不需要额外更新状态,用types.NewBlock(header, txs, uncles, receipts, new(trie.Trie))就可以完成组装

    Seal

    组装好的区块发布前要做的工作。该方法异步返回,在完全准备好区块后才通过channel将区块交给上层

    若我们要实现BFT共识中,需要进行额外的节点通信来获得多签。注意到event/event.go中,Post方法可以用于广播数据

    验证外来区块

    VerifySeal

    验证一个区块头是否满足共识中的密码学要求(如PoW中哈希是否符合难度限制,以及PoA中验证签名)

    之所以将密码学验证从区块中验证中提取出来,是因为geth支持Ultra Light Client (ULC)模式,该模式需要尽可能避免复杂计算

    VerifyHeader

    大多数情况下,该方法检查从外界收到的区块头是否合法(考虑共识、时间戳、分叉等因素)

    该方法有一个bool类型的参数seal,当seal为false时,最好避免运行VerifySeal中的密码学检查

    VerifyHeaders

    一次性验证一批区块头,允许并发(当然也可以不并发)

    在Quorum的IBFT中,以及原生的Clique中,都没有进行并发验证,原因未知。为了保险我们最好也不要并发了

    verifyUncles

    ethash中的BlockDAG有关

    我们不需要考虑,直接通过就好

    Finalize

    若外来区块中的交易除了本身的转账和合约运行外,还通过其他方式(比如blockDAG中的区块奖励)对状态有影响,应该在这里更新状态数据库

    我们应该不需要在这里做任何事

    其他

    Author

    输入块头,返回一个地址:在PoW中为块的Coinbase受益者,在PoA中可以自定义为其他地址,如共识中的某个签名者。

    作为块的上下文,智能合约可能会使用该属性,因此需要保证一个块打包后,在不同节点上能得到相同的Author

    APIs

    返回共识特有的RPC-API,用于注册到RPC服务器

    这里参考consensus/ethash/api.goconsensus/ethash/ethash.go写就行

    CalcDifficulty

    因为types.block.goHeader类中,将Difficulty写死在了区块头数据结构里,所以我们必须给每个区块设定一个难度值

    在非PoW的共识中,可以像QuorumIBFT一样直接返回0,也可以活用这一块空间放点东西,比如Clique就用它来表示是否"in turn"

    SealHash

    输入一个未签名区块头,返回它的哈希

    注意传入的区块头可能是带签名的,此时要主动去掉签名部分

  • 相关阅读:
    prometheus day07
    MySQL的安装与卸载
    uni-app 可视化创建的项目 移动端安装调试插件vconsole
    SerializationException: Could not read JSON: Could not resolve type
    latex-minted高亮代码配置
    aix操作系统管子san存储卷
    ES-ES的基本概念
    CEP开发基础知识-AI|PS|AE插件-事件机制-文件操作-界面颜色
    Pycharm 2023 设置远程调试
    【C++】C++基础知识(一)---基本概念
  • 原文地址:https://blog.csdn.net/Leo_h1104/article/details/125902845