client

package
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 11, 2022 License: BSD-3-Clause Imports: 15 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Events = map[Event]string{
	EventOpen:                          "ClientEventOpen",
	EventPaymentChannelErrored:         "ClientEventPaymentChannelErrored",
	EventDealProposed:                  "ClientEventDealProposed",
	EventAllocateLaneErrored:           "ClientEventAllocateLaneErrored",
	EventPaymentChannelCreateInitiated: "ClientEventPaymentChannelCreateInitiated",
	EventPaymentChannelReady:           "ClientEventPaymentChannelReady",
	EventPaymentChannelAddingFunds:     "ClientEventPaymentChannelAddingFunds",
	EventPaymentChannelAddFundsErrored: "ClientEventPaymentChannelAddFundsErrored",
	EventPaymentChannelSkip:            "ClientEventPaymentChannelSkip",
	EventWriteDealProposalErrored:      "ClientEventWriteDealProposalErrored",
	EventDealRejected:                  "ClientEventDealRejected",
	EventDealNotFound:                  "ClientEventDealNotFound",
	EventDealAccepted:                  "ClientEventDealAccepted",
	EventProviderCancelled:             "ClientEventProviderCancelled",
	EventUnknownResponseReceived:       "ClientEventUnknownResponseReceived",
	EventLastPaymentRequested:          "ClientEventLastPaymentRequested",
	EventAllBlocksReceived:             "ClientEventAllBlocksReceived",
	EventPaymentRequested:              "ClientEventPaymentRequested",
	EventUnsealPaymentRequested:        "ClientEventUnsealPaymentRequested",
	EventBlocksReceived:                "ClientEventBlocksReceived",
	EventSendFunds:                     "ClientEventSendFunds",
	EventFundsExpended:                 "ClientEventFundsExpended",
	EventBadPaymentRequested:           "ClientEventBadPaymentRequested",
	EventCreateVoucherFailed:           "ClientEventCreateVoucherFailed",
	EventWriteDealPaymentErrored:       "ClientEventWriteDealPaymentErrored",
	EventPaymentSent:                   "ClientEventPaymentSent",
	EventPaymentNotSent:                "ClientEventPaymentNotSent",
	EventDataTransferError:             "ClientEventDataTransferError",
	EventComplete:                      "ClientEventComplete",
	EventCancelComplete:                "ClientEventCancelComplete",
	EventEarlyTermination:              "ClientEventEarlyTermination",
	EventCompleteVerified:              "ClientEventCompleteVerified",
	EventLaneAllocated:                 "ClientEventLaneAllocated",
	EventVoucherShortfall:              "ClientEventVoucherShortfall",
	EventRecheckFunds:                  "ClientEventRecheckFunds",
	EventCancel:                        "ClientEventCancel",
	EventWaitForLastBlocks:             "ClientEventWaitForLastBlocks",
	EventProviderErrored:               "ClientEventProviderErrored",
}

Events is a human readable map of client event name -> event description

