go-fil-markets
go-fil-markets copied to clipboard
Mismatch in proposal CIDs
Im getting different deal proposal CIDs between what im sending to the miner and what i get back in the deal response.
I construct and sign my market.ClientDealProposal and then send it to the miner. I also call .Cid() on it to get the proposal cid for local indexing. However, when i get the response back from the miner resp.Response.Proposal is a different value.
Something seems wrong here, and its possible im doing something wrong, but im just calling the provided methods on the exact objects im writing over the wire to the miner. Seems fishy.
Same problem but in a different direction, If i request the deal status using the proposal CID, then call .Cid() on resp.Proposal.Cid() gives a different value
The reason there is a difference between the cids is that when you call proposal.Cid() it's calculated in one way in specs-actors: https://github.com/filecoin-project/specs-actors/blob/7f44654d2f07d08178f2aa034e5354db49656edf/actors/builtin/market/deal.go#L73-L79
However resp.Response.Proposal is calculated differently in go-fil-markets:
https://github.com/filecoin-project/go-fil-markets/blob/d5b199009d48846981c791605db1f6fa8d644f65/storagemarket/impl/provider.go#L227-L254
Also proposal.Cid() is calculated on DealProposal and resp.Response.Proposal is calculated over the signed DealProposal
Is there any reason why proposal.Cid() should exist then? Its a pretty massive footgun there for someone who is looking for the proposal cid to ask a miner about.
Hey, jumping to mention something related that I experienced some time ago. It isn't really a problem that we're suffering now, but just related to all this as an anecdote.
In Powergate, we use the cid.Cid returned by ClientStartDeal as a temporary identifier of the proposal being tracked. Also, to call future ClientGetDealInfo, etc, which require this cid.Cid.
Some months ago, that I don't recall what I was doing, I realized that that proposal-cid is something local to the node, not something global. And I realized a fact that is quite related to all this.
I was digging if I could reconstruct that ProposalCid from a call to StateMarketStorageDeal, which returns:
type MarketDeal struct {
Proposal market.DealProposal
State market.DealState
}
The "problem" here is that market.DealProposal is an unsigned proposal, so it's Cid didn't match that cid.Cid that was returned in ClientStartDeal.
Digging a bit more, the cid.Cid returned by ClientStartDeal comes from go-fil-markets, in particular:
dealProposal := market.DealProposal{
PieceCID: commP,
PieceSize: pieceSize.Padded(),
Client: params.Addr,
Provider: params.Info.Address,
Label: label,
StartEpoch: params.StartEpoch,
EndEpoch: params.EndEpoch,
StoragePricePerEpoch: params.Price,
ProviderCollateral: pcMin,
ClientCollateral: big.Zero(),
VerifiedDeal: params.VerifiedDeal,
}
clientDealProposal, err := c.node.SignProposal(ctx, params.Addr, dealProposal)
if err != nil {
return nil, xerrors.Errorf("signing deal proposal failed: %w", err)
}
proposalNd, err := cborutil.AsIpld(clientDealProposal)
if err != nil {
return nil, xerrors.Errorf("getting proposal node failed: %w", err)
}
deal := &storagemarket.ClientDeal{
ProposalCid: proposalNd.Cid(),
ClientDealProposal: *clientDealProposal,
State: storagemarket.StorageDealUnknown,
Miner: params.Info.PeerID,
MinerWorker: params.Info.Worker,
DataRef: params.Data,
FastRetrieval: params.FastRetrieval,
StoreID: params.StoreID,
CreationTime: curTime(),
}
So basically, the ProposalCID returned by ClientStartDeal is the Proposal only signed by the client.
This means that to transform the unsigned Proposal returned by StateMarketStorageDeal to the one that was returned by the previous call to ClientStartDeal, I'd have to have the key and sign it, and in theory I'd guess they should match.
Anyway, I got out of that being a problem afterward. But I think I fall in the same trap of comparing Cids of proposals that were unsigned vs partially signed.