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  }