View Source
var FSMEvents = fsm.Events{
	fsm.Event(EventOpen).
		From(deal.StatusNew).ToNoChange(),

	fsm.Event(EventWriteDealProposalErrored).
		FromAny().To(deal.StatusErrored).
		Action(func(ds *deal.ClientState, err error) error {
			ds.Message = fmt.Errorf("proposing deal: %w", err).Error()
			return nil
		}),
	fsm.Event(EventDealProposed).
		From(deal.StatusNew).To(deal.StatusWaitForAcceptance).
		Action(func(ds *deal.ClientState, channelID datatransfer.ChannelID) error {
			ds.ChannelID = channelID
			ds.Message = ""
			return nil
		}),

	fsm.Event(EventDealRejected).
		From(deal.StatusWaitForAcceptance).To(deal.StatusRejected).
		Action(func(deal *deal.ClientState, message string) error {
			deal.Message = fmt.Sprintf("deal rejected: %s", message)
			return nil
		}),
	fsm.Event(EventDealNotFound).
		From(deal.StatusWaitForAcceptance).To(deal.StatusDealNotFound).
		Action(func(ds *deal.ClientState, message string) error {
			ds.Message = fmt.Sprintf("deal not found: %s", message)
			return nil
		}),
	fsm.Event(EventDealAccepted).
		From(deal.StatusWaitForAcceptance).To(deal.StatusAccepted).
		From(deal.StatusClientWaitingForLastBlocks).ToNoChange(),
	fsm.Event(EventUnknownResponseReceived).
		FromAny().To(deal.StatusFailing).
		Action(func(ds *deal.ClientState, status deal.Status) error {
			ds.Message = fmt.Sprintf("Unexpected deal response status: %s", deal.Statuses[status])
			return nil
		}),

	fsm.Event(EventPaymentChannelSkip).
		From(deal.StatusAccepted).To(deal.StatusOngoing),

	fsm.Event(EventPaymentChannelErrored).
		FromMany(deal.StatusAccepted, deal.StatusPaymentChannelCreating, deal.StatusPaymentChannelAddingFunds).To(deal.StatusFailing).
		Action(func(ds *deal.ClientState, err error) error {
			ds.Message = fmt.Errorf("error from payment channel: %w", err).Error()
			return nil
		}),
	fsm.Event(EventPaymentChannelCreateInitiated).
		From(deal.StatusAccepted).To(deal.StatusPaymentChannelCreating).
		Action(func(ds *deal.ClientState, msgCID cid.Cid) error {
			ds.WaitMsgCID = &msgCID
			return nil
		}),
	fsm.Event(EventPaymentChannelAddingFunds).
		From(deal.StatusAccepted).To(deal.StatusPaymentChannelAddingInitialFunds).
		From(deal.StatusCheckFunds).To(deal.StatusPaymentChannelAddingFunds).
		Action(func(ds *deal.ClientState, msgCID cid.Cid, payCh address.Address) error {
			ds.WaitMsgCID = &msgCID
			if ds.PaymentInfo == nil {
				ds.PaymentInfo = &deal.PaymentInfo{
					PayCh: payCh,
				}
			}
			return nil
		}),
	fsm.Event(EventPaymentChannelReady).
		FromMany(deal.StatusPaymentChannelCreating, deal.StatusPaymentChannelAddingInitialFunds, deal.StatusAccepted).
		To(deal.StatusPaymentChannelAllocatingLane).
		From(deal.StatusPaymentChannelAddingFunds).To(deal.StatusOngoing).
		From(deal.StatusCheckFunds).To(deal.StatusOngoing).
		Action(func(ds *deal.ClientState, payCh address.Address) error {
			if ds.PaymentInfo == nil {
				ds.PaymentInfo = &deal.PaymentInfo{
					PayCh: payCh,
				}
			}
			ds.WaitMsgCID = nil

			ds.Message = ""
			return nil
		}),
	fsm.Event(EventAllocateLaneErrored).
		FromMany(deal.StatusPaymentChannelAllocatingLane).
		To(deal.StatusFailing).
		Action(func(ds *deal.ClientState, err error) error {
			ds.Message = fmt.Errorf("allocating payment lane: %w", err).Error()
			return nil
		}),

	fsm.Event(EventLaneAllocated).
		From(deal.StatusPaymentChannelAllocatingLane).To(deal.StatusOngoing).
		Action(func(ds *deal.ClientState, lane uint64) error {
			ds.PaymentInfo.Lane = lane
			return nil
		}),

	fsm.Event(EventProviderErrored).
		FromAny().To(deal.StatusErrored).
		Action(func(ds *deal.ClientState, msg string) error {
			ds.Message = msg
			return nil
		}),

	fsm.Event(EventDataTransferError).
		FromAny().To(deal.StatusErrored).
		Action(func(ds *deal.ClientState, err error) error {
			ds.Message = fmt.Sprintf("error generated by data transfer: %s", err.Error())
			return nil
		}),

	fsm.Event(EventLastPaymentRequested).
		FromMany(
			deal.StatusOngoing,
			deal.StatusFundsNeededLastPayment,
			deal.StatusFundsNeeded).To(deal.StatusFundsNeededLastPayment).
		From(deal.StatusSendFunds).To(deal.StatusOngoing).
		From(deal.StatusCheckComplete).ToNoChange().
		From(deal.StatusBlocksComplete).To(deal.StatusSendFundsLastPayment).
		FromMany(
			paymentChannelCreationStates...).ToJustRecord().
		Action(func(ds *deal.ClientState, paymentOwed abi.TokenAmount) error {
			ds.PaymentRequested = big.Add(ds.PaymentRequested, paymentOwed)
			ds.LastPaymentRequested = true
			return nil
		}),
	fsm.Event(EventPaymentRequested).
		FromMany(
			deal.StatusOngoing,
			deal.StatusBlocksComplete,
			deal.StatusFundsNeededLastPayment,
			deal.StatusFundsNeeded).To(deal.StatusFundsNeeded).
		From(deal.StatusSendFunds).To(deal.StatusOngoing).
		From(deal.StatusCheckComplete).ToNoChange().
		FromMany(
			paymentChannelCreationStates...).ToJustRecord().
		Action(func(ds *deal.ClientState, paymentOwed abi.TokenAmount) error {
			ds.PaymentRequested = big.Add(ds.PaymentRequested, paymentOwed)
			return nil
		}),

	fsm.Event(EventUnsealPaymentRequested).
		From(deal.StatusWaitForAcceptance).To(deal.StatusAccepted).
		Action(func(ds *deal.ClientState, paymentOwed abi.TokenAmount) error {
			ds.PaymentRequested = big.Add(ds.PaymentRequested, paymentOwed)
			return nil
		}),

	fsm.Event(EventAllBlocksReceived).
		FromMany(
			deal.StatusOngoing,
			deal.StatusBlocksComplete,
		).To(deal.StatusBlocksComplete).
		FromMany(paymentChannelCreationStates...).ToJustRecord().
		FromMany(deal.StatusSendFunds, deal.StatusSendFundsLastPayment).To(deal.StatusOngoing).
		From(deal.StatusFundsNeeded).ToNoChange().
		From(deal.StatusFundsNeededLastPayment).To(deal.StatusSendFundsLastPayment).
		FromMany(
			deal.StatusClientWaitingForLastBlocks,

			deal.StatusCheckComplete,
		).To(deal.StatusCompleted).
		Action(func(ds *deal.ClientState) error {
			ds.AllBlocksReceived = true
			return nil
		}),
	fsm.Event(EventBlocksReceived).
		FromMany(deal.StatusOngoing,
			deal.StatusFundsNeeded,
			deal.StatusFundsNeededLastPayment,
			deal.StatusCheckComplete,
			deal.StatusClientWaitingForLastBlocks).ToNoChange().
		FromMany(deal.StatusSendFunds, deal.StatusSendFundsLastPayment).To(deal.StatusOngoing).
		FromMany(paymentChannelCreationStates...).ToJustRecord().
		Action(recordReceived),

	fsm.Event(EventSendFunds).
		FromMany(deal.StatusSendFunds, deal.StatusSendFundsLastPayment).To(deal.StatusOngoing).
		From(deal.StatusFundsNeeded).To(deal.StatusSendFunds).
		From(deal.StatusFundsNeededLastPayment).To(deal.StatusSendFundsLastPayment),

	fsm.Event(EventFundsExpended).
		From(deal.StatusCheckFunds).To(deal.StatusInsufficientFunds).
		Action(func(ds *deal.ClientState, shortfall abi.TokenAmount) error {
			ds.Message = fmt.Sprintf("not enough current or pending funds in payment channel, shortfall of %s", shortfall.String())
			ds.VoucherShortfall = shortfall
			return nil
		}),
	fsm.Event(EventBadPaymentRequested).
		FromMany(deal.StatusSendFunds, deal.StatusSendFundsLastPayment).To(deal.StatusFailing).
		Action(func(ds *deal.ClientState, message string) error {
			ds.Message = message
			return nil
		}),
	fsm.Event(EventCreateVoucherFailed).
		FromMany(deal.StatusSendFunds, deal.StatusSendFundsLastPayment).To(deal.StatusFailing).
		Action(func(ds *deal.ClientState, err error) error {
			ds.Message = fmt.Errorf("creating payment voucher: %w", err).Error()
			return nil
		}),
	fsm.Event(EventVoucherShortfall).
		FromMany(deal.StatusSendFunds, deal.StatusSendFundsLastPayment).To(deal.StatusCheckFunds).
		Action(func(ds *deal.ClientState, shortfall abi.TokenAmount) error {
			return nil
		}),

	fsm.Event(EventWriteDealPaymentErrored).
		FromAny().To(deal.StatusErrored).
		Action(func(ds *deal.ClientState, err error) error {
			ds.Message = fmt.Errorf("writing deal payment: %w", err).Error()
			return nil
		}),

	fsm.Event(EventPaymentNotSent).
		From(deal.StatusOngoing).ToJustRecord().
		From(deal.StatusSendFunds).To(deal.StatusOngoing).
		From(deal.StatusSendFundsLastPayment).To(deal.StatusFinalizing),
	fsm.Event(EventPaymentSent).
		From(deal.StatusOngoing).ToJustRecord().
		From(deal.StatusBlocksComplete).To(deal.StatusCheckComplete).
		From(deal.StatusCheckComplete).ToNoChange().
		FromMany(
			deal.StatusFundsNeeded,
			deal.StatusFundsNeededLastPayment,
			deal.StatusSendFunds).To(deal.StatusOngoing).
		From(deal.StatusSendFundsLastPayment).To(deal.StatusFinalizing).
		Action(func(state *deal.ClientState, voucherAmt abi.TokenAmount) error {

			sentAmt := big.Sub(voucherAmt, state.FundsSpent)
			state.PaymentRequested = big.Sub(state.PaymentRequested, sentAmt)

			state.FundsSpent = voucherAmt

			if state.UnsealPrice.GreaterThanEqual(state.FundsSpent) {
				state.UnsealFundsPaid = state.FundsSpent
				return nil
			}

			state.UnsealFundsPaid = state.UnsealPrice

			if state.PricePerByte.IsZero() {
				return nil
			}

			paidSoFarForTransfer := big.Sub(state.FundsSpent, state.UnsealFundsPaid)
			state.BytesPaidFor = big.Div(paidSoFarForTransfer, state.PricePerByte).Uint64()

			if state.BytesPaidFor >= state.CurrentInterval {
				state.CurrentInterval = state.NextInterval()
			}

			return nil
		}),

	fsm.Event(EventComplete).
		FromMany(
			deal.StatusSendFunds,
			deal.StatusSendFundsLastPayment,
			deal.StatusFundsNeeded,
			deal.StatusFundsNeededLastPayment,
			deal.StatusBlocksComplete,
			deal.StatusWaitForAcceptance,
			deal.StatusAccepted,
			deal.StatusOngoing).To(deal.StatusCheckComplete).
		From(deal.StatusFinalizing).To(deal.StatusCompleted),
	fsm.Event(EventCompleteVerified).
		From(deal.StatusCheckComplete).To(deal.StatusCompleted),
	fsm.Event(EventEarlyTermination).
		From(deal.StatusCheckComplete).To(deal.StatusErrored).
		Action(func(state *deal.ClientState) error {
			state.Message = "Provider sent complete status without sending all data"
			return nil
		}),

	fsm.Event(EventWaitForLastBlocks).
		From(deal.StatusCheckComplete).To(deal.StatusClientWaitingForLastBlocks).
		From(deal.StatusCompleted).ToJustRecord(),

	fsm.Event(EventCancelComplete).
		From(deal.StatusFailing).To(deal.StatusErrored).
		From(deal.StatusCancelling).To(deal.StatusCancelled),

	fsm.Event(EventProviderCancelled).
		From(deal.StatusFailing).ToJustRecord().
		From(deal.StatusCancelling).ToJustRecord().
		FromAny().To(deal.StatusCancelling).Action(
		func(ds *deal.ClientState) error {
			if ds.Status != deal.StatusFailing && ds.Status != deal.StatusCancelling {
				ds.Message = "Provider cancelled retrieval"
			}
			return nil
		},
	),

	fsm.Event(EventCancel).FromAny().To(deal.StatusCancelling).Action(func(ds *deal.ClientState) error {
		ds.Message = "Client cancelled retrieval"
		return nil
	}),

	fsm.Event(EventRecheckFunds).From(deal.StatusInsufficientFunds).To(deal.StatusCheckFunds),
}

