Add an error return to all actor state interface methods

This commit is contained in:
Aayush Rajasekaran 2020-09-23 01:19:43 -04:00
parent e27fc03f55
commit 476e7992e8
19 changed files with 245 additions and 111 deletions

View File

@ -31,13 +31,13 @@ func Load(store adt.Store, act *types.Actor) (st State, err error) {
type State interface { type State interface {
cbor.Marshaler cbor.Marshaler
BalancesChanged(State) bool BalancesChanged(State) (bool, error)
EscrowTable() (BalanceTable, error) EscrowTable() (BalanceTable, error)
LockedTable() (BalanceTable, error) LockedTable() (BalanceTable, error)
TotalLocked() (abi.TokenAmount, error) TotalLocked() (abi.TokenAmount, error)
StatesChanged(State) bool StatesChanged(State) (bool, error)
States() (DealStates, error) States() (DealStates, error)
ProposalsChanged(State) bool ProposalsChanged(State) (bool, error)
Proposals() (DealProposals, error) Proposals() (DealProposals, error)
VerifyDealsForActivation( VerifyDealsForActivation(
minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch, minerAddr address.Address, deals []abi.DealID, currEpoch, sectorExpiry abi.ChainEpoch,

View File

@ -25,24 +25,24 @@ func (s *state0) TotalLocked() (abi.TokenAmount, error) {
return fml, nil return fml, nil
} }
func (s *state0) BalancesChanged(otherState State) bool { func (s *state0) BalancesChanged(otherState State) (bool, error) {
otherState0, ok := otherState.(*state0) otherState0, ok := otherState.(*state0)
if !ok { if !ok {
// there's no way to compare different versions of the state, so let's // there's no way to compare different versions of the state, so let's
// just say that means the state of balances has changed // just say that means the state of balances has changed
return true return true, nil
} }
return !s.State.EscrowTable.Equals(otherState0.State.EscrowTable) || !s.State.LockedTable.Equals(otherState0.State.LockedTable) return !s.State.EscrowTable.Equals(otherState0.State.EscrowTable) || !s.State.LockedTable.Equals(otherState0.State.LockedTable), nil
} }
func (s *state0) StatesChanged(otherState State) bool { func (s *state0) StatesChanged(otherState State) (bool, error) {
otherState0, ok := otherState.(*state0) otherState0, ok := otherState.(*state0)
if !ok { if !ok {
// there's no way to compare different versions of the state, so let's // there's no way to compare different versions of the state, so let's
// just say that means the state of balances has changed // just say that means the state of balances has changed
return true return true, nil
} }
return !s.State.States.Equals(otherState0.State.States) return !s.State.States.Equals(otherState0.State.States), nil
} }
func (s *state0) States() (DealStates, error) { func (s *state0) States() (DealStates, error) {
@ -53,14 +53,14 @@ func (s *state0) States() (DealStates, error) {
return &dealStates0{stateArray}, nil return &dealStates0{stateArray}, nil
} }
func (s *state0) ProposalsChanged(otherState State) bool { func (s *state0) ProposalsChanged(otherState State) (bool, error) {
otherState0, ok := otherState.(*state0) otherState0, ok := otherState.(*state0)
if !ok { if !ok {
// there's no way to compare different versions of the state, so let's // there's no way to compare different versions of the state, so let's
// just say that means the state of balances has changed // just say that means the state of balances has changed
return true return true, nil
} }
return !s.State.Proposals.Equals(otherState0.State.Proposals) return !s.State.Proposals.Equals(otherState0.State.Proposals), nil
} }
func (s *state0) Proposals() (DealProposals, error) { func (s *state0) Proposals() (DealProposals, error) {

View File

@ -58,11 +58,11 @@ type State interface {
LoadDeadline(idx uint64) (Deadline, error) LoadDeadline(idx uint64) (Deadline, error)
ForEachDeadline(cb func(idx uint64, dl Deadline) error) error ForEachDeadline(cb func(idx uint64, dl Deadline) error) error
NumDeadlines() (uint64, error) NumDeadlines() (uint64, error)
DeadlinesChanged(State) bool DeadlinesChanged(State) (bool, error)
Info() (MinerInfo, error) Info() (MinerInfo, error)
DeadlineInfo(epoch abi.ChainEpoch) *dline.Info DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error)
// Diff helpers. Used by Diff* functions internally. // Diff helpers. Used by Diff* functions internally.
sectors() (adt.Array, error) sectors() (adt.Array, error)
@ -76,7 +76,7 @@ type Deadline interface {
ForEachPartition(cb func(idx uint64, part Partition) error) error ForEachPartition(cb func(idx uint64, part Partition) error) error
PostSubmissions() (bitfield.BitField, error) PostSubmissions() (bitfield.BitField, error)
PartitionsChanged(Deadline) bool PartitionsChanged(Deadline) (bool, error)
} }
type Partition interface { type Partition interface {

View File

@ -244,14 +244,14 @@ func (s *state0) NumDeadlines() (uint64, error) {
return miner0.WPoStPeriodDeadlines, nil return miner0.WPoStPeriodDeadlines, nil
} }
func (s *state0) DeadlinesChanged(other State) bool { func (s *state0) DeadlinesChanged(other State) (bool, error) {
other0, ok := other.(*state0) other0, ok := other.(*state0)
if !ok { if !ok {
// treat an upgrade as a change, always // treat an upgrade as a change, always
return true return true, nil
} }
return s.State.Deadlines.Equals(other0.Deadlines) return s.State.Deadlines.Equals(other0.Deadlines), nil
} }
func (s *state0) Info() (MinerInfo, error) { func (s *state0) Info() (MinerInfo, error) {
@ -288,8 +288,8 @@ func (s *state0) Info() (MinerInfo, error) {
return mi, nil return mi, nil
} }
func (s *state0) DeadlineInfo(epoch abi.ChainEpoch) *dline.Info { func (s *state0) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) {
return s.State.DeadlineInfo(epoch) return s.State.DeadlineInfo(epoch), nil
} }
func (s *state0) sectors() (adt.Array, error) { func (s *state0) sectors() (adt.Array, error) {
@ -339,14 +339,14 @@ func (d *deadline0) ForEachPartition(cb func(uint64, Partition) error) error {
}) })
} }
func (d *deadline0) PartitionsChanged(other Deadline) bool { func (d *deadline0) PartitionsChanged(other Deadline) (bool, error) {
other0, ok := other.(*deadline0) other0, ok := other.(*deadline0)
if !ok { if !ok {
// treat an upgrade as a change, always // treat an upgrade as a change, always
return true return true, nil
} }
return d.Deadline.Partitions.Equals(other0.Deadline.Partitions) return d.Deadline.Partitions.Equals(other0.Deadline.Partitions), nil
} }
func (d *deadline0) PostSubmissions() (bitfield.BitField, error) { func (d *deadline0) PostSubmissions() (bitfield.BitField, error) {

View File

@ -31,11 +31,11 @@ type State interface {
cbor.Marshaler cbor.Marshaler
LockedBalance(epoch abi.ChainEpoch) (abi.TokenAmount, error) LockedBalance(epoch abi.ChainEpoch) (abi.TokenAmount, error)
StartEpoch() abi.ChainEpoch StartEpoch() (abi.ChainEpoch, error)
UnlockDuration() abi.ChainEpoch UnlockDuration() (abi.ChainEpoch, error)
InitialBalance() abi.TokenAmount InitialBalance() (abi.TokenAmount, error)
Threshold() uint64 Threshold() (uint64, error)
Signers() []address.Address Signers() ([]address.Address, error)
ForEachPendingTxn(func(id int64, txn Transaction) error) error ForEachPendingTxn(func(id int64, txn Transaction) error) error
} }

View File

@ -23,24 +23,24 @@ func (s *state0) LockedBalance(currEpoch abi.ChainEpoch) (abi.TokenAmount, error
return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil return s.State.AmountLocked(currEpoch - s.State.StartEpoch), nil
} }
func (s *state0) StartEpoch() abi.ChainEpoch { func (s *state0) StartEpoch() (abi.ChainEpoch, error) {
return s.State.StartEpoch return s.State.StartEpoch, nil
} }
func (s *state0) UnlockDuration() abi.ChainEpoch { func (s *state0) UnlockDuration() (abi.ChainEpoch, error) {
return s.State.UnlockDuration return s.State.UnlockDuration, nil
} }
func (s *state0) InitialBalance() abi.TokenAmount { func (s *state0) InitialBalance() (abi.TokenAmount, error) {
return s.State.InitialBalance return s.State.InitialBalance, nil
} }
func (s *state0) Threshold() uint64 { func (s *state0) Threshold() (uint64, error) {
return s.State.NumApprovalsThreshold return s.State.NumApprovalsThreshold, nil
} }
func (s *state0) Signers() []address.Address { func (s *state0) Signers() ([]address.Address, error) {
return s.State.Signers return s.State.Signers, nil
} }
func (s *state0) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error { func (s *state0) ForEachPendingTxn(cb func(id int64, txn Transaction) error) error {

View File

@ -45,23 +45,23 @@ func (ms *mockState) MarshalCBOR(io.Writer) error {
} }
// Channel owner, who has funded the actor // Channel owner, who has funded the actor
func (ms *mockState) From() address.Address { func (ms *mockState) From() (address.Address, error) {
return ms.from return ms.from, nil
} }
// Recipient of payouts from channel // Recipient of payouts from channel
func (ms *mockState) To() address.Address { func (ms *mockState) To() (address.Address, error) {
return ms.to return ms.to, nil
} }
// Height at which the channel can be `Collected` // Height at which the channel can be `Collected`
func (ms *mockState) SettlingAt() abi.ChainEpoch { func (ms *mockState) SettlingAt() (abi.ChainEpoch, error) {
return ms.settlingAt return ms.settlingAt, nil
} }
// Amount successfully redeemed through the payment channel, paid out on `Collect()` // Amount successfully redeemed through the payment channel, paid out on `Collect()`
func (ms *mockState) ToSend() abi.TokenAmount { func (ms *mockState) ToSend() (abi.TokenAmount, error) {
return ms.toSend return ms.toSend, nil
} }
// Get total number of lanes // Get total number of lanes
@ -80,10 +80,10 @@ func (ms *mockState) ForEachLaneState(cb func(idx uint64, dl paych.LaneState) er
return lastErr return lastErr
} }
func (mls *mockLaneState) Redeemed() big.Int { func (mls *mockLaneState) Redeemed() (big.Int, error) {
return mls.redeemed return mls.redeemed, nil
} }
func (mls *mockLaneState) Nonce() uint64 { func (mls *mockLaneState) Nonce() (uint64, error) {
return mls.nonce return mls.nonce, nil
} }

View File

@ -33,15 +33,15 @@ func Load(store adt.Store, act *types.Actor) (State, error) {
type State interface { type State interface {
cbor.Marshaler cbor.Marshaler
// Channel owner, who has funded the actor // Channel owner, who has funded the actor
From() address.Address From() (address.Address, error)
// Recipient of payouts from channel // Recipient of payouts from channel
To() address.Address To() (address.Address, error)
// Height at which the channel can be `Collected` // Height at which the channel can be `Collected`
SettlingAt() abi.ChainEpoch SettlingAt() (abi.ChainEpoch, error)
// Amount successfully redeemed through the payment channel, paid out on `Collect()` // Amount successfully redeemed through the payment channel, paid out on `Collect()`
ToSend() abi.TokenAmount ToSend() (abi.TokenAmount, error)
// Get total number of lanes // Get total number of lanes
LaneCount() (uint64, error) LaneCount() (uint64, error)
@ -52,8 +52,8 @@ type State interface {
// LaneState is an abstract copy of the state of a single lane // LaneState is an abstract copy of the state of a single lane
type LaneState interface { type LaneState interface {
Redeemed() big.Int Redeemed() (big.Int, error)
Nonce() uint64 Nonce() (uint64, error)
} }
type SignedVoucher = paych0.SignedVoucher type SignedVoucher = paych0.SignedVoucher

View File

@ -18,23 +18,23 @@ type state0 struct {
} }
// Channel owner, who has funded the actor // Channel owner, who has funded the actor
func (s *state0) From() address.Address { func (s *state0) From() (address.Address, error) {
return s.State.From return s.State.From, nil
} }
// Recipient of payouts from channel // Recipient of payouts from channel
func (s *state0) To() address.Address { func (s *state0) To() (address.Address, error) {
return s.State.To return s.State.To, nil
} }
// Height at which the channel can be `Collected` // Height at which the channel can be `Collected`
func (s *state0) SettlingAt() abi.ChainEpoch { func (s *state0) SettlingAt() (abi.ChainEpoch, error) {
return s.State.SettlingAt return s.State.SettlingAt, nil
} }
// Amount successfully redeemed through the payment channel, paid out on `Collect()` // Amount successfully redeemed through the payment channel, paid out on `Collect()`
func (s *state0) ToSend() abi.TokenAmount { func (s *state0) ToSend() (abi.TokenAmount, error) {
return s.State.ToSend return s.State.ToSend, nil
} }
func (s *state0) getOrLoadLsAmt() (*adt0.Array, error) { func (s *state0) getOrLoadLsAmt() (*adt0.Array, error) {
@ -82,10 +82,10 @@ type laneState0 struct {
paych.LaneState paych.LaneState
} }
func (ls *laneState0) Redeemed() big.Int { func (ls *laneState0) Redeemed() (big.Int, error) {
return ls.LaneState.Redeemed return ls.LaneState.Redeemed, nil
} }
func (ls *laneState0) Nonce() uint64 { func (ls *laneState0) Nonce() (uint64, error) {
return ls.LaneState.Nonce return ls.LaneState.Nonce, nil
} }

View File

@ -97,7 +97,12 @@ type DiffBalanceTablesFunc func(ctx context.Context, oldBalanceTable, newBalance
// OnBalanceChanged runs when the escrow table for available balances changes // OnBalanceChanged runs when the escrow table for available balances changes
func (sp *StatePredicates) OnBalanceChanged(diffBalances DiffBalanceTablesFunc) DiffStorageMarketStateFunc { func (sp *StatePredicates) OnBalanceChanged(diffBalances DiffBalanceTablesFunc) DiffStorageMarketStateFunc {
return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) { return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) {
if !oldState.BalancesChanged(newState) { bc, err := oldState.BalancesChanged(newState)
if err != nil {
return false, nil, err
}
if !bc {
return false, nil, nil return false, nil, nil
} }
@ -132,7 +137,12 @@ type DiffAdtArraysFunc func(ctx context.Context, oldDealStateRoot, newDealStateR
// OnDealStateChanged calls diffDealStates when the market deal state changes // OnDealStateChanged calls diffDealStates when the market deal state changes
func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc) DiffStorageMarketStateFunc { func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc) DiffStorageMarketStateFunc {
return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) { return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) {
if !oldState.StatesChanged(newState) { sc, err := oldState.StatesChanged(newState)
if err != nil {
return false, nil, err
}
if !sc {
return false, nil, nil return false, nil, nil
} }
@ -152,7 +162,12 @@ func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc)
// OnDealProposalChanged calls diffDealProps when the market proposal state changes // OnDealProposalChanged calls diffDealProps when the market proposal state changes
func (sp *StatePredicates) OnDealProposalChanged(diffDealProps DiffDealProposalsFunc) DiffStorageMarketStateFunc { func (sp *StatePredicates) OnDealProposalChanged(diffDealProps DiffDealProposalsFunc) DiffStorageMarketStateFunc {
return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) { return func(ctx context.Context, oldState market.State, newState market.State) (changed bool, user UserData, err error) {
if !oldState.ProposalsChanged(newState) { pc, err := oldState.ProposalsChanged(newState)
if err != nil {
return false, nil, err
}
if !pc {
return false, nil, nil return false, nil, nil
} }
@ -379,12 +394,22 @@ 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()) { ots, err := oldState.ToSend()
if err != nil {
return false, nil, err
}
nts, err := newState.ToSend()
if err != nil {
return false, nil, err
}
if ots.Equals(nts) {
return false, nil, nil return false, nil, nil
} }
return true, &PayChToSendChange{ return true, &PayChToSendChange{
OldToSend: oldState.ToSend(), OldToSend: ots,
NewToSend: newState.ToSend(), NewToSend: nts,
}, nil }, nil
} }
} }

View File

@ -843,15 +843,30 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
return err return err
} }
if s.StartEpoch() != 0 { se, err := s.StartEpoch()
if err != nil {
return err
}
if se != 0 {
return xerrors.New("genesis multisig doesn't start vesting at epoch 0!") return xerrors.New("genesis multisig doesn't start vesting at epoch 0!")
} }
ot, f := totalsByEpoch[s.UnlockDuration()] ud, err := s.UnlockDuration()
if err != nil {
return err
}
ib, err := s.InitialBalance()
if err != nil {
return err
}
ot, f := totalsByEpoch[ud]
if f { if f {
totalsByEpoch[s.UnlockDuration()] = big.Add(ot, s.InitialBalance()) totalsByEpoch[ud] = big.Add(ot, ib)
} else { } else {
totalsByEpoch[s.UnlockDuration()] = s.InitialBalance() totalsByEpoch[ud] = ib
} }
} else if act.IsAccountActor() { } else if act.IsAccountActor() {

View File

@ -206,13 +206,32 @@ var msigInspectCmd = &cli.Command{
fmt.Printf("Spendable: %s\n", types.FIL(types.BigSub(act.Balance, locked))) fmt.Printf("Spendable: %s\n", types.FIL(types.BigSub(act.Balance, locked)))
if cctx.Bool("vesting") { if cctx.Bool("vesting") {
fmt.Printf("InitialBalance: %s\n", types.FIL(mstate.InitialBalance())) ib, err := mstate.InitialBalance()
fmt.Printf("StartEpoch: %d\n", mstate.StartEpoch()) if err != nil {
fmt.Printf("UnlockDuration: %d\n", mstate.UnlockDuration()) return err
}
fmt.Printf("InitialBalance: %s\n", types.FIL(ib))
se, err := mstate.StartEpoch()
if err != nil {
return err
}
fmt.Printf("StartEpoch: %d\n", se)
ud, err := mstate.UnlockDuration()
if err != nil {
return err
}
fmt.Printf("UnlockDuration: %d\n", ud)
} }
signers := mstate.Signers() signers, err := mstate.Signers()
fmt.Printf("Threshold: %d / %d\n", mstate.Threshold(), len(signers)) if err != nil {
return err
}
threshold, err := mstate.Threshold()
if err != nil {
return err
}
fmt.Printf("Threshold: %d / %d\n", threshold, len(signers))
fmt.Println("Signers:") fmt.Println("Signers:")
for _, s := range signers { for _, s := range signers {
fmt.Printf("\t%s\n", s) fmt.Printf("\t%s\n", s)

View File

@ -89,7 +89,9 @@ 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()) sa, err := chState.SettlingAt()
require.NoError(t, err)
waitForHeight(ctx, t, paymentReceiver, sa)
// receiver: paych collect <channel> // receiver: paych collect <channel>
cmd = []string{chAddr.String()} cmd = []string{chAddr.String()}

View File

@ -684,7 +684,11 @@ func (p *Processor) diffMinerPartitions(ctx context.Context, m minerActorInfo, e
return err return err
} }
curMiner := m.state curMiner := m.state
if !prevMiner.DeadlinesChanged(curMiner) { dc, err := prevMiner.DeadlinesChanged(curMiner)
if err != nil {
return err
}
if !dc {
return nil return nil
} }
panic("TODO") panic("TODO")

View File

@ -108,10 +108,19 @@ var genesisVerifyCmd = &cli.Command{
return xerrors.Errorf("multisig actor: %w", err) return xerrors.Errorf("multisig actor: %w", err)
} }
signers, err := st.Signers()
if err != nil {
return xerrors.Errorf("multisig actor: %w", err)
}
threshold, err := st.Threshold()
if err != nil {
return xerrors.Errorf("multisig actor: %w", err)
}
kmultisigs[addr] = msigInfo{ kmultisigs[addr] = msigInfo{
Balance: types.FIL(act.Balance), Balance: types.FIL(act.Balance),
Signers: st.Signers(), Signers: signers,
Threshold: st.Threshold(), Threshold: threshold,
} }
msigAddrs = append(msigAddrs, addr) msigAddrs = append(msigAddrs, addr)
case act.IsAccountActor(): case act.IsAccountActor():

View File

@ -212,7 +212,12 @@ func (a *StateAPI) StateMinerProvingDeadline(ctx context.Context, addr address.A
return nil, xerrors.Errorf("failed to load miner actor state: %w", err) return nil, xerrors.Errorf("failed to load miner actor state: %w", err)
} }
return mas.DeadlineInfo(ts.Height()).NextNotElapsed(), nil di, err := mas.DeadlineInfo(ts.Height())
if err != nil {
return nil, xerrors.Errorf("failed to get deadline info: %w", err)
}
return di.NextNotElapsed(), nil
} }
func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) { func (a *StateAPI) StateMinerFaults(ctx context.Context, addr address.Address, tsk types.TipSetKey) (bitfield.BitField, error) {

View File

@ -48,12 +48,12 @@ type laneState struct {
nonce uint64 nonce uint64
} }
func (ls laneState) Redeemed() big.Int { func (ls laneState) Redeemed() (big.Int, error) {
return ls.redeemed return ls.redeemed, nil
} }
func (ls laneState) Nonce() uint64 { func (ls laneState) Nonce() (uint64, error) {
return ls.nonce return ls.nonce, nil
} }
// channelAccessor is used to simplify locking when accessing a channel // channelAccessor is used to simplify locking when accessing a channel
@ -181,7 +181,12 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
} }
// Load channel "From" account actor state // Load channel "From" account actor state
from, err := ca.api.ResolveToKeyAddress(ctx, pchState.From(), nil) f, err := pchState.From()
if err != nil {
return nil, err
}
from, err := ca.api.ResolveToKeyAddress(ctx, f, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -208,14 +213,25 @@ 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 {
n, err := ls.Nonce()
if err != nil {
return nil, err
}
if sv.Nonce <= n {
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()) { r, err := ls.Redeemed()
if err != nil {
return nil, err
}
if sv.Amount.LessThanEqual(r) {
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")
} }
}
// Total redeemed is the total redeemed amount for all lanes, including // Total redeemed is the total redeemed amount for all lanes, including
// the new voucher // the new voucher
@ -239,7 +255,12 @@ 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()) ts, err := pchState.ToSend()
if err != nil {
return nil, err
}
newTotal := types.BigAdd(totalRedeemed, ts)
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))
} }
@ -322,7 +343,7 @@ func (ca *channelAccessor) getPaychRecipient(ctx context.Context, ch address.Add
return address.Address{}, err return address.Address{}, err
} }
return state.To(), nil return state.To()
} }
func (ca *channelAccessor) addVoucher(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) { func (ca *channelAccessor) addVoucher(ctx context.Context, ch address.Address, sv *paych0.SignedVoucher, proof []byte, minDelta types.BigInt) (types.BigInt, error) {
@ -376,7 +397,10 @@ 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, err = laneState.Redeemed()
if err != nil {
return types.NewInt(0), err
}
} }
delta := types.BigSub(sv.Amount, redeemed) delta := types.BigSub(sv.Amount, redeemed)
@ -531,10 +555,15 @@ 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 {
if ok && v.Voucher.Nonce < ls.Nonce() { n, err := ls.Nonce()
if err != nil {
return nil, err
}
if v.Voucher.Nonce < n {
continue continue
} }
}
laneStates[v.Voucher.Lane] = laneState{v.Voucher.Amount, v.Voucher.Nonce} laneStates[v.Voucher.Lane] = laneState{v.Voucher.Amount, v.Voucher.Nonce}
} }
@ -551,17 +580,31 @@ 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()) r, err := ls.Redeemed()
if err != nil {
return big.Int{}, err
}
total = big.Add(total, r)
} }
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() { n, err := lane.Nonce()
if err != nil {
return big.Int{}, err
}
if sv.Nonce > n {
// 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()) r, err := lane.Redeemed()
if err != nil {
return big.Int{}, err
}
delta := big.Sub(sv.Amount, r)
total = big.Add(total, delta) total = big.Add(total, delta)
} }
} else { } else {

View File

@ -317,7 +317,11 @@ func (ca *channelAccessor) currentAvailableFunds(channelID string, queuedAmt typ
} }
for _, ls := range laneStates { for _, ls := range laneStates {
totalRedeemed = types.BigAdd(totalRedeemed, ls.Redeemed()) r, err := ls.Redeemed()
if err != nil {
return nil, err
}
totalRedeemed = types.BigAdd(totalRedeemed, r)
} }
} }

View File

@ -24,11 +24,19 @@ func (ca *stateAccessor) loadStateChannelInfo(ctx context.Context, ch address.Ad
} }
// Load channel "From" account actor state // Load channel "From" account actor state
from, err := ca.sm.ResolveToKeyAddress(ctx, st.From(), nil) f, err := st.From()
if err != nil { if err != nil {
return nil, err return nil, err
} }
to, err := ca.sm.ResolveToKeyAddress(ctx, st.To(), nil) from, err := ca.sm.ResolveToKeyAddress(ctx, f, nil)
if err != nil {
return nil, err
}
t, err := st.To()
if err != nil {
return nil, err
}
to, err := ca.sm.ResolveToKeyAddress(ctx, t, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }