github.com/iotexproject/iotex-core@v1.14.1-rc1/db/trie/mptrie/leafnode_test.go (about)

     1  // Copyright (c) 2020 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package mptrie
     7  
     8  import (
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/iotexproject/iotex-core/db/trie"
    14  	"github.com/iotexproject/iotex-core/db/trie/triepb"
    15  )
    16  
    17  func TestLeafNodeProto(t *testing.T) {
    18  	require := require.New(t)
    19  	lnode := &leafNode{
    20  		key:   []byte("iotex"),
    21  		value: []byte("chain"),
    22  	}
    23  	proto, err := lnode.proto(nil, true)
    24  	require.NoError(err)
    25  	nodepb, ok := proto.(*triepb.NodePb)
    26  	require.True(ok)
    27  	leaf, ok := nodepb.Node.(*triepb.NodePb_Leaf)
    28  	require.True(ok)
    29  	lnode1 := newLeafNodeFromProtoPb(leaf.Leaf, nil)
    30  	require.Equal(lnode.key, lnode1.key)
    31  	require.Equal(lnode.value, lnode1.value)
    32  }
    33  
    34  func TestLeafOperation(t *testing.T) {
    35  	var (
    36  		require = require.New(t)
    37  		cli     = &merklePatriciaTrie{
    38  			hashFunc: DefaultHashFunc,
    39  			kvStore:  trie.NewMemKVStore(),
    40  		}
    41  	)
    42  
    43  	// create
    44  	node, err := newLeafNode(cli, keyType("iotex"), []byte("coin"))
    45  	require.NoError(err)
    46  
    47  	// leaf.Upsert newLeafNode -> leaf
    48  	node, err = node.Upsert(cli, keyType("iotex"), 0, []byte("chain"))
    49  	require.NoError(err)
    50  	leaf, ok := node.(*leafNode)
    51  	require.True(ok)
    52  	require.Equal(keyType("iotex"), leaf.key)
    53  	require.Equal([]byte("chain"), leaf.value)
    54  
    55  	// leaf.Upsert newBranchNode -> branch
    56  	node, err = node.Upsert(cli, keyType("block"), 0, []byte("chain"))
    57  	require.NoError(err)
    58  	bnode, ok := node.(*branchNode)
    59  	require.True(ok)
    60  	require.Len(bnode.children, 2)
    61  	checkLeaf(require, bnode, keyType("iotex"), 0, []byte("chain"))
    62  	checkLeaf(require, bnode, keyType("block"), 0, []byte("chain"))
    63  
    64  	// branch.Upsert child.Upsert -> leaf.Upsert newExtensionNode -> extension
    65  	node, err = node.Upsert(cli, keyType("ioabc123"), 0, []byte("chabc"))
    66  	require.NoError(err)
    67  	bnode, ok = node.(*branchNode)
    68  	require.True(ok)
    69  	require.Len(bnode.children, 2)
    70  	enode, ok := bnode.children[byte('i')].(*extensionNode)
    71  	require.True(ok)
    72  	require.Equal([]byte("o"), enode.path)
    73  	bnode, ok = enode.child.(*branchNode)
    74  	require.True(ok)
    75  	require.Len(bnode.children, 2)
    76  	checkLeaf(require, bnode, keyType("iotex"), 2, []byte("chain"))
    77  	checkLeaf(require, bnode, keyType("ioabc123"), 2, []byte("chabc"))
    78  
    79  	// branch.Upsert child.Upsert -> branch
    80  	node, err = node.Upsert(cli, keyType("ixy"), 0, []byte("dog"))
    81  	require.NoError(err)
    82  	bnode, ok = node.(*branchNode)
    83  	require.True(ok)
    84  	require.Len(bnode.children, 2) // (block, (ixy, ext))
    85  	node1, ok := bnode.children[byte('i')]
    86  	require.True(ok)
    87  	bnode1, ok := node1.(*branchNode)
    88  	require.True(ok)
    89  	require.Len(bnode1.children, 2) // ixy, ext
    90  	node2, ok := bnode1.children[byte('o')]
    91  	require.True(ok)
    92  	enode2, ok := node2.(*extensionNode)
    93  	require.True(ok)
    94  	require.Equal([]byte(""), enode2.path)
    95  	require.Len(enode2.child.(*branchNode).children, 2)
    96  	checkLeaf(require, bnode1, keyType("ixy"), 1, []byte("dog"))
    97  
    98  	// insert wrong key
    99  	for _, key := range []keyType{
   100  		keyType("i"), keyType("bloc"), keyType("iote"), keyType("ioabc12345678"),
   101  	} {
   102  		require.Panics(func() { node.Upsert(cli, key, 0, []byte("ch")) }, "index out of range in commonPrefixLength.")
   103  	}
   104  
   105  	// check key
   106  	node1, err = node.Search(cli, keyType("iotex"), 0)
   107  	require.NoError(err)
   108  	require.Equal([]byte("chain"), node1.(*leafNode).value)
   109  	node1, err = node.Search(cli, keyType("ioabc123"), 0)
   110  	require.NoError(err)
   111  	require.Equal([]byte("chabc"), node1.(*leafNode).value)
   112  	node1, err = node.Search(cli, keyType("block"), 0)
   113  	require.NoError(err)
   114  	require.Equal([]byte("chain"), node1.(*leafNode).value)
   115  	node1, err = node.Search(cli, keyType("ixy"), 0)
   116  	require.NoError(err)
   117  	require.Equal([]byte("dog"), node1.(*leafNode).value)
   118  
   119  	// branch.Delete case2 case *extensionNode -> branch.Delete b.updateChild -> branch
   120  	node, err = node.Delete(cli, keyType("ixy"), 0)
   121  	require.NoError(err)
   122  	bnode, ok = node.(*branchNode)
   123  	require.True(ok)
   124  	require.Len(bnode.children, 2) // block, ext
   125  	checkLeaf(require, bnode, keyType("block"), 0, []byte("chain"))
   126  	enode, ok = bnode.children[byte('i')].(*extensionNode)
   127  	require.True(ok)
   128  	require.Equal([]byte("o"), enode.path)
   129  	require.Len(enode.child.(*branchNode).children, 2)
   130  	node1, err = node.Search(cli, keyType("ixy"), 0)
   131  	require.Equal(trie.ErrNotExist, err)
   132  
   133  	// branch.Delete case2 case *extensionNode -> extension
   134  	node, err = node.Delete(cli, keyType("block"), 0)
   135  	require.NoError(err)
   136  	enode, ok = node.(*extensionNode)
   137  	require.True(ok)
   138  	require.Equal([]byte("io"), enode.path)
   139  	require.Len(enode2.child.(*branchNode).children, 2)
   140  	node1, err = node.Search(cli, keyType("block"), 0)
   141  	require.Equal(trie.ErrNotExist, err)
   142  
   143  	// extension.Delete default -> branch.Delete case2 case *leafNode -> leaf
   144  	node, err = node.Delete(cli, keyType("iotex"), 0)
   145  	require.NoError(err)
   146  	leaf, ok = node.(*leafNode)
   147  	require.True(ok)
   148  	require.Equal(keyType("ioabc123"), leaf.key)
   149  	require.Equal([]byte("chabc"), leaf.value)
   150  	node1, err = node.Search(cli, keyType("iotex"), 0)
   151  	require.Equal(trie.ErrNotExist, err)
   152  
   153  	// leaf.Delete -> nil
   154  	node, err = node.Delete(cli, keyType("ioabc123"), 0)
   155  	require.NoError(err)
   156  	require.Nil(node)
   157  
   158  	// key is nil
   159  	node, err = newLeafNode(cli, keyType{}, []byte("0"))
   160  	require.NoError(err)
   161  	node1, err = node.Search(cli, keyType{}, 0)
   162  	require.NoError(err)
   163  	require.Equal([]byte("0"), node1.(*leafNode).value)
   164  	_, err = node.Delete(cli, keyType("123"), 0)
   165  	require.Equal(trie.ErrNotExist, err)
   166  	node2, err = node.Delete(cli, keyType{}, 0)
   167  	require.NoError(err)
   168  	require.Nil(node2)
   169  }