FSMEvents is the state chart defining the events that can happen in a retrieval client it is almost identical to go-fil-markets implementation except we don't support legacy events

FinalityStates are terminal states after which no further events are received

StateEntryFuncs are the handlers for different states in a retrieval client

Functions

func AllocateLane

func AllocateLane(ctx fsm.Context, environment DealEnvironment, ds deal.ClientState) error

AllocateLane allocates a lane for this retrieval operation

func CancelDeal

func CancelDeal(ctx fsm.Context, environment DealEnvironment, ds deal.ClientState) error

CancelDeal clears a deal that went wrong for an unknown reason

func CheckComplete

func CheckComplete(ctx fsm.Context, environment DealEnvironment, ds deal.ClientState) 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, env DealEnvironment, ds deal.ClientState) 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 DataTransferSubscriber

func DataTransferSubscriber(deals EventReceiver, host peer.ID) datatransfer.Subscriber

DataTransferSubscriber is the function called when an event occurs in a data transfer initiated on the client -- it reads the voucher to verify this even occurred in a storage market deal, then, based on the data transfer event that occurred, it dispatches an event to the appropriate state machine

func Dispatcher

func Dispatcher(evt pubsub.Event, subscriberFn pubsub.SubscriberFn) error

Dispatcher casts a pubsub event into a provider event and publishes it to a subscriber

