美文网首页
Matic 数据流分析

Matic 数据流分析

作者: 雪落无留痕 | 来源:发表于2021-10-24 11:20 被阅读0次

本文主要分析Matic数据流在 Ethereum <---> Heimdall <---> Bor 中的数据流动过程。

From Ethereum to polygon

Ethereum contracts

触发depositERC20 合约函数 :

    function depositERC20(address _token, uint256 _amount) external {
        depositERC20ForUser(_token, msg.sender, _amount);
    }

调用syncState 函数:

contract StateSender {
    /**
     * Emits `stateSynced` events to start sync process on Ethereum chain
     * @param receiver    Target contract on Bor chain
     * @param data        Data to send
     */
    function syncState (
        address receiver, 
        bytes calldata data
    ) external;
}

发出 StateSynced 事件。

/**
 * Emits `stateSynced` events to start sync process on Ethereum chain
 * @param id                  State id
 * @param contractAddress     Target contract address on Bor
 * @param data                Data to send to Bor chain for Target contract address
 */
event StateSynced (
    uint256 indexed id, 
    address indexed contractAddress, 
    bytes data
);

Heimdall

初始化 clerk processor

    // initialize clerk processor
    clerkProcessor := NewClerkProcessor(&contractCaller.StateSenderABI)
    clerkProcessor.BaseProcessor = *NewBaseProcessor(cdc, queueConnector, httpClient, txBroadcaster, "clerk", clerkProcessor)

注册监听任务:

// RegisterTasks - Registers clerk related tasks with machinery
func (cp *ClerkProcessor) RegisterTasks() {
    cp.Logger.Info("Registering clerk tasks")
    if err := cp.queueConnector.Server.RegisterTask("sendStateSyncedToHeimdall", cp.sendStateSyncedToHeimdall); err != nil {
        cp.Logger.Error("RegisterTasks | sendStateSyncedToHeimdall", "error", err)
    }
}

监听收到的日志消息,签名以交易形式广播

消息类型为:

// MsgEventRecord - state msg
type MsgEventRecord struct {
    From            types.HeimdallAddress `json:"from"`
    TxHash          types.HeimdallHash    `json:"tx_hash"`
    LogIndex        uint64                `json:"log_index"`
    BlockNumber     uint64                `json:"block_number"`
    ContractAddress types.HeimdallAddress `json:"contract_address"`
    Data            types.HexBytes        `json:"data"`
    ID              uint64                `json:"id"`
    ChainID         string                `json:"bor_chain_id"`
}

然后将签名消息进行广播:

// HandleStateSyncEvent - handle state sync event from rootchain
// 1. check if this deposit event has to be broadcasted to heimdall
// 2. create and broadcast  record transaction to heimdall
func (cp *ClerkProcessor) sendStateSyncedToHeimdall(eventName string, logBytes string) error {
     // 判断deposit交易是否已经被处理  
   if isOld, _ := cp.isOldTx(cp.cliCtx, vLog.TxHash.String(), uint64(vLog.Index)); isOld {
            cp.Logger.Info("Ignoring task to send deposit to heimdall as already processed",
                "event", eventName,
                "id", event.Id,
                "contract", event.ContractAddress,
                "data", hex.EncodeToString(event.Data),
                "borChainId", chainParams.BorChainID,
                "txHash", hmTypes.BytesToHeimdallHash(vLog.TxHash.Bytes()),
                "logIndex", uint64(vLog.Index),
                "blockNumber", vLog.BlockNumber,
            )
            return nil
        }
     
        // return broadcast to heimdall
        if err := cp.txBroadcaster.BroadcastToHeimdall(msg); err != nil {
            cp.Logger.Error("Error while broadcasting clerk Record to heimdall", "error", err)
            return err
        }
}

交易处理存储

func PostHandleMsgEventRecord(ctx sdk.Context, k Keeper, msg types.MsgEventRecord, sideTxResult abci.SideTxResultType) sdk.Result {
  
  ...
  
    // save event into state
    if err := k.SetEventRecord(ctx, record); err != nil {
        k.Logger(ctx).Error("Unable to update event record", "error", err, "id", msg.ID)
        return types.ErrEventUpdate(k.Codespace()).Result()
    }
  ...
}

