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 {
cbor.Marshaler
BalancesChanged(State) bool
BalancesChanged(State) (bool, error)
EscrowTable() (BalanceTable, error)
LockedTable() (BalanceTable, error)
TotalLocked() (abi.TokenAmount, error)
StatesChanged(State) bool
StatesChanged(State) (bool, error)
States() (DealStates, error)
ProposalsChanged(State) bool
ProposalsChanged(State) (bool, error)
Proposals() (DealProposals, error)
VerifyDealsForActivation(
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
}
func (s *state0) BalancesChanged(otherState State) bool {
func (s *state0) BalancesChanged(otherState State) (bool, error) {
otherState0, ok := otherState.(*state0)
if !ok {
// there's no way to compare different versions of the state, so let's
// 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)
if !ok {
// there's no way to compare different versions of the state, so let's
// 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) {
@ -53,14 +53,14 @@ func (s *state0) States() (DealStates, error) {
return &dealStates0{stateArray}, nil
}
func (s *state0) ProposalsChanged(otherState State) bool {
func (s *state0) ProposalsChanged(otherState State) (bool, error) {
otherState0, ok := otherState.(*state0)
if !ok {
// there's no way to compare different versions of the state, so let's
// 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) {

View File

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

View File

@ -244,14 +244,14 @@ func (s *state0) NumDeadlines() (uint64, error) {
return miner0.WPoStPeriodDeadlines, nil
}
func (s *state0) DeadlinesChanged(other State) bool {
func (s *state0) DeadlinesChanged(other State) (bool, error) {
other0, ok := other.(*state0)
if !ok {
// 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) {
@ -288,8 +288,8 @@ func (s *state0) Info() (MinerInfo, error) {
return mi, nil
}
func (s *state0) DeadlineInfo(epoch abi.ChainEpoch) *dline.Info {
return s.State.DeadlineInfo(epoch)
func (s *state0) DeadlineInfo(epoch abi.ChainEpoch) (*dline.Info, error) {
return s.State.DeadlineInfo(epoch), nil
}
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)
if !ok {
// 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) {

View File

@ -31,11 +31,11 @@ type State interface {
cbor.Marshaler
LockedBalance(epoch abi.ChainEpoch) (abi.TokenAmount, error)
StartEpoch() abi.ChainEpoch
UnlockDuration() abi.ChainEpoch
InitialBalance() abi.TokenAmount
Threshold() uint64
Signers() []address.Address
StartEpoch() (abi.ChainEpoch, error)
UnlockDuration() (abi.ChainEpoch, error)
InitialBalance() (abi.TokenAmount, error)
Threshold() (uint64, error)
Signers() ([]address.Address, 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
}
func (s *state0) StartEpoch() abi.ChainEpoch {
return s.State.StartEpoch
func (s *state0) StartEpoch() (abi.ChainEpoch, error) {
return s.State.StartEpoch, nil
}
func (s *state0) UnlockDuration() abi.ChainEpoch {
return s.State.UnlockDuration
func (s *state0) UnlockDuration() (abi.ChainEpoch, error) {
return s.State.UnlockDuration, nil
}
func (s *state0) InitialBalance() abi.TokenAmount {
return s.State.InitialBalance
func (s *state0) InitialBalance() (abi.TokenAmount, error) {
return s.State.InitialBalance, nil
}
func (s *state0) Threshold() uint64 {
return s.State.NumApprovalsThreshold
func (s *state0) Threshold() (uint64, error) {
return s.State.NumApprovalsThreshold, nil
}
func (s *state0) Signers() []address.Address {
return s.State.Signers
func (s *state0) Signers() ([]address.Address, error) {
return s.State.Signers, nil
}
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
func (ms *mockState) From() address.Address {
return ms.from
func (ms *mockState) From() (address.Address, error) {
return ms.from, nil
}
// Recipient of payouts from channel
func (ms *mockState) To() address.Address {
return ms.to
func (ms *mockState) To() (address.Address, error) {
return ms.to, nil
}
// Height at which the channel can be `Collected`
func (ms *mockState) SettlingAt() abi.ChainEpoch {
return ms.settlingAt
func (ms *mockState) SettlingAt() (abi.ChainEpoch, error) {
return ms.settlingAt, nil
}
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
func (ms *mockState) ToSend() abi.TokenAmount {
return ms.toSend
func (ms *mockState) ToSend() (abi.TokenAmount, error) {
return ms.toSend, nil
}
// Get total number of lanes
@ -80,10 +80,10 @@ func (ms *mockState) ForEachLaneState(cb func(idx uint64, dl paych.LaneState) er
return lastErr
}
func (mls *mockLaneState) Redeemed() big.Int {
return mls.redeemed
func (mls *mockLaneState) Redeemed() (big.Int, error) {
return mls.redeemed, nil
}
func (mls *mockLaneState) Nonce() uint64 {
return mls.nonce
func (mls *mockLaneState) Nonce() (uint64, error) {
return mls.nonce, nil
}

View File

@ -33,15 +33,15 @@ func Load(store adt.Store, act *types.Actor) (State, error) {
type State interface {
cbor.Marshaler
// Channel owner, who has funded the actor
From() address.Address
From() (address.Address, error)
// Recipient of payouts from channel
To() address.Address
To() (address.Address, error)
// 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()`
ToSend() abi.TokenAmount
ToSend() (abi.TokenAmount, error)
// Get total number of lanes
LaneCount() (uint64, error)
@ -52,8 +52,8 @@ type State interface {
// LaneState is an abstract copy of the state of a single lane
type LaneState interface {
Redeemed() big.Int
Nonce() uint64
Redeemed() (big.Int, error)
Nonce() (uint64, error)
}
type SignedVoucher = paych0.SignedVoucher

View File

@ -18,23 +18,23 @@ type state0 struct {
}
// Channel owner, who has funded the actor
func (s *state0) From() address.Address {
return s.State.From
func (s *state0) From() (address.Address, error) {
return s.State.From, nil
}
// Recipient of payouts from channel
func (s *state0) To() address.Address {
return s.State.To
func (s *state0) To() (address.Address, error) {
return s.State.To, nil
}
// Height at which the channel can be `Collected`
func (s *state0) SettlingAt() abi.ChainEpoch {
return s.State.SettlingAt
func (s *state0) SettlingAt() (abi.ChainEpoch, error) {
return s.State.SettlingAt, nil
}
// Amount successfully redeemed through the payment channel, paid out on `Collect()`
func (s *state0) ToSend() abi.TokenAmount {
return s.State.ToSend
func (s *state0) ToSend() (abi.TokenAmount, error) {
return s.State.ToSend, nil
}
func (s *state0) getOrLoadLsAmt() (*adt0.Array, error) {
@ -82,10 +82,10 @@ type laneState0 struct {
paych.LaneState
}
func (ls *laneState0) Redeemed() big.Int {
return ls.LaneState.Redeemed
func (ls *laneState0) Redeemed() (big.Int, error) {
return ls.LaneState.Redeemed, nil
}
func (ls *laneState0) Nonce() uint64 {
return ls.LaneState.Nonce
func (ls *laneState0) Nonce() (uint64, error) {
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
func (sp *StatePredicates) OnBalanceChanged(diffBalances DiffBalanceTablesFunc) DiffStorageMarketStateFunc {
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
}
@ -132,7 +137,12 @@ type DiffAdtArraysFunc func(ctx context.Context, oldDealStateRoot, newDealStateR
// OnDealStateChanged calls diffDealStates when the market deal state changes
func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc) DiffStorageMarketStateFunc {
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
}
@ -152,7 +162,12 @@ func (sp *StatePredicates) OnDealStateChanged(diffDealStates DiffDealStatesFunc)
// OnDealProposalChanged calls diffDealProps when the market proposal state changes
func (sp *StatePredicates) OnDealProposalChanged(diffDealProps DiffDealProposalsFunc) DiffStorageMarketStateFunc {
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
}
@ -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
func (sp *StatePredicates) OnToSendAmountChanges() DiffPaymentChannelStateFunc {
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 true, &PayChToSendChange{
OldToSend: oldState.ToSend(),
NewToSend: newState.ToSend(),
OldToSend: ots,
NewToSend: nts,
}, nil
}
}

View File

@ -843,15 +843,30 @@ func (sm *StateManager) setupGenesisActors(ctx context.Context) error {
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!")
}
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 {
totalsByEpoch[s.UnlockDuration()] = big.Add(ot, s.InitialBalance())
totalsByEpoch[ud] = big.Add(ot, ib)
} else {
totalsByEpoch[s.UnlockDuration()] = s.InitialBalance()
totalsByEpoch[ud] = ib
}
} 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)))
if cctx.Bool("vesting") {
fmt.Printf("InitialBalance: %s\n", types.FIL(mstate.InitialBalance()))
fmt.Printf("StartEpoch: %d\n", mstate.StartEpoch())
fmt.Printf("UnlockDuration: %d\n", mstate.UnlockDuration())
ib, err := mstate.InitialBalance()
if err != nil {
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()
fmt.Printf("Threshold: %d / %d\n", mstate.Threshold(), len(signers))
signers, err := mstate.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:")
for _, s := range signers {
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
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>
cmd = []string{chAddr.String()}

View File

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

View File

@ -108,10 +108,19 @@ var genesisVerifyCmd = &cli.Command{
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{
Balance: types.FIL(act.Balance),
Signers: st.Signers(),
Threshold: st.Threshold(),
Signers: signers,
Threshold: threshold,
}
msigAddrs = append(msigAddrs, addr)
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 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) {

View File

@ -48,12 +48,12 @@ type laneState struct {
nonce uint64
}
func (ls laneState) Redeemed() big.Int {
return ls.redeemed
func (ls laneState) Redeemed() (big.Int, error) {
return ls.redeemed, nil
}
func (ls laneState) Nonce() uint64 {
return ls.nonce
func (ls laneState) Nonce() (uint64, error) {
return ls.nonce, nil
}
// 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
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 {
return nil, err
}
@ -208,13 +213,24 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
// If the new voucher nonce value is less than the highest known
// nonce for the lane
ls, lsExists := laneStates[sv.Lane]
if lsExists && sv.Nonce <= ls.Nonce() {
return nil, fmt.Errorf("nonce too low")
}
if lsExists {
n, err := ls.Nonce()
if err != nil {
return nil, err
}
// If the voucher amount is less than the highest known voucher amount
if lsExists && sv.Amount.LessThanEqual(ls.Redeemed()) {
return nil, fmt.Errorf("voucher amount is lower than amount for voucher with lower nonce")
if sv.Nonce <= n {
return nil, fmt.Errorf("nonce too low")
}
// If the voucher amount is less than the highest known voucher amount
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")
}
}
// Total redeemed is the total redeemed amount for all lanes, including
@ -239,7 +255,12 @@ func (ca *channelAccessor) checkVoucherValidUnlocked(ctx context.Context, ch add
// Total required balance = total redeemed + toSend
// 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) {
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 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) {
@ -376,7 +397,10 @@ func (ca *channelAccessor) addVoucherUnlocked(ctx context.Context, ch address.Ad
laneState, exists := laneStates[sv.Lane]
redeemed := big.NewInt(0)
if exists {
redeemed = laneState.Redeemed()
redeemed, err = laneState.Redeemed()
if err != nil {
return types.NewInt(0), err
}
}
delta := types.BigSub(sv.Amount, redeemed)
@ -531,9 +555,14 @@ 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
// create it
ls, ok := laneStates[v.Voucher.Lane]
if ok && v.Voucher.Nonce < ls.Nonce() {
continue
if ok {
n, err := ls.Nonce()
if err != nil {
return nil, err
}
if v.Voucher.Nonce < n {
continue
}
}
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)
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]
if ok {
// If the voucher is for an existing lane, and the voucher 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
// 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)
}
} else {

View File

@ -317,7 +317,11 @@ func (ca *channelAccessor) currentAvailableFunds(channelID string, queuedAmt typ
}
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
from, err := ca.sm.ResolveToKeyAddress(ctx, st.From(), nil)
f, err := st.From()
if err != nil {
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 {
return nil, err
}