chore: cleanup baseapp tests (#14162)
This commit is contained in:
+3
-3
@@ -173,7 +173,7 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
|
||||
|
||||
// add block gas meter
|
||||
var gasMeter sdk.GasMeter
|
||||
if maxGas := app.getMaximumBlockGas(app.deliverState.ctx); maxGas > 0 {
|
||||
if maxGas := app.GetMaximumBlockGas(app.deliverState.ctx); maxGas > 0 {
|
||||
gasMeter = sdk.NewGasMeter(maxGas)
|
||||
} else {
|
||||
gasMeter = sdk.NewInfiniteGasMeter()
|
||||
@@ -615,7 +615,7 @@ func (app *BaseApp) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci.
|
||||
}
|
||||
|
||||
func (app *BaseApp) handleQueryGRPC(handler GRPCQueryHandler, req abci.RequestQuery) abci.ResponseQuery {
|
||||
ctx, err := app.createQueryContext(req.Height, req.Prove)
|
||||
ctx, err := app.CreateQueryContext(req.Height, req.Prove)
|
||||
if err != nil {
|
||||
return sdkerrors.QueryResult(err, app.trace)
|
||||
}
|
||||
@@ -663,7 +663,7 @@ func checkNegativeHeight(height int64) error {
|
||||
|
||||
// createQueryContext creates a new sdk.Context for a query, taking as args
|
||||
// the block height and whether the query needs a proof or not.
|
||||
func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, error) {
|
||||
func (app *BaseApp) CreateQueryContext(height int64, prove bool) (sdk.Context, error) {
|
||||
if err := checkNegativeHeight(height); err != nil {
|
||||
return sdk.Context{}, err
|
||||
}
|
||||
|
||||
+1332
-96
File diff suppressed because it is too large
Load Diff
@@ -1,194 +0,0 @@
|
||||
package baseapp_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
|
||||
"cosmossdk.io/depinject"
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/runtime"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/mempool"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
)
|
||||
|
||||
type NoopCounterServerImpl struct{}
|
||||
|
||||
func (m NoopCounterServerImpl) IncrementCounter(
|
||||
_ context.Context,
|
||||
_ *baseapptestutil.MsgCounter,
|
||||
) (*baseapptestutil.MsgCreateCounterResponse, error) {
|
||||
return &baseapptestutil.MsgCreateCounterResponse{}, nil
|
||||
}
|
||||
|
||||
type ABCIv1TestSuite struct {
|
||||
suite.Suite
|
||||
baseApp *baseapp.BaseApp
|
||||
mempool mempool.Mempool
|
||||
txConfig client.TxConfig
|
||||
cdc codec.ProtoCodecMarshaler
|
||||
options []func(app *baseapp.BaseApp)
|
||||
}
|
||||
|
||||
func TestABCIv1TestSuite(t *testing.T) {
|
||||
suite.Run(t, new(ABCIv1TestSuite))
|
||||
}
|
||||
|
||||
func (s *ABCIv1TestSuite) SetupTest() {
|
||||
t := s.T()
|
||||
anteKey := []byte("ante-key")
|
||||
pool := mempool.NewSenderNonceMempool()
|
||||
anteOpt := func(bapp *baseapp.BaseApp) {
|
||||
bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey))
|
||||
}
|
||||
|
||||
var (
|
||||
appBuilder *runtime.AppBuilder
|
||||
cdc codec.ProtoCodecMarshaler
|
||||
registry codectypes.InterfaceRegistry
|
||||
)
|
||||
err := depinject.Inject(makeMinimalConfig(), &appBuilder, &cdc, ®istry)
|
||||
require.NoError(t, err)
|
||||
|
||||
s.options = append(s.options, baseapp.SetMempool(pool), anteOpt)
|
||||
app := setupBaseApp(t, s.options...)
|
||||
baseapptestutil.RegisterInterfaces(registry)
|
||||
app.SetMsgServiceRouter(baseapp.NewMsgServiceRouter())
|
||||
app.SetInterfaceRegistry(registry)
|
||||
|
||||
baseapptestutil.RegisterKeyValueServer(app.MsgServiceRouter(), MsgKeyValueImpl{})
|
||||
baseapptestutil.RegisterCounterServer(app.MsgServiceRouter(), NoopCounterServerImpl{})
|
||||
header := tmproto.Header{Height: app.LastBlockHeight() + 1}
|
||||
|
||||
app.InitChain(abci.RequestInitChain{
|
||||
ConsensusParams: &tmproto.ConsensusParams{},
|
||||
})
|
||||
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
// patch in TxConfig insted of using an output from x/auth/tx
|
||||
txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes)
|
||||
|
||||
app.SetTxDecoder(txConfig.TxDecoder())
|
||||
app.SetTxEncoder(txConfig.TxEncoder())
|
||||
|
||||
s.baseApp = app
|
||||
s.mempool = pool
|
||||
s.txConfig = txConfig
|
||||
s.cdc = cdc
|
||||
}
|
||||
|
||||
func (s *ABCIv1TestSuite) TestABCIv1_HappyPath() {
|
||||
txConfig := s.txConfig
|
||||
t := s.T()
|
||||
|
||||
tx := newTxCounter(txConfig, 0, 1)
|
||||
txBytes, err := txConfig.TxEncoder()(tx)
|
||||
require.NoError(t, err)
|
||||
|
||||
reqCheckTx := abci.RequestCheckTx{
|
||||
Tx: txBytes,
|
||||
Type: abci.CheckTxType_New,
|
||||
}
|
||||
s.baseApp.CheckTx(reqCheckTx)
|
||||
|
||||
tx2 := newTxCounter(txConfig, 1, 1)
|
||||
|
||||
tx2Bytes, err := txConfig.TxEncoder()(tx2)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = s.mempool.Insert(sdk.Context{}, tx2)
|
||||
require.NoError(t, err)
|
||||
reqPreparePropossal := abci.RequestPrepareProposal{
|
||||
MaxTxBytes: 1000,
|
||||
}
|
||||
resPreparePropossal := s.baseApp.PrepareProposal(reqPreparePropossal)
|
||||
|
||||
require.Equal(t, 2, len(resPreparePropossal.Txs))
|
||||
|
||||
var reqProposalTxBytes [2][]byte
|
||||
reqProposalTxBytes[0] = txBytes
|
||||
reqProposalTxBytes[1] = tx2Bytes
|
||||
reqProcessProposal := abci.RequestProcessProposal{
|
||||
Txs: reqProposalTxBytes[:],
|
||||
}
|
||||
|
||||
resProcessProposal := s.baseApp.ProcessProposal(reqProcessProposal)
|
||||
require.Equal(t, abci.ResponseProcessProposal_ACCEPT, resProcessProposal.Status)
|
||||
|
||||
res := s.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
|
||||
require.Equal(t, 1, s.mempool.CountTx())
|
||||
|
||||
require.NotEmpty(t, res.Events)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
}
|
||||
|
||||
func (s *ABCIv1TestSuite) TestABCIv1_PrepareProposal_ReachedMaxBytes() {
|
||||
txConfig := s.txConfig
|
||||
t := s.T()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
tx2 := newTxCounter(txConfig, int64(i), int64(i))
|
||||
err := s.mempool.Insert(sdk.Context{}, tx2)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
reqPreparePropossal := abci.RequestPrepareProposal{
|
||||
MaxTxBytes: 1500,
|
||||
}
|
||||
resPreparePropossal := s.baseApp.PrepareProposal(reqPreparePropossal)
|
||||
|
||||
require.Equal(t, 10, len(resPreparePropossal.Txs))
|
||||
}
|
||||
|
||||
func (s *ABCIv1TestSuite) TestABCIv1_PrepareProposal_BadEncoding() {
|
||||
txConfig := authtx.NewTxConfig(s.cdc, authtx.DefaultSignModes)
|
||||
|
||||
t := s.T()
|
||||
|
||||
tx := newTxCounter(txConfig, 0, 0)
|
||||
err := s.mempool.Insert(sdk.Context{}, tx)
|
||||
require.NoError(t, err)
|
||||
|
||||
reqPrepareProposal := abci.RequestPrepareProposal{
|
||||
MaxTxBytes: 1000,
|
||||
}
|
||||
resPrepareProposal := s.baseApp.PrepareProposal(reqPrepareProposal)
|
||||
|
||||
require.Equal(t, 1, len(resPrepareProposal.Txs))
|
||||
}
|
||||
|
||||
func (s *ABCIv1TestSuite) TestABCIv1_PrepareProposal_Failures() {
|
||||
tx := newTxCounter(s.txConfig, 0, 0)
|
||||
txBytes, err := s.txConfig.TxEncoder()(tx)
|
||||
s.NoError(err)
|
||||
|
||||
reqCheckTx := abci.RequestCheckTx{
|
||||
Tx: txBytes,
|
||||
Type: abci.CheckTxType_New,
|
||||
}
|
||||
checkTxRes := s.baseApp.CheckTx(reqCheckTx)
|
||||
s.True(checkTxRes.IsOK())
|
||||
|
||||
failTx := newTxCounter(s.txConfig, 1, 1)
|
||||
failTx = setFailOnAnte(s.txConfig, failTx, true)
|
||||
err = s.mempool.Insert(sdk.Context{}, failTx)
|
||||
s.NoError(err)
|
||||
s.Equal(2, s.mempool.CountTx())
|
||||
|
||||
req := abci.RequestPrepareProposal{
|
||||
MaxTxBytes: 1000,
|
||||
}
|
||||
res := s.baseApp.PrepareProposal(req)
|
||||
s.Equal(1, len(res.Txs))
|
||||
}
|
||||
+2
-2
@@ -485,10 +485,10 @@ func (app *BaseApp) AddRunTxRecoveryHandler(handlers ...RecoveryHandler) {
|
||||
}
|
||||
}
|
||||
|
||||
// getMaximumBlockGas gets the maximum gas from the consensus params. It panics
|
||||
// GetMaximumBlockGas gets the maximum gas from the consensus params. It panics
|
||||
// if maximum block gas is less than negative one and returns zero if negative
|
||||
// one.
|
||||
func (app *BaseApp) getMaximumBlockGas(ctx sdk.Context) uint64 {
|
||||
func (app *BaseApp) GetMaximumBlockGas(ctx sdk.Context) uint64 {
|
||||
cp := app.GetConsensusParams(ctx)
|
||||
if cp == nil || cp.Block == nil {
|
||||
return 0
|
||||
|
||||
+579
-42
@@ -1,7 +1,10 @@
|
||||
package baseapp
|
||||
package baseapp_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
@@ -9,47 +12,604 @@ import (
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
pruningtypes "github.com/cosmos/cosmos-sdk/store/pruning/types"
|
||||
"github.com/cosmos/cosmos-sdk/store/rootmulti"
|
||||
"github.com/cosmos/cosmos-sdk/store/snapshots"
|
||||
snapshottypes "github.com/cosmos/cosmos-sdk/store/snapshots/types"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
"github.com/cosmos/cosmos-sdk/testutil"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
)
|
||||
|
||||
var (
|
||||
capKey1 = sdk.NewKVStoreKey("key1")
|
||||
capKey2 = sdk.NewKVStoreKey("key2")
|
||||
|
||||
// testTxPriority is the CheckTx priority that we set in the test
|
||||
// AnteHandler.
|
||||
testTxPriority = int64(42)
|
||||
)
|
||||
|
||||
type (
|
||||
BaseAppSuite struct {
|
||||
baseApp *baseapp.BaseApp
|
||||
cdc *codec.ProtoCodec
|
||||
txConfig client.TxConfig
|
||||
}
|
||||
|
||||
SnapshotsConfig struct {
|
||||
blocks uint64
|
||||
blockTxs int
|
||||
snapshotInterval uint64
|
||||
snapshotKeepRecent uint32
|
||||
pruningOpts pruningtypes.PruningOptions
|
||||
}
|
||||
)
|
||||
|
||||
func NewBaseAppSuite(t *testing.T, opts ...func(*baseapp.BaseApp)) *BaseAppSuite {
|
||||
cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
|
||||
baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry())
|
||||
|
||||
txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes)
|
||||
logger := defaultLogger()
|
||||
db := dbm.NewMemDB()
|
||||
|
||||
app := baseapp.NewBaseApp(t.Name(), logger, db, txConfig.TxDecoder(), opts...)
|
||||
require.Equal(t, t.Name(), app.Name())
|
||||
|
||||
app.SetInterfaceRegistry(cdc.InterfaceRegistry())
|
||||
app.MsgServiceRouter().SetInterfaceRegistry(cdc.InterfaceRegistry())
|
||||
app.MountStores(capKey1, capKey2)
|
||||
app.SetParamStore(¶mStore{db: dbm.NewMemDB()})
|
||||
app.SetTxDecoder(txConfig.TxDecoder())
|
||||
app.SetTxEncoder(txConfig.TxEncoder())
|
||||
|
||||
// mount stores and seal
|
||||
require.Nil(t, app.LoadLatestVersion())
|
||||
|
||||
return &BaseAppSuite{
|
||||
baseApp: app,
|
||||
cdc: cdc,
|
||||
txConfig: txConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func NewBaseAppSuiteWithSnapshots(t *testing.T, cfg SnapshotsConfig, opts ...func(*baseapp.BaseApp)) *BaseAppSuite {
|
||||
snapshotTimeout := 1 * time.Minute
|
||||
snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), testutil.GetTempDir(t))
|
||||
require.NoError(t, err)
|
||||
|
||||
suite := NewBaseAppSuite(
|
||||
t,
|
||||
append(
|
||||
opts,
|
||||
baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(cfg.snapshotInterval, cfg.snapshotKeepRecent)),
|
||||
baseapp.SetPruning(cfg.pruningOpts),
|
||||
)...,
|
||||
)
|
||||
|
||||
baseapptestutil.RegisterKeyValueServer(suite.baseApp.MsgServiceRouter(), MsgKeyValueImpl{})
|
||||
|
||||
suite.baseApp.InitChain(abci.RequestInitChain{
|
||||
ConsensusParams: &tmproto.ConsensusParams{},
|
||||
})
|
||||
|
||||
r := rand.New(rand.NewSource(3920758213583))
|
||||
keyCounter := 0
|
||||
|
||||
for height := int64(1); height <= int64(cfg.blocks); height++ {
|
||||
suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: height}})
|
||||
|
||||
for txNum := 0; txNum < cfg.blockTxs; txNum++ {
|
||||
msgs := []sdk.Msg{}
|
||||
for msgNum := 0; msgNum < 100; msgNum++ {
|
||||
key := []byte(fmt.Sprintf("%v", keyCounter))
|
||||
value := make([]byte, 10000)
|
||||
|
||||
_, err := r.Read(value)
|
||||
require.NoError(t, err)
|
||||
|
||||
msgs = append(msgs, &baseapptestutil.MsgKeyValue{Key: key, Value: value})
|
||||
keyCounter++
|
||||
}
|
||||
|
||||
builder := suite.txConfig.NewTxBuilder()
|
||||
builder.SetMsgs(msgs...)
|
||||
setTxSignature(t, builder, 0)
|
||||
|
||||
txBytes, err := suite.txConfig.TxEncoder()(builder.GetTx())
|
||||
require.NoError(t, err)
|
||||
|
||||
resp := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
|
||||
require.True(t, resp.IsOK(), "%v", resp.String())
|
||||
}
|
||||
|
||||
suite.baseApp.EndBlock(abci.RequestEndBlock{Height: height})
|
||||
suite.baseApp.Commit()
|
||||
|
||||
// wait for snapshot to be taken, since it happens asynchronously
|
||||
if cfg.snapshotInterval > 0 && uint64(height)%cfg.snapshotInterval == 0 {
|
||||
start := time.Now()
|
||||
for {
|
||||
if time.Since(start) > snapshotTimeout {
|
||||
t.Errorf("timed out waiting for snapshot after %v", snapshotTimeout)
|
||||
}
|
||||
|
||||
snapshot, err := snapshotStore.Get(uint64(height), snapshottypes.CurrentFormat)
|
||||
require.NoError(t, err)
|
||||
|
||||
if snapshot != nil {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return suite
|
||||
}
|
||||
|
||||
func TestLoadVersion(t *testing.T) {
|
||||
logger := defaultLogger()
|
||||
pruningOpt := baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing))
|
||||
db := dbm.NewMemDB()
|
||||
name := t.Name()
|
||||
app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
|
||||
// make a cap key and mount the store
|
||||
err := app.LoadLatestVersion() // needed to make stores non-nil
|
||||
require.Nil(t, err)
|
||||
|
||||
emptyCommitID := storetypes.CommitID{}
|
||||
|
||||
// fresh store has zero/empty last commit
|
||||
lastHeight := app.LastBlockHeight()
|
||||
lastID := app.LastCommitID()
|
||||
require.Equal(t, int64(0), lastHeight)
|
||||
require.Equal(t, emptyCommitID, lastID)
|
||||
|
||||
// execute a block, collect commit ID
|
||||
header := tmproto.Header{Height: 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
res := app.Commit()
|
||||
commitID1 := storetypes.CommitID{Version: 1, Hash: res.Data}
|
||||
|
||||
// execute a block, collect commit ID
|
||||
header = tmproto.Header{Height: 2}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
res = app.Commit()
|
||||
commitID2 := storetypes.CommitID{Version: 2, Hash: res.Data}
|
||||
|
||||
// reload with LoadLatestVersion
|
||||
app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
app.MountStores()
|
||||
|
||||
err = app.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
testLoadVersionHelper(t, app, int64(2), commitID2)
|
||||
|
||||
// Reload with LoadVersion, see if you can commit the same block and get
|
||||
// the same result.
|
||||
app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
err = app.LoadVersion(1)
|
||||
require.Nil(t, err)
|
||||
|
||||
testLoadVersionHelper(t, app, int64(1), commitID1)
|
||||
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
app.Commit()
|
||||
|
||||
testLoadVersionHelper(t, app, int64(2), commitID2)
|
||||
}
|
||||
|
||||
func TestSetLoader(t *testing.T) {
|
||||
useDefaultLoader := func(app *baseapp.BaseApp) {
|
||||
app.SetStoreLoader(baseapp.DefaultStoreLoader)
|
||||
}
|
||||
|
||||
initStore := func(t *testing.T, db dbm.DB, storeKey string, k, v []byte) {
|
||||
rs := rootmulti.NewStore(db, log.NewNopLogger())
|
||||
rs.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing))
|
||||
|
||||
key := sdk.NewKVStoreKey(storeKey)
|
||||
rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil)
|
||||
|
||||
err := rs.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(0), rs.LastCommitID().Version)
|
||||
|
||||
// write some data in substore
|
||||
kv, _ := rs.GetStore(key).(storetypes.KVStore)
|
||||
require.NotNil(t, kv)
|
||||
kv.Set(k, v)
|
||||
|
||||
commitID := rs.Commit()
|
||||
require.Equal(t, int64(1), commitID.Version)
|
||||
}
|
||||
|
||||
checkStore := func(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) {
|
||||
rs := rootmulti.NewStore(db, log.NewNopLogger())
|
||||
rs.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningDefault))
|
||||
|
||||
key := sdk.NewKVStoreKey(storeKey)
|
||||
rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil)
|
||||
|
||||
err := rs.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, ver, rs.LastCommitID().Version)
|
||||
|
||||
// query data in substore
|
||||
kv, _ := rs.GetStore(key).(storetypes.KVStore)
|
||||
require.NotNil(t, kv)
|
||||
require.Equal(t, v, kv.Get(k))
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
setLoader func(*baseapp.BaseApp)
|
||||
origStoreKey string
|
||||
loadStoreKey string
|
||||
}{
|
||||
"don't set loader": {
|
||||
origStoreKey: "foo",
|
||||
loadStoreKey: "foo",
|
||||
},
|
||||
"default loader": {
|
||||
setLoader: useDefaultLoader,
|
||||
origStoreKey: "foo",
|
||||
loadStoreKey: "foo",
|
||||
},
|
||||
}
|
||||
|
||||
k := []byte("key")
|
||||
v := []byte("value")
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
// prepare a db with some data
|
||||
db := dbm.NewMemDB()
|
||||
initStore(t, db, tc.origStoreKey, k, v)
|
||||
|
||||
// load the app with the existing db
|
||||
opts := []func(*baseapp.BaseApp){baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing))}
|
||||
if tc.setLoader != nil {
|
||||
opts = append(opts, tc.setLoader)
|
||||
}
|
||||
app := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, nil, opts...)
|
||||
app.MountStores(sdk.NewKVStoreKey(tc.loadStoreKey))
|
||||
err := app.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
// "execute" one block
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 2}})
|
||||
res := app.Commit()
|
||||
require.NotNil(t, res.Data)
|
||||
|
||||
// check db is properly updated
|
||||
checkStore(t, db, 2, tc.loadStoreKey, k, v)
|
||||
checkStore(t, db, 2, tc.loadStoreKey, []byte("foo"), nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionSetterGetter(t *testing.T) {
|
||||
logger := defaultLogger()
|
||||
pruningOpt := baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningDefault))
|
||||
db := dbm.NewMemDB()
|
||||
name := t.Name()
|
||||
app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
|
||||
require.Equal(t, "", app.Version())
|
||||
res := app.Query(abci.RequestQuery{Path: "app/version"})
|
||||
require.True(t, res.IsOK())
|
||||
require.Equal(t, "", string(res.Value))
|
||||
|
||||
versionString := "1.0.0"
|
||||
app.SetVersion(versionString)
|
||||
require.Equal(t, versionString, app.Version())
|
||||
|
||||
res = app.Query(abci.RequestQuery{Path: "app/version"})
|
||||
require.True(t, res.IsOK())
|
||||
require.Equal(t, versionString, string(res.Value))
|
||||
}
|
||||
|
||||
func TestLoadVersionInvalid(t *testing.T) {
|
||||
logger := log.NewNopLogger()
|
||||
pruningOpt := baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing))
|
||||
db := dbm.NewMemDB()
|
||||
name := t.Name()
|
||||
app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
|
||||
err := app.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
// require error when loading an invalid version
|
||||
err = app.LoadVersion(-1)
|
||||
require.Error(t, err)
|
||||
|
||||
header := tmproto.Header{Height: 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
res := app.Commit()
|
||||
commitID1 := storetypes.CommitID{Version: 1, Hash: res.Data}
|
||||
|
||||
// create a new app with the stores mounted under the same cap key
|
||||
app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
|
||||
// require we can load the latest version
|
||||
err = app.LoadVersion(1)
|
||||
require.Nil(t, err)
|
||||
testLoadVersionHelper(t, app, int64(1), commitID1)
|
||||
|
||||
// require error when loading an invalid version
|
||||
err = app.LoadVersion(2)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestOptionFunction(t *testing.T) {
|
||||
testChangeNameHelper := func(name string) func(*baseapp.BaseApp) {
|
||||
return func(bap *baseapp.BaseApp) {
|
||||
bap.SetName(name)
|
||||
}
|
||||
}
|
||||
|
||||
logger := defaultLogger()
|
||||
db := dbm.NewMemDB()
|
||||
bap := baseapp.NewBaseApp("starting name", logger, db, nil, testChangeNameHelper("new name"))
|
||||
require.Equal(t, bap.Name(), "new name", "BaseApp should have had name changed via option function")
|
||||
}
|
||||
|
||||
func TestBaseAppOptionSeal(t *testing.T) {
|
||||
suite := NewBaseAppSuite(t)
|
||||
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetName("")
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetVersion("")
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetDB(nil)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetCMS(nil)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetInitChainer(nil)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetBeginBlocker(nil)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetEndBlocker(nil)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetAnteHandler(nil)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetAddrPeerFilter(nil)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetIDPeerFilter(nil)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
suite.baseApp.SetFauxMerkleMode()
|
||||
})
|
||||
}
|
||||
|
||||
func TestTxDecoder(t *testing.T) {
|
||||
cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
|
||||
baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry())
|
||||
|
||||
// patch in TxConfig instead of using an output from x/auth/tx
|
||||
txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes)
|
||||
|
||||
tx := newTxCounter(t, txConfig, 1, 0)
|
||||
txBytes, err := txConfig.TxEncoder()(tx)
|
||||
require.NoError(t, err)
|
||||
|
||||
dTx, err := txConfig.TxDecoder()(txBytes)
|
||||
require.NoError(t, err)
|
||||
|
||||
counter, _ := parseTxMemo(t, tx)
|
||||
dTxCounter, _ := parseTxMemo(t, dTx)
|
||||
require.Equal(t, counter, dTxCounter)
|
||||
}
|
||||
|
||||
func TestCustomRunTxPanicHandler(t *testing.T) {
|
||||
customPanicMsg := "test panic"
|
||||
anteErr := sdkerrors.Register("fakeModule", 100500, "fakeError")
|
||||
anteOpt := func(bapp *baseapp.BaseApp) {
|
||||
bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) {
|
||||
panic(sdkerrors.Wrap(anteErr, "anteHandler"))
|
||||
})
|
||||
}
|
||||
suite := NewBaseAppSuite(t, anteOpt)
|
||||
|
||||
suite.baseApp.InitChain(abci.RequestInitChain{
|
||||
ConsensusParams: &tmproto.ConsensusParams{},
|
||||
})
|
||||
|
||||
header := tmproto.Header{Height: 1}
|
||||
suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
suite.baseApp.AddRunTxRecoveryHandler(func(recoveryObj interface{}) error {
|
||||
err, ok := recoveryObj.(error)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if anteErr.Is(err) {
|
||||
panic(customPanicMsg)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
|
||||
// transaction should panic with custom handler above
|
||||
{
|
||||
tx := newTxCounter(t, suite.txConfig, 0, 0)
|
||||
|
||||
require.PanicsWithValue(t, customPanicMsg, func() {
|
||||
suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), tx)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseAppAnteHandler(t *testing.T) {
|
||||
anteKey := []byte("ante-key")
|
||||
anteOpt := func(bapp *baseapp.BaseApp) {
|
||||
bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey))
|
||||
}
|
||||
suite := NewBaseAppSuite(t, anteOpt)
|
||||
|
||||
deliverKey := []byte("deliver-key")
|
||||
baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImpl{t, capKey1, deliverKey})
|
||||
|
||||
suite.baseApp.InitChain(abci.RequestInitChain{
|
||||
ConsensusParams: &tmproto.ConsensusParams{},
|
||||
})
|
||||
|
||||
header := tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}
|
||||
suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
// execute a tx that will fail ante handler execution
|
||||
//
|
||||
// NOTE: State should not be mutated here. This will be implicitly checked by
|
||||
// the next txs ante handler execution (anteHandlerTxTest).
|
||||
tx := newTxCounter(t, suite.txConfig, 0, 0)
|
||||
tx = setFailOnAnte(t, suite.txConfig, tx, true)
|
||||
|
||||
txBytes, err := suite.txConfig.TxEncoder()(tx)
|
||||
require.NoError(t, err)
|
||||
|
||||
res := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
|
||||
require.Empty(t, res.Events)
|
||||
require.False(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
||||
ctx := getDeliverStateCtx(suite.baseApp)
|
||||
store := ctx.KVStore(capKey1)
|
||||
require.Equal(t, int64(0), getIntFromStore(t, store, anteKey))
|
||||
|
||||
// execute at tx that will pass the ante handler (the checkTx state should
|
||||
// mutate) but will fail the message handler
|
||||
tx = newTxCounter(t, suite.txConfig, 0, 0)
|
||||
tx = setFailOnHandler(suite.txConfig, tx, true)
|
||||
|
||||
txBytes, err = suite.txConfig.TxEncoder()(tx)
|
||||
require.NoError(t, err)
|
||||
|
||||
res = suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
|
||||
require.NotEmpty(t, res.Events)
|
||||
require.False(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
||||
ctx = getDeliverStateCtx(suite.baseApp)
|
||||
store = ctx.KVStore(capKey1)
|
||||
require.Equal(t, int64(1), getIntFromStore(t, store, anteKey))
|
||||
require.Equal(t, int64(0), getIntFromStore(t, store, deliverKey))
|
||||
|
||||
// Execute a successful ante handler and message execution where state is
|
||||
// implicitly checked by previous tx executions.
|
||||
tx = newTxCounter(t, suite.txConfig, 1, 0)
|
||||
|
||||
txBytes, err = suite.txConfig.TxEncoder()(tx)
|
||||
require.NoError(t, err)
|
||||
|
||||
res = suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
|
||||
require.NotEmpty(t, res.Events)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
||||
ctx = getDeliverStateCtx(suite.baseApp)
|
||||
store = ctx.KVStore(capKey1)
|
||||
require.Equal(t, int64(2), getIntFromStore(t, store, anteKey))
|
||||
require.Equal(t, int64(1), getIntFromStore(t, store, deliverKey))
|
||||
|
||||
suite.baseApp.EndBlock(abci.RequestEndBlock{})
|
||||
suite.baseApp.Commit()
|
||||
}
|
||||
|
||||
// Test and ensure that invalid block heights always cause errors.
|
||||
// See issues:
|
||||
// - https://github.com/cosmos/cosmos-sdk/issues/11220
|
||||
// - https://github.com/cosmos/cosmos-sdk/issues/7662
|
||||
func TestABCI_CreateQueryContext(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
logger := defaultLogger()
|
||||
db := dbm.NewMemDB()
|
||||
name := t.Name()
|
||||
app := baseapp.NewBaseApp(name, logger, db, nil)
|
||||
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 1}})
|
||||
app.Commit()
|
||||
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 2}})
|
||||
app.Commit()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
height int64
|
||||
prove bool
|
||||
expErr bool
|
||||
}{
|
||||
{"valid height", 2, true, false},
|
||||
{"future height", 10, true, true},
|
||||
{"negative height, prove=true", -1, true, true},
|
||||
{"negative height, prove=false", -1, false, true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
_, err := app.CreateQueryContext(tc.height, tc.prove)
|
||||
if tc.expErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMinGasPrices(t *testing.T) {
|
||||
minGasPrices := sdk.DecCoins{sdk.NewInt64DecCoin("stake", 5000)}
|
||||
app := setupBaseApp(t, SetMinGasPrices(minGasPrices.String()))
|
||||
require.Equal(t, minGasPrices, app.minGasPrices)
|
||||
suite := NewBaseAppSuite(t, baseapp.SetMinGasPrices(minGasPrices.String()))
|
||||
|
||||
ctx := getCheckStateCtx(suite.baseApp)
|
||||
require.Equal(t, minGasPrices, ctx.MinGasPrices())
|
||||
}
|
||||
|
||||
func TestGetMaximumBlockGas(t *testing.T) {
|
||||
app := setupBaseApp(t)
|
||||
app.InitChain(abci.RequestInitChain{})
|
||||
ctx := app.NewContext(true, tmproto.Header{})
|
||||
suite := NewBaseAppSuite(t)
|
||||
suite.baseApp.InitChain(abci.RequestInitChain{})
|
||||
ctx := suite.baseApp.NewContext(true, tmproto.Header{})
|
||||
|
||||
app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 0}})
|
||||
require.Equal(t, uint64(0), app.getMaximumBlockGas(ctx))
|
||||
suite.baseApp.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 0}})
|
||||
require.Equal(t, uint64(0), suite.baseApp.GetMaximumBlockGas(ctx))
|
||||
|
||||
app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -1}})
|
||||
require.Equal(t, uint64(0), app.getMaximumBlockGas(ctx))
|
||||
suite.baseApp.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -1}})
|
||||
require.Equal(t, uint64(0), suite.baseApp.GetMaximumBlockGas(ctx))
|
||||
|
||||
app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 5000000}})
|
||||
require.Equal(t, uint64(5000000), app.getMaximumBlockGas(ctx))
|
||||
suite.baseApp.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 5000000}})
|
||||
require.Equal(t, uint64(5000000), suite.baseApp.GetMaximumBlockGas(ctx))
|
||||
|
||||
app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -5000000}})
|
||||
require.Panics(t, func() { app.getMaximumBlockGas(ctx) })
|
||||
suite.baseApp.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -5000000}})
|
||||
require.Panics(t, func() { suite.baseApp.GetMaximumBlockGas(ctx) })
|
||||
}
|
||||
|
||||
func TestLoadVersionPruning(t *testing.T) {
|
||||
logger := log.NewNopLogger()
|
||||
pruningOptions := pruningtypes.NewCustomPruningOptions(10, 15)
|
||||
pruningOpt := SetPruning(pruningOptions)
|
||||
pruningOpt := baseapp.SetPruning(pruningOptions)
|
||||
db := dbm.NewMemDB()
|
||||
name := t.Name()
|
||||
app := NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
|
||||
// make a cap key and mount the store
|
||||
capKey := sdk.NewKVStoreKey("key1")
|
||||
@@ -77,43 +637,20 @@ func TestLoadVersionPruning(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, v := range []int64{1, 2, 4} {
|
||||
_, err = app.cms.CacheMultiStoreWithVersion(v)
|
||||
_, err = app.CommitMultiStore().CacheMultiStoreWithVersion(v)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
for _, v := range []int64{3, 5, 6, 7} {
|
||||
_, err = app.cms.CacheMultiStoreWithVersion(v)
|
||||
_, err = app.CommitMultiStore().CacheMultiStoreWithVersion(v)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// reload with LoadLatestVersion, check it loads last version
|
||||
app = NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt)
|
||||
app.MountStores(capKey)
|
||||
|
||||
err = app.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
testLoadVersionHelper(t, app, int64(7), lastCommitID)
|
||||
}
|
||||
|
||||
// simple one store baseapp
|
||||
func setupBaseApp(t *testing.T, options ...func(*BaseApp)) *BaseApp {
|
||||
logger := defaultLogger()
|
||||
db := dbm.NewMemDB()
|
||||
app := NewBaseApp(t.Name(), logger, db, nil, options...)
|
||||
require.Equal(t, t.Name(), app.Name())
|
||||
|
||||
app.MountStores(capKey1, capKey2)
|
||||
app.SetParamStore(¶mStore{db: dbm.NewMemDB()})
|
||||
|
||||
// stores are mounted
|
||||
err := app.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
return app
|
||||
}
|
||||
|
||||
func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, expectedID storetypes.CommitID) {
|
||||
lastHeight := app.LastBlockHeight()
|
||||
lastID := app.LastCommitID()
|
||||
require.Equal(t, expectedHeight, lastHeight)
|
||||
require.Equal(t, expectedID, lastID)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) {
|
||||
|
||||
// Create the sdk.Context. Passing false as 2nd arg, as we can't
|
||||
// actually support proofs with gRPC right now.
|
||||
sdkCtx, err := app.createQueryContext(height, false)
|
||||
sdkCtx, err := app.CreateQueryContext(height, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
package baseapp_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"unsafe"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
storetypes "github.com/cosmos/cosmos-sdk/store/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
)
|
||||
|
||||
var (
|
||||
ParamStoreKey = []byte("paramstore")
|
||||
)
|
||||
|
||||
func defaultLogger() log.Logger {
|
||||
if testing.Verbose() {
|
||||
return log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "baseapp/test")
|
||||
}
|
||||
|
||||
return log.NewNopLogger()
|
||||
}
|
||||
|
||||
type MsgKeyValueImpl struct{}
|
||||
|
||||
func (m MsgKeyValueImpl) Set(ctx context.Context, msg *baseapptestutil.MsgKeyValue) (*baseapptestutil.MsgCreateKeyValueResponse, error) {
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
sdkCtx.KVStore(capKey2).Set(msg.Key, msg.Value)
|
||||
return &baseapptestutil.MsgCreateKeyValueResponse{}, nil
|
||||
}
|
||||
|
||||
type CounterServerImplGasMeterOnly struct {
|
||||
gas uint64
|
||||
}
|
||||
|
||||
func (m CounterServerImplGasMeterOnly) IncrementCounter(ctx context.Context, msg *baseapptestutil.MsgCounter) (*baseapptestutil.MsgCreateCounterResponse, error) {
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
gas := m.gas
|
||||
|
||||
// if no gas is provided, use the counter as gas. This is useful for testing
|
||||
if gas == 0 {
|
||||
gas = uint64(msg.Counter)
|
||||
}
|
||||
|
||||
sdkCtx.GasMeter().ConsumeGas(gas, "test")
|
||||
return &baseapptestutil.MsgCreateCounterResponse{}, nil
|
||||
}
|
||||
|
||||
type NoopCounterServerImpl struct{}
|
||||
|
||||
func (m NoopCounterServerImpl) IncrementCounter(
|
||||
_ context.Context,
|
||||
_ *baseapptestutil.MsgCounter,
|
||||
) (*baseapptestutil.MsgCreateCounterResponse, error) {
|
||||
return &baseapptestutil.MsgCreateCounterResponse{}, nil
|
||||
}
|
||||
|
||||
type CounterServerImpl struct {
|
||||
t *testing.T
|
||||
capKey storetypes.StoreKey
|
||||
deliverKey []byte
|
||||
}
|
||||
|
||||
func (m CounterServerImpl) IncrementCounter(ctx context.Context, msg *baseapptestutil.MsgCounter) (*baseapptestutil.MsgCreateCounterResponse, error) {
|
||||
return incrementCounter(ctx, m.t, m.capKey, m.deliverKey, msg)
|
||||
}
|
||||
|
||||
type Counter2ServerImpl struct {
|
||||
t *testing.T
|
||||
capKey storetypes.StoreKey
|
||||
deliverKey []byte
|
||||
}
|
||||
|
||||
func (m Counter2ServerImpl) IncrementCounter(ctx context.Context, msg *baseapptestutil.MsgCounter2) (*baseapptestutil.MsgCreateCounterResponse, error) {
|
||||
return incrementCounter(ctx, m.t, m.capKey, m.deliverKey, msg)
|
||||
}
|
||||
|
||||
func incrementCounter(ctx context.Context,
|
||||
t *testing.T,
|
||||
capKey storetypes.StoreKey,
|
||||
deliverKey []byte,
|
||||
msg sdk.Msg,
|
||||
) (*baseapptestutil.MsgCreateCounterResponse, error) {
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
store := sdkCtx.KVStore(capKey)
|
||||
|
||||
sdkCtx.GasMeter().ConsumeGas(5, "test")
|
||||
|
||||
var msgCount int64
|
||||
|
||||
switch m := msg.(type) {
|
||||
case *baseapptestutil.MsgCounter:
|
||||
if m.FailOnHandler {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "message handler failure")
|
||||
}
|
||||
msgCount = m.Counter
|
||||
case *baseapptestutil.MsgCounter2:
|
||||
if m.FailOnHandler {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "message handler failure")
|
||||
}
|
||||
msgCount = m.Counter
|
||||
}
|
||||
|
||||
sdkCtx.EventManager().EmitEvents(
|
||||
counterEvent(sdk.EventTypeMessage, msgCount),
|
||||
)
|
||||
|
||||
_, err := incrementingCounter(t, store, deliverKey, msgCount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &baseapptestutil.MsgCreateCounterResponse{}, nil
|
||||
}
|
||||
|
||||
func counterEvent(evType string, msgCount int64) sdk.Events {
|
||||
return sdk.Events{
|
||||
sdk.NewEvent(
|
||||
evType,
|
||||
sdk.NewAttribute("update_counter", fmt.Sprintf("%d", msgCount)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func anteHandlerTxTest(t *testing.T, capKey storetypes.StoreKey, storeKey []byte) sdk.AnteHandler {
|
||||
return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
|
||||
store := ctx.KVStore(capKey)
|
||||
counter, failOnAnte := parseTxMemo(t, tx)
|
||||
|
||||
if failOnAnte {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "ante handler failure")
|
||||
}
|
||||
|
||||
_, err := incrementingCounter(t, store, storeKey, counter)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
ctx.EventManager().EmitEvents(
|
||||
counterEvent("ante_handler", counter),
|
||||
)
|
||||
|
||||
ctx = ctx.WithPriority(testTxPriority)
|
||||
return ctx, nil
|
||||
}
|
||||
}
|
||||
|
||||
func incrementingCounter(t *testing.T, store sdk.KVStore, counterKey []byte, counter int64) (*sdk.Result, error) {
|
||||
storedCounter := getIntFromStore(t, store, counterKey)
|
||||
require.Equal(t, storedCounter, counter)
|
||||
setIntOnStore(store, counterKey, counter+1)
|
||||
return &sdk.Result{}, nil
|
||||
}
|
||||
|
||||
func setIntOnStore(store sdk.KVStore, key []byte, i int64) {
|
||||
bz := make([]byte, 8)
|
||||
n := binary.PutVarint(bz, i)
|
||||
store.Set(key, bz[:n])
|
||||
}
|
||||
|
||||
type paramStore struct {
|
||||
db *dbm.MemDB
|
||||
}
|
||||
|
||||
func (ps *paramStore) Set(_ sdk.Context, value *tmproto.ConsensusParams) {
|
||||
bz, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ps.db.Set(ParamStoreKey, bz)
|
||||
}
|
||||
|
||||
func (ps *paramStore) Has(_ sdk.Context) bool {
|
||||
ok, err := ps.db.Has(ParamStoreKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func (ps paramStore) Get(ctx sdk.Context) (*tmproto.ConsensusParams, error) {
|
||||
bz, err := ps.db.Get(ParamStoreKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(bz) == 0 {
|
||||
return nil, errors.New("params not found")
|
||||
}
|
||||
|
||||
var params tmproto.ConsensusParams
|
||||
if err := json.Unmarshal(bz, ¶ms); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return ¶ms, nil
|
||||
}
|
||||
|
||||
func setTxSignature(t *testing.T, builder client.TxBuilder, nonce uint64) {
|
||||
privKey := secp256k1.GenPrivKeyFromSecret([]byte("test"))
|
||||
pubKey := privKey.PubKey()
|
||||
err := builder.SetSignatures(
|
||||
signingtypes.SignatureV2{
|
||||
PubKey: pubKey,
|
||||
Sequence: nonce,
|
||||
Data: &signingtypes.SingleSignatureData{},
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func testLoadVersionHelper(t *testing.T, app *baseapp.BaseApp, expectedHeight int64, expectedID storetypes.CommitID) {
|
||||
lastHeight := app.LastBlockHeight()
|
||||
lastID := app.LastCommitID()
|
||||
require.Equal(t, expectedHeight, lastHeight)
|
||||
require.Equal(t, expectedID, lastID)
|
||||
}
|
||||
|
||||
func getCheckStateCtx(app *baseapp.BaseApp) sdk.Context {
|
||||
v := reflect.ValueOf(app).Elem()
|
||||
f := v.FieldByName("checkState")
|
||||
rf := reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem()
|
||||
return rf.MethodByName("Context").Call(nil)[0].Interface().(sdk.Context)
|
||||
}
|
||||
|
||||
func getDeliverStateCtx(app *baseapp.BaseApp) sdk.Context {
|
||||
v := reflect.ValueOf(app).Elem()
|
||||
f := v.FieldByName("deliverState")
|
||||
rf := reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem()
|
||||
return rf.MethodByName("Context").Call(nil)[0].Interface().(sdk.Context)
|
||||
}
|
||||
|
||||
func parseTxMemo(t *testing.T, tx sdk.Tx) (counter int64, failOnAnte bool) {
|
||||
txWithMemo, ok := tx.(sdk.TxWithMemo)
|
||||
require.True(t, ok)
|
||||
|
||||
memo := txWithMemo.GetMemo()
|
||||
vals, err := url.ParseQuery(memo)
|
||||
require.NoError(t, err)
|
||||
|
||||
counter, err = strconv.ParseInt(vals.Get("counter"), 10, 64)
|
||||
require.NoError(t, err)
|
||||
|
||||
failOnAnte = vals.Get("failOnAnte") == "true"
|
||||
return counter, failOnAnte
|
||||
}
|
||||
|
||||
func newTxCounter(t *testing.T, cfg client.TxConfig, counter int64, msgCounters ...int64) signing.Tx {
|
||||
msgs := make([]sdk.Msg, 0, len(msgCounters))
|
||||
for _, c := range msgCounters {
|
||||
msg := &baseapptestutil.MsgCounter{Counter: c, FailOnHandler: false}
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
|
||||
builder := cfg.NewTxBuilder()
|
||||
builder.SetMsgs(msgs...)
|
||||
builder.SetMemo("counter=" + strconv.FormatInt(counter, 10) + "&failOnAnte=false")
|
||||
setTxSignature(t, builder, uint64(counter))
|
||||
|
||||
return builder.GetTx()
|
||||
}
|
||||
|
||||
func getIntFromStore(t *testing.T, store sdk.KVStore, key []byte) int64 {
|
||||
bz := store.Get(key)
|
||||
if len(bz) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
i, err := binary.ReadVarint(bytes.NewBuffer(bz))
|
||||
require.NoError(t, err)
|
||||
|
||||
return i
|
||||
}
|
||||
|
||||
func setFailOnAnte(t *testing.T, cfg client.TxConfig, tx signing.Tx, failOnAnte bool) signing.Tx {
|
||||
builder := cfg.NewTxBuilder()
|
||||
builder.SetMsgs(tx.GetMsgs()...)
|
||||
|
||||
memo := tx.GetMemo()
|
||||
vals, err := url.ParseQuery(memo)
|
||||
require.NoError(t, err)
|
||||
|
||||
vals.Set("failOnAnte", strconv.FormatBool(failOnAnte))
|
||||
memo = vals.Encode()
|
||||
builder.SetMemo(memo)
|
||||
setTxSignature(t, builder, 1)
|
||||
|
||||
return builder.GetTx()
|
||||
}
|
||||
|
||||
func setFailOnHandler(cfg client.TxConfig, tx signing.Tx, fail bool) signing.Tx {
|
||||
builder := cfg.NewTxBuilder()
|
||||
builder.SetMemo(tx.GetMemo())
|
||||
|
||||
msgs := tx.GetMsgs()
|
||||
for i, msg := range msgs {
|
||||
msgs[i] = &baseapptestutil.MsgCounter{
|
||||
Counter: msg.(*baseapptestutil.MsgCounter).Counter,
|
||||
FailOnHandler: fail,
|
||||
}
|
||||
}
|
||||
|
||||
builder.SetMsgs(msgs...)
|
||||
return builder.GetTx()
|
||||
}
|
||||
+5
-12
@@ -7,13 +7,12 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
db "github.com/tendermint/tm-db"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
@@ -23,26 +22,22 @@ import (
|
||||
|
||||
// NewApp creates a simple mock kvstore app for testing. It should work
|
||||
// similar to a real app. Make sure rootDir is empty before running the test,
|
||||
// in order to guarantee consistent results
|
||||
// in order to guarantee consistent results.
|
||||
func NewApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
db, err := db.NewGoLevelDB("mock", filepath.Join(rootDir, "data"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Capabilities key to access the main KVStore.
|
||||
capKeyMainStore := sdk.NewKVStoreKey("main")
|
||||
|
||||
// Create BaseApp.
|
||||
baseApp := bam.NewBaseApp("kvstore", logger, db, decodeTx)
|
||||
|
||||
// Set mounts for BaseApp's MultiStore.
|
||||
baseApp.MountStores(capKeyMainStore)
|
||||
|
||||
baseApp.SetInitChainer(InitChainer(capKeyMainStore))
|
||||
|
||||
interfaceRegistry := codectypes.NewInterfaceRegistry()
|
||||
interfaceRegistry.RegisterImplementations((*sdk.Msg)(nil), &kvstoreTx{})
|
||||
|
||||
router := bam.NewMsgServiceRouter()
|
||||
router.SetInterfaceRegistry(interfaceRegistry)
|
||||
|
||||
@@ -59,7 +54,6 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
router.RegisterService(newDesc, &MsgServerImpl{capKeyMainStore})
|
||||
baseApp.SetMsgServiceRouter(router)
|
||||
|
||||
// Load latest version.
|
||||
if err := baseApp.LoadLatestVersion(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -68,7 +62,7 @@ func NewApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
}
|
||||
|
||||
// KVStoreHandler is a simple handler that takes kvstoreTx and writes
|
||||
// them to the db
|
||||
// them to the db.
|
||||
func KVStoreHandler(storeKey storetypes.StoreKey) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
||||
dTx, ok := msg.(*kvstoreTx)
|
||||
@@ -76,7 +70,6 @@ func KVStoreHandler(storeKey storetypes.StoreKey) sdk.Handler {
|
||||
return nil, errors.New("KVStoreHandler should only receive kvstoreTx")
|
||||
}
|
||||
|
||||
// tx is already unmarshalled
|
||||
key := dTx.key
|
||||
value := dTx.value
|
||||
|
||||
|
||||
+9
-12
@@ -5,30 +5,25 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
|
||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
)
|
||||
|
||||
// TestInitApp makes sure we can initialize this thing without an error
|
||||
func TestInitApp(t *testing.T) {
|
||||
// set up an app
|
||||
app, closer, err := SetupApp()
|
||||
|
||||
// closer may need to be run, even when error in later stage
|
||||
if closer != nil {
|
||||
defer closer()
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
// initialize it future-way
|
||||
appState, err := AppGenState(nil, types.GenesisDoc{}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// TODO test validators in the init chain?
|
||||
req := abci.RequestInitChain{
|
||||
AppStateBytes: appState,
|
||||
}
|
||||
@@ -40,14 +35,13 @@ func TestInitApp(t *testing.T) {
|
||||
Path: "/store/main/key",
|
||||
Data: []byte("foo"),
|
||||
}
|
||||
|
||||
qres := app.Query(query)
|
||||
require.Equal(t, uint32(0), qres.Code, qres.Log)
|
||||
require.Equal(t, []byte("bar"), qres.Value)
|
||||
}
|
||||
|
||||
// TextDeliverTx ensures we can write a tx
|
||||
func TestDeliverTx(t *testing.T) {
|
||||
// set up an app
|
||||
app, closer, err := SetupApp()
|
||||
// closer may need to be run, even when error in later stage
|
||||
if closer != nil {
|
||||
@@ -64,14 +58,16 @@ func TestDeliverTx(t *testing.T) {
|
||||
tx := NewTx(key, value, randomAccounts[0].Address)
|
||||
txBytes := tx.GetSignBytes()
|
||||
|
||||
header := tmproto.Header{
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{
|
||||
AppHash: []byte("apphash"),
|
||||
Height: 1,
|
||||
}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
}})
|
||||
|
||||
dres := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
|
||||
require.Equal(t, uint32(0), dres.Code, dres.Log)
|
||||
|
||||
app.EndBlock(abci.RequestEndBlock{})
|
||||
|
||||
cres := app.Commit()
|
||||
require.NotEmpty(t, cres.Data)
|
||||
|
||||
@@ -80,6 +76,7 @@ func TestDeliverTx(t *testing.T) {
|
||||
Path: "/store/main/key",
|
||||
Data: []byte(key),
|
||||
}
|
||||
|
||||
qres := app.Query(query)
|
||||
require.Equal(t, uint32(0), qres.Code, qres.Log)
|
||||
require.Equal(t, []byte(value), qres.Value)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
// SetupApp returns an application as well as a clean-up function
|
||||
// to be used to quickly setup a test case with an app
|
||||
// to be used to quickly setup a test case with an app.
|
||||
func SetupApp() (abci.Application, func(), error) {
|
||||
logger := tmlog.NewTMLogger(tmlog.NewSyncWriter(os.Stdout)).With("module", "mock")
|
||||
|
||||
|
||||
@@ -173,7 +173,6 @@ func (k Keeper) GranteeGrants(c context.Context, req *authz.QueryGranteeGrantsRe
|
||||
}, func() *authz.Grant {
|
||||
return &authz.Grant{}
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user