lotus/markets/storageadapter/dealstatematcher.go

85 lines
3.0 KiB
Go

package storageadapter
import (
"context"
"sync"
"github.com/filecoin-project/go-state-types/abi"
actorsmarket "github.com/filecoin-project/lotus/chain/actors/builtin/market"
"github.com/filecoin-project/lotus/chain/events"
"github.com/filecoin-project/lotus/chain/events/state"
"github.com/filecoin-project/lotus/chain/types"
)
// dealStateMatcher caches the DealStates for the most recent
// old/new tipset combination
type dealStateMatcher struct {
preds *state.StatePredicates
lk sync.Mutex
oldTsk types.TipSetKey
newTsk types.TipSetKey
oldDealStateRoot actorsmarket.DealStates
newDealStateRoot actorsmarket.DealStates
}
func newDealStateMatcher(preds *state.StatePredicates) *dealStateMatcher {
return &dealStateMatcher{preds: preds}
}
// matcher returns a function that checks if the state of the given dealID
// has changed.
// It caches the DealStates for the most recent old/new tipset combination.
func (mc *dealStateMatcher) matcher(ctx context.Context, dealID abi.DealID) events.StateMatchFunc {
// The function that is called to check if the deal state has changed for
// the target deal ID
dealStateChangedForID := mc.preds.DealStateChangedForIDs([]abi.DealID{dealID})
// The match function is called by the events API to check if there's
// been a state change for the deal with the target deal ID
match := func(oldTs, newTs *types.TipSet) (bool, events.StateChange, error) {
mc.lk.Lock()
defer mc.lk.Unlock()
// Check if we've already fetched the DealStates for the given tipsets
if mc.oldTsk == oldTs.Key() && mc.newTsk == newTs.Key() {
// If we fetch the DealStates and there is no difference between
// them, they are stored as nil. So we can just bail out.
if mc.oldDealStateRoot == nil || mc.newDealStateRoot == nil {
return false, nil, nil
}
// Check if the deal state has changed for the target ID
return dealStateChangedForID(ctx, mc.oldDealStateRoot, mc.newDealStateRoot)
}
// We haven't already fetched the DealStates for the given tipsets, so
// do so now
// Replace dealStateChangedForID with a function that records the
// DealStates so that we can cache them
var oldDealStateRootSaved, newDealStateRootSaved actorsmarket.DealStates
recorder := func(ctx context.Context, oldDealStateRoot, newDealStateRoot actorsmarket.DealStates) (changed bool, user state.UserData, err error) {
// Record DealStates
oldDealStateRootSaved = oldDealStateRoot
newDealStateRootSaved = newDealStateRoot
return dealStateChangedForID(ctx, oldDealStateRoot, newDealStateRoot)
}
// Call the match function
dealDiff := mc.preds.OnStorageMarketActorChanged(
mc.preds.OnDealStateChanged(recorder))
matched, data, err := dealDiff(ctx, oldTs.Key(), newTs.Key())
// Save the recorded DealStates for the tipsets
mc.oldTsk = oldTs.Key()
mc.newTsk = newTs.Key()
mc.oldDealStateRoot = oldDealStateRootSaved
mc.newDealStateRoot = newDealStateRootSaved
return matched, data, err
}
return match
}