Documentation ¶
Overview ¶
Package clientstates contains state machine logic relating to the `RetrievalClient`.
client_fsm.go is where the state transitions are defined, and the default handlers for each new state are defined.
client_states.go contains state handler functions.
The following diagram illustrates the operation of the client state machine. This diagram is auto-generated from current code and should remain up to date over time:
https://raw.githubusercontent.com/chenjianmei111/go-fil-markets/master/docs/retrievalclient.mmd.svg
Index ¶
- Variables
- func AllocateLane(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- func CancelDeal(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- func CheckComplete(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- func CheckFunds(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- func IsFinalityState(st fsm.StateKey) bool
- func Ongoing(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- func ProcessPaymentRequested(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- func ProposeDeal(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- func SendFunds(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- func SetupPaymentChannelStart(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- func WaitPaymentChannelReady(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
- type ClientDealEnvironment
Constants ¶
This section is empty.
Variables ¶
var ClientEvents = fsm.Events{ fsm.Event(rm.ClientEventOpen). From(rm.DealStatusNew).ToNoChange(), fsm.Event(rm.ClientEventWriteDealProposalErrored). FromAny().To(rm.DealStatusErrored). Action(func(deal *rm.ClientDealState, err error) error { deal.Message = xerrors.Errorf("proposing deal: %w", err).Error() return nil }), fsm.Event(rm.ClientEventDealProposed). From(rm.DealStatusNew).To(rm.DealStatusWaitForAcceptance). From(rm.DealStatusRetryLegacy).To(rm.DealStatusWaitForAcceptanceLegacy). From(rm.DealStatusCancelling).ToJustRecord(). Action(func(deal *rm.ClientDealState, channelID datatransfer.ChannelID) error { deal.ChannelID = &channelID deal.Message = "" return nil }), fsm.Event(rm.ClientEventDealRejected). From(rm.DealStatusWaitForAcceptance).To(rm.DealStatusRetryLegacy). From(rm.DealStatusWaitForAcceptanceLegacy).To(rm.DealStatusRejected). Action(func(deal *rm.ClientDealState, message string) error { deal.Message = fmt.Sprintf("deal rejected: %s", message) deal.LegacyProtocol = true return nil }), fsm.Event(rm.ClientEventDealNotFound). FromMany(rm.DealStatusWaitForAcceptance, rm.DealStatusWaitForAcceptanceLegacy).To(rm.DealStatusDealNotFound). Action(func(deal *rm.ClientDealState, message string) error { deal.Message = fmt.Sprintf("deal not found: %s", message) return nil }), fsm.Event(rm.ClientEventDealAccepted). FromMany(rm.DealStatusWaitForAcceptance, rm.DealStatusWaitForAcceptanceLegacy).To(rm.DealStatusAccepted), fsm.Event(rm.ClientEventUnknownResponseReceived). FromAny().To(rm.DealStatusFailing). Action(func(deal *rm.ClientDealState, status rm.DealStatus) error { deal.Message = fmt.Sprintf("Unexpected deal response status: %s", rm.DealStatuses[status]) return nil }), fsm.Event(rm.ClientEventPaymentChannelErrored). FromMany(rm.DealStatusAccepted, rm.DealStatusPaymentChannelCreating, rm.DealStatusPaymentChannelAddingFunds).To(rm.DealStatusFailing). Action(func(deal *rm.ClientDealState, err error) error { deal.Message = xerrors.Errorf("error from payment channel: %w", err).Error() return nil }), fsm.Event(rm.ClientEventPaymentChannelSkip). From(rm.DealStatusAccepted).To(rm.DealStatusOngoing), fsm.Event(rm.ClientEventPaymentChannelCreateInitiated). From(rm.DealStatusAccepted).To(rm.DealStatusPaymentChannelCreating). Action(func(deal *rm.ClientDealState, msgCID cid.Cid) error { deal.WaitMsgCID = &msgCID return nil }), fsm.Event(rm.ClientEventPaymentChannelAddingFunds). FromMany(rm.DealStatusAccepted).To(rm.DealStatusPaymentChannelAddingInitialFunds). FromMany(rm.DealStatusCheckFunds).To(rm.DealStatusPaymentChannelAddingFunds). Action(func(deal *rm.ClientDealState, msgCID cid.Cid, payCh address.Address) error { deal.WaitMsgCID = &msgCID if deal.PaymentInfo == nil { deal.PaymentInfo = &rm.PaymentInfo{ PayCh: payCh, } } return nil }), fsm.Event(rm.ClientEventPaymentChannelReady). From(rm.DealStatusPaymentChannelCreating).To(rm.DealStatusPaymentChannelAllocatingLane). From(rm.DealStatusPaymentChannelAddingInitialFunds).To(rm.DealStatusPaymentChannelAllocatingLane). From(rm.DealStatusPaymentChannelAddingFunds).To(rm.DealStatusOngoing). From(rm.DealStatusCheckFunds).To(rm.DealStatusOngoing). Action(func(deal *rm.ClientDealState, payCh address.Address) error { if deal.PaymentInfo == nil { deal.PaymentInfo = &rm.PaymentInfo{ PayCh: payCh, } } deal.WaitMsgCID = nil deal.Message = "" return nil }), fsm.Event(rm.ClientEventAllocateLaneErrored). FromMany(rm.DealStatusPaymentChannelAllocatingLane). To(rm.DealStatusFailing). Action(func(deal *rm.ClientDealState, err error) error { deal.Message = xerrors.Errorf("allocating payment lane: %w", err).Error() return nil }), fsm.Event(rm.ClientEventLaneAllocated). From(rm.DealStatusPaymentChannelAllocatingLane).To(rm.DealStatusOngoing). Action(func(deal *rm.ClientDealState, lane uint64) error { deal.PaymentInfo.Lane = lane return nil }), fsm.Event(rm.ClientEventDataTransferError). FromAny().To(rm.DealStatusErrored). Action(func(deal *rm.ClientDealState, err error) error { deal.Message = fmt.Sprintf("error generated by data transfer: %s", err.Error()) return nil }), fsm.Event(rm.ClientEventLastPaymentRequested). FromMany( rm.DealStatusOngoing, rm.DealStatusFundsNeededLastPayment, rm.DealStatusFundsNeeded).To(rm.DealStatusFundsNeededLastPayment). From(rm.DealStatusBlocksComplete).To(rm.DealStatusSendFundsLastPayment). FromMany( paymentChannelCreationStates...).ToJustRecord(). Action(func(deal *rm.ClientDealState, paymentOwed abi.TokenAmount) error { deal.PaymentRequested = big.Add(deal.PaymentRequested, paymentOwed) deal.LastPaymentRequested = true return nil }), fsm.Event(rm.ClientEventPaymentRequested). FromMany( rm.DealStatusOngoing, rm.DealStatusBlocksComplete, rm.DealStatusFundsNeeded).To(rm.DealStatusFundsNeeded). FromMany( paymentChannelCreationStates...).ToJustRecord(). Action(func(deal *rm.ClientDealState, paymentOwed abi.TokenAmount) error { deal.PaymentRequested = big.Add(deal.PaymentRequested, paymentOwed) return nil }), fsm.Event(rm.ClientEventUnsealPaymentRequested). FromMany(rm.DealStatusWaitForAcceptance, rm.DealStatusWaitForAcceptanceLegacy).To(rm.DealStatusAccepted). Action(func(deal *rm.ClientDealState, paymentOwed abi.TokenAmount) error { deal.PaymentRequested = big.Add(deal.PaymentRequested, paymentOwed) return nil }), fsm.Event(rm.ClientEventAllBlocksReceived). FromMany( rm.DealStatusOngoing, rm.DealStatusBlocksComplete, ).To(rm.DealStatusBlocksComplete). FromMany(paymentChannelCreationStates...).ToJustRecord(). FromMany(rm.DealStatusSendFunds, rm.DealStatusFundsNeeded).ToJustRecord(). From(rm.DealStatusFundsNeededLastPayment).To(rm.DealStatusSendFundsLastPayment). From(rm.DealStatusClientWaitingForLastBlocks).To(rm.DealStatusCompleted). Action(func(deal *rm.ClientDealState) error { deal.AllBlocksReceived = true return nil }), fsm.Event(rm.ClientEventBlocksReceived). FromMany(rm.DealStatusOngoing, rm.DealStatusFundsNeeded, rm.DealStatusFundsNeededLastPayment, rm.DealStatusCheckComplete, rm.DealStatusClientWaitingForLastBlocks).ToNoChange(). FromMany(paymentChannelCreationStates...).ToJustRecord(). Action(recordReceived), fsm.Event(rm.ClientEventSendFunds). From(rm.DealStatusFundsNeeded).To(rm.DealStatusSendFunds). From(rm.DealStatusFundsNeededLastPayment).To(rm.DealStatusSendFundsLastPayment), fsm.Event(rm.ClientEventFundsExpended). FromMany(rm.DealStatusCheckFunds).To(rm.DealStatusInsufficientFunds). Action(func(deal *rm.ClientDealState, shortfall abi.TokenAmount) error { deal.Message = fmt.Sprintf("not enough current or pending funds in payment channel, shortfall of %s", shortfall.String()) return nil }), fsm.Event(rm.ClientEventBadPaymentRequested). FromMany(rm.DealStatusSendFunds, rm.DealStatusSendFundsLastPayment).To(rm.DealStatusFailing). Action(func(deal *rm.ClientDealState, message string) error { deal.Message = message return nil }), fsm.Event(rm.ClientEventCreateVoucherFailed). FromMany(rm.DealStatusSendFunds, rm.DealStatusSendFundsLastPayment).To(rm.DealStatusFailing). Action(func(deal *rm.ClientDealState, err error) error { deal.Message = xerrors.Errorf("creating payment voucher: %w", err).Error() return nil }), fsm.Event(rm.ClientEventVoucherShortfall). FromMany(rm.DealStatusSendFunds, rm.DealStatusSendFundsLastPayment).To(rm.DealStatusCheckFunds). Action(func(deal *rm.ClientDealState, shortfall abi.TokenAmount) error { return nil }), fsm.Event(rm.ClientEventWriteDealPaymentErrored). FromAny().To(rm.DealStatusErrored). Action(func(deal *rm.ClientDealState, err error) error { deal.Message = xerrors.Errorf("writing deal payment: %w", err).Error() return nil }), fsm.Event(rm.ClientEventPaymentSent). From(rm.DealStatusSendFunds).To(rm.DealStatusOngoing). From(rm.DealStatusSendFundsLastPayment).To(rm.DealStatusFinalizing). Action(func(deal *rm.ClientDealState) error { deal.FundsSpent = big.Add(deal.FundsSpent, deal.PaymentRequested) 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 }), fsm.Event(rm.ClientEventComplete). From(rm.DealStatusOngoing).To(rm.DealStatusCheckComplete). From(rm.DealStatusBlocksComplete).To(rm.DealStatusCheckComplete). From(rm.DealStatusFinalizing).To(rm.DealStatusCompleted), fsm.Event(rm.ClientEventCompleteVerified). From(rm.DealStatusCheckComplete).To(rm.DealStatusCompleted), fsm.Event(rm.ClientEventEarlyTermination). From(rm.DealStatusCheckComplete).To(rm.DealStatusErrored). Action(func(deal *rm.ClientDealState) error { deal.Message = "Provider sent complete status without sending all data" return nil }), fsm.Event(rm.ClientEventWaitForLastBlocks). From(rm.DealStatusCheckComplete).To(rm.DealStatusClientWaitingForLastBlocks), fsm.Event(rm.ClientEventCancelComplete). From(rm.DealStatusFailing).To(rm.DealStatusErrored). From(rm.DealStatusCancelling).To(rm.DealStatusCancelled), fsm.Event(rm.ClientEventProviderCancelled). From(rm.DealStatusFailing).ToJustRecord(). From(rm.DealStatusCancelling).ToJustRecord(). FromAny().To(rm.DealStatusCancelling).Action( func(deal *rm.ClientDealState) error { if deal.Status != rm.DealStatusFailing && deal.Status != rm.DealStatusCancelling { deal.Message = "Provider cancelled retrieval" } return nil }, ), fsm.Event(rm.ClientEventCancel).FromAny().To(rm.DealStatusCancelling).Action(func(deal *rm.ClientDealState) error { deal.Message = "Client cancelled retrieval" return nil }), fsm.Event(rm.ClientEventRecheckFunds).From(rm.DealStatusInsufficientFunds).To(rm.DealStatusCheckFunds), }
ClientEvents are the events that can happen in a retrieval client
var ClientFinalityStates = []fsm.StateKey{ rm.DealStatusErrored, rm.DealStatusCompleted, rm.DealStatusCancelled, rm.DealStatusRejected, rm.DealStatusDealNotFound, }
ClientFinalityStates are terminal states after which no further events are received
var ClientStateEntryFuncs = fsm.StateEntryFuncs{ rm.DealStatusNew: ProposeDeal, rm.DealStatusRetryLegacy: ProposeDeal, rm.DealStatusAccepted: SetupPaymentChannelStart, rm.DealStatusPaymentChannelCreating: WaitPaymentChannelReady, rm.DealStatusPaymentChannelAddingInitialFunds: WaitPaymentChannelReady, rm.DealStatusPaymentChannelAllocatingLane: AllocateLane, rm.DealStatusOngoing: Ongoing, rm.DealStatusFundsNeeded: ProcessPaymentRequested, rm.DealStatusFundsNeededLastPayment: ProcessPaymentRequested, rm.DealStatusSendFunds: SendFunds, rm.DealStatusSendFundsLastPayment: SendFunds, rm.DealStatusCheckFunds: CheckFunds, rm.DealStatusPaymentChannelAddingFunds: WaitPaymentChannelReady, rm.DealStatusFailing: CancelDeal, rm.DealStatusCancelling: CancelDeal, rm.DealStatusCheckComplete: CheckComplete, }
ClientStateEntryFuncs are the handlers for different states in a retrieval client
Functions ¶
func AllocateLane ¶
func AllocateLane(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
AllocateLane allocates a lane for this retrieval operation
func CancelDeal ¶
func CancelDeal(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
CancelDeal clears a deal that went wrong for an unknown reason
func CheckComplete ¶
func CheckComplete(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
CheckComplete verifies that a provider that completed without a last payment requested did in fact send us all the data
func CheckFunds ¶
func CheckFunds(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
CheckFunds examines current available funds in a payment channel after a voucher shortfall to determine a course of action -- whether it's a good time to try again, wait for pending operations, or we've truly expended all funds and we need to wait for a manual readd
func IsFinalityState ¶
func Ongoing ¶
func Ongoing(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
Ongoing just double checks that we may need to move out of the ongoing state cause a payment was previously requested
func ProcessPaymentRequested ¶
func ProcessPaymentRequested(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
ProcessPaymentRequested processes a request for payment from the provider
func ProposeDeal ¶
func ProposeDeal(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
ProposeDeal sends the proposal to the other party
func SendFunds ¶
func SendFunds(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
SendFunds sends the next amount requested by the provider
func SetupPaymentChannelStart ¶
func SetupPaymentChannelStart(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
SetupPaymentChannelStart initiates setting up a payment channel for a deal
func WaitPaymentChannelReady ¶
func WaitPaymentChannelReady(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error
WaitPaymentChannelReady waits for a pending operation on a payment channel -- either creating or depositing funds
Types ¶
type ClientDealEnvironment ¶
type ClientDealEnvironment interface { // Node returns the node interface for this deal Node() rm.RetrievalClientNode OpenDataTransfer(ctx context.Context, to peer.ID, proposal *rm.DealProposal, legacy bool) (datatransfer.ChannelID, error) SendDataTransferVoucher(context.Context, datatransfer.ChannelID, *rm.DealPayment, bool) error CloseDataTransfer(context.Context, datatransfer.ChannelID) error }
ClientDealEnvironment is a bridge to the environment a client deal is executing in. It provides access to relevant functionality on the retrieval client