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 }