github.com/ethereum/go-ethereum@v1.16.1/triedb/pathdb/history_index_block_test.go (about) 1 // Copyright 2025 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/ 16 17 package pathdb 18 19 import ( 20 "math" 21 "math/rand" 22 "slices" 23 "sort" 24 "testing" 25 ) 26 27 func TestBlockReaderBasic(t *testing.T) { 28 elements := []uint64{ 29 1, 5, 10, 11, 20, 30 } 31 bw, _ := newBlockWriter(nil, newIndexBlockDesc(0)) 32 for i := 0; i < len(elements); i++ { 33 bw.append(elements[i]) 34 } 35 36 br, err := newBlockReader(bw.finish()) 37 if err != nil { 38 t.Fatalf("Failed to construct the block reader, %v", err) 39 } 40 cases := []struct { 41 value uint64 42 result uint64 43 }{ 44 {0, 1}, 45 {1, 5}, 46 {10, 11}, 47 {19, 20}, 48 {20, math.MaxUint64}, 49 {21, math.MaxUint64}, 50 } 51 for _, c := range cases { 52 got, err := br.readGreaterThan(c.value) 53 if err != nil { 54 t.Fatalf("Unexpected error, got %v", err) 55 } 56 if got != c.result { 57 t.Fatalf("Unexpected result, got %v, wanted %v", got, c.result) 58 } 59 } 60 } 61 62 func TestBlockReaderLarge(t *testing.T) { 63 var elements []uint64 64 for i := 0; i < 1000; i++ { 65 elements = append(elements, rand.Uint64()) 66 } 67 slices.Sort(elements) 68 69 bw, _ := newBlockWriter(nil, newIndexBlockDesc(0)) 70 for i := 0; i < len(elements); i++ { 71 bw.append(elements[i]) 72 } 73 74 br, err := newBlockReader(bw.finish()) 75 if err != nil { 76 t.Fatalf("Failed to construct the block reader, %v", err) 77 } 78 for i := 0; i < 100; i++ { 79 value := rand.Uint64() 80 pos := sort.Search(len(elements), func(i int) bool { 81 return elements[i] > value 82 }) 83 got, err := br.readGreaterThan(value) 84 if err != nil { 85 t.Fatalf("Unexpected error, got %v", err) 86 } 87 if pos == len(elements) { 88 if got != math.MaxUint64 { 89 t.Fatalf("Unexpected result, got %d, wanted math.MaxUint64", got) 90 } 91 } else if got != elements[pos] { 92 t.Fatalf("Unexpected result, got %d, wanted %d", got, elements[pos]) 93 } 94 } 95 } 96 97 func TestBlockWriterBasic(t *testing.T) { 98 bw, _ := newBlockWriter(nil, newIndexBlockDesc(0)) 99 if !bw.empty() { 100 t.Fatal("expected empty block") 101 } 102 bw.append(2) 103 if err := bw.append(1); err == nil { 104 t.Fatal("out-of-order insertion is not expected") 105 } 106 for i := 0; i < 10; i++ { 107 bw.append(uint64(i + 3)) 108 } 109 110 bw, err := newBlockWriter(bw.finish(), newIndexBlockDesc(0)) 111 if err != nil { 112 t.Fatalf("Failed to construct the block writer, %v", err) 113 } 114 for i := 0; i < 10; i++ { 115 if err := bw.append(uint64(i + 100)); err != nil { 116 t.Fatalf("Failed to append value %d: %v", i, err) 117 } 118 } 119 bw.finish() 120 } 121 122 func TestBlockWriterDelete(t *testing.T) { 123 bw, _ := newBlockWriter(nil, newIndexBlockDesc(0)) 124 for i := 0; i < 10; i++ { 125 bw.append(uint64(i + 1)) 126 } 127 // Pop unknown id, the request should be rejected 128 if err := bw.pop(100); err == nil { 129 t.Fatal("Expect error to occur for unknown id") 130 } 131 for i := 10; i >= 1; i-- { 132 if err := bw.pop(uint64(i)); err != nil { 133 t.Fatalf("Unexpected error for element popping, %v", err) 134 } 135 empty := i == 1 136 if empty != bw.empty() { 137 t.Fatalf("Emptiness is not matched, want: %T, got: %T", empty, bw.empty()) 138 } 139 newMax := uint64(i - 1) 140 if bw.desc.max != newMax { 141 t.Fatalf("Maxmium element is not matched, want: %d, got: %d", newMax, bw.desc.max) 142 } 143 } 144 } 145 146 func TestBlcokWriterDeleteWithData(t *testing.T) { 147 elements := []uint64{ 148 1, 5, 10, 11, 20, 149 } 150 bw, _ := newBlockWriter(nil, newIndexBlockDesc(0)) 151 for i := 0; i < len(elements); i++ { 152 bw.append(elements[i]) 153 } 154 155 // Re-construct the block writer with data 156 desc := &indexBlockDesc{ 157 id: 0, 158 max: 20, 159 entries: 5, 160 } 161 bw, err := newBlockWriter(bw.finish(), desc) 162 if err != nil { 163 t.Fatalf("Failed to construct block writer %v", err) 164 } 165 for i := len(elements) - 1; i > 0; i-- { 166 if err := bw.pop(elements[i]); err != nil { 167 t.Fatalf("Failed to pop element, %v", err) 168 } 169 newTail := elements[i-1] 170 171 // Ensure the element can still be queried with no issue 172 br, err := newBlockReader(bw.finish()) 173 if err != nil { 174 t.Fatalf("Failed to construct the block reader, %v", err) 175 } 176 cases := []struct { 177 value uint64 178 result uint64 179 }{ 180 {0, 1}, 181 {1, 5}, 182 {10, 11}, 183 {19, 20}, 184 {20, math.MaxUint64}, 185 {21, math.MaxUint64}, 186 } 187 for _, c := range cases { 188 want := c.result 189 if c.value >= newTail { 190 want = math.MaxUint64 191 } 192 got, err := br.readGreaterThan(c.value) 193 if err != nil { 194 t.Fatalf("Unexpected error, got %v", err) 195 } 196 if got != want { 197 t.Fatalf("Unexpected result, got %v, wanted %v", got, want) 198 } 199 } 200 } 201 } 202 203 func TestCorruptedIndexBlock(t *testing.T) { 204 bw, _ := newBlockWriter(nil, newIndexBlockDesc(0)) 205 for i := 0; i < 10; i++ { 206 bw.append(uint64(i + 1)) 207 } 208 buf := bw.finish() 209 210 // Mutate the buffer manually 211 buf[len(buf)-1]++ 212 _, err := newBlockWriter(buf, newIndexBlockDesc(0)) 213 if err == nil { 214 t.Fatal("Corrupted index block data is not detected") 215 } 216 }