Fix tracker.Restore test, add CT workflow #5
23
.github/workflows/test.yml
vendored
Normal file
23
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: '*'
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Run unit tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
check-latest: true
|
||||||
|
- name: Run unit tests
|
||||||
|
run: |
|
||||||
|
go test -v -p 1 ./...
|
||||||
|
go test -v ./tracker -count 20
|
2
go.mod
2
go.mod
@ -1,6 +1,6 @@
|
|||||||
module github.com/cerc-io/eth-iterator-utils
|
module github.com/cerc-io/eth-iterator-utils
|
||||||
|
|
||||||
go 1.19
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cerc-io/eth-testing v0.4.0
|
github.com/cerc-io/eth-testing v0.4.0
|
||||||
|
@ -189,7 +189,7 @@ func (tr *TrackerImpl) Restore(makeIterator iter.IteratorConstructor) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// force the lower bound path to an even length (required by geth API/HexToKeyBytes)
|
// force the lower bound path to an even length (required by NodeIterator constructor)
|
||||||
if len(recoveredPath)&1 == 1 {
|
if len(recoveredPath)&1 == 1 {
|
||||||
// to avoid skipped nodes, we must rewind by one index
|
// to avoid skipped nodes, we must rewind by one index
|
||||||
recoveredPath = rewindPath(recoveredPath)
|
recoveredPath = rewindPath(recoveredPath)
|
||||||
@ -246,6 +246,7 @@ func (it *Iterator) Next(descend bool) bool {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bounds returns the bounds of the underlying PrefixBoundIterator, if any
|
||||||
func (it *Iterator) Bounds() ([]byte, []byte) {
|
func (it *Iterator) Bounds() ([]byte, []byte) {
|
||||||
if impl, ok := it.NodeIterator.(*iter.PrefixBoundIterator); ok {
|
if impl, ok := it.NodeIterator.(*iter.PrefixBoundIterator); ok {
|
||||||
return impl.Bounds()
|
return impl.Bounds()
|
||||||
@ -253,20 +254,21 @@ func (it *Iterator) Bounds() ([]byte, []byte) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rewinds to the path of the previous (pre-order) node:
|
// Returns the path, rewound to the previous (pre-order) node:
|
||||||
|
// If path is the root (empty) or a leaf path, it's returned.
|
||||||
// If the last byte of the path is zero, pops it (e.g. [1 0] => [1]).
|
// If the last byte of the path is zero, pops it (e.g. [1 0] => [1]).
|
||||||
// Otherwise, decrements it and pads with 0xF to 64 bytes (e.g. [1] => [0 f f f ...]).
|
// Otherwise, decrements it and pads with 0xF to 64 bytes (e.g. [1] => [0 f f f ...]).
|
||||||
// The passed slice is not modified.
|
// The passed slice is not modified.
|
||||||
func rewindPath(path []byte) []byte {
|
func rewindPath(path []byte) []byte {
|
||||||
if len(path) == 0 {
|
if len(path) == 0 || path[len(path)-1] == 0x10 {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
if path[len(path)-1] == 0 {
|
if path[len(path)-1] == 0 {
|
||||||
return path[:len(path)-1]
|
return path[:len(path)-1]
|
||||||
}
|
}
|
||||||
path[len(path)-1]--
|
|
||||||
padded := make([]byte, 64)
|
padded := make([]byte, 64)
|
||||||
i := copy(padded, path)
|
i := copy(padded, path)
|
||||||
|
padded[len(path)-1]--
|
||||||
for ; i < len(padded); i++ {
|
for ; i < len(padded); i++ {
|
||||||
padded[i] = 0xf
|
padded[i] = 0xf
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ func TestTracker(t *testing.T) {
|
|||||||
tr := tracker.New(recoveryFile, NumIters)
|
tr := tracker.New(recoveryFile, NumIters)
|
||||||
defer tr.CloseAndSave()
|
defer tr.CloseAndSave()
|
||||||
|
|
||||||
var prevPath []byte
|
|
||||||
count := 0
|
count := 0
|
||||||
nodeit, err := tree.NodeIterator(nil)
|
nodeit, err := tree.NodeIterator(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -33,9 +32,9 @@ func TestTracker(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for it := tr.Tracked(nodeit); it.Next(true); {
|
for it := tr.Tracked(nodeit); it.Next(true); {
|
||||||
if count == interrupt {
|
if count == interrupt {
|
||||||
return prevPath // tracker rewinds one node to prevent gaps
|
t.Logf("interrupting at: i=%d path=%v", count, it.Path())
|
||||||
|
return it.Path()
|
||||||
}
|
}
|
||||||
prevPath = it.Path()
|
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -58,8 +57,18 @@ func TestTracker(t *testing.T) {
|
|||||||
if uint(len(its)) != NumIters {
|
if uint(len(its)) != NumIters {
|
||||||
t.Fatalf("expected to restore %d iterators, got %d", NumIters, len(its))
|
t.Fatalf("expected to restore %d iterators, got %d", NumIters, len(its))
|
||||||
}
|
}
|
||||||
|
if !its[0].Next(true) {
|
||||||
|
t.Fatal("iterator ends prematurely after restore")
|
||||||
|
}
|
||||||
if !bytes.Equal(failedAt, its[0].Path()) {
|
if !bytes.Equal(failedAt, its[0].Path()) {
|
||||||
t.Fatalf("iterator restored to wrong position: expected %v, got %v", failedAt, its[0].Path())
|
// Due to the constraint that NodeIterator can only be initialized with an even-length path,
|
||||||
|
// we sometimes rewind an extra node when restoring (e.g. [1 2 0] => [1 2]).
|
||||||
|
if !its[0].Next(true) {
|
||||||
|
t.Fatal("iterator ends prematurely after restore")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(failedAt, its[0].Path()) {
|
||||||
|
t.Fatalf("iterator restored to wrong position: expected %v, got %v", failedAt, its[0].Path())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if fileExists(recoveryFile) {
|
if fileExists(recoveryFile) {
|
||||||
|
Loading…
Reference in New Issue
Block a user