前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >matic checkpoint理解

matic checkpoint理解

作者头像
潇洒
发布2023-10-23 08:46:43
1580
发布2023-10-23 08:46:43
举报
文章被收录于专栏:石头岛

概念

checkpointMatic协议中最关键的部分。它代表了Bor链状态的快照,应该由⅔+的验证器集证明,然后再验证并提交给部署在以太坊上的合约。

这里有几个问题:

  1. checkpoint 是什么
  2. 为什么要提交bor的状态,状态中包含哪些信息
  3. checkpoint 验证流程

checkpoint 是什么

checkpointMatic协议中最关键的部分。它代表了Bor链状态的快照,应该由⅔+的validator集证明,然后再验证并提交给部署在以太坊上的合约。

Heimdall 层允许将 Bor 生成的区块聚合到单个 Merkle 根中,并定期将其发布到以太坊主链。 此已发布状态也称为检查点,因此整个过程称为validator(检查点)。 检查点提议者最初是通过 Tendermint 的加权循环算法选择的。

checkpoint 结构

代码语言:javascript
复制
type CheckpointBlockHeader struct {
    // Proposer is selected based on stake
    Proposer        types.HeimdallAddress `json:"proposer"`

    // StartBlock: The block number on Bor from which this checkpoint starts
    StartBlock      uint64                `json:"startBlock"`

    // EndBlock: The block number on Bor from which this checkpoint ends
    EndBlock        uint64                `json:"endBlock"`

    // RootHash is the Merkle root of all the leaves containing the block
    // headers starting from start to the end block
    RootHash        types.HeimdallHash    `json:"rootHash"`

    // Account root hash for each validator
    // Hash of data that needs to be passed from Heimdall to Ethereum chain like slashing, withdraw topup etc.
    AccountRootHash types.HeimdallHash    `json:"accountRootHash"`

  // Timestamp when checkpoint was created on Heimdall
    TimeStamp       uint64          `json:"timestamp"`
}

注意:这里 checkpoint 的提交是基于 bor 的StartBlockEndBlock之间的区块,这点很重要。 bor是基于Ethereum协议实现的底层链。官方定义

checkpoint
checkpoint

blockHash

代码语言:javascript
复制
blockHash = keccak256([number, time, tx hash, receipt hash])

rootHash

代码语言:javascript
复制
B(1) := keccak256([number, time, tx hash, receipt hash])
B(2) := keccak256([number, time, tx hash, receipt hash])
.
.
.
B(n) := keccak256([number, time, tx hash, receipt hash])

// checkpoint is Merkle root of all block hash
checkpoint's root hash = Merkel[B(1), B(2), ....., B(n)]

代码实现

下面是 Bor 链区块创建checkpoint的代码片段,官方代码: https://github.com/maticnetwork/heimdall/blob/develop/checkpoint/types/merkel.go#L60-L114

代码语言:javascript
复制
// Golang representation of block data used in checkpoint
blockData := crypto.Keccak256(appendBytes32(
    blockHeader.Number.Bytes(),
    new(big.Int).SetUint64(blockHeader.Time).Bytes(),
    blockHeader.TxHash.Bytes(),
    blockHeader.ReceiptHash.Bytes(),
))

// array of block hashes of Bor blocks
headers := [blockData1, blockData2, ..., blockDataN]

// merkel tre
tree := merkle.NewTreeWithOpts(merkle.TreeOptions{EnableHashSorting: false, DisableHashLeaves: true})
tree.Generate(convert(headers), sha3.NewLegacyKeccak256())

// create checkpoint's root hash
rootHash := tree.Root().Hash

总体流程

  1. 侧链提交 checkpoint
  2. Validator 接收、验证checkpoint,并提交主链
  3. 主链接收checkpoint,并发送checkpoint-ack
  4. Validator 接收、验证 checkpoint-ack

Validator 层通过 bridge模块监听主链侧链上的合约事件。

质押:质押链为ETH主链

存款:发生在ETH主链

取款:发生在MATIC侧链 下面的流程图代表了checkpoint的生命周期。

checkpoint流程
checkpoint流程

Heimdall使用与Tendermint相同的共识算法来选择下一个Proposer。Proposer 也就是 Heimdall 层的出块者,在 Matic 中发分起一个 Propose 提案

在以太坊链上提交checkpoint时,可能会因为多种原因而失败,如gas limit,以太坊拥堵,高gas费用。这就是为什么需要多阶段的checkpoint过程。

因为每个checkpointProposer提起的,而每个validator都有机会被选举为Proposer。 如果提交以太坊链上的checkpoint成功或失败,将会发送ackno-ack交易将改变Heimdall上的提议者,以进行下一个检查点。

Checkpoint 流程

![Checkpoint 流程](checkpointMessage 流程.jpg)

那么问题来了,Heimdall 链是怎么知道 checkpoint 提交 Ethereum主链成功没成功?

Heimdall项目中的bor模块,是基于Ethereum实现ETH协议,实际就是包装了EVM,可以接收ETH广播的区块,并监听合约事件,从事件中获取需要的事件信息。

Checkpoint 事件监听

看下 checkpoint 相关的事件监听,heimdall 的事件处理通过将监听器监听到的事件,发送到队列当中,由事件处理器进行处理。 这些逻辑在 bridge 模块中进行。