提供查询函数:

func handleQueryRecord(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) {
    var params types.QueryRecordParams
    if err := keeper.cdc.UnmarshalJSON(req.Data, &params); err != nil {
        return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err))
    }

    // get state record by record id
    record, err := keeper.GetEventRecord(ctx, params.RecordID)
    if err != nil {
        return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not get state record", err.Error()))
    }

    // json record
    bz, err := json.Marshal(record)
    if err != nil {
        return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error()))
    }
    return bz, nil
}

Bor

Bor 查询获取记录的消息

// CommitStates commit states
func (c *Bor) CommitStates(
    state *state.StateDB,
    header *types.Header,
    chain chainContext,
) ([]*types.StateSyncData, error) {
    stateSyncs := make([]*types.StateSyncData, 0)
    number := header.Number.Uint64()
    _lastStateID, err := c.GenesisContractsClient.LastStateId(number - 1)
    if err != nil {
        return nil, err
    }

    to := time.Unix(int64(chain.Chain.GetHeaderByNumber(number-c.config.Sprint).Time), 0)
    lastStateID := _lastStateID.Uint64()
    log.Info(
        "Fetching state updates from Heimdall",
        "fromID", lastStateID+1,
        "to", to.Format(time.RFC3339))
    eventRecords, err := c.HeimdallClient.FetchStateSyncEvents(lastStateID+1, to.Unix())  //查询事件
    if c.config.OverrideStateSyncRecords != nil {
        if val, ok := c.config.OverrideStateSyncRecords[strconv.FormatUint(number, 10)]; ok {
            eventRecords = eventRecords[0:val]
        }
    }

    chainID := c.chainConfig.ChainID.String()
    for _, eventRecord := range eventRecords {
        if eventRecord.ID <= lastStateID {
            continue
        }
        if err := validateEventRecord(eventRecord, number, to, lastStateID, chainID); err != nil {
            log.Error(err.Error())
            break
        }

        stateData := types.StateSyncData{
            ID:       eventRecord.ID,
            Contract: eventRecord.Contract,
            Data:     hex.EncodeToString(eventRecord.Data),
            TxHash:   eventRecord.TxHash,
        }
        stateSyncs = append(stateSyncs, &stateData)
    
    // 调用系统合约
        if err := c.GenesisContractsClient.CommitState(eventRecord, state, header, chain); err != nil {
            return nil, err
        }
        lastStateID++
    }
    return stateSyncs, nil
}

查询Heimdall的接口:

func (h *HeimdallClient) FetchStateSyncEvents(fromID uint64, to int64) ([]*EventRecordWithTime, error) {
    eventRecords := make([]*EventRecordWithTime, 0)
    for {
        queryParams := fmt.Sprintf("from-id=%d&to-time=%d&limit=%d", fromID, to, stateFetchLimit)
        log.Info("Fetching state sync events", "queryParams", queryParams)
        response, err := h.FetchWithRetry("clerk/event-record/list", queryParams)
        if err != nil {
            return nil, err
        }
        var _eventRecords []*EventRecordWithTime
        if response.Result == nil { // status 204
            break
        }
        if err := json.Unmarshal(response.Result, &_eventRecords); err != nil {
            return nil, err
        }
        eventRecords = append(eventRecords, _eventRecords...)
        if len(_eventRecords) < stateFetchLimit {
            break
        }
        fromID += uint64(stateFetchLimit)
    }

    sort.SliceStable(eventRecords, func(i, j int) bool {
        return eventRecords[i].ID < eventRecords[j].ID
    })
    return eventRecords, nil
}

调用系统合约:

