精通Filecoin:Lotus真实数据处理之Client处理存储

巴比特 view 45214 2020-7-28 11:11
share to
Scan QR code with WeChat

接上文:《精通 Filecoin:Lotus 真实数据处理之 Client 初始化》

客户端发起交易之后,最终调用 Lotus(Client)API 的 ClientStartDeal 方法对交易进行处理。这个方法最终调用 Client 对象的 ProposeStorageDeal 方法处理交易:

result, err := a.SMDealClient.ProposeStorageDeal(     ctx,     params.Walle   &providerInfo,     params.Data,    // 包含了客户端的数据     dealStart,     calcDealExpiration(params.MinBlocksDuration, md, dealStart),     params.EpochPrice,     big.Zero(),     rt,     params.FastRetrieval,     params.VerifiedDeal, )

Client 对象的 ProposeStorageDeal 方法处理如下:

计算客户数据的 commP。

commP, pieceSize, err := clientutils.CommP(ctx, c.pio, rt, data)

检查数据的大小。如果不符合,则直接返回。

创建交易提案对象。

dealProposal := market.DealProposal{     PieceCID:             commP,     PieceSize:            pieceSize.Padded(),     Client:               addr,     Provider:             info.Address,     StartEpoch:           startEpoch,     EndEpoch:             endEpoch,     StoragePricePerEpoch: price,     ProviderCollateral:   abi.NewTokenAmount(int64(pieceSize)), // TODO: real calc     ClientCollateral:     big.Zero(),     VerifiedDeal:         verifiedDeal, }

对交易提案进行签名。

clientDealProposal, err := c.node.SignProposal(ctx, addr, dealProposal)

把交易提案转化为 ipld 节点对象。

proposalNd, err := cborutil.AsIpld(clientDealProposal)

创建客户端交易对象。

deal := &storagemarket.ClientDeal{     ProposalCid:        proposalNd.Cid(),     ClientDealProposal: *clientDealProposal,     State:              storagemarket.StorageDealUnknown,     Miner:              info.PeerID,     MinerWorker:        info.Worker,     DataRef:            data,     FastRetrieval:      fastRetrieval, }

调用 fsm 状态组的  的方法,生成一个状态机,并开始跟踪客户端交易对象。

err = c.statemachines.Begin(proposalNd.Cid(), deal)

向 fsm 状态组发送  事件。

err = c.statemachines.Send(deal.ProposalCid, storagemarket.ClientEventOpen)

当状态机收到这个事件后,因为初始状态为默认值 0,即 ,事件处理器对象经过内部处理把状态从  修改为 ,从而调用其处理函数  确定是否接收交易。

返回结果。

return &storagemarket.ProposeStorageDealResult{         ProposalCid: deal.ProposalCid,     }, c.discovery.AddPeer(data.Root, retrievalmarket.RetrievalPeer{         Address:  dealProposal.Provider,         ID:       deal.Miner,         PieceCID: &commP,     })

1、`EnsureClientFunds` 函数

这个函数用来确认客户端有足够的资金来开始交易提案。

这个函数的执行如下:

获取客户适配器对象。

node := environment.Node()

获取区块链最顶端 tipset 对应的 tipset key 和 tipset 的高度。

tok, _, err := node.GetChainHead(ctx.Context())

确认客户端有足够多的资金来进行交易。

mcid, err := node.EnsureFunds(ctx.Context(), deal.Proposal.Client, deal.Proposal.Client, deal.Proposal.ClientBalanceRequirement(), tok)

EnsureFunds 方法在确认客户资金过程中,会调用 market Actor 对象的 AddBalance 方法进行处理。

如果客户有足够多的资金,则调用 fsm 上下文对象的 Trigger 方法,通过事件处理器生成一个事件对象,然后发送事件对象到状态机。此处生成的事件对象名称为 ClientEventFundsEnsured

if mcid == cid.Undef {     return ctx.Trigger(storagemarket.ClientEventFundsEnsured) }

当状态机收到这个事件后,经过事件处理器把状态从 StorageDealEnsureClientFunds 修改为 StorageDealFundsEnsured,从而调用其处理函数 ProposeDeal 处理提议的交易。

2、`ProposeDeal` 函数

这个函数处理提议的交易,把交易发送给 provider 对象。

生成交易提议对象。

proposal := network.Proposal{     DealProposal:  &deal.ClientDealProposal,     Piece:         deal.DataRef,     FastRetrieval: deal.FastRetrieval, }

创建一个到矿工的交易流。

s, err := environment.NewDealStream(ctx.Context(), deal.Miner)

客户环境对象的  方法直接底层网络对象()的同名方法进行处理。后者以指定的协议创建到指定矿工的流,并返回包装之后的流对象。包装之后的流对象是  对象(storagemarket/network/deal_stream.go)。

当存储矿工收到这个请求后,使用自身的  方法处理处理这个流。在这个方法中对流进行简单包装,然后调用矿工对象的  方法处理客户交易。

通过流把交易提案提交到矿工。

err := s.WriteDealProposal(proposal);

这个过程会把交易提案对象转化为 cbor 编码的对象。

读取流返回的响应对象。

resp, err := s.ReadDealResponse()

等待矿工确定是否接收交易。结果是矿工签名的消息。内容如下:

network.Response{     State:    storagemarket.StorageDealWaitingForData,     Proposal: deal.ProposalCid, }

关闭流。

err = s.Close()

获取当前链顶部相关信息。

tok, _, err := environment.Node().GetChainHead(ctx.Context())

验证矿工返回的响应。

err := clientutils.VerifyResponse(ctx.Context(), resp, deal.MinerWorker, tok, environment.Node().VerifySignature);

如果响应状态不是等待数据,则发送  事件。

if resp.Response.State != storagemarket.StorageDealWaitingForData {     return ctx.Trigger(storagemarket.ClientEventUnexpectedDealState, resp.Response.State, resp.Response.Message) }

发送初始化数据传输事件。

return ctx.Trigger(storagemarket.ClientEventInitiateDataTransfer)

当状态机收到这个事件后,经过事件处理器把状态从  修改为 ,从而调用其处理函数  处理提议的交易。

3、`InitiateDataTransfer` 函数

初始化数据传输。

btcfans公众号

Scan QR code with WeChat

Disclaimer:

Previous: 区块链正推动着“信息互联网”向“价值互联网”变革 Next: 黄金白银连创新高,数字货币集体“躁动” ,比特币价格升破1.1万美元

Related