diff --git a/chain/events/events.go b/chain/events/events.go index 9f19b1691..c3934fe4d 100644 --- a/chain/events/events.go +++ b/chain/events/events.go @@ -142,6 +142,8 @@ func (e *Events) listenHeadChangesOnce(ctx context.Context) error { } e.readyOnce.Do(func() { + e.at = cur[0].Val.Height() + e.ready.Done() }) diff --git a/chain/events/events_called.go b/chain/events/events_called.go index e2c81a004..228781f2e 100644 --- a/chain/events/events_called.go +++ b/chain/events/events_called.go @@ -62,6 +62,8 @@ type calledEvents struct { ctx context.Context gcConfidence uint64 + at abi.ChainEpoch + lk sync.Mutex ctr triggerId @@ -83,14 +85,16 @@ type calledEvents struct { func (e *calledEvents) headChangeCalled(rev, app []*types.TipSet) error { for _, ts := range rev { e.handleReverts(ts) + e.at = ts.Height() } for _, ts := range app { // called triggers - e.checkNewCalls(ts) - e.applyWithConfidence(ts) - e.applyTimeouts(ts) + for ; e.at <= ts.Height(); e.at++ { + e.applyWithConfidence(ts, e.at) + e.applyTimeouts(ts) + } } return nil @@ -170,8 +174,8 @@ func (e *calledEvents) queueForConfidence(triggerId uint64, msg *types.Message, e.revertQueue[appliedH] = append(e.revertQueue[appliedH], triggerH) } -func (e *calledEvents) applyWithConfidence(ts *types.TipSet) { - byOrigH, ok := e.confQueue[ts.Height()] +func (e *calledEvents) applyWithConfidence(ts *types.TipSet, height abi.ChainEpoch) { + byOrigH, ok := e.confQueue[height] if !ok { return // no triggers at thin height } @@ -179,7 +183,7 @@ func (e *calledEvents) applyWithConfidence(ts *types.TipSet) { for origH, events := range byOrigH { triggerTs, err := e.tsc.get(origH) if err != nil { - log.Errorf("events: applyWithConfidence didn't find tipset for event; wanted %d; current %d", origH, ts.Height()) + log.Errorf("events: applyWithConfidence didn't find tipset for event; wanted %d; current %d", origH, height) } for _, event := range events { @@ -198,9 +202,9 @@ func (e *calledEvents) applyWithConfidence(ts *types.TipSet) { return } - more, err := trigger.handle(event.msg, rec, triggerTs, ts.Height()) + more, err := trigger.handle(event.msg, rec, triggerTs, height) if err != nil { - log.Errorf("chain trigger (call %s.%d() @H %d, called @ %d) failed: %s", event.msg.To, event.msg.Method, origH, ts.Height(), err) + log.Errorf("chain trigger (call %s.%d() @H %d, called @ %d) failed: %s", event.msg.To, event.msg.Method, origH, height, err) continue // don't revert failed calls } diff --git a/chain/events/events_test.go b/chain/events/events_test.go index bfd734281..10c418d4a 100644 --- a/chain/events/events_test.go +++ b/chain/events/events_test.go @@ -884,3 +884,68 @@ func TestCalledOrder(t *testing.T) { fcs.advance(9, 1, nil) } + +func TestCalledNull(t *testing.T) { + fcs := &fakeCS{ + t: t, + h: 1, + + msgs: map[cid.Cid]fakeMsg{}, + blkMsgs: map[cid.Cid]cid.Cid{}, + tsc: newTSCache(2*build.ForkLengthThreshold, nil), + } + require.NoError(t, fcs.tsc.add(makeTs(t, 1, dummyCid))) + + events := NewEvents(context.Background(), fcs) + + t0123, err := address.NewFromString("t0123") + require.NoError(t, err) + + more := true + var applied, reverted bool + + err = events.Called(func(ts *types.TipSet) (d bool, m bool, e error) { + return false, true, nil + }, func(msg *types.Message, rec *types.MessageReceipt, ts *types.TipSet, curH abi.ChainEpoch) (bool, error) { + require.Equal(t, false, applied) + applied = true + return more, nil + }, func(_ context.Context, ts *types.TipSet) error { + reverted = true + return nil + }, 3, 20, matchAddrMethod(t0123, 5)) + require.NoError(t, err) + + // create few blocks to make sure nothing get's randomly called + + fcs.advance(0, 4, nil) // H=5 + require.Equal(t, false, applied) + require.Equal(t, false, reverted) + + // create blocks with message (but below confidence threshold) + + fcs.advance(0, 3, map[int]cid.Cid{ // msg at H=6; H=8 (confidence=2) + 0: fcs.fakeMsgs(fakeMsg{ + bmsgs: []*types.Message{ + {To: t0123, From: t0123, Method: 5, Nonce: 1}, + }, + }), + }) + + require.Equal(t, false, applied) + require.Equal(t, false, reverted) + + // create additional blocks so we are above confidence threshold, but with null tipset at the height + // of application + + fcs.advance(0, 3, nil, 10) // H=11 (confidence=3, apply) + + require.Equal(t, true, applied) + require.Equal(t, false, reverted) + applied = false + + fcs.advance(5, 1, nil, 10) + + require.Equal(t, false, applied) + require.Equal(t, true, reverted) +}