prysm-pulse/beacon-chain/sync/backfill/batcher_test.go
terence 5a66807989
Update to V5 (#13622)
* First take at updating everything to v5

* Patch gRPC gateway to use prysm v5

Fix patch

* Update go ssz

---------

Co-authored-by: Preston Van Loon <pvanloon@offchainlabs.com>
2024-02-15 05:46:47 +00:00

209 lines
6.8 KiB
Go

package backfill
import (
"fmt"
"testing"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/testing/require"
)
func TestBatcherBefore(t *testing.T) {
cases := []struct {
name string
b batcher
upTo []primitives.Slot
expect []batch
}{
{
name: "size 10",
b: batcher{min: 0, size: 10},
upTo: []primitives.Slot{33, 30, 10, 6},
expect: []batch{
{begin: 23, end: 33, state: batchInit},
{begin: 20, end: 30, state: batchInit},
{begin: 0, end: 10, state: batchInit},
{begin: 0, end: 6, state: batchInit},
},
},
{
name: "size 4",
b: batcher{min: 0, size: 4},
upTo: []primitives.Slot{33, 6, 4},
expect: []batch{
{begin: 29, end: 33, state: batchInit},
{begin: 2, end: 6, state: batchInit},
{begin: 0, end: 4, state: batchInit},
},
},
{
name: "trigger end",
b: batcher{min: 20, size: 10},
upTo: []primitives.Slot{33, 30, 25, 21, 20, 19},
expect: []batch{
{begin: 23, end: 33, state: batchInit},
{begin: 20, end: 30, state: batchInit},
{begin: 20, end: 25, state: batchInit},
{begin: 20, end: 21, state: batchInit},
{begin: 20, end: 20, state: batchEndSequence},
{begin: 19, end: 19, state: batchEndSequence},
},
},
}
for _, c := range cases {
for i := range c.upTo {
upTo := c.upTo[i]
expect := c.expect[i]
t.Run(fmt.Sprintf("%s upTo %d", c.name, upTo), func(t *testing.T) {
got := c.b.before(upTo)
require.Equal(t, expect.begin, got.begin)
require.Equal(t, expect.end, got.end)
require.Equal(t, expect.state, got.state)
})
}
}
}
func TestBatchSequencer(t *testing.T) {
var min, max, size primitives.Slot
seqLen := 8
min = 0
max = 11235
size = 64
seq := newBatchSequencer(seqLen, min, max, size)
expected := []batch{
{begin: 11171, end: 11235},
{begin: 11107, end: 11171},
{begin: 11043, end: 11107},
{begin: 10979, end: 11043},
{begin: 10915, end: 10979},
{begin: 10851, end: 10915},
{begin: 10787, end: 10851},
{begin: 10723, end: 10787},
}
got, err := seq.sequence()
require.Equal(t, seqLen, len(got))
for i := 0; i < seqLen; i++ {
g := got[i]
exp := expected[i]
require.NoError(t, err)
require.Equal(t, exp.begin, g.begin)
require.Equal(t, exp.end, g.end)
require.Equal(t, batchSequenced, g.state)
}
// This should give us the error indicating there are too many outstanding batches.
_, err = seq.sequence()
require.ErrorIs(t, err, errMaxBatches)
// mark the last batch completed so we can call sequence again.
last := seq.seq[len(seq.seq)-1]
// With this state, the batch should get served back to us as the next batch.
last.state = batchErrRetryable
seq.update(last)
nextS, err := seq.sequence()
require.Equal(t, 1, len(nextS))
next := nextS[0]
require.NoError(t, err)
require.Equal(t, last.begin, next.begin)
require.Equal(t, last.end, next.end)
// sequence() should replace the batchErrRetryable state with batchSequenced.
require.Equal(t, batchSequenced, next.state)
// No batches have been marked importable.
require.Equal(t, 0, len(seq.importable()))
// Mark our batch importable and make sure it shows up in the list of importable batches.
next.state = batchImportable
seq.update(next)
require.Equal(t, 0, len(seq.importable()))
first := seq.seq[0]
first.state = batchImportable
seq.update(first)
require.Equal(t, 1, len(seq.importable()))
require.Equal(t, len(seq.seq), seqLen)
// change the last element back to batchInit so that the importable test stays simple
last = seq.seq[len(seq.seq)-1]
last.state = batchInit
seq.update(last)
// ensure that the number of importable elements grows as the list is marked importable
for i := 0; i < len(seq.seq); i++ {
seq.seq[i].state = batchImportable
require.Equal(t, i+1, len(seq.importable()))
}
// reset everything to init
for i := 0; i < len(seq.seq); i++ {
seq.seq[i].state = batchInit
require.Equal(t, 0, len(seq.importable()))
}
// loop backwards and make sure importable is zero until the first element is importable
for i := len(seq.seq) - 1; i > 0; i-- {
seq.seq[i].state = batchImportable
require.Equal(t, 0, len(seq.importable()))
}
seq.seq[0].state = batchImportable
require.Equal(t, len(seq.seq), len(seq.importable()))
// reset everything to init again
for i := 0; i < len(seq.seq); i++ {
seq.seq[i].state = batchInit
require.Equal(t, 0, len(seq.importable()))
}
// set first 3 elements to importable. we should see them in the result for importable()
// and be able to use update to cycle them away.
seq.seq[0].state, seq.seq[1].state, seq.seq[2].state = batchImportable, batchImportable, batchImportable
require.Equal(t, 3, len(seq.importable()))
a, b, c, z := seq.seq[0], seq.seq[1], seq.seq[2], seq.seq[3]
require.NotEqual(t, z.begin, seq.seq[2].begin)
require.NotEqual(t, z.begin, seq.seq[1].begin)
require.NotEqual(t, z.begin, seq.seq[0].begin)
a.state, b.state, c.state = batchImportComplete, batchImportComplete, batchImportComplete
seq.update(a)
// follow z as it moves down the chain to the first spot
require.Equal(t, z.begin, seq.seq[2].begin)
require.NotEqual(t, z.begin, seq.seq[1].begin)
require.NotEqual(t, z.begin, seq.seq[0].begin)
seq.update(b)
require.NotEqual(t, z.begin, seq.seq[2].begin)
require.Equal(t, z.begin, seq.seq[1].begin)
require.NotEqual(t, z.begin, seq.seq[0].begin)
seq.update(c)
require.NotEqual(t, z.begin, seq.seq[2].begin)
require.NotEqual(t, z.begin, seq.seq[1].begin)
require.Equal(t, z.begin, seq.seq[0].begin)
// Check integrity of begin/end alignment across the sequence.
// Also update all the states to sequenced for the convenience of the next test.
for i := 1; i < len(seq.seq); i++ {
require.Equal(t, seq.seq[i].end, seq.seq[i-1].begin)
// won't touch the first element, which is fine because it is marked complete below.
seq.seq[i].state = batchSequenced
}
// set the min for the batcher close to the lowest slot. This will force the next batch to be partial and the batch
// after that to be the final batch.
newMin := seq.seq[len(seq.seq)-1].begin - 30
seq.batcher.min = newMin
first = seq.seq[0]
first.state = batchImportComplete
// update() with a complete state will cause the sequence to be extended with an additional batch
seq.update(first)
lastS, err := seq.sequence()
last = lastS[0]
require.NoError(t, err)
require.Equal(t, newMin, last.begin)
require.Equal(t, seq.seq[len(seq.seq)-2].begin, last.end)
// Mark first batch done again, this time check that sequence() gives errEndSequence.
first = seq.seq[0]
first.state = batchImportComplete
// update() with a complete state will cause the sequence to be extended with an additional batch
seq.update(first)
endExp, err := seq.sequence()
require.NoError(t, err)
require.Equal(t, 1, len(endExp))
end := endExp[0]
//require.ErrorIs(t, err, errEndSequence)
require.Equal(t, batchEndSequence, end.state)
}