github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/nodedb_test.go (about)

     1  package iavl
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"math/rand"
     7  	"strconv"
     8  	"testing"
     9  
    10  	"github.com/fibonacci-chain/fbc/libs/iavl/mock"
    11  	db "github.com/fibonacci-chain/fbc/libs/tm-db"
    12  	"github.com/golang/mock/gomock"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func BenchmarkNodeKey(b *testing.B) {
    17  	ndb := &nodeDB{}
    18  	hashes := makeHashes(b, 2432325)
    19  	for i := 0; i < b.N; i++ {
    20  		ndb.nodeKey(hashes[i])
    21  	}
    22  }
    23  
    24  func BenchmarkOrphanKey(b *testing.B) {
    25  	ndb := &nodeDB{}
    26  	hashes := makeHashes(b, 2432325)
    27  	for i := 0; i < b.N; i++ {
    28  		ndb.orphanKey(1234, 1239, hashes[i])
    29  	}
    30  }
    31  
    32  func makeHashes(b *testing.B, seed int64) [][]byte {
    33  	b.StopTimer()
    34  	rnd := rand.NewSource(seed)
    35  	hashes := make([][]byte, b.N)
    36  	hashBytes := 8 * ((hashSize + 7) / 8)
    37  	for i := 0; i < b.N; i++ {
    38  		hashes[i] = make([]byte, hashBytes)
    39  		for b := 0; b < hashBytes; b += 8 {
    40  			binary.BigEndian.PutUint64(hashes[i][b:b+8], uint64(rnd.Int63()))
    41  		}
    42  		hashes[i] = hashes[i][:hashSize]
    43  	}
    44  	b.StartTimer()
    45  	return hashes
    46  }
    47  
    48  func TestNewNoDbStorage_StorageVersionInDb_Success(t *testing.T) {
    49  	const expectedVersion = defaultStorageVersionValue
    50  
    51  	ctrl := gomock.NewController(t)
    52  	dbMock := mock.NewMockDB(ctrl)
    53  
    54  	dbMock.EXPECT().Get(gomock.Any()).Return([]byte(expectedVersion), nil).Times(1)
    55  	dbMock.EXPECT().NewBatch().Return(nil).Times(0)
    56  
    57  	ndb := newNodeDB(dbMock, 0, nil)
    58  	require.Equal(t, expectedVersion, ndb.storageVersion)
    59  }
    60  
    61  func TestNewNoDbStorage_ErrorInConstructor_DefaultSet(t *testing.T) {
    62  	const expectedVersion = defaultStorageVersionValue
    63  
    64  	ctrl := gomock.NewController(t)
    65  	dbMock := mock.NewMockDB(ctrl)
    66  
    67  	dbMock.EXPECT().Get(gomock.Any()).Return(nil, errors.New("some db error")).Times(1)
    68  	dbMock.EXPECT().NewBatch().Return(nil).Times(0)
    69  
    70  	ndb := newNodeDB(dbMock, 0, nil)
    71  	require.Equal(t, expectedVersion, ndb.getStorageVersion())
    72  }
    73  
    74  func TestNewNoDbStorage_DoesNotExist_DefaultSet(t *testing.T) {
    75  	const expectedVersion = defaultStorageVersionValue
    76  
    77  	ctrl := gomock.NewController(t)
    78  	dbMock := mock.NewMockDB(ctrl)
    79  
    80  	dbMock.EXPECT().Get(gomock.Any()).Return(nil, nil).Times(1)
    81  	dbMock.EXPECT().NewBatch().Return(nil).Times(0)
    82  
    83  	ndb := newNodeDB(dbMock, 0, nil)
    84  	require.Equal(t, expectedVersion, ndb.getStorageVersion())
    85  }
    86  
    87  func TestSetStorageVersion_Success(t *testing.T) {
    88  	const expectedVersion = fastStorageVersionValue
    89  
    90  	db := db.NewMemDB()
    91  
    92  	ndb := newNodeDB(db, 0, nil)
    93  	require.Equal(t, defaultStorageVersionValue, ndb.getStorageVersion())
    94  
    95  	batch := db.NewBatch()
    96  	err := ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion())
    97  	require.NoError(t, err)
    98  	require.Equal(t, expectedVersion+fastStorageVersionDelimiter+strconv.Itoa(int(ndb.getLatestVersion())), ndb.getStorageVersion())
    99  	require.NoError(t, batch.Write())
   100  }
   101  
   102  // TestSetStorageVersion_DBFailure_OldKept now has useless meaning.
   103  // Our `batch.Set` do not return error. so here can't work as community
   104  func TestSetStorageVersion_DBFailure_OldKept(t *testing.T) {
   105  	ctrl := gomock.NewController(t)
   106  	dbMock := mock.NewMockDB(ctrl)
   107  	batchMock := mock.NewMockBatch(ctrl)
   108  	rIterMock := mock.NewMockIterator(ctrl)
   109  
   110  	//expectedErrorMsg := "some db error"
   111  
   112  	expectedFastCacheVersion := 2
   113  
   114  	dbMock.EXPECT().Get(gomock.Any()).Return([]byte(defaultStorageVersionValue), nil).Times(1)
   115  	dbMock.EXPECT().NewBatch().Return(batchMock).Times(1)
   116  
   117  	// rIterMock is used to get the latest version from disk. We are mocking that rIterMock returns latestTreeVersion from disk
   118  	rIterMock.EXPECT().Valid().Return(true).Times(1)
   119  	rIterMock.EXPECT().Key().Return(rootKeyFormat.Key(expectedFastCacheVersion)).Times(1)
   120  	rIterMock.EXPECT().Close().Times(1)
   121  
   122  	dbMock.EXPECT().ReverseIterator(gomock.Any(), gomock.Any()).Return(rIterMock, nil).Times(1)
   123  	batchMock.EXPECT().Set(metadataKeyFormat.Key([]byte(storageVersionKey)), []byte(fastStorageVersionValue+fastStorageVersionDelimiter+strconv.Itoa(expectedFastCacheVersion))).Return().Times(1)
   124  
   125  	ndb := newNodeDB(dbMock, 0, nil)
   126  	require.Equal(t, defaultStorageVersionValue, ndb.getStorageVersion())
   127  
   128  	batch := ndb.NewBatch()
   129  	ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion())
   130  	//	err := ndb.setFastStorageVersionToBatch(batch)
   131  	//	require.Error(t, err)
   132  	///	require.Equal(t, expectedErrorMsg, err.Error())
   133  	//require.Equal(t, defaultStorageVersionValue, ndb.getStorageVersion())
   134  }
   135  
   136  func TestSetStorageVersion_InvalidVersionFailure_OldKept(t *testing.T) {
   137  	ctrl := gomock.NewController(t)
   138  	dbMock := mock.NewMockDB(ctrl)
   139  	batchMock := mock.NewMockBatch(ctrl)
   140  
   141  	expectedErrorMsg := errInvalidFastStorageVersion
   142  
   143  	invalidStorageVersion := fastStorageVersionValue + fastStorageVersionDelimiter + "1" + fastStorageVersionDelimiter + "2"
   144  
   145  	dbMock.EXPECT().Get(gomock.Any()).Return([]byte(invalidStorageVersion), nil).Times(1)
   146  	dbMock.EXPECT().NewBatch().Return(batchMock).Times(1)
   147  
   148  	ndb := newNodeDB(dbMock, 0, nil)
   149  	require.Equal(t, invalidStorageVersion, ndb.getStorageVersion())
   150  
   151  	batch := ndb.NewBatch()
   152  	invalidVersion := int64(0)
   153  	err := ndb.setFastStorageVersionToBatch(batch, invalidVersion)
   154  	require.Error(t, err)
   155  	require.Equal(t, expectedErrorMsg, err.Error())
   156  	require.Equal(t, invalidStorageVersion, ndb.getStorageVersion())
   157  }
   158  
   159  func TestSetStorageVersion_FastVersionFirst_VersionAppended(t *testing.T) {
   160  	db := db.NewMemDB()
   161  	ndb := newNodeDB(db, 0, nil)
   162  	ndb.storageVersion = fastStorageVersionValue
   163  	ndb.latestPersistedVersion = 100
   164  
   165  	batch := ndb.NewBatch()
   166  	err := ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion())
   167  	require.NoError(t, err)
   168  	require.Equal(t, fastStorageVersionValue+fastStorageVersionDelimiter+strconv.Itoa(int(ndb.latestPersistedVersion)), ndb.storageVersion)
   169  }
   170  
   171  func TestSetStorageVersion_FastVersionSecond_VersionAppended(t *testing.T) {
   172  	db := db.NewMemDB()
   173  	ndb := newNodeDB(db, 0, nil)
   174  	ndb.latestPersistedVersion = 100
   175  
   176  	storageVersionBytes := []byte(fastStorageVersionValue)
   177  	storageVersionBytes[len(fastStorageVersionValue)-1]++ // increment last byte
   178  	ndb.storageVersion = string(storageVersionBytes)
   179  
   180  	batch := ndb.NewBatch()
   181  	err := ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion())
   182  	require.NoError(t, err)
   183  	require.Equal(t, string(storageVersionBytes)+fastStorageVersionDelimiter+strconv.Itoa(int(ndb.latestPersistedVersion)), ndb.storageVersion)
   184  }
   185  
   186  func TestSetStorageVersion_SameVersionTwice(t *testing.T) {
   187  	db := db.NewMemDB()
   188  	ndb := newNodeDB(db, 0, nil)
   189  	ndb.latestPersistedVersion = 100
   190  
   191  	storageVersionBytes := []byte(fastStorageVersionValue)
   192  	storageVersionBytes[len(fastStorageVersionValue)-1]++ // increment last byte
   193  	ndb.storageVersion = string(storageVersionBytes)
   194  
   195  	batch := db.NewBatch()
   196  	err := ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion())
   197  	require.NoError(t, err)
   198  	newStorageVersion := string(storageVersionBytes) + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion))
   199  	require.Equal(t, newStorageVersion, ndb.storageVersion)
   200  
   201  	err = ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion())
   202  	require.NoError(t, err)
   203  	require.Equal(t, newStorageVersion, ndb.storageVersion)
   204  }
   205  
   206  // Test case where version is incorrect and has some extra garbage at the end
   207  func TestShouldForceFastStorageUpdate_DefaultVersion_True(t *testing.T) {
   208  	db := db.NewMemDB()
   209  	ndb := newNodeDB(db, 0, nil)
   210  	ndb.storageVersion = defaultStorageVersionValue
   211  	ndb.latestPersistedVersion = 100
   212  
   213  	require.False(t, ndb.shouldForceFastStorageUpgrade())
   214  }
   215  
   216  func TestShouldForceFastStorageUpdate_FastVersion_Greater_True(t *testing.T) {
   217  	db := db.NewMemDB()
   218  	ndb := newNodeDB(db, 0, nil)
   219  	ndb.latestPersistedVersion = 100
   220  	ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion+1))
   221  
   222  	require.True(t, ndb.shouldForceFastStorageUpgrade())
   223  }
   224  
   225  func TestShouldForceFastStorageUpdate_FastVersion_Smaller_True(t *testing.T) {
   226  	db := db.NewMemDB()
   227  	ndb := newNodeDB(db, 0, nil)
   228  	ndb.latestPersistedVersion = 100
   229  	ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion-1))
   230  
   231  	require.True(t, ndb.shouldForceFastStorageUpgrade())
   232  }
   233  
   234  func TestShouldForceFastStorageUpdate_FastVersion_Match_False(t *testing.T) {
   235  	db := db.NewMemDB()
   236  	ndb := newNodeDB(db, 0, nil)
   237  	ndb.latestPersistedVersion = 100
   238  	ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion))
   239  
   240  	require.False(t, ndb.shouldForceFastStorageUpgrade())
   241  }
   242  
   243  func TestIsFastStorageEnabled_True(t *testing.T) {
   244  	db := db.NewMemDB()
   245  	ndb := newNodeDB(db, 0, nil)
   246  	ndb.latestPersistedVersion = 100
   247  	ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion))
   248  
   249  	require.True(t, ndb.hasUpgradedToFastStorage())
   250  }
   251  
   252  func TestIsFastStorageEnabled_False(t *testing.T) {
   253  	db := db.NewMemDB()
   254  	ndb := newNodeDB(db, 0, nil)
   255  	ndb.latestPersistedVersion = 100
   256  	ndb.storageVersion = defaultStorageVersionValue
   257  
   258  	require.False(t, ndb.shouldForceFastStorageUpgrade())
   259  }
   260  
   261  func makeAndPopulateMutableTree(tb testing.TB) *MutableTree {
   262  	memDB := db.NewMemDB()
   263  	tree, err := NewMutableTreeWithOpts(memDB, 0, &Options{InitialVersion: 9})
   264  	require.NoError(tb, err)
   265  
   266  	for i := 0; i < 1e4; i++ {
   267  		buf := make([]byte, 0, (i/255)+1)
   268  		for j := 0; 1<<j <= i; j++ {
   269  			buf = append(buf, byte((i>>j)&0xff))
   270  		}
   271  		tree.Set(buf, buf)
   272  	}
   273  	_, _, _, err = tree.SaveVersion(false)
   274  	require.Nil(tb, err, "Expected .SaveVersion to succeed")
   275  	return tree
   276  }