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 }