Documentation ¶
Overview ¶
Package clientstates contains state machine logic relating to the `StorageMarket`.
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/brossetti1/go-fil-markets/master/docs/storageclient.mmd.svg
Index ¶
- Constants
- Variables
- func CheckForDealAcceptance(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func FailDeal(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func InitiateDataTransfer(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func ProposeDeal(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func ReserveClientFunds(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func RestartDataTransfer(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func ValidateDealPublished(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func VerifyDealActivated(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func VerifyDealPreCommitted(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func WaitForDealCompletion(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- func WaitForFunding(ctx fsm.Context, environment ClientDealEnvironment, ...) error
- type ClientDealEnvironment
- type ClientStateEntryFunc
Constants ¶
const MaxGraceEpochsForDealAcceptance = 10
MaxGraceEpochsForDealAcceptance is the maximum number of epochs we will wait for past the start epoch for the provider to publish a deal.
Variables ¶
var ClientEvents = fsm.Events{ fsm.Event(storagemarket.ClientEventOpen). From(storagemarket.StorageDealUnknown).To(storagemarket.StorageDealReserveClientFunds), fsm.Event(storagemarket.ClientEventFundingInitiated). From(storagemarket.StorageDealReserveClientFunds).To(storagemarket.StorageDealClientFunding). Action(func(deal *storagemarket.ClientDeal, mcid cid.Cid) error { deal.AddFundsCid = &mcid deal.AddLog("reserving funds for storage deal, message cid: <%s>", mcid) return nil }), fsm.Event(storagemarket.ClientEventReserveFundsFailed). FromMany(storagemarket.StorageDealClientFunding, storagemarket.StorageDealReserveClientFunds).To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("adding market funds failed: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventFundsReserved). From(storagemarket.StorageDealReserveClientFunds).ToJustRecord(). Action(func(deal *storagemarket.ClientDeal, fundsReserved abi.TokenAmount) error { if deal.FundsReserved.Nil() { deal.FundsReserved = fundsReserved } else { deal.FundsReserved = big.Add(deal.FundsReserved, fundsReserved) } deal.AddLog("funds reserved, amount <%s>", fundsReserved) return nil }), fsm.Event(storagemarket.ClientEventFundsReleased). FromMany(storagemarket.StorageDealProposalAccepted, storagemarket.StorageDealFailing).ToJustRecord(). Action(func(deal *storagemarket.ClientDeal, fundsReleased abi.TokenAmount) error { deal.FundsReserved = big.Subtract(deal.FundsReserved, fundsReleased) deal.AddLog("funds released, amount <%s>", fundsReleased) return nil }), fsm.Event(storagemarket.ClientEventFundingComplete). FromMany(storagemarket.StorageDealReserveClientFunds, storagemarket.StorageDealClientFunding).To(storagemarket.StorageDealFundsReserved), fsm.Event(storagemarket.ClientEventWriteProposalFailed). From(storagemarket.StorageDealFundsReserved).To(storagemarket.StorageDealError). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("sending proposal to storage provider failed: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventReadResponseFailed). From(storagemarket.StorageDealFundsReserved).To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("error reading Response message from provider: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventResponseVerificationFailed). From(storagemarket.StorageDealFundsReserved).To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal) error { deal.Message = "unable to verify signature on deal response" deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventInitiateDataTransfer). From(storagemarket.StorageDealFundsReserved).To(storagemarket.StorageDealStartDataTransfer). Action(func(deal *storagemarket.ClientDeal) error { deal.AddLog("opening data transfer to storage provider") return nil }), fsm.Event(storagemarket.ClientEventUnexpectedDealState). From(storagemarket.StorageDealFundsReserved).To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal, status storagemarket.StorageDealStatus, providerMessage string) error { deal.Message = xerrors.Errorf("unexpected deal status while waiting for data request: %d (%s). Provider message: %s", status, storagemarket.DealStates[status], providerMessage).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDataTransferFailed). FromMany(storagemarket.StorageDealStartDataTransfer, storagemarket.StorageDealTransferring, storagemarket.StorageDealTransferQueued). To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("failed to complete data transfer: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDataTransferRestartFailed).From(storagemarket.StorageDealClientTransferRestart). To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("failed to restart data transfer: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDataTransferQueued). FromMany(storagemarket.StorageDealStartDataTransfer).To(storagemarket.StorageDealTransferQueued). Action(func(deal *storagemarket.ClientDeal, channelId datatransfer.ChannelID) error { deal.AddLog("provider data transfer request added to client's queue: channel id <%s>", channelId) return nil }), fsm.Event(storagemarket.ClientEventDataTransferInitiated). FromMany(storagemarket.StorageDealTransferQueued).To(storagemarket.StorageDealTransferring). Action(func(deal *storagemarket.ClientDeal, channelId datatransfer.ChannelID) error { deal.TransferChannelID = &channelId deal.AddLog("data transfer initiated on channel id <%s>", channelId) return nil }), fsm.Event(storagemarket.ClientEventDataTransferRestarted). FromMany(storagemarket.StorageDealClientTransferRestart, storagemarket.StorageDealStartDataTransfer, storagemarket.StorageDealTransferQueued).To(storagemarket.StorageDealTransferring). From(storagemarket.StorageDealTransferring).ToJustRecord(). Action(func(deal *storagemarket.ClientDeal, channelId datatransfer.ChannelID) error { deal.TransferChannelID = &channelId deal.Message = "" deal.AddLog("data transfer restarted on channel id <%s>", channelId) return nil }), fsm.Event(storagemarket.ClientEventDataTransferStalled). FromMany(storagemarket.StorageDealTransferring, storagemarket.StorageDealTransferQueued). To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("could not complete data transfer, could not connect to provider %s", deal.Miner).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDataTransferCancelled). FromMany( storagemarket.StorageDealStartDataTransfer, storagemarket.StorageDealTransferring, storagemarket.StorageDealClientTransferRestart, storagemarket.StorageDealTransferQueued, ). To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal) error { deal.Message = "data transfer cancelled" deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDataTransferComplete). FromMany(storagemarket.StorageDealTransferring, storagemarket.StorageDealStartDataTransfer, storagemarket.StorageDealTransferQueued). To(storagemarket.StorageDealCheckForAcceptance), fsm.Event(storagemarket.ClientEventWaitForDealState). From(storagemarket.StorageDealCheckForAcceptance).ToNoChange(). Action(func(deal *storagemarket.ClientDeal, pollError bool, providerState storagemarket.StorageDealStatus) error { deal.PollRetryCount++ if pollError { deal.PollErrorCount++ } deal.Message = fmt.Sprintf("Provider state: %s", storagemarket.DealStates[providerState]) switch storagemarket.DealStates[providerState] { case "StorageDealVerifyData": deal.AddLog("provider is verifying the data") case "StorageDealPublish": deal.AddLog("waiting for provider to publish the deal on-chain") case "StorageDealPublishing": deal.AddLog("provider has submitted the deal on-chain and is waiting for confirmation") case "StorageDealProviderFunding": deal.AddLog("waiting for provider to lock collateral on-chain") default: deal.AddLog(deal.Message) } return nil }), fsm.Event(storagemarket.ClientEventResponseDealDidNotMatch). From(storagemarket.StorageDealCheckForAcceptance).To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal, responseCid cid.Cid, proposalCid cid.Cid) error { deal.Message = xerrors.Errorf("miner responded to a wrong proposal: %s != %s", responseCid, proposalCid).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDealRejected). From(storagemarket.StorageDealCheckForAcceptance).To(storagemarket.StorageDealFailing). Action(func(deal *storagemarket.ClientDeal, state storagemarket.StorageDealStatus, reason string) error { deal.Message = xerrors.Errorf("deal failed: (State=%d) %s", state, reason).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDealAccepted). From(storagemarket.StorageDealCheckForAcceptance).To(storagemarket.StorageDealProposalAccepted). Action(func(deal *storagemarket.ClientDeal, publishMessage *cid.Cid) error { deal.PublishMessage = publishMessage deal.Message = "" deal.AddLog("deal has been accepted by storage provider") return nil }), fsm.Event(storagemarket.ClientEventStreamCloseError). FromAny().To(storagemarket.StorageDealError). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("error attempting to close stream: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDealPublishFailed). From(storagemarket.StorageDealProposalAccepted).To(storagemarket.StorageDealError). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("error validating deal published: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDealPublished). From(storagemarket.StorageDealProposalAccepted).To(storagemarket.StorageDealAwaitingPreCommit). Action(func(deal *storagemarket.ClientDeal, dealID abi.DealID) error { deal.DealID = dealID deal.AddLog("") return nil }), fsm.Event(storagemarket.ClientEventDealPrecommitFailed). From(storagemarket.StorageDealAwaitingPreCommit).To(storagemarket.StorageDealError). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("error waiting for deal pre-commit message to appear on chain: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDealPrecommitted). From(storagemarket.StorageDealAwaitingPreCommit).To(storagemarket.StorageDealSealing). Action(func(deal *storagemarket.ClientDeal, sectorNumber abi.SectorNumber) error { deal.SectorNumber = sectorNumber deal.AddLog("deal pre-commit message has landed on chain") return nil }), fsm.Event(storagemarket.ClientEventDealActivationFailed). From(storagemarket.StorageDealSealing).To(storagemarket.StorageDealError). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("error in deal activation: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventDealActivated). FromMany(storagemarket.StorageDealAwaitingPreCommit, storagemarket.StorageDealSealing). To(storagemarket.StorageDealActive). Action(func(deal *storagemarket.ClientDeal) error { deal.AddLog("deal activated") return nil }), fsm.Event(storagemarket.ClientEventDealSlashed). From(storagemarket.StorageDealActive).To(storagemarket.StorageDealSlashed). Action(func(deal *storagemarket.ClientDeal, slashEpoch abi.ChainEpoch) error { deal.SlashEpoch = slashEpoch deal.AddLog("deal slashed at epoch <%d>", slashEpoch) return nil }), fsm.Event(storagemarket.ClientEventDealExpired). From(storagemarket.StorageDealActive).To(storagemarket.StorageDealExpired), fsm.Event(storagemarket.ClientEventDealCompletionFailed). From(storagemarket.StorageDealActive).To(storagemarket.StorageDealError). Action(func(deal *storagemarket.ClientDeal, err error) error { deal.Message = xerrors.Errorf("error waiting for deal completion: %w", err).Error() deal.AddLog(deal.Message) return nil }), fsm.Event(storagemarket.ClientEventFailed). From(storagemarket.StorageDealFailing).To(storagemarket.StorageDealError). Action(func(deal *storagemarket.ClientDeal) error { deal.AddLog("") return nil }), fsm.Event(storagemarket.ClientEventRestart).From(storagemarket.StorageDealTransferring).To(storagemarket.StorageDealClientTransferRestart). FromAny().ToNoChange(), }
ClientEvents are the events that can happen in a storage client
var ClientFinalityStates = []fsm.StateKey{ storagemarket.StorageDealSlashed, storagemarket.StorageDealExpired, storagemarket.StorageDealError, }
ClientFinalityStates are the states that terminate deal processing for a deal. When a client restarts, it restarts only deals that are not in a finality state.
var ClientStateEntryFuncs = fsm.StateEntryFuncs{ storagemarket.StorageDealReserveClientFunds: ReserveClientFunds, storagemarket.StorageDealClientFunding: WaitForFunding, storagemarket.StorageDealFundsReserved: ProposeDeal, storagemarket.StorageDealStartDataTransfer: InitiateDataTransfer, storagemarket.StorageDealClientTransferRestart: RestartDataTransfer, storagemarket.StorageDealCheckForAcceptance: CheckForDealAcceptance, storagemarket.StorageDealProposalAccepted: ValidateDealPublished, storagemarket.StorageDealAwaitingPreCommit: VerifyDealPreCommitted, storagemarket.StorageDealSealing: VerifyDealActivated, storagemarket.StorageDealActive: WaitForDealCompletion, storagemarket.StorageDealFailing: FailDeal, }
ClientStateEntryFuncs are the handlers for different states in a storage client
Functions ¶
func CheckForDealAcceptance ¶
func CheckForDealAcceptance(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
CheckForDealAcceptance is run until the deal is sealed and published by the provider, or errors
func FailDeal ¶
func FailDeal(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
FailDeal cleans up a failing deal
func InitiateDataTransfer ¶
func InitiateDataTransfer(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
InitiateDataTransfer initiates data transfer to the provider
func ProposeDeal ¶
func ProposeDeal(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
ProposeDeal sends the deal proposal to the provider
func ReserveClientFunds ¶
func ReserveClientFunds(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
ReserveClientFunds attempts to reserve funds for this deal and ensure they are available in the Storage Market Actor
func RestartDataTransfer ¶
func RestartDataTransfer(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
RestartDataTransfer restarts a data transfer to the provider that was initiated earlier
func ValidateDealPublished ¶
func ValidateDealPublished(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
ValidateDealPublished confirms with the chain that a deal was published
func VerifyDealActivated ¶
func VerifyDealActivated(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
VerifyDealActivated confirms that a deal was successfully committed to a sector and is active
func VerifyDealPreCommitted ¶
func VerifyDealPreCommitted(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
VerifyDealPreCommitted verifies that a deal has been pre-committed
func WaitForDealCompletion ¶
func WaitForDealCompletion(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
WaitForDealCompletion waits for the deal to be slashed or to expire
func WaitForFunding ¶
func WaitForFunding(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
WaitForFunding waits for an AddFunds message to appear on the chain
Types ¶
type ClientDealEnvironment ¶
type ClientDealEnvironment interface { // CleanBlockstore cleans up the read-only CARv2 blockstore that provides random access on top of client deal data. // It's important to do this when the client deal finishes successfully or errors out. CleanBlockstore(rootCid cid.Cid) error Node() storagemarket.StorageClientNode NewDealStream(ctx context.Context, p peer.ID) (network.StorageDealStream, error) StartDataTransfer(ctx context.Context, to peer.ID, voucher datatransfer.TypedVoucher, baseCid cid.Cid, selector datamodel.Node) (datatransfer.ChannelID, error) RestartDataTransfer(ctx context.Context, chid datatransfer.ChannelID) error GetProviderDealState(ctx context.Context, proposalCid cid.Cid) (*storagemarket.ProviderDealState, error) PollingInterval() time.Duration network.PeerTagger }
ClientDealEnvironment is an abstraction for interacting with dependencies from the storage client environment
type ClientStateEntryFunc ¶
type ClientStateEntryFunc func(ctx fsm.Context, environment ClientDealEnvironment, deal storagemarket.ClientDeal) error
ClientStateEntryFunc is the type for all state entry functions on a storage client