From 704d4d33dc86f8dc4b3a5ecc66f8fdb62804beb6 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 11:34:48 -0300 Subject: [PATCH 01/13] fix: use deliverState in prepare and processProposal at height 1 --- baseapp/abci.go | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index e704c386facc..4cc8d46a2297 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -248,11 +248,23 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/tendermint/tendermint/blob/main/spec/abci/abci%2B%2B_basic_concepts.md func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci.ResponsePrepareProposal) { - ctx := app.getContextForTx(runTxPrepareProposal, []byte{}) if app.prepareProposal == nil { panic("PrepareProposal method not set") } + ctx := app.prepareProposalState.ctx + // Here we use deliverState on the first block given that we want to be able + // to access any state changes made in InitChain. + if req.Height == 1 { + ctx = app.deliverState.ctx + } + + ctx = ctx.WithVoteInfos(app.voteInfos). + WithBlockHeight(req.Height). + WithBlockTime(req.Time). + WithProposer(req.ProposerAddress). + WithConsensusParams(app.GetConsensusParams(ctx)) + defer func() { if err := recover(); err != nil { app.logger.Error( @@ -289,13 +301,20 @@ func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) (resp abci. panic("app.ProcessProposal is not set") } - ctx := app.processProposalState.ctx. + ctx := app.processProposalState.ctx + // Here we use deliverState on the first block given that we want to be able + // to access any state changes made in InitChain. + if req.Height == 1 { + ctx = app.deliverState.ctx + } + + ctx = ctx. WithVoteInfos(app.voteInfos). WithBlockHeight(req.Height). WithBlockTime(req.Time). WithHeaderHash(req.Hash). WithProposer(req.ProposerAddress). - WithConsensusParams(app.GetConsensusParams(app.processProposalState.ctx)) + WithConsensusParams(app.GetConsensusParams(ctx)) defer func() { if err := recover(); err != nil { From c0d666c09cb73e50ae1a7b5203d40cc9ea1d3517 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 12:58:24 -0300 Subject: [PATCH 02/13] cache deliverState --- baseapp/abci.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index 4cc8d46a2297..0e4a8a523e1f 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -256,7 +256,7 @@ func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci. // Here we use deliverState on the first block given that we want to be able // to access any state changes made in InitChain. if req.Height == 1 { - ctx = app.deliverState.ctx + ctx, _ = app.deliverState.ctx.CacheContext() } ctx = ctx.WithVoteInfos(app.voteInfos). @@ -305,7 +305,7 @@ func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) (resp abci. // Here we use deliverState on the first block given that we want to be able // to access any state changes made in InitChain. if req.Height == 1 { - ctx = app.deliverState.ctx + ctx, _ = app.deliverState.ctx.CacheContext() } ctx = ctx. From 2d80482a2f63bc1898fb128a007429f36395a3f1 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 13:15:42 -0300 Subject: [PATCH 03/13] add test + add panic if prepareProposal gets called with height=0 --- baseapp/abci.go | 6 +++++ baseapp/abci_test.go | 60 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index 0e4a8a523e1f..fd3f21c992fe 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -252,6 +252,12 @@ func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci. panic("PrepareProposal method not set") } + // Tendermint must never call PrepareProposal with a height of 0. + // TODO: Link to a doc stating this. + if req.Height < 1 { + panic("PrepareProposal called with invalid height") + } + ctx := app.prepareProposalState.ctx // Here we use deliverState on the first block given that we want to be able // to access any state changes made in InitChain. diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 460c9c6cb16f..be105b75fe6c 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -10,6 +10,7 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/jsonpb" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -1323,10 +1324,6 @@ func TestABCI_Proposal_HappyPath(t *testing.T) { ConsensusParams: &tmproto.ConsensusParams{}, }) - suite.baseApp.BeginBlock(abci.RequestBeginBlock{ - Header: tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}, - }) - tx := newTxCounter(t, suite.txConfig, 0, 1) txBytes, err := suite.txConfig.TxEncoder()(tx) require.NoError(t, err) @@ -1347,6 +1344,7 @@ func TestABCI_Proposal_HappyPath(t *testing.T) { reqPrepareProposal := abci.RequestPrepareProposal{ MaxTxBytes: 1000, + Height: 1, } resPrepareProposal := suite.baseApp.PrepareProposal(reqPrepareProposal) require.Equal(t, 2, len(resPrepareProposal.Txs)) @@ -1362,6 +1360,10 @@ func TestABCI_Proposal_HappyPath(t *testing.T) { resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) require.Equal(t, abci.ResponseProcessProposal_ACCEPT, resProcessProposal.Status) + suite.baseApp.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}, + }) + res := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) require.Equal(t, 1, pool.CountTx()) @@ -1369,6 +1371,52 @@ func TestABCI_Proposal_HappyPath(t *testing.T) { require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) } +func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { + someKey := []byte("some-key") + + setInitChainerOpt := func(bapp *baseapp.BaseApp) { + bapp.SetInitChainer(func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + ctx.KVStore(capKey1).Set(someKey, []byte("foo")) + return abci.ResponseInitChain{} + }) + } + + prepareOpt := func(bapp *baseapp.BaseApp) { + bapp.SetPrepareProposal(func(ctx sdk.Context, req types.RequestPrepareProposal) types.ResponsePrepareProposal { + value := ctx.KVStore(capKey1).Get(someKey) + // We should be able to access any state written in InitChain + require.Equal(t, "foo", string(value)) + return abci.ResponsePrepareProposal{Txs: req.Txs} + }) + } + + suite := NewBaseAppSuite(t, setInitChainerOpt, prepareOpt) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + reqPrepareProposal := abci.RequestPrepareProposal{ + MaxTxBytes: 1000, + Height: 1, // this value can't be 0 + } + resPrepareProposal := suite.baseApp.PrepareProposal(reqPrepareProposal) + require.Equal(t, 0, len(resPrepareProposal.Txs)) + + reqProposalTxBytes := [][]byte{} + reqProcessProposal := abci.RequestProcessProposal{ + Txs: reqProposalTxBytes[:], + } + + resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) + require.Equal(t, abci.ResponseProcessProposal_ACCEPT, resProcessProposal.Status) + + suite.baseApp.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}, + }) + +} + func TestABCI_PrepareProposal_ReachedMaxBytes(t *testing.T) { anteKey := []byte("ante-key") pool := mempool.NewSenderNonceMempool() @@ -1389,6 +1437,7 @@ func TestABCI_PrepareProposal_ReachedMaxBytes(t *testing.T) { reqPrepareProposal := abci.RequestPrepareProposal{ MaxTxBytes: 1500, + Height: 1, } resPrepareProposal := suite.baseApp.PrepareProposal(reqPrepareProposal) require.Equal(t, 10, len(resPrepareProposal.Txs)) @@ -1412,6 +1461,7 @@ func TestABCI_PrepareProposal_BadEncoding(t *testing.T) { reqPrepareProposal := abci.RequestPrepareProposal{ MaxTxBytes: 1000, + Height: 1, } resPrepareProposal := suite.baseApp.PrepareProposal(reqPrepareProposal) require.Equal(t, 1, len(resPrepareProposal.Txs)) @@ -1449,6 +1499,7 @@ func TestABCI_PrepareProposal_Failures(t *testing.T) { req := abci.RequestPrepareProposal{ MaxTxBytes: 1000, + Height: 1, } res := suite.baseApp.PrepareProposal(req) require.Equal(t, 1, len(res.Txs)) @@ -1468,6 +1519,7 @@ func TestABCI_PrepareProposal_PanicRecovery(t *testing.T) { req := abci.RequestPrepareProposal{ MaxTxBytes: 1000, + Height: 1, } require.NotPanics(t, func() { From 18e8dafe53f8b110d5f7e0d7a352efc92e92b1d9 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 13:39:46 -0300 Subject: [PATCH 04/13] make the linter happy --- baseapp/abci_test.go | 6 ++--- simapp/app_v2.go | 63 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index be105b75fe6c..3675c3ea2046 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -10,7 +10,6 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/jsonpb" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -1382,7 +1381,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { } prepareOpt := func(bapp *baseapp.BaseApp) { - bapp.SetPrepareProposal(func(ctx sdk.Context, req types.RequestPrepareProposal) types.ResponsePrepareProposal { + bapp.SetPrepareProposal(func(ctx sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { value := ctx.KVStore(capKey1).Get(someKey) // We should be able to access any state written in InitChain require.Equal(t, "foo", string(value)) @@ -1405,7 +1404,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { reqProposalTxBytes := [][]byte{} reqProcessProposal := abci.RequestProcessProposal{ - Txs: reqProposalTxBytes[:], + Txs: reqProposalTxBytes, } resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) @@ -1414,7 +1413,6 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { suite.baseApp.BeginBlock(abci.RequestBeginBlock{ Header: tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}, }) - } func TestABCI_PrepareProposal_ReachedMaxBytes(t *testing.T) { diff --git a/simapp/app_v2.go b/simapp/app_v2.go index 40af6b81f2c2..81b8b0f0f542 100644 --- a/simapp/app_v2.go +++ b/simapp/app_v2.go @@ -4,11 +4,14 @@ package simapp import ( _ "embed" + "errors" + "fmt" "io" "os" "path/filepath" dbm "github.com/cosmos/cosmos-db" + "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" "cosmossdk.io/client/v2/autocli" @@ -25,6 +28,8 @@ import ( servertypes "github.com/cosmos/cosmos-sdk/server/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/mempool" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" @@ -245,6 +250,64 @@ func NewSimApp( panic(err) } + nonceMempool := mempool.NewSenderNonceMempool() + mempoolOpt := baseapp.SetMempool(nonceMempool) + prepareOpt := func(bapp *baseapp.BaseApp) { + bapp.SetPrepareProposal(func(ctx sdk.Context, req types.RequestPrepareProposal) types.ResponsePrepareProposal { + fmt.Println("prepare proposal!!!! height:", ctx.BlockHeight()) + balances := app.BankKeeper.GetAccountsBalances(ctx) + fmt.Println("all balances!!!!!", balances) + err := app.BankKeeper.MintCoins(ctx, "mint", sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000000000000000000)))) + fmt.Println("mint coins err:", err) + totalPower := app.StakingKeeper.GetLastTotalPower(ctx) + fmt.Println("total power!!!!!", totalPower) + bankParams := app.StakingKeeper.GetParams(ctx) + fmt.Println("staking params!!!!!", bankParams) + var ( + txsBytes [][]byte + byteCount int64 + ) + + iterator := nonceMempool.Select(ctx, req.Txs) + for iterator != nil { + memTx := iterator.Tx() + + bz, err := app.txConfig.TxEncoder()(memTx) + if err != nil { + panic(err) + } + + txSize := int64(len(bz)) + + // NOTE: Since runTx was already executed in CheckTx, which calls + // mempool.Insert, ideally everything in the pool should be valid. But + // some mempool implementations may insert invalid txs, so we check again. + res := app.CheckTx(types.RequestCheckTx{ + Tx: bz, + Type: types.CheckTxType_Recheck, + }) + if res.IsErr() { + err := nonceMempool.Remove(memTx) + if err != nil && !errors.Is(err, mempool.ErrTxNotFound) { + panic(err) + } + + iterator = iterator.Next() + continue + } else if byteCount += txSize; byteCount <= req.MaxTxBytes { + txsBytes = append(txsBytes, bz) + } else { + break + } + + iterator = iterator.Next() + } + + return types.ResponsePrepareProposal{Txs: txsBytes} + }) + } + baseAppOptions = append(baseAppOptions, prepareOpt, mempoolOpt) + app.App = appBuilder.Build(logger, db, traceStore, baseAppOptions...) if err := app.App.BaseApp.SetStreamingService(appOpts, app.appCodec, app.kvStoreKeys()); err != nil { From fac4b17562af864f9b259369710c39cb379ad612 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 13:39:46 -0300 Subject: [PATCH 05/13] make the linter happy --- baseapp/abci_test.go | 6 ++--- simapp/app_v2.go | 63 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index be105b75fe6c..3675c3ea2046 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -10,7 +10,6 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/jsonpb" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -1382,7 +1381,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { } prepareOpt := func(bapp *baseapp.BaseApp) { - bapp.SetPrepareProposal(func(ctx sdk.Context, req types.RequestPrepareProposal) types.ResponsePrepareProposal { + bapp.SetPrepareProposal(func(ctx sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { value := ctx.KVStore(capKey1).Get(someKey) // We should be able to access any state written in InitChain require.Equal(t, "foo", string(value)) @@ -1405,7 +1404,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { reqProposalTxBytes := [][]byte{} reqProcessProposal := abci.RequestProcessProposal{ - Txs: reqProposalTxBytes[:], + Txs: reqProposalTxBytes, } resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) @@ -1414,7 +1413,6 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { suite.baseApp.BeginBlock(abci.RequestBeginBlock{ Header: tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}, }) - } func TestABCI_PrepareProposal_ReachedMaxBytes(t *testing.T) { diff --git a/simapp/app_v2.go b/simapp/app_v2.go index 40af6b81f2c2..81b8b0f0f542 100644 --- a/simapp/app_v2.go +++ b/simapp/app_v2.go @@ -4,11 +4,14 @@ package simapp import ( _ "embed" + "errors" + "fmt" "io" "os" "path/filepath" dbm "github.com/cosmos/cosmos-db" + "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" "cosmossdk.io/client/v2/autocli" @@ -25,6 +28,8 @@ import ( servertypes "github.com/cosmos/cosmos-sdk/server/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/mempool" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" @@ -245,6 +250,64 @@ func NewSimApp( panic(err) } + nonceMempool := mempool.NewSenderNonceMempool() + mempoolOpt := baseapp.SetMempool(nonceMempool) + prepareOpt := func(bapp *baseapp.BaseApp) { + bapp.SetPrepareProposal(func(ctx sdk.Context, req types.RequestPrepareProposal) types.ResponsePrepareProposal { + fmt.Println("prepare proposal!!!! height:", ctx.BlockHeight()) + balances := app.BankKeeper.GetAccountsBalances(ctx) + fmt.Println("all balances!!!!!", balances) + err := app.BankKeeper.MintCoins(ctx, "mint", sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000000000000000000)))) + fmt.Println("mint coins err:", err) + totalPower := app.StakingKeeper.GetLastTotalPower(ctx) + fmt.Println("total power!!!!!", totalPower) + bankParams := app.StakingKeeper.GetParams(ctx) + fmt.Println("staking params!!!!!", bankParams) + var ( + txsBytes [][]byte + byteCount int64 + ) + + iterator := nonceMempool.Select(ctx, req.Txs) + for iterator != nil { + memTx := iterator.Tx() + + bz, err := app.txConfig.TxEncoder()(memTx) + if err != nil { + panic(err) + } + + txSize := int64(len(bz)) + + // NOTE: Since runTx was already executed in CheckTx, which calls + // mempool.Insert, ideally everything in the pool should be valid. But + // some mempool implementations may insert invalid txs, so we check again. + res := app.CheckTx(types.RequestCheckTx{ + Tx: bz, + Type: types.CheckTxType_Recheck, + }) + if res.IsErr() { + err := nonceMempool.Remove(memTx) + if err != nil && !errors.Is(err, mempool.ErrTxNotFound) { + panic(err) + } + + iterator = iterator.Next() + continue + } else if byteCount += txSize; byteCount <= req.MaxTxBytes { + txsBytes = append(txsBytes, bz) + } else { + break + } + + iterator = iterator.Next() + } + + return types.ResponsePrepareProposal{Txs: txsBytes} + }) + } + baseAppOptions = append(baseAppOptions, prepareOpt, mempoolOpt) + app.App = appBuilder.Build(logger, db, traceStore, baseAppOptions...) if err := app.App.BaseApp.SetStreamingService(appOpts, app.appCodec, app.kvStoreKeys()); err != nil { From aec901010911225938dd57c2809252abad08f3b4 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 13:45:23 -0300 Subject: [PATCH 06/13] add comment --- baseapp/abci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index fd3f21c992fe..47f954a8a060 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -253,7 +253,7 @@ func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci. } // Tendermint must never call PrepareProposal with a height of 0. - // TODO: Link to a doc stating this. + // Ref: https://github.com/tendermint/tendermint/blob/059798a4f5b0c9f52aa8655fa619054a0154088c/spec/core/state.md?plain=1#L37-L38 if req.Height < 1 { panic("PrepareProposal called with invalid height") } From a220784db1bca3b05cd431a228ada9b66c6abaf1 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 13:47:46 -0300 Subject: [PATCH 07/13] Revert "make the linter happy" This reverts commit fac4b17562af864f9b259369710c39cb379ad612. --- baseapp/abci_test.go | 6 +++-- simapp/app_v2.go | 63 -------------------------------------------- 2 files changed, 4 insertions(+), 65 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 3675c3ea2046..be105b75fe6c 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -10,6 +10,7 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/jsonpb" "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -1381,7 +1382,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { } prepareOpt := func(bapp *baseapp.BaseApp) { - bapp.SetPrepareProposal(func(ctx sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + bapp.SetPrepareProposal(func(ctx sdk.Context, req types.RequestPrepareProposal) types.ResponsePrepareProposal { value := ctx.KVStore(capKey1).Get(someKey) // We should be able to access any state written in InitChain require.Equal(t, "foo", string(value)) @@ -1404,7 +1405,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { reqProposalTxBytes := [][]byte{} reqProcessProposal := abci.RequestProcessProposal{ - Txs: reqProposalTxBytes, + Txs: reqProposalTxBytes[:], } resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) @@ -1413,6 +1414,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { suite.baseApp.BeginBlock(abci.RequestBeginBlock{ Header: tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}, }) + } func TestABCI_PrepareProposal_ReachedMaxBytes(t *testing.T) { diff --git a/simapp/app_v2.go b/simapp/app_v2.go index 81b8b0f0f542..40af6b81f2c2 100644 --- a/simapp/app_v2.go +++ b/simapp/app_v2.go @@ -4,14 +4,11 @@ package simapp import ( _ "embed" - "errors" - "fmt" "io" "os" "path/filepath" dbm "github.com/cosmos/cosmos-db" - "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" "cosmossdk.io/client/v2/autocli" @@ -28,8 +25,6 @@ import ( servertypes "github.com/cosmos/cosmos-sdk/server/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/mempool" "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/auth" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" @@ -250,64 +245,6 @@ func NewSimApp( panic(err) } - nonceMempool := mempool.NewSenderNonceMempool() - mempoolOpt := baseapp.SetMempool(nonceMempool) - prepareOpt := func(bapp *baseapp.BaseApp) { - bapp.SetPrepareProposal(func(ctx sdk.Context, req types.RequestPrepareProposal) types.ResponsePrepareProposal { - fmt.Println("prepare proposal!!!! height:", ctx.BlockHeight()) - balances := app.BankKeeper.GetAccountsBalances(ctx) - fmt.Println("all balances!!!!!", balances) - err := app.BankKeeper.MintCoins(ctx, "mint", sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000000000000000000)))) - fmt.Println("mint coins err:", err) - totalPower := app.StakingKeeper.GetLastTotalPower(ctx) - fmt.Println("total power!!!!!", totalPower) - bankParams := app.StakingKeeper.GetParams(ctx) - fmt.Println("staking params!!!!!", bankParams) - var ( - txsBytes [][]byte - byteCount int64 - ) - - iterator := nonceMempool.Select(ctx, req.Txs) - for iterator != nil { - memTx := iterator.Tx() - - bz, err := app.txConfig.TxEncoder()(memTx) - if err != nil { - panic(err) - } - - txSize := int64(len(bz)) - - // NOTE: Since runTx was already executed in CheckTx, which calls - // mempool.Insert, ideally everything in the pool should be valid. But - // some mempool implementations may insert invalid txs, so we check again. - res := app.CheckTx(types.RequestCheckTx{ - Tx: bz, - Type: types.CheckTxType_Recheck, - }) - if res.IsErr() { - err := nonceMempool.Remove(memTx) - if err != nil && !errors.Is(err, mempool.ErrTxNotFound) { - panic(err) - } - - iterator = iterator.Next() - continue - } else if byteCount += txSize; byteCount <= req.MaxTxBytes { - txsBytes = append(txsBytes, bz) - } else { - break - } - - iterator = iterator.Next() - } - - return types.ResponsePrepareProposal{Txs: txsBytes} - }) - } - baseAppOptions = append(baseAppOptions, prepareOpt, mempoolOpt) - app.App = appBuilder.Build(logger, db, traceStore, baseAppOptions...) if err := app.App.BaseApp.SetStreamingService(appOpts, app.appCodec, app.kvStoreKeys()); err != nil { From d5d0bbcf0745f66371df8ab4b54652f806f086df Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 13:49:10 -0300 Subject: [PATCH 08/13] fix a wrongly pushed test app --- baseapp/abci_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index be105b75fe6c..bab711e9cf02 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -10,7 +10,6 @@ import ( dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/jsonpb" "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" @@ -1382,7 +1381,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { } prepareOpt := func(bapp *baseapp.BaseApp) { - bapp.SetPrepareProposal(func(ctx sdk.Context, req types.RequestPrepareProposal) types.ResponsePrepareProposal { + bapp.SetPrepareProposal(func(ctx sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { value := ctx.KVStore(capKey1).Get(someKey) // We should be able to access any state written in InitChain require.Equal(t, "foo", string(value)) @@ -1414,7 +1413,6 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { suite.baseApp.BeginBlock(abci.RequestBeginBlock{ Header: tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}, }) - } func TestABCI_PrepareProposal_ReachedMaxBytes(t *testing.T) { From f9167dcdaa7cb193a67ee11caa37db0898bd0844 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 13:57:57 -0300 Subject: [PATCH 09/13] make the linter happy --- baseapp/abci_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index bab711e9cf02..7243ed39c061 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -1404,7 +1404,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { reqProposalTxBytes := [][]byte{} reqProcessProposal := abci.RequestProcessProposal{ - Txs: reqProposalTxBytes[:], + Txs: reqProposalTxBytes[], } resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) From 223c4459deb1c599b9c7866ab5a4c8207187cd67 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 14:15:12 -0300 Subject: [PATCH 10/13] make the linter happy --- baseapp/abci_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index 7243ed39c061..bab711e9cf02 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -1404,7 +1404,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { reqProposalTxBytes := [][]byte{} reqProcessProposal := abci.RequestProcessProposal{ - Txs: reqProposalTxBytes[], + Txs: reqProposalTxBytes[:], } resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) From 4ce6f8c340a04f59b8f6cef40ae08bc5fd945d48 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Thu, 5 Jan 2023 14:24:34 -0300 Subject: [PATCH 11/13] make the linter happy --- baseapp/abci_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index bab711e9cf02..3675c3ea2046 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -1404,7 +1404,7 @@ func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { reqProposalTxBytes := [][]byte{} reqProcessProposal := abci.RequestProcessProposal{ - Txs: reqProposalTxBytes[:], + Txs: reqProposalTxBytes, } resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) From 4a3beff6cdc85e7fd9e3ef645c952bbbebde852e Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Fri, 6 Jan 2023 18:13:27 -0300 Subject: [PATCH 12/13] suggestion from @ttl33 --- baseapp/abci.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/baseapp/abci.go b/baseapp/abci.go index 47f954a8a060..aacfcb77ed64 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -258,12 +258,7 @@ func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci. panic("PrepareProposal called with invalid height") } - ctx := app.prepareProposalState.ctx - // Here we use deliverState on the first block given that we want to be able - // to access any state changes made in InitChain. - if req.Height == 1 { - ctx, _ = app.deliverState.ctx.CacheContext() - } + ctx := app.getContextForProposal(app.prepareProposalState.ctx, req.Height) ctx = ctx.WithVoteInfos(app.voteInfos). WithBlockHeight(req.Height). @@ -307,12 +302,7 @@ func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) (resp abci. panic("app.ProcessProposal is not set") } - ctx := app.processProposalState.ctx - // Here we use deliverState on the first block given that we want to be able - // to access any state changes made in InitChain. - if req.Height == 1 { - ctx, _ = app.deliverState.ctx.CacheContext() - } + ctx := app.getContextForProposal(app.processProposalState.ctx, req.Height) ctx = ctx. WithVoteInfos(app.voteInfos). @@ -953,3 +943,14 @@ func SplitABCIQueryPath(requestPath string) (path []string) { return path } + +// getContextForProposal returns the right context for PrepareProposal and +// ProcessProposal. We use deliverState on the first block to be able to access +// any state changes made in InitChain. +func (app *BaseApp) getContextForProposal(ctx sdk.Context, height int64) sdk.Context { + if height == 1 { + ctx, _ = app.deliverState.ctx.CacheContext() + return ctx + } + return ctx +} From ac4c3f2b8342a305910f4e1e7fe2a18ea4269214 Mon Sep 17 00:00:00 2001 From: Facundo Medica Date: Fri, 6 Jan 2023 18:15:14 -0300 Subject: [PATCH 13/13] add cl --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 246503b62178..2c8731082235 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -216,6 +216,7 @@ extension interfaces. `module.Manager.Modules` is now of type `map[string]interf ### Bug Fixes +* (baseapp) [#14505](https://github.com/cosmos/cosmos-sdk/pull/14505) PrepareProposal and ProcessProposal now use deliverState for the first block in order to access changes made in InitChain. * (server) [#14441](https://github.com/cosmos/cosmos-sdk/pull/14441) Fix `--log_format` flag not working. * (x/upgrade) [#13936](https://github.com/cosmos/cosmos-sdk/pull/13936) Make downgrade verification work again * (x/group) [#13742](https://github.com/cosmos/cosmos-sdk/pull/13742) Fix `validate-genesis` when group policy accounts exist.