func (gc *GenesisContractsClient) CommitState(
    event *EventRecordWithTime,
    state *state.StateDB,
    header *types.Header,
    chCtx chainContext,
) error {
    eventRecord := event.BuildEventRecord()
    recordBytes, err := rlp.EncodeToBytes(eventRecord)
    if err != nil {
        return err
    }
    method := "commitState"
    t := event.Time.Unix()
    data, err := gc.stateReceiverABI.Pack(method, big.NewInt(0).SetInt64(t), recordBytes)
    if err != nil {
        log.Error("Unable to pack tx for commitState", "error", err)
        return err
    }
    log.Info("→ committing new state", "eventRecord", event.String())
    msg := getSystemMessage(common.HexToAddress(gc.StateReceiverContract), data)
    if err := applyMessage(msg, state, header, gc.chainConfig, chCtx); err != nil {
        return err
    }
    return nil
}

最终调用ChildERC20中的deposit 函数。

    function deposit(address user, bytes calldata depositData)
        external
        override
        only(DEPOSITOR_ROLE)
    {
        uint256 amount = abi.decode(depositData, (uint256));
        _mint(user, amount);
    }

From Polygon to Ethereum

Bor

用户在Bor链上调用withdraw 函数,发起取款交易。

    /**
     * @notice called when user wants to withdraw tokens back to root chain
     * @dev Should burn user's tokens. This transaction will be verified when exiting on root chain
     * @param amount amount of tokens to withdraw
     */
    function withdraw(uint256 amount) external {
        _burn(_msgSender(), amount);
    }

Bor 提供获取checkpoint RootHash的API接口:

// GetRootHash returns the merkle root of the start to end block headers
func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
  ...
    length := uint64(end - start + 1)
    if length > MaxCheckpointLength {
        return "", &MaxCheckpointLengthExceededError{start, end}
    }

    headers := make([][32]byte, nextPowerOfTwo(length))
    for i := 0; i < len(blockHeaders); i++ {
        blockHeader := blockHeaders[i]
        header := crypto.Keccak256(appendBytes32(
            blockHeader.Number.Bytes(),
            new(big.Int).SetUint64(blockHeader.Time).Bytes(),
            blockHeader.TxHash.Bytes(),
            blockHeader.ReceiptHash.Bytes(),
        ))

        var arr [32]byte
        copy(arr[:], header)
        headers[i] = arr
    }
   
    tree := merkle.NewTreeWithOpts(merkle.TreeOptions{EnableHashSorting: false, DisableHashLeaves: true})
    if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil {
        return "", err
    }
    root := hex.EncodeToString(tree.Root().Hash)
    api.rootHashCache.Add(key, root)
    return root, nil
}

Heimdall

checkpoing 模块有三个任务:

// 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)
   }
}

sendCheckpointToHeimdall

验证者首先判断自己是否为proposer , 若是的话,检查是否需要生成checkpoint (验证bor最新固化的块和以太坊上最新固化的块数差值是256的倍数), 然后生成checkpoint交易。

