github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/bft/abci/example/kvstore/kvstore_test.go (about) 1 package kvstore 2 3 import ( 4 "sort" 5 "testing" 6 7 "github.com/stretchr/testify/require" 8 9 abci "github.com/gnolang/gno/tm2/pkg/bft/abci/types" 10 ) 11 12 const ( 13 testKey = "abc" 14 testValue = "def" 15 ) 16 17 func testKVStore(t *testing.T, app abci.Application, tx []byte, key, value string) { 18 t.Helper() 19 20 req := abci.RequestDeliverTx{Tx: tx} 21 ar := app.DeliverTx(req) 22 require.False(t, ar.IsErr(), ar) 23 // repeating tx doesn't raise error 24 ar = app.DeliverTx(req) 25 require.False(t, ar.IsErr(), ar) 26 27 // make sure query is fine 28 resQuery := app.Query(abci.RequestQuery{ 29 Path: "/store", 30 Data: []byte(key), 31 }) 32 require.Equal(t, nil, resQuery.Error) 33 require.Equal(t, value, string(resQuery.Value)) 34 35 // make sure proof is fine 36 resQuery = app.Query(abci.RequestQuery{ 37 Path: "/store", 38 Data: []byte(key), 39 Prove: true, 40 }) 41 require.EqualValues(t, nil, resQuery.Error) 42 require.Equal(t, value, string(resQuery.Value)) 43 } 44 45 func TestKVStoreKV(t *testing.T) { 46 kvstore := NewKVStoreApplication() 47 key := testKey 48 value := key 49 tx := []byte(key) 50 testKVStore(t, kvstore, tx, key, value) 51 52 value = testValue 53 tx = []byte(key + "=" + value) 54 testKVStore(t, kvstore, tx, key, value) 55 } 56 57 func TestPersistentKVStoreKV(t *testing.T) { 58 kvstore := NewPersistentKVStoreApplication(t.TempDir()) 59 key := testKey 60 value := key 61 tx := []byte(key) 62 testKVStore(t, kvstore, tx, key, value) 63 64 value = testValue 65 tx = []byte(key + "=" + value) 66 testKVStore(t, kvstore, tx, key, value) 67 } 68 69 func TestPersistentKVStoreInfo(t *testing.T) { 70 kvstore := NewPersistentKVStoreApplication(t.TempDir()) 71 InitKVStore(kvstore) 72 height := int64(0) 73 74 resInfo := kvstore.Info(abci.RequestInfo{}) 75 if resInfo.LastBlockHeight != height { 76 t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight) 77 } 78 79 // make and apply block 80 height = int64(1) 81 hash := []byte("foo") 82 header := abci.MockHeader{ 83 Height: height, 84 } 85 kvstore.BeginBlock(abci.RequestBeginBlock{Hash: hash, Header: header}) 86 kvstore.EndBlock(abci.RequestEndBlock{Height: header.Height}) 87 kvstore.Commit() 88 89 resInfo = kvstore.Info(abci.RequestInfo{}) 90 if resInfo.LastBlockHeight != height { 91 t.Fatalf("expected height of %d, got %d", height, resInfo.LastBlockHeight) 92 } 93 } 94 95 // add a validator, remove a validator, update a validator 96 func TestValUpdates(t *testing.T) { 97 dir := t.TempDir() 98 kvstore := NewPersistentKVStoreApplication(dir) 99 100 // init with some validators 101 total := 10 102 nInit := 5 103 vals := RandVals(total) 104 // initialize with the first nInit 105 kvstore.InitChain(abci.RequestInitChain{ 106 Validators: vals[:nInit], 107 }) 108 109 vals1, vals2 := vals[:nInit], kvstore.Validators() 110 valsEqual(t, vals1, vals2) 111 112 var v1, v2, v3 abci.ValidatorUpdate 113 114 // add some validators 115 v1, v2 = vals[nInit], vals[nInit+1] 116 diff := []abci.ValidatorUpdate{v1, v2} 117 tx1 := MakeValSetChangeTx(v1.PubKey, v1.Power) 118 tx2 := MakeValSetChangeTx(v2.PubKey, v2.Power) 119 120 makeApplyBlock(t, kvstore, 1, diff, tx1, tx2) 121 122 vals1, vals2 = vals[:nInit+2], kvstore.Validators() 123 valsEqual(t, vals1, vals2) 124 125 // remove some validators 126 v1, v2, v3 = vals[nInit-2], vals[nInit-1], vals[nInit] 127 v1.Power = 0 128 v2.Power = 0 129 v3.Power = 0 130 diff = []abci.ValidatorUpdate{v1, v2, v3} 131 tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power) 132 tx2 = MakeValSetChangeTx(v2.PubKey, v2.Power) 133 tx3 := MakeValSetChangeTx(v3.PubKey, v3.Power) 134 135 makeApplyBlock(t, kvstore, 2, diff, tx1, tx2, tx3) 136 137 vals1 = append(vals[:nInit-2], vals[nInit+1]) //nolint: gocritic 138 vals2 = kvstore.Validators() 139 valsEqual(t, vals1, vals2) 140 141 // update some validators 142 v1 = vals[0] 143 if v1.Power == 5 { 144 v1.Power = 6 145 } else { 146 v1.Power = 5 147 } 148 diff = []abci.ValidatorUpdate{v1} 149 tx1 = MakeValSetChangeTx(v1.PubKey, v1.Power) 150 151 makeApplyBlock(t, kvstore, 3, diff, tx1) 152 153 vals1 = append([]abci.ValidatorUpdate{v1}, vals1[1:]...) 154 vals2 = kvstore.Validators() 155 valsEqual(t, vals1, vals2) 156 } 157 158 func makeApplyBlock(t *testing.T, kvstore abci.Application, heightInt int, diff []abci.ValidatorUpdate, txs ...[]byte) { 159 t.Helper() 160 161 // make and apply block 162 height := int64(heightInt) 163 hash := []byte("foo") 164 header := abci.MockHeader{ 165 Height: height, 166 } 167 kvstore.BeginBlock(abci.RequestBeginBlock{Hash: hash, Header: header}) 168 for _, tx := range txs { 169 if r := kvstore.DeliverTx(abci.RequestDeliverTx{Tx: tx}); r.IsErr() { 170 t.Fatal(r) 171 } 172 } 173 resEndBlock := kvstore.EndBlock(abci.RequestEndBlock{Height: header.Height}) 174 kvstore.Commit() 175 176 valsEqual(t, diff, resEndBlock.ValidatorUpdates) 177 } 178 179 // order doesn't matter 180 func valsEqual(t *testing.T, vals1, vals2 []abci.ValidatorUpdate) { 181 t.Helper() 182 183 if len(vals1) != len(vals2) { 184 t.Fatalf("vals dont match in len. got %d, expected %d", len(vals2), len(vals1)) 185 } 186 sort.Sort(abci.ValidatorUpdates(vals1)) 187 sort.Sort(abci.ValidatorUpdates(vals2)) 188 for i, v1 := range vals1 { 189 v2 := vals2[i] 190 if !v1.PubKey.Equals(v2.PubKey) || 191 v1.Power != v2.Power { 192 t.Fatalf("vals dont match at index %d. got %X/%d , expected %X/%d", i, v2.PubKey, v2.Power, v1.PubKey, v1.Power) 193 } 194 } 195 }