github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/storage/merkle/proof_test.go (about) 1 package merkle 2 3 import ( 4 "math/rand" 5 "testing" 6 7 "github.com/stretchr/testify/assert" 8 "github.com/stretchr/testify/require" 9 ) 10 11 // TestProofWithASingleKey tests proof generation and verification 12 // when trie includes only a single value 13 func TestProofWithASingleKey(t *testing.T) { 14 minKeyLength := 1 15 keyLengths := []int{minKeyLength, 32, maxKeyLength} 16 for _, keyLength := range keyLengths { 17 tree1, err := NewTree(keyLength) 18 assert.NoError(t, err) 19 20 key, val := randomKeyValuePair(keyLength, 128) 21 22 replaced, err := tree1.Put(key, val) 23 assert.NoError(t, err) 24 require.False(t, replaced) 25 26 // work for an existing key 27 proof, existed := tree1.Prove(key) 28 require.True(t, existed) 29 30 err = proof.Verify(tree1.Hash()) 31 assert.NoError(t, err) 32 33 // fail for non-existing key 34 key2, _ := randomKeyValuePair(keyLength, 128) 35 36 proof, existed = tree1.Prove(key2) 37 require.False(t, existed) 38 require.Nil(t, proof) 39 } 40 } 41 42 // TestValidateFormat tests cases a proof can not be valid 43 func TestValidateFormat(t *testing.T) { 44 45 // construct a valid proof 46 keyLength := 31 47 key := make([]byte, keyLength) 48 key[0] = uint8(5) 49 value := make([]byte, 128) 50 value[0] = uint8(6) 51 52 key2 := make([]byte, keyLength) 53 key2[0] = uint8(4) 54 value2 := make([]byte, 128) 55 56 tree1, err := NewTree(keyLength) 57 assert.NoError(t, err) 58 replaced, err := tree1.Put(key, value) 59 assert.NoError(t, err) 60 require.False(t, replaced) 61 replaced, err = tree1.Put(key2, value2) 62 assert.NoError(t, err) 63 require.False(t, replaced) 64 proof, existed := tree1.Prove(key) 65 require.True(t, existed) 66 67 // invalid key size 68 proof.Key = make([]byte, 0) 69 err = proof.validateFormat() 70 assert.True(t, IsMalformedProofError(err)) 71 assert.Equal(t, err.Error(), "malformed proof, key length in bytes must be in interval [1, 8191], but is 0") 72 73 // invalid key size (too large) 74 proof.Key = make([]byte, maxKeyLength+1) 75 err = proof.validateFormat() 76 assert.True(t, IsMalformedProofError(err)) 77 assert.Equal(t, err.Error(), "malformed proof, key length in bytes must be in interval [1, 8191], but is 8192") 78 79 // issue with the key size not matching the rest of the proof 80 proof.Key = make([]byte, 64) 81 err = proof.validateFormat() 82 assert.True(t, IsMalformedProofError(err)) 83 assert.Equal(t, err.Error(), "malformed proof, key length in bits (512) doesn't match the length of ShortPathLengths and SiblingHashes (248)") 84 85 // reset the key back to its original value 86 proof.Key = key 87 88 // empty InterimNodeTypes 89 InterimNodeTypesBackup := proof.InterimNodeTypes 90 proof.InterimNodeTypes = make([]byte, 0) 91 err = proof.validateFormat() 92 assert.True(t, IsMalformedProofError(err)) 93 assert.Equal(t, err.Error(), "malformed proof, the length of InterimNodeTypes doesn't match the length of ShortPathLengths and SiblingHashes") 94 95 // too many interim nodes 96 proof.InterimNodeTypes = make([]byte, maxKeyLength+1) 97 err = proof.validateFormat() 98 assert.True(t, IsMalformedProofError(err)) 99 assert.Equal(t, err.Error(), "malformed proof, InterimNodeTypes is larger than max key length allowed (8192 > 8191)") 100 101 // issue with the size of InterimNodeTypes 102 proof.InterimNodeTypes = append(InterimNodeTypesBackup, byte(0)) 103 err = proof.validateFormat() 104 assert.True(t, IsMalformedProofError(err)) 105 assert.Equal(t, err.Error(), "malformed proof, the length of InterimNodeTypes doesn't match the length of ShortPathLengths and SiblingHashes") 106 107 proof.InterimNodeTypes = InterimNodeTypesBackup 108 109 // issue with a short count 110 backupShortPathLengths := proof.ShortPathLengths 111 proof.ShortPathLengths[0] = uint16(10) 112 err = proof.validateFormat() 113 assert.True(t, IsMalformedProofError(err)) 114 assert.Equal(t, err.Error(), "malformed proof, key length in bits (248) doesn't match the length of ShortPathLengths and SiblingHashes (251)") 115 116 proof.ShortPathLengths[0] = uint16(0) 117 err = proof.validateFormat() 118 assert.True(t, IsMalformedProofError(err)) 119 assert.Equal(t, err.Error(), "malformed proof, short path length cannot be zero") 120 121 // drop a shortpathlength - index out of bound 122 proof.ShortPathLengths = proof.ShortPathLengths[:1] 123 proof.ShortPathLengths[0] = uint16(247) 124 err = proof.validateFormat() 125 assert.True(t, IsMalformedProofError(err)) 126 assert.Equal(t, err.Error(), "malformed proof, len(ShortPathLengths) (1) does not match number of set bits in InterimNodeTypes (2)") 127 proof.ShortPathLengths = backupShortPathLengths 128 129 // construct a new proof 130 proof, existed = tree1.Prove(key) 131 require.True(t, existed) 132 133 // trailing zero test 134 proof.InterimNodeTypes[len(proof.InterimNodeTypes)-1] = byte(129) 135 err = proof.validateFormat() 136 assert.True(t, IsMalformedProofError(err)) 137 assert.Equal(t, err.Error(), "malformed proof, tailing auxiliary bits in InterimNodeTypes should all be zero") 138 } 139 140 // TestProofsWithRandomKeys tests proof generation and verification 141 // when trie includes many random keys. (only a random subset of keys are checked for proofs) 142 func TestProofsWithRandomKeys(t *testing.T) { 143 // initialize random generator, two trees and zero hash 144 145 keyLength := 32 146 numberOfInsertions := 10000 147 numberOfProofsToVerify := 100 148 tree1, err := NewTree(keyLength) 149 assert.NoError(t, err) 150 151 // generate the desired number of keys and map a value to each key 152 keys := make([][]byte, 0, numberOfInsertions) 153 vals := make(map[string][]byte) 154 for i := 0; i < numberOfInsertions; i++ { 155 key, val := randomKeyValuePair(32, 128) 156 keys = append(keys, key) 157 vals[string(key)] = val 158 } 159 160 // insert all key-value paris into the first tree 161 for _, key := range keys { 162 val := vals[string(key)] 163 replaced, err := tree1.Put(key, val) 164 assert.NoError(t, err) 165 require.False(t, replaced) 166 } 167 168 // shuffle the keys and insert them with random order into the second tree 169 rand.Shuffle(len(keys), func(i int, j int) { 170 keys[i], keys[j] = keys[j], keys[i] 171 }) 172 173 // get proofs for keys and verify for a subset of keys 174 for _, key := range keys[:numberOfProofsToVerify] { 175 proof, existed := tree1.Prove(key) 176 require.True(t, existed) 177 err := proof.Verify(tree1.Hash()) 178 assert.NoError(t, err) 179 } 180 // pass a malformed proof and expect the verify to call the validate 181 malformedProof := &Proof{} 182 err = malformedProof.Verify(tree1.Hash()) 183 assert.True(t, IsMalformedProofError(err)) 184 }