feat(paych): convert paych actor

build abstraction for paych actor and switch to using it in payment channel manager and state
predicates
This commit is contained in:
hannahhoward 2020-09-15 21:06:04 -07:00
parent 4e01fad0d4
commit 05c11531b1
15 changed files with 460 additions and 346 deletions

View File

@ -0,0 +1,89 @@
package mock
import (
"io"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
)
type mockState struct {
from address.Address
to address.Address
settlingAt abi.ChainEpoch
toSend abi.TokenAmount
lanes map[uint64]paych.LaneState
}
type mockLaneState struct {
redeemed big.Int
nonce uint64
}
// NewMockPayChState constructs a state for a payment channel with the set fixed values
// that satisfies the paych.State interface.
func NewMockPayChState(from address.Address,
to address.Address,
settlingAt abi.ChainEpoch,
toSend abi.TokenAmount,
lanes map[uint64]paych.LaneState,
) paych.State {
return &mockState{from, to, settlingAt, toSend, lanes}
}
// NewMockLaneState constructs a state for a payment channel lane with the set fixed values
// that satisfies the paych.LaneState interface. Useful for populating lanes when
// calling NewMockPayChState
func NewMockLaneState(redeemed big.Int, nonce uint64) paych.LaneState {
return &mockLaneState{redeemed, nonce}
}
func (ms *mockState) MarshalCBOR(io.Writer) error {
panic("not implemented")
}
// Channel owner, who has funded the actor
func (ms *mockState) From() address.Address {
return ms.from
}
// Recipient of payouts from channel
func (ms *mockState) To() address.Address {
return ms.to
}
// Height at which the channel can be `Collected`
func (ms *mockState) SettlingAt() abi.ChainEpoch {
return ms.settlingAt
}
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
func (ms *mockState) ToSend() abi.TokenAmount {
return ms.toSend
}
// Get total number of lanes
func (ms *mockState) LaneCount() (uint64, error) {
return uint64(len(ms.lanes)), nil
}
// Iterate lane states
func (ms *mockState) ForEachLaneState(cb func(idx uint64, dl paych.LaneState) error) error {
var lastErr error
for lane, state := range ms.lanes {
if err := cb(lane, state); err != nil {
lastErr = err
}
}
return lastErr
}
func (mls *mockLaneState) Redeemed() big.Int {
return mls.redeemed
}
func (mls *mockLaneState) Nonce() uint64 {
return mls.nonce
}

View File

@ -0,0 +1,56 @@
package paych
import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
big "github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/cbor"
v0builtin "github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/types"
)
// Load returns an abstract copy of payment channel state, irregardless of actor version
func Load(store adt.Store, act *types.Actor) (State, error) {
switch act.Code {
case v0builtin.PaymentChannelActorCodeID:
out := v0State{store: store}
err := store.Get(store.Context(), act.Head, &out)
if err != nil {
return nil, err
}
return &out, nil
}
return nil, xerrors.Errorf("unknown actor code %s", act.Code)
}
// State is an abstract version of payment channel state that works across
// versions
type State interface {
cbor.Marshaler
// Channel owner, who has funded the actor
From() address.Address
// Recipient of payouts from channel
To() address.Address
// Height at which the channel can be `Collected`
SettlingAt() abi.ChainEpoch
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
ToSend() abi.TokenAmount
// Get total number of lanes
LaneCount() (uint64, error)
// Iterate lane states
ForEachLaneState(cb func(idx uint64, dl LaneState) error) error
}
// LaneState is an abstract copy of the state of a single lane
type LaneState interface {
Redeemed() big.Int
Nonce() uint64
}

View File