// sendCheckpointToHeimdall - handles headerblock from maticchain
// 1. check if i am the proposer for next checkpoint
// 2. check if checkpoint has to be proposed for given headerblock
// 3. if so, propose checkpoint to heimdall.
func (cp *CheckpointProcessor) sendCheckpointToHeimdall(headerBlockStr string) (err error) {
  
  
    var isProposer bool
    if isProposer, err = util.IsProposer(cp.cliCtx); err != nil {
        cp.Logger.Error("Error checking isProposer in HeaderBlock handler", "error", err)
        return err
    }

    if isProposer {
        // fetch checkpoint context
        checkpointContext, err := cp.getCheckpointContext()
        if err != nil {
            return err
        }

        // process latest confirmed child block only
        chainmanagerParams := checkpointContext.ChainmanagerParams
        cp.Logger.Debug("no of checkpoint confirmations required", "maticchainTxConfirmations", chainmanagerParams.MaticchainTxConfirmations)
    
    //获取最新固化的块
        latestConfirmedChildBlock := header.Number.Uint64() - chainmanagerParams.MaticchainTxConfirmations
        if latestConfirmedChildBlock <= 0 {
            cp.Logger.Error("no of blocks on childchain is less than confirmations required", "childChainBlocks", header.Number.Uint64(), "confirmationsRequired", chainmanagerParams.MaticchainTxConfirmations)
            return errors.New("no of blocks on childchain is less than confirmations required")
        }

        expectedCheckpointState, err := cp.nextExpectedCheckpoint(checkpointContext, latestConfirmedChildBlock)
        if err != nil {
            cp.Logger.Error("Error while calculate next expected checkpoint", "error", err)
            return err
        }
        start := expectedCheckpointState.newStart
        end := expectedCheckpointState.newEnd

        //
        // Check checkpoint buffer
        //
        timeStamp := uint64(time.Now().Unix())
        checkpointBufferTime := uint64(checkpointContext.CheckpointParams.CheckpointBufferTime.Seconds())

        bufferedCheckpoint, err := util.GetBufferedCheckpoint(cp.cliCtx)
        if err != nil {
            cp.Logger.Debug("No buffered checkpoint", "bufferedCheckpoint", bufferedCheckpoint)
        }

        if bufferedCheckpoint != nil && !(bufferedCheckpoint.TimeStamp == 0 || ((timeStamp > bufferedCheckpoint.TimeStamp) && timeStamp-bufferedCheckpoint.TimeStamp >= checkpointBufferTime)) {
            cp.Logger.Info("Checkpoint already exits in buffer", "Checkpoint", bufferedCheckpoint.String())
            return nil
        }

        if err := cp.createAndSendCheckpointToHeimdall(checkpointContext, start, end); err != nil {
            cp.Logger.Error("Error sending checkpoint to heimdall", "error", err)
            return err
        }
    } else {
        cp.Logger.Info("I am not the proposer. skipping newheader", "headerNumber", header.Number)
        return
    }

    return nil
}

Heimdall 验证节点获取rootHash, 以交易的形式广播到Heimdall网络

// sendCheckpointToHeimdall - creates checkpoint msg and broadcasts to heimdall
func (cp *CheckpointProcessor) createAndSendCheckpointToHeimdall(checkpointContext *CheckpointContext, start uint64, end uint64) error {
    cp.Logger.Debug("Initiating checkpoint to Heimdall", "start", start, "end", end)

    // get checkpoint params
    checkpointParams := checkpointContext.CheckpointParams

    // Get root hash
    root, err := cp.contractConnector.GetRootHash(start, end, checkpointParams.MaxCheckpointLength)  
    if err != nil {
        return err
    }
    cp.Logger.Info("Root hash calculated", "rootHash", hmTypes.BytesToHeimdallHash(root))
    var accountRootHash hmTypes.HeimdallHash
    //Get DividendAccountRoot from HeimdallServer
    if accountRootHash, err = cp.fetchDividendAccountRoot(); err != nil {
        cp.Logger.Info("Error while fetching initial account root hash from HeimdallServer", "err", err)
        return err
    }

    chainParams := checkpointContext.ChainmanagerParams.ChainParams

    // create and send checkpoint message
    msg := checkpointTypes.NewMsgCheckpointBlock(
        hmTypes.BytesToHeimdallAddress(helper.GetAddress()),
        start,
        end,
        hmTypes.BytesToHeimdallHash(root),
        accountRootHash,
        chainParams.BorChainID,
    )

    // return broadcast to heimdall
    if err := cp.txBroadcaster.BroadcastToHeimdall(msg); err != nil {
        cp.Logger.Error("Error while broadcasting checkpoint to heimdall", "error", err)
        return err
    }

    return nil
}

sendCheckpointToRootchain

验证节点会轮循 Heimdall 区块 checkpoint 事件:

// 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)
    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:   // 检查checkpoint事件
        hl.sendBlockTask("sendCheckpointToRootchain", eventBytes, blockHeight)
    case slashingTypes.EventTypeSlashLimit:
        hl.sendBlockTask("sendTickToHeimdall", eventBytes, blockHeight)
    case slashingTypes.EventTypeTickConfirm:
        hl.sendBlockTask("sendTickToRootchain", eventBytes, blockHeight)
    default:
        hl.Logger.Debug("BlockEvent Type mismatch", "eventType", event.Type)
    }
}

