paych: Test pre-funding
This commit is contained in:
parent
8e46b9ea5d
commit
9715113898
@ -1976,18 +1976,18 @@ func (mr *MockFullNodeMockRecorder) PaychCollect(arg0, arg1 interface{}) *gomock
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PaychGet mocks base method.
|
// PaychGet mocks base method.
|
||||||
func (m *MockFullNode) PaychGet(arg0 context.Context, arg1, arg2 address.Address, arg3 big.Int) (*api.ChannelInfo, error) {
|
func (m *MockFullNode) PaychGet(arg0 context.Context, arg1, arg2 address.Address, arg3 big.Int, arg4 bool) (*api.ChannelInfo, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "PaychGet", arg0, arg1, arg2, arg3)
|
ret := m.ctrl.Call(m, "PaychGet", arg0, arg1, arg2, arg3, arg4)
|
||||||
ret0, _ := ret[0].(*api.ChannelInfo)
|
ret0, _ := ret[0].(*api.ChannelInfo)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaychGet indicates an expected call of PaychGet.
|
// PaychGet indicates an expected call of PaychGet.
|
||||||
func (mr *MockFullNodeMockRecorder) PaychGet(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
func (mr *MockFullNodeMockRecorder) PaychGet(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PaychGet", reflect.TypeOf((*MockFullNode)(nil).PaychGet), arg0, arg1, arg2, arg3)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PaychGet", reflect.TypeOf((*MockFullNode)(nil).PaychGet), arg0, arg1, arg2, arg3, arg4)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PaychGetWaitReady mocks base method.
|
// PaychGetWaitReady mocks base method.
|
||||||
|
@ -4509,7 +4509,11 @@ Response:
|
|||||||
```
|
```
|
||||||
|
|
||||||
### PaychGet
|
### PaychGet
|
||||||
There are not yet any comments for this method.
|
PaychGet gets or creates a payment channel between address pair
|
||||||
|
- If reserve is false, the specified amount will be added to the channel through on-chain send for future use
|
||||||
|
- If reserve is true, the specified amount will be reserved for use. If there aren't enough non-reserved funds
|
||||||
|
available, funds will be added through an on-chain message.
|
||||||
|
|
||||||
|
|
||||||
Perms: sign
|
Perms: sign
|
||||||
|
|
||||||
@ -4518,7 +4522,8 @@ Inputs:
|
|||||||
[
|
[
|
||||||
"f01234",
|
"f01234",
|
||||||
"f01234",
|
"f01234",
|
||||||
"0"
|
"0",
|
||||||
|
true
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ func TestPaychGetCreateChannelMsg(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
ch, mcid, err := mgr.GetPaych(ctx, from, to, amt)
|
ch, mcid, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, address.Undef, ch)
|
require.Equal(t, address.Undef, ch)
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ func TestPaychGetCreateChannelThenAddFunds(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel with value 10
|
// Send create message for a channel with value 10
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, amt)
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Should have no channels yet (message sent but channel not created)
|
// Should have no channels yet (message sent but channel not created)
|
||||||
@ -100,7 +100,7 @@ func TestPaychGetCreateChannelThenAddFunds(t *testing.T) {
|
|||||||
|
|
||||||
// 2. Request add funds - should block until create channel has completed
|
// 2. Request add funds - should block until create channel has completed
|
||||||
amt2 := big.NewInt(5)
|
amt2 := big.NewInt(5)
|
||||||
ch2, addFundsMsgCid, err := mgr.GetPaych(ctx, from, to, amt2)
|
ch2, addFundsMsgCid, err := mgr.GetPaych(ctx, from, to, amt2, true)
|
||||||
|
|
||||||
// 4. This GetPaych should return after create channel from first
|
// 4. This GetPaych should return after create channel from first
|
||||||
// GetPaych completes
|
// GetPaych completes
|
||||||
@ -154,6 +154,74 @@ func TestPaychGetCreateChannelThenAddFunds(t *testing.T) {
|
|||||||
<-done
|
<-done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPaychGetCreatePrefundedChannelThenAddFunds(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||||
|
|
||||||
|
ch := tutils.NewIDAddr(t, 100)
|
||||||
|
from := tutils.NewIDAddr(t, 101)
|
||||||
|
to := tutils.NewIDAddr(t, 102)
|
||||||
|
|
||||||
|
mock := newMockManagerAPI()
|
||||||
|
defer mock.close()
|
||||||
|
|
||||||
|
mgr, err := newManager(store, mock)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Send create message for a channel with value 10
|
||||||
|
amt := big.NewInt(10)
|
||||||
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, amt, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Should have no channels yet (message sent but channel not created)
|
||||||
|
cis, err := mgr.ListChannels(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, cis, 0)
|
||||||
|
|
||||||
|
// 1. Set up create channel response (sent in response to WaitForMsg())
|
||||||
|
response := testChannelResponse(t, ch)
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
defer close(done)
|
||||||
|
|
||||||
|
// 2. Request add funds - shouldn't block
|
||||||
|
amt2 := big.NewInt(3)
|
||||||
|
ch2, addFundsMsgCid, err := mgr.GetPaych(ctx, from, to, amt2, true)
|
||||||
|
|
||||||
|
// 4. This GetPaych should return after create channel from first
|
||||||
|
// GetPaych completes
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Expect the channel to be the same
|
||||||
|
require.Equal(t, ch, ch2)
|
||||||
|
require.Equal(t, cid.Undef, addFundsMsgCid)
|
||||||
|
|
||||||
|
// Should have one channel, whose address is the channel that was created
|
||||||
|
cis, err := mgr.ListChannels(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, cis, 1)
|
||||||
|
require.Equal(t, ch, cis[0])
|
||||||
|
|
||||||
|
// Amount should be amount sent to first GetPaych (to create
|
||||||
|
// channel).
|
||||||
|
// PendingAmount should be zero, AvailableAmount should be Amount minus what we requested
|
||||||
|
|
||||||
|
ci, err := mgr.GetChannelInfo(ctx, ch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 10, ci.Amount.Int64())
|
||||||
|
require.EqualValues(t, 0, ci.PendingAmount.Int64())
|
||||||
|
require.EqualValues(t, 7, ci.AvailableAmount.Int64())
|
||||||
|
require.Nil(t, ci.CreateMsg)
|
||||||
|
require.Nil(t, ci.AddFundsMsg)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 3. Send create channel response
|
||||||
|
mock.receiveMsgResponse(createMsgCid, response)
|
||||||
|
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
|
||||||
// TestPaychGetCreateChannelWithErrorThenCreateAgain tests that if an
|
// TestPaychGetCreateChannelWithErrorThenCreateAgain tests that if an
|
||||||
// operation is queued up behind a create channel operation, and the create
|
// operation is queued up behind a create channel operation, and the create
|
||||||
// channel fails, then the waiting operation can succeed.
|
// channel fails, then the waiting operation can succeed.
|
||||||
@ -172,7 +240,7 @@ func TestPaychGetCreateChannelWithErrorThenCreateAgain(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel
|
// Send create message for a channel
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, mcid1, err := mgr.GetPaych(ctx, from, to, amt)
|
_, mcid1, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// 1. Set up create channel response (sent in response to WaitForMsg())
|
// 1. Set up create channel response (sent in response to WaitForMsg())
|
||||||
@ -190,7 +258,7 @@ func TestPaychGetCreateChannelWithErrorThenCreateAgain(t *testing.T) {
|
|||||||
// Because first channel create fails, this request
|
// Because first channel create fails, this request
|
||||||
// should be for channel create again.
|
// should be for channel create again.
|
||||||
amt2 := big.NewInt(5)
|
amt2 := big.NewInt(5)
|
||||||
ch2, mcid2, err := mgr.GetPaych(ctx, from, to, amt2)
|
ch2, mcid2, err := mgr.GetPaych(ctx, from, to, amt2, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, address.Undef, ch2)
|
require.Equal(t, address.Undef, ch2)
|
||||||
|
|
||||||
@ -237,7 +305,7 @@ func TestPaychGetRecoverAfterError(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel
|
// Send create message for a channel
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, mcid, err := mgr.GetPaych(ctx, from, to, amt)
|
_, mcid, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Send error create channel response
|
// Send error create channel response
|
||||||
@ -248,7 +316,7 @@ func TestPaychGetRecoverAfterError(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel again
|
// Send create message for a channel again
|
||||||
amt2 := big.NewInt(7)
|
amt2 := big.NewInt(7)
|
||||||
_, mcid2, err := mgr.GetPaych(ctx, from, to, amt2)
|
_, mcid2, err := mgr.GetPaych(ctx, from, to, amt2, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Send success create channel response
|
// Send success create channel response
|
||||||
@ -289,7 +357,7 @@ func TestPaychGetRecoverAfterAddFundsError(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel
|
// Send create message for a channel
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, mcid1, err := mgr.GetPaych(ctx, from, to, amt)
|
_, mcid1, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Send success create channel response
|
// Send success create channel response
|
||||||
@ -298,7 +366,7 @@ func TestPaychGetRecoverAfterAddFundsError(t *testing.T) {
|
|||||||
|
|
||||||
// Send add funds message for channel
|
// Send add funds message for channel
|
||||||
amt2 := big.NewInt(5)
|
amt2 := big.NewInt(5)
|
||||||
_, mcid2, err := mgr.GetPaych(ctx, from, to, amt2)
|
_, mcid2, err := mgr.GetPaych(ctx, from, to, amt2, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Send error add funds response
|
// Send error add funds response
|
||||||
@ -325,7 +393,7 @@ func TestPaychGetRecoverAfterAddFundsError(t *testing.T) {
|
|||||||
|
|
||||||
// Send add funds message for channel again
|
// Send add funds message for channel again
|
||||||
amt3 := big.NewInt(2)
|
amt3 := big.NewInt(2)
|
||||||
_, mcid3, err := mgr.GetPaych(ctx, from, to, amt3)
|
_, mcid3, err := mgr.GetPaych(ctx, from, to, amt3, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Send success add funds response
|
// Send success add funds response
|
||||||
@ -370,7 +438,7 @@ func TestPaychGetRestartAfterCreateChannelMsg(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel with value 10
|
// Send create message for a channel with value 10
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, amt)
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Simulate shutting down system
|
// Simulate shutting down system
|
||||||
@ -397,7 +465,7 @@ func TestPaychGetRestartAfterCreateChannelMsg(t *testing.T) {
|
|||||||
|
|
||||||
// 2. Request add funds - should block until create channel has completed
|
// 2. Request add funds - should block until create channel has completed
|
||||||
amt2 := big.NewInt(5)
|
amt2 := big.NewInt(5)
|
||||||
ch2, addFundsMsgCid, err := mgr2.GetPaych(ctx, from, to, amt2)
|
ch2, addFundsMsgCid, err := mgr2.GetPaych(ctx, from, to, amt2, true)
|
||||||
|
|
||||||
// 4. This GetPaych should return after create channel from first
|
// 4. This GetPaych should return after create channel from first
|
||||||
// GetPaych completes
|
// GetPaych completes
|
||||||
@ -449,7 +517,7 @@ func TestPaychGetRestartAfterAddFundsMsg(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel
|
// Send create message for a channel
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, mcid1, err := mgr.GetPaych(ctx, from, to, amt)
|
_, mcid1, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Send success create channel response
|
// Send success create channel response
|
||||||
@ -458,7 +526,7 @@ func TestPaychGetRestartAfterAddFundsMsg(t *testing.T) {
|
|||||||
|
|
||||||
// Send add funds message for channel
|
// Send add funds message for channel
|
||||||
amt2 := big.NewInt(5)
|
amt2 := big.NewInt(5)
|
||||||
_, mcid2, err := mgr.GetPaych(ctx, from, to, amt2)
|
_, mcid2, err := mgr.GetPaych(ctx, from, to, amt2, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Simulate shutting down system
|
// Simulate shutting down system
|
||||||
@ -512,7 +580,7 @@ func TestPaychGetWait(t *testing.T) {
|
|||||||
|
|
||||||
// 1. Get
|
// 1. Get
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, amt)
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
expch := tutils.NewIDAddr(t, 100)
|
expch := tutils.NewIDAddr(t, 100)
|
||||||
@ -535,7 +603,7 @@ func TestPaychGetWait(t *testing.T) {
|
|||||||
|
|
||||||
// Request add funds
|
// Request add funds
|
||||||
amt2 := big.NewInt(15)
|
amt2 := big.NewInt(15)
|
||||||
_, addFundsMsgCid, err := mgr.GetPaych(ctx, from, to, amt2)
|
_, addFundsMsgCid, err := mgr.GetPaych(ctx, from, to, amt2, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -569,7 +637,7 @@ func TestPaychGetWaitErr(t *testing.T) {
|
|||||||
|
|
||||||
// 1. Create channel
|
// 1. Create channel
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, mcid, err := mgr.GetPaych(ctx, from, to, amt)
|
_, mcid, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
done := make(chan address.Address)
|
done := make(chan address.Address)
|
||||||
@ -615,7 +683,7 @@ func TestPaychGetWaitCtx(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, mcid, err := mgr.GetPaych(ctx, from, to, amt)
|
_, mcid, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// When the context is cancelled, should unblock wait
|
// When the context is cancelled, should unblock wait
|
||||||
@ -646,7 +714,7 @@ func TestPaychGetMergeAddFunds(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel with value 10
|
// Send create message for a channel with value 10
|
||||||
createAmt := big.NewInt(10)
|
createAmt := big.NewInt(10)
|
||||||
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt)
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Queue up two add funds requests behind create channel
|
// Queue up two add funds requests behind create channel
|
||||||
@ -664,7 +732,7 @@ func TestPaychGetMergeAddFunds(t *testing.T) {
|
|||||||
|
|
||||||
// Request add funds - should block until create channel has completed
|
// Request add funds - should block until create channel has completed
|
||||||
var err error
|
var err error
|
||||||
addFundsCh1, addFundsMcid1, err = mgr.GetPaych(ctx, from, to, addFundsAmt1)
|
addFundsCh1, addFundsMcid1, err = mgr.GetPaych(ctx, from, to, addFundsAmt1, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -673,7 +741,7 @@ func TestPaychGetMergeAddFunds(t *testing.T) {
|
|||||||
|
|
||||||
// Request add funds again - should merge with waiting add funds request
|
// Request add funds again - should merge with waiting add funds request
|
||||||
var err error
|
var err error
|
||||||
addFundsCh2, addFundsMcid2, err = mgr.GetPaych(ctx, from, to, addFundsAmt2)
|
addFundsCh2, addFundsMcid2, err = mgr.GetPaych(ctx, from, to, addFundsAmt2, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
// Wait for add funds requests to be queued up
|
// Wait for add funds requests to be queued up
|
||||||
@ -726,6 +794,199 @@ func TestPaychGetMergeAddFunds(t *testing.T) {
|
|||||||
require.Equal(t, types.BigAdd(addFundsAmt1, addFundsAmt2), addFundsMsg.Message.Value)
|
require.Equal(t, types.BigAdd(addFundsAmt1, addFundsAmt2), addFundsMsg.Message.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPaychGetMergePrefundAndReserve(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||||
|
|
||||||
|
ch := tutils.NewIDAddr(t, 100)
|
||||||
|
from := tutils.NewIDAddr(t, 101)
|
||||||
|
to := tutils.NewIDAddr(t, 102)
|
||||||
|
|
||||||
|
mock := newMockManagerAPI()
|
||||||
|
defer mock.close()
|
||||||
|
|
||||||
|
mgr, err := newManager(store, mock)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Send create message for a channel with value 10
|
||||||
|
createAmt := big.NewInt(10)
|
||||||
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Queue up two add funds requests behind create channel
|
||||||
|
var addFundsSent sync.WaitGroup
|
||||||
|
addFundsSent.Add(2)
|
||||||
|
|
||||||
|
addFundsAmt1 := big.NewInt(5) // 1 prefunds
|
||||||
|
addFundsAmt2 := big.NewInt(3) // 2 reserves
|
||||||
|
var addFundsCh1 address.Address
|
||||||
|
var addFundsCh2 address.Address
|
||||||
|
var addFundsMcid1 cid.Cid
|
||||||
|
var addFundsMcid2 cid.Cid
|
||||||
|
go func() {
|
||||||
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
|
// Request add funds - should block until create channel has completed
|
||||||
|
var err error
|
||||||
|
addFundsCh1, addFundsMcid1, err = mgr.GetPaych(ctx, from, to, addFundsAmt1, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
|
// Request add funds again - should merge with waiting add funds request
|
||||||
|
var err error
|
||||||
|
addFundsCh2, addFundsMcid2, err = mgr.GetPaych(ctx, from, to, addFundsAmt2, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
// Wait for add funds requests to be queued up
|
||||||
|
waitForQueueSize(t, mgr, from, to, 2)
|
||||||
|
|
||||||
|
// Send create channel response
|
||||||
|
response := testChannelResponse(t, ch)
|
||||||
|
mock.receiveMsgResponse(createMsgCid, response)
|
||||||
|
|
||||||
|
// Wait for create channel response
|
||||||
|
chres, err := mgr.GetPaychWaitReady(ctx, createMsgCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ch, chres)
|
||||||
|
|
||||||
|
// Wait for add funds requests to be sent
|
||||||
|
addFundsSent.Wait()
|
||||||
|
|
||||||
|
// Expect add funds requests to have same channel as create channel and
|
||||||
|
// same message cid as each other (because they should have been merged)
|
||||||
|
require.Equal(t, ch, addFundsCh1)
|
||||||
|
require.Equal(t, ch, addFundsCh2)
|
||||||
|
require.Equal(t, addFundsMcid1, addFundsMcid2)
|
||||||
|
|
||||||
|
// Send success add funds response
|
||||||
|
mock.receiveMsgResponse(addFundsMcid1, types.MessageReceipt{
|
||||||
|
ExitCode: 0,
|
||||||
|
Return: []byte{},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Wait for add funds response
|
||||||
|
addFundsCh, err := mgr.GetPaychWaitReady(ctx, addFundsMcid1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ch, addFundsCh)
|
||||||
|
|
||||||
|
// Make sure that one create channel message and one add funds message was
|
||||||
|
// sent
|
||||||
|
require.Equal(t, 2, mock.pushedMessageCount())
|
||||||
|
|
||||||
|
// Check create message amount is correct
|
||||||
|
createMsg := mock.pushedMessages(createMsgCid)
|
||||||
|
require.Equal(t, from, createMsg.Message.From)
|
||||||
|
require.Equal(t, lotusinit.Address, createMsg.Message.To)
|
||||||
|
require.Equal(t, createAmt, createMsg.Message.Value)
|
||||||
|
|
||||||
|
// Check merged add funds amount is the sum of the individual
|
||||||
|
// amounts
|
||||||
|
addFundsMsg := mock.pushedMessages(addFundsMcid1)
|
||||||
|
require.Equal(t, from, addFundsMsg.Message.From)
|
||||||
|
require.Equal(t, ch, addFundsMsg.Message.To)
|
||||||
|
require.Equal(t, types.BigAdd(addFundsAmt1, addFundsAmt2), addFundsMsg.Message.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPaychGetMergePrefundAndReservePrefunded(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||||
|
|
||||||
|
ch := tutils.NewIDAddr(t, 100)
|
||||||
|
from := tutils.NewIDAddr(t, 101)
|
||||||
|
to := tutils.NewIDAddr(t, 102)
|
||||||
|
|
||||||
|
mock := newMockManagerAPI()
|
||||||
|
defer mock.close()
|
||||||
|
|
||||||
|
mgr, err := newManager(store, mock)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Send create message for a channel with value 10
|
||||||
|
createAmt := big.NewInt(10)
|
||||||
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Queue up two add funds requests behind create channel
|
||||||
|
var addFundsSent sync.WaitGroup
|
||||||
|
addFundsSent.Add(2)
|
||||||
|
|
||||||
|
addFundsAmt1 := big.NewInt(5) // 1 prefunds
|
||||||
|
addFundsAmt2 := big.NewInt(3) // 2 reserves
|
||||||
|
var addFundsCh1 address.Address
|
||||||
|
var addFundsCh2 address.Address
|
||||||
|
var addFundsMcid1 cid.Cid
|
||||||
|
var addFundsMcid2 cid.Cid
|
||||||
|
go func() {
|
||||||
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
|
// Request add funds - should block until create channel has completed
|
||||||
|
var err error
|
||||||
|
addFundsCh1, addFundsMcid1, err = mgr.GetPaych(ctx, from, to, addFundsAmt1, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
|
// Request add funds again - should merge with waiting add funds request
|
||||||
|
var err error
|
||||||
|
addFundsCh2, addFundsMcid2, err = mgr.GetPaych(ctx, from, to, addFundsAmt2, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
// Wait for add funds requests to be queued up
|
||||||
|
waitForQueueSize(t, mgr, from, to, 2)
|
||||||
|
|
||||||
|
// Send create channel response
|
||||||
|
response := testChannelResponse(t, ch)
|
||||||
|
mock.receiveMsgResponse(createMsgCid, response)
|
||||||
|
|
||||||
|
// Wait for create channel response
|
||||||
|
chres, err := mgr.GetPaychWaitReady(ctx, createMsgCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ch, chres)
|
||||||
|
|
||||||
|
// Wait for add funds requests to be sent
|
||||||
|
addFundsSent.Wait()
|
||||||
|
|
||||||
|
// Expect add funds requests to have same channel as create channel and
|
||||||
|
// same message cid as each other (because they should have been merged)
|
||||||
|
require.Equal(t, ch, addFundsCh1)
|
||||||
|
require.Equal(t, ch, addFundsCh2)
|
||||||
|
require.NotEqual(t, cid.Undef, addFundsMcid1)
|
||||||
|
require.Equal(t, cid.Undef, addFundsMcid2)
|
||||||
|
|
||||||
|
// Send success add funds response
|
||||||
|
mock.receiveMsgResponse(addFundsMcid1, types.MessageReceipt{
|
||||||
|
ExitCode: 0,
|
||||||
|
Return: []byte{},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Wait for add funds response
|
||||||
|
addFundsCh, err := mgr.GetPaychWaitReady(ctx, addFundsMcid1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ch, addFundsCh)
|
||||||
|
|
||||||
|
// Make sure that one create channel message and one add funds message was
|
||||||
|
// sent
|
||||||
|
require.Equal(t, 2, mock.pushedMessageCount())
|
||||||
|
|
||||||
|
// Check create message amount is correct
|
||||||
|
createMsg := mock.pushedMessages(createMsgCid)
|
||||||
|
require.Equal(t, from, createMsg.Message.From)
|
||||||
|
require.Equal(t, lotusinit.Address, createMsg.Message.To)
|
||||||
|
require.Equal(t, createAmt, createMsg.Message.Value)
|
||||||
|
|
||||||
|
// Check merged add funds amount is the sum of the individual
|
||||||
|
// amounts
|
||||||
|
addFundsMsg := mock.pushedMessages(addFundsMcid1)
|
||||||
|
require.Equal(t, from, addFundsMsg.Message.From)
|
||||||
|
require.Equal(t, ch, addFundsMsg.Message.To)
|
||||||
|
require.Equal(t, addFundsAmt1, addFundsMsg.Message.Value)
|
||||||
|
}
|
||||||
|
|
||||||
// TestPaychGetMergeAddFundsCtxCancelOne tests that when a queued add funds
|
// TestPaychGetMergeAddFundsCtxCancelOne tests that when a queued add funds
|
||||||
// request is cancelled, its amount is removed from the total merged add funds
|
// request is cancelled, its amount is removed from the total merged add funds
|
||||||
func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) {
|
func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) {
|
||||||
@ -744,7 +1005,7 @@ func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel with value 10
|
// Send create message for a channel with value 10
|
||||||
createAmt := big.NewInt(10)
|
createAmt := big.NewInt(10)
|
||||||
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt)
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Queue up two add funds requests behind create channel
|
// Queue up two add funds requests behind create channel
|
||||||
@ -761,7 +1022,7 @@ func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) {
|
|||||||
defer addFundsSent.Done()
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
// Request add funds - should block until create channel has completed
|
// Request add funds - should block until create channel has completed
|
||||||
_, _, addFundsErr1 = mgr.GetPaych(addFundsCtx1, from, to, addFundsAmt1)
|
_, _, addFundsErr1 = mgr.GetPaych(addFundsCtx1, from, to, addFundsAmt1, true)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -769,7 +1030,7 @@ func TestPaychGetMergeAddFundsCtxCancelOne(t *testing.T) {
|
|||||||
|
|
||||||
// Request add funds again - should merge with waiting add funds request
|
// Request add funds again - should merge with waiting add funds request
|
||||||
var err error
|
var err error
|
||||||
addFundsCh2, addFundsMcid2, err = mgr.GetPaych(ctx, from, to, addFundsAmt2)
|
addFundsCh2, addFundsMcid2, err = mgr.GetPaych(ctx, from, to, addFundsAmt2, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
// Wait for add funds requests to be queued up
|
// Wait for add funds requests to be queued up
|
||||||
@ -841,7 +1102,7 @@ func TestPaychGetMergeAddFundsCtxCancelAll(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel with value 10
|
// Send create message for a channel with value 10
|
||||||
createAmt := big.NewInt(10)
|
createAmt := big.NewInt(10)
|
||||||
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt)
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Queue up two add funds requests behind create channel
|
// Queue up two add funds requests behind create channel
|
||||||
@ -856,14 +1117,14 @@ func TestPaychGetMergeAddFundsCtxCancelAll(t *testing.T) {
|
|||||||
defer addFundsSent.Done()
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
// Request add funds - should block until create channel has completed
|
// Request add funds - should block until create channel has completed
|
||||||
_, _, addFundsErr1 = mgr.GetPaych(addFundsCtx1, from, to, big.NewInt(5))
|
_, _, addFundsErr1 = mgr.GetPaych(addFundsCtx1, from, to, big.NewInt(5), true)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer addFundsSent.Done()
|
defer addFundsSent.Done()
|
||||||
|
|
||||||
// Request add funds again - should merge with waiting add funds request
|
// Request add funds again - should merge with waiting add funds request
|
||||||
_, _, addFundsErr2 = mgr.GetPaych(addFundsCtx2, from, to, big.NewInt(3))
|
_, _, addFundsErr2 = mgr.GetPaych(addFundsCtx2, from, to, big.NewInt(3), true)
|
||||||
}()
|
}()
|
||||||
// Wait for add funds requests to be queued up
|
// Wait for add funds requests to be queued up
|
||||||
waitForQueueSize(t, mgr, from, to, 2)
|
waitForQueueSize(t, mgr, from, to, 2)
|
||||||
@ -928,7 +1189,7 @@ func TestPaychAvailableFunds(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel with value 10
|
// Send create message for a channel with value 10
|
||||||
createAmt := big.NewInt(10)
|
createAmt := big.NewInt(10)
|
||||||
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt)
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Available funds should reflect create channel message sent
|
// Available funds should reflect create channel message sent
|
||||||
@ -953,7 +1214,7 @@ func TestPaychAvailableFunds(t *testing.T) {
|
|||||||
|
|
||||||
// Request add funds - should block until create channel has completed
|
// Request add funds - should block until create channel has completed
|
||||||
var err error
|
var err error
|
||||||
_, addFundsMcid, err = mgr.GetPaych(ctx, from, to, addFundsAmt)
|
_, addFundsMcid, err = mgr.GetPaych(ctx, from, to, addFundsAmt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ func TestPaychAddVoucherAfterAddFunds(t *testing.T) {
|
|||||||
|
|
||||||
// Send create message for a channel with value 10
|
// Send create message for a channel with value 10
|
||||||
createAmt := big.NewInt(10)
|
createAmt := big.NewInt(10)
|
||||||
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt)
|
_, createMsgCid, err := mgr.GetPaych(ctx, from, to, createAmt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Send create channel response
|
// Send create channel response
|
||||||
@ -82,7 +82,7 @@ func TestPaychAddVoucherAfterAddFunds(t *testing.T) {
|
|||||||
require.Equal(t, res.Shortfall, excessAmt)
|
require.Equal(t, res.Shortfall, excessAmt)
|
||||||
|
|
||||||
// Add funds so as to cover the voucher shortfall
|
// Add funds so as to cover the voucher shortfall
|
||||||
_, addFundsMsgCid, err := mgr.GetPaych(ctx, from, to, excessAmt)
|
_, addFundsMsgCid, err := mgr.GetPaych(ctx, from, to, excessAmt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Trigger add funds confirmation
|
// Trigger add funds confirmation
|
||||||
|
@ -29,7 +29,7 @@ func TestPaychSettle(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
amt := big.NewInt(10)
|
amt := big.NewInt(10)
|
||||||
_, mcid, err := mgr.GetPaych(ctx, from, to, amt)
|
_, mcid, err := mgr.GetPaych(ctx, from, to, amt, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Send channel create response
|
// Send channel create response
|
||||||
@ -49,7 +49,7 @@ func TestPaychSettle(t *testing.T) {
|
|||||||
// (should create a new channel because the previous channel
|
// (should create a new channel because the previous channel
|
||||||
// is settling)
|
// is settling)
|
||||||
amt2 := big.NewInt(5)
|
amt2 := big.NewInt(5)
|
||||||
_, mcid2, err := mgr.GetPaych(ctx, from, to, amt2)
|
_, mcid2, err := mgr.GetPaych(ctx, from, to, amt2, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEqual(t, cid.Undef, mcid2)
|
require.NotEqual(t, cid.Undef, mcid2)
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ func newMergedFundsReq(reqs []*fundsReq) *mergedFundsReq {
|
|||||||
|
|
||||||
sort.Slice(m.reqs, func(i, j int) bool {
|
sort.Slice(m.reqs, func(i, j int) bool {
|
||||||
if m.reqs[i].reserve != m.reqs[j].reserve { // non-reserve first
|
if m.reqs[i].reserve != m.reqs[j].reserve { // non-reserve first
|
||||||
return m.reqs[j].reserve
|
return m.reqs[i].reserve
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort by amount asc (reducing latency for smaller requests)
|
// sort by amount asc (reducing latency for smaller requests)
|
||||||
@ -220,50 +220,7 @@ func (ca *channelAccessor) processQueue(ctx context.Context, channelID string) (
|
|||||||
return ca.currentAvailableFunds(ctx, channelID, amt)
|
return ca.currentAvailableFunds(ctx, channelID, amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
res := ca.processTask(merged, amt, avail)
|
||||||
toReserve := types.BigSub(amt, avail)
|
|
||||||
avail := types.NewInt(0)
|
|
||||||
|
|
||||||
// reserve at most what we need
|
|
||||||
ca.mutateChannelInfo(ctx, channelID, func(ci *ChannelInfo) {
|
|
||||||
avail = ci.AvailableAmount
|
|
||||||
if avail.GreaterThan(toReserve) {
|
|
||||||
avail = toReserve
|
|
||||||
}
|
|
||||||
ci.AvailableAmount = big.Sub(ci.AvailableAmount, avail)
|
|
||||||
})
|
|
||||||
|
|
||||||
used := types.NewInt(0)
|
|
||||||
|
|
||||||
next := 0
|
|
||||||
for i, r := range merged.reqs {
|
|
||||||
if !r.reserve {
|
|
||||||
// non-reserving request are put after reserving requests, so we are done here
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.amt.GreaterThan(types.BigSub(avail, used)) {
|
|
||||||
// requests are sorted by amount ascending, so if we hit this, there aren't any more requests we can fill
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't try to fill inactive requests
|
|
||||||
if !r.isActive() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
used = types.BigAdd(used, r.amt)
|
|
||||||
r.onComplete(&paychFundsRes{})
|
|
||||||
next = i + 1
|
|
||||||
}
|
|
||||||
merged.reqs = merged.reqs[next:]
|
|
||||||
|
|
||||||
// return any unused reserved funds (e.g. from cancelled requests)
|
|
||||||
ca.mutateChannelInfo(ctx, channelID, func(ci *ChannelInfo) {
|
|
||||||
ci.AvailableAmount = types.BigAdd(ci.AvailableAmount, types.BigSub(avail, used))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
res := ca.processTask(merged.ctx, amt, avail)
|
|
||||||
|
|
||||||
// If the task is waiting on an external event (eg something to appear on
|
// If the task is waiting on an external event (eg something to appear on
|
||||||
// chain) it will return nil
|
// chain) it will return nil
|
||||||
@ -394,7 +351,9 @@ func (ca *channelAccessor) currentAvailableFunds(ctx context.Context, channelID
|
|||||||
// Note that processTask may be called repeatedly in the same state, and should
|
// Note that processTask may be called repeatedly in the same state, and should
|
||||||
// return nil if there is no state change to be made (eg when waiting for a
|
// return nil if there is no state change to be made (eg when waiting for a
|
||||||
// message to be confirmed on chain)
|
// message to be confirmed on chain)
|
||||||
func (ca *channelAccessor) processTask(ctx context.Context, amt, avail types.BigInt) *paychFundsRes {
|
func (ca *channelAccessor) processTask(merged *mergedFundsReq, amt, avail types.BigInt) *paychFundsRes {
|
||||||
|
ctx := merged.ctx
|
||||||
|
|
||||||
// Get the payment channel for the from/to addresses.
|
// Get the payment channel for the from/to addresses.
|
||||||
// Note: It's ok if we get ErrChannelNotTracked. It just means we need to
|
// Note: It's ok if we get ErrChannelNotTracked. It just means we need to
|
||||||
// create a channel.
|
// create a channel.
|
||||||
@ -427,6 +386,56 @@ func (ca *channelAccessor) processTask(ctx context.Context, amt, avail types.Big
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
toReserve := types.BigSub(amt, avail)
|
||||||
|
avail := types.NewInt(0)
|
||||||
|
|
||||||
|
// reserve at most what we need
|
||||||
|
ca.mutateChannelInfo(ctx, channelInfo.ChannelID, func(ci *ChannelInfo) {
|
||||||
|
avail = ci.AvailableAmount
|
||||||
|
if avail.GreaterThan(toReserve) {
|
||||||
|
avail = toReserve
|
||||||
|
}
|
||||||
|
ci.AvailableAmount = big.Sub(ci.AvailableAmount, avail)
|
||||||
|
})
|
||||||
|
|
||||||
|
used := types.NewInt(0)
|
||||||
|
|
||||||
|
next := 0
|
||||||
|
for i, r := range merged.reqs {
|
||||||
|
if !r.reserve {
|
||||||
|
// non-reserving request are put after reserving requests, so we are done here
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.amt.GreaterThan(types.BigSub(avail, used)) {
|
||||||
|
// requests are sorted by amount ascending, so if we hit this, there aren't any more requests we can fill
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't try to fill inactive requests
|
||||||
|
if !r.isActive() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
used = types.BigAdd(used, r.amt)
|
||||||
|
r.onComplete(&paychFundsRes{channel: *channelInfo.Channel})
|
||||||
|
next = i + 1
|
||||||
|
}
|
||||||
|
merged.reqs = merged.reqs[next:]
|
||||||
|
|
||||||
|
// return any unused reserved funds (e.g. from cancelled requests)
|
||||||
|
ca.mutateChannelInfo(ctx, channelInfo.ChannelID, func(ci *ChannelInfo) {
|
||||||
|
ci.AvailableAmount = types.BigAdd(ci.AvailableAmount, types.BigSub(avail, used))
|
||||||
|
})
|
||||||
|
|
||||||
|
amt = types.BigSub(amt, used)
|
||||||
|
}
|
||||||
|
|
||||||
|
if amt.LessThanEqual(types.NewInt(0)) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// We need to add more funds, so send an add funds message to
|
// We need to add more funds, so send an add funds message to
|
||||||
// cover the amount for this request
|
// cover the amount for this request
|
||||||
mcid, err := ca.addFunds(ctx, channelInfo, amt, avail)
|
mcid, err := ca.addFunds(ctx, channelInfo, amt, avail)
|
||||||
|
Loading…
Reference in New Issue
Block a user