func Ongoing

func Ongoing(ctx fsm.Context, environment DealEnvironment, ds deal.ClientState) 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 DealEnvironment, ds deal.ClientState) error

ProcessPaymentRequested processes a request for payment from the provider

func ProposeDeal

func ProposeDeal(ctx fsm.Context, environment DealEnvironment, ds deal.ClientState) error

ProposeDeal sends the proposal to the other party

func SendFunds

func SendFunds(ctx fsm.Context, env DealEnvironment, ds deal.ClientState) error

SendFunds sends the next amount requested by the provider

func SetupPaymentChannelStart

func SetupPaymentChannelStart(ctx fsm.Context, environment DealEnvironment, ds deal.ClientState) error

SetupPaymentChannelStart initiates setting up a payment channel for a deal

func WaitPaymentChannelReady

func WaitPaymentChannelReady(ctx fsm.Context, environment DealEnvironment, ds deal.ClientState) error

WaitPaymentChannelReady waits for a pending operation on a payment channel -- either creating or depositing funds

Types

type DealEnvironment

type DealEnvironment interface {
	Payments() payments.Manager
	OpenDataTransfer(ctx context.Context, to peer.ID, proposal *deal.Proposal) (datatransfer.ChannelID, error)
	SendDataTransferVoucher(context.Context, datatransfer.ChannelID, *deal.Payment) error
	CloseDataTransfer(context.Context, datatransfer.ChannelID) error
}