@ -0,0 +1,89 @@
package paych
import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
big "github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
v0adt "github.com/filecoin-project/specs-actors/actors/util/adt"
)
type v0State struct {
paych.State
store adt.Store
lsAmt *v0adt.Array
}
// Channel owner, who has funded the actor
func (s *v0State) From() address.Address {
return s.State.From
}
// Recipient of payouts from channel
func (s *v0State) To() address.Address {
return s.State.From
}
// Height at which the channel can be `Collected`
func (s *v0State) SettlingAt() abi.ChainEpoch {
return s.State.SettlingAt
}
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
func (s *v0State) ToSend() abi.TokenAmount {
return s.State.ToSend
}
func (s *v0State) getOrLoadLsAmt() (*v0adt.Array, error) {
if s.lsAmt != nil {
return s.lsAmt, nil
}
// Get the lane state from the chain
lsamt, err := v0adt.AsArray(s.store, s.State.LaneStates)
if err != nil {
return nil, err
}
s.lsAmt = lsamt
return lsamt, nil
}
// Get total number of lanes
func (s *v0State) LaneCount() (uint64, error) {
lsamt, err := s.getOrLoadLsAmt()
if err != nil {
return 0, err
}
return lsamt.Length(), nil
}
// Iterate lane states
func (s *v0State) ForEachLaneState(cb func(idx uint64, dl LaneState) error) error {
// Get the lane state from the chain
lsamt, err := s.getOrLoadLsAmt()
if err != nil {
return 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
return lsamt.ForEach(&ls, func(i int64) error {
return cb(uint64(i), &v0LaneState{ls})
})
}
type v0LaneState struct {
paych.LaneState
}
func (ls *v0LaneState) Redeemed() big.Int {
return ls.LaneState.Redeemed
}
func (ls *v0LaneState) Nonce() uint64 {
return ls.LaneState.Nonce
}

View File

@ -7,13 +7,12 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/specs-actors/actors/builtin" "github.com/filecoin-project/specs-actors/actors/builtin"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init" init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/builtin/market" "github.com/filecoin-project/specs-actors/actors/builtin/market"
"github.com/filecoin-project/specs-actors/actors/builtin/miner" "github.com/filecoin-project/specs-actors/actors/builtin/miner"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/filecoin-project/specs-actors/actors/util/adt" "github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
typegen "github.com/whyrusleeping/cbor-gen" typegen "github.com/whyrusleeping/cbor-gen"
@ -49,7 +48,7 @@ func NewStatePredicates(api ChainAPI) *StatePredicates {
// - err // - err
type DiffTipSetKeyFunc func(ctx context.Context, oldState, newState types.TipSetKey) (changed bool, user UserData, err error) type DiffTipSetKeyFunc func(ctx context.Context, oldState, newState types.TipSetKey) (changed bool, user UserData, err error)
type DiffActorStateFunc func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) type DiffActorStateFunc func(ctx context.Context, oldActorState *types.Actor, newActorState *types.Actor) (changed bool, user UserData, err error)
// OnActorStateChanged calls diffStateFunc when the state changes for the given actor // OnActorStateChanged calls diffStateFunc when the state changes for the given actor
func (sp *StatePredicates) OnActorStateChanged(addr address.Address, diffStateFunc DiffActorStateFunc) DiffTipSetKeyFunc { func (sp *StatePredicates) OnActorStateChanged(addr address.Address, diffStateFunc DiffActorStateFunc) DiffTipSetKeyFunc {
@ -66,7 +65,7 @@ func (sp *StatePredicates) OnActorStateChanged(addr address.Address, diffStateFu
if oldActor.Head.Equals(newActor.Head) { if oldActor.Head.Equals(newActor.Head) {
return false, nil, nil return false, nil, nil
} }
return diffStateFunc(ctx, oldActor.Head, newActor.Head) return diffStateFunc(ctx, oldActor, newActor)
} }
} }
@ -74,13 +73,13 @@ type DiffStorageMarketStateFunc func(ctx context.Context, oldState *market.State
// OnStorageMarketActorChanged calls diffStorageMarketState when the state changes for the market actor // OnStorageMarketActorChanged calls diffStorageMarketState when the state changes for the market actor
func (sp *StatePredicates) OnStorageMarketActorChanged(diffStorageMarketState DiffStorageMarketStateFunc) DiffTipSetKeyFunc { func (sp *StatePredicates) OnStorageMarketActorChanged(diffStorageMarketState DiffStorageMarketStateFunc) DiffTipSetKeyFunc {
return sp.OnActorStateChanged(builtin.StorageMarketActorAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) { return sp.OnActorStateChanged(builtin.StorageMarketActorAddr, func(ctx context.Context, oldActorState, newActorState *types.Actor) (changed bool, user UserData, err error) {
var oldState market.State var oldState market.State
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil { if err := sp.cst.Get(ctx, oldActorState.Head, &oldState); err != nil {
return false, nil, err return false, nil, err
} }
var newState market.State var newState market.State
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil { if err := sp.cst.Get(ctx, newActorState.Head, &newState); err != nil {
return false, nil, err return false, nil, err
} }
return diffStorageMarketState(ctx, &oldState, &newState) return diffStorageMarketState(ctx, &oldState, &newState)
@ -408,13 +407,13 @@ func (sp *StatePredicates) AvailableBalanceChangedForAddresses(getAddrs func() [
type DiffMinerActorStateFunc func(ctx context.Context, oldState *miner.State, newState *miner.State) (changed bool, user UserData, err error) type DiffMinerActorStateFunc func(ctx context.Context, oldState *miner.State, newState *miner.State) (changed bool, user UserData, err error)
func (sp *StatePredicates) OnInitActorChange(diffInitActorState DiffInitActorStateFunc) DiffTipSetKeyFunc { func (sp *StatePredicates) OnInitActorChange(diffInitActorState DiffInitActorStateFunc) DiffTipSetKeyFunc {
return sp.OnActorStateChanged(builtin.InitActorAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) { return sp.OnActorStateChanged(builtin.InitActorAddr, func(ctx context.Context, oldActorState, newActorState *types.Actor) (changed bool, user UserData, err error) {
var oldState init_.State var oldState init_.State
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil { if err := sp.cst.Get(ctx, oldActorState.Head, &oldState); err != nil {
return false, nil, err return false, nil, err
} }
var newState init_.State var newState init_.State
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil { if err := sp.cst.Get(ctx, newActorState.Head, &newState); err != nil {
return false, nil, err return false, nil, err
} }
return diffInitActorState(ctx, &oldState, &newState) return diffInitActorState(ctx, &oldState, &newState)
@ -423,13 +422,13 @@ func (sp *StatePredicates) OnInitActorChange(diffInitActorState DiffInitActorSta
} }
func (sp *StatePredicates) OnMinerActorChange(minerAddr address.Address, diffMinerActorState DiffMinerActorStateFunc) DiffTipSetKeyFunc { func (sp *StatePredicates) OnMinerActorChange(minerAddr address.Address, diffMinerActorState DiffMinerActorStateFunc) DiffTipSetKeyFunc {
return sp.OnActorStateChanged(minerAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) { return sp.OnActorStateChanged(minerAddr, func(ctx context.Context, oldActorState, newActorState *types.Actor) (changed bool, user UserData, err error) {
var oldState miner.State var oldState miner.State
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil { if err := sp.cst.Get(ctx, oldActorState.Head, &oldState); err != nil {
return false, nil, err return false, nil, err
} }
var newState miner.State var newState miner.State
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil { if err := sp.cst.Get(ctx, newActorState.Head, &newState); err != nil {
return false, nil, err return false, nil, err
} }
return diffMinerActorState(ctx, &oldState, &newState) return diffMinerActorState(ctx, &oldState, &newState)
@ -608,20 +607,20 @@ func (sp *StatePredicates) OnMinerPreCommitChange() DiffMinerActorStateFunc {
} }
// DiffPaymentChannelStateFunc is function that compares two states for the payment channel // DiffPaymentChannelStateFunc is function that compares two states for the payment channel
type DiffPaymentChannelStateFunc func(ctx context.Context, oldState *paych.State, newState *paych.State) (changed bool, user UserData, err error) type DiffPaymentChannelStateFunc func(ctx context.Context, oldState paych.State, newState paych.State) (changed bool, user UserData, err error)
// OnPaymentChannelActorChanged calls diffPaymentChannelState when the state changes for the the payment channel actor // OnPaymentChannelActorChanged calls diffPaymentChannelState when the state changes for the the payment channel actor
func (sp *StatePredicates) OnPaymentChannelActorChanged(paychAddr address.Address, diffPaymentChannelState DiffPaymentChannelStateFunc) DiffTipSetKeyFunc { func (sp *StatePredicates) OnPaymentChannelActorChanged(paychAddr address.Address, diffPaymentChannelState DiffPaymentChannelStateFunc) DiffTipSetKeyFunc {
return sp.OnActorStateChanged(paychAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) { return sp.OnActorStateChanged(paychAddr, func(ctx context.Context, oldActorState, newActorState *types.Actor) (changed bool, user UserData, err error) {
var oldState paych.State oldState, err := paych.Load(adt.WrapStore(ctx, sp.cst), oldActorState)
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
var newState paych.State newState, err := paych.Load(adt.WrapStore(ctx, sp.cst), newActorState)
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
return diffPaymentChannelState(ctx, &oldState, &newState) return diffPaymentChannelState(ctx, oldState, newState)
}) })
} }
@ -633,13 +632,13 @@ type PayChToSendChange struct {
// OnToSendAmountChanges monitors changes on the total amount to send from one party to the other on a payment channel // OnToSendAmountChanges monitors changes on the total amount to send from one party to the other on a payment channel
func (sp *StatePredicates) OnToSendAmountChanges() DiffPaymentChannelStateFunc { func (sp *StatePredicates) OnToSendAmountChanges() DiffPaymentChannelStateFunc {
return func(ctx context.Context, oldState *paych.State, newState *paych.State) (changed bool, user UserData, err error) { return func(ctx context.Context, oldState paych.State, newState paych.State) (changed bool, user UserData, err error) {
if oldState.ToSend.Equals(newState.ToSend) { if oldState.ToSend().Equals(newState.ToSend()) {
return false, nil, nil return false, nil, nil
} }
return true, &PayChToSendChange{ return true, &PayChToSendChange{
OldToSend: oldState.ToSend, OldToSend: oldState.ToSend(),
NewToSend: newState.ToSend, NewToSend: newState.ToSend(),
}, nil }, nil
} }
} }

View File

@ -221,7 +221,7 @@ func TestMarketPredicates(t *testing.T) {
// Test that OnActorStateChanged does not call the callback if the state has not changed // Test that OnActorStateChanged does not call the callback if the state has not changed
mockAddr, err := address.NewFromString("t01") mockAddr, err := address.NewFromString("t01")
require.NoError(t, err) require.NoError(t, err)
actorDiffFn := preds.OnActorStateChanged(mockAddr, func(context.Context, cid.Cid, cid.Cid) (bool, UserData, error) { actorDiffFn := preds.OnActorStateChanged(mockAddr, func(context.Context, *types.Actor, *types.Actor) (bool, UserData, error) {
t.Fatal("No state change so this should not be called") t.Fatal("No state change so this should not be called")
return false, nil, nil return false, nil, nil
}) })

View File

@ -25,6 +25,7 @@ import (
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/builtin/market" "github.com/filecoin-project/lotus/chain/actors/builtin/market"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/actors/builtin/power" "github.com/filecoin-project/lotus/chain/actors/builtin/power"
"github.com/filecoin-project/lotus/chain/state" "github.com/filecoin-project/lotus/chain/state"
"github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/store"
@ -1145,3 +1146,21 @@ func (sm *StateManager) GetNtwkVersion(ctx context.Context, height abi.ChainEpoc
return build.NewestNetworkVersion return build.NewestNetworkVersion
} }
func (sm *StateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) {
st, err := sm.ParentState(ts)
if err != nil {
return nil, nil, err
}
act, err := st.GetActor(addr)
if err != nil {
return nil, nil, err
}
actState, err := paych.Load(sm.cs.Store(ctx), act)
if err != nil {
return nil, nil, err
}
return act, actState, nil
}

View File

@ -24,7 +24,8 @@ import (
"github.com/filecoin-project/lotus/chain/events" "github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/api/apibstore" "github.com/filecoin-project/lotus/api/apibstore"
"github.com/filecoin-project/specs-actors/actors/builtin/paych" "github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
@ -88,7 +89,7 @@ func TestPaymentChannels(t *testing.T) {
// Wait for the chain to reach the settle height // Wait for the chain to reach the settle height
chState := getPaychState(ctx, t, paymentReceiver, chAddr) chState := getPaychState(ctx, t, paymentReceiver, chAddr)
waitForHeight(ctx, t, paymentReceiver, chState.SettlingAt) waitForHeight(ctx, t, paymentReceiver, chState.SettlingAt())
// receiver: paych collect <channel> // receiver: paych collect <channel>
cmd = []string{chAddr.String()} cmd = []string{chAddr.String()}
@ -540,8 +541,7 @@ func getPaychState(ctx context.Context, t *testing.T, node test.TestNode, chAddr
require.NoError(t, err) require.NoError(t, err)
store := cbor.NewCborStore(apibstore.NewAPIBlockstore(node)) store := cbor.NewCborStore(apibstore.NewAPIBlockstore(node))
var chState paych.State chState, err := paych.Load(adt.WrapStore(ctx, store), act)
err = store.Get(ctx, act.Head, &chState)
require.NoError(t, err) require.NoError(t, err)
return chState return chState

View File

@ -4,28 +4,23 @@ import (
"context" "context"
"sync" "sync"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/node/modules/helpers"
"github.com/ipfs/go-datastore"
xerrors "golang.org/x/xerrors"
"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" "github.com/ipfs/go-cid"
"github.com/ipfs/go-datastore"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
"go.uber.org/fx" "go.uber.org/fx"
xerrors "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/crypto"
v0paych "github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors/adt"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/node/impl/full" "github.com/filecoin-project/lotus/node/impl/full"
"github.com/filecoin-project/lotus/node/modules/helpers"
) )
var log = logging.Logger("paych") var log = logging.Logger("paych")
@ -40,9 +35,9 @@ type PaychAPI struct {
// stateManagerAPI defines the methods needed from StateManager // stateManagerAPI defines the methods needed from StateManager
type stateManagerAPI interface { type stateManagerAPI interface {
LoadActorState(ctx context.Context, a address.Address, out interface{}, ts *types.TipSet) (*types.Actor, error) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error)
Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, 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 // paychAPI defines the API methods needed by the payment channel manager
@ -226,7 +221,7 @@ func (pm *Manager) GetChannelInfo(addr address.Address) (*ChannelInfo, error) {
return ca.getChannelInfo(addr) return ca.getChannelInfo(addr)
} }
func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, voucher paych.SignedVoucher) (*api.VoucherCreateResult, error) { func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, voucher v0paych.SignedVoucher) (*api.VoucherCreateResult, error) {
ca, err := pm.accessorByAddress(ch) ca, err := pm.accessorByAddress(ch)
if err != nil { if err != nil {
return nil, err return nil, err
@ -238,7 +233,7 @@ func (pm *Manager) CreateVoucher(ctx context.Context, ch address.Address, vouche
// CheckVoucherValid checks if the given voucher is valid (is or could become spendable at some point). // CheckVoucherValid checks if the given voucher is valid (is or could become spendable at some point).
// If the channel is not in the store, fetches the channel from state (and checks that // 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). // the channel To address is owned by the wallet).
func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) error { func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher) error {
// Get an accessor for the channel, creating it from state if necessary // Get an accessor for the channel, creating it from state if necessary
ca, err := pm.inboundChannelAccessor(ctx, ch) ca, err := pm.inboundChannelAccessor(ctx, ch)
if err != nil { if err != nil {
@ -250,7 +245,7 @@ func (pm *Manager) CheckVoucherValid(ctx context.Context, ch address.Address, sv
} }
// CheckVoucherSpendable checks if the given voucher is currently spendable // CheckVoucherSpendable checks if the given voucher is currently spendable
func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher, secret []byte, proof []byte) (bool, error) {
ca, err := pm.accessorByAddress(ch) ca, err := pm.accessorByAddress(ch)
if err != nil { if err != nil {
return false, err return false, err
@ -261,7 +256,7 @@ func (pm *Manager) CheckVoucherSpendable(ctx context.Context, ch address.Address
// AddVoucherOutbound adds a voucher for an outbound channel. // AddVoucherOutbound adds a voucher for an outbound channel.
// Returns an error if the channel is not already in the store. // 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) { func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
ca, err := pm.accessorByAddress(ch) ca, err := pm.accessorByAddress(ch)
if err != nil { if err != nil {
return types.NewInt(0), err return types.NewInt(0), err
@ -272,7 +267,7 @@ func (pm *Manager) AddVoucherOutbound(ctx context.Context, ch address.Address, s
// AddVoucherInbound adds a voucher for an inbound channel. // AddVoucherInbound adds a voucher for an inbound channel.
// If the channel is not in the store, fetches the channel from state (and checks that // 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). // 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) { func (pm *Manager) AddVoucherInbound(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
// Get an accessor for the channel, creating it from state if necessary // Get an accessor for the channel, creating it from state if necessary
ca, err := pm.inboundChannelAccessor(ctx, ch) ca, err := pm.inboundChannelAccessor(ctx, ch)
if err != nil { if err != nil {
@ -341,7 +336,7 @@ func (pm *Manager) trackInboundChannel(ctx context.Context, ch address.Address)
return pm.store.TrackChannel(stateCi) return pm.store.TrackChannel(stateCi)
} }
func (pm *Manager) SubmitVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) { func (pm *Manager) SubmitVoucher(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) {
ca, err := pm.accessorByAddress(ch) ca, err := pm.accessorByAddress(ch)
if err != nil { if err != nil {
return cid.Undef, err return cid.Undef, err

View File

@ -2,23 +2,18 @@ package paychmgr
import ( import (
"context" "context"
"fmt" "errors"
"sync" "sync"
"github.com/filecoin-project/lotus/lib/sigs" "github.com/ipfs/go-cid"
"github.com/filecoin-project/go-state-types/crypto"
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/go-address"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/builtin/account" "github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/ipfs/go-cid"
) )
type mockManagerAPI struct { type mockManagerAPI struct {
@ -40,29 +35,23 @@ type mockPchState struct {
type mockStateManager struct { type mockStateManager struct {
lk sync.Mutex lk sync.Mutex
accountState map[address.Address]account.State accountState map[address.Address]address.Address
paychState map[address.Address]mockPchState paychState map[address.Address]mockPchState
store adt.Store
response *api.InvocResult response *api.InvocResult
lastCall *types.Message lastCall *types.Message
} }
func newMockStateManager() *mockStateManager { func newMockStateManager() *mockStateManager {
return &mockStateManager{ return &mockStateManager{
accountState: make(map[address.Address]account.State), accountState: make(map[address.Address]address.Address),
paychState: make(map[address.Address]mockPchState), paychState: make(map[address.Address]mockPchState),
store: adt.WrapStore(context.Background(), cbornode.NewMemCborStore()),
} }
} }
func (sm *mockStateManager) AdtStore(ctx context.Context) adt.Store { func (sm *mockStateManager) setAccountAddress(a address.Address, lookup address.Address) {
return sm.store
}
func (sm *mockStateManager) setAccountState(a address.Address, state account.State) {
sm.lk.Lock() sm.lk.Lock()
defer sm.lk.Unlock() defer sm.lk.Unlock()
sm.accountState[a] = state sm.accountState[a] = lookup
} }
func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor, state paych.State) { func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor, state paych.State) {
@ -71,31 +60,24 @@ func (sm *mockStateManager) setPaychState(a address.Address, actor *types.Actor,
sm.paychState[a] = mockPchState{actor, state} sm.paychState[a] = mockPchState{actor, state}
} }
func (sm *mockStateManager) storeLaneStates(laneStates map[uint64]paych.LaneState) (cid.Cid, error) { func (sm *mockStateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, 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() sm.lk.Lock()
defer sm.lk.Unlock() defer sm.lk.Unlock()
keyAddr, ok := sm.accountState[addr]
if !ok {
return address.Undef, errors.New("not found")
}
return keyAddr, nil
}
if outState, ok := out.(*account.State); ok { func (sm *mockStateManager) GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) {
*outState = sm.accountState[a] sm.lk.Lock()
return nil, nil defer sm.lk.Unlock()
info, ok := sm.paychState[addr]
if !ok {
return nil, nil, errors.New("not found")
} }
if outState, ok := out.(*paych.State); ok { return info.actor, info.state, nil
info := sm.paychState[a]
*outState = info.state
return info.actor, nil
}
panic(fmt.Sprintf("unexpected state type %v", out))
} }
func (sm *mockStateManager) setCallResponse(response *api.InvocResult) { func (sm *mockStateManager) setCallResponse(response *api.InvocResult) {

View File

@ -4,9 +4,7 @@ import (
"testing" "testing"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"golang.org/x/xerrors" "golang.org/x/xerrors"
) )

View File

@ -5,22 +5,20 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
cborutil "github.com/filecoin-project/go-cbor-util" cborutil "github.com/filecoin-project/go-cbor-util"
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
v0paych "github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/account"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
"golang.org/x/xerrors"
) )
// insufficientFundsErr indicates that there are not enough funds in the // insufficientFundsErr indicates that there are not enough funds in the
@ -45,6 +43,19 @@ func (e *ErrInsufficientFunds) Shortfall() types.BigInt {
return e.shortfall return e.shortfall
} }
type laneState struct {
redeemed big.Int
nonce uint64
}
func (ls laneState) Redeemed() big.Int {
return ls.redeemed
}
func (ls laneState) Nonce() uint64 {
return ls.nonce
}
// channelAccessor is used to simplify locking when accessing a channel // channelAccessor is used to simplify locking when accessing a channel
type channelAccessor struct { type channelAccessor struct {
from address.Address from address.Address
@ -92,7 +103,7 @@ func (ca *channelAccessor) outboundActiveByFromTo(from, to address.Address) (*Ch
// nonce, signing the voucher and storing it in the local datastore. // nonce, signing the voucher and storing it in the local datastore.
// If there are not enough funds in the channel to create the voucher, returns // If there are not enough funds in the channel to create the voucher, returns
// the shortfall in funds. // the shortfall in funds.
func (ca *channelAccessor) createVoucher(ctx context.Context, ch address.Address, voucher paych.SignedVoucher) (*api.VoucherCreateResult, error) { func (ca *channelAccessor) createVoucher(ctx context.Context, ch address.Address, voucher v0paych.SignedVoucher) (*api.VoucherCreateResult, error) {
ca.lk.Lock() ca.lk.Lock()
defer ca.lk.Unlock() defer ca.lk.Unlock()
@ -151,14 +162,14 @@ func (ca *channelAccessor) nextNonceForLane(ci *ChannelInfo, lane uint64) uint64
return maxnonce + 1 return maxnonce + 1
} }
func (ca *channelAccessor) checkVoucherValid(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (map[uint64]*paych.LaneState, error) { func (ca *channelAccessor) checkVoucherValid(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher) (map[uint64]paych.LaneState, error) {
ca.lk.Lock() ca.lk.Lock()
defer ca.lk.Unlock() defer ca.lk.Unlock()
return ca.checkVoucherValidUnlocked(ctx, ch, sv) return ca.checkVoucherValidUnlocked(ctx, ch, sv)
} }
func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch address.Address, sv *paych.SignedVoucher) (map[uint64]*paych.LaneState, error) { func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher) (map[uint64]paych.LaneState, error) {
if sv.ChannelAddr != ch { if sv.ChannelAddr != ch {
return nil, xerrors.Errorf("voucher ChannelAddr doesn't match channel address, got %s, expected %s", sv.ChannelAddr, ch) return nil, xerrors.Errorf("voucher ChannelAddr doesn't match channel address, got %s, expected %s", sv.ChannelAddr, ch)
} }
@ -170,12 +181,10 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
} }
// Load channel "From" account actor state // Load channel "From" account actor state
var actState account.State from, err := ca.api.ResolveToKeyAddress(ctx, pchState.From(), nil)
_, err = ca.api.LoadActorState(ctx, pchState.From, &actState, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
from := actState.Address
// verify voucher signature // verify voucher signature
vb, err := sv.SigningBytes() vb, err := sv.SigningBytes()
@ -199,12 +208,12 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
// If the new voucher nonce value is less than the highest known // If the new voucher nonce value is less than the highest known
// nonce for the lane // nonce for the lane
ls, lsExists := laneStates[sv.Lane] ls, lsExists := laneStates[sv.Lane]
if lsExists && sv.Nonce <= ls.Nonce { if lsExists && sv.Nonce <= ls.Nonce() {
return nil, fmt.Errorf("nonce too low") return nil, fmt.Errorf("nonce too low")
} }
// If the voucher amount is less than the highest known voucher amount // If the voucher amount is less than the highest known voucher amount
if lsExists && sv.Amount.LessThanEqual(ls.Redeemed) { if lsExists && sv.Amount.LessThanEqual(ls.Redeemed()) {
return nil, fmt.Errorf("voucher amount is lower than amount for voucher with lower nonce") return nil, fmt.Errorf("voucher amount is lower than amount for voucher with lower nonce")
} }
@ -230,7 +239,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
// Total required balance = total redeemed + toSend // Total required balance = total redeemed + toSend
// Must not exceed actor balance // Must not exceed actor balance
newTotal := types.BigAdd(totalRedeemed, pchState.ToSend) newTotal := types.BigAdd(totalRedeemed, pchState.ToSend())
if act.Balance.LessThan(newTotal) { if act.Balance.LessThan(newTotal) {
return nil, newErrInsufficientFunds(types.BigSub(newTotal, act.Balance)) return nil, newErrInsufficientFunds(types.BigSub(newTotal, act.Balance))
} }
@ -242,7 +251,7 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
return laneStates, nil return laneStates, nil
} }
func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher, secret []byte, proof []byte) (bool, error) {
ca.lk.Lock() ca.lk.Lock()
defer ca.lk.Unlock() defer ca.lk.Unlock()
@ -281,7 +290,7 @@ func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address
} }
} }
enc, err := actors.SerializeParams(&paych.UpdateChannelStateParams{ enc, err := actors.SerializeParams(&v0paych.UpdateChannelStateParams{
Sv: *sv, Sv: *sv,
Secret: secret, Secret: secret,
Proof: proof, Proof: proof,
@ -308,22 +317,22 @@ func (ca *channelAccessor) checkVoucherSpendable(ctx context.Context, ch address
} }
func (ca *channelAccessor) getPaychRecipient(ctx context.Context, ch address.Address) (address.Address, error) { func (ca *channelAccessor) getPaychRecipient(ctx context.Context, ch address.Address) (address.Address, error) {
var state paych.State _, state, err := ca.api.GetPaychState(ctx, ch, nil)
if _, err := ca.api.LoadActorState(ctx, ch, &state, nil); err != nil { if err != nil {
return address.Address{}, err return address.Address{}, err
} }
return state.To, nil return state.To(), nil
} }
func (ca *channelAccessor) addVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { func (ca *channelAccessor) addVoucher(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
ca.lk.Lock() ca.lk.Lock()
defer ca.lk.Unlock() defer ca.lk.Unlock()
return ca.addVoucherUnlocked(ctx, ch, sv, proof, minDelta) return ca.addVoucherUnlocked(ctx, ch, sv, proof, minDelta)
} }
func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
ci, err := ca.store.ByAddress(ch) ci, err := ca.store.ByAddress(ch)
if err != nil { if err != nil {
return types.BigInt{}, err return types.BigInt{}, err
@ -367,7 +376,7 @@ func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Ad
laneState, exists := laneStates[sv.Lane] laneState, exists := laneStates[sv.Lane]
redeemed := big.NewInt(0) redeemed := big.NewInt(0)
if exists { if exists {
redeemed = laneState.Redeemed redeemed = laneState.Redeemed()
} }
delta := types.BigSub(sv.Amount, redeemed) delta := types.BigSub(sv.Amount, redeemed)
@ -387,7 +396,7 @@ func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Ad
return delta, ca.store.putChannelInfo(ci) return delta, ca.store.putChannelInfo(ci)
} }
func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address, sv *paych.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) { func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address, sv *v0paych.SignedVoucher, secret []byte, proof []byte) (cid.Cid, error) {
ca.lk.Lock() ca.lk.Lock()
defer ca.lk.Unlock() defer ca.lk.Unlock()
@ -428,7 +437,7 @@ func (ca *channelAccessor) submitVoucher(ctx context.Context, ch address.Address
} }
} }
enc, err := actors.SerializeParams(&paych.UpdateChannelStateParams{ enc, err := actors.SerializeParams(&v0paych.UpdateChannelStateParams{
Sv: *sv, Sv: *sv,
Secret: secret, Secret: secret,
Proof: proof, Proof: proof,
@ -487,13 +496,11 @@ func (ca *channelAccessor) listVouchers(ctx context.Context, ch address.Address)
// laneState gets the LaneStates from chain, then applies all vouchers in // laneState gets the LaneStates from chain, then applies all vouchers in
// the data store over the chain state // the data store over the chain state
func (ca *channelAccessor) laneState(ctx context.Context, 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 // TODO: we probably want to call UpdateChannelState with all vouchers to be fully correct
// (but technically dont't need to) // (but technically dont't need to)
// Get the lane state from the chain laneCount, err := state.LaneCount()
store := ca.api.AdtStore(ctx)
lsamt, err := adt.AsArray(store, state.LaneStates)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -501,11 +508,9 @@ func (ca *channelAccessor) laneState(ctx context.Context, state *paych.State, ch
// Note: we use a map instead of an array to store laneStates because the // 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 // client sets the lane ID (the index) and potentially they could use a
// very large index. // very large index.
var ls paych.LaneState laneStates := make(map[uint64]paych.LaneState, laneCount)
laneStates := make(map[uint64]*paych.LaneState, lsamt.Length()) err = state.ForEachLaneState(func(idx uint64, ls paych.LaneState) error {
err = lsamt.ForEach(&ls, func(i int64) error { laneStates[idx] = ls
current := ls
laneStates[uint64(i)] = &current
return nil return nil
}) })
if err != nil { if err != nil {
@ -526,27 +531,19 @@ func (ca *channelAccessor) laneState(ctx context.Context, state *paych.State, ch
// If there's a voucher for a lane that isn't in chain state just // If there's a voucher for a lane that isn't in chain state just
// create it // create it
ls, ok := laneStates[v.Voucher.Lane] ls, ok := laneStates[v.Voucher.Lane]
if !ok {
ls = &paych.LaneState{
Redeemed: types.NewInt(0),
Nonce: 0,
}
laneStates[v.Voucher.Lane] = ls
}
if v.Voucher.Nonce < ls.Nonce { if ok && v.Voucher.Nonce < ls.Nonce() {
continue continue
} }
ls.Nonce = v.Voucher.Nonce laneStates[v.Voucher.Lane] = laneState{v.Voucher.Amount, v.Voucher.Nonce}
ls.Redeemed = v.Voucher.Amount
} }
return laneStates, nil return laneStates, nil
} }
// Get the total redeemed amount across all lanes, after applying the voucher // Get the total redeemed amount across all lanes, after applying the voucher
func (ca *channelAccessor) totalRedeemedWithVoucher(laneStates map[uint64]*paych.LaneState, sv *paych.SignedVoucher) (big.Int, error) { func (ca *channelAccessor) totalRedeemedWithVoucher(laneStates map[uint64]paych.LaneState, sv *v0paych.SignedVoucher) (big.Int, error) {
// TODO: merges // TODO: merges
if len(sv.Merges) != 0 { if len(sv.Merges) != 0 {
return big.Int{}, xerrors.Errorf("dont currently support paych lane merges") return big.Int{}, xerrors.Errorf("dont currently support paych lane merges")
@ -554,17 +551,17 @@ func (ca *channelAccessor) totalRedeemedWithVoucher(laneStates map[uint64]*paych
total := big.NewInt(0) total := big.NewInt(0)
for _, ls := range laneStates { for _, ls := range laneStates {
total = big.Add(total, ls.Redeemed) total = big.Add(total, ls.Redeemed())
} }
lane, ok := laneStates[sv.Lane] lane, ok := laneStates[sv.Lane]
if ok { if ok {
// If the voucher is for an existing lane, and the voucher nonce // If the voucher is for an existing lane, and the voucher nonce
// is higher than the lane nonce // is higher than the lane nonce
if sv.Nonce > lane.Nonce { if sv.Nonce > lane.Nonce() {
// Add the delta between the redeemed amount and the voucher // Add the delta between the redeemed amount and the voucher
// amount to the total // amount to the total
delta := big.Sub(sv.Amount, lane.Redeemed) delta := big.Sub(sv.Amount, lane.Redeemed())
total = big.Add(total, delta) total = big.Add(total, delta)
} }
} else { } else {

View File

@ -5,31 +5,24 @@ import (
"context" "context"
"testing" "testing"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/abi"
tutils "github.com/filecoin-project/specs-actors/support/testing"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/filecoin-project/specs-actors/actors/builtin/account"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
ds "github.com/ipfs/go-datastore" ds "github.com/ipfs/go-datastore"
ds_sync "github.com/ipfs/go-datastore/sync" ds_sync "github.com/ipfs/go-datastore/sync"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/specs-actors/actors/builtin"
v0paych "github.com/filecoin-project/specs-actors/actors/builtin/paych"
tutils "github.com/filecoin-project/specs-actors/support/testing"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
paychmock "github.com/filecoin-project/lotus/chain/actors/builtin/paych/mock"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs"
) )
func TestCheckVoucherValid(t *testing.T) { func TestCheckVoucherValid(t *testing.T) {
@ -46,8 +39,8 @@ func TestCheckVoucherValid(t *testing.T) {
toAcct := tutils.NewActorAddr(t, "toAct") toAcct := tutils.NewActorAddr(t, "toAct")
mock := newMockManagerAPI() mock := newMockManagerAPI()
mock.setAccountState(fromAcct, account.State{Address: from}) mock.setAccountAddress(fromAcct, from)
mock.setAccountState(toAcct, account.State{Address: to}) mock.setAccountAddress(toAcct, to)
tcases := []struct { tcases := []struct {
name string name string
@ -96,10 +89,7 @@ func TestCheckVoucherValid(t *testing.T) {
voucherLane: 1, voucherLane: 1,
voucherNonce: 2, voucherNonce: 2,
laneStates: map[uint64]paych.LaneState{ laneStates: map[uint64]paych.LaneState{
1: { 1: paychmock.NewMockLaneState(big.NewInt(2), 3),
Redeemed: big.NewInt(2),
Nonce: 3,
},
}, },
}, { }, {
name: "passes when nonce higher", name: "passes when nonce higher",
@ -110,10 +100,7 @@ func TestCheckVoucherValid(t *testing.T) {
voucherLane: 1, voucherLane: 1,
voucherNonce: 3, voucherNonce: 3,
laneStates: map[uint64]paych.LaneState{ laneStates: map[uint64]paych.LaneState{
1: { 1: paychmock.NewMockLaneState(big.NewInt(2), 2),
Redeemed: big.NewInt(2),
Nonce: 2,
},
}, },
}, { }, {
name: "passes when nonce for different lane", name: "passes when nonce for different lane",
@ -124,10 +111,7 @@ func TestCheckVoucherValid(t *testing.T) {
voucherLane: 2, voucherLane: 2,
voucherNonce: 2, voucherNonce: 2,
laneStates: map[uint64]paych.LaneState{ laneStates: map[uint64]paych.LaneState{
1: { 1: paychmock.NewMockLaneState(big.NewInt(2), 3),
Redeemed: big.NewInt(2),
Nonce: 3,
},
}, },
}, { }, {
name: "fails when voucher has higher nonce but lower value than lane state", name: "fails when voucher has higher nonce but lower value than lane state",
@ -139,10 +123,7 @@ func TestCheckVoucherValid(t *testing.T) {
voucherLane: 1, voucherLane: 1,
voucherNonce: 3, voucherNonce: 3,
laneStates: map[uint64]paych.LaneState{ laneStates: map[uint64]paych.LaneState{
1: { 1: paychmock.NewMockLaneState(big.NewInt(6), 2),
Redeemed: big.NewInt(6),
Nonce: 2,
},
}, },
}, { }, {
name: "fails when voucher + ToSend > balance", name: "fails when voucher + ToSend > balance",
@ -168,10 +149,7 @@ func TestCheckVoucherValid(t *testing.T) {
voucherNonce: 2, voucherNonce: 2,
laneStates: map[uint64]paych.LaneState{ laneStates: map[uint64]paych.LaneState{
// Lane 1 (same as voucher lane 1) // Lane 1 (same as voucher lane 1)
1: { 1: paychmock.NewMockLaneState(big.NewInt(4), 1),
Redeemed: big.NewInt(4),
Nonce: 1,
},
}, },
}, { }, {
// required balance = toSend + total redeemed // required balance = toSend + total redeemed
@ -188,10 +166,7 @@ func TestCheckVoucherValid(t *testing.T) {
voucherNonce: 1, voucherNonce: 1,
laneStates: map[uint64]paych.LaneState{ laneStates: map[uint64]paych.LaneState{
// Lane 2 (different from voucher lane 1) // Lane 2 (different from voucher lane 1)
2: { 2: paychmock.NewMockLaneState(big.NewInt(4), 1),
Redeemed: big.NewInt(4),
Nonce: 1,
},
}, },
}} }}
@ -208,18 +183,8 @@ func TestCheckVoucherValid(t *testing.T) {
Balance: tcase.actorBalance, Balance: tcase.actorBalance,
} }
// Set the state of the channel's lanes mock.setPaychState(ch, act, paychmock.NewMockPayChState(
laneStates, err := mock.storeLaneStates(tcase.laneStates) fromAcct, toAcct, abi.ChainEpoch(0), tcase.toSend, 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: laneStates,
})
// Create a manager // Create a manager
mgr, err := newManager(store, mock) mgr, err := newManager(store, mock)
@ -255,22 +220,16 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
minDelta := big.NewInt(0) minDelta := big.NewInt(0)
mock := newMockManagerAPI() mock := newMockManagerAPI()
mock.setAccountState(fromAcct, account.State{Address: from}) mock.setAccountAddress(fromAcct, from)
mock.setAccountState(toAcct, account.State{Address: to}) mock.setAccountAddress(toAcct, to)
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
actorBalance := big.NewInt(10) actorBalance := big.NewInt(10)
toSend := big.NewInt(1) toSend := big.NewInt(1)
laneStates := map[uint64]paych.LaneState{ laneStates := map[uint64]paych.LaneState{
1: { 1: paychmock.NewMockLaneState(big.NewInt(3), 1),
Nonce: 1, 2: paychmock.NewMockLaneState(big.NewInt(4), 1),
Redeemed: big.NewInt(3),
},
2: {
Nonce: 1,
Redeemed: big.NewInt(4),
},
} }
act := &types.Actor{ act := &types.Actor{
@ -280,16 +239,7 @@ func TestCheckVoucherValidCountingAllLanes(t *testing.T) {
Balance: actorBalance, Balance: actorBalance,
} }
lsCid, err := mock.storeLaneStates(laneStates) mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), toSend, 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: lsCid,
})
mgr, err := newManager(store, mock) mgr, err := newManager(store, mock)
require.NoError(t, err) require.NoError(t, err)
@ -389,7 +339,7 @@ func TestCreateVoucher(t *testing.T) {
// Create a voucher in lane 1 // Create a voucher in lane 1
voucherLane1Amt := big.NewInt(5) voucherLane1Amt := big.NewInt(5)
voucher := paych.SignedVoucher{ voucher := v0paych.SignedVoucher{
Lane: 1, Lane: 1,
Amount: voucherLane1Amt, Amount: voucherLane1Amt,
} }
@ -404,7 +354,7 @@ func TestCreateVoucher(t *testing.T) {
// Create a voucher in lane 1 again, with a higher amount // Create a voucher in lane 1 again, with a higher amount
voucherLane1Amt = big.NewInt(8) voucherLane1Amt = big.NewInt(8)
voucher = paych.SignedVoucher{ voucher = v0paych.SignedVoucher{
Lane: 1, Lane: 1,
Amount: voucherLane1Amt, Amount: voucherLane1Amt,
} }
@ -419,7 +369,7 @@ func TestCreateVoucher(t *testing.T) {
// Create a voucher in lane 2 that covers all the remaining funds // Create a voucher in lane 2 that covers all the remaining funds
// in the channel // in the channel
voucherLane2Amt := big.Sub(s.amt, voucherLane1Amt) voucherLane2Amt := big.Sub(s.amt, voucherLane1Amt)
voucher = paych.SignedVoucher{ voucher = v0paych.SignedVoucher{
Lane: 2, Lane: 2,
Amount: voucherLane2Amt, Amount: voucherLane2Amt,
} }
@ -433,7 +383,7 @@ func TestCreateVoucher(t *testing.T) {
// Create a voucher in lane 2 that exceeds the remaining funds in the // Create a voucher in lane 2 that exceeds the remaining funds in the
// channel // channel
voucherLane2Amt = big.Add(voucherLane2Amt, big.NewInt(1)) voucherLane2Amt = big.Add(voucherLane2Amt, big.NewInt(1))
voucher = paych.SignedVoucher{ voucher = v0paych.SignedVoucher{
Lane: 2, Lane: 2,
Amount: voucherLane2Amt, Amount: voucherLane2Amt,
} }
@ -567,8 +517,8 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) {
toAcct := tutils.NewActorAddr(t, "toAct") toAcct := tutils.NewActorAddr(t, "toAct")
mock := newMockManagerAPI() mock := newMockManagerAPI()
mock.setAccountState(fromAcct, account.State{Address: from}) mock.setAccountAddress(fromAcct, from)
mock.setAccountState(toAcct, account.State{Address: to}) mock.setAccountAddress(toAcct, to)
mock.addWalletAddress(to) mock.addWalletAddress(to)
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
@ -584,16 +534,7 @@ func TestAllocateLaneWithExistingLaneState(t *testing.T) {
Balance: actorBalance, Balance: actorBalance,
} }
arr, err := adt.MakeEmptyArray(mock.store).Root() mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), toSend, make(map[uint64]paych.LaneState)))
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: arr,
})
mgr, err := newManager(store, mock) mgr, err := newManager(store, mock)
require.NoError(t, err) require.NoError(t, err)
@ -681,19 +622,10 @@ func TestAddVoucherInboundWalletKey(t *testing.T) {
} }
mock := newMockManagerAPI() mock := newMockManagerAPI()
arr, err := adt.MakeEmptyArray(mock.store).Root() mock.setAccountAddress(fromAcct, from)
require.NoError(t, err) mock.setAccountAddress(toAcct, to)
mock.setAccountState(fromAcct, account.State{Address: from})
mock.setAccountState(toAcct, account.State{Address: to})
mock.setPaychState(ch, act, paych.State{ mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), types.NewInt(0), make(map[uint64]paych.LaneState)))
From: fromAcct,
To: toAcct,
ToSend: types.NewInt(0),
SettlingAt: abi.ChainEpoch(0),
MinSettleHeight: abi.ChainEpoch(0),
LaneStates: arr,
})
// Create a manager // Create a manager
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
@ -840,7 +772,7 @@ func TestCheckSpendable(t *testing.T) {
// Check that the secret and proof were passed through correctly // Check that the secret and proof were passed through correctly
lastCall := s.mock.getLastCall() lastCall := s.mock.getLastCall()
var p paych.UpdateChannelStateParams var p v0paych.UpdateChannelStateParams
err = p.UnmarshalCBOR(bytes.NewReader(lastCall.Params)) err = p.UnmarshalCBOR(bytes.NewReader(lastCall.Params))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, otherProof, p.Proof) require.Equal(t, otherProof, p.Proof)
@ -854,7 +786,7 @@ func TestCheckSpendable(t *testing.T) {
require.True(t, spendable) require.True(t, spendable)
lastCall = s.mock.getLastCall() lastCall = s.mock.getLastCall()
var p2 paych.UpdateChannelStateParams var p2 v0paych.UpdateChannelStateParams
err = p2.UnmarshalCBOR(bytes.NewReader(lastCall.Params)) err = p2.UnmarshalCBOR(bytes.NewReader(lastCall.Params))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, proof, p2.Proof) require.Equal(t, proof, p2.Proof)
@ -911,7 +843,7 @@ func TestSubmitVoucher(t *testing.T) {
// Check that the secret and proof were passed through correctly // Check that the secret and proof were passed through correctly
msg := s.mock.pushedMessages(submitCid) msg := s.mock.pushedMessages(submitCid)
var p paych.UpdateChannelStateParams var p v0paych.UpdateChannelStateParams
err = p.UnmarshalCBOR(bytes.NewReader(msg.Message.Params)) err = p.UnmarshalCBOR(bytes.NewReader(msg.Message.Params))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, submitProof, p.Proof) require.Equal(t, submitProof, p.Proof)
@ -931,7 +863,7 @@ func TestSubmitVoucher(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
msg = s.mock.pushedMessages(submitCid) msg = s.mock.pushedMessages(submitCid)
var p2 paych.UpdateChannelStateParams var p2 v0paych.UpdateChannelStateParams
err = p2.UnmarshalCBOR(bytes.NewReader(msg.Message.Params)) err = p2.UnmarshalCBOR(bytes.NewReader(msg.Message.Params))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, addVoucherProof2, p2.Proof) require.Equal(t, addVoucherProof2, p2.Proof)
@ -947,7 +879,7 @@ func TestSubmitVoucher(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
msg = s.mock.pushedMessages(submitCid) msg = s.mock.pushedMessages(submitCid)
var p3 paych.UpdateChannelStateParams var p3 v0paych.UpdateChannelStateParams
err = p3.UnmarshalCBOR(bytes.NewReader(msg.Message.Params)) err = p3.UnmarshalCBOR(bytes.NewReader(msg.Message.Params))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, proof3, p3.Proof) require.Equal(t, proof3, p3.Proof)
@ -986,10 +918,8 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) *testScaffold {
toAcct := tutils.NewActorAddr(t, "toAct") toAcct := tutils.NewActorAddr(t, "toAct")
mock := newMockManagerAPI() mock := newMockManagerAPI()
arr, err := adt.MakeEmptyArray(mock.store).Root() mock.setAccountAddress(fromAcct, from)
require.NoError(t, err) mock.setAccountAddress(toAcct, to)
mock.setAccountState(fromAcct, account.State{Address: from})
mock.setAccountState(toAcct, account.State{Address: to})
// Create channel in state // Create channel in state
balance := big.NewInt(20) balance := big.NewInt(20)
@ -999,14 +929,7 @@ func testSetupMgrWithChannel(ctx context.Context, t *testing.T) *testScaffold {
Nonce: 0, Nonce: 0,
Balance: balance, Balance: balance,
} }
mock.setPaychState(ch, act, paych.State{ mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), big.NewInt(0), make(map[uint64]paych.LaneState)))
From: fromAcct,
To: toAcct,
ToSend: big.NewInt(0),
SettlingAt: abi.ChainEpoch(0),
MinSettleHeight: abi.ChainEpoch(0),
LaneStates: arr,
})
store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore())) store := NewStore(ds_sync.MutexWrap(ds.NewMapDatastore()))
mgr, err := newManager(store, mock) mgr, err := newManager(store, mock)
@ -1043,8 +966,8 @@ func testGenerateKeyPair(t *testing.T) ([]byte, []byte) {
return priv, pub return priv, pub
} }
func createTestVoucher(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) *v0paych.SignedVoucher {
sv := &paych.SignedVoucher{ sv := &v0paych.SignedVoucher{
ChannelAddr: ch, ChannelAddr: ch,
Lane: voucherLane, Lane: voucherLane,
Nonce: nonce, Nonce: nonce,
@ -1059,13 +982,13 @@ func createTestVoucher(t *testing.T, ch address.Address, voucherLane uint64, non
return sv return sv
} }
func createTestVoucherWithExtra(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *paych.SignedVoucher { func createTestVoucherWithExtra(t *testing.T, ch address.Address, voucherLane uint64, nonce uint64, voucherAmount big.Int, key []byte) *v0paych.SignedVoucher {
sv := &paych.SignedVoucher{ sv := &v0paych.SignedVoucher{
ChannelAddr: ch, ChannelAddr: ch,
Lane: voucherLane, Lane: voucherLane,
Nonce: nonce, Nonce: nonce,
Amount: voucherAmount, Amount: voucherAmount,
Extra: &paych.ModVerifyParams{ Extra: &v0paych.ModVerifyParams{
Actor: tutils.NewActorAddr(t, "act"), Actor: tutils.NewActorAddr(t, "act"),
}, },
} }
@ -1083,13 +1006,13 @@ type mockBestSpendableAPI struct {
mgr *Manager mgr *Manager
} }
func (m *mockBestSpendableAPI) PaychVoucherList(ctx context.Context, ch address.Address) ([]*paych.SignedVoucher, error) { func (m *mockBestSpendableAPI) PaychVoucherList(ctx context.Context, ch address.Address) ([]*v0paych.SignedVoucher, error) {
vi, err := m.mgr.ListVouchers(ctx, ch) vi, err := m.mgr.ListVouchers(ctx, ch)
if err != nil { if err != nil {
return nil, err return nil, err
} }
out := make([]*paych.SignedVoucher, len(vi)) out := make([]*v0paych.SignedVoucher, len(vi))
for k, v := range vi { for k, v := range vi {
out[k] = v.Voucher out[k] = v.Voucher
} }
@ -1097,7 +1020,7 @@ func (m *mockBestSpendableAPI) PaychVoucherList(ctx context.Context, ch address.
return out, nil return out, nil
} }
func (m *mockBestSpendableAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Address, voucher *paych.SignedVoucher, secret []byte, proof []byte) (bool, error) { func (m *mockBestSpendableAPI) PaychVoucherCheckSpendable(ctx context.Context, ch address.Address, voucher *v0paych.SignedVoucher, secret []byte, proof []byte) (bool, error) {
return m.mgr.CheckVoucherSpendable(ctx, ch, voucher, secret, proof) return m.mgr.CheckVoucherSpendable(ctx, ch, voucher, secret, proof)
} }

View File

@ -6,29 +6,22 @@ import (
"testing" "testing"
"time" "time"
"github.com/filecoin-project/specs-actors/actors/builtin/account"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
cborrpc "github.com/filecoin-project/go-cbor-util" cborrpc "github.com/filecoin-project/go-cbor-util"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"
tutils "github.com/filecoin-project/specs-actors/support/testing"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore" ds "github.com/ipfs/go-datastore"
ds_sync "github.com/ipfs/go-datastore/sync" ds_sync "github.com/ipfs/go-datastore/sync"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
tutils "github.com/filecoin-project/specs-actors/support/testing"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
paychmock "github.com/filecoin-project/lotus/chain/actors/builtin/paych/mock"
"github.com/filecoin-project/lotus/chain/types"
) )
func testChannelResponse(t *testing.T, ch address.Address) types.MessageReceipt { func testChannelResponse(t *testing.T, ch address.Address) types.MessageReceipt {
@ -976,25 +969,15 @@ func TestPaychAvailableFunds(t *testing.T) {
require.EqualValues(t, 0, av.VoucherReedeemedAmt.Int64()) require.EqualValues(t, 0, av.VoucherReedeemedAmt.Int64())
// Create channel in state // Create channel in state
arr, err := adt.MakeEmptyArray(mock.store).Root() mock.setAccountAddress(fromAcct, from)
require.NoError(t, err) mock.setAccountAddress(toAcct, to)
mock.setAccountState(fromAcct, account.State{Address: from})
mock.setAccountState(toAcct, account.State{Address: to})
act := &types.Actor{ act := &types.Actor{
Code: builtin.AccountActorCodeID, Code: builtin.AccountActorCodeID,
Head: cid.Cid{}, Head: cid.Cid{},
Nonce: 0, Nonce: 0,
Balance: createAmt, Balance: createAmt,
} }
mock.setPaychState(ch, act, paych.State{ mock.setPaychState(ch, act, paychmock.NewMockPayChState(fromAcct, toAcct, abi.ChainEpoch(0), big.NewInt(0), make(map[uint64]paych.LaneState)))
From: fromAcct,
To: toAcct,
ToSend: big.NewInt(0),
SettlingAt: abi.ChainEpoch(0),
MinSettleHeight: abi.ChainEpoch(0),
LaneStates: arr,
})
// Send create channel response // Send create channel response
response := testChannelResponse(t, ch) response := testChannelResponse(t, ch)
mock.receiveMsgResponse(createMsgCid, response) mock.receiveMsgResponse(createMsgCid, response)

View File

@ -6,20 +6,17 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/filecoin-project/lotus/api"
"golang.org/x/sync/errgroup"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"golang.org/x/sync/errgroup"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/specs-actors/actors/builtin"
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
v0paych "github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
@ -320,7 +317,7 @@ func (ca *channelAccessor) currentAvailableFunds(channelID string, queuedAmt typ
} }
for _, ls := range laneStates { for _, ls := range laneStates {
totalRedeemed = types.BigAdd(totalRedeemed, ls.Redeemed) totalRedeemed = types.BigAdd(totalRedeemed, ls.Redeemed())
} }
} }
@ -385,7 +382,7 @@ func (ca *channelAccessor) processTask(ctx context.Context, amt types.BigInt) *p
// createPaych sends a message to create the channel and returns the message cid // createPaych sends a message to create the channel and returns the message cid
func (ca *channelAccessor) createPaych(ctx context.Context, amt types.BigInt) (cid.Cid, error) { func (ca *channelAccessor) createPaych(ctx context.Context, amt types.BigInt) (cid.Cid, error) {
params, aerr := actors.SerializeParams(&paych.ConstructorParams{From: ca.from, To: ca.to}) params, aerr := actors.SerializeParams(&v0paych.ConstructorParams{From: ca.from, To: ca.to})
if aerr != nil { if aerr != nil {
return cid.Undef, aerr return cid.Undef, aerr
} }

View File

@ -3,13 +3,9 @@ package paychmgr
import ( import (
"context" "context"
"github.com/filecoin-project/specs-actors/actors/util/adt"
"github.com/filecoin-project/specs-actors/actors/builtin/account"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/actors/builtin/paych"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
) )
@ -17,14 +13,8 @@ type stateAccessor struct {
sm stateManagerAPI sm stateManagerAPI
} }
func (ca *stateAccessor) loadPaychActorState(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 return ca.sm.GetPaychState(ctx, ch, nil)
act, err := ca.sm.LoadActorState(ctx, ch, &pcast, nil)
if err != nil {
return nil, nil, err
}
return act, &pcast, nil
} }
func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Address, dir uint64) (*ChannelInfo, error) { func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Address, dir uint64) (*ChannelInfo, error) {
@ -33,17 +23,15 @@ func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Ad
return nil, err return nil, err
} }
var account account.State // Load channel "From" account actor state
_, err = ca.sm.LoadActorState(ctx, st.From, &account, nil) from, err := ca.sm.ResolveToKeyAddress(ctx, st.From(), nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
from := account.Address to, err := ca.sm.ResolveToKeyAddress(ctx, st.To(), nil)
_, err = ca.sm.LoadActorState(ctx, st.To, &account, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
to := account.Address
nextLane, err := ca.nextLaneFromState(ctx, st) nextLane, err := ca.nextLaneFromState(ctx, st)
if err != nil { if err != nil {
@ -67,25 +55,24 @@ func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Ad
return ci, nil return ci, nil
} }
func (ca *stateAccessor) nextLaneFromState(ctx context.Context, st *paych.State) (uint64, error) { func (ca *stateAccessor) nextLaneFromState(ctx context.Context, st paych.State) (uint64, error) {
store := ca.sm.AdtStore(ctx) laneCount, err := st.LaneCount()
laneStates, err := adt.AsArray(store, st.LaneStates)
if err != nil { if err != nil {
return 0, err return 0, err
} }
if laneStates.Length() == 0 { if laneCount == 0 {
return 0, nil return 0, nil
} }
maxID := int64(0) maxID := uint64(0)
if err := laneStates.ForEach(nil, func(i int64) error { if err := st.ForEachLaneState(func(idx uint64, _ paych.LaneState) error {
if i > maxID { if idx > maxID {
maxID = i maxID = idx
} }
return nil return nil
}); err != nil { }); err != nil {
return 0, err return 0, err
} }
return uint64(maxID + 1), nil return maxID + 1, nil
} }