From 55c3880b2e9821508d593c8453fd2ed4e52d02a6 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 20 Mar 2024 16:31:57 +0100 Subject: [PATCH] test(kvstore): enforce version to be equal to height --- abci/example/example_test.go | 9 ++++++-- abci/example/kvstore/kvstore.go | 29 +++++++++++++++++++++++--- abci/example/kvstore/kvstore_test.go | 31 +++++++++++++++++----------- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/abci/example/example_test.go b/abci/example/example_test.go index 07d0bf5135..d5541d3a91 100644 --- a/abci/example/example_test.go +++ b/abci/example/example_test.go @@ -20,6 +20,7 @@ import ( "github.com/dashpay/tenderdash/abci/types" "github.com/dashpay/tenderdash/libs/log" tmnet "github.com/dashpay/tenderdash/libs/net" + "github.com/dashpay/tenderdash/proto/tendermint/version" ) func TestKVStore(t *testing.T) { @@ -28,7 +29,7 @@ func TestKVStore(t *testing.T) { logger := log.NewNopLogger() t.Log("### Testing KVStore") - app, err := kvstore.NewMemoryApp(kvstore.WithLogger(logger)) + app, err := kvstore.NewMemoryApp(kvstore.WithLogger(logger), kvstore.WithEnforceVersionToHeight()) require.NoError(t, err) testBulk(ctx, t, logger, app) } @@ -73,7 +74,11 @@ func testBulk(ctx context.Context, t *testing.T, logger log.Logger, app types.Ap require.NoError(t, err) // Construct request - rpp := &types.RequestProcessProposal{Height: 1, Txs: make([][]byte, numDeliverTxs)} + rpp := &types.RequestProcessProposal{ + Height: 1, + Txs: make([][]byte, numDeliverTxs), + Version: &version.Consensus{App: 1}, + } for counter := 0; counter < numDeliverTxs; counter++ { rpp.Txs[counter] = []byte("test") } diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index ab04ac3c71..a248e05198 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -27,7 +27,9 @@ import ( "github.com/dashpay/tenderdash/version" ) -const ProtocolVersion uint64 = 0x12345678 +// ProtocolVersion defines initial protocol (app) version. +// App version is incremented on every block, to match current height. +const ProtocolVersion uint64 = 1 //--------------------------------------------------- @@ -85,6 +87,8 @@ type Application struct { offerSnapshot *offerSnapshot shouldCommitVerify bool + // shouldEnforceVersionToHeight set to true will cause the application to enforce the app version to be equal to the height + shouldEnforceVersionToHeight bool } // WithCommitVerification enables commit verification @@ -95,6 +99,15 @@ func WithCommitVerification() OptFunc { } } +// WithEnforceVersionToHeight enables the application to enforce the app version to be equal to the height using app_version +// field in the RequestPrepareProposal +func WithEnforceVersionToHeight() OptFunc { + return func(app *Application) error { + app.shouldEnforceVersionToHeight = true + return nil + } +} + // WithValidatorSetUpdates defines initial validator set when creating Application func WithValidatorSetUpdates(validatorSetUpdates map[int64]abci.ValidatorSetUpdate) OptFunc { return func(app *Application) error { @@ -287,7 +300,7 @@ func (app *Application) InitChain(_ context.Context, req *abci.RequestInitChain) if !ok { consensusParams = types1.ConsensusParams{ Version: &types1.VersionParams{ - AppVersion: ProtocolVersion, + AppVersion: uint64(app.LastCommittedState.GetHeight()) + 1, }, } } @@ -346,6 +359,7 @@ func (app *Application) PrepareProposal(_ context.Context, req *abci.RequestPrep ConsensusParamUpdates: app.getConsensusParamsUpdate(req.Height), CoreChainLockUpdate: coreChainLock, ValidatorSetUpdate: app.getValidatorSetUpdate(req.Height), + XAppVersion: &abci.ResponsePrepareProposal_AppVersion{AppVersion: uint64(roundState.GetHeight())}, } if app.cfg.PrepareProposalDelayMS != 0 { @@ -373,6 +387,15 @@ func (app *Application) ProcessProposal(_ context.Context, req *abci.RequestProc Status: abci.ResponseProcessProposal_REJECT, }, err } + + if req.Version.App != uint64(roundState.GetHeight()) { + app.logger.Error("app version mismatch, kvstore expects it to be equal to the current height", + "version", req.Version, "height", roundState.GetHeight()) + return &abci.ResponseProcessProposal{ + Status: abci.ResponseProcessProposal_REJECT, + }, nil + } + resp := &abci.ResponseProcessProposal{ Status: abci.ResponseProcessProposal_ACCEPT, AppHash: roundState.GetAppHash(), @@ -584,7 +607,7 @@ func (app *Application) Info(_ context.Context, req *abci.RequestInfo) (*abci.Re resp := &abci.ResponseInfo{ Data: fmt.Sprintf("{\"appHash\":\"%s\"}", appHash.String()), Version: version.ABCIVersion, - AppVersion: ProtocolVersion, + AppVersion: uint64(app.LastCommittedState.GetHeight()) + 1, // we set app version to CURRENT height LastBlockHeight: app.LastCommittedState.GetHeight(), LastBlockAppHash: app.LastCommittedState.GetAppHash(), } diff --git a/abci/example/kvstore/kvstore_test.go b/abci/example/kvstore/kvstore_test.go index 66274fe414..f70f2c95b6 100644 --- a/abci/example/kvstore/kvstore_test.go +++ b/abci/example/kvstore/kvstore_test.go @@ -21,6 +21,7 @@ import ( "github.com/dashpay/tenderdash/libs/log" "github.com/dashpay/tenderdash/libs/service" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" + pbversion "github.com/dashpay/tenderdash/proto/tendermint/version" tmtypes "github.com/dashpay/tenderdash/types" "github.com/dashpay/tenderdash/version" ) @@ -48,8 +49,9 @@ func testKVStore(ctx context.Context, t *testing.T, app types.Application, tx [] require.ErrorContains(t, err, "duplicate PrepareProposal call") reqProcess := &types.RequestProcessProposal{ - Txs: [][]byte{tx}, - Height: height, + Txs: [][]byte{tx}, + Height: height, + Version: &pbversion.Consensus{App: uint64(height)}, } respProcess, err := app.ProcessProposal(ctx, reqProcess) require.NoError(t, err) @@ -241,7 +243,7 @@ func TestValUpdates(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - kvstore, err := NewMemoryApp() + kvstore, err := NewMemoryApp(WithEnforceVersionToHeight()) require.NoError(t, err) // init with some validators @@ -283,9 +285,10 @@ func makeApplyBlock( } respProcessProposal, err := kvstore.ProcessProposal(ctx, &types.RequestProcessProposal{ - Hash: hash, - Height: height, - Txs: txs, + Hash: hash, + Height: height, + Txs: txs, + Version: &pbversion.Consensus{App: uint64(height)}, }) require.NoError(t, err) require.NotZero(t, respProcessProposal) @@ -368,7 +371,9 @@ func TestClientServer(t *testing.T) { logger := log.NewTestingLogger(t) // set up socket app - kvstore, err := NewMemoryApp(WithLogger(logger.With("module", "app"))) + kvstore, err := NewMemoryApp( + WithLogger(logger.With("module", "app")), + WithEnforceVersionToHeight()) require.NoError(t, err) client, server, err := makeSocketClientServer(ctx, t, logger, kvstore, "kvstore-socket") @@ -406,8 +411,9 @@ func runClientTests(ctx context.Context, t *testing.T, client abciclient.Client) func testClient(ctx context.Context, t *testing.T, app abciclient.Client, height int64, tx []byte, key, value string) { rpp, err := app.ProcessProposal(ctx, &types.RequestProcessProposal{ - Txs: [][]byte{tx}, - Height: height, + Txs: [][]byte{tx}, + Height: height, + Version: &pbversion.Consensus{App: uint64(height)}, }) require.NoError(t, err) require.NotZero(t, rpp) @@ -522,6 +528,7 @@ func newKvApp(ctx context.Context, t *testing.T, genesisHeight int64, opts ...Op WithValidatorSetUpdates(map[int64]types.ValidatorSetUpdate{ genesisHeight: RandValidatorSetUpdate(1), }), + WithEnforceVersionToHeight(), } app, err := NewMemoryApp(append(defaultOpts, opts...)...) require.NoError(t, err) @@ -536,17 +543,17 @@ func newKvApp(ctx context.Context, t *testing.T, genesisHeight int64, opts ...Op return app } -func assertRespInfo(t *testing.T, expectHeight int64, expectAppHash tmbytes.HexBytes, actual types.ResponseInfo, msgs ...interface{}) { +func assertRespInfo(t *testing.T, expectLastBlockHeight int64, expectAppHash tmbytes.HexBytes, actual types.ResponseInfo, msgs ...interface{}) { t.Helper() if expectAppHash == nil { expectAppHash = make(tmbytes.HexBytes, tmcrypto.DefaultAppHashSize) } expected := types.ResponseInfo{ - LastBlockHeight: expectHeight, + LastBlockHeight: expectLastBlockHeight, LastBlockAppHash: expectAppHash, Version: version.ABCIVersion, - AppVersion: ProtocolVersion, + AppVersion: uint64(expectLastBlockHeight + 1), Data: fmt.Sprintf(`{"appHash":"%s"}`, expectAppHash.String()), }