github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/mpt/store_test.go (about)

     1  package mpt
     2  
     3  import (
     4  	"crypto/rand"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"testing"
     9  
    10  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags"
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types"
    12  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    13  	"github.com/spf13/viper"
    14  	"github.com/stretchr/testify/suite"
    15  )
    16  
    17  var (
    18  	commonKeys   = []string{"key1", "key2", "key3", "key4", "key5"}
    19  	commonValues = []string{"value1", "value2", "value3", "value4", "value5"}
    20  
    21  	randKeyNum = 1000
    22  )
    23  
    24  func randBytes(numBytes int) []byte {
    25  	b := make([]byte, numBytes)
    26  	_, _ = rand.Read(b)
    27  	return b
    28  }
    29  
    30  type StoreTestSuite struct {
    31  	suite.Suite
    32  
    33  	mptStore *MptStore
    34  }
    35  
    36  func TestStoreTestSuite(t *testing.T) {
    37  	suite.Run(t, new(StoreTestSuite))
    38  }
    39  
    40  func (suite *StoreTestSuite) SetupTest() {
    41  	// set fbchaind path
    42  	serverDir, err := ioutil.TempDir("", ".fbchaind")
    43  	if err != nil {
    44  		panic(err)
    45  	}
    46  	defer os.RemoveAll(serverDir)
    47  	viper.Set(flags.FlagHome, serverDir)
    48  
    49  	mptStore, err := mockMptStore(nil, types.CommitID{})
    50  	if err != nil {
    51  		panic(err)
    52  	}
    53  	for _, key := range commonKeys {
    54  		mptStore.Set([]byte(key), []byte(commonValues[0]))
    55  	}
    56  	for i := 0; i < randKeyNum; i++ {
    57  		key := randBytes(12)
    58  		value := randBytes(32)
    59  		mptStore.Set(key, value)
    60  	}
    61  	mptStore.CommitterCommit(nil)
    62  
    63  	suite.mptStore = mptStore
    64  }
    65  
    66  func (suite *StoreTestSuite) TestLoadStore() {
    67  	store := suite.mptStore
    68  	key := []byte(commonKeys[0])
    69  
    70  	// Create non-pruned height H
    71  	valueH := randBytes(32)
    72  	store.Set(key, valueH)
    73  	cIDH, _ := store.CommitterCommit(nil)
    74  
    75  	// Create pruned height Hp
    76  	valueHp := randBytes(32)
    77  	store.Set(key, valueHp)
    78  	cIDHp, _ := store.CommitterCommit(nil)
    79  
    80  	// Create current height Hc
    81  	valueHc := randBytes(32)
    82  	store.Set(key, valueHc)
    83  	cIDHc, _ := store.CommitterCommit(nil)
    84  
    85  	// Querying an existing store at some previous non-pruned height H
    86  	hStore, err := store.GetImmutable(cIDH.Version)
    87  	suite.Require().NoError(err)
    88  	suite.Require().Equal(hStore.Get(key), valueH)
    89  
    90  	// Querying an existing store at some previous pruned height Hp
    91  	hpStore, err := store.GetImmutable(cIDHp.Version)
    92  	suite.Require().NoError(err)
    93  	suite.Require().Equal(hpStore.Get(key), valueHp)
    94  
    95  	// Querying an existing store at current height Hc
    96  	hcStore, err := store.GetImmutable(cIDHc.Version)
    97  	suite.Require().NoError(err)
    98  	suite.Require().Equal(hcStore.Get(key), valueHc)
    99  }
   100  
   101  func (suite *StoreTestSuite) TestMPTStoreGetSetHasDelete() {
   102  	store := suite.mptStore
   103  	key, originValue := commonKeys[0], commonValues[0]
   104  
   105  	exists := store.Has([]byte(key))
   106  	suite.Require().True(exists)
   107  
   108  	value := store.Get([]byte(key))
   109  	suite.Require().EqualValues(value, originValue)
   110  
   111  	value2 := "notgoodbye"
   112  	store.Set([]byte(key), []byte(value2))
   113  
   114  	value = store.Get([]byte(key))
   115  	suite.Require().EqualValues(value, value2)
   116  
   117  	store.Delete([]byte(key))
   118  	exists = store.Has([]byte(key))
   119  	suite.Require().False(exists)
   120  }
   121  
   122  func (suite *StoreTestSuite) TestMPTStoreNoNilSet() {
   123  	store := suite.mptStore
   124  	suite.Require().Panics(func() { store.Set([]byte("key"), nil) }, "setting a nil value should panic")
   125  }
   126  
   127  func (suite *StoreTestSuite) TestGetImmutable() {
   128  	store := suite.mptStore
   129  	key := []byte(commonKeys[0])
   130  	oldValue := store.Get(key)
   131  
   132  	newValue := randBytes(32)
   133  	store.Set(key, newValue)
   134  	cID, _ := store.CommitterCommit(nil)
   135  
   136  	_, err := store.GetImmutable(cID.Version + 1)
   137  	suite.Require().NoError(err)
   138  
   139  	oldStore, err := store.GetImmutable(cID.Version - 1)
   140  	suite.Require().NoError(err)
   141  	suite.Require().Equal(oldStore.Get(key), oldValue)
   142  
   143  	curStore, err := store.GetImmutable(cID.Version)
   144  	suite.Require().NoError(err)
   145  	suite.Require().Equal(curStore.Get(key), newValue)
   146  
   147  	res := curStore.Query(abci.RequestQuery{Data: key, Height: cID.Version, Path: "/key", Prove: true})
   148  	suite.Require().Equal(res.Value, newValue)
   149  	suite.Require().NotNil(res.Proof)
   150  
   151  	suite.Require().Panics(func() { curStore.Set(nil, nil) })
   152  	suite.Require().NotPanics(func() { curStore.Delete(nil) })
   153  	suite.Require().Panics(func() { curStore.CommitterCommit(nil) })
   154  }
   155  
   156  func (suite *StoreTestSuite) TestTestIterator() {
   157  	store := suite.mptStore
   158  	iter := store.Iterator(nil, nil)
   159  	i := 0
   160  	for ; iter.Valid(); iter.Next() {
   161  		suite.Require().NotNil(iter.Key())
   162  		suite.Require().NotNil(iter.Value())
   163  		i++
   164  	}
   165  
   166  	suite.Require().Equal(len(commonKeys)+randKeyNum, i)
   167  }
   168  
   169  func nextVersion(iStore *MptStore) {
   170  	key := []byte(fmt.Sprintf("Key for tree: %d", iStore.LastCommitID().Version))
   171  	value := []byte(fmt.Sprintf("Value for tree: %d", iStore.LastCommitID().Version))
   172  	iStore.Set(key, value)
   173  	iStore.CommitterCommit(nil)
   174  }
   175  
   176  func (suite *StoreTestSuite) TestMPTNoPrune() {
   177  	store := suite.mptStore
   178  	nextVersion(store)
   179  
   180  	for i := 1; i < 100; i++ {
   181  		for j := 1; j <= i; j++ {
   182  			rootHash := store.GetMptRootHash(uint64(j))
   183  			suite.Require().NotEqual(NilHash, rootHash)
   184  			tire, err := store.db.OpenTrie(rootHash)
   185  			suite.Require().NoError(err)
   186  			suite.Require().NotEqual(EmptyCodeHash, tire.Hash())
   187  		}
   188  
   189  		nextVersion(store)
   190  	}
   191  }
   192  
   193  func (suite *StoreTestSuite) TestMPTStoreQuery() {
   194  	store := suite.mptStore
   195  
   196  	k1, v1 := []byte(commonKeys[0]), []byte(commonValues[0])
   197  	k2, v2 := []byte(commonKeys[1]), []byte(commonValues[1])
   198  	v3 := []byte(commonValues[2])
   199  
   200  	cid, _ := store.CommitterCommit(nil)
   201  	ver := cid.Version
   202  	query := abci.RequestQuery{Path: "/key", Data: k1, Height: ver}
   203  	querySub := abci.RequestQuery{Path: "/subspace", Data: []byte("key"), Height: ver}
   204  
   205  	// query subspace before anything set
   206  	qres := store.Query(querySub)
   207  	suite.Require().NotEqual(uint32(0), qres.Code)
   208  
   209  	// set data
   210  	store.Set(k1, v1)
   211  	store.Set(k2, v2)
   212  
   213  	// query data without commit
   214  	qres = store.Query(query)
   215  	suite.Require().Equal(uint32(0), qres.Code)
   216  	suite.Require().Equal(v1, qres.Value)
   217  
   218  	// commit it, but still don't see on old version
   219  	cid, _ = store.CommitterCommit(nil)
   220  	qres = store.Query(query)
   221  	suite.Require().Equal(uint32(0), qres.Code)
   222  	suite.Require().Equal(v1, qres.Value)
   223  
   224  	// but yes on the new version
   225  	query.Height = cid.Version
   226  	qres = store.Query(query)
   227  	suite.Require().Equal(uint32(0), qres.Code)
   228  	suite.Require().Equal(v1, qres.Value)
   229  
   230  	// modify
   231  	store.Set(k1, v3)
   232  	cid, _ = store.CommitterCommit(nil)
   233  
   234  	// query will return old values, as height is fixed
   235  	qres = store.Query(query)
   236  	suite.Require().Equal(uint32(0), qres.Code)
   237  	suite.Require().Equal(v1, qres.Value)
   238  
   239  	// update to latest in the query and we are happy
   240  	query.Height = cid.Version
   241  	qres = store.Query(query)
   242  	suite.Require().Equal(uint32(0), qres.Code)
   243  	suite.Require().Equal(v3, qres.Value)
   244  	query2 := abci.RequestQuery{Path: "/key", Data: k2, Height: cid.Version}
   245  
   246  	qres = store.Query(query2)
   247  	suite.Require().Equal(uint32(0), qres.Code)
   248  	suite.Require().Equal(v2, qres.Value)
   249  
   250  	// default (height 0) will show latest
   251  	query0 := abci.RequestQuery{Path: "/key", Data: k1}
   252  	qres = store.Query(query0)
   253  	suite.Require().Equal(uint32(0), qres.Code)
   254  	suite.Require().Equal(v3, qres.Value)
   255  }