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  }