Skip to content

Commit e236607

Browse files
alexanderbezjackzampolin
authored andcommitted
Merge PR #3801: BaseApp Security Improvements
1 parent c57de3d commit e236607

File tree

13 files changed

+279
-106
lines changed

13 files changed

+279
-106
lines changed

PENDING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
* #3808 `gaiad` and `gaiacli` integration tests use ./build/ binaries.
4545

4646
### SDK
47+
* #3801 `baseapp` saftey improvements
4748

4849
### Tendermint
4950

baseapp/baseapp.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,25 @@ func (app *BaseApp) storeConsensusParams(consensusParams *abci.ConsensusParams)
287287
mainStore.Set(mainConsensusParamsKey, consensusParamsBz)
288288
}
289289

290-
// getMaximumBlockGas gets the maximum gas from the consensus params.
291-
func (app *BaseApp) getMaximumBlockGas() (maxGas uint64) {
290+
// getMaximumBlockGas gets the maximum gas from the consensus params. It panics
291+
// if maximum block gas is less than negative one and returns zero if negative
292+
// one.
293+
func (app *BaseApp) getMaximumBlockGas() uint64 {
292294
if app.consensusParams == nil || app.consensusParams.BlockSize == nil {
293295
return 0
294296
}
295-
return uint64(app.consensusParams.BlockSize.MaxGas)
297+
298+
maxGas := app.consensusParams.BlockSize.MaxGas
299+
switch {
300+
case maxGas < -1:
301+
panic(fmt.Sprintf("invalid maximum block gas: %d", maxGas))
302+
303+
case maxGas == -1:
304+
return 0
305+
306+
default:
307+
return uint64(maxGas)
308+
}
296309
}
297310

298311
// ----------------------------------------------------------------------------
@@ -510,6 +523,19 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
510523
}
511524
}
512525

526+
func (app *BaseApp) validateHeight(req abci.RequestBeginBlock) error {
527+
if req.Header.Height < 1 {
528+
return fmt.Errorf("invalid height: %d", req.Header.Height)
529+
}
530+
531+
prevHeight := app.LastBlockHeight()
532+
if req.Header.Height != prevHeight+1 {
533+
return fmt.Errorf("invalid height: %d; expected: %d", req.Header.Height, prevHeight+1)
534+
}
535+
536+
return nil
537+
}
538+
513539
// BeginBlock implements the ABCI application interface.
514540
func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) {
515541
if app.cms.TracingEnabled() {
@@ -518,6 +544,10 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
518544
))
519545
}
520546

547+
if err := app.validateHeight(req); err != nil {
548+
panic(err)
549+
}
550+
521551
// Initialize the DeliverTx state. If this is the first block, it should
522552
// already be initialized in InitChain. Otherwise app.deliverState will be
523553
// nil, since it is reset on Commit.

baseapp/baseapp_test.go

Lines changed: 82 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ func TestInitChainer(t *testing.T) {
296296
// stores are mounted and private members are set - sealing baseapp
297297
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
298298
require.Nil(t, err)
299+
require.Equal(t, int64(0), app.LastBlockHeight())
299300

300301
app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}"), ChainId: "test-chain-id"}) // must have valid JSON genesis file, even if empty
301302