对于checkpoing 事件,执行sendCheckpointToRootchain任务,判断自己是否为proposer,并且是否应该提交checkpoint (根据event 和rootchain上一个checkpoing 块号判断),然后向以太坊链上提交checkpoint

// sendCheckpointToRootchain - handles checkpoint confirmation event from heimdall.
// 1. check if i am the current proposer.
// 2. check if this checkpoint has to be submitted to rootchain
// 3. if so, create and broadcast checkpoint transaction to rootchain
func (cp *CheckpointProcessor) sendCheckpointToRootchain(eventBytes string, blockHeight int64) error {

    cp.Logger.Info("Received sendCheckpointToRootchain request", "eventBytes", eventBytes, "blockHeight", blockHeight)
    var event = sdk.StringEvent{}
    if err := json.Unmarshal([]byte(eventBytes), &event); err != nil {
        cp.Logger.Error("Error unmarshalling event from heimdall", "error", err)
        return err
    }

    // var tx = sdk.TxResponse{}
    // if err := json.Unmarshal([]byte(txBytes), &tx); err != nil {
    //  cp.Logger.Error("Error unmarshalling txResponse", "error", err)
    //  return err
    // }

    cp.Logger.Info("processing checkpoint confirmation event", "eventtype", event.Type)
    isCurrentProposer, err := util.IsCurrentProposer(cp.cliCtx)
    if err != nil {
        cp.Logger.Error("Error checking isCurrentProposer in CheckpointConfirmation handler", "error", err)
        return err
    }

    var startBlock uint64
    var endBlock uint64
    var txHash string

    for _, attr := range event.Attributes {
        if attr.Key == checkpointTypes.AttributeKeyStartBlock {
            startBlock, _ = strconv.ParseUint(attr.Value, 10, 64)
        }
        if attr.Key == checkpointTypes.AttributeKeyEndBlock {
            endBlock, _ = strconv.ParseUint(attr.Value, 10, 64)
        }
        if attr.Key == hmTypes.AttributeKeyTxHash {
            txHash = attr.Value
        }
    }

    checkpointContext, err := cp.getCheckpointContext()
    if err != nil {
        return err
    }

    shouldSend, err := cp.shouldSendCheckpoint(checkpointContext, startBlock, endBlock)
    if err != nil {
        return err
    }

    if shouldSend && isCurrentProposer {
        txHash := common.FromHex(txHash)
        if err := cp.createAndSendCheckpointToRootchain(checkpointContext, startBlock, endBlock, blockHeight, txHash); err != nil {
            cp.Logger.Error("Error sending checkpoint to rootchain", "error", err)
            return err
        }
    } else {
        cp.Logger.Info("I am not the current proposer or checkpoint already sent. Ignoring", "eventType", event.Type)
        return nil
    }
    return nil
}

createAndSendCheckpointToRootchain 会收集签名,然后调用链上合约。

// createAndSendCheckpointToRootchain prepares the data required for rootchain checkpoint submission
// and sends a transaction to rootchain
func (cp *CheckpointProcessor) createAndSendCheckpointToRootchain(checkpointContext *CheckpointContext, start uint64, end uint64, height int64, txHash []byte) error {
  
  ....
  
    // get sigs
    sigs, err := helper.FetchSideTxSigs(cp.httpClient, height, tx.Tx.Hash(), sideTxData)  // 收集签名
    if err != nil {
        cp.Logger.Error("Error fetching votes for checkpoint tx", "height", height)
        return err
    }

    shouldSend, err := cp.shouldSendCheckpoint(checkpointContext, start, end)
    if err != nil {
        return err
    }

    if shouldSend {
        // chain manager params
        chainParams := checkpointContext.ChainmanagerParams.ChainParams
        // root chain address
        rootChainAddress := chainParams.RootChainAddress.EthAddress()
        // root chain instance
        rootChainInstance, err := cp.contractConnector.GetRootChainInstance(rootChainAddress)
        if err != nil {
            cp.Logger.Info("Error while creating rootchain instance", "error", err)
            return err
        }
    
    // 调用以太坊上合约
        if err := cp.contractConnector.SendCheckpoint(sideTxData, sigs, rootChainAddress, rootChainInstance); err != nil {
            cp.Logger.Info("Error submitting checkpoint to rootchain", "error", err)
            return err
        }
    }

    return nil
}

