Skip to content

Commit

Permalink
passing tests! 'and there was much rejoicing:' yaaaaay.
Browse files Browse the repository at this point in the history
  • Loading branch information
shannonwells committed Apr 10, 2020
1 parent 1d33549 commit 44e543e
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 63 deletions.
26 changes: 8 additions & 18 deletions retrievalmarket/impl/clientstates/client_fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,13 @@ var ClientEvents = fsm.Events{
fsm.Event(rm.ClientEventPaymentChannelCreateInitiated).
From(rm.DealStatusAccepted).To(rm.DealStatusPaymentChannelCreating).
Action(func(deal *rm.ClientDealState, msgCID cid.Cid) error {
// WaitForPaychCreate, triggers ClientEventPaymentChannelCreated
deal.WaitMsgCID = &msgCID
return nil
}),
fsm.Event(rm.ClientEventPaymentChannelCreated).
From(rm.DealStatusPaymentChannelCreating).ToNoChange().
Action(func(deal *rm.ClientDealState, paych address.Address) error {
// AllocateLane, triggers ClientEventPaymentChannelReady
return nil
}),
}),
fsm.Event(rm.ClientEventPaymentChannelAddingFunds).
From(rm.DealStatusPaymentChannelReady).To(rm.DealStatusPaymentChannelAddingFunds),
fsm.Event(rm.ClientEventPaymentChannelReady).
FromMany(rm.DealStatusPaymentChannelCreating, rm.ClientEventPaymentChannelFundsAdded).
FromMany(rm.DealStatusPaymentChannelCreating, rm.DealStatusPaymentChannelAddingFunds).
To(rm.DealStatusPaymentChannelReady).
Action(func(deal *rm.ClientDealState, payCh address.Address, lane uint64) error {
deal.PaymentInfo = &rm.PaymentInfo{
Expand All @@ -56,12 +52,6 @@ var ClientEvents = fsm.Events{
}
return nil
}),
fsm.Event(rm.ClientEventPaymentChannelAddingFunds).
From(rm.DealStatusPaymentChannelReady).To(rm.DealStatusPaymentChannelAddingFunds).
Action(func(deal *rm.ClientDealState, paych address.Address, msgCID cid.Cid) error {
// WaitForPaychAddFunds, triggers ClientEventPaychFundsAdded
return nil
}),
fsm.Event(rm.ClientEventAllocateLaneErrored).
From(rm.DealStatusAccepted).To(rm.DealStatusFailed).
Action(func(deal *rm.ClientDealState, err error) error {
Expand Down Expand Up @@ -182,9 +172,9 @@ var ClientEvents = fsm.Events{
// ClientStateEntryFuncs are the handlers for different states in a retrieval client
var ClientStateEntryFuncs = fsm.StateEntryFuncs{
rm.DealStatusNew: ProposeDeal,
rm.DealStatusAccepted: SetupPaymentChannel,
rm.DealStatusPaymentChannelCreating: ProcessNextResponse,
rm.DealStatusPaymentChannelAddingFunds: ProcessNextResponse,
rm.DealStatusAccepted: SetupPaymentChannelStart,
rm.DealStatusPaymentChannelCreating: WaitForPaymentChannelCreate,
rm.DealStatusPaymentChannelAddingFunds: WaitForPaymentChannelAddFunds,
rm.DealStatusPaymentChannelReady: ProcessNextResponse,
rm.DealStatusOngoing: ProcessNextResponse,
rm.DealStatusBlocksComplete: ProcessNextResponse,
Expand Down
46 changes: 36 additions & 10 deletions retrievalmarket/impl/clientstates/client_states.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ type ClientDealEnvironment interface {
ConsumeBlock(context.Context, rm.DealID, rm.Block) (uint64, bool, error)
}

// SetupPaymentChannel sets up a payment channel for a deal
func SetupPaymentChannel(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error {
// SetupPaymentChannelStart sets up a payment channel for a deal
func SetupPaymentChannelStart(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error {
tok, _, err := environment.Node().GetChainHead(ctx.Context())
if err != nil {
return ctx.Trigger(rm.ClientEventPaymentChannelErrored, err)
Expand All @@ -30,14 +30,40 @@ func SetupPaymentChannel(ctx fsm.Context, environment ClientDealEnvironment, dea
if err != nil {
return ctx.Trigger(rm.ClientEventPaymentChannelErrored, err)
}
if paych == address.Undef {
return ctx.Trigger(rm.ClientEventPaymentChannelCreateInitiated)

if paych == address.Undef {
return ctx.Trigger(rm.ClientEventPaymentChannelCreateInitiated, msgCID)
}

return ctx.Trigger(rm.ClientEventPaymentChannelAddingFunds)
}

// WaitForPaymentChannelCreate waits for payment channel creation to be posted on chain,
// allocates a lane for vouchers, then signals that the payment channel is ready
func WaitForPaymentChannelCreate(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error {
paych, err := environment.Node().WaitForPaymentChannelCreation(*deal.WaitMsgCID)
if err != nil {
return ctx.Trigger(rm.ClientEventPaymentChannelErrored, err)
}
// if successful call allocate lane and trigger ClientEventPaymentChannelReady evt

lane, err := environment.Node().AllocateLane(paych)
if err != nil {
return ctx.Trigger(rm.ClientEventAllocateLaneErrored, err)
}
return ctx.Trigger(rm.ClientEventPaymentChannelReady, paych, lane)
}

// WaitForPaymentChannelAddFunds waits for funds to be added to a payment channel, then
// signals that payment channel is ready again
func WaitForPaymentChannelAddFunds(ctx fsm.Context, environment ClientDealEnvironment, deal rm.ClientDealState) error {
// call wait for funds to be added func,
err := environment.Node().WaitForPaymentChannelAddFunds(*deal.WaitMsgCID)
if err != nil {
return ctx.Trigger(rm.ClientEventPaymentChannelErrored, err)
}
//lane, err := environment.Node().AllocateLane(paych)
//if err != nil {
// return ctx.Trigger(rm.ClientEventAllocateLaneErrored, err)
//}
return ctx.Trigger(rm.ClientEventPaymentChannelAddingFunds, paych, msgCID)
// then trigger ClientEventPaymentChannelReady evt
return ctx.Trigger(rm.ClientEventPaymentChannelReady, deal.PaymentInfo.PayCh, deal.PaymentInfo.Lane)
}

// ProposeDeal sends the proposal to the other party
Expand Down Expand Up @@ -151,7 +177,7 @@ func ProcessNextResponse(ctx fsm.Context, environment ClientDealEnvironment, dea
return ctx.Trigger(rm.ClientEventEarlyTermination)
case rm.DealStatusFundsNeeded:
return ctx.Trigger(rm.ClientEventPaymentRequested, totalProcessed, response.PaymentOwed)
case rm.DealStatusOngoing:
case rm.DealStatusOngoing, rm.DealStatusPaymentChannelReady:
return ctx.Trigger(rm.ClientEventBlocksReceived, totalProcessed)
default:
return ctx.Trigger(rm.ClientEventUnknownResponseReceived)
Expand Down
43 changes: 28 additions & 15 deletions retrievalmarket/impl/clientstates/client_states_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,45 +66,58 @@ func TestSetupPaymentChannel(t *testing.T) {
node := testnodes.NewTestRetrievalClientNode(params)
environment := &fakeEnvironment{node, ds, 0, nil}
fsmCtx := fsmtest.NewTestContext(ctx, eventMachine)
err := clientstates.SetupPaymentChannel(fsmCtx, environment, *dealState)
err := clientstates.SetupPaymentChannelStart(fsmCtx, environment, *dealState)
require.NoError(t, err)
fsmCtx.ReplayEvents(t, dealState)
}

t.Run("payment channel create initiated", func(t *testing.T) {
envParams := testnodes.TestRetrievalClientNodeParams{
PayCh: address.Undef,
CreatePaychCID: testnet.GenerateCids(1)[0],
PayCh: address.Undef,
CreatePaychCID: testnet.GenerateCids(1)[0],
}
dealState := makeDealState(retrievalmarket.DealStatusAccepted)
runSetupPaymentChannel(t, envParams, dealState)
require.NotEmpty(t, dealState.Message)
require.Empty(t, dealState.Message)
require.Equal(t, dealState.Status, retrievalmarket.DealStatusPaymentChannelCreating)
})

t.Run("when create payment channel fails", func(t *testing.T) {
dealState := makeDealState(retrievalmarket.DealStatusAccepted)
t.Run("payment channel needs funds added", func(t *testing.T) {
envParams := testnodes.TestRetrievalClientNodeParams{
PayCh: address.Undef,
PayChErr: errors.New("Something went wrong"),
Lane: expectedLane,
AddFundsOnly: true,
PayCh: expectedPayCh,
CreatePaychCID: testnet.GenerateCids(1)[0],
}
dealState := makeDealState(retrievalmarket.DealStatusPaymentChannelReady)
runSetupPaymentChannel(t, envParams, dealState)
require.NotEmpty(t, dealState.Message)
require.Equal(t, dealState.Status, retrievalmarket.DealStatusFailed)
require.Empty(t, dealState.Message)
require.Equal(t, dealState.Status, retrievalmarket.DealStatusPaymentChannelAddingFunds)
})

t.Run("when allocate lane fails", func(t *testing.T) {
t.Run("when create payment channel fails", func(t *testing.T) {
dealState := makeDealState(retrievalmarket.DealStatusAccepted)
envParams := testnodes.TestRetrievalClientNodeParams{
PayCh: expectedPayCh,
Lane: expectedLane,
LaneError: errors.New("Something went wrong"),
PayCh: address.Undef,
PayChErr: errors.New("Something went wrong"),
Lane: expectedLane,
}
runSetupPaymentChannel(t, envParams, dealState)
require.NotEmpty(t, dealState.Message)
require.Equal(t, dealState.Status, retrievalmarket.DealStatusFailed)
})

// TODO: find the right place for this test
//t.Run("when allocate lane fails", func(t *testing.T) {
// dealState := makeDealState(retrievalmarket.ClientEventPaymentChannelAddingFunds)
// envParams := testnodes.TestRetrievalClientNodeParams{
// PayCh: expectedPayCh,
// Lane: expectedLane,
// LaneError: errors.New("Something went wrong"),
// }
// runSetupPaymentChannel(t, envParams, dealState)
// require.NotEmpty(t, dealState.Message)
// require.Equal(t, dealState.Status, retrievalmarket.DealStatusFailed)
//})
}

func TestProposeDeal(t *testing.T) {
Expand Down
10 changes: 9 additions & 1 deletion retrievalmarket/impl/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,12 @@ func requireSetupTestClientAndProvider(bgCtx context.Context, t *testing.T, payC
retrievalmarket.RetrievalProvider) {
testData := tut.NewLibp2pTestData(bgCtx, t)
nw1 := rmnet.NewFromLibp2pHost(testData.Host1)
rcNode1 := testnodes.NewTestRetrievalClientNode(testnodes.TestRetrievalClientNodeParams{PayCh: payChAddr})
cids := tut.GenerateCids(2)
rcNode1 := testnodes.NewTestRetrievalClientNode(testnodes.TestRetrievalClientNodeParams{
PayCh: payChAddr,
CreatePaychCID: cids[0],
AddFundsCID: cids[1],
})
client, err := retrievalimpl.NewClient(nw1, testData.Bs1, rcNode1, &testPeerResolver{}, testData.Ds1, testData.StoredCounter1)
require.NoError(t, err)
nw2 := rmnet.NewFromLibp2pHost(testData.Host2)
Expand Down Expand Up @@ -389,13 +394,16 @@ func setupClient(
paymentVoucherRecorder := func(v *paych.SignedVoucher) {
createdVoucher = *v
}
cids := tut.GenerateCids(2)
clientNode := testnodes.NewTestRetrievalClientNode(testnodes.TestRetrievalClientNodeParams{
PayCh: clientPaymentChannel,
Lane: expectedVoucher.Lane,
Voucher: expectedVoucher,
PaymentChannelRecorder: paymentChannelRecorder,
AllocateLaneRecorder: laneRecorder,
PaymentVoucherRecorder: paymentVoucherRecorder,
CreatePaychCID: cids[0],
AddFundsCID: cids[1],
})
client, err := retrievalimpl.NewClient(nw1, testData.Bs1, clientNode, &testPeerResolver{}, testData.Ds1, testData.StoredCounter1)
return &createdChan, &newLaneAddr, &createdVoucher, client, err
Expand Down
48 changes: 32 additions & 16 deletions retrievalmarket/impl/testnodes/test_retrieval_client_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ import (
// TestRetrievalClientNode is a node adapter for a retrieval client whose responses
// are stubbed
type TestRetrievalClientNode struct {
payCh address.Address
payChErr error
addFundsOnly bool // set this to true if the payment channel is expected to have been created already
payCh address.Address
payChErr error
createPaychMsgCID, addFundsMsgCID cid.Cid
lane uint64
laneError error
voucher *paych.SignedVoucher
voucherError error
lane uint64
laneError error
voucher *paych.SignedVoucher
voucherError error

allocateLaneRecorder func(address.Address)
createPaymentVoucherRecorder func(voucher *paych.SignedVoucher)
Expand All @@ -30,23 +31,25 @@ type TestRetrievalClientNode struct {

// TestRetrievalClientNodeParams are parameters for initializing a TestRetrievalClientNode
type TestRetrievalClientNodeParams struct {
PayCh address.Address
PayChErr error
PayCh address.Address
PayChErr error
CreatePaychCID, AddFundsCID cid.Cid
Lane uint64
LaneError error
Voucher *paych.SignedVoucher
VoucherError error
AllocateLaneRecorder func(address.Address)
PaymentVoucherRecorder func(voucher *paych.SignedVoucher)
PaymentChannelRecorder func(address.Address, address.Address, abi.TokenAmount)
Lane uint64
LaneError error
Voucher *paych.SignedVoucher
VoucherError error
AllocateLaneRecorder func(address.Address)
PaymentVoucherRecorder func(voucher *paych.SignedVoucher)
PaymentChannelRecorder func(address.Address, address.Address, abi.TokenAmount)
AddFundsOnly bool
}

var _ retrievalmarket.RetrievalClientNode = &TestRetrievalClientNode{}

// NewTestRetrievalClientNode instantiates a new TestRetrievalClientNode based ont he given params
func NewTestRetrievalClientNode(params TestRetrievalClientNodeParams) *TestRetrievalClientNode {
return &TestRetrievalClientNode{
addFundsOnly: params.AddFundsOnly,
payCh: params.PayCh,
payChErr: params.PayChErr,
lane: params.Lane,
Expand All @@ -56,6 +59,8 @@ func NewTestRetrievalClientNode(params TestRetrievalClientNodeParams) *TestRetri
allocateLaneRecorder: params.AllocateLaneRecorder,
createPaymentVoucherRecorder: params.PaymentVoucherRecorder,
getCreatePaymentChannelRecorder: params.PaymentChannelRecorder,
createPaychMsgCID: params.CreatePaychCID,
addFundsMsgCID: params.AddFundsCID,
}
}

Expand All @@ -64,7 +69,11 @@ func (trcn *TestRetrievalClientNode) GetOrCreatePaymentChannel(ctx context.Conte
if trcn.getCreatePaymentChannelRecorder != nil {
trcn.getCreatePaymentChannelRecorder(clientAddress, minerAddress, clientFundsAvailable)
}
return trcn.payCh, trcn.createPaychMsgCID, trcn.payChErr
var payCh address.Address
if trcn.addFundsOnly {
payCh = trcn.payCh
}
return payCh, trcn.createPaychMsgCID, trcn.payChErr
}

// AllocateLane creates a mock lane on a payment channel
Expand All @@ -86,3 +95,10 @@ func (trcn *TestRetrievalClientNode) CreatePaymentVoucher(ctx context.Context, p
func (trcn *TestRetrievalClientNode) GetChainHead(ctx context.Context) (shared.TipSetToken, abi.ChainEpoch, error) {
return shared.TipSetToken{}, 0, nil
}
func (trcn *TestRetrievalClientNode) WaitForPaymentChannelAddFunds(messageCID cid.Cid) error {
return nil
}

func (trcn *TestRetrievalClientNode) WaitForPaymentChannelCreation(messageCID cid.Cid) (address.Address, error) {
return trcn.payCh, nil
}
14 changes: 13 additions & 1 deletion retrievalmarket/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type ClientDealState struct {
CurrentInterval uint64
PaymentRequested abi.TokenAmount
FundsSpent abi.TokenAmount
WaitMsgCID *cid.Cid // the CID of any message the client deal is waiting for
}

// ClientEvent is an event that occurs in a deal lifecycle on the client
Expand Down Expand Up @@ -209,6 +210,14 @@ type RetrievalClientNode interface {
// given payment channel so that all the payment vouchers in the lane add up
// to the given amount (so the payment voucher will be for the difference)
CreatePaymentVoucher(ctx context.Context, paymentChannel address.Address, amount abi.TokenAmount, lane uint64, tok shared.TipSetToken) (*paych.SignedVoucher, error)

// WaitForPaymentChannelAddFunds waits for a message on chain that funds have
// been sent to a payment channel
WaitForPaymentChannelAddFunds(messageCID cid.Cid) error

// WaitForPaymentChannelCreation waits for a message on chain that a
// payment channel has been created
WaitForPaymentChannelCreation(messageCID cid.Cid) (address.Address, error)
}

// ProviderDealState is the current state of a deal from the point of view
Expand Down Expand Up @@ -460,6 +469,9 @@ const (
// to finish being sent to the payment channel
DealStatusPaymentChannelAddingFunds

// DealStatusPaymentChannelAllocatingLane is the status during lane allocation
DealStatusPaymentChannelAllocatingLane

// DealStatusPaymentChannelReady is a deal status that has a payment channel
// & lane setup
DealStatusPaymentChannelReady
Expand Down Expand Up @@ -510,7 +522,7 @@ const (
// DealStatuses maps deal status to a human readable representation
var DealStatuses = map[DealStatus]string{
DealStatusNew: "DealStatusNew",
DealStatusPaymentChannelCreating: "DealStatusPaymentChannelCreating",
DealStatusPaymentChannelCreating: "DealStatusPaymentChannelCreating",
DealStatusAccepted: "DealStatusAccepted",
DealStatusFailed: "DealStatusFailed",
DealStatusRejected: "DealStatusRejected",
Expand Down
Loading

0 comments on commit 44e543e

Please sign in to comment.