关键事件:

  1. sendCheckpointToHeimdall
  2. sendCheckpointToRootchain
  3. sendCheckpointAckToHeimdall

Rootchain是Ethereum Heimdall是matic的中间层

获取监听事件

bridge/setu/listener/heimdall.go

代码语言:javascript
复制
// ProcessBlockEvent - process Blockevents (BeginBlock, EndBlock events) from heimdall.
func (hl *HeimdallListener) ProcessBlockEvent(event sdk.StringEvent, blockHeight int64) {
	hl.Logger.Info("Received block event from Heimdall", "eventType", event.Type, "height", blockHeight)
	eventBytes, err := json.Marshal(event)
	if err != nil {
		hl.Logger.Error("Error while parsing block event", "error", err, "eventType", event.Type)
		return
	}

	switch event.Type {
	case checkpointTypes.EventTypeCheckpoint:
        //发送事件到队列
		hl.sendBlockTask("sendCheckpointToRootchain", eventBytes, blockHeight)
	case checkpointTypes.EventTypeCheckpointSync:
		hl.sendBlockTask("sendCheckpointSyncToStakeChain", eventBytes, blockHeight)
	case slashingTypes.EventTypeSlashLimit:
		hl.sendBlockTask("sendTickToHeimdall", eventBytes, blockHeight)
	case slashingTypes.EventTypeTickConfirm:
		hl.sendBlockTask("sendTickToRootchain", eventBytes, blockHeight)

	case stakingTypes.EventTypeValidatorJoin,
		stakingTypes.EventTypeSignerUpdate,
		stakingTypes.EventTypeValidatorExit,
		stakingTypes.EventTypeStakingSyncAck:
		hl.sendBlockTask("sendStakingSyncToHeimdall", eventBytes, blockHeight)
	case stakingTypes.EventTypeStakingSync:
		hl.sendBlockTask("sendStakingSyncToRootChain", eventBytes, blockHeight)
	default:
		hl.Logger.Debug("BlockEvent Type mismatch", "eventType", event.Type)
	}
}

发送事件到队列

hl.queueConnector 是Heimdall的内部队列

代码语言:javascript
复制
func (hl *HeimdallListener) sendBlockTask(taskName string, eventBytes []byte, blockHeight int64) {
	// create machinery task
	signature := &tasks.Signature{
		Name: taskName,
		Args: []tasks.Arg{
			{
				Type:  "string",
				Value: string(eventBytes),
			},
			{
				Type:  "int64",
				Value: blockHeight,
			},
		},
	}
	signature.RetryCount = 3
	signature.RetryTimeout = 3
	hl.Logger.Info("Sending block level task",
		"taskName", taskName, "eventBytes", eventBytes, "currentTime", time.Now(), "blockHeight", blockHeight)
	// send task
	_, err := hl.queueConnector.Server.SendTask(signature)
	if err != nil {
		hl.Logger.Error("Error sending block level task", "taskName", taskName, "blockHeight", blockHeight, "error", err)
	}
}

处理队列的 checkpoint 事件

bridge/setu/processor/checkpoint.go

  1. sendCheckpointToHeimdall 监听事件
  2. cp.sendCheckpointToHeimdall 事件处理器
  3. sendCheckpointAckToHeimdall checkpoint-Ack事件
代码语言:javascript
复制
// RegisterTasks - Registers checkpoint related tasks with machinery
func (cp *CheckpointProcessor) RegisterTasks() {
	cp.Logger.Info("Registering checkpoint tasks")
	if err := cp.queueConnector.Server.RegisterTask("sendCheckpointToHeimdall", cp.sendCheckpointToHeimdall); err != nil {
		cp.Logger.Error("RegisterTasks | sendCheckpointToHeimdall", "error", err)
	}
	if err := cp.queueConnector.Server.RegisterTask("sendCheckpointToRootchain", cp.sendCheckpointToRootchain); err != nil {
		cp.Logger.Error("RegisterTasks | sendCheckpointToRootchain", "error", err)
	}
	if err := cp.queueConnector.Server.RegisterTask("sendCheckpointAckToHeimdall", cp.sendCheckpointAckToHeimdall); err != nil {
		cp.Logger.Error("RegisterTasks | sendCheckpointAckToHeimdall", "error", err)
	}
	if err := cp.queueConnector.Server.RegisterTask("sendCheckpointSyncToStakeChain", cp.sendCheckpointSyncToStakeChain); err != nil {
		cp.Logger.Error("RegisterTasks | sendCheckpointSyncToStakeChain", "error", err)
	}
	if err := cp.queueConnector.Server.RegisterTask("sendCheckpointSyncAckToHeimdall", cp.sendCheckpointSyncAckToHeimdall); err != nil {
		cp.Logger.Error("RegisterTasks | sendCheckpointSyncAckToHeimdall", "error", err)
	}
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-10-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概念
  • checkpoint 是什么
    • checkpoint 结构
      • blockHash
        • rootHash
          • 代码实现
          • 总体流程
          • Checkpoint 流程
          • Checkpoint 事件监听
            • 获取监听事件
              • 发送事件到队列
                • 处理队列的 checkpoint 事件
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档