test: improve chain event tests

This commit is contained in:
Steven Allen 2021-08-09 22:15:38 -07:00
parent 3846170302
commit 82ac0a24a0
3 changed files with 269 additions and 183 deletions

View File

@ -393,7 +393,7 @@ type StateMatchFunc func(oldTs, newTs *types.TipSet) (bool, StateChange, error)
// * `StateChangeHandler` is called when the specified state change was observed
// on-chain, and a confidence threshold was reached, or the specified `timeout`
// height was reached with no state change observed. When this callback is
// invoked on a timeout, `oldState` and `newState` are set to nil.
// invoked on a timeout, `oldTs` and `states are set to nil.
// This callback returns a boolean specifying whether further notifications
// should be sent, like `more` return param from `CheckFunc` above.
//

View File

@ -43,10 +43,10 @@ type fakeCS struct {
tipsets map[types.TipSetKey]*types.TipSet
sub func(rev, app []*types.TipSet)
callNumberLk sync.Mutex
callNumber map[string]int
mu sync.Mutex
waitSub chan struct{}
subCh chan<- []*api.HeadChange
callNumber map[string]int
}
func newFakeCS(t *testing.T) *fakeCS {
@ -58,55 +58,82 @@ func newFakeCS(t *testing.T) *fakeCS {
tipsets: make(map[types.TipSetKey]*types.TipSet),
tsc: newTSCache(nil, 2*build.ForkLengthThreshold),
callNumber: map[string]int{},
waitSub: make(chan struct{}),
}
require.NoError(t, fcs.tsc.add(fcs.makeTs(t, nil, 1, dummyCid)))
return fcs
}
func (fcs *fakeCS) ChainHead(ctx context.Context) (*types.TipSet, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.mu.Lock()
defer fcs.mu.Unlock()
fcs.callNumber["ChainHead"] = fcs.callNumber["ChainHead"] + 1
panic("implement me")
}
func (fcs *fakeCS) ChainGetPath(ctx context.Context, from, to types.TipSetKey) ([]*api.HeadChange, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.mu.Lock()
fcs.callNumber["ChainGetPath"] = fcs.callNumber["ChainGetPath"] + 1
panic("Not Implemented")
fcs.mu.Unlock()
fromTs, err := fcs.ChainGetTipSet(ctx, from)
if err != nil {
return nil, err
}
toTs, err := fcs.ChainGetTipSet(ctx, to)
if err != nil {
return nil, err
}
// copied from the chainstore
revert, apply, err := store.ReorgOps(func(tsk types.TipSetKey) (*types.TipSet, error) {
return fcs.ChainGetTipSet(ctx, tsk)
}, fromTs, toTs)
if err != nil {
return nil, err
}
path := make([]*api.HeadChange, len(revert)+len(apply))
for i, r := range revert {
path[i] = &api.HeadChange{Type: store.HCRevert, Val: r}
}
for j, i := 0, len(apply)-1; i >= 0; j, i = j+1, i-1 {
path[j+len(revert)] = &api.HeadChange{Type: store.HCApply, Val: apply[i]}
}
return path, nil
}
func (fcs *fakeCS) ChainGetTipSet(ctx context.Context, key types.TipSetKey) (*types.TipSet, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.mu.Lock()
defer fcs.mu.Unlock()
fcs.callNumber["ChainGetTipSet"] = fcs.callNumber["ChainGetTipSet"] + 1
return fcs.tipsets[key], nil
}
func (fcs *fakeCS) StateSearchMsg(ctx context.Context, from types.TipSetKey, msg cid.Cid, limit abi.ChainEpoch, allowReplaced bool) (*api.MsgLookup, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.mu.Lock()
defer fcs.mu.Unlock()
fcs.callNumber["StateSearchMsg"] = fcs.callNumber["StateSearchMsg"] + 1
return nil, nil
}
func (fcs *fakeCS) StateGetActor(ctx context.Context, actor address.Address, tsk types.TipSetKey) (*types.Actor, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.mu.Lock()
defer fcs.mu.Unlock()
fcs.callNumber["StateGetActor"] = fcs.callNumber["StateGetActor"] + 1
panic("Not Implemented")
}
func (fcs *fakeCS) ChainGetTipSetByHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.mu.Lock()
defer fcs.mu.Unlock()
fcs.callNumber["ChainGetTipSetByHeight"] = fcs.callNumber["ChainGetTipSetByHeight"] + 1
panic("Not Implemented")
}
func (fcs *fakeCS) ChainGetTipSetAfterHeight(context.Context, abi.ChainEpoch, types.TipSetKey) (*types.TipSet, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.mu.Lock()
defer fcs.mu.Unlock()
fcs.callNumber["ChainGetTipSetAfterHeight"] = fcs.callNumber["ChainGetTipSetAfterHeight"] + 1
panic("Not Implemented")
}
@ -158,47 +185,32 @@ func (fcs *fakeCS) makeTs(t *testing.T, parents []cid.Cid, h abi.ChainEpoch, msg
}
func (fcs *fakeCS) ChainNotify(ctx context.Context) (<-chan []*api.HeadChange, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.mu.Lock()
defer fcs.mu.Unlock()
fcs.callNumber["ChainNotify"] = fcs.callNumber["ChainNotify"] + 1
out := make(chan []*api.HeadChange, 1)
if fcs.subCh != nil {
close(out)
fcs.t.Error("already subscribed to notifications")
return out, nil
}
best, err := fcs.tsc.ChainHead(ctx)
if err != nil {
return nil, err
}
out <- []*api.HeadChange{{Type: store.HCCurrent, Val: best}}
fcs.sub = func(rev, app []*types.TipSet) {
notif := make([]*api.HeadChange, len(rev)+len(app))
for i, r := range rev {
notif[i] = &api.HeadChange{
Type: store.HCRevert,
Val: r,
}
}
for i, r := range app {
notif[i+len(rev)] = &api.HeadChange{
Type: store.HCApply,
Val: r,
}
}
select {
case out <- notif:
case <-ctx.Done():
// TODO: fail test?
return
}
}
fcs.subCh = out
close(fcs.waitSub)
return out, nil
}
func (fcs *fakeCS) ChainGetBlockMessages(ctx context.Context, blk cid.Cid) (*api.BlockMessages, error) {
fcs.callNumberLk.Lock()
defer fcs.callNumberLk.Unlock()
fcs.mu.Lock()
defer fcs.mu.Unlock()
fcs.callNumber["ChainGetBlockMessages"] = fcs.callNumber["ChainGetBlockMessages"] + 1
messages, ok := fcs.blkMsgs[blk]
if !ok {
@ -235,11 +247,44 @@ func (fcs *fakeCS) fakeMsgs(m fakeMsg) cid.Cid {
return c
}
func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { // todo: allow msgs
if fcs.sub == nil {
func (fcs *fakeCS) dropSub() {
fcs.mu.Lock()
if fcs.subCh == nil {
fcs.mu.Unlock()
fcs.t.Fatal("sub not be nil")
}
waitCh := make(chan struct{})
fcs.waitSub = waitCh
close(fcs.subCh)
fcs.subCh = nil
fcs.mu.Unlock()
<-waitCh
}
func (fcs *fakeCS) sub(rev, app []*types.TipSet) {
<-fcs.waitSub
notif := make([]*api.HeadChange, len(rev)+len(app))
for i, r := range rev {
notif[i] = &api.HeadChange{
Type: store.HCRevert,
Val: r,
}
}
for i, r := range app {
notif[i+len(rev)] = &api.HeadChange{
Type: store.HCApply,
Val: r,
}
}
fcs.subCh <- notif
}
func (fcs *fakeCS) advance(rev, app, drop int, msgs map[int]cid.Cid, nulls ...int) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@ -255,9 +300,17 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
require.NoError(fcs.t, err)
if _, ok := nullm[int(from.Height())]; !ok {
revs = append(revs, from)
require.NoError(fcs.t, fcs.tsc.revert(from))
if drop == 0 {
revs = append(revs, from)
}
}
if drop > 0 {
drop--
if drop == 0 {
fcs.dropSub()
}
}
fcs.h--
}
@ -272,20 +325,27 @@ func (fcs *fakeCS) advance(rev, app int, msgs map[int]cid.Cid, nulls ...int) { /
mc = dummyCid
}
if _, ok := nullm[int(fcs.h)]; ok {
continue
if _, ok := nullm[int(fcs.h)]; !ok {
best, err := fcs.tsc.ChainHead(ctx)
require.NoError(fcs.t, err)
ts := fcs.makeTs(fcs.t, best.Key().Cids(), fcs.h, mc)
require.NoError(fcs.t, fcs.tsc.add(ts))
if hasMsgs {
fcs.blkMsgs[ts.Blocks()[0].Cid()] = mc
}
if drop == 0 {
apps = append(apps, ts)
}
}
best, err := fcs.tsc.ChainHead(ctx)
require.NoError(fcs.t, err)
ts := fcs.makeTs(fcs.t, best.Key().Cids(), fcs.h, mc)
require.NoError(fcs.t, fcs.tsc.add(ts))
if hasMsgs {
fcs.blkMsgs[ts.Blocks()[0].Cid()] = mc
if drop > 0 {
drop--
if drop == 0 {
fcs.dropSub()
}
}
apps = append(apps, ts)
}
fcs.sub(revs, apps)
@ -316,88 +376,47 @@ func TestAt(t *testing.T) {
}, 3, 5)
require.NoError(t, err)
fcs.advance(0, 3, nil)
fcs.advance(0, 3, 0, nil)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
fcs.advance(0, 3, nil)
fcs.advance(0, 3, 0, nil)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
fcs.advance(0, 3, nil)
fcs.advance(0, 3, 0, nil)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
applied = false
fcs.advance(0, 3, nil)
fcs.advance(0, 3, 0, nil)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
fcs.advance(10, 10, nil)
fcs.advance(10, 10, 0, nil)
require.Equal(t, true, applied)
require.Equal(t, true, reverted)
applied = false
reverted = false
fcs.advance(10, 1, nil)
fcs.advance(10, 1, 0, nil)
require.Equal(t, false, applied)
require.Equal(t, true, reverted)
reverted = false
fcs.advance(0, 1, nil)
fcs.advance(0, 1, 0, nil)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
fcs.advance(0, 2, nil)
fcs.advance(0, 2, 0, nil)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
fcs.advance(0, 1, nil) // 8
fcs.advance(0, 1, 0, nil) // 8
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
}
func TestAtDoubleTrigger(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fcs := newFakeCS(t)
events, err := NewEvents(ctx, fcs)
require.NoError(t, err)
var applied bool
var reverted bool
err = events.ChainAt(ctx, func(_ context.Context, ts *types.TipSet, curH abi.ChainEpoch) error {
require.Equal(t, 5, int(ts.Height()))
require.Equal(t, 8, int(curH))
applied = true
return nil
}, func(_ context.Context, ts *types.TipSet) error {
reverted = true
return nil
}, 3, 5)
require.NoError(t, err)
fcs.advance(0, 6, nil)
require.False(t, applied)
require.False(t, reverted)
fcs.advance(0, 1, nil)
require.True(t, applied)
require.False(t, reverted)
applied = false
fcs.advance(2, 2, nil)
require.False(t, applied)
require.False(t, reverted)
fcs.advance(4, 4, nil)
require.True(t, applied)
require.True(t, reverted)
}
func TestAtNullTrigger(t *testing.T) {
fcs := newFakeCS(t)
events, err := NewEvents(context.Background(), fcs)
@ -417,11 +436,11 @@ func TestAtNullTrigger(t *testing.T) {
}, 3, 5)
require.NoError(t, err)
fcs.advance(0, 6, nil, 5)
fcs.advance(0, 6, 0, nil, 5)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
fcs.advance(0, 3, nil)
fcs.advance(0, 3, 0, nil)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
applied = false
@ -450,16 +469,16 @@ func TestAtNullConf(t *testing.T) {
}, 3, 5)
require.NoError(t, err)
fcs.advance(0, 6, nil)
fcs.advance(0, 6, 0, nil)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
fcs.advance(0, 3, nil, 8)
fcs.advance(0, 3, 0, nil, 8)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
applied = false
fcs.advance(7, 1, nil)
fcs.advance(7, 1, 0, nil)
require.Equal(t, false, applied)
require.Equal(t, true, reverted)
reverted = false
@ -471,7 +490,7 @@ func TestAtStart(t *testing.T) {
events, err := NewEvents(context.Background(), fcs)
require.NoError(t, err)
fcs.advance(0, 5, nil) // 6
fcs.advance(0, 5, 0, nil) // 6
var applied bool
var reverted bool
@ -490,7 +509,7 @@ func TestAtStart(t *testing.T) {
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
fcs.advance(0, 5, nil) // 11
fcs.advance(0, 5, 0, nil) // 11
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
}
@ -501,7 +520,7 @@ func TestAtStartConfidence(t *testing.T) {
events, err := NewEvents(context.Background(), fcs)
require.NoError(t, err)
fcs.advance(0, 10, nil) // 11
fcs.advance(0, 10, 0, nil) // 11
var applied bool
var reverted bool
@ -545,7 +564,7 @@ func TestAtChained(t *testing.T) {
}, 3, 5)
require.NoError(t, err)
fcs.advance(0, 15, nil)
fcs.advance(0, 15, 0, nil)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
@ -557,7 +576,7 @@ func TestAtChainedConfidence(t *testing.T) {
events, err := NewEvents(context.Background(), fcs)
require.NoError(t, err)
fcs.advance(0, 15, nil)
fcs.advance(0, 15, 0, nil)
var applied bool
var reverted bool
@ -587,7 +606,7 @@ func TestAtChainedConfidenceNull(t *testing.T) {
events, err := NewEvents(context.Background(), fcs)
require.NoError(t, err)
fcs.advance(0, 15, nil, 5)
fcs.advance(0, 15, 0, nil, 5)
var applied bool
var reverted bool
@ -644,13 +663,13 @@ func TestCalled(t *testing.T) {
// create few blocks to make sure nothing get's randomly called
fcs.advance(0, 4, nil) // H=5
fcs.advance(0, 4, 0, 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)
fcs.advance(0, 3, 0, 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},
@ -663,14 +682,14 @@ func TestCalled(t *testing.T) {
// create additional block so we are above confidence threshold
fcs.advance(0, 2, nil) // H=10 (confidence=3, apply)
fcs.advance(0, 2, 0, nil) // H=10 (confidence=3, apply)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
applied = false
// dip below confidence
fcs.advance(2, 2, nil) // H=10 (confidence=3, apply)
fcs.advance(2, 2, 0, nil) // H=10 (confidence=3, apply)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
@ -684,13 +703,13 @@ func TestCalled(t *testing.T) {
// revert some blocks, keep the message
fcs.advance(3, 1, nil) // H=8 (confidence=1)
fcs.advance(3, 1, 0, nil) // H=8 (confidence=1)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// revert the message
fcs.advance(2, 1, nil) // H=7, we reverted ts with the msg execution, but not the msg itself
fcs.advance(2, 1, 0, nil) // H=7, we reverted ts with the msg execution, but not the msg itself
require.Equal(t, false, applied)
require.Equal(t, true, reverted)
@ -704,7 +723,7 @@ func TestCalled(t *testing.T) {
},
})
fcs.advance(0, 3, map[int]cid.Cid{ // (n2msg confidence=1)
fcs.advance(0, 3, 0, map[int]cid.Cid{ // (n2msg confidence=1)
0: n2msg,
})
@ -713,7 +732,7 @@ func TestCalled(t *testing.T) {
require.Equal(t, abi.ChainEpoch(10), appliedH)
applied = false
fcs.advance(0, 2, nil) // (confidence=3)
fcs.advance(0, 2, 0, nil) // (confidence=3)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
@ -728,7 +747,7 @@ func TestCalled(t *testing.T) {
// revert and apply at different height
fcs.advance(8, 6, map[int]cid.Cid{ // (confidence=3)
fcs.advance(8, 6, 0, map[int]cid.Cid{ // (confidence=3)
1: n2msg,
})
@ -749,7 +768,7 @@ func TestCalled(t *testing.T) {
// call method again
fcs.advance(0, 5, map[int]cid.Cid{
fcs.advance(0, 5, 0, map[int]cid.Cid{
0: n2msg,
})
@ -758,7 +777,7 @@ func TestCalled(t *testing.T) {
applied = false
// send and revert below confidence, then cross confidence
fcs.advance(0, 2, map[int]cid.Cid{
fcs.advance(0, 2, 0, map[int]cid.Cid{
0: fcs.fakeMsgs(fakeMsg{
bmsgs: []*types.Message{
{To: t0123, From: t0123, Method: 5, Nonce: 3},
@ -766,14 +785,14 @@ func TestCalled(t *testing.T) {
}),
})
fcs.advance(2, 5, nil) // H=19, but message reverted
fcs.advance(2, 5, 0, nil) // H=19, but message reverted
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// test timeout (it's set to 20 in the call to `events.Called` above)
fcs.advance(0, 6, nil)
fcs.advance(0, 6, 0, nil)
require.Equal(t, false, applied) // not calling timeout as we received messages
require.Equal(t, false, reverted)
@ -781,7 +800,7 @@ func TestCalled(t *testing.T) {
// test unregistering with more
more = false
fcs.advance(0, 5, map[int]cid.Cid{
fcs.advance(0, 5, 0, map[int]cid.Cid{
0: fcs.fakeMsgs(fakeMsg{
bmsgs: []*types.Message{
{To: t0123, From: t0123, Method: 5, Nonce: 4}, // this signals we don't want more
@ -793,7 +812,7 @@ func TestCalled(t *testing.T) {
require.Equal(t, false, reverted)
applied = false
fcs.advance(0, 5, map[int]cid.Cid{
fcs.advance(0, 5, 0, map[int]cid.Cid{
0: fcs.fakeMsgs(fakeMsg{
bmsgs: []*types.Message{
{To: t0123, From: t0123, Method: 5, Nonce: 5},
@ -806,12 +825,12 @@ func TestCalled(t *testing.T) {
// revert after disabled
fcs.advance(5, 1, nil) // try reverting msg sent after disabling
fcs.advance(5, 1, 0, nil) // try reverting msg sent after disabling
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
fcs.advance(5, 1, nil) // try reverting msg sent before disabling
fcs.advance(5, 1, 0, nil) // try reverting msg sent before disabling
require.Equal(t, false, applied)
require.Equal(t, true, reverted)
@ -842,10 +861,10 @@ func TestCalledTimeout(t *testing.T) {
}, 3, 20, matchAddrMethod(t0123, 5))
require.NoError(t, err)
fcs.advance(0, 21, nil)
fcs.advance(0, 21, 0, nil)
require.False(t, called)
fcs.advance(0, 5, nil)
fcs.advance(0, 5, 0, nil)
require.True(t, called)
called = false
@ -856,9 +875,7 @@ func TestCalledTimeout(t *testing.T) {
events, err = NewEvents(context.Background(), fcs)
require.NoError(t, err)
// XXX: Needed to set the latest head so "check" succeeds". Is that OK? Or do we expect
// check to work _before_ we've received any events.
fcs.advance(0, 1, nil)
fcs.advance(0, 1, 0, nil)
err = events.Called(context.Background(), func(ctx context.Context, ts *types.TipSet) (d bool, m bool, e error) {
return true, true, nil
@ -874,10 +891,10 @@ func TestCalledTimeout(t *testing.T) {
}, 3, 20, matchAddrMethod(t0123, 5))
require.NoError(t, err)
fcs.advance(0, 21, nil)
fcs.advance(0, 21, 0, nil)
require.False(t, called)
fcs.advance(0, 5, nil)
fcs.advance(0, 5, 0, nil)
require.False(t, called)
}
@ -921,7 +938,7 @@ func TestCalledOrder(t *testing.T) {
}, 3, 20, matchAddrMethod(t0123, 5))
require.NoError(t, err)
fcs.advance(0, 10, map[int]cid.Cid{
fcs.advance(0, 10, 0, map[int]cid.Cid{
1: fcs.fakeMsgs(fakeMsg{
bmsgs: []*types.Message{
{To: t0123, From: t0123, Method: 5, Nonce: 1},
@ -934,7 +951,7 @@ func TestCalledOrder(t *testing.T) {
}),
})
fcs.advance(9, 1, nil)
fcs.advance(9, 1, 0, nil)
}
func TestCalledNull(t *testing.T) {
@ -963,13 +980,13 @@ func TestCalledNull(t *testing.T) {
// create few blocks to make sure nothing get's randomly called
fcs.advance(0, 4, nil) // H=5
fcs.advance(0, 4, 0, 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)
fcs.advance(0, 3, 0, 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},
@ -983,13 +1000,13 @@ func TestCalledNull(t *testing.T) {
// 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)
fcs.advance(0, 3, 0, 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)
fcs.advance(5, 1, 0, nil, 10)
require.Equal(t, false, applied)
require.Equal(t, true, reverted)
@ -1021,13 +1038,13 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
// create few blocks to make sure nothing get's randomly called
fcs.advance(0, 4, nil) // H=5
fcs.advance(0, 4, 0, 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 occurs at H=5, applied at H=6; H=8 (confidence=2)
fcs.advance(0, 3, 0, map[int]cid.Cid{ // msg occurs at H=5, applied at H=6; H=8 (confidence=2)
0: fcs.fakeMsgs(fakeMsg{
bmsgs: []*types.Message{
{To: t0123, From: t0123, Method: 5, Nonce: 1},
@ -1039,19 +1056,19 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
require.Equal(t, false, reverted)
// revert applied TS & message TS
fcs.advance(3, 1, nil) // H=6 (tipset message applied in reverted, AND message reverted)
fcs.advance(3, 1, 0, nil) // H=6 (tipset message applied in reverted, AND message reverted)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create additional blocks so we are above confidence threshold, but message not applied
// as it was reverted
fcs.advance(0, 5, nil) // H=11 (confidence=3, apply)
fcs.advance(0, 5, 0, nil) // H=11 (confidence=3, apply)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create blocks with message again (but below confidence threshold)
fcs.advance(0, 3, map[int]cid.Cid{ // msg occurs at H=12, applied at H=13; H=15 (confidence=2)
fcs.advance(0, 3, 0, map[int]cid.Cid{ // msg occurs at H=12, applied at H=13; H=15 (confidence=2)
0: fcs.fakeMsgs(fakeMsg{
bmsgs: []*types.Message{
{To: t0123, From: t0123, Method: 5, Nonce: 2},
@ -1062,12 +1079,12 @@ func TestRemoveTriggersOnMessage(t *testing.T) {
require.Equal(t, false, reverted)
// revert applied height TS, but don't remove message trigger
fcs.advance(2, 1, nil) // H=13 (tipset message applied in reverted, by tipset with message not reverted)
fcs.advance(2, 1, 0, nil) // H=13 (tipset message applied in reverted, by tipset with message not reverted)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create additional blocks so we are above confidence threshold
fcs.advance(0, 4, nil) // H=18 (confidence=3, apply)
fcs.advance(0, 4, 0, nil) // H=18 (confidence=3, apply)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
@ -1098,6 +1115,9 @@ func TestStateChanged(t *testing.T) {
err = events.StateChanged(func(ctx context.Context, ts *types.TipSet) (d bool, m bool, e error) {
return false, true, nil
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
if data != nil {
require.Equal(t, oldTs.Key(), newTs.Parents())
}
require.Equal(t, false, applied)
applied = true
appliedData = data
@ -1109,6 +1129,7 @@ func TestStateChanged(t *testing.T) {
reverted = true
return nil
}, confidence, timeout, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
require.Equal(t, oldTs.Key(), newTs.Parents())
if matchData == nil {
return false, matchData, nil
}
@ -1121,27 +1142,27 @@ func TestStateChanged(t *testing.T) {
// create few blocks to make sure nothing get's randomly called
fcs.advance(0, 4, nil) // H=5
fcs.advance(0, 4, 0, nil) // H=5
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create state change (but below confidence threshold)
matchData = testStateChange{from: "a", to: "b"}
fcs.advance(0, 3, nil)
fcs.advance(0, 3, 0, nil)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// create additional block so we are above confidence threshold
fcs.advance(0, 2, nil) // H=10 (confidence=3, apply)
fcs.advance(0, 2, 0, nil) // H=10 (confidence=3, apply)
require.Equal(t, true, applied)
require.Equal(t, false, reverted)
applied = false
// dip below confidence (should not apply again)
fcs.advance(2, 2, nil) // H=10 (confidence=3, apply)
fcs.advance(2, 2, 0, nil) // H=10 (confidence=3, apply)
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
@ -1175,6 +1196,9 @@ func TestStateChangedRevert(t *testing.T) {
err = events.StateChanged(func(ctx context.Context, ts *types.TipSet) (d bool, m bool, e error) {
return false, true, nil
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
if data != nil {
require.Equal(t, oldTs.Key(), newTs.Parents())
}
require.Equal(t, false, applied)
applied = true
return more, nil
@ -1182,6 +1206,8 @@ func TestStateChangedRevert(t *testing.T) {
reverted = true
return nil
}, confidence, timeout, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
require.Equal(t, oldTs.Key(), newTs.Parents())
if matchData == nil {
return false, matchData, nil
}
@ -1192,18 +1218,18 @@ func TestStateChangedRevert(t *testing.T) {
})
require.NoError(t, err)
fcs.advance(0, 2, nil) // H=3
fcs.advance(0, 2, 0, nil) // H=3
// Make a state change from TS at height 3 to TS at height 4
matchData = testStateChange{from: "a", to: "b"}
fcs.advance(0, 1, nil) // H=4
fcs.advance(0, 1, 0, nil) // H=4
// Haven't yet reached confidence
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// Advance to reach confidence level
fcs.advance(0, 1, nil) // H=5
fcs.advance(0, 1, 0, nil) // H=5
// Should now have called the handler
require.Equal(t, true, applied)
@ -1211,19 +1237,19 @@ func TestStateChangedRevert(t *testing.T) {
applied = false
// Advance 3 more TS
fcs.advance(0, 3, nil) // H=8
fcs.advance(0, 3, 0, nil) // H=8
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// Regress but not so far as to cause a revert
fcs.advance(3, 1, nil) // H=6
fcs.advance(3, 1, 0, nil) // H=6
require.Equal(t, false, applied)
require.Equal(t, false, reverted)
// Regress back to state where change happened
fcs.advance(3, 1, nil) // H=4
fcs.advance(3, 1, 0, nil) // H=4
// Expect revert to have happened
require.Equal(t, false, applied)
@ -1241,6 +1267,9 @@ func TestStateChangedTimeout(t *testing.T) {
err = events.StateChanged(func(ctx context.Context, ts *types.TipSet) (d bool, m bool, e error) {
return false, true, nil
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
if data != nil {
require.Equal(t, oldTs.Key(), newTs.Parents())
}
called = true
require.Nil(t, data)
require.Equal(t, abi.ChainEpoch(20), newTs.Height())
@ -1250,15 +1279,16 @@ func TestStateChangedTimeout(t *testing.T) {
t.Fatal("revert on timeout")
return nil
}, 3, 20, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
require.Equal(t, oldTs.Key(), newTs.Parents())
return false, nil, nil
})
require.NoError(t, err)
fcs.advance(0, 21, nil)
fcs.advance(0, 21, 0, nil)
require.False(t, called)
fcs.advance(0, 5, nil)
fcs.advance(0, 5, 0, nil)
require.True(t, called)
called = false
@ -1268,13 +1298,14 @@ func TestStateChangedTimeout(t *testing.T) {
events, err = NewEvents(context.Background(), fcs)
require.NoError(t, err)
// XXX: Needed to set the latest head so "check" succeeds". Is that OK? Or do we expect
// check to work _before_ we've received any events.
fcs.advance(0, 1, nil)
fcs.advance(0, 1, 0, nil)
err = events.StateChanged(func(ctx context.Context, ts *types.TipSet) (d bool, m bool, e error) {
return true, true, nil
}, func(oldTs, newTs *types.TipSet, data StateChange, curH abi.ChainEpoch) (bool, error) {
if data != nil {
require.Equal(t, oldTs.Key(), newTs.Parents())
}
called = true
require.Nil(t, data)
require.Equal(t, abi.ChainEpoch(20), newTs.Height())
@ -1284,14 +1315,15 @@ func TestStateChangedTimeout(t *testing.T) {
t.Fatal("revert on timeout")
return nil
}, 3, 20, func(oldTs, newTs *types.TipSet) (bool, StateChange, error) {
require.Equal(t, oldTs.Key(), newTs.Parents())
return false, nil, nil
})
require.NoError(t, err)
fcs.advance(0, 21, nil)
fcs.advance(0, 21, 0, nil)
require.False(t, called)
fcs.advance(0, 5, nil)
fcs.advance(0, 5, 0, nil)
require.False(t, called)
}
@ -1335,7 +1367,7 @@ func TestCalledMultiplePerEpoch(t *testing.T) {
}, 3, 20, matchAddrMethod(t0123, 5))
require.NoError(t, err)
fcs.advance(0, 10, map[int]cid.Cid{
fcs.advance(0, 10, 0, map[int]cid.Cid{
1: fcs.fakeMsgs(fakeMsg{
bmsgs: []*types.Message{
{To: t0123, From: t0123, Method: 5, Nonce: 1},
@ -1344,7 +1376,7 @@ func TestCalledMultiplePerEpoch(t *testing.T) {
}),
})
fcs.advance(9, 1, nil)
fcs.advance(9, 1, 0, nil)
}
func TestCachedSameBlock(t *testing.T) {
@ -1353,9 +1385,63 @@ func TestCachedSameBlock(t *testing.T) {
_, err := NewEvents(context.Background(), fcs)
require.NoError(t, err)
fcs.advance(0, 10, map[int]cid.Cid{})
fcs.advance(0, 10, 0, map[int]cid.Cid{})
assert.Assert(t, fcs.callNumber["ChainGetBlockMessages"] == 20, "expect call ChainGetBlockMessages %d but got ", 20, fcs.callNumber["ChainGetBlockMessages"])
fcs.advance(5, 10, map[int]cid.Cid{})
fcs.advance(5, 10, 0, map[int]cid.Cid{})
assert.Assert(t, fcs.callNumber["ChainGetBlockMessages"] == 30, "expect call ChainGetBlockMessages %d but got ", 30, fcs.callNumber["ChainGetBlockMessages"])
}
type testObserver struct {
t *testing.T
head *types.TipSet
}
func (t *testObserver) Apply(_ context.Context, from, to *types.TipSet) error {
if t.head != nil {
require.True(t.t, t.head.Equals(from))
}
t.head = to
return nil
}
func (t *testObserver) Revert(_ context.Context, from, to *types.TipSet) error {
if t.head != nil {
require.True(t.t, t.head.Equals(from))
}
t.head = to
return nil
}
func TestReconnect(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fcs := newFakeCS(t)
events, err := NewEvents(ctx, fcs)
require.NoError(t, err)
fcs.advance(0, 1, 0, nil)
events.Observe(&testObserver{t: t})
fcs.advance(0, 3, 0, nil)
// Drop on apply
fcs.advance(0, 6, 2, nil)
require.True(t, fcs.callNumber["ChainGetPath"] == 1)
// drop across revert/apply boundary
fcs.advance(4, 2, 3, nil)
require.True(t, fcs.callNumber["ChainGetPath"] == 2)
fcs.advance(0, 6, 0, nil)
// drop on revert
fcs.advance(3, 0, 2, nil)
require.True(t, fcs.callNumber["ChainGetPath"] == 3)
// drop with nulls
fcs.advance(0, 5, 2, nil, 0, 1, 3)
require.True(t, fcs.callNumber["ChainGetPath"] == 4)
}

View File

@ -111,7 +111,7 @@ func (o *observer) listenHeadChangesOnce(ctx context.Context) error {
}
if err := o.applyChanges(ctx, changes); err != nil {
return xerrors.Errorf("failed to apply head changes: %w", err)
return xerrors.Errorf("failed catch-up head changes: %w", err)
}
}