签名来源于投票vote中, 其包含于block中:

// Vote represents a prevote, precommit, or commit vote from validators for
// consensus.
type Vote struct {
    Type             SignedMsgType `json:"type"`
    Height           int64         `json:"height"`
    Round            int           `json:"round"`
    BlockID          BlockID       `json:"block_id"` // zero if vote is nil.
    Timestamp        time.Time     `json:"timestamp"`
    ValidatorAddress Address       `json:"validator_address"`
    ValidatorIndex   int           `json:"validator_index"`
    Signature        []byte        `json:"signature"`

    SideTxResults []SideTxResult `json:"side_tx_results"` // side-tx result [peppermint]
}

// SideTxResult side tx result for vote
type SideTxResult struct {
    TxHash []byte `json:"tx_hash"`
    Result int32  `json:"result"`
    Sig    []byte `json:"sig"`      //收集的签名
}

以太坊上合约触发:

// Solidity: function submitCheckpoint(bytes data, uint256[3][] sigs) returns()
func (_Rootchain *RootchainTransactor) SubmitCheckpoint(opts *bind.TransactOpts, data []byte, sigs [][3]*big.Int) (*types.Transaction, error) {
    return _Rootchain.contract.Transact(opts, "submitCheckpoint", data, sigs)
}

Ethereum

用户构建blockproof 燃烧证明

  async submitCheckpoint(rootChain, receipt, proposer) {
    const event = {
      tx: await web3Child.eth.getTransaction(receipt.transactionHash),
      receipt: await web3Child.eth.getTransactionReceipt(
        receipt.transactionHash
      ),
      block: await web3Child.eth.getBlock(
        receipt.blockHash,
        true /* returnTransactionObjects */
      )
    }

    // rootChain expects the first checkpoint to start from block 0.
    // However, ganache would already be running and would be much ahead of block 0.
    // offset is used to treat the block of the first checkpoint to be 0
    if (this.offset == null) {
      this.offset = event.block.number
    }
    event.block.number -= this.offset // rootChain will thank you for this
    const start = this.lastEndBlock + 1
    const end = event.block.number
    this.lastEndBlock = end
    if (start > end) {
      throw new Error(`Invalid end block number for checkpoint`, { start, end });
    }

    const headers = []
    for (let i = start; i <= end; i++) {
      const block = await web3Child.eth.getBlock(i + this.offset)
      block.number = i
      headers.push(getBlockHeader(block))
    }
    const blockHeader = getBlockHeader(event.block)
    const tree = new MerkleTree(headers)
    const root = ethUtils.bufferToHex(tree.getRoot())
    const blockProof = await tree.getProof(blockHeader)  // 获取blockproof
    // tree
    //   .verify(blockHeader, end - start, tree.getRoot(), blockProof)
    //   .should.equal(true)
    const { data, sigs } = utils.buildsubmitCheckpointPaylod(
      proposer[0],
      start,
      end,
      root,
      proposer,
      { rewardsRootHash: ethUtils.keccak256('RandomState') }
    )
    const submitCheckpoint = await rootChain.submitCheckpoint(
      data, sigs)

    // const txProof = await getTxProof(event.tx, event.block)
    // assert.isTrue(verifyTxProof(txProof), 'Tx proof must be valid (failed in js)')
    // const receiptProof = await getReceiptProof(event.receipt, event.block, web3Child)
    // assert.isTrue(verifyReceiptProof(receiptProof), 'Receipt proof must be valid (failed in js)')

    const NewHeaderBlockEvent = submitCheckpoint.logs.find(
      log => log.event === 'NewHeaderBlock'
    )
    return {
      block: event.block,
      blockProof,
      headerNumber: NewHeaderBlockEvent.args.headerBlockId,
      createdAt: (await rootChain.headerBlocks(
        NewHeaderBlockEvent.args.headerBlockId
      )).createdAt,
      reference: await build(event)
    }
  }

