github.com/MetalBlockchain/metalgo@v1.11.9/x/merkledb/hashing_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package merkledb 5 6 import ( 7 "math/rand" 8 "testing" 9 10 "github.com/stretchr/testify/require" 11 12 "github.com/MetalBlockchain/metalgo/ids" 13 "github.com/MetalBlockchain/metalgo/utils/maybe" 14 ) 15 16 var sha256HashNodeTests = []struct { 17 name string 18 n *node 19 expectedHash string 20 }{ 21 { 22 name: "empty node", 23 n: newNode(Key{}), 24 expectedHash: "rbhtxoQ1DqWHvb6w66BZdVyjmPAneZUSwQq9uKj594qvFSdav", 25 }, 26 { 27 name: "has value", 28 n: func() *node { 29 n := newNode(Key{}) 30 n.setValue(SHA256Hasher, maybe.Some([]byte("value1"))) 31 return n 32 }(), 33 expectedHash: "2vx2xueNdWoH2uB4e8hbMU5jirtZkZ1c3ePCWDhXYaFRHpCbnQ", 34 }, 35 { 36 name: "has key", 37 n: newNode(ToKey([]byte{0, 1, 2, 3, 4, 5, 6, 7})), 38 expectedHash: "2vA8ggXajhFEcgiF8zHTXgo8T2ALBFgffp1xfn48JEni1Uj5uK", 39 }, 40 { 41 name: "1 child", 42 n: func() *node { 43 n := newNode(Key{}) 44 childNode := newNode(ToKey([]byte{255})) 45 childNode.setValue(SHA256Hasher, maybe.Some([]byte("value1"))) 46 n.addChildWithID(childNode, 4, SHA256Hasher.HashNode(childNode)) 47 return n 48 }(), 49 expectedHash: "YfJRufqUKBv9ez6xZx6ogpnfDnw9fDsyebhYDaoaH57D3vRu3", 50 }, 51 { 52 name: "2 children", 53 n: func() *node { 54 n := newNode(Key{}) 55 56 childNode1 := newNode(ToKey([]byte{255})) 57 childNode1.setValue(SHA256Hasher, maybe.Some([]byte("value1"))) 58 59 childNode2 := newNode(ToKey([]byte{237})) 60 childNode2.setValue(SHA256Hasher, maybe.Some([]byte("value2"))) 61 62 n.addChildWithID(childNode1, 4, SHA256Hasher.HashNode(childNode1)) 63 n.addChildWithID(childNode2, 4, SHA256Hasher.HashNode(childNode2)) 64 return n 65 }(), 66 expectedHash: "YVmbx5MZtSKuYhzvHnCqGrswQcxmozAkv7xE1vTA2EiGpWUkv", 67 }, 68 { 69 name: "16 children", 70 n: func() *node { 71 n := newNode(Key{}) 72 73 for i := byte(0); i < 16; i++ { 74 childNode := newNode(ToKey([]byte{i << 4})) 75 childNode.setValue(SHA256Hasher, maybe.Some([]byte("some value"))) 76 77 n.addChildWithID(childNode, 4, SHA256Hasher.HashNode(childNode)) 78 } 79 return n 80 }(), 81 expectedHash: "5YiFLL7QV3f441See9uWePi3wVKsx9fgvX5VPhU8PRxtLqhwY", 82 }, 83 } 84 85 // Ensure that SHA256.HashNode is deterministic 86 func Fuzz_SHA256_HashNode(f *testing.F) { 87 f.Fuzz( 88 func( 89 t *testing.T, 90 randSeed int, 91 ) { 92 require := require.New(t) 93 for _, bf := range validBranchFactors { // Create a random node 94 r := rand.New(rand.NewSource(int64(randSeed))) // #nosec G404 95 96 children := map[byte]*child{} 97 numChildren := r.Intn(int(bf)) // #nosec G404 98 for i := 0; i < numChildren; i++ { 99 compressedKeyLen := r.Intn(32) // #nosec G404 100 compressedKeyBytes := make([]byte, compressedKeyLen) 101 _, _ = r.Read(compressedKeyBytes) // #nosec G404 102 103 children[byte(i)] = &child{ 104 compressedKey: ToKey(compressedKeyBytes), 105 id: ids.GenerateTestID(), 106 hasValue: r.Intn(2) == 1, // #nosec G404 107 } 108 } 109 110 hasValue := r.Intn(2) == 1 // #nosec G404 111 value := maybe.Nothing[[]byte]() 112 if hasValue { 113 valueBytes := make([]byte, r.Intn(64)) // #nosec G404 114 _, _ = r.Read(valueBytes) // #nosec G404 115 value = maybe.Some(valueBytes) 116 } 117 118 key := make([]byte, r.Intn(32)) // #nosec G404 119 _, _ = r.Read(key) // #nosec G404 120 121 hv := &node{ 122 key: ToKey(key), 123 dbNode: dbNode{ 124 children: children, 125 value: value, 126 }, 127 } 128 129 // Hash hv multiple times 130 hash1 := SHA256Hasher.HashNode(hv) 131 hash2 := SHA256Hasher.HashNode(hv) 132 133 // Make sure they're the same 134 require.Equal(hash1, hash2) 135 } 136 }, 137 ) 138 } 139 140 func Test_SHA256_HashNode(t *testing.T) { 141 for _, test := range sha256HashNodeTests { 142 t.Run(test.name, func(t *testing.T) { 143 hash := SHA256Hasher.HashNode(test.n) 144 require.Equal(t, test.expectedHash, hash.String()) 145 }) 146 } 147 } 148 149 func Benchmark_SHA256_HashNode(b *testing.B) { 150 for _, benchmark := range sha256HashNodeTests { 151 b.Run(benchmark.name, func(b *testing.B) { 152 for i := 0; i < b.N; i++ { 153 SHA256Hasher.HashNode(benchmark.n) 154 } 155 }) 156 } 157 }