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  }