2022-08-29 14:25:30 +00:00
|
|
|
// stm: #unit
|
2019-11-16 21:36:21 +00:00
|
|
|
package chain
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2022-06-14 15:00:51 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2019-11-16 21:36:21 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types/mock"
|
|
|
|
)
|
|
|
|
|
2020-10-29 17:32:09 +00:00
|
|
|
func init() {
|
|
|
|
BootstrapPeerThreshold = 1
|
|
|
|
}
|
|
|
|
|
2019-11-16 21:36:21 +00:00
|
|
|
var genTs = mock.TipSet(mock.MkBlock(nil, 0, 0))
|
|
|
|
|
|
|
|
type syncOp struct {
|
|
|
|
ts *types.TipSet
|
|
|
|
done func()
|
|
|
|
}
|
|
|
|
|
2020-09-14 20:58:59 +00:00
|
|
|
func runSyncMgrTest(t *testing.T, tname string, thresh int, tf func(*testing.T, *syncManager, chan *syncOp)) {
|
2019-11-16 21:36:21 +00:00
|
|
|
syncTargets := make(chan *syncOp)
|
|
|
|
sm := NewSyncManager(func(ctx context.Context, ts *types.TipSet) error {
|
|
|
|
ch := make(chan struct{})
|
|
|
|
syncTargets <- &syncOp{
|
|
|
|
ts: ts,
|
|
|
|
done: func() { close(ch) },
|
|
|
|
}
|
|
|
|
<-ch
|
|
|
|
return nil
|
2020-09-14 20:58:59 +00:00
|
|
|
}).(*syncManager)
|
2020-10-26 12:11:19 +00:00
|
|
|
|
|
|
|
oldBootstrapPeerThreshold := BootstrapPeerThreshold
|
|
|
|
BootstrapPeerThreshold = thresh
|
|
|
|
defer func() {
|
|
|
|
BootstrapPeerThreshold = oldBootstrapPeerThreshold
|
|
|
|
}()
|
2019-11-16 21:36:21 +00:00
|
|
|
|
|
|
|
sm.Start()
|
|
|
|
defer sm.Stop()
|
|
|
|
t.Run(tname+fmt.Sprintf("-%d", thresh), func(t *testing.T) {
|
|
|
|
tf(t, sm, syncTargets)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertTsEqual(t *testing.T, actual, expected *types.TipSet) {
|
|
|
|
t.Helper()
|
|
|
|
if !actual.Equals(expected) {
|
|
|
|
t.Fatalf("got unexpected tipset %s (expected: %s)", actual.Cids(), expected.Cids())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertNoOp(t *testing.T, c chan *syncOp) {
|
|
|
|
t.Helper()
|
|
|
|
select {
|
|
|
|
case <-time.After(time.Millisecond * 20):
|
|
|
|
case <-c:
|
|
|
|
t.Fatal("shouldnt have gotten any sync operations yet")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertGetSyncOp(t *testing.T, c chan *syncOp, ts *types.TipSet) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-time.After(time.Millisecond * 100):
|
|
|
|
t.Fatal("expected sync manager to try and sync to our target")
|
|
|
|
case op := <-c:
|
|
|
|
op.done()
|
|
|
|
if !op.ts.Equals(ts) {
|
|
|
|
t.Fatalf("somehow got wrong tipset from syncer (got %s, expected %s)", op.ts.Cids(), ts.Cids())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-22 21:33:05 +00:00
|
|
|
func TestSyncManagerEdgeCase(t *testing.T) {
|
feat: Add additional test annotations (#8272)
* Annotate api,proxy_util,blockstore_badger, policy tests
* Annotate splitstore: bsbadger / markset
* Annotate splitstore feature
* Annotate union/timed blockstore tests
* Annotate openrpc, diff_adt tests
* Annotate error,drand,events tests
* Annotate predicates_test
* Fix annotations
* Annotate tscache, gen tests
* Annotate fundmanager test
* Annotate repub and selection tests
* Annotate statetree_test
* Annotate forks_test
* Annotate searchwait_test.go
* Fix duplicated @@ symbols
* Annotate chain stmgr/store tests
* Annotate more (types) tests
* More tests annotated
* Annotate conformance chaos actor tests
* Annotate more integration tests
* Annotate journal system tests
* Annotate more tests.
* Annotate gas,head buffer behaviors
* Fix markset annotations
* doc: test annotations for the markets dagstore wrapper
* Annotate miner_api test in dagstore
* Annotate more test files
* Remove bad annotations from fsrepo
* Annotate wdpost system
* Remove bad annotations
* Renamce "conformance" to "chaos_actor" tests
* doc: stm annotations for blockheader & election proof tests
* Annotate remaining "A" tests
* annotate: stm for error_test
* memrepo_test.go
* Annotate "b" file tests
* message_test.go
* doc: stm annotate for fsrepo_test
* Annotate "c" file tests
* Annotate "D" test files
* message_test.go
* doc: stm annotate for chain, node/config & client
* docs: stm annotate node_test
* Annotate u,v,wl tests
* doc: stm annotations for various test files
* Annotate "T" test files
* doc: stm annotate for proxy_util_test & policy_test
* doc: stm annotate for various tests
* doc: final few stm annotations
* Add mempool unit tests
* Add two more memPool Add tests
* Update submodules
* Add check function tests
* Add stm annotations, refactor test helper
* Annotate api,proxy_util,blockstore_badger, policy tests
* Annotate splitstore: bsbadger / markset
solving merge conflicts
* Annotate splitstore feature
* Annotate union/timed blockstore tests
* Annotate openrpc, diff_adt tests
* Annotate error,drand,events tests
* Annotate predicates_test
* Fix annotations
* Annotate tscache, gen tests
* Annotate fundmanager test
* Annotate statetree_test
* Annotate forks_test
* Annotate searchwait_test.go
* Fix duplicated @@ symbols
* Annotate chain stmgr/store tests
* Annotate more (types) tests
* More tests annotated
* Annotate conformance chaos actor tests
* Annotate more integration tests
* Annotate journal system tests
* Annotate more tests.
* Annotate gas,head buffer behaviors
solve merge conflict
* Fix markset annotations
* Annotate miner_api test in dagstore
* Annotate more test files
* doc: test annotations for the markets dagstore wrapper
* Annotate wdpost system
* Renamce "conformance" to "chaos_actor" tests
* Annotate remaining "A" tests
* doc: stm annotations for blockheader & election proof tests
* annotate: stm for error_test
* Annotate "b" file tests
* memrepo_test.go
* Annotate "c" file tests
* message_test.go
* Annotate "D" test files
* doc: stm annotate for fsrepo_test
* Annotate u,v,wl tests
* message_test.go
* doc: stm annotate for chain, node/config & client
* docs: stm annotate node_test
* Annotate "T" test files
* doc: stm annotations for various test files
* Add mempool unit tests
solve merge conflict
* doc: stm annotate for proxy_util_test & policy_test
* doc: stm annotate for various tests
* doc: final few stm annotations
* Add two more memPool Add tests
* Update submodules
* Add check function tests
solve conflict
* Add stm annotations, refactor test helper
solve merge conflict
* Change CLI test kinds to "unit"
* Fix double merged test
* Fix ccupgrade_test merge
* Fix lint issues
* Add stm annotation to types_Test
* Test vectors submodule
* Add file annotation to burn_test
Co-authored-by: Nikola Divic <divicnikola@gmail.com>
Co-authored-by: TheMenko <themenkoprojects@gmail.com>
2022-03-16 17:37:34 +00:00
|
|
|
//stm: @CHAIN_SYNCER_SET_PEER_HEAD_001
|
2020-10-22 21:33:05 +00:00
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
a := mock.TipSet(mock.MkBlock(genTs, 1, 1))
|
|
|
|
t.Logf("a: %s", a)
|
|
|
|
b1 := mock.TipSet(mock.MkBlock(a, 1, 2))
|
|
|
|
t.Logf("b1: %s", b1)
|
|
|
|
b2 := mock.TipSet(mock.MkBlock(a, 2, 3))
|
|
|
|
t.Logf("b2: %s", b2)
|
|
|
|
c1 := mock.TipSet(mock.MkBlock(b1, 2, 4))
|
|
|
|
t.Logf("c1: %s", c1)
|
|
|
|
c2 := mock.TipSet(mock.MkBlock(b2, 1, 5))
|
|
|
|
t.Logf("c2: %s", c2)
|
2020-10-22 22:33:35 +00:00
|
|
|
d1 := mock.TipSet(mock.MkBlock(c1, 1, 6))
|
|
|
|
t.Logf("d1: %s", d1)
|
|
|
|
e1 := mock.TipSet(mock.MkBlock(d1, 1, 7))
|
|
|
|
t.Logf("e1: %s", e1)
|
2020-10-22 21:33:05 +00:00
|
|
|
|
|
|
|
runSyncMgrTest(t, "edgeCase", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
|
|
|
sm.SetPeerHead(ctx, "peer1", a)
|
|
|
|
|
|
|
|
sm.SetPeerHead(ctx, "peer1", b1)
|
|
|
|
sm.SetPeerHead(ctx, "peer1", b2)
|
|
|
|
|
2020-10-26 13:19:40 +00:00
|
|
|
assertGetSyncOp(t, stc, a)
|
|
|
|
|
|
|
|
// b1 and b2 are in queue after a; the sync manager should pick the heaviest one which is b2
|
|
|
|
bop := <-stc
|
|
|
|
if !bop.ts.Equals(b2) {
|
|
|
|
t.Fatalf("Expected tipset %s to sync, but got %s", b2, bop.ts)
|
2020-10-22 21:33:05 +00:00
|
|
|
}
|
|
|
|
|
2020-10-26 13:19:40 +00:00
|
|
|
sm.SetPeerHead(ctx, "peer2", c2)
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c1)
|
|
|
|
sm.SetPeerHead(ctx, "peer3", b2)
|
|
|
|
sm.SetPeerHead(ctx, "peer1", a)
|
2020-10-22 21:33:05 +00:00
|
|
|
|
2020-10-26 13:19:40 +00:00
|
|
|
bop.done()
|
2020-10-22 21:33:05 +00:00
|
|
|
|
2020-10-26 13:19:40 +00:00
|
|
|
// get the next sync target; it should be c1 as the heaviest tipset but added last (same weight as c2)
|
|
|
|
bop = <-stc
|
2021-01-21 00:08:29 +00:00
|
|
|
if bop.ts.Equals(c2) {
|
|
|
|
// there's a small race and we might get c2 first.
|
|
|
|
// But we should still end on c1.
|
|
|
|
bop.done()
|
|
|
|
bop = <-stc
|
|
|
|
}
|
|
|
|
|
2020-10-26 13:19:40 +00:00
|
|
|
if !bop.ts.Equals(c1) {
|
|
|
|
t.Fatalf("Expected tipset %s to sync, but got %s", c1, bop.ts)
|
|
|
|
}
|
2020-10-22 21:33:05 +00:00
|
|
|
|
2020-10-26 13:19:40 +00:00
|
|
|
sm.SetPeerHead(ctx, "peer4", d1)
|
|
|
|
sm.SetPeerHead(ctx, "peer5", e1)
|
|
|
|
bop.done()
|
|
|
|
|
|
|
|
// get the last sync target; it should be e1
|
|
|
|
var last *types.TipSet
|
|
|
|
for i := 0; i < 10; {
|
|
|
|
select {
|
|
|
|
case bop = <-stc:
|
|
|
|
bop.done()
|
|
|
|
if last == nil || bop.ts.Height() > last.Height() {
|
|
|
|
last = bop.ts
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
i++
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !last.Equals(e1) {
|
|
|
|
t.Fatalf("Expected tipset %s to sync, but got %s", e1, last)
|
|
|
|
}
|
2020-10-22 22:33:35 +00:00
|
|
|
|
2021-01-20 22:43:19 +00:00
|
|
|
sm.mx.Lock()
|
|
|
|
activeSyncs := len(sm.state)
|
|
|
|
sm.mx.Unlock()
|
|
|
|
if activeSyncs != 0 {
|
|
|
|
t.Errorf("active syncs expected empty but got: %d", activeSyncs)
|
2020-10-22 21:33:05 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-11-16 21:36:21 +00:00
|
|
|
func TestSyncManager(t *testing.T) {
|
feat: Add additional test annotations (#8272)
* Annotate api,proxy_util,blockstore_badger, policy tests
* Annotate splitstore: bsbadger / markset
* Annotate splitstore feature
* Annotate union/timed blockstore tests
* Annotate openrpc, diff_adt tests
* Annotate error,drand,events tests
* Annotate predicates_test
* Fix annotations
* Annotate tscache, gen tests
* Annotate fundmanager test
* Annotate repub and selection tests
* Annotate statetree_test
* Annotate forks_test
* Annotate searchwait_test.go
* Fix duplicated @@ symbols
* Annotate chain stmgr/store tests
* Annotate more (types) tests
* More tests annotated
* Annotate conformance chaos actor tests
* Annotate more integration tests
* Annotate journal system tests
* Annotate more tests.
* Annotate gas,head buffer behaviors
* Fix markset annotations
* doc: test annotations for the markets dagstore wrapper
* Annotate miner_api test in dagstore
* Annotate more test files
* Remove bad annotations from fsrepo
* Annotate wdpost system
* Remove bad annotations
* Renamce "conformance" to "chaos_actor" tests
* doc: stm annotations for blockheader & election proof tests
* Annotate remaining "A" tests
* annotate: stm for error_test
* memrepo_test.go
* Annotate "b" file tests
* message_test.go
* doc: stm annotate for fsrepo_test
* Annotate "c" file tests
* Annotate "D" test files
* message_test.go
* doc: stm annotate for chain, node/config & client
* docs: stm annotate node_test
* Annotate u,v,wl tests
* doc: stm annotations for various test files
* Annotate "T" test files
* doc: stm annotate for proxy_util_test & policy_test
* doc: stm annotate for various tests
* doc: final few stm annotations
* Add mempool unit tests
* Add two more memPool Add tests
* Update submodules
* Add check function tests
* Add stm annotations, refactor test helper
* Annotate api,proxy_util,blockstore_badger, policy tests
* Annotate splitstore: bsbadger / markset
solving merge conflicts
* Annotate splitstore feature
* Annotate union/timed blockstore tests
* Annotate openrpc, diff_adt tests
* Annotate error,drand,events tests
* Annotate predicates_test
* Fix annotations
* Annotate tscache, gen tests
* Annotate fundmanager test
* Annotate statetree_test
* Annotate forks_test
* Annotate searchwait_test.go
* Fix duplicated @@ symbols
* Annotate chain stmgr/store tests
* Annotate more (types) tests
* More tests annotated
* Annotate conformance chaos actor tests
* Annotate more integration tests
* Annotate journal system tests
* Annotate more tests.
* Annotate gas,head buffer behaviors
solve merge conflict
* Fix markset annotations
* Annotate miner_api test in dagstore
* Annotate more test files
* doc: test annotations for the markets dagstore wrapper
* Annotate wdpost system
* Renamce "conformance" to "chaos_actor" tests
* Annotate remaining "A" tests
* doc: stm annotations for blockheader & election proof tests
* annotate: stm for error_test
* Annotate "b" file tests
* memrepo_test.go
* Annotate "c" file tests
* message_test.go
* Annotate "D" test files
* doc: stm annotate for fsrepo_test
* Annotate u,v,wl tests
* message_test.go
* doc: stm annotate for chain, node/config & client
* docs: stm annotate node_test
* Annotate "T" test files
* doc: stm annotations for various test files
* Add mempool unit tests
solve merge conflict
* doc: stm annotate for proxy_util_test & policy_test
* doc: stm annotate for various tests
* doc: final few stm annotations
* Add two more memPool Add tests
* Update submodules
* Add check function tests
solve conflict
* Add stm annotations, refactor test helper
solve merge conflict
* Change CLI test kinds to "unit"
* Fix double merged test
* Fix ccupgrade_test merge
* Fix lint issues
* Add stm annotation to types_Test
* Test vectors submodule
* Add file annotation to burn_test
Co-authored-by: Nikola Divic <divicnikola@gmail.com>
Co-authored-by: TheMenko <themenkoprojects@gmail.com>
2022-03-16 17:37:34 +00:00
|
|
|
//stm: @CHAIN_SYNCER_SET_PEER_HEAD_001
|
2019-11-16 21:36:21 +00:00
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
a := mock.TipSet(mock.MkBlock(genTs, 1, 1))
|
|
|
|
b := mock.TipSet(mock.MkBlock(a, 1, 2))
|
|
|
|
c1 := mock.TipSet(mock.MkBlock(b, 1, 3))
|
|
|
|
c2 := mock.TipSet(mock.MkBlock(b, 2, 4))
|
2019-12-11 20:41:24 +00:00
|
|
|
c3 := mock.TipSet(mock.MkBlock(b, 3, 5))
|
2019-11-16 21:36:21 +00:00
|
|
|
d := mock.TipSet(mock.MkBlock(c1, 4, 5))
|
|
|
|
|
2020-09-14 20:58:59 +00:00
|
|
|
runSyncMgrTest(t, "testBootstrap", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
2019-11-16 21:36:21 +00:00
|
|
|
sm.SetPeerHead(ctx, "peer1", c1)
|
|
|
|
assertGetSyncOp(t, stc, c1)
|
|
|
|
})
|
|
|
|
|
2020-09-14 20:58:59 +00:00
|
|
|
runSyncMgrTest(t, "testBootstrap", 2, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
2019-11-16 21:36:21 +00:00
|
|
|
sm.SetPeerHead(ctx, "peer1", c1)
|
|
|
|
assertNoOp(t, stc)
|
|
|
|
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c1)
|
|
|
|
assertGetSyncOp(t, stc, c1)
|
|
|
|
})
|
|
|
|
|
2020-09-14 20:58:59 +00:00
|
|
|
runSyncMgrTest(t, "testSyncAfterBootstrap", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
2019-11-16 21:36:21 +00:00
|
|
|
sm.SetPeerHead(ctx, "peer1", b)
|
|
|
|
assertGetSyncOp(t, stc, b)
|
|
|
|
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c1)
|
|
|
|
assertGetSyncOp(t, stc, c1)
|
|
|
|
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c2)
|
|
|
|
assertGetSyncOp(t, stc, c2)
|
|
|
|
})
|
|
|
|
|
2020-09-14 20:58:59 +00:00
|
|
|
runSyncMgrTest(t, "testCoalescing", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
2019-11-16 21:36:21 +00:00
|
|
|
sm.SetPeerHead(ctx, "peer1", a)
|
|
|
|
assertGetSyncOp(t, stc, a)
|
|
|
|
|
|
|
|
sm.SetPeerHead(ctx, "peer2", b)
|
|
|
|
op := <-stc
|
|
|
|
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c1)
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c2)
|
|
|
|
sm.SetPeerHead(ctx, "peer2", d)
|
|
|
|
|
|
|
|
assertTsEqual(t, op.ts, b)
|
|
|
|
|
|
|
|
// need a better way to 'wait until syncmgr is idle'
|
|
|
|
time.Sleep(time.Millisecond * 20)
|
|
|
|
|
|
|
|
op.done()
|
|
|
|
|
|
|
|
assertGetSyncOp(t, stc, d)
|
|
|
|
})
|
2019-12-11 20:41:24 +00:00
|
|
|
|
2020-09-14 20:58:59 +00:00
|
|
|
runSyncMgrTest(t, "testSyncIncomingTipset", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
2019-12-11 20:41:24 +00:00
|
|
|
sm.SetPeerHead(ctx, "peer1", a)
|
|
|
|
assertGetSyncOp(t, stc, a)
|
|
|
|
|
|
|
|
sm.SetPeerHead(ctx, "peer2", b)
|
|
|
|
op := <-stc
|
|
|
|
op.done()
|
|
|
|
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c1)
|
|
|
|
op1 := <-stc
|
|
|
|
fmt.Println("op1: ", op1.ts.Cids())
|
|
|
|
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c2)
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c3)
|
|
|
|
|
|
|
|
op1.done()
|
|
|
|
|
|
|
|
op2 := <-stc
|
|
|
|
fmt.Println("op2: ", op2.ts.Cids())
|
|
|
|
op2.done()
|
|
|
|
|
|
|
|
op3 := <-stc
|
|
|
|
fmt.Println("op3: ", op3.ts.Cids())
|
|
|
|
op3.done()
|
|
|
|
})
|
2019-11-16 21:36:21 +00:00
|
|
|
}
|
2022-02-10 23:46:59 +00:00
|
|
|
|
|
|
|
func TestSyncManagerBucketSet(t *testing.T) {
|
|
|
|
ts1 := mock.TipSet(mock.MkBlock(nil, 0, 0))
|
|
|
|
ts2 := mock.TipSet(mock.MkBlock(ts1, 1, 0))
|
|
|
|
bucket1 := newSyncTargetBucket(ts1, ts2)
|
|
|
|
bucketSet := syncBucketSet{buckets: []*syncTargetBucket{bucket1}}
|
|
|
|
|
2022-02-11 14:06:06 +00:00
|
|
|
// inserting a tipset (potential sync target) from an existing chain, should add to an existing bucket
|
|
|
|
//stm: @CHAIN_SYNCER_ADD_SYNC_TARGET_001
|
2022-02-10 23:46:59 +00:00
|
|
|
ts3 := mock.TipSet(mock.MkBlock(ts2, 2, 0))
|
|
|
|
bucketSet.Insert(ts3)
|
|
|
|
require.Equal(t, 1, len(bucketSet.buckets))
|
|
|
|
require.Equal(t, 3, len(bucketSet.buckets[0].tips))
|
|
|
|
|
|
|
|
// inserting a tipset from new chain, should create a new bucket
|
|
|
|
ts4fork := mock.TipSet(mock.MkBlock(nil, 1, 1))
|
|
|
|
bucketSet.Insert(ts4fork)
|
|
|
|
require.Equal(t, 2, len(bucketSet.buckets))
|
|
|
|
require.Equal(t, 3, len(bucketSet.buckets[0].tips))
|
|
|
|
require.Equal(t, 1, len(bucketSet.buckets[1].tips))
|
|
|
|
|
2022-02-11 14:06:06 +00:00
|
|
|
// Pop removes the best bucket (best sync target), e.g. bucket1
|
|
|
|
//stm: @CHAIN_SYNCER_SELECT_SYNC_TARGET_001
|
2022-02-10 23:46:59 +00:00
|
|
|
popped := bucketSet.Pop()
|
|
|
|
require.Equal(t, popped, bucket1)
|
|
|
|
require.Equal(t, 1, len(bucketSet.buckets))
|
|
|
|
|
|
|
|
// PopRelated removes the bucket containing the given tipset, leaving the set empty
|
|
|
|
bucketSet.PopRelated(ts4fork)
|
|
|
|
require.Equal(t, 0, len(bucketSet.buckets))
|
|
|
|
}
|