@@ -308,6 +309,7 @@ func TestInitChainer(t *testing.T) {
308309

309310
app.Commit()
310311
res = app.Query(query)
312+
require.Equal(t, int64(1), app.LastBlockHeight())
311313
require.Equal(t, value, res.Value)
312314

313315
// reload app
@@ -316,14 +318,17 @@ func TestInitChainer(t *testing.T) {
316318
app.MountStores(capKey, capKey2)
317319
err = app.LoadLatestVersion(capKey) // needed to make stores non-nil
318320
require.Nil(t, err)
321+
require.Equal(t, int64(1), app.LastBlockHeight())
319322

320323
// ensure we can still query after reloading
321324
res = app.Query(query)
322325
require.Equal(t, value, res.Value)
323326

324327
// commit and ensure we can still query
325-
app.BeginBlock(abci.RequestBeginBlock{})
328+
header := abci.Header{Height: app.LastBlockHeight() + 1}
329+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
326330
app.Commit()
331+
327332
res = app.Query(query)
328333
require.Equal(t, value, res.Value)
329334
}
@@ -514,7 +519,6 @@ func TestCheckTx(t *testing.T) {
514519
app := setupBaseApp(t, anteOpt, routerOpt)
515520

516521
nTxs := int64(5)
517-
518522
app.InitChain(abci.RequestInitChain{})
519523

520524
// Create same codec used in txDecoder
@@ -536,7 +540,8 @@ func TestCheckTx(t *testing.T) {
536540
require.Equal(t, nTxs, storedCounter)
537541

538542
// If a block is committed, CheckTx state should be reset.
539-
app.BeginBlock(abci.RequestBeginBlock{})
543+
header := abci.Header{Height: 1}
544+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
540545
app.EndBlock(abci.RequestEndBlock{})
541546
app.Commit()
542547

@@ -567,16 +572,22 @@ func TestDeliverTx(t *testing.T) {
567572

568573
nBlocks := 3
569574
txPerHeight := 5
575+
570576
for blockN := 0; blockN < nBlocks; blockN++ {
571-
app.BeginBlock(abci.RequestBeginBlock{})
577+
header := abci.Header{Height: int64(blockN) + 1}
578+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
579+
572580
for i := 0; i < txPerHeight; i++ {
573581
counter := int64(blockN*txPerHeight + i)
574582
tx := newTxCounter(counter, counter)
583+
575584
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
576585
require.NoError(t, err)
586+
577587
res := app.DeliverTx(txBytes)
578588
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
579589
}
590+
580591
app.EndBlock(abci.RequestEndBlock{})
581592
app.Commit()
582593
}
@@ -610,48 +621,47 @@ func TestMultiMsgDeliverTx(t *testing.T) {
610621

611622
// run a multi-msg tx
612623
// with all msgs the same route
613-
{
614-
app.BeginBlock(abci.RequestBeginBlock{})
615-
tx := newTxCounter(0, 0, 1, 2)
616-
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
617-
require.NoError(t, err)
618-
res := app.DeliverTx(txBytes)
619-
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
620624

621-
store := app.deliverState.ctx.KVStore(capKey1)
625+
header := abci.Header{Height: 1}
626+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
627+
tx := newTxCounter(0, 0, 1, 2)
628+
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
629+
require.NoError(t, err)
630+
res := app.DeliverTx(txBytes)
631+
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
632+
633+
store := app.deliverState.ctx.KVStore(capKey1)
622634

623-
// tx counter only incremented once
624-
txCounter := getIntFromStore(store, anteKey)
625-
require.Equal(t, int64(1), txCounter)
635+
// tx counter only incremented once
636+
txCounter := getIntFromStore(store, anteKey)
637+
require.Equal(t, int64(1), txCounter)
626638

627-
// msg counter incremented three times
628-
msgCounter := getIntFromStore(store, deliverKey)
629-
require.Equal(t, int64(3), msgCounter)
630-
}
639+
// msg counter incremented three times
640+
msgCounter := getIntFromStore(store, deliverKey)
641+
require.Equal(t, int64(3), msgCounter)
631642

632643
// replace the second message with a msgCounter2
633-
{
634-
tx := newTxCounter(1, 3)
635-
tx.Msgs = append(tx.Msgs, msgCounter2{0})
636-
tx.Msgs = append(tx.Msgs, msgCounter2{1})
637-
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
638-
require.NoError(t, err)
639-
res := app.DeliverTx(txBytes)
640-
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
641644

642-
store := app.deliverState.ctx.KVStore(capKey1)
645+
tx = newTxCounter(1, 3)
646+
tx.Msgs = append(tx.Msgs, msgCounter2{0})
647+
tx.Msgs = append(tx.Msgs, msgCounter2{1})
648+
txBytes, err = codec.MarshalBinaryLengthPrefixed(tx)
649+
require.NoError(t, err)
650+
res = app.DeliverTx(txBytes)
651+
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
652+
653+
store = app.deliverState.ctx.KVStore(capKey1)
643654

644-
// tx counter only incremented once
645-
txCounter := getIntFromStore(store, anteKey)
646-
require.Equal(t, int64(2), txCounter)
655+
// tx counter only incremented once
656+
txCounter = getIntFromStore(store, anteKey)
657+
require.Equal(t, int64(2), txCounter)
647658

648-
// original counter increments by one
649-
// new counter increments by two
650-
msgCounter := getIntFromStore(store, deliverKey)
651-
require.Equal(t, int64(4), msgCounter)
652-
msgCounter2 := getIntFromStore(store, deliverKey2)
653-
require.Equal(t, int64(2), msgCounter2)
654-
}
659+
// original counter increments by one
660+
// new counter increments by two
661+
msgCounter = getIntFromStore(store, deliverKey)
662+
require.Equal(t, int64(4), msgCounter)
663+
msgCounter2 := getIntFromStore(store, deliverKey2)
664+
require.Equal(t, int64(2), msgCounter2)
655665
}
656666

657667
// Interleave calls to Check and Deliver and ensure
@@ -692,7 +702,8 @@ func TestSimulateTx(t *testing.T) {
692702
nBlocks := 3
693703
for blockN := 0; blockN < nBlocks; blockN++ {
694704
count := int64(blockN + 1)
695-
app.BeginBlock(abci.RequestBeginBlock{})
705+
header := abci.Header{Height: count}
706+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
696707

697708
tx := newTxCounter(count, count)
698709
txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx)
@@ -737,7 +748,9 @@ func TestRunInvalidTransaction(t *testing.T) {
737748
}
738749

739750
app := setupBaseApp(t, anteOpt, routerOpt)
740-
app.BeginBlock(abci.RequestBeginBlock{})
751+
752+
header := abci.Header{Height: 1}
753+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
741754

742755
// Transaction with no messages
743756
{
@@ -847,7 +860,8 @@ func TestTxGasLimits(t *testing.T) {
847860

848861
app := setupBaseApp(t, anteOpt, routerOpt)
849862

850-
app.BeginBlock(abci.RequestBeginBlock{})
863+
header := abci.Header{Height: 1}
864+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
851865

852866
testCases := []struct {
853867
tx *txTest
@@ -962,7 +976,8 @@ func TestMaxBlockGasLimits(t *testing.T) {
962976
tx := tc.tx
963977

964978
// reset the block gas
965-
app.BeginBlock(abci.RequestBeginBlock{})
979+
header := abci.Header{Height: app.LastBlockHeight() + 1}
980+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
966981

967982
// execute the transaction multiple times
968983
for j := 0; j < tc.numDelivers; j++ {
@@ -1005,7 +1020,9 @@ func TestBaseAppAnteHandler(t *testing.T) {
10051020

10061021
app.InitChain(abci.RequestInitChain{})
10071022
registerTestCodec(cdc)
1008-
app.BeginBlock(abci.RequestBeginBlock{})
1023+
1024+
header := abci.Header{Height: app.LastBlockHeight() + 1}
1025+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
10091026

10101027
// execute a tx that will fail ante handler execution
10111028
//
@@ -1112,7 +1129,9 @@ func TestGasConsumptionBadTx(t *testing.T) {
11121129
})
11131130

11141131
app.InitChain(abci.RequestInitChain{})
1115-
app.BeginBlock(abci.RequestBeginBlock{})
1132+
1133+
header := abci.Header{Height: app.LastBlockHeight() + 1}
1134+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
11161135

11171136
tx := newTxCounter(5, 0)
11181137
tx.setFailOnAnte(true)
@@ -1174,7 +1193,9 @@ func TestQuery(t *testing.T) {
11741193
require.Equal(t, 0, len(res.Value))
11751194

11761195
// query is still empty after a DeliverTx before we commit
1177-
app.BeginBlock(abci.RequestBeginBlock{})
1196+
header := abci.Header{Height: app.LastBlockHeight() + 1}
1197+
app.BeginBlock(abci.RequestBeginBlock{Header: header})
1198+
11781199
resTx = app.Deliver(tx)
11791200
require.True(t, resTx.IsOK(), fmt.Sprintf("%v", resTx))
11801201
res = app.Query(query)
@@ -1216,3 +1237,19 @@ func TestP2PQuery(t *testing.T) {
12161237
res = app.Query(idQuery)
12171238
require.Equal(t, uint32(4), res.Code)
12181239
}
1240+
1241+
func TestGetMaximumBlockGas(t *testing.T) {
1242+
app := setupBaseApp(t)
1243+
1244+
app.setConsensusParams(&abci.ConsensusParams{BlockSize: &abci.BlockSizeParams{MaxGas: 0}})
1245+
require.Equal(t, uint64(0), app.getMaximumBlockGas())
1246+
1247+
app.setConsensusParams(&abci.ConsensusParams{BlockSize: &abci.BlockSizeParams{MaxGas: -1}})
1248+
require.Equal(t, uint64(0), app.getMaximumBlockGas())
1249+
1250+
app.setConsensusParams(&abci.ConsensusParams{BlockSize: &abci.BlockSizeParams{MaxGas: 5000000}})
1251+
require.Equal(t, uint64(5000000), app.getMaximumBlockGas())
1252+
1253+
app.setConsensusParams(&abci.ConsensusParams{BlockSize: &abci.BlockSizeParams{MaxGas: -5000000}})
1254+
require.Panics(t, func() { app.getMaximumBlockGas() })
1255+
}

x/bank/app_test.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ func TestSendNotEnoughBalance(t *testing.T) {
123123
origSeq := res1.GetSequence()
124124

125125
sendMsg := NewMsgSend(addr1, addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)})
126-
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{sendMsg}, []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1)
126+
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
127+
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{sendMsg}, []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1)
127128

128129
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)})
129130

@@ -173,7 +174,8 @@ func TestMsgMultiSendWithAccounts(t *testing.T) {
173174
}
174175

175176
for _, tc := range testCases {
176-
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
177+
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
178+
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
177179

178180
for _, eb := range tc.expectedBalances {
179181
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
@@ -212,7 +214,8 @@ func TestMsgMultiSendMultipleOut(t *testing.T) {
212214
}
213215

214216
for _, tc := range testCases {
215-
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
217+
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
218+
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
216219

217220
for _, eb := range tc.expectedBalances {
218221
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
@@ -241,7 +244,7 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) {
241244
testCases := []appTestCase{
242245
{
243246
msgs: []sdk.Msg{multiSendMsg3},
244-
accNums: []uint64{0, 0},
247+
accNums: []uint64{0, 2},
245248
accSeqs: []uint64{0, 0},
246249
expSimPass: true,
247250
expPass: true,
@@ -256,7 +259,8 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) {
256259
}
257260

258261
for _, tc := range testCases {
259-
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
262+
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
263+
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
260264

261265
for _, eb := range tc.expectedBalances {
262266
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
@@ -289,7 +293,7 @@ func TestMsgMultiSendDependent(t *testing.T) {
289293
},
290294
{
291295
msgs: []sdk.Msg{multiSendMsg4},
292-
accNums: []uint64{0},
296+
accNums: []uint64{1},
293297
accSeqs: []uint64{0},
294298
expSimPass: true,
295299
expPass: true,
@@ -301,7 +305,8 @@ func TestMsgMultiSendDependent(t *testing.T) {
301305
}
302306

303307
for _, tc := range testCases {
304-
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
308+
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
309+
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
305310

306311
for _, eb := range tc.expectedBalances {
307312
mock.CheckBalance(t, mapp, eb.addr, eb.coins)

0 commit comments

Comments
 (0)