github.com/lazyledger/lazyledger-core@v0.35.0-dev.0.20210613111200-4c651f053571/abci/example/kvstore/kvstore_test.go (about)

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