github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/iavl/basic_test.go (about) 1 package iavl 2 3 import ( 4 "bytes" 5 mrand "math/rand" 6 "sort" 7 "testing" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 12 "github.com/gnolang/gno/tm2/pkg/db" 13 "github.com/gnolang/gno/tm2/pkg/db/memdb" 14 ) 15 16 func TestBasic(t *testing.T) { 17 t.Parallel() 18 19 tree := NewMutableTree(memdb.NewMemDB(), 0) 20 up := tree.Set([]byte("1"), []byte("one")) 21 if up { 22 t.Error("Did not expect an update (should have been create)") 23 } 24 up = tree.Set([]byte("2"), []byte("two")) 25 if up { 26 t.Error("Did not expect an update (should have been create)") 27 } 28 up = tree.Set([]byte("2"), []byte("TWO")) 29 if !up { 30 t.Error("Expected an update") 31 } 32 up = tree.Set([]byte("5"), []byte("five")) 33 if up { 34 t.Error("Did not expect an update (should have been create)") 35 } 36 37 // Test 0x00 38 { 39 idx, val := tree.Get([]byte{0x00}) 40 if val != nil { 41 t.Errorf("Expected no value to exist") 42 } 43 if idx != 0 { 44 t.Errorf("Unexpected idx %x", idx) 45 } 46 if string(val) != "" { 47 t.Errorf("Unexpected value %v", string(val)) 48 } 49 } 50 51 // Test "1" 52 { 53 idx, val := tree.Get([]byte("1")) 54 if val == nil { 55 t.Errorf("Expected value to exist") 56 } 57 if idx != 0 { 58 t.Errorf("Unexpected idx %x", idx) 59 } 60 if string(val) != "one" { 61 t.Errorf("Unexpected value %v", string(val)) 62 } 63 } 64 65 // Test "2" 66 { 67 idx, val := tree.Get([]byte("2")) 68 if val == nil { 69 t.Errorf("Expected value to exist") 70 } 71 if idx != 1 { 72 t.Errorf("Unexpected idx %x", idx) 73 } 74 if string(val) != "TWO" { 75 t.Errorf("Unexpected value %v", string(val)) 76 } 77 } 78 79 // Test "4" 80 { 81 idx, val := tree.Get([]byte("4")) 82 if val != nil { 83 t.Errorf("Expected no value to exist") 84 } 85 if idx != 2 { 86 t.Errorf("Unexpected idx %x", idx) 87 } 88 if string(val) != "" { 89 t.Errorf("Unexpected value %v", string(val)) 90 } 91 } 92 93 // Test "6" 94 { 95 idx, val := tree.Get([]byte("6")) 96 if val != nil { 97 t.Errorf("Expected no value to exist") 98 } 99 if idx != 3 { 100 t.Errorf("Unexpected idx %x", idx) 101 } 102 if string(val) != "" { 103 t.Errorf("Unexpected value %v", string(val)) 104 } 105 } 106 } 107 108 func TestUnit(t *testing.T) { 109 t.Parallel() 110 111 expectHash := func(tree *ImmutableTree, hashCount int64) { 112 // ensure number of new hash calculations is as expected. 113 hash, count := tree.hashWithCount() 114 if count != hashCount { 115 t.Fatalf("Expected %v new hashes, got %v", hashCount, count) 116 } 117 // nuke hashes and reconstruct hash, ensure it's the same. 118 tree.root.traverse(tree, true, func(node *Node) bool { 119 node.hash = nil 120 return false 121 }) 122 // ensure that the new hash after nuking is the same as the old. 123 newHash, _ := tree.hashWithCount() 124 if !bytes.Equal(hash, newHash) { 125 t.Fatalf("Expected hash %v but got %v after nuking", hash, newHash) 126 } 127 } 128 129 expectSet := func(tree *MutableTree, i int, repr string, hashCount int64) { 130 origNode := tree.root 131 updated := tree.Set(i2b(i), []byte{}) 132 // ensure node was added & structure is as expected. 133 if updated || P(tree.root) != repr { 134 t.Fatalf("Adding %v to %v:\nExpected %v\nUnexpectedly got %v updated:%v", 135 i, P(origNode), repr, P(tree.root), updated) 136 } 137 // ensure hash calculation requirements 138 expectHash(tree.ImmutableTree, hashCount) 139 tree.root = origNode 140 } 141 142 expectRemove := func(tree *MutableTree, i int, repr string, hashCount int64) { 143 origNode := tree.root 144 value, removed := tree.Remove(i2b(i)) 145 // ensure node was added & structure is as expected. 146 if len(value) != 0 || !removed || P(tree.root) != repr { 147 t.Fatalf("Removing %v from %v:\nExpected %v\nUnexpectedly got %v value:%v removed:%v", 148 i, P(origNode), repr, P(tree.root), value, removed) 149 } 150 // ensure hash calculation requirements 151 expectHash(tree.ImmutableTree, hashCount) 152 tree.root = origNode 153 } 154 155 // ////// Test Set cases: 156 157 // Case 1: 158 t1 := T(N(4, 20)) 159 160 expectSet(t1, 8, "((4 8) 20)", 3) 161 expectSet(t1, 25, "(4 (20 25))", 3) 162 163 t2 := T(N(4, N(20, 25))) 164 165 expectSet(t2, 8, "((4 8) (20 25))", 3) 166 expectSet(t2, 30, "((4 20) (25 30))", 4) 167 168 t3 := T(N(N(1, 2), 6)) 169 170 expectSet(t3, 4, "((1 2) (4 6))", 4) 171 expectSet(t3, 8, "((1 2) (6 8))", 3) 172 173 t4 := T(N(N(1, 2), N(N(5, 6), N(7, 9)))) 174 175 expectSet(t4, 8, "(((1 2) (5 6)) ((7 8) 9))", 5) 176 expectSet(t4, 10, "(((1 2) (5 6)) (7 (9 10)))", 5) 177 178 // ////// Test Remove cases: 179 180 t10 := T(N(N(1, 2), 3)) 181 182 expectRemove(t10, 2, "(1 3)", 1) 183 expectRemove(t10, 3, "(1 2)", 0) 184 185 t11 := T(N(N(N(1, 2), 3), N(4, 5))) 186 187 expectRemove(t11, 4, "((1 2) (3 5))", 2) 188 expectRemove(t11, 3, "((1 2) (4 5))", 1) 189 } 190 191 func TestRemove(t *testing.T) { 192 t.Parallel() 193 194 size := 10000 195 keyLen, dataLen := 16, 40 196 197 d, err := db.NewDB("test", "memdb", "") 198 require.NoError(t, err) 199 200 defer d.Close() 201 t1 := NewMutableTree(d, size) 202 203 // insert a bunch of random nodes 204 keys := make([][]byte, size) 205 l := int32(len(keys)) 206 for i := 0; i < size; i++ { 207 key := randBytes(keyLen) 208 t1.Set(key, randBytes(dataLen)) 209 keys[i] = key 210 } 211 212 for i := 0; i < 10; i++ { 213 step := 50 * i 214 // remove a bunch of existing keys (may have been deleted twice) 215 for j := 0; j < step; j++ { 216 key := keys[mrand.Int31n(l)] 217 t1.Remove(key) 218 } 219 t1.SaveVersion() 220 } 221 } 222 223 func TestIntegration(t *testing.T) { 224 t.Parallel() 225 226 type record struct { 227 key string 228 value string 229 } 230 231 records := make([]*record, 400) 232 tree := NewMutableTree(memdb.NewMemDB(), 0) 233 234 randomRecord := func() *record { 235 return &record{randstr(20), randstr(20)} 236 } 237 238 for i := range records { 239 r := randomRecord() 240 records[i] = r 241 updated := tree.Set([]byte(r.key), []byte{}) 242 if updated { 243 t.Error("should have not been updated") 244 } 245 updated = tree.Set([]byte(r.key), []byte(r.value)) 246 if !updated { 247 t.Error("should have been updated") 248 } 249 if tree.Size() != int64(i+1) { 250 t.Error("size was wrong", tree.Size(), i+1) 251 } 252 } 253 254 for _, r := range records { 255 if has := tree.Has([]byte(r.key)); !has { 256 t.Error("Missing key", r.key) 257 } 258 if has := tree.Has([]byte(randstr(12))); has { 259 t.Error("Table has extra key") 260 } 261 if _, val := tree.Get([]byte(r.key)); string(val) != r.value { 262 t.Error("wrong value") 263 } 264 } 265 266 for i, x := range records { 267 if val, removed := tree.Remove([]byte(x.key)); !removed { 268 t.Error("Wasn't removed") 269 } else if string(val) != x.value { 270 t.Error("Wrong value") 271 } 272 for _, r := range records[i+1:] { 273 if has := tree.Has([]byte(r.key)); !has { 274 t.Error("Missing key", r.key) 275 } 276 if has := tree.Has([]byte(randstr(12))); has { 277 t.Error("Table has extra key") 278 } 279 _, val := tree.Get([]byte(r.key)) 280 if string(val) != r.value { 281 t.Error("wrong value") 282 } 283 } 284 if tree.Size() != int64(len(records)-(i+1)) { 285 t.Error("size was wrong", tree.Size(), (len(records) - (i + 1))) 286 } 287 } 288 } 289 290 func TestIterateRange(t *testing.T) { 291 t.Parallel() 292 293 type record struct { 294 key string 295 value string 296 } 297 298 records := []record{ 299 {"abc", "123"}, 300 {"low", "high"}, 301 {"fan", "456"}, 302 {"foo", "a"}, 303 {"foobaz", "c"}, 304 {"good", "bye"}, 305 {"foobang", "d"}, 306 {"foobar", "b"}, 307 {"food", "e"}, 308 {"foml", "f"}, 309 } 310 keys := make([]string, len(records)) 311 for i, r := range records { 312 keys[i] = r.key 313 } 314 sort.Strings(keys) 315 316 tree := NewMutableTree(memdb.NewMemDB(), 0) 317 318 // insert all the data 319 for _, r := range records { 320 updated := tree.Set([]byte(r.key), []byte(r.value)) 321 if updated { 322 t.Error("should have not been updated") 323 } 324 } 325 // test traversing the whole node works... in order 326 viewed := []string{} 327 tree.Iterate(func(key []byte, value []byte) bool { 328 viewed = append(viewed, string(key)) 329 return false 330 }) 331 if len(viewed) != len(keys) { 332 t.Error("not the same number of keys as expected") 333 } 334 for i, v := range viewed { 335 if v != keys[i] { 336 t.Error("Keys out of order", v, keys[i]) 337 } 338 } 339 340 trav := traverser{} 341 tree.IterateRange([]byte("foo"), []byte("goo"), true, trav.view) 342 expectTraverse(t, trav, "foo", "food", 5) 343 344 trav = traverser{} 345 tree.IterateRange([]byte("aaa"), []byte("abb"), true, trav.view) 346 expectTraverse(t, trav, "", "", 0) 347 348 trav = traverser{} 349 tree.IterateRange(nil, []byte("flap"), true, trav.view) 350 expectTraverse(t, trav, "abc", "fan", 2) 351 352 trav = traverser{} 353 tree.IterateRange([]byte("foob"), nil, true, trav.view) 354 expectTraverse(t, trav, "foobang", "low", 6) 355 356 trav = traverser{} 357 tree.IterateRange([]byte("very"), nil, true, trav.view) 358 expectTraverse(t, trav, "", "", 0) 359 360 // make sure it doesn't include end 361 trav = traverser{} 362 tree.IterateRange([]byte("fooba"), []byte("food"), true, trav.view) 363 expectTraverse(t, trav, "foobang", "foobaz", 3) 364 365 // make sure backwards also works... (doesn't include end) 366 trav = traverser{} 367 tree.IterateRange([]byte("fooba"), []byte("food"), false, trav.view) 368 expectTraverse(t, trav, "foobaz", "foobang", 3) 369 370 // make sure backwards also works... 371 trav = traverser{} 372 tree.IterateRange([]byte("g"), nil, false, trav.view) 373 expectTraverse(t, trav, "low", "good", 2) 374 } 375 376 func TestPersistence(t *testing.T) { 377 t.Parallel() 378 379 db := memdb.NewMemDB() 380 381 // Create some random key value pairs 382 records := make(map[string]string) 383 for i := 0; i < 10000; i++ { 384 records[randstr(20)] = randstr(20) 385 } 386 387 // Construct some tree and save it 388 t1 := NewMutableTree(db, 0) 389 for key, value := range records { 390 t1.Set([]byte(key), []byte(value)) 391 } 392 t1.SaveVersion() 393 394 // Load a tree 395 t2 := NewMutableTree(db, 0) 396 t2.Load() 397 for key, value := range records { 398 _, t2value := t2.Get([]byte(key)) 399 if string(t2value) != value { 400 t.Fatalf("Invalid value. Expected %v, got %v", value, t2value) 401 } 402 } 403 } 404 405 func TestProof(t *testing.T) { 406 t.Parallel() 407 408 // Construct some random tree 409 db := memdb.NewMemDB() 410 tree := NewMutableTree(db, 100) 411 for i := 0; i < 10; i++ { 412 key, value := randstr(20), randstr(20) 413 tree.Set([]byte(key), []byte(value)) 414 } 415 416 // Persist the items so far 417 tree.SaveVersion() 418 419 // Add more items so it's not all persisted 420 for i := 0; i < 10; i++ { 421 key, value := randstr(20), randstr(20) 422 tree.Set([]byte(key), []byte(value)) 423 } 424 425 // Now for each item, construct a proof and verify 426 tree.Iterate(func(key []byte, value []byte) bool { 427 value2, proof, err := tree.GetWithProof(key) 428 assert.NoError(t, err) 429 assert.Equal(t, value, value2) 430 if assert.NotNil(t, proof) { 431 verifyProof(t, proof, tree.WorkingHash()) 432 } 433 return false 434 }) 435 } 436 437 func TestTreeProof(t *testing.T) { 438 t.Parallel() 439 440 db := memdb.NewMemDB() 441 tree := NewMutableTree(db, 100) 442 assert.Equal(t, tree.Hash(), []byte(nil)) 443 444 // should get false for proof with nil root 445 value, proof, err := tree.GetWithProof([]byte("foo")) 446 assert.Nil(t, value) 447 assert.Nil(t, proof) 448 assert.Error(t, proof.Verify([]byte(nil))) 449 assert.NoError(t, err) 450 451 // insert lots of info and store the bytes 452 keys := make([][]byte, 200) 453 for i := 0; i < 200; i++ { 454 key := randstr(20) 455 tree.Set([]byte(key), []byte(key)) 456 keys[i] = []byte(key) 457 } 458 459 tree.SaveVersion() 460 461 // query random key fails 462 value, proof, err = tree.GetWithProof([]byte("foo")) 463 assert.Nil(t, value) 464 assert.NotNil(t, proof) 465 assert.NoError(t, err) 466 assert.NoError(t, proof.Verify(tree.Hash())) 467 assert.NoError(t, proof.VerifyAbsence([]byte("foo"))) 468 469 // valid proof for real keys 470 root := tree.WorkingHash() 471 for _, key := range keys { 472 value, proof, err := tree.GetWithProof(key) 473 if assert.NoError(t, err) { 474 require.Nil(t, err, "Failed to read proof from bytes: %v", err) 475 assert.Equal(t, key, value) 476 err := proof.Verify(root) 477 assert.NoError(t, err, "#### %v", proof.String()) 478 err = proof.VerifyItem(key, key) 479 assert.NoError(t, err, "#### %v", proof.String()) 480 } 481 } 482 }