Merge pull request #2991 from filecoin-project/refactor/paych-lane-amt
paych: use spec-actors paych with AMT for lane states
This commit is contained in:
commit
bd31e8d37e
6
go.mod
6
go.mod
@ -18,7 +18,7 @@ require (
|
||||
github.com/drand/drand v1.0.3-0.20200714175734-29705eaf09d4
|
||||
github.com/drand/kyber v1.1.1
|
||||
github.com/fatih/color v1.8.0
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200812173150-c013d785a8d5
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef
|
||||
github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200716204036-cddc56607e1d
|
||||
github.com/filecoin-project/go-address v0.0.3
|
||||
github.com/filecoin-project/go-amt-ipld/v2 v2.1.1-0.20200731171407-e559a0579161 // indirect
|
||||
@ -35,7 +35,7 @@ require (
|
||||
github.com/filecoin-project/go-statestore v0.1.0
|
||||
github.com/filecoin-project/go-storedcounter v0.0.0-20200421200003-1c99c62e8a5b
|
||||
github.com/filecoin-project/sector-storage v0.0.0-20200810171746-eac70842d8e0
|
||||
github.com/filecoin-project/specs-actors v0.8.7-0.20200811223639-8db91253c07a
|
||||
github.com/filecoin-project/specs-actors v0.9.2
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401
|
||||
github.com/filecoin-project/storage-fsm v0.0.0-20200805013058-9d9ea4e6331f
|
||||
github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1
|
||||
@ -115,7 +115,7 @@ require (
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/urfave/cli/v2 v2.2.0
|
||||
github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200811225321-4fed70922d45
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7
|
||||
github.com/whyrusleeping/pubsub v0.0.0-20131020042734-02de8aa2db3d
|
||||
github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542
|
||||
|
8
go.sum
8
go.sum
@ -215,8 +215,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
|
||||
github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY=
|
||||
github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
|
||||
github.com/fd/go-nat v1.0.0/go.mod h1:BTBu/CKvMmOMUPkKVef1pngt2WFH/lg7E6yQnulfp6E=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200812173150-c013d785a8d5 h1:1oXwXT5RTSKrcOuxes8a4JzZF+PJ3yYjPWxpgIh/igg=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200812173150-c013d785a8d5/go.mod h1:/R8d9VnHt2kkbiC+dbDV8cbZJ5EgRjKBgNQgtl5dubQ=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef h1:MtQRSnJLsQOOlmsd/Ua5KWXimpxcaa715h6FUh/eJPY=
|
||||
github.com/filecoin-project/chain-validation v0.0.6-0.20200813000554-40c22fe26eef/go.mod h1:SMj5VK1pYgqC8FXVEtOBRTc+9AIrYu+C+K3tAXi2Rk8=
|
||||
github.com/filecoin-project/go-address v0.0.0-20200107215422-da8eea2842b5/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=
|
||||
github.com/filecoin-project/go-address v0.0.2-0.20200218010043-eb9bb40ed5be/go.mod h1:SAOwJoakQ8EPjwNIsiakIQKsoKdkcbx8U3IapgCg9R0=
|
||||
github.com/filecoin-project/go-address v0.0.3 h1:eVfbdjEbpbzIrbiSa+PiGUY+oDK9HnUn+M1R/ggoHf8=
|
||||
@ -266,6 +266,8 @@ github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923 h1
|
||||
github.com/filecoin-project/specs-actors v0.8.7-0.20200811203034-272d022c1923/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU=
|
||||
github.com/filecoin-project/specs-actors v0.8.7-0.20200811223639-8db91253c07a h1:DIOf9d5S4aBs6jwqGPzNSGhuMjn5w3R4kbHU3NpNBtw=
|
||||
github.com/filecoin-project/specs-actors v0.8.7-0.20200811223639-8db91253c07a/go.mod h1:hukRu6vKQrrS7Nt+fC/ql4PqWLSfmAWNshD/VDtARZU=
|
||||
github.com/filecoin-project/specs-actors v0.9.2 h1:0JG0QLHw8pO6BPqPRe9eQxQW60biHAQsx1rlQ9QbzZ0=
|
||||
github.com/filecoin-project/specs-actors v0.9.2/go.mod h1:YasnVUOUha0DN5wB+twl+V8LlDKVNknRG00kTJpsfFA=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea h1:iixjULRQFPn7Q9KlIqfwLJnlAXO10bbkI+xy5GKGdLY=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200622113353-88a9704877ea/go.mod h1:Pr5ntAaxsh+sLG/LYiL4tKzvA83Vk5vLODYhfNwOg7k=
|
||||
github.com/filecoin-project/specs-storage v0.1.1-0.20200730063404-f7db367e9401 h1:jLzN1hwO5WpKPu8ASbW8fs1FUCsOWNvoBXzQhv+8/E8=
|
||||
@ -1383,6 +1385,8 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c h1:BMg3YUwL
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200810223238-211df3b9e24c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200811225321-4fed70922d45 h1:2QQ0rYt7Y8NhRPtuAlZMBNdqoVCh2dR6BQAtGJLlZgw=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200811225321-4fed70922d45/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c h1:otRnI08JoahNBxUFqX3372Ab9GnTj8L5J9iP5ImyxGU=
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20200812213548-958ddffe352c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
|
||||
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=
|
||||
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8=
|
||||
github.com/whyrusleeping/go-ctrlnet v0.0.0-20180313164037-f564fbbdaa95/go.mod h1:SJqKCCPXRfBFCwXjfNT/skfsceF7+MBFLI2OrvuRA7g=
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
@ -39,6 +40,7 @@ type PaychAPI struct {
|
||||
type stateManagerAPI interface {
|
||||
LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error)
|
||||
Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error)
|
||||
AdtStore(ctx context.Context) adt.Store
|
||||
}
|
||||
|
||||
// paychAPI defines the API methods needed by the payment channel manager
|
||||
@ -55,10 +57,14 @@ type managerAPI interface {
|
||||
|
||||
// managerAPIImpl is used to create a composite that implements managerAPI
|
||||
type managerAPIImpl struct {
|
||||
stateManagerAPI
|
||||
*stmgr.StateManager
|
||||
paychAPI
|
||||
}
|
||||
|
||||
func (m *managerAPIImpl) AdtStore(ctx context.Context) adt.Store {
|
||||
return m.ChainStore().Store(ctx)
|
||||
}
|
||||
|
||||
type Manager struct {
|
||||
// The Manager context is used to terminate wait operations on shutdown
|
||||
ctx context.Context
|
||||
@ -76,7 +82,7 @@ func NewManager(mctx helpers.MetricsCtx, lc fx.Lifecycle, sm *stmgr.StateManager
|
||||
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||
ctx, shutdown := context.WithCancel(ctx)
|
||||
|
||||
impl := &managerAPIImpl{stateManagerAPI: sm, paychAPI: &api}
|
||||
impl := &managerAPIImpl{StateManager: sm, paychAPI: &api}
|
||||
return &Manager{
|
||||
ctx: ctx,
|
||||
shutdown: shutdown,
|
||||
|
@ -5,6 +5,10 @@ import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
cbornode "github.com/ipfs/go-ipld-cbor"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -34,6 +38,7 @@ type mockStateManager struct {
|
||||
lk sync.Mutex
|
||||
accountState map[address.Address]account.State
|
||||
paychState map[address.Address]mockPchState
|
||||
store adt.Store
|
||||
response *api.InvocResult
|
||||
}
|
||||
|
||||
@ -41,9 +46,14 @@ func newMockStateManager() *mockStateManager {
|
||||
return &mockStateManager{
|
||||
accountState: make(map[address.Address]account.State),
|
||||
paychState: make(map[address.Address]mockPchState),
|
||||
store: adt.WrapStore(context.Background(), cbornode.NewMemCborStore()),
|
||||
}
|
||||
}
|
||||
|
||||
func (sm *mockStateManager) AdtStore(ctx context.Context) adt.Store {
|
||||
return sm.store
|
||||
}
|
||||
|
||||
func (sm *mockStateManager) setAccountState(a address.Address, state account.State) {
|
||||
sm.lk.Lock()
|
||||
defer sm.lk.Unlock()
|
||||
@ -56,6 +66,17 @@ func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor,
|
||||
sm.paychState[a] = mockPchState{actor, state}
|
||||
}
|
||||
|
||||
func (sm *mockStateManager) storeLaneStates(laneStates map[uint64]paych.LaneState) (cid.Cid, error) {
|
||||
arr := adt.MakeEmptyArray(sm.store)
|
||||
for i, ls := range laneStates {
|
||||
ls := ls
|
||||
if err := arr.Set(i, &ls); err != nil {
|
||||
return cid.Undef, err
|
||||
}
|
||||
}
|
||||
return arr.Root()
|
||||
}
|
||||
|
||||
func (sm *mockStateManager) LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) {
|
||||
sm.lk.Lock()
|
||||
defer sm.lk.Unlock()
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
@ -88,7 +90,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
|
||||
}
|
||||
|
||||
// Check the voucher against the highest known voucher nonce / value
|
||||
laneStates, err := ca.laneState(pchState, ch)
|
||||
laneStates, err := ca.laneState(ctx, pchState, ch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -313,14 +315,29 @@ func (ca *channelAccessor) nextNonceForLane(ctx context.Context, ch address.Addr
|
||||
|
||||
// laneState gets the LaneStates from chain, then applies all vouchers in
|
||||
// the data store over the chain state
|
||||
func (ca *channelAccessor) laneState(state *paych.State, ch address.Address) (map[uint64]*paych.LaneState, error) {
|
||||
func (ca *channelAccessor) laneState(ctx context.Context, state *paych.State, ch address.Address) (map[uint64]*paych.LaneState, error) {
|
||||
// TODO: we probably want to call UpdateChannelState with all vouchers to be fully correct
|
||||
// (but technically dont't need to)
|
||||
laneStates := make(map[uint64]*paych.LaneState, len(state.LaneStates))
|
||||
|
||||
// Get the lane state from the chain
|
||||
for _, laneState := range state.LaneStates {
|
||||
laneStates[laneState.ID] = laneState
|
||||
store := ca.api.AdtStore(ctx)
|
||||
lsamt, err := adt.AsArray(store, state.LaneStates)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Note: we use a map instead of an array to store laneStates because the
|
||||
// client sets the lane ID (the index) and potentially they could use a
|
||||
// very large index.
|
||||
var ls paych.LaneState
|
||||
laneStates := make(map[uint64]*paych.LaneState, lsamt.Length())
|
||||
err = lsamt.ForEach(&ls, func(i int64) error {
|
||||
current := ls
|
||||
laneStates[uint64(i)] = ¤t
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Apply locally stored vouchers
|
||||
@ -339,7 +356,6 @@ func (ca *channelAccessor) laneState(state *paych.State, ch address.Address) (ma
|
||||
ls, ok := laneStates[v.Voucher.Lane]
|
||||
if !ok {
|
||||
ls = &paych.LaneState{
|
||||
ID: v.Voucher.Lane,
|
||||
Redeemed: types.NewInt(0),
|
||||
Nonce: 0,
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
@ -39,6 +40,8 @@ func TestPaychOutbound(t *testing.T) {
|
||||
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{
|
||||
@ -47,7 +50,7 @@ func TestPaychOutbound(t *testing.T) {
|
||||
ToSend: big.NewInt(0),
|
||||
SettlingAt: abi.ChainEpoch(0),
|
||||
MinSettleHeight: abi.ChainEpoch(0),
|
||||
LaneStates: []*paych.LaneState{},
|
||||
LaneStates: arr,
|
||||
})
|
||||
|
||||
mgr, err := newManager(store, mock)
|
||||
@ -77,6 +80,8 @@ func TestPaychInbound(t *testing.T) {
|
||||
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{
|
||||
@ -85,7 +90,7 @@ func TestPaychInbound(t *testing.T) {
|
||||
ToSend: big.NewInt(0),
|
||||
SettlingAt: abi.ChainEpoch(0),
|
||||
MinSettleHeight: abi.ChainEpoch(0),
|
||||
LaneStates: []*paych.LaneState{},
|
||||
LaneStates: arr,
|
||||
})
|
||||
|
||||
mgr, err := newManager(store, mock)
|
||||
@ -129,7 +134,7 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
voucherAmount big.Int
|
||||
voucherLane uint64
|
||||
voucherNonce uint64
|
||||
laneStates []*paych.LaneState
|
||||
laneStates map[uint64]paych.LaneState
|
||||
}{{
|
||||
name: "passes when voucher amount < balance",
|
||||
key: fromKeyPrivate,
|
||||
@ -159,11 +164,12 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
voucherAmount: big.NewInt(5),
|
||||
voucherLane: 1,
|
||||
voucherNonce: 2,
|
||||
laneStates: []*paych.LaneState{{
|
||||
ID: 1,
|
||||
Redeemed: big.NewInt(2),
|
||||
Nonce: 3,
|
||||
}},
|
||||
laneStates: map[uint64]paych.LaneState{
|
||||
1: {
|
||||
Redeemed: big.NewInt(2),
|
||||
Nonce: 3,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "passes when nonce higher",
|
||||
key: fromKeyPrivate,
|
||||
@ -172,11 +178,12 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
voucherAmount: big.NewInt(5),
|
||||
voucherLane: 1,
|
||||
voucherNonce: 3,
|
||||
laneStates: []*paych.LaneState{{
|
||||
ID: 1,
|
||||
Redeemed: big.NewInt(2),
|
||||
Nonce: 2,
|
||||
}},
|
||||
laneStates: map[uint64]paych.LaneState{
|
||||
1: {
|
||||
Redeemed: big.NewInt(2),
|
||||
Nonce: 2,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "passes when nonce for different lane",
|
||||
key: fromKeyPrivate,
|
||||
@ -185,11 +192,12 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
voucherAmount: big.NewInt(5),
|
||||
voucherLane: 2,
|
||||
voucherNonce: 2,
|
||||
laneStates: []*paych.LaneState{{
|
||||
ID: 1,
|
||||
Redeemed: big.NewInt(2),
|
||||
Nonce: 3,
|
||||
}},
|
||||
laneStates: map[uint64]paych.LaneState{
|
||||
1: {
|
||||
Redeemed: big.NewInt(2),
|
||||
Nonce: 3,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "fails when voucher has higher nonce but lower value than lane state",
|
||||
expectError: true,
|
||||
@ -199,11 +207,12 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
voucherAmount: big.NewInt(5),
|
||||
voucherLane: 1,
|
||||
voucherNonce: 3,
|
||||
laneStates: []*paych.LaneState{{
|
||||
ID: 1,
|
||||
Redeemed: big.NewInt(6),
|
||||
Nonce: 2,
|
||||
}},
|
||||
laneStates: map[uint64]paych.LaneState{
|
||||
1: {
|
||||
Redeemed: big.NewInt(6),
|
||||
Nonce: 2,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
name: "fails when voucher + ToSend > balance",
|
||||
expectError: true,
|
||||
@ -226,11 +235,13 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
voucherAmount: big.NewInt(6),
|
||||
voucherLane: 1,
|
||||
voucherNonce: 2,
|
||||
laneStates: []*paych.LaneState{{
|
||||
ID: 1, // Lane 1 (same as voucher lane 1)
|
||||
Redeemed: big.NewInt(4),
|
||||
Nonce: 1,
|
||||
}},
|
||||
laneStates: map[uint64]paych.LaneState{
|
||||
// Lane 1 (same as voucher lane 1)
|
||||
1: {
|
||||
Redeemed: big.NewInt(4),
|
||||
Nonce: 1,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
// required balance = toSend + total redeemed
|
||||
// = 1 + 4 (lane 2) + 6 (voucher lane 1)
|
||||
@ -244,11 +255,13 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
voucherAmount: big.NewInt(6),
|
||||
voucherLane: 1,
|
||||
voucherNonce: 1,
|
||||
laneStates: []*paych.LaneState{{
|
||||
ID: 2, // Lane 2 (different from voucher lane 1)
|
||||
Redeemed: big.NewInt(4),
|
||||
Nonce: 1,
|
||||
}},
|
||||
laneStates: map[uint64]paych.LaneState{
|
||||
// Lane 2 (different from voucher lane 1)
|
||||
2: {
|
||||
Redeemed: big.NewInt(4),
|
||||
Nonce: 1,
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
||||
for _, tcase := range tcases {
|
||||
@ -262,13 +275,17 @@ func TestCheckVoucherValid(t *testing.T) {
|
||||
Nonce: 0,
|
||||
Balance: tcase.actorBalance,
|
||||
}
|
||||
|
||||
laneStates, err := mock.storeLaneStates(tcase.laneStates)
|
||||
require.NoError(t, err)
|
||||
|
||||
mock.setPaychState(ch, act, paych.State{
|
||||
From: fromAcct,
|
||||
To: toAcct,
|
||||
ToSend: tcase.toSend,
|
||||
SettlingAt: abi.ChainEpoch(0),
|
||||
MinSettleHeight: abi.ChainEpoch(0),
|
||||
LaneStates: tcase.laneStates,
|
||||
LaneStates: laneStates,
|
||||
})
|
||||
|
||||
mgr, err := newManager(store, mock)
|
||||
@ -309,15 +326,16 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
|
||||
|
||||
actorBalance := big.NewInt(10)
|
||||
toSend := big.NewInt(1)
|
||||
laneStates := []*paych.LaneState{{
|
||||
ID: 1,
|
||||
Nonce: 1,
|
||||
Redeemed: big.NewInt(3),
|
||||
}, {
|
||||
ID: 2,
|
||||
Nonce: 1,
|
||||
Redeemed: big.NewInt(4),
|
||||
}}
|
||||
laneStates := map[uint64]paych.LaneState{
|
||||
1: {
|
||||
Nonce: 1,
|
||||
Redeemed: big.NewInt(3),
|
||||
},
|
||||
2: {
|
||||
Nonce: 1,
|
||||
Redeemed: big.NewInt(4),
|
||||
},
|
||||
}
|
||||
|
||||
act := &types.Actor{
|
||||
Code: builtin.AccountActorCodeID,
|
||||
@ -325,13 +343,16 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
|
||||
Nonce: 0,
|
||||
Balance: actorBalance,
|
||||
}
|
||||
|
||||
lsCid, err := mock.storeLaneStates(laneStates)
|
||||
require.NoError(t, err)
|
||||
mock.setPaychState(ch, act, paych.State{
|
||||
From: fromAcct,
|
||||
To: toAcct,
|
||||
ToSend: toSend,
|
||||
SettlingAt: abi.ChainEpoch(0),
|
||||
MinSettleHeight: abi.ChainEpoch(0),
|
||||
LaneStates: laneStates,
|
||||
LaneStates: lsCid,
|
||||
})
|
||||
|
||||
mgr, err := newManager(store, mock)
|
||||
@ -625,6 +646,8 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, addre
|
||||
toAcct := tutils.NewActorAddr(t, "toAct")
|
||||
|
||||
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})
|
||||
|
||||
@ -640,7 +663,7 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) (*Manager, addre
|
||||
ToSend: big.NewInt(0),
|
||||
SettlingAt: abi.ChainEpoch(0),
|
||||
MinSettleHeight: abi.ChainEpoch(0),
|
||||
LaneStates: []*paych.LaneState{},
|
||||
LaneStates: arr,
|
||||
})
|
||||
|
||||
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
|
||||
|
@ -2,6 +2,9 @@ package paychmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
||||
|
||||
@ -43,10 +46,15 @@ func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Ad
|
||||
}
|
||||
to := account.Address
|
||||
|
||||
nextLane, err := ca.nextLaneFromState(ctx, st)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ci := &ChannelInfo{
|
||||
Channel: &ch,
|
||||
Direction: dir,
|
||||
NextLane: nextLaneFromState(st),
|
||||
NextLane: nextLane,
|
||||
}
|
||||
|
||||
if dir == DirOutbound {
|
||||
@ -60,16 +68,28 @@ func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Ad
|
||||
return ci, nil
|
||||
}
|
||||
|
||||
func nextLaneFromState(st *paych.State) uint64 {
|
||||
if len(st.LaneStates) == 0 {
|
||||
return 0
|
||||
func (ca *stateAccessor) nextLaneFromState(ctx context.Context, st *paych.State) (uint64, error) {
|
||||
store := ca.sm.AdtStore(ctx)
|
||||
laneStates, err := adt.AsArray(store, st.LaneStates)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if laneStates.Length() == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
maxLane := st.LaneStates[0].ID
|
||||
for _, state := range st.LaneStates {
|
||||
if state.ID > maxLane {
|
||||
maxLane = state.ID
|
||||
nextID := int64(0)
|
||||
stopErr := errors.New("stop")
|
||||
if err := laneStates.ForEach(nil, func(i int64) error {
|
||||
if nextID < i {
|
||||
// We've found a hole. Stop here.
|
||||
return stopErr
|
||||
}
|
||||
nextID++
|
||||
return nil
|
||||
}); err != nil && err != stopErr {
|
||||
return 0, err
|
||||
}
|
||||
return maxLane + 1
|
||||
|
||||
return uint64(nextID), nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user