网络中收到跨链交易后,将交易转发给矿工模块。
if ev, ok := ev.Data.(core.NewOtherTxsEvent); ok { for _, tx := range ev.Txs { if w.insertCM(tx) && !request { request = true w.requestCrossTxProof(tx.Hash()) } } }
矿工将交易插入缓存并去重,调用请求收据proof证明。
BestPeer请求证明
请求证明的过程涉及到找哪一个Peer请求数据的流程
if ev, ok := obj.Data.(core.NewRequestTxProofEvent); ok { peer := pm.peersOther.BestPeer() if peer != nil { peer.RequestMMRReceipts([]common.Hash{ev.TxHash}) } }
通过寻找难度最高的节点请求数据是最好的,如果难度最高的节点验证失败,找次之节点继续验证
对链Hash通知
本链每个区块的Hash和难度都会通过NewOtherBlockHashesMsg
广播到对链,这样对链有了一个缓存本链哪个Peer的区块是最新的机制。
MMR第二次请求
当节点收到GetMMRReceiptProofMsg
消息,为对链查询跨链消息的证明。
case msg.Code == GetMMRReceiptProofMsg: var query getBlockMMRData if err := msg.Decode(&query) var mtProof ulvp.SimpleUlvpProof receiptRep, receipt, err := pm.ulVP.GetReceiptProof(query.TxHash) data, err := pm.ulVP.HandleSimpleUlvpMsgReq(pm.ulVP.GetSimpleUlvpMsgReq([]uint64{receipt.BlockNumber.Uint64(), pm.blockchain.CurrentBlock().NumberU64()})) mtProof.Result = true mtProof.ReceiptProof = receiptRep mtProof.ChainProof = &ulvp.UlvpChainProof{Res: data} mtProof.Header = pm.blockchain.GetHeaderByHash(receipt.BlockHash) mtProof.End = pm.blockchain.CurrentBlock().Number() mtProof.TxHash = query.TxHash
首先拿到对链请求的Txhash
,查找此交易收据是否存在,生成收据的proof证明。
func (uv *SimpleULVP) GetReceiptProof(txHash common.Hash) (*ulvp.ReceiptTrieResps, *types.Receipt, error) { lookup := uv.localChain.GetTransactionLookup(txHash) receipts := uv.localChain.GetReceiptsByHash(lookup.BlockHash) tri := types.DeriveShaHasher(receipts, new(trie.Trie)) keybuf := new(bytes.Buffer) keybuf.Reset() rlp.Encode(keybuf, lookup.Index) proofs := types.NewNodeSet() tri.Prove(keybuf.Bytes(), 0, proofs) return &ulvp.ReceiptTrieResps{Proofs: proofs.NodeList(), Index: lookup.Index, ReceiptHash: block.ReceiptHash()}, receipt, nil }
根据交易所在高度生成MMR证明,由于高度发生改变,需要重新采样,故此时需要新的MMR证明。
data, err := pm.ulVP.HandleSimpleUlvpMsgReq(pm.ulVP.GetSimpleUlvpMsgReq([]uint64{receipt.BlockNumber.Uint64(), pm.blockchain.CurrentBlock().NumberU64()}))
将收据所在高度和当前区块的高度传进去生成证明。将两个证明拼在一起发给对方节点。
节点收据校验
节点收到验证数据,验证MMR和收据证明是否正确,校验失败将把本peer踢掉,然后通知矿工从新请求。
case msg.Code == MMRReceiptProofMsg: var request *ulvp.SimpleUlvpProof if err := msg.Decode(&request); err != nil { return errResp(ErrDecode, "%v: %v", msg, err) } find := false if !request.Result { find = true } else if _, err := request.VerifyULVPTXMsg(request.TxHash); err != nil { find = true } if find { pm.removeOtherPeer(p.id) request.Result = false } pm.eventMux.Post(core.NewProofEvent{MRProof: request})
如果验证成功,矿工需要转换跨链为新的铸币交易,这部分在下篇继续梳理。目前已把节点证明和收据证明梳理完。
Mouse和Duck跨链github链接
感兴趣的朋友欢迎一起讨论。