DealEnvironment is a bridge to the environment a client deal is executing in. It provides access to relevant functionality on the retrieval client

type Event

type Event uint64

Event is an event that occurs in a deal lifecycle on the client

const (
	// EventOpen indicates a deal was initiated
	EventOpen Event = iota

	// EventWriteDealProposalErrored means a network error writing a deal proposal
	EventWriteDealProposalErrored

	// EventDealProposed means a deal was successfully sent to a miner
	EventDealProposed

	// EventDealRejected means a deal was rejected by the provider
	EventDealRejected

	// EventDealNotFound means a provider could not find a piece for a deal
	EventDealNotFound

	// EventDealAccepted means a provider accepted a deal
	EventDealAccepted

	// EventProviderCancelled means a provider has sent a message to cancel a deal
	EventProviderCancelled

	// EventUnknownResponseReceived means a client received a response it doesn't
	// understand from the provider
	EventUnknownResponseReceived

	// EventPaymentChannelErrored means there was a failure creating a payment channel
	EventPaymentChannelErrored

	// EventAllocateLaneErrored means there was a failure creating a lane in a payment channel
	EventAllocateLaneErrored

	// EventPaymentChannelCreateInitiated means we are waiting for a message to
	// create a payment channel to appear on chain
	EventPaymentChannelCreateInitiated

	// EventPaymentChannelReady means the newly created payment channel is ready for the
	// deal to resume
	EventPaymentChannelReady

	// EventPaymentChannelSkip means we can skip payment channel because the deal price is 0
	EventPaymentChannelSkip

	// EventPaymentChannelAddingFunds mean we are waiting for funds to be
	// added to a payment channel
	EventPaymentChannelAddingFunds

	// EventPaymentChannelAddFundsErrored means that adding funds to the payment channel
	// failed
	EventPaymentChannelAddFundsErrored

	// EventLastPaymentRequested indicates the provider requested a final payment
	EventLastPaymentRequested

	// EventAllBlocksReceived indicates the provider has sent all blocks
	EventAllBlocksReceived

	// EventPaymentRequested indicates the provider requested a payment
	EventPaymentRequested

	// EventPaymentNotSent indicates that payment was requested, but no
	// payment was actually due, so a voucher was not sent to the provider
	EventPaymentNotSent

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

	// EventBlocksReceived indicates the provider has sent blocks
	EventBlocksReceived

	// EventSendFunds emits when we reach the threshold to send the next payment
	EventSendFunds

	// EventFundsExpended indicates a deal has run out of funds in the payment channel
	// forcing the client to add more funds to continue the deal
	EventFundsExpended // when totalFunds is expended

	// EventBadPaymentRequested indicates the provider asked for funds
	// in a way that does not match the terms of the deal
	EventBadPaymentRequested

	// EventCreateVoucherFailed indicates an error happened creating a payment voucher
	EventCreateVoucherFailed

	// EventWriteDealPaymentErrored indicates a network error trying to write a payment
	EventWriteDealPaymentErrored

	// EventPaymentSent indicates a payment was sent to the provider
	EventPaymentSent

	// EventComplete indicates a deal has completed
	EventComplete

	// EventDataTransferError emits when something go wrong at the data transfer level
	EventDataTransferError

	// EventCancelComplete happens when a deal cancellation is transmitted to the provider
	EventCancelComplete

	// EventEarlyTermination indications a provider send a deal complete without sending all data
	EventEarlyTermination

	// EventCompleteVerified means that a provider completed without requesting a final payment but
	// we verified we received all data
	EventCompleteVerified

	// EventLaneAllocated is called when a lane is allocated
	EventLaneAllocated

	// EventVoucherShortfall means we tried to create a voucher but did not have enough funds in channel
	// to create it
	EventVoucherShortfall

	// EventRecheckFunds runs when an external caller indicates there may be new funds in a payment channel
	EventRecheckFunds

	// EventCancel runs when a user cancels a deal
	EventCancel

	// EventWaitForLastBlocks is fired when the provider has told
	// the client that all blocks were sent for the deal, and the client is
	// waiting for the last blocks to arrive
	EventWaitForLastBlocks

	// EventProviderErrored happens when we receive a status in response voucher
	// telling us something went wrong on the provider side but they don't know what (500)
	EventProviderErrored
)

type EventReceiver

type EventReceiver interface {
	Has(id interface{}) (bool, error) // Check if we have any state before sending
	Send(id interface{}, name fsm.EventName, args ...interface{}) (err error)
}

EventReceiver is any thing that can receive FSM events

type InternalEvent

type InternalEvent struct {
	Evt   Event
	State deal.ClientState
}

InternalEvent is an atomic state change in the client

type Subscriber

type Subscriber func(event Event, state deal.ClientState)

Subscriber is a callback that is registered to listen for retrieval events

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL