github.com/koko1123/flow-go-1@v0.29.6/storage/merkle/proof_test.go (about)

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