调用以太坊上Exit函数 :

function startExitWithBurntTokens(bytes calldata data) external {
    RLPReader.RLPItem[] memory referenceTxData = data.toRlpItem().toList();
    bytes memory receipt = referenceTxData[6].toBytes();
    RLPReader.RLPItem[] memory inputItems = receipt.toRlpItem().toList();
    uint256 logIndex = referenceTxData[9].toUint();
    require(logIndex < MAX_LOGS, "Supporting a max of 10 logs");
    uint256 age = withdrawManager.verifyInclusion(         // Merkle 路径验证
        data,
        0, /* offset */
        false /* verifyTxInclusion */
    );
    inputItems = inputItems[3].toList()[logIndex].toList(); // select log based on given logIndex

    // "address" (contract address that emitted the log) field in the receipt
    address childToken = RLPReader.toAddress(inputItems[0]);
    bytes memory logData = inputItems[2].toBytes();
    inputItems = inputItems[1].toList(); // topics
    // now, inputItems[i] refers to i-th (0-based) topic in the topics array
    // event Withdraw(address indexed token, address indexed from, uint256 amountOrTokenId, uint256 input1, uint256 output1)
    require(
        bytes32(inputItems[0].toUint()) == WITHDRAW_EVENT_SIG,
        "Not a withdraw event signature"
    );
    address rootToken = address(RLPReader.toUint(inputItems[1]));
    require(
        msg.sender == address(inputItems[2].toUint()), // from
        "Withdrawer and burn exit tx do not match"
    );
    uint256 exitAmount = BytesLib.toUint(logData, 0); // amountOrTokenId
    withdrawManager.addExitToQueue(
        msg.sender,
        childToken,
        rootToken,
        exitAmount,
        bytes32(0x0),
        true, /* isRegularExit */
        age << 1
    );
}

最终退出调用合约processExiits函数:

    function processExits(address _token) public {
        uint256 exitableAt;
        uint256 exitId;

        PriorityQueue exitQueue = PriorityQueue(exitsQueues[_token]);

        while (exitQueue.currentSize() > 0 && gasleft() > ON_FINALIZE_GAS_LIMIT) {
            (exitableAt, exitId) = exitQueue.getMin();
            exitId = (exitableAt << 128) | exitId;
            PlasmaExit memory currentExit = exits[exitId];

            // Stop processing exits if the exit that is next is queue is still in its challenge period
            if (exitableAt > block.timestamp) return;

            exitQueue.delMin();
            // If the exitNft was deleted as a result of a challenge, skip processing this exit
            if (!exitNft.exists(exitId)) continue;
            address exitor = exitNft.ownerOf(exitId);
            exits[exitId].owner = exitor;
            exitNft.burn(exitId);
            // If finalizing a particular exit is reverting, it will block any following exits from being processed.
            // Hence, call predicate.onFinalizeExit in a revertless manner.
            // (bool success, bytes memory result) =
            currentExit.predicate.call(
                abi.encodeWithSignature("onFinalizeExit(bytes)", encodeExitForProcessExit(exitId))  //最终退出
            );

            emit Withdraw(exitId, exitor, _token, currentExit.receiptAmountOrNFTId);

            if (!currentExit.isRegularExit) {
                // return the bond amount if this was a MoreVp style exit
                address(uint160(exitor)).send(BOND_AMOUNT);
            }
        }
    }

参考

https://github.com/maticnetwork

相关文章

网友评论

      本文标题:Matic 数据流分析

      本文链接:https://www.haomeiwen.com/subject/xwpjaltx.html