// Copyright 2025 go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package bintrie import ( "bytes" "encoding/binary" "testing" "github.com/ethereum/go-ethereum/common" ) var ( zeroKey = [32]byte{} oneKey = common.HexToHash("0101010101010101010101010101010101010101010101010101010101010101") twoKey = common.HexToHash("0202020202020202020202020202020202020202020202020202020202020202") threeKey = common.HexToHash("0303030303030303030303030303030303030303030303030303030303030303") fourKey = common.HexToHash("0404040404040404040404040404040404040404040404040404040404040404") ffKey = common.HexToHash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") ) func TestSingleEntry(t *testing.T) { tree := NewBinaryNode() tree, err := tree.Insert(zeroKey[:], oneKey[:], nil, 0) if err != nil { t.Fatal(err) } if tree.GetHeight() != 1 { t.Fatal("invalid depth") } expected := common.HexToHash("aab1060e04cb4f5dc6f697ae93156a95714debbf77d54238766adc5709282b6f") got := tree.Hash() if got != expected { t.Fatalf("invalid tree root, got %x, want %x", got, expected) } } func TestTwoEntriesDiffFirstBit(t *testing.T) { var err error tree := NewBinaryNode() tree, err = tree.Insert(zeroKey[:], oneKey[:], nil, 0) if err != nil { t.Fatal(err) } tree, err = tree.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000000").Bytes(), twoKey[:], nil, 0) if err != nil { t.Fatal(err) } if tree.GetHeight() != 2 { t.Fatal("invalid height") } if tree.Hash() != common.HexToHash("dfc69c94013a8b3c65395625a719a87534a7cfd38719251ad8c8ea7fe79f065e") { t.Fatal("invalid tree root") } } func TestOneStemColocatedValues(t *testing.T) { var err error tree := NewBinaryNode() tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil, 0) if err != nil { t.Fatal(err) } tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil, 0) if err != nil { t.Fatal(err) } tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000009").Bytes(), threeKey[:], nil, 0) if err != nil { t.Fatal(err) } tree, err = tree.Insert(common.HexToHash("00000000000000000000000000000000000000000000000000000000000000FF").Bytes(), fourKey[:], nil, 0) if err != nil { t.Fatal(err) } if tree.GetHeight() != 1 { t.Fatal("invalid height") } } func TestTwoStemColocatedValues(t *testing.T) { var err error tree := NewBinaryNode() // stem: 0...0 tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil, 0) if err != nil { t.Fatal(err) } tree, err = tree.Insert(common.HexToHash("0000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil, 0) if err != nil { t.Fatal(err) } // stem: 10...0 tree, err = tree.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000003").Bytes(), oneKey[:], nil, 0) if err != nil { t.Fatal(err) } tree, err = tree.Insert(common.HexToHash("8000000000000000000000000000000000000000000000000000000000000004").Bytes(), twoKey[:], nil, 0) if err != nil { t.Fatal(err) } if tree.GetHeight() != 2 { t.Fatal("invalid height") } } func TestTwoKeysMatchFirst42Bits(t *testing.T) { var err error tree := NewBinaryNode() // key1 and key 2 have the same prefix of 42 bits (b0*42+b1+b1) and differ after. key1 := common.HexToHash("0000000000C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0").Bytes() key2 := common.HexToHash("0000000000E00000000000000000000000000000000000000000000000000000").Bytes() tree, err = tree.Insert(key1, oneKey[:], nil, 0) if err != nil { t.Fatal(err) } tree, err = tree.Insert(key2, twoKey[:], nil, 0) if err != nil { t.Fatal(err) } if tree.GetHeight() != 1+42+1 { t.Fatal("invalid height") } } func TestInsertDuplicateKey(t *testing.T) { var err error tree := NewBinaryNode() tree, err = tree.Insert(oneKey[:], oneKey[:], nil, 0) if err != nil { t.Fatal(err) } tree, err = tree.Insert(oneKey[:], twoKey[:], nil, 0) if err != nil { t.Fatal(err) } if tree.GetHeight() != 1 { t.Fatal("invalid height") } // Verify that the value is updated if !bytes.Equal(tree.(*StemNode).Values[1], twoKey[:]) { t.Fatal("invalid height") } } func TestLargeNumberOfEntries(t *testing.T) { var err error tree := NewBinaryNode() for i := range 256 { var key [32]byte key[0] = byte(i) tree, err = tree.Insert(key[:], ffKey[:], nil, 0) if err != nil { t.Fatal(err) } } height := tree.GetHeight() if height != 1+8 { t.Fatalf("invalid height, wanted %d, got %d", 1+8, height) } } func TestMerkleizeMultipleEntries(t *testing.T) { var err error tree := NewBinaryNode() keys := [][]byte{ zeroKey[:], common.HexToHash("8000000000000000000000000000000000000000000000000000000000000000").Bytes(), common.HexToHash("0100000000000000000000000000000000000000000000000000000000000000").Bytes(), common.HexToHash("8100000000000000000000000000000000000000000000000000000000000000").Bytes(), } for i, key := range keys { var v [32]byte binary.LittleEndian.PutUint64(v[:8], uint64(i)) tree, err = tree.Insert(key, v[:], nil, 0) if err != nil { t.Fatal(err) } } got := tree.Hash() expected := common.HexToHash("9317155862f7a3867660ddd0966ff799a3d16aa4df1e70a7516eaa4a675191b5") if got != expected { t.Fatalf("invalid root, expected=%x, got = %x", expected, got) } }