github.com/iotexproject/iotex-core@v1.14.1-rc1/db/trie/mptrie/branchnode_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 "bytes" 10 "testing" 11 12 "github.com/stretchr/testify/require" 13 14 "github.com/iotexproject/iotex-core/db/trie" 15 "github.com/iotexproject/iotex-core/db/trie/triepb" 16 ) 17 18 func equals(bn *branchNode, clone *branchNode) bool { 19 if bn.isRoot != clone.isRoot { 20 return false 21 } 22 if bn.dirty != clone.dirty { 23 return false 24 } 25 if !bytes.Equal(bn.hashVal, clone.hashVal) || !bytes.Equal(bn.ser, clone.ser) { 26 return false 27 } 28 if len(bn.children) != len(clone.children) { 29 return false 30 } 31 for key, child := range clone.children { 32 if bn.children[key] != child { 33 return false 34 } 35 } 36 indices := bn.indices.List() 37 cloneIndices := clone.indices.List() 38 if len(indices) != len(cloneIndices) { 39 return false 40 } 41 for i, value := range cloneIndices { 42 if indices[i] != value { 43 return false 44 } 45 } 46 return true 47 } 48 49 func TestBranchNodeClone(t *testing.T) { 50 require := require.New(t) 51 cli := &merklePatriciaTrie{async: true, hashFunc: DefaultHashFunc} 52 t.Run("dirty empty root", func(t *testing.T) { 53 children := map[byte]node{} 54 indices := NewSortedList(children) 55 node, err := newRootBranchNode(cli, children, indices, true) 56 require.NoError(err) 57 bn, ok := node.(*branchNode) 58 require.True(ok) 59 clone, err := node.Clone() 60 require.NoError(err) 61 cbn, ok := clone.(*branchNode) 62 require.True(ok) 63 require.True(equals(bn, cbn)) 64 }) 65 t.Run("clean empty root", func(t *testing.T) { 66 children := map[byte]node{} 67 indices := NewSortedList(children) 68 node, err := newRootBranchNode(cli, children, indices, false) 69 require.NoError(err) 70 bn, ok := node.(*branchNode) 71 require.True(ok) 72 clone, err := node.Clone() 73 require.NoError(err) 74 cbn, ok := clone.(*branchNode) 75 require.True(ok) 76 require.True(equals(bn, cbn)) 77 }) 78 t.Run("normal branch node", func(t *testing.T) { 79 children := map[byte]node{} 80 children['a'] = &hashNode{hashVal: []byte("a")} 81 children['b'] = &hashNode{hashVal: []byte("b")} 82 children['c'] = &hashNode{hashVal: []byte("c")} 83 children['d'] = &hashNode{hashVal: []byte("d")} 84 indices := NewSortedList(children) 85 node, err := newBranchNode(cli, children, indices) 86 require.NoError(err) 87 bn, ok := node.(*branchNode) 88 require.True(ok) 89 clone, err := bn.Clone() 90 require.NoError(err) 91 cbn, ok := clone.(*branchNode) 92 require.True(ok) 93 require.True(equals(bn, cbn)) 94 }) 95 } 96 97 func TestBranchNodeProto(t *testing.T) { 98 require := require.New(t) 99 children := map[byte]node{} 100 children['a'] = &hashNode{hashVal: []byte("a")} 101 children['b'] = &hashNode{hashVal: []byte("b")} 102 children['c'] = &hashNode{hashVal: []byte("c")} 103 children['d'] = &hashNode{hashVal: []byte("d")} 104 indices := NewSortedList(children) 105 bnode := &branchNode{ 106 children: children, 107 indices: indices, 108 } 109 cli := &merklePatriciaTrie{async: true, hashFunc: DefaultHashFunc} 110 proto, err := bnode.proto(cli, true) 111 require.NoError(err) 112 nodepb, ok := proto.(*triepb.NodePb) 113 require.True(ok) 114 branch, ok := nodepb.Node.(*triepb.NodePb_Branch) 115 require.True(ok) 116 bnode1 := newBranchNodeFromProtoPb(branch.Branch, nil) 117 for key, child := range bnode1.children { 118 h, err := bnode.children[key].Hash(cli) 119 require.NoError(err) 120 h1, err := child.Hash(cli) 121 require.NoError(err) 122 require.Equal(h, h1) 123 } 124 li := bnode.indices.List() 125 for i, value := range bnode1.indices.List() { 126 require.Equal(li[i], value) 127 } 128 require.Equal(bnode.isRoot, bnode1.isRoot) 129 require.Equal(bnode.dirty, bnode1.dirty) 130 } 131 132 func TestBranchNodeChildren(t *testing.T) { 133 require := require.New(t) 134 children := map[byte]node{} 135 children['a'] = &hashNode{hashVal: []byte("a")} 136 children['b'] = &hashNode{hashVal: []byte("b")} 137 children['c'] = &hashNode{hashVal: []byte("c")} 138 children['d'] = &hashNode{hashVal: []byte("d")} 139 indices := NewSortedList(children) 140 bnode := &branchNode{ 141 children: children, 142 indices: indices, 143 } 144 childs := bnode.Children() 145 li := bnode.indices.List() 146 for i, node := range childs { 147 require.Equal(bnode.children[li[i]], node) 148 } 149 } 150 151 func TestBranchOperation(t *testing.T) { 152 var ( 153 require = require.New(t) 154 cli = &merklePatriciaTrie{ 155 hashFunc: DefaultHashFunc, 156 kvStore: trie.NewMemKVStore(), 157 } 158 children = make(map[byte]node) 159 ) 160 161 // create 162 node, err := newLeafNode(cli, keyType("iotex"), []byte("coin")) 163 require.NoError(err) 164 children[byte('i')] = node 165 node, err = newBranchNode(cli, children, nil) 166 require.NoError(err) 167 require.Panics(func() { node.Delete(cli, keyType("iotex"), 0) }, "branch shouldn't have 0 child after deleting") 168 169 // branch.Upsert child.Upsert -> branch 170 node, err = node.Upsert(cli, keyType("ioabc123"), 0, []byte("chabc")) 171 require.NoError(err) 172 bnode, ok := node.(*branchNode) 173 require.True(ok) 174 require.Len(bnode.children, 1) // ext 175 vn, ok := bnode.children[byte('i')] 176 require.True(ok) 177 ex1, ok := vn.(*extensionNode) 178 require.True(ok) 179 require.Equal([]byte("o"), ex1.path) 180 bn1, ok := ex1.child.(*branchNode) 181 require.True(ok) 182 require.Len(bn1.children, 2) 183 checkLeaf(require, bn1, keyType("iotex"), 2, []byte("coin")) 184 checkLeaf(require, bn1, keyType("ioabc123"), 2, []byte("chabc")) 185 186 // branch.Upsert newLeafNode -> branch 187 node, err = node.Upsert(cli, keyType("block"), 0, []byte("chain")) 188 require.NoError(err) 189 bnode1, ok := node.(*branchNode) 190 require.True(ok) 191 require.Len(bnode1.children, 2) // block, ext 192 require.Equal(bnode.children[byte('i')], bnode1.children[byte('i')]) 193 checkLeaf(require, bnode1, keyType("block"), 0, []byte("chain")) 194 195 // branch.Upsert child.Upsert -> branch 196 node, err = node.Upsert(cli, keyType("iotex"), 0, []byte("chain")) 197 require.NoError(err) 198 bnode2, ok := node.(*branchNode) 199 require.True(ok) 200 require.Len(bnode2.children, 2) // block, ex2 201 require.Equal(bnode1.children[byte('b')], bnode2.children[byte('b')]) 202 require.NotEqual(bnode.children[byte('i')], bnode2.children[byte('i')]) 203 ex2, ok := bnode2.children[byte('i')].(*extensionNode) 204 require.True(ok) 205 bn2, ok := ex2.child.(*branchNode) 206 require.True(ok) 207 checkLeaf(require, bn2, keyType("iotex"), 2, []byte("chain")) 208 209 // branch.Upsert child.Upsert -> branch 210 node, err = node.Upsert(cli, keyType("ixy"), 0, []byte("dog")) 211 require.NoError(err) 212 bnode3, ok := node.(*branchNode) 213 require.True(ok) 214 require.Len(bnode3.children, 2) // block, bn3 215 require.Equal(bnode1.children[byte('b')], bnode3.children[byte('b')]) 216 require.NotEqual(bnode.children[byte('i')], bnode3.children[byte('i')]) 217 bn3, ok := bnode3.children[byte('i')].(*branchNode) 218 require.True(ok) 219 require.Len(bn3.children, 2) // ixy, ext 220 checkLeaf(require, bn3, keyType("ixy"), 1, []byte("dog")) 221 222 // branch.Upsert child.Upsert -> branch 223 node, err = node.Upsert(cli, keyType("idef"), 0, []byte("cat")) 224 require.NoError(err) 225 bnode4, ok := node.(*branchNode) 226 require.True(ok) 227 require.Len(bnode4.children, 2) // block, bn4 228 require.Equal(bnode1.children[byte('b')], bnode4.children[byte('b')]) 229 bn4, ok := bnode4.children[byte('i')].(*branchNode) 230 require.True(ok) 231 require.Len(bn4.children, 3) // idef, ixy, ext 232 checkLeaf(require, bn4, keyType("idef"), 1, []byte("cat")) 233 234 // check key 235 node1, err := node.Search(cli, keyType("iotex"), 0) 236 require.NoError(err) 237 require.Equal([]byte("chain"), node1.(*leafNode).value) 238 node1, err = node.Search(cli, keyType("ioabc123"), 0) 239 require.NoError(err) 240 require.Equal([]byte("chabc"), node1.(*leafNode).value) 241 node1, err = node.Search(cli, keyType("block"), 0) 242 require.NoError(err) 243 require.Equal([]byte("chain"), node1.(*leafNode).value) 244 node1, err = node.Search(cli, keyType("ixy"), 0) 245 require.NoError(err) 246 require.Equal([]byte("dog"), node1.(*leafNode).value) 247 node1, err = node.Search(cli, keyType("idef"), 0) 248 require.NoError(err) 249 require.Equal([]byte("cat"), node1.(*leafNode).value) 250 251 // branch.Delete default b.updateChild -> extension 252 node, err = node.Delete(cli, keyType("idef"), 0) 253 require.NoError(err) 254 bnode, ok = node.(*branchNode) 255 require.True(ok) 256 require.Len(bnode.children, 2) 257 node1, err = node.Search(cli, keyType("idef"), 0) 258 require.Equal(trie.ErrNotExist, err) 259 260 // branch.Delete case2 case *leafNode -> branch.Delete b.updateChild 261 node, err = node.Delete(cli, keyType("ioabc123"), 0) 262 require.NoError(err) 263 bnode, ok = node.(*branchNode) 264 require.True(ok) 265 require.Len(bnode.children, 2) 266 node1, err = node.Search(cli, keyType("ioabc123"), 0) 267 require.Equal(trie.ErrNotExist, err) 268 269 // branch.Delete case2 default newExtensionNode 270 node, err = node.Delete(cli, keyType("block"), 0) 271 require.NoError(err) 272 enode, ok := node.(*extensionNode) 273 require.True(ok) 274 bn1, ok = enode.child.(*branchNode) 275 require.True(ok) 276 require.Len(bn1.children, 2) 277 node1, err = node.Search(cli, keyType("block"), 0) 278 require.Equal(trie.ErrNotExist, err) 279 280 // extension.Delete default 281 node, err = node.Delete(cli, keyType("iotex"), 0) 282 require.NoError(err) 283 _, ok = node.(*leafNode) 284 require.True(ok) 285 node1, err = node.Search(cli, keyType("iotex"), 0) 286 require.Equal(trie.ErrNotExist, err) 287 288 // leaf.Delete 289 node, err = node.Delete(cli, keyType("ixy"), 0) 290 require.NoError(err) 291 require.Nil(node) 292 293 // children is nil 294 node, err = newRootBranchNode(cli, nil, nil, false) 295 require.NoError(err) 296 node, err = node.Delete(cli, keyType{1}, 0) 297 require.Equal(trie.ErrNotExist, err) 298 require.Nil(node) 299 300 // children is max 301 node, err = newRootBranchNode(cli, nil, nil, false) 302 for i := byte(0); i < 255; i++ { 303 node, err = node.Upsert(cli, keyType{1, i}, 1, []byte{i}) 304 require.NoError(err) 305 } 306 require.Len(node.(*branchNode).children, 255) 307 n1, err := node.Search(cli, keyType{1, 2}, 1) 308 require.NoError(err) 309 require.Equal([]byte{2}, n1.(*leafNode).value) 310 node, err = node.Upsert(cli, keyType{2, 3, 4, 5}, 0, []byte{2, 3, 4, 5}) 311 require.NoError(err) 312 n1, err = node.Search(cli, keyType{2, 3, 4, 5}, 0) 313 require.NoError(err) 314 require.Equal([]byte{2, 3, 4, 5}, n1.(*leafNode).value) 315 require.Panics(func() { node.Search(cli, keyType{1, 2}, 1) }, "keyType{1, 2} is not exist") 316 } 317 318 func checkLeaf(require *require.Assertions, bnode *branchNode, key keyType, offset uint8, value []byte) { 319 child, ok := bnode.children[key[offset]] 320 require.True(ok) 321 ln, ok := child.(*leafNode) 322 require.True(ok) 323 require.Equal(value, ln.value) 324 }