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 }