Skip to content

Commit

Permalink
Support retrieval UnsealPrice (#325) (#330)
Browse files Browse the repository at this point in the history
* WIP

* Make selector required for retrieval deal params V1

* Add provider states for unsealing funds

* Fix up channel tracking and payment flow for unsealing
  • Loading branch information
ingar authored Jul 23, 2020
1 parent 026a533 commit cb4181f
Show file tree
Hide file tree
Showing 26 changed files with 262 additions and 122 deletions.
101 changes: 51 additions & 50 deletions docs/retrievalclient.mmd
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@ stateDiagram-v2
state "DealStatusPaymentChannelCreating" as 4
state "DealStatusPaymentChannelAddingFunds" as 5
state "DealStatusAccepted" as 6
state "DealStatusFailed" as 7
state "DealStatusRejected" as 8
state "DealStatusFundsNeeded" as 9
state "DealStatusSendFunds" as 10
state "DealStatusSendFundsLastPayment" as 11
state "DealStatusOngoing" as 12
state "DealStatusFundsNeededLastPayment" as 13
state "DealStatusCompleted" as 14
state "DealStatusDealNotFound" as 15
state "DealStatusErrored" as 16
state "DealStatusBlocksComplete" as 17
state "DealStatusFinalizing" as 18
state "DealStatusFailed" as 8
state "DealStatusRejected" as 9
state "DealStatusFundsNeeded" as 10
state "DealStatusSendFunds" as 11
state "DealStatusSendFundsLastPayment" as 12
state "DealStatusOngoing" as 13
state "DealStatusFundsNeededLastPayment" as 14
state "DealStatusCompleted" as 15
state "DealStatusDealNotFound" as 16
state "DealStatusErrored" as 17
state "DealStatusBlocksComplete" as 18
state "DealStatusFinalizing" as 19
0 : On entry runs ProposeDeal
4 : On entry runs WaitForPaymentChannelCreate
5 : On entry runs WaitForPaymentChannelAddFunds
6 : On entry runs SetupPaymentChannelStart
7 : On entry runs CancelDeal
9 : On entry runs ProcessPaymentRequested
10 : On entry runs SendFunds
8 : On entry runs CancelDeal
10 : On entry runs ProcessPaymentRequested
11 : On entry runs SendFunds
12 : On entry runs Ongoing
13 : On entry runs ProcessPaymentRequested
12 : On entry runs SendFunds
13 : On entry runs Ongoing
14 : On entry runs ProcessPaymentRequested
[*] --> 0
note right of 0
The following events are not shown cause they can trigger from any state.
Expand All @@ -37,43 +37,44 @@ stateDiagram-v2
end note
0 --> 0 : ClientEventOpen
0 --> 3 : ClientEventDealProposed
3 --> 8 : ClientEventDealRejected
3 --> 15 : ClientEventDealNotFound
3 --> 9 : ClientEventDealRejected
3 --> 16 : ClientEventDealNotFound
3 --> 6 : ClientEventDealAccepted
4 --> 7 : ClientEventPaymentChannelErrored
6 --> 7 : ClientEventPaymentChannelErrored
4 --> 8 : ClientEventPaymentChannelErrored
6 --> 8 : ClientEventPaymentChannelErrored
6 --> 4 : ClientEventPaymentChannelCreateInitiated
6 --> 5 : ClientEventPaymentChannelAddingFunds
4 --> 12 : ClientEventPaymentChannelReady
5 --> 12 : ClientEventPaymentChannelReady
4 --> 7 : ClientEventAllocateLaneErrored
5 --> 7 : ClientEventAllocateLaneErrored
5 --> 7 : ClientEventPaymentChannelAddFundsErrored
9 --> 13 : ClientEventLastPaymentRequested
12 --> 13 : ClientEventLastPaymentRequested
13 --> 13 : ClientEventLastPaymentRequested
17 --> 11 : ClientEventLastPaymentRequested
9 --> 9 : ClientEventPaymentRequested
12 --> 9 : ClientEventPaymentRequested
17 --> 9 : ClientEventPaymentRequested
12 --> 17 : ClientEventAllBlocksReceived
13 --> 11 : ClientEventAllBlocksReceived
17 --> 17 : ClientEventAllBlocksReceived
9 --> 9 : ClientEventBlocksReceived
12 --> 12 : ClientEventBlocksReceived
4 --> 13 : ClientEventPaymentChannelReady
5 --> 13 : ClientEventPaymentChannelReady
4 --> 8 : ClientEventAllocateLaneErrored
5 --> 8 : ClientEventAllocateLaneErrored
5 --> 8 : ClientEventPaymentChannelAddFundsErrored
10 --> 14 : ClientEventLastPaymentRequested
13 --> 14 : ClientEventLastPaymentRequested
14 --> 14 : ClientEventLastPaymentRequested
18 --> 12 : ClientEventLastPaymentRequested
10 --> 10 : ClientEventPaymentRequested
13 --> 10 : ClientEventPaymentRequested
18 --> 10 : ClientEventPaymentRequested
3 --> 6 : ClientEventUnsealPaymentRequested
13 --> 18 : ClientEventAllBlocksReceived
14 --> 12 : ClientEventAllBlocksReceived
18 --> 18 : ClientEventAllBlocksReceived
10 --> 10 : ClientEventBlocksReceived
13 --> 13 : ClientEventBlocksReceived
9 --> 10 : ClientEventSendFunds
13 --> 11 : ClientEventSendFunds
10 --> 7 : ClientEventFundsExpended
11 --> 7 : ClientEventFundsExpended
10 --> 7 : ClientEventBadPaymentRequested
11 --> 7 : ClientEventBadPaymentRequested
10 --> 7 : ClientEventCreateVoucherFailed
11 --> 7 : ClientEventCreateVoucherFailed
10 --> 12 : ClientEventPaymentSent
11 --> 18 : ClientEventPaymentSent
18 --> 14 : ClientEventComplete
7 --> 16 : <invalid Value>
14 --> 14 : ClientEventBlocksReceived
10 --> 11 : ClientEventSendFunds
14 --> 12 : ClientEventSendFunds
11 --> 8 : ClientEventFundsExpended
12 --> 8 : ClientEventFundsExpended
11 --> 8 : ClientEventBadPaymentRequested
12 --> 8 : ClientEventBadPaymentRequested
11 --> 8 : ClientEventCreateVoucherFailed
12 --> 8 : ClientEventCreateVoucherFailed
11 --> 13 : ClientEventPaymentSent
12 --> 19 : ClientEventPaymentSent
19 --> 15 : ClientEventComplete
8 --> 17 : <invalid Value>

note left of 3 : The following events only record in this state.<br><br>ClientEventLastPaymentRequested<br>ClientEventPaymentRequested<br>ClientEventAllBlocksReceived<br>ClientEventBlocksReceived

Expand Down
Binary file modified docs/retrievalclient.mmd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions docs/retrievalclient.mmd.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 32 additions & 26 deletions docs/retrievalprovider.mmd
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ stateDiagram-v2
state "DealStatusNew" as 0
state "DealStatusUnsealing" as 1
state "DealStatusUnsealed" as 2
state "DealStatusFailed" as 7
state "DealStatusFundsNeeded" as 9
state "DealStatusOngoing" as 12
state "DealStatusFundsNeededLastPayment" as 13
state "DealStatusCompleted" as 14
state "DealStatusErrored" as 16
state "DealStatusBlocksComplete" as 17
state "DealStatusFinalizing" as 18
state "DealStatusCompleting" as 19
state "DealStatusFundsNeededUnseal" as 7
state "DealStatusFailed" as 8
state "DealStatusFundsNeeded" as 10
state "DealStatusOngoing" as 13
state "DealStatusFundsNeededLastPayment" as 14
state "DealStatusCompleted" as 15
state "DealStatusErrored" as 17
state "DealStatusBlocksComplete" as 18
state "DealStatusFinalizing" as 19
state "DealStatusCompleting" as 20
1 : On entry runs UnsealData
2 : On entry runs UnpauseDeal
7 : On entry runs CancelDeal
19 : On entry runs CleanupDeal
7 : On entry runs TrackTransfer
8 : On entry runs CancelDeal
20 : On entry runs CleanupDeal
[*] --> 0
note right of 0
The following events are not shown cause they can trigger from any state.
Expand All @@ -23,19 +25,23 @@ stateDiagram-v2
end note
0 --> 0 : ProviderEventOpen
0 --> 1 : ProviderEventDealAccepted
1 --> 7 : ProviderEventUnsealError
7 --> 7 : ProviderEventDealAccepted
1 --> 8 : ProviderEventUnsealError
1 --> 2 : ProviderEventUnsealComplete
2 --> 12 : ProviderEventBlockSent
12 --> 12 : ProviderEventBlockSent
12 --> 17 : ProviderEventBlocksCompleted
12 --> 9 : ProviderEventPaymentRequested
17 --> 13 : ProviderEventPaymentRequested
9 --> 7 : ProviderEventSaveVoucherFailed
13 --> 7 : ProviderEventSaveVoucherFailed
9 --> 9 : ProviderEventPartialPaymentReceived
13 --> 13 : ProviderEventPartialPaymentReceived
9 --> 12 : ProviderEventPaymentReceived
13 --> 18 : ProviderEventPaymentReceived
18 --> 19 : ProviderEventComplete
19 --> 14 : ProviderEventCleanupComplete
7 --> 16 : ProviderEventCancelComplete
2 --> 13 : ProviderEventBlockSent
13 --> 13 : ProviderEventBlockSent
13 --> 18 : ProviderEventBlocksCompleted
0 --> 7 : ProviderEventPaymentRequested
2 --> 10 : ProviderEventPaymentRequested
13 --> 10 : ProviderEventPaymentRequested
18 --> 14 : ProviderEventPaymentRequested
10 --> 8 : ProviderEventSaveVoucherFailed
14 --> 8 : ProviderEventSaveVoucherFailed
10 --> 10 : ProviderEventPartialPaymentReceived
14 --> 14 : ProviderEventPartialPaymentReceived
7 --> 1 : ProviderEventPaymentReceived
10 --> 13 : ProviderEventPaymentReceived
14 --> 19 : ProviderEventPaymentReceived
19 --> 20 : ProviderEventComplete
20 --> 15 : ProviderEventCleanupComplete
8 --> 17 : ProviderEventCancelComplete
Binary file modified docs/retrievalprovider.mmd.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions docs/retrievalprovider.mmd.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions retrievalmarket/dealstatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ const (
// and its is ready to proceed with retrieval
DealStatusAccepted

// DealStatusFundsNeededUnseal means a deal has been accepted by a provider
// and payment is needed to unseal the data
DealStatusFundsNeededUnseal

// DealStatusFailing indicates something went wrong during a retrieval,
// and we are cleaning up before termianting with an error
DealStatusFailing
Expand Down Expand Up @@ -86,6 +90,7 @@ var DealStatuses = map[DealStatus]string{
DealStatusPaymentChannelCreating: "DealStatusPaymentChannelCreating",
DealStatusPaymentChannelAddingFunds: "DealStatusPaymentChannelAddingFunds",
DealStatusAccepted: "DealStatusAccepted",
DealStatusFundsNeededUnseal: "DealStatusFundsNeededUnseal",
DealStatusFailing: "DealStatusFailed",
DealStatusRejected: "DealStatusRejected",
DealStatusFundsNeeded: "DealStatusFundsNeeded",
Expand Down
4 changes: 4 additions & 0 deletions retrievalmarket/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ const (
// ClientEventPaymentRequested indicates the provider requested a payment
ClientEventPaymentRequested

// ClientEventUnsealPaymentRequested indicates the provider requested a payment for unsealing the sector
ClientEventUnsealPaymentRequested

// ClientEventBlocksReceived indicates the provider has sent blocks
ClientEventBlocksReceived

Expand Down Expand Up @@ -111,6 +114,7 @@ var ClientEvents = map[ClientEvent]string{
ClientEventLastPaymentRequested: "ClientEventLastPaymentRequested",
ClientEventAllBlocksReceived: "ClientEventAllBlocksReceived",
ClientEventPaymentRequested: "ClientEventPaymentRequested",
ClientEventUnsealPaymentRequested: "ClientEventUnsealPaymentRequested",
ClientEventBlocksReceived: "ClientEventBlocksReceived",
ClientEventSendFunds: "ClientEventSendFunds",
ClientEventFundsExpended: "ClientEventFundsExpended",
Expand Down
2 changes: 2 additions & 0 deletions retrievalmarket/impl/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/filecoin-project/go-statemachine/fsm"
"github.com/filecoin-project/go-storedcounter"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/abi/big"

"github.com/filecoin-project/go-fil-markets/retrievalmarket"
"github.com/filecoin-project/go-fil-markets/retrievalmarket/impl/clientstates"
Expand Down Expand Up @@ -200,6 +201,7 @@ func (c *Client) Retrieve(ctx context.Context, payloadCID cid.Cid, params retrie
FundsSpent: abi.NewTokenAmount(0),
Status: retrievalmarket.DealStatusNew,
Sender: miner,
UnsealFundsPaid: big.Zero(),
}

// start the deal processing
Expand Down
13 changes: 12 additions & 1 deletion retrievalmarket/impl/clientstates/client_fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,13 @@ var ClientEvents = fsm.Events{
return nil
}),

fsm.Event(rm.ClientEventUnsealPaymentRequested).
From(rm.DealStatusWaitForAcceptance).To(rm.DealStatusAccepted).
Action(func(deal *rm.ClientDealState, paymentOwed abi.TokenAmount) error {
deal.PaymentRequested = big.Add(deal.PaymentRequested, paymentOwed)
return nil
}),

// Receiving data
fsm.Event(rm.ClientEventAllBlocksReceived).
FromMany(
Expand Down Expand Up @@ -206,11 +213,15 @@ var ClientEvents = fsm.Events{
// currentInterval = currentInterval + proposal.intervalIncrease
// bytesPaidFor = bytesPaidFor + (paymentRequested / pricePerByte)
deal.FundsSpent = big.Add(deal.FundsSpent, deal.PaymentRequested)
bytesPaidFor := big.Div(deal.PaymentRequested, deal.PricePerByte).Uint64()

paymentForUnsealing := big.Min(deal.PaymentRequested, big.Sub(deal.UnsealPrice, deal.UnsealFundsPaid))

bytesPaidFor := big.Div(big.Sub(deal.PaymentRequested, paymentForUnsealing), deal.PricePerByte).Uint64()
if bytesPaidFor >= deal.CurrentInterval {
deal.CurrentInterval += deal.DealProposal.PaymentIntervalIncrease
}
deal.BytesPaidFor += bytesPaidFor
deal.UnsealFundsPaid = big.Add(deal.UnsealFundsPaid, paymentForUnsealing)
deal.PaymentRequested = abi.NewTokenAmount(0)
return nil
}),
Expand Down
13 changes: 8 additions & 5 deletions retrievalmarket/impl/clientstates/client_states.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,10 @@ func Ongoing(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientD

// ProcessPaymentRequested processes a request for payment from the provider
func ProcessPaymentRequested(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error {

// check that totalReceived - bytesPaidFor >= currentInterval, and send money if we meet that threshold
if deal.TotalReceived-deal.BytesPaidFor >= deal.CurrentInterval || deal.AllBlocksReceived {
// see if we need to send payment
if deal.TotalReceived-deal.BytesPaidFor >= deal.CurrentInterval ||
deal.AllBlocksReceived ||
deal.UnsealPrice.GreaterThan(deal.UnsealFundsPaid) {
return ctx.Trigger(rm.ClientEventSendFunds)
}
return nil
Expand All @@ -112,8 +113,10 @@ func SendFunds(ctx fsm.Context, environment ClientDealEnvironment, deal rm.Clien
return ctx.Trigger(rm.ClientEventFundsExpended, expectedTotal, actualTotal)
}

// check that paymentRequest <= (totalReceived - bytesPaidFor) * pricePerByte, or fail
if deal.PaymentRequested.GreaterThan(big.Mul(abi.NewTokenAmount(int64(deal.TotalReceived-deal.BytesPaidFor)), deal.PricePerByte)) {
// check that paymentRequest <= (totalReceived - bytesPaidFor) * pricePerByte + (unsealPrice - unsealFundsPaid), or fail
retrievalPrice := big.Mul(abi.NewTokenAmount(int64(deal.TotalReceived-deal.BytesPaidFor)), deal.PricePerByte)
unsealPrice := big.Sub(deal.UnsealPrice, deal.UnsealFundsPaid)
if deal.PaymentRequested.GreaterThan(big.Add(retrievalPrice, unsealPrice)) {
return ctx.Trigger(rm.ClientEventBadPaymentRequested, "too much money requested for bytes sent")
}

Expand Down
2 changes: 2 additions & 0 deletions retrievalmarket/impl/clientstates/client_states_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ var defaultTotalReceived = uint64(6000)
var defaultBytesPaidFor = uint64(5000)
var defaultFundsSpent = abi.NewTokenAmount(2500000)
var defaultPaymentRequested = abi.NewTokenAmount(500000)
var defaultUnsealFundsPaid = abi.NewTokenAmount(0)

func makeDealState(status retrievalmarket.DealStatus) *retrievalmarket.ClientDealState {
return &retrievalmarket.ClientDealState{
Expand All @@ -519,6 +520,7 @@ func makeDealState(status retrievalmarket.DealStatus) *retrievalmarket.ClientDea
TotalReceived: defaultTotalReceived,
CurrentInterval: defaultCurrentInterval,
FundsSpent: defaultFundsSpent,
UnsealFundsPaid: defaultUnsealFundsPaid,
PaymentRequested: defaultPaymentRequested,
DealProposal: retrievalmarket.DealProposal{
ID: retrievalmarket.DealID(10),
Expand Down
2 changes: 2 additions & 0 deletions retrievalmarket/impl/dtutils/dtutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ func clientEventForResponse(response *rm.DealResponse) (rm.ClientEvent, []interf
return rm.ClientEventDealNotFound, []interface{}{response.Message}
case rm.DealStatusAccepted:
return rm.ClientEventDealAccepted, nil
case rm.DealStatusFundsNeededUnseal:
return rm.ClientEventUnsealPaymentRequested, []interface{}{response.PaymentOwed}
case rm.DealStatusFundsNeededLastPayment:
return rm.ClientEventLastPaymentRequested, []interface{}{response.PaymentOwed}
case rm.DealStatusCompleted:
Expand Down
Loading

0 comments on commit cb4181f

Please sign in to comment.