Merge pull request #3111 from filecoin-project/fix/paych-addvchr-chk
paych: check To address is owned by wallet for inbound channels
This commit is contained in:
commit
2f6f978cd5
@ -124,9 +124,7 @@ func (a *PaychAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Ad
|
||||
}
|
||||
|
||||
func (a *PaychAPI) PaychVoucherAdd(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
|
||||
_ = a.PaychMgr.TrackInboundChannel(ctx, ch) // TODO: expose those calls
|
||||
|
||||
return a.PaychMgr.AddVoucher(ctx, ch, sv, proof, minDelta)
|
||||
return a.PaychMgr.AddVoucherInbound(ctx, ch, sv, proof, minDelta)
|
||||
}
|
||||
|
||||
// PaychVoucherCreate creates a new signed voucher on the given payment channel
|
||||
@ -164,7 +162,7 @@ func (a *PaychAPI) paychVoucherCreate(ctx context.Context, pch address.Address,
|
||||
|
||||
sv.Signature = sig
|
||||
|
||||
if _, err := a.PaychMgr.AddVoucher(ctx, pch, sv, nil, types.NewInt(0)); err != nil {
|
||||
if _, err := a.PaychMgr.AddVoucherOutbound(ctx, pch, sv, nil, types.NewInt(0)); err != nil {
|
||||
return nil, xerrors.Errorf("failed to persist voucher: %w", err)
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,10 @@ type stateManagerAPI interface {
|
||||
|
||||
// paychAPI defines the API methods needed by the payment channel manager
|
||||
type paychAPI interface {
|
||||
StateAccountKey(context.Context, address.Address, types.TipSetKey) (address.Address, error)
|
||||
StateWaitMsg(ctx context.Context, msg cid.Cid, confidence uint64) (*api.MsgLookup, error)
|
||||
MpoolPushMessage(ctx context.Context, msg *types.Message, maxFee *api.MessageSendSpec) (*types.SignedMessage, error)
|
||||
WalletHas(ctx context.Context, addr address.Address) (bool, error)
|
||||
}
|
||||
|
||||
// managerAPI defines all methods needed by the manager
|
||||
@ -127,26 +129,6 @@ func (pm *Manager) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pm *Manager) TrackOutboundChannel(ctx context.Context, ch address.Address) error {
|
||||
return pm.trackChannel(ctx, ch, DirOutbound)
|
||||
}
|
||||
|
||||
func (pm *Manager) TrackInboundChannel(ctx context.Context, ch address.Address) error {
|
||||
return pm.trackChannel(ctx, ch, DirInbound)
|
||||
}
|
||||
|
||||
func (pm *Manager) trackChannel(ctx context.Context, ch address.Address, dir uint64) error {
|
||||
pm.lk.Lock()
|
||||
defer pm.lk.Unlock()
|
||||
|
||||
ci, err := pm.sa.loadStateChannelInfo(ctx, ch, dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return pm.store.TrackChannel(ci)
|
||||
}
|
||||
|
||||
func (pm *Manager) GetPaych(ctx context.Context, from, to address.Address, amt types.BigInt) (address.Address, cid.Cid, error) {
|
||||
chanAccessor, err := pm.accessorByFromTo(from, to)
|
||||
if err != nil {
|
||||
@ -218,7 +200,9 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address
|
||||
return ca.checkVoucherSpendable(ctx, ch, sv, secret, proof)
|
||||
}
|
||||
|
||||
func (pm *Manager) AddVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
|
||||
// AddVoucherOutbound adds a voucher for an outbound channel.
|
||||
// Returns an error if the channel is not already in the store.
|
||||
func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
|
||||
ca, err := pm.accessorByAddress(ch)
|
||||
if err != nil {
|
||||
return types.NewInt(0), err
|
||||
@ -226,6 +210,70 @@ func (pm *Manager) AddVoucher(ctx context.Context, ch address.Address, sv *paych
|
||||
return ca.addVoucher(ctx, ch, sv, proof, minDelta)
|
||||
}
|
||||
|
||||
// AddVoucherInbound adds a voucher for an inbound channel.
|
||||
// If the channel is not in the store, fetches the channel from state (and checks that
|
||||
// the channel To address is owned by the wallet).
|
||||
func (pm *Manager) AddVoucherInbound(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
|
||||
// Make sure channel is in store, or can be fetched from state, and that
|
||||
// the channel To address is owned by the wallet
|
||||
ci, err := pm.trackInboundChannel(ctx, ch)
|
||||
if err != nil {
|
||||
return types.BigInt{}, err
|
||||
}
|
||||
|
||||
// This is an inbound channel, so To is the Control address (this node)
|
||||
from := ci.Target
|
||||
to := ci.Control
|
||||
ca, err := pm.accessorByFromTo(from, to)
|
||||
if err != nil {
|
||||
return types.BigInt{}, err
|
||||
}
|
||||
return ca.addVoucher(ctx, ch, sv, proof, minDelta)
|
||||
}
|
||||
|
||||
func (pm *Manager) trackInboundChannel(ctx context.Context, ch address.Address) (*ChannelInfo, error) {
|
||||
// Need to take an exclusive lock here so that channel operations can't run
|
||||
// in parallel (see channelLock)
|
||||
pm.lk.Lock()
|
||||
defer pm.lk.Unlock()
|
||||
|
||||
// Check if channel is in store
|
||||
ci, err := pm.store.ByAddress(ch)
|
||||
if err == nil {
|
||||
// Channel is in store, so it's already being tracked
|
||||
return ci, nil
|
||||
}
|
||||
|
||||
// If there's an error (besides channel not in store) return err
|
||||
if err != ErrChannelNotTracked {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Channel is not in store, so get channel from state
|
||||
stateCi, err := pm.sa.loadStateChannelInfo(ctx, ch, DirInbound)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check that channel To address is in wallet
|
||||
to := stateCi.Control // Inbound channel so To addr is Control (this node)
|
||||
toKey, err := pm.pchapi.StateAccountKey(ctx, to, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
has, err := pm.pchapi.WalletHas(ctx, toKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !has {
|
||||
msg := "cannot add voucher for channel %s: wallet does not have key for address %s"
|
||||
return nil, xerrors.Errorf(msg, ch, to)
|
||||
}
|
||||
|
||||
// Save channel to store
|
||||
return pm.store.TrackChannel(stateCi)
|
||||
}
|
||||
|
||||
func (pm *Manager) AllocateLane(ch address.Address) (uint64, error) {
|
||||
ca, err := pm.accessorByAddress(ch)
|
||||
if err != nil {
|
||||
|
@ -111,6 +111,7 @@ type mockPaychAPI struct {
|
||||
messages map[cid.Cid]*types.SignedMessage
|
||||
waitingCalls map[cid.Cid]*waitingCall
|
||||
waitingResponses map[cid.Cid]*waitingResponse
|
||||
wallet map[address.Address]struct{}
|
||||
}
|
||||
|
||||
func newMockPaychAPI() *mockPaychAPI {
|
||||
@ -118,6 +119,7 @@ func newMockPaychAPI() *mockPaychAPI {
|
||||
messages: make(map[cid.Cid]*types.SignedMessage),
|
||||
waitingCalls: make(map[cid.Cid]*waitingCall),
|
||||
waitingResponses: make(map[cid.Cid]*waitingResponse),
|
||||
wallet: make(map[address.Address]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,3 +201,22 @@ func (pchapi *mockPaychAPI) pushedMessageCount() int {
|
||||
|
||||
return len(pchapi.messages)
|
||||
}
|
||||
|
||||
func (pchapi *mockPaychAPI) StateAccountKey(ctx context.Context, addr address.Address, tsk types.TipSetKey) (address.Address, error) {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
func (pchapi *mockPaychAPI) WalletHas(ctx context.Context, addr address.Address) (bool, error) {
|
||||
pchapi.lk.Lock()
|
||||
defer pchapi.lk.Unlock()
|
||||
|
||||
_, ok := pchapi.wallet[addr]
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
func (pchapi *mockPaychAPI) addWalletAddress(addr address.Address) {
|
||||
pchapi.lk.Lock()
|
||||
defer pchapi.lk.Unlock()
|
||||
|
||||
pchapi.wallet[addr] = struct{}{}
|
||||
}
|
||||
|
@ -64,11 +64,13 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
|
||||
return nil, xerrors.Errorf("voucher ChannelAddr doesn't match channel address, got %s, expected %s", sv.ChannelAddr, ch)
|
||||
}
|
||||
|
||||
act, pchState, err := ca.sa.loadPaychState(ctx, ch)
|
||||
// Load payment channel actor state
|
||||
act, pchState, err := ca.sa.loadPaychActorState(ctx, ch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Load channel "From" account actor state
|
||||
var actState account.State
|
||||
_, err = ca.api.LoadActorState(ctx, pchState.From, &actState, nil)
|
||||
if err != nil {
|
||||
@ -76,7 +78,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
|
||||
}
|
||||
from := actState.Address
|
||||
|
||||
// verify signature
|
||||
// verify voucher signature
|
||||
vb, err := sv.SigningBytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -29,95 +29,16 @@ import (
|
||||
ds_sync "github.com/ipfs/go-datastore/sync"
|
||||
)
|
||||
|
||||
func TestPaychOutbound(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)
|
||||
fromAcct := tutils.NewIDAddr(t, 201)
|
||||
toAcct := tutils.NewIDAddr(t, 202)
|
||||
|
||||
mock := newMockManagerAPI()
|
||||
arr, err := adt.MakeEmptyArray(mock.store).Root()
|
||||
require.NoError(t, err)
|
||||
mock.setAccountState(fromAcct, account.State{Address: from})
|
||||
mock.setAccountState(toAcct, account.State{Address: to})
|
||||
mock.setPaychState(ch, nil, paych.State{
|
||||
From: fromAcct,
|
||||
To: toAcct,
|
||||
ToSend: big.NewInt(0),
|
||||
SettlingAt: abi.ChainEpoch(0),
|
||||
MinSettleHeight: abi.ChainEpoch(0),
|
||||
LaneStates: arr,
|
||||
})
|
||||
|
||||
mgr, err := newManager(store, mock)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mgr.TrackOutboundChannel(ctx, ch)
|
||||
require.NoError(t, err)
|
||||
|
||||
ci, err := mgr.GetChannelInfo(ch)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, *ci.Channel, ch)
|
||||
require.Equal(t, ci.Control, from)
|
||||
require.Equal(t, ci.Target, to)
|
||||
require.EqualValues(t, ci.Direction, DirOutbound)
|
||||
require.EqualValues(t, ci.NextLane, 0)
|
||||
require.Len(t, ci.Vouchers, 0)
|
||||
}
|
||||
|
||||
func TestPaychInbound(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)
|
||||
fromAcct := tutils.NewIDAddr(t, 201)
|
||||
toAcct := tutils.NewIDAddr(t, 202)
|
||||
|
||||
mock := newMockManagerAPI()
|
||||
arr, err := adt.MakeEmptyArray(mock.store).Root()
|
||||
require.NoError(t, err)
|
||||
mock.setAccountState(fromAcct, account.State{Address: from})
|
||||
mock.setAccountState(toAcct, account.State{Address: to})
|
||||
mock.setPaychState(ch, nil, paych.State{
|
||||
From: fromAcct,
|
||||
To: toAcct,
|
||||
ToSend: big.NewInt(0),
|
||||
SettlingAt: abi.ChainEpoch(0),
|
||||
MinSettleHeight: abi.ChainEpoch(0),
|
||||
LaneStates: arr,
|
||||
})
|
||||
|
||||
mgr, err := newManager(store, mock)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mgr.TrackInboundChannel(ctx, ch)
|
||||
require.NoError(t, err)
|
||||
|
||||
ci, err := mgr.GetChannelInfo(ch)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, *ci.Channel, ch)
|
||||
require.Equal(t, ci.Control, to)
|
||||
require.Equal(t, ci.Target, from)
|
||||
require.EqualValues(t, ci.Direction, DirInbound)
|
||||
require.EqualValues(t, ci.NextLane, 0)
|
||||
require.Len(t, ci.Vouchers, 0)
|
||||
}
|
||||
|
||||
func TestCheckVoucherValid(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
fromKeyPrivate, fromKeyPublic := testGenerateKeyPair(t)
|
||||
toKeyPrivate, toKeyPublic := testGenerateKeyPair(t)
|
||||
randKeyPrivate, _ := testGenerateKeyPair(t)
|
||||
|
||||
ch := tutils.NewIDAddr(t, 100)
|
||||
from := tutils.NewSECP256K1Addr(t, string(fromKeyPublic))
|
||||
to := tutils.NewSECP256K1Addr(t, "secpTo")
|
||||
to := tutils.NewSECP256K1Addr(t, string(toKeyPublic))
|
||||
fromAcct := tutils.NewActorAddr(t, "fromAct")
|
||||
toAcct := tutils.NewActorAddr(t, "toAct")
|
||||
|
||||
@ -155,6 +76,13 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
actorBalance: big.NewInt(10),
|
||||
toSend: big.NewInt(0),
|
||||
voucherAmount: big.NewInt(5),
|
||||
}, {
|
||||
name: "fails when signed by channel To account (instead of From account)",
|
||||
expectError: true,
|
||||
key: toKeyPrivate,
|
||||
actorBalance: big.NewInt(10),
|
||||
toSend: big.NewInt(0),
|
||||
voucherAmount: big.NewInt(5),
|
||||
}, {
|
||||
name: "fails when nonce too low",
|
||||
expectError: true,
|
||||
@ -269,6 +197,7 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
t.Run(tcase.name, func(t *testing.T) {
|
||||
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
|
||||
// Create an actor for the channel with the test case balance
|
||||
act := &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Head: cid.Cid{},
|
||||
@ -276,6 +205,7 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
Balance: tcase.actorBalance,
|
||||
}
|
||||
|
||||
// Set the state of the channel's lanes
|
||||
laneStates, err := mock.storeLaneStates(tcase.laneStates)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -288,14 +218,24 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
LaneStates: laneStates,
|
||||
})
|
||||
|
||||
// Create a manager
|
||||
mgr, err := newManager(store, mock)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mgr.TrackInboundChannel(ctx, ch)
|
||||
// Create the channel in the manager's store
|
||||
ci := &ChannelInfo{
|
||||
Channel: &ch,
|
||||
Control: toAcct,
|
||||
Target: fromAcct,
|
||||
Direction: DirInbound,
|
||||
}
|
||||
err = mgr.store.putChannelInfo(ci)
|
||||
require.NoError(t, err)
|
||||
|
||||
sv := testCreateVoucher(t, ch, tcase.voucherLane, tcase.voucherNonce, tcase.voucherAmount, tcase.key)
|
||||
// Create a signed voucher
|
||||
sv := createTestVoucher(t, ch, tcase.voucherLane, tcase.voucherNonce, tcase.voucherAmount, tcase.key)
|
||||
|
||||
// Check the voucher's validity
|
||||
err = mgr.CheckVoucherValid(ctx, ch, sv)
|
||||
if tcase.expectError {
|
||||
require.Error(t, err)
|
||||
@ -358,7 +298,14 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
|
||||
mgr, err := newManager(store, mock)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mgr.TrackInboundChannel(ctx, ch)
|
||||
// Create the channel in the manager's store
|
||||
ci := &ChannelInfo{
|
||||
Channel: &ch,
|
||||
Control: toAcct,
|
||||
Target: fromAcct,
|
||||
Direction: DirInbound,
|
||||
}
|
||||
err = mgr.store.putChannelInfo(ci)
|
||||
require.NoError(t, err)
|
||||
|
||||
//
|
||||
@ -380,7 +327,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
|
||||
voucherLane := uint64(1)
|
||||
voucherNonce := uint64(2)
|
||||
voucherAmount := big.NewInt(6)
|
||||
sv := testCreateVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate)
|
||||
sv := createTestVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate)
|
||||
err = mgr.CheckVoucherValid(ctx, ch, sv)
|
||||
require.Error(t, err)
|
||||
|
||||
@ -398,13 +345,13 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
|
||||
// actor balance is 10 so total is ok.
|
||||
//
|
||||
voucherAmount = big.NewInt(4)
|
||||
sv = testCreateVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate)
|
||||
sv = createTestVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate)
|
||||
err = mgr.CheckVoucherValid(ctx, ch, sv)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add voucher to lane 1, so Lane 1 effective redeemed
|
||||
// (with first voucher) is now 4
|
||||
_, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
|
||||
//
|
||||
@ -422,7 +369,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
|
||||
//
|
||||
voucherNonce++
|
||||
voucherAmount = big.NewInt(6)
|
||||
sv = testCreateVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate)
|
||||
sv = createTestVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate)
|
||||
err = mgr.CheckVoucherValid(ctx, ch, sv)
|
||||
require.Error(t, err)
|
||||
|
||||
@ -440,7 +387,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
|
||||
// actor balance is 10 so total is ok.
|
||||
//
|
||||
voucherAmount = big.NewInt(5)
|
||||
sv = testCreateVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate)
|
||||
sv = createTestVoucher(t, ch, voucherLane, voucherNonce, voucherAmount, fromKeyPrivate)
|
||||
err = mgr.CheckVoucherValid(ctx, ch, sv)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
@ -457,23 +404,23 @@ func TestAddVoucherDelta(t *testing.T) {
|
||||
minDelta := big.NewInt(2)
|
||||
nonce := uint64(1)
|
||||
voucherAmount := big.NewInt(1)
|
||||
sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.Error(t, err)
|
||||
|
||||
// Expect success when adding a voucher whose amount is equal to minDelta
|
||||
nonce++
|
||||
voucherAmount = big.NewInt(2)
|
||||
sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
delta, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
delta, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, delta.Int64(), 2)
|
||||
|
||||
// Check that delta is correct when there's an existing voucher
|
||||
nonce++
|
||||
voucherAmount = big.NewInt(5)
|
||||
sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
delta, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
delta, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, delta.Int64(), 3)
|
||||
|
||||
@ -481,8 +428,8 @@ func TestAddVoucherDelta(t *testing.T) {
|
||||
nonce = uint64(1)
|
||||
voucherAmount = big.NewInt(6)
|
||||
voucherLane = uint64(2)
|
||||
sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
delta, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
delta, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, delta.Int64(), 6)
|
||||
}
|
||||
@ -499,8 +446,8 @@ func TestAddVoucherNextLane(t *testing.T) {
|
||||
// Add a voucher in lane 2
|
||||
nonce := uint64(1)
|
||||
voucherLane := uint64(2)
|
||||
sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
|
||||
ci, err := mgr.GetChannelInfo(ch)
|
||||
@ -518,8 +465,8 @@ func TestAddVoucherNextLane(t *testing.T) {
|
||||
|
||||
// Add a voucher in lane 1
|
||||
voucherLane = uint64(1)
|
||||
sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
|
||||
ci, err = mgr.GetChannelInfo(ch)
|
||||
@ -528,8 +475,8 @@ func TestAddVoucherNextLane(t *testing.T) {
|
||||
|
||||
// Add a voucher in lane 7
|
||||
voucherLane = uint64(7)
|
||||
sv = testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
|
||||
ci, err = mgr.GetChannelInfo(ch)
|
||||
@ -557,7 +504,7 @@ func TestAllocateLane(t *testing.T) {
|
||||
func TestAllocateLaneWithExistingLaneState(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
_, fromKeyPublic := testGenerateKeyPair(t)
|
||||
fromKeyPrivate, fromKeyPublic := testGenerateKeyPair(t)
|
||||
|
||||
ch := tutils.NewIDAddr(t, 100)
|
||||
from := tutils.NewSECP256K1Addr(t, string(fromKeyPublic))
|
||||
@ -568,17 +515,13 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) {
|
||||
mock := newMockManagerAPI()
|
||||
mock.setAccountState(fromAcct, account.State{Address: from})
|
||||
mock.setAccountState(toAcct, account.State{Address: to})
|
||||
mock.addWalletAddress(to)
|
||||
|
||||
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
|
||||
// Create a channel that will be retrieved from state
|
||||
actorBalance := big.NewInt(10)
|
||||
toSend := big.NewInt(1)
|
||||
laneStates := map[uint64]paych.LaneState{
|
||||
2: {
|
||||
Nonce: 1,
|
||||
Redeemed: big.NewInt(4),
|
||||
},
|
||||
}
|
||||
|
||||
act := &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
@ -587,7 +530,7 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) {
|
||||
Balance: actorBalance,
|
||||
}
|
||||
|
||||
lsCid, err := mock.storeLaneStates(laneStates)
|
||||
arr, err := adt.MakeEmptyArray(mock.store).Root()
|
||||
require.NoError(t, err)
|
||||
mock.setPaychState(ch, act, paych.State{
|
||||
From: fromAcct,
|
||||
@ -595,15 +538,23 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) {
|
||||
ToSend: toSend,
|
||||
SettlingAt: abi.ChainEpoch(0),
|
||||
MinSettleHeight: abi.ChainEpoch(0),
|
||||
LaneStates: lsCid,
|
||||
LaneStates: arr,
|
||||
})
|
||||
|
||||
mgr, err := newManager(store, mock)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mgr.TrackInboundChannel(ctx, ch)
|
||||
// Create a voucher on lane 2
|
||||
// (also reads the channel from state and puts it in the store)
|
||||
voucherLane := uint64(2)
|
||||
minDelta := big.NewInt(0)
|
||||
nonce := uint64(2)
|
||||
voucherAmount := big.NewInt(5)
|
||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err = mgr.AddVoucherInbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Allocate lane should return the next lane (lane 3)
|
||||
lane, err := mgr.AllocateLane(ch)
|
||||
require.NoError(t, err)
|
||||
require.EqualValues(t, 3, lane)
|
||||
@ -623,8 +574,8 @@ func TestAddVoucherProof(t *testing.T) {
|
||||
|
||||
// Add a voucher with no proof
|
||||
var proof []byte
|
||||
sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect one voucher with no proof
|
||||
@ -635,7 +586,7 @@ func TestAddVoucherProof(t *testing.T) {
|
||||
|
||||
// Add same voucher with no proof
|
||||
voucherLane = uint64(1)
|
||||
_, err = mgr.AddVoucher(ctx, ch, sv, proof, minDelta)
|
||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, proof, minDelta)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect one voucher with no proof
|
||||
@ -646,7 +597,7 @@ func TestAddVoucherProof(t *testing.T) {
|
||||
|
||||
// Add same voucher with proof
|
||||
proof = []byte{1}
|
||||
_, err = mgr.AddVoucher(ctx, ch, sv, proof, minDelta)
|
||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, proof, minDelta)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should add proof to existing voucher
|
||||
@ -656,6 +607,69 @@ func TestAddVoucherProof(t *testing.T) {
|
||||
require.Len(t, ci.Vouchers[0].Proof, 1)
|
||||
}
|
||||
|
||||
func TestAddVoucherInboundWalletKey(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
fromKeyPrivate, fromKeyPublic := testGenerateKeyPair(t)
|
||||
|
||||
ch := tutils.NewIDAddr(t, 100)
|
||||
from := tutils.NewSECP256K1Addr(t, string(fromKeyPublic))
|
||||
to := tutils.NewSECP256K1Addr(t, "secpTo")
|
||||
fromAcct := tutils.NewActorAddr(t, "fromAct")
|
||||
toAcct := tutils.NewActorAddr(t, "toAct")
|
||||
|
||||
// Create an actor for the channel in state
|
||||
act := &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Head: cid.Cid{},
|
||||
Nonce: 0,
|
||||
Balance: types.NewInt(20),
|
||||
}
|
||||
|
||||
mock := newMockManagerAPI()
|
||||
arr, err := adt.MakeEmptyArray(mock.store).Root()
|
||||
require.NoError(t, err)
|
||||
mock.setAccountState(fromAcct, account.State{Address: from})
|
||||
mock.setAccountState(toAcct, account.State{Address: to})
|
||||
|
||||
mock.setPaychState(ch, act, paych.State{
|
||||
From: fromAcct,
|
||||
To: toAcct,
|
||||
ToSend: types.NewInt(0),
|
||||
SettlingAt: abi.ChainEpoch(0),
|
||||
MinSettleHeight: abi.ChainEpoch(0),
|
||||
LaneStates: arr,
|
||||
})
|
||||
|
||||
// Create a manager
|
||||
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
mgr, err := newManager(store, mock)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add a voucher
|
||||
nonce := uint64(1)
|
||||
voucherLane := uint64(1)
|
||||
minDelta := big.NewInt(0)
|
||||
voucherAmount := big.NewInt(2)
|
||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err = mgr.AddVoucherInbound(ctx, ch, sv, nil, minDelta)
|
||||
|
||||
// Should fail because there is no wallet key matching the channel To
|
||||
// address (ie, the channel is not "owned" by this node)
|
||||
require.Error(t, err)
|
||||
|
||||
// Add wallet key for To address
|
||||
mock.addWalletAddress(to)
|
||||
|
||||
// Add voucher again
|
||||
sv = createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, fromKeyPrivate)
|
||||
_, err = mgr.AddVoucherInbound(ctx, ch, sv, nil, minDelta)
|
||||
|
||||
// Should now pass because there is a wallet key matching the channel To
|
||||
// address
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestNextNonceForLane(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
@ -674,19 +688,19 @@ func TestNextNonceForLane(t *testing.T) {
|
||||
// Add vouchers such that we have
|
||||
// lane 1: nonce 2
|
||||
// lane 1: nonce 4
|
||||
// lane 2: nonce 7
|
||||
voucherLane := uint64(1)
|
||||
for _, nonce := range []uint64{2, 4} {
|
||||
voucherAmount = big.Add(voucherAmount, big.NewInt(1))
|
||||
sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, key)
|
||||
_, err := mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, key)
|
||||
_, err := mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// lane 2: nonce 7
|
||||
voucherLane = uint64(2)
|
||||
nonce := uint64(7)
|
||||
sv := testCreateVoucher(t, ch, voucherLane, nonce, voucherAmount, key)
|
||||
_, err = mgr.AddVoucher(ctx, ch, sv, nil, minDelta)
|
||||
sv := createTestVoucher(t, ch, voucherLane, nonce, voucherAmount, key)
|
||||
_, err = mgr.AddVoucherOutbound(ctx, ch, sv, nil, minDelta)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect next nonce for lane 1 to be 5
|
||||
@ -715,6 +729,7 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, addre
|
||||
mock.setAccountState(fromAcct, account.State{Address: from})
|
||||
mock.setAccountState(toAcct, account.State{Address: to})
|
||||
|
||||
// Create channel in state
|
||||
act := &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
Head: cid.Cid{},
|
||||
@ -734,8 +749,16 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, addre
|
||||
mgr, err := newManager(store, mock)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = mgr.TrackInboundChannel(ctx, ch)
|
||||
// Create the channel in the manager's store
|
||||
ci := &ChannelInfo{
|
||||
Channel: &ch,
|
||||
Control: fromAcct,
|
||||
Target: toAcct,
|
||||
Direction: DirOutbound,
|
||||
}
|
||||
err = mgr.store.putChannelInfo(ci)
|
||||
require.NoError(t, err)
|
||||
|
||||
return mgr, ch, fromKeyPrivate
|
||||
}
|
||||
|
||||
@ -747,7 +770,7 @@ func testGenerateKeyPair(t *testing.T) ([]byte, []byte) {
|
||||
return priv, pub
|
||||
}
|
||||
|
||||
func testCreateVoucher(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych.SignedVoucher {
|
||||
func createTestVoucher(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych.SignedVoucher {
|
||||
sv := &paych.SignedVoucher{
|
||||
ChannelAddr: ch,
|
||||
Lane: voucherLane,
|
||||
|
@ -17,7 +17,7 @@ type stateAccessor struct {
|
||||
sm stateManagerAPI
|
||||
}
|
||||
|
||||
func (ca *stateAccessor) loadPaychState(ctx context.Context, ch address.Address) (*types.Actor, *paych.State, error) {
|
||||
func (ca *stateAccessor) loadPaychActorState(ctx context.Context, ch address.Address) (*types.Actor, *paych.State, error) {
|
||||
var pcast paych.State
|
||||
act, err := ca.sm.LoadActorState(ctx, ch, &pcast, nil)
|
||||
if err != nil {
|
||||
@ -28,7 +28,7 @@ func (ca *stateAccessor) loadPaychState(ctx context.Context, ch address.Address)
|
||||
}
|
||||
|
||||
func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Address, dir uint64) (*ChannelInfo, error) {
|
||||
_, st, err := ca.loadPaychState(ctx, ch)
|
||||
_, st, err := ca.loadPaychActorState(ctx, ch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -84,15 +84,20 @@ type ChannelInfo struct {
|
||||
|
||||
// TrackChannel stores a channel, returning an error if the channel was already
|
||||
// being tracked
|
||||
func (ps *Store) TrackChannel(ci *ChannelInfo) error {
|
||||
func (ps *Store) TrackChannel(ci *ChannelInfo) (*ChannelInfo, error) {
|
||||
_, err := ps.ByAddress(*ci.Channel)
|
||||
switch err {
|
||||
default:
|
||||
return err
|
||||
return nil, err
|
||||
case nil:
|
||||
return fmt.Errorf("already tracking channel: %s", ci.Channel)
|
||||
return nil, fmt.Errorf("already tracking channel: %s", ci.Channel)
|
||||
case ErrChannelNotTracked:
|
||||
return ps.putChannelInfo(ci)
|
||||
err = ps.putChannelInfo(ci)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ps.ByAddress(*ci.Channel)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,15 +38,15 @@ func TestStore(t *testing.T) {
|
||||
}
|
||||
|
||||
// Track the channel
|
||||
err = store.TrackChannel(ci)
|
||||
_, err = store.TrackChannel(ci)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Tracking same channel again should error
|
||||
err = store.TrackChannel(ci)
|
||||
_, err = store.TrackChannel(ci)
|
||||
require.Error(t, err)
|
||||
|
||||
// Track another channel
|
||||
err = store.TrackChannel(ci2)
|
||||
_, err = store.TrackChannel(ci2)
|
||||
require.NoError(t, err)
|
||||
|
||||
// List channels should include all channels
|
||||
|
Loading…
Reference in New Issue
Block a user