lotus/chain/events/state/predicates.go

145 lines
5.1 KiB
Go
Raw Normal View History

2020-06-22 21:38:40 +00:00
package state
import (
"context"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-amt-ipld/v2"
2020-06-26 19:36:48 +00:00
"github.com/filecoin-project/lotus/api/apibstore"
2020-06-22 21:38:40 +00:00
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/abi"
"github.com/filecoin-project/specs-actors/actors/builtin"
"github.com/filecoin-project/specs-actors/actors/builtin/market"
2020-06-26 19:36:48 +00:00
"github.com/ipfs/go-cid"
cbor "github.com/ipfs/go-ipld-cbor"
2020-06-22 21:38:40 +00:00
)
2020-06-26 19:36:48 +00:00
// UserData is the data returned from the DiffFunc
2020-06-25 21:43:37 +00:00
type UserData interface{}
2020-06-26 19:36:48 +00:00
// ChainAPI abstracts out calls made by this class to external APIs
type ChainAPI interface {
2020-06-26 15:51:45 +00:00
apibstore.ChainIO
2020-06-25 21:43:37 +00:00
StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error)
}
2020-06-26 19:36:48 +00:00
// StatePredicates has common predicates for responding to state changes
2020-06-22 21:38:40 +00:00
type StatePredicates struct {
2020-06-26 19:36:48 +00:00
api ChainAPI
2020-06-25 21:43:37 +00:00
cst *cbor.BasicIpldStore
2020-06-22 21:38:40 +00:00
}
2020-06-26 19:36:48 +00:00
func NewStatePredicates(api ChainAPI) *StatePredicates {
2020-06-22 21:38:40 +00:00
return &StatePredicates{
2020-06-25 21:43:37 +00:00
api: api,
cst: cbor.NewCborStore(apibstore.NewAPIBlockstore(api)),
2020-06-22 21:38:40 +00:00
}
}
2020-06-26 19:36:48 +00:00
// DiffFunc check if there's a change form oldState to newState, and returns
2020-06-26 18:59:23 +00:00
// - changed: was there a change
// - user: user-defined data representing the state change
// - err
2020-06-25 21:43:37 +00:00
type DiffFunc func(ctx context.Context, oldState, newState *types.TipSet) (changed bool, user UserData, err error)
2020-06-22 21:38:40 +00:00
type DiffStateFunc func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error)
2020-06-26 19:36:48 +00:00
// OnActorStateChanged calls diffStateFunc when the state changes for the given actor
2020-06-22 21:38:40 +00:00
func (sp *StatePredicates) OnActorStateChanged(addr address.Address, diffStateFunc DiffStateFunc) DiffFunc {
return func(ctx context.Context, oldState, newState *types.TipSet) (changed bool, user UserData, err error) {
2020-06-25 21:43:37 +00:00
oldActor, err := sp.api.StateGetActor(ctx, addr, oldState.Key())
2020-06-22 21:38:40 +00:00
if err != nil {
return false, nil, err
}
2020-06-25 21:43:37 +00:00
newActor, err := sp.api.StateGetActor(ctx, addr, newState.Key())
2020-06-26 19:36:48 +00:00
if err != nil {
return false, nil, err
}
2020-06-22 21:38:40 +00:00
if oldActor.Head.Equals(newActor.Head) {
return false, nil, nil
}
return diffStateFunc(ctx, oldActor.Head, newActor.Head)
}
}
type DiffStorageMarketStateFunc func(ctx context.Context, oldState *market.State, newState *market.State) (changed bool, user UserData, err error)
2020-06-26 19:36:48 +00:00
// OnStorageMarketActorChanged calls diffStorageMarketState when the state changes for the market actor
2020-06-26 15:51:45 +00:00
func (sp *StatePredicates) OnStorageMarketActorChanged(diffStorageMarketState DiffStorageMarketStateFunc) DiffFunc {
2020-06-22 21:38:40 +00:00
return sp.OnActorStateChanged(builtin.StorageMarketActorAddr, func(ctx context.Context, oldActorStateHead, newActorStateHead cid.Cid) (changed bool, user UserData, err error) {
var oldState market.State
2020-06-25 21:43:37 +00:00
if err := sp.cst.Get(ctx, oldActorStateHead, &oldState); err != nil {
2020-06-22 21:38:40 +00:00
return false, nil, err
}
var newState market.State
2020-06-25 21:43:37 +00:00
if err := sp.cst.Get(ctx, newActorStateHead, &newState); err != nil {
2020-06-22 21:38:40 +00:00
return false, nil, err
}
return diffStorageMarketState(ctx, &oldState, &newState)
})
}
type DiffDealStatesFunc func(ctx context.Context, oldDealStateRoot *amt.Root, newDealStateRoot *amt.Root) (changed bool, user UserData, err error)
2020-06-26 19:36:48 +00:00
// OnDealStateChanged calls diffDealStates when the market state changes
2020-06-22 21:38:40 +00:00
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.States.Equals(newState.States) {
return false, nil, nil
}
2020-06-25 21:43:37 +00:00
oldRoot, err := amt.LoadAMT(ctx, sp.cst, oldState.States)
2020-06-22 21:38:40 +00:00
if err != nil {
return false, nil, err
}
2020-06-25 21:43:37 +00:00
newRoot, err := amt.LoadAMT(ctx, sp.cst, newState.States)
2020-06-22 21:38:40 +00:00
if err != nil {
return false, nil, err
}
2020-06-25 21:43:37 +00:00
2020-06-22 21:38:40 +00:00
return diffDealStates(ctx, oldRoot, newRoot)
}
}
2020-06-26 19:36:48 +00:00
// ChangedDeals is a set of changes to deal state
2020-06-26 15:51:45 +00:00
type ChangedDeals map[abi.DealID]DealStateChange
2020-06-26 19:36:48 +00:00
// DealStateChange is a change in deal state from -> to
2020-06-26 15:51:45 +00:00
type DealStateChange struct {
From *market.DealState
To *market.DealState
2020-06-26 15:51:45 +00:00
}
2020-06-26 19:36:48 +00:00
// DealStateChangedForIDs detects changes in the deal state AMT for the given deal IDs
2020-06-25 21:43:37 +00:00
func (sp *StatePredicates) DealStateChangedForIDs(dealIds []abi.DealID) DiffDealStatesFunc {
return func(ctx context.Context, oldDealStateRoot *amt.Root, newDealStateRoot *amt.Root) (changed bool, user UserData, err error) {
2020-06-26 15:51:45 +00:00
changedDeals := make(ChangedDeals)
2020-06-26 19:36:48 +00:00
for _, dealID := range dealIds {
var oldDealPtr, newDealPtr *market.DealState
2020-06-25 21:43:37 +00:00
var oldDeal, newDeal market.DealState
// If the deal has been removed, we just set it to nil
2020-06-26 19:36:48 +00:00
err := oldDealStateRoot.Get(ctx, uint64(dealID), &oldDeal)
if err == nil {
oldDealPtr = &oldDeal
} else if _, ok := err.(*amt.ErrNotFound); !ok {
2020-06-25 21:43:37 +00:00
return false, nil, err
}
2020-06-26 19:36:48 +00:00
err = newDealStateRoot.Get(ctx, uint64(dealID), &newDeal)
if err == nil {
newDealPtr = &newDeal
} else if _, ok := err.(*amt.ErrNotFound); !ok {
2020-06-25 21:43:37 +00:00
return false, nil, err
}
if oldDeal != newDeal {
changedDeals[dealID] = DealStateChange{oldDealPtr, newDealPtr}
2020-06-25 21:43:37 +00:00
}
2020-06-22 21:38:40 +00:00
}
2020-06-25 21:43:37 +00:00
if len(changedDeals) > 0 {
2020-06-26 15:51:45 +00:00
return true, changedDeals, nil
2020-06-22 21:38:40 +00:00
}
2020-06-25 21:43:37 +00:00
return false, nil, nil
2020-06-22 21:38:40 +00:00
}
}