github.com/Finschia/finschia-sdk@v0.48.1/baseapp/deliver_tx_test.go (about) 1 package baseapp 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "math/rand" 8 "os" 9 "strings" 10 "sync" 11 "testing" 12 "time" 13 14 "github.com/gogo/protobuf/jsonpb" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 abci "github.com/tendermint/tendermint/abci/types" 18 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 19 dbm "github.com/tendermint/tm-db" 20 21 ocabci "github.com/Finschia/ostracon/abci/types" 22 "github.com/Finschia/ostracon/libs/log" 23 24 "github.com/Finschia/finschia-sdk/codec" 25 "github.com/Finschia/finschia-sdk/snapshots" 26 snapshottypes "github.com/Finschia/finschia-sdk/snapshots/types" 27 "github.com/Finschia/finschia-sdk/store/rootmulti" 28 store "github.com/Finschia/finschia-sdk/store/types" 29 "github.com/Finschia/finschia-sdk/testutil/testdata" 30 sdk "github.com/Finschia/finschia-sdk/types" 31 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 32 ) 33 34 func TestLoadSnapshotChunk(t *testing.T) { 35 app, teardown := setupBaseAppWithSnapshots(t, 2, 5) 36 defer teardown() 37 38 testcases := map[string]struct { 39 height uint64 40 format uint32 41 chunk uint32 42 expectEmpty bool 43 }{ 44 "Existing snapshot": {2, 1, 1, false}, 45 "Missing height": {100, 1, 1, true}, 46 "Missing format": {2, 2, 1, true}, 47 "Missing chunk": {2, 1, 9, true}, 48 "Zero height": {0, 1, 1, true}, 49 "Zero format": {2, 0, 1, true}, 50 "Zero chunk": {2, 1, 0, false}, 51 } 52 for name, tc := range testcases { 53 tc := tc 54 t.Run(name, func(t *testing.T) { 55 resp := app.LoadSnapshotChunk(abci.RequestLoadSnapshotChunk{ 56 Height: tc.height, 57 Format: tc.format, 58 Chunk: tc.chunk, 59 }) 60 if tc.expectEmpty { 61 assert.Equal(t, abci.ResponseLoadSnapshotChunk{}, resp) 62 return 63 } 64 assert.NotEmpty(t, resp.Chunk) 65 }) 66 } 67 } 68 69 func TestOfferSnapshot_Errors(t *testing.T) { 70 // Set up app before test cases, since it's fairly expensive. 71 app, teardown := setupBaseAppWithSnapshots(t, 0, 0) 72 defer teardown() 73 74 m := snapshottypes.Metadata{ChunkHashes: [][]byte{{1}, {2}, {3}}} 75 metadata, err := m.Marshal() 76 require.NoError(t, err) 77 hash := []byte{1, 2, 3} 78 79 testcases := map[string]struct { 80 snapshot *abci.Snapshot 81 result abci.ResponseOfferSnapshot_Result 82 }{ 83 "nil snapshot": {nil, abci.ResponseOfferSnapshot_REJECT}, 84 "invalid format": {&abci.Snapshot{ 85 Height: 1, Format: 9, Chunks: 3, Hash: hash, Metadata: metadata, 86 }, abci.ResponseOfferSnapshot_REJECT_FORMAT}, 87 "incorrect chunk count": {&abci.Snapshot{ 88 Height: 1, Format: 1, Chunks: 2, Hash: hash, Metadata: metadata, 89 }, abci.ResponseOfferSnapshot_REJECT}, 90 "no chunks": {&abci.Snapshot{ 91 Height: 1, Format: 1, Chunks: 0, Hash: hash, Metadata: metadata, 92 }, abci.ResponseOfferSnapshot_REJECT}, 93 "invalid metadata serialization": {&abci.Snapshot{ 94 Height: 1, Format: 1, Chunks: 0, Hash: hash, Metadata: []byte{3, 1, 4}, 95 }, abci.ResponseOfferSnapshot_REJECT}, 96 } 97 for name, tc := range testcases { 98 tc := tc 99 t.Run(name, func(t *testing.T) { 100 resp := app.OfferSnapshot(abci.RequestOfferSnapshot{Snapshot: tc.snapshot}) 101 assert.Equal(t, tc.result, resp.Result) 102 }) 103 } 104 105 // Offering a snapshot after one has been accepted should error 106 resp := app.OfferSnapshot(abci.RequestOfferSnapshot{Snapshot: &abci.Snapshot{ 107 Height: 1, 108 Format: snapshottypes.CurrentFormat, 109 Chunks: 3, 110 Hash: []byte{1, 2, 3}, 111 Metadata: metadata, 112 }}) 113 require.Equal(t, abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ACCEPT}, resp) 114 115 resp = app.OfferSnapshot(abci.RequestOfferSnapshot{Snapshot: &abci.Snapshot{ 116 Height: 2, 117 Format: snapshottypes.CurrentFormat, 118 Chunks: 3, 119 Hash: []byte{1, 2, 3}, 120 Metadata: metadata, 121 }}) 122 require.Equal(t, abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT}, resp) 123 } 124 125 func TestApplySnapshotChunk(t *testing.T) { 126 source, teardown := setupBaseAppWithSnapshots(t, 4, 10) 127 defer teardown() 128 129 target, teardown := setupBaseAppWithSnapshots(t, 0, 0) 130 defer teardown() 131 132 // Fetch latest snapshot to restore 133 respList := source.ListSnapshots(abci.RequestListSnapshots{}) 134 require.NotEmpty(t, respList.Snapshots) 135 snapshot := respList.Snapshots[0] 136 137 // Make sure the snapshot has at least 3 chunks 138 require.GreaterOrEqual(t, snapshot.Chunks, uint32(3), "Not enough snapshot chunks") 139 140 // Begin a snapshot restoration in the target 141 respOffer := target.OfferSnapshot(abci.RequestOfferSnapshot{Snapshot: snapshot}) 142 require.Equal(t, abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ACCEPT}, respOffer) 143 144 // We should be able to pass an invalid chunk and get a verify failure, before reapplying it. 145 respApply := target.ApplySnapshotChunk(abci.RequestApplySnapshotChunk{ 146 Index: 0, 147 Chunk: []byte{9}, 148 Sender: "sender", 149 }) 150 require.Equal(t, abci.ResponseApplySnapshotChunk{ 151 Result: abci.ResponseApplySnapshotChunk_RETRY, 152 RefetchChunks: []uint32{0}, 153 RejectSenders: []string{"sender"}, 154 }, respApply) 155 156 // Fetch each chunk from the source and apply it to the target 157 for index := uint32(0); index < snapshot.Chunks; index++ { 158 respChunk := source.LoadSnapshotChunk(abci.RequestLoadSnapshotChunk{ 159 Height: snapshot.Height, 160 Format: snapshot.Format, 161 Chunk: index, 162 }) 163 require.NotNil(t, respChunk.Chunk) 164 respApply := target.ApplySnapshotChunk(abci.RequestApplySnapshotChunk{ 165 Index: index, 166 Chunk: respChunk.Chunk, 167 }) 168 require.Equal(t, abci.ResponseApplySnapshotChunk{ 169 Result: abci.ResponseApplySnapshotChunk_ACCEPT, 170 }, respApply) 171 } 172 173 // The target should now have the same hash as the source 174 assert.Equal(t, source.LastCommitID(), target.LastCommitID()) 175 } 176 177 // NOTE: represents a new custom router for testing purposes of WithRouter() 178 type testCustomRouter struct { 179 routes sync.Map 180 } 181 182 func (rtr *testCustomRouter) AddRoute(route sdk.Route) sdk.Router { 183 rtr.routes.Store(route.Path(), route.Handler()) 184 return rtr 185 } 186 187 func (rtr *testCustomRouter) Route(ctx sdk.Context, path string) sdk.Handler { 188 if v, ok := rtr.routes.Load(path); ok { 189 if h, ok := v.(sdk.Handler); ok { 190 return h 191 } 192 } 193 return nil 194 } 195 196 func TestWithRouter(t *testing.T) { 197 // test increments in the ante 198 anteKey := []byte("ante-key") 199 anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) } 200 201 // test increments in the handler 202 deliverKey := []byte("deliver-key") 203 routerOpt := func(bapp *BaseApp) { 204 bapp.SetRouter(&testCustomRouter{routes: sync.Map{}}) 205 r := sdk.NewRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey)) 206 bapp.Router().AddRoute(r) 207 } 208 209 app := setupBaseApp(t, anteOpt, routerOpt) 210 app.InitChain(abci.RequestInitChain{}) 211 212 // Create same codec used in txDecoder 213 codec := codec.NewLegacyAmino() 214 registerTestCodec(codec) 215 216 nBlocks := 3 217 txPerHeight := 5 218 219 for blockN := 0; blockN < nBlocks; blockN++ { 220 header := tmproto.Header{Height: int64(blockN) + 1} 221 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 222 223 for i := 0; i < txPerHeight; i++ { 224 counter := int64(blockN*txPerHeight + i) 225 tx := newTxCounter(counter, counter) 226 227 txBytes, err := codec.Marshal(tx) 228 require.NoError(t, err) 229 230 res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 231 require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) 232 } 233 234 app.EndBlock(abci.RequestEndBlock{}) 235 app.Commit() 236 } 237 } 238 239 func TestBaseApp_EndBlock(t *testing.T) { 240 db := dbm.NewMemDB() 241 name := t.Name() 242 logger := defaultLogger() 243 244 cp := &abci.ConsensusParams{ 245 Block: &abci.BlockParams{ 246 MaxGas: 5000000, 247 }, 248 } 249 250 app := NewBaseApp(name, logger, db, nil) 251 app.SetParamStore(¶mStore{db: dbm.NewMemDB()}) 252 app.InitChain(abci.RequestInitChain{ 253 ConsensusParams: cp, 254 }) 255 256 app.SetEndBlocker(func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { 257 return abci.ResponseEndBlock{ 258 ValidatorUpdates: []abci.ValidatorUpdate{ 259 {Power: 100}, 260 }, 261 } 262 }) 263 app.Seal() 264 265 res := app.EndBlock(abci.RequestEndBlock{}) 266 require.Len(t, res.GetValidatorUpdates(), 1) 267 require.Equal(t, int64(100), res.GetValidatorUpdates()[0].Power) 268 require.Equal(t, cp.Block.MaxGas, res.ConsensusParamUpdates.Block.MaxGas) 269 } 270 271 // Test that we can only query from the latest committed state. 272 func TestQuery(t *testing.T) { 273 key, value := []byte("hello"), []byte("goodbye") 274 anteOpt := func(bapp *BaseApp) { 275 bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { 276 store := ctx.KVStore(capKey1) 277 store.Set(key, value) 278 return 279 }) 280 } 281 282 routerOpt := func(bapp *BaseApp) { 283 r := sdk.NewRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 284 store := ctx.KVStore(capKey1) 285 store.Set(key, value) 286 return &sdk.Result{}, nil 287 }) 288 bapp.Router().AddRoute(r) 289 } 290 291 app := setupBaseApp(t, anteOpt, routerOpt) 292 293 app.InitChain(abci.RequestInitChain{}) 294 295 // NOTE: "/store/key1" tells us KVStore 296 // and the final "/key" says to use the data as the 297 // key in the given KVStore ... 298 query := abci.RequestQuery{ 299 Path: "/store/key1/key", 300 Data: key, 301 } 302 tx := newTxCounter(0, 0) 303 304 // query is empty before we do anything 305 res := app.Query(query) 306 require.Equal(t, 0, len(res.Value)) 307 308 // query is still empty after a CheckTx 309 _, err := app.Check(aminoTxEncoder(), tx) 310 require.NoError(t, err) 311 res = app.Query(query) 312 require.Equal(t, 0, len(res.Value)) 313 314 // query is still empty after a DeliverTx before we commit 315 header := tmproto.Header{Height: app.LastBlockHeight() + 1} 316 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 317 318 _, resTx, err := app.Deliver(aminoTxEncoder(), tx) 319 require.NoError(t, err) 320 require.NotNil(t, resTx) 321 res = app.Query(query) 322 require.Equal(t, 0, len(res.Value)) 323 324 // query returns correct value after Commit 325 app.Commit() 326 res = app.Query(query) 327 require.Equal(t, value, res.Value) 328 } 329 330 func TestGRPCQuery(t *testing.T) { 331 grpcQueryOpt := func(bapp *BaseApp) { 332 testdata.RegisterQueryServer( 333 bapp.GRPCQueryRouter(), 334 testdata.QueryImpl{}, 335 ) 336 } 337 338 app := setupBaseApp(t, grpcQueryOpt) 339 340 app.InitChain(abci.RequestInitChain{}) 341 header := tmproto.Header{Height: app.LastBlockHeight() + 1} 342 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 343 app.Commit() 344 345 req := testdata.SayHelloRequest{Name: "foo"} 346 reqBz, err := req.Marshal() 347 require.NoError(t, err) 348 349 reqQuery := abci.RequestQuery{ 350 Data: reqBz, 351 Path: "/testdata.Query/SayHello", 352 } 353 354 resQuery := app.Query(reqQuery) 355 356 require.Equal(t, abci.CodeTypeOK, resQuery.Code, resQuery) 357 358 var res testdata.SayHelloResponse 359 err = res.Unmarshal(resQuery.Value) 360 require.NoError(t, err) 361 require.Equal(t, "Hello foo!", res.Greeting) 362 } 363 364 // Test p2p filter queries 365 func TestP2PQuery(t *testing.T) { 366 addrPeerFilterOpt := func(bapp *BaseApp) { 367 bapp.SetAddrPeerFilter(func(addrport string) abci.ResponseQuery { 368 require.Equal(t, "1.1.1.1:8000", addrport) 369 return abci.ResponseQuery{Code: uint32(3)} 370 }) 371 } 372 373 idPeerFilterOpt := func(bapp *BaseApp) { 374 bapp.SetIDPeerFilter(func(id string) abci.ResponseQuery { 375 require.Equal(t, "testid", id) 376 return abci.ResponseQuery{Code: uint32(4)} 377 }) 378 } 379 380 app := setupBaseApp(t, addrPeerFilterOpt, idPeerFilterOpt) 381 382 addrQuery := abci.RequestQuery{ 383 Path: "/p2p/filter/addr/1.1.1.1:8000", 384 } 385 res := app.Query(addrQuery) 386 require.Equal(t, uint32(3), res.Code) 387 388 idQuery := abci.RequestQuery{ 389 Path: "/p2p/filter/id/testid", 390 } 391 res = app.Query(idQuery) 392 require.Equal(t, uint32(4), res.Code) 393 } 394 395 // One call to DeliverTx should process all the messages, in order. 396 func TestMultiMsgDeliverTx(t *testing.T) { 397 // increment the tx counter 398 anteKey := []byte("ante-key") 399 anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) } 400 401 // increment the msg counter 402 deliverKey := []byte("deliver-key") 403 deliverKey2 := []byte("deliver-key2") 404 routerOpt := func(bapp *BaseApp) { 405 r1 := sdk.NewRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey)) 406 r2 := sdk.NewRoute(routeMsgCounter2, handlerMsgCounter(t, capKey1, deliverKey2)) 407 bapp.Router().AddRoute(r1) 408 bapp.Router().AddRoute(r2) 409 } 410 411 app := setupBaseApp(t, anteOpt, routerOpt) 412 413 // Create same codec used in txDecoder 414 codec := codec.NewLegacyAmino() 415 registerTestCodec(codec) 416 417 // run a multi-msg tx 418 // with all msgs the same route 419 420 header := tmproto.Header{Height: 1} 421 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 422 tx := newTxCounter(0, 0, 1, 2) 423 txBytes, err := codec.Marshal(tx) 424 require.NoError(t, err) 425 res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 426 require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) 427 428 store := app.deliverState.ctx.KVStore(capKey1) 429 430 // tx counter only incremented once 431 txCounter := getIntFromStore(store, anteKey) 432 require.Equal(t, int64(1), txCounter) 433 434 // msg counter incremented three times 435 msgCounter := getIntFromStore(store, deliverKey) 436 require.Equal(t, int64(3), msgCounter) 437 438 // replace the second message with a msgCounter2 439 440 tx = newTxCounter(1, 3) 441 tx.Msgs = append(tx.Msgs, msgCounter2{0}) 442 tx.Msgs = append(tx.Msgs, msgCounter2{1}) 443 txBytes, err = codec.Marshal(tx) 444 require.NoError(t, err) 445 res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 446 require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) 447 448 store = app.deliverState.ctx.KVStore(capKey1) 449 450 // tx counter only incremented once 451 txCounter = getIntFromStore(store, anteKey) 452 require.Equal(t, int64(2), txCounter) 453 454 // original counter increments by one 455 // new counter increments by two 456 msgCounter = getIntFromStore(store, deliverKey) 457 require.Equal(t, int64(4), msgCounter) 458 msgCounter2 := getIntFromStore(store, deliverKey2) 459 require.Equal(t, int64(2), msgCounter2) 460 } 461 462 // Interleave calls to Check and Deliver and ensure 463 // that there is no cross-talk. Check sees results of the previous Check calls 464 // and Deliver sees that of the previous Deliver calls, but they don't see eachother. 465 func TestConcurrentCheckDeliver(t *testing.T) { 466 // TODO 467 } 468 469 // Simulate a transaction that uses gas to compute the gas. 470 // Simulate() and Query("/app/simulate", txBytes) should give 471 // the same results. 472 func TestSimulateTx(t *testing.T) { 473 gasConsumed := uint64(5) 474 475 anteOpt := func(bapp *BaseApp) { 476 bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { 477 newCtx = ctx.WithGasMeter(sdk.NewGasMeter(gasConsumed)) 478 return 479 }) 480 } 481 482 routerOpt := func(bapp *BaseApp) { 483 r := sdk.NewRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 484 ctx.GasMeter().ConsumeGas(gasConsumed, "test") 485 return &sdk.Result{}, nil 486 }) 487 bapp.Router().AddRoute(r) 488 } 489 490 app := setupBaseApp(t, anteOpt, routerOpt) 491 492 app.InitChain(abci.RequestInitChain{}) 493 494 // Create same codec used in txDecoder 495 cdc := codec.NewLegacyAmino() 496 registerTestCodec(cdc) 497 498 nBlocks := 3 499 for blockN := 0; blockN < nBlocks; blockN++ { 500 count := int64(blockN + 1) 501 header := tmproto.Header{Height: count} 502 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 503 504 tx := newTxCounter(count, count) 505 txBytes, err := cdc.Marshal(tx) 506 require.Nil(t, err) 507 508 // simulate a message, check gas reported 509 gInfo, result, err := app.Simulate(txBytes) 510 require.NoError(t, err) 511 require.NotNil(t, result) 512 require.Equal(t, gasConsumed, gInfo.GasUsed) 513 514 // simulate again, same result 515 gInfo, result, err = app.Simulate(txBytes) 516 require.NoError(t, err) 517 require.NotNil(t, result) 518 require.Equal(t, gasConsumed, gInfo.GasUsed) 519 520 // simulate by calling Query with encoded tx 521 query := abci.RequestQuery{ 522 Path: "/app/simulate", 523 Data: txBytes, 524 } 525 queryResult := app.Query(query) 526 require.True(t, queryResult.IsOK(), queryResult.Log) 527 528 var simRes sdk.SimulationResponse 529 require.NoError(t, jsonpb.Unmarshal(strings.NewReader(string(queryResult.Value)), &simRes)) 530 531 require.Equal(t, gInfo, simRes.GasInfo) 532 require.Equal(t, result.Log, simRes.Result.Log) 533 require.Equal(t, result.Events, simRes.Result.Events) 534 require.True(t, bytes.Equal(result.Data, simRes.Result.Data)) 535 536 app.EndBlock(abci.RequestEndBlock{}) 537 app.Commit() 538 } 539 } 540 541 func TestRunInvalidTransaction(t *testing.T) { 542 anteOpt := func(bapp *BaseApp) { 543 bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { 544 return 545 }) 546 } 547 routerOpt := func(bapp *BaseApp) { 548 r := sdk.NewRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 549 return &sdk.Result{}, nil 550 }) 551 bapp.Router().AddRoute(r) 552 } 553 554 app := setupBaseApp(t, anteOpt, routerOpt) 555 556 header := tmproto.Header{Height: 1} 557 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 558 559 // transaction with no messages 560 { 561 emptyTx := &txTest{} 562 _, result, err := app.Deliver(aminoTxEncoder(), emptyTx) 563 require.Error(t, err) 564 require.Nil(t, result) 565 566 space, code, _ := sdkerrors.ABCIInfo(err, false) 567 require.EqualValues(t, sdkerrors.ErrInvalidRequest.Codespace(), space, err) 568 require.EqualValues(t, sdkerrors.ErrInvalidRequest.ABCICode(), code, err) 569 } 570 571 // transaction where ValidateBasic fails 572 { 573 testCases := []struct { 574 tx *txTest 575 fail bool 576 }{ 577 {newTxCounter(0, 0), false}, 578 {newTxCounter(-1, 0), false}, 579 {newTxCounter(100, 100), false}, 580 {newTxCounter(100, 5, 4, 3, 2, 1), false}, 581 582 {newTxCounter(0, -1), true}, 583 {newTxCounter(0, 1, -2), true}, 584 {newTxCounter(0, 1, 2, -10, 5), true}, 585 } 586 587 for _, testCase := range testCases { 588 tx := testCase.tx 589 _, result, err := app.Deliver(aminoTxEncoder(), tx) 590 591 if testCase.fail { 592 require.Error(t, err) 593 594 space, code, _ := sdkerrors.ABCIInfo(err, false) 595 require.EqualValues(t, sdkerrors.ErrInvalidSequence.Codespace(), space, err) 596 require.EqualValues(t, sdkerrors.ErrInvalidSequence.ABCICode(), code, err) 597 } else { 598 require.NotNil(t, result) 599 } 600 } 601 } 602 603 // transaction with no known route 604 { 605 unknownRouteTx := txTest{[]sdk.Msg{msgNoRoute{}}, 0, false} 606 _, result, err := app.Deliver(aminoTxEncoder(), unknownRouteTx) 607 require.Error(t, err) 608 require.Nil(t, result) 609 610 space, code, _ := sdkerrors.ABCIInfo(err, false) 611 require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), space, err) 612 require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err) 613 614 unknownRouteTx = txTest{[]sdk.Msg{msgCounter{}, msgNoRoute{}}, 0, false} 615 _, result, err = app.Deliver(aminoTxEncoder(), unknownRouteTx) 616 require.Error(t, err) 617 require.Nil(t, result) 618 619 space, code, _ = sdkerrors.ABCIInfo(err, false) 620 require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), space, err) 621 require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err) 622 } 623 624 // Transaction with an unregistered message 625 { 626 tx := newTxCounter(0, 0) 627 tx.Msgs = append(tx.Msgs, msgNoDecode{}) 628 629 // new codec so we can encode the tx, but we shouldn't be able to decode 630 newCdc := codec.NewLegacyAmino() 631 registerTestCodec(newCdc) 632 newCdc.RegisterConcrete(&msgNoDecode{}, "cosmos-sdk/baseapp/msgNoDecode", nil) 633 634 txBytes, err := newCdc.Marshal(tx) 635 require.NoError(t, err) 636 637 res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 638 require.EqualValues(t, sdkerrors.ErrTxDecode.ABCICode(), res.Code) 639 require.EqualValues(t, sdkerrors.ErrTxDecode.Codespace(), res.Codespace) 640 } 641 } 642 643 // Test that transactions exceeding gas limits fail 644 func TestTxGasLimits(t *testing.T) { 645 gasGranted := uint64(10) 646 anteOpt := func(bapp *BaseApp) { 647 bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { 648 newCtx = ctx.WithGasMeter(sdk.NewGasMeter(gasGranted)) 649 650 // AnteHandlers must have their own defer/recover in order for the BaseApp 651 // to know how much gas was used! This is because the GasMeter is created in 652 // the AnteHandler, but if it panics the context won't be set properly in 653 // runTx's recover call. 654 defer func() { 655 if r := recover(); r != nil { 656 switch rType := r.(type) { 657 case sdk.ErrorOutOfGas: 658 err = sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, "out of gas in location: %v", rType.Descriptor) 659 default: 660 panic(r) 661 } 662 } 663 }() 664 665 count := tx.(*txTest).Counter 666 newCtx.GasMeter().ConsumeGas(uint64(count), "counter-ante") 667 668 return newCtx, nil 669 }) 670 } 671 672 routerOpt := func(bapp *BaseApp) { 673 r := sdk.NewRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 674 count := msg.(msgCounter).Counter 675 ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler") 676 return &sdk.Result{}, nil 677 }) 678 bapp.Router().AddRoute(r) 679 } 680 681 app := setupBaseApp(t, anteOpt, routerOpt) 682 683 header := tmproto.Header{Height: 1} 684 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 685 686 testCases := []struct { 687 tx *txTest 688 gasUsed uint64 689 fail bool 690 }{ 691 {newTxCounter(0, 0), 0, false}, 692 {newTxCounter(1, 1), 2, false}, 693 {newTxCounter(9, 1), 10, false}, 694 {newTxCounter(1, 9), 10, false}, 695 {newTxCounter(10, 0), 10, false}, 696 {newTxCounter(0, 10), 10, false}, 697 {newTxCounter(0, 8, 2), 10, false}, 698 {newTxCounter(0, 5, 1, 1, 1, 1, 1), 10, false}, 699 {newTxCounter(0, 5, 1, 1, 1, 1), 9, false}, 700 701 {newTxCounter(9, 2), 11, true}, 702 {newTxCounter(2, 9), 11, true}, 703 {newTxCounter(9, 1, 1), 11, true}, 704 {newTxCounter(1, 8, 1, 1), 11, true}, 705 {newTxCounter(11, 0), 11, true}, 706 {newTxCounter(0, 11), 11, true}, 707 {newTxCounter(0, 5, 11), 16, true}, 708 } 709 710 for i, tc := range testCases { 711 tx := tc.tx 712 gInfo, result, err := app.Deliver(aminoTxEncoder(), tx) 713 714 // check gas used and wanted 715 require.Equal(t, tc.gasUsed, gInfo.GasUsed, fmt.Sprintf("tc #%d; gas: %v, result: %v, err: %s", i, gInfo, result, err)) 716 717 // check for out of gas 718 if !tc.fail { 719 require.NotNil(t, result, fmt.Sprintf("%d: %v, %v", i, tc, err)) 720 } else { 721 require.Error(t, err) 722 require.Nil(t, result) 723 724 space, code, _ := sdkerrors.ABCIInfo(err, false) 725 require.EqualValues(t, sdkerrors.ErrOutOfGas.Codespace(), space, err) 726 require.EqualValues(t, sdkerrors.ErrOutOfGas.ABCICode(), code, err) 727 } 728 } 729 } 730 731 // Test that transactions exceeding gas limits fail 732 func TestMaxBlockGasLimits(t *testing.T) { 733 gasGranted := uint64(10) 734 anteOpt := func(bapp *BaseApp) { 735 bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { 736 newCtx = ctx.WithGasMeter(sdk.NewGasMeter(gasGranted)) 737 738 defer func() { 739 if r := recover(); r != nil { 740 switch rType := r.(type) { 741 case sdk.ErrorOutOfGas: 742 err = sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, "out of gas in location: %v", rType.Descriptor) 743 default: 744 panic(r) 745 } 746 } 747 }() 748 749 count := tx.(*txTest).Counter 750 newCtx.GasMeter().ConsumeGas(uint64(count), "counter-ante") 751 752 return 753 }) 754 } 755 756 routerOpt := func(bapp *BaseApp) { 757 r := sdk.NewRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 758 count := msg.(msgCounter).Counter 759 ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler") 760 return &sdk.Result{}, nil 761 }) 762 bapp.Router().AddRoute(r) 763 } 764 765 app := setupBaseApp(t, anteOpt, routerOpt) 766 app.InitChain(abci.RequestInitChain{ 767 ConsensusParams: &abci.ConsensusParams{ 768 Block: &abci.BlockParams{ 769 MaxGas: 100, 770 }, 771 }, 772 }) 773 774 testCases := []struct { 775 tx *txTest 776 numDelivers int 777 gasUsedPerDeliver uint64 778 fail bool 779 failAfterDeliver int 780 }{ 781 {newTxCounter(0, 0), 0, 0, false, 0}, 782 {newTxCounter(9, 1), 2, 10, false, 0}, 783 {newTxCounter(10, 0), 3, 10, false, 0}, 784 {newTxCounter(10, 0), 10, 10, false, 0}, 785 {newTxCounter(2, 7), 11, 9, false, 0}, 786 {newTxCounter(10, 0), 10, 10, false, 0}, // hit the limit but pass 787 788 {newTxCounter(10, 0), 11, 10, true, 10}, 789 {newTxCounter(10, 0), 15, 10, true, 10}, 790 {newTxCounter(9, 0), 12, 9, true, 11}, // fly past the limit 791 } 792 793 for i, tc := range testCases { 794 tx := tc.tx 795 796 // reset the block gas 797 header := tmproto.Header{Height: app.LastBlockHeight() + 1} 798 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 799 800 // execute the transaction multiple times 801 for j := 0; j < tc.numDelivers; j++ { 802 _, result, err := app.Deliver(aminoTxEncoder(), tx) 803 804 ctx := app.deliverState.ctx 805 806 // check for failed transactions 807 if tc.fail && (j+1) > tc.failAfterDeliver { 808 require.Error(t, err, fmt.Sprintf("tc #%d; result: %v, err: %s", i, result, err)) 809 require.Nil(t, result, fmt.Sprintf("tc #%d; result: %v, err: %s", i, result, err)) 810 811 space, code, _ := sdkerrors.ABCIInfo(err, false) 812 require.EqualValues(t, sdkerrors.ErrOutOfGas.Codespace(), space, err) 813 require.EqualValues(t, sdkerrors.ErrOutOfGas.ABCICode(), code, err) 814 require.True(t, ctx.BlockGasMeter().IsOutOfGas()) 815 } else { 816 // check gas used and wanted 817 blockGasUsed := ctx.BlockGasMeter().GasConsumed() 818 expBlockGasUsed := tc.gasUsedPerDeliver * uint64(j+1) 819 require.Equal( 820 t, expBlockGasUsed, blockGasUsed, 821 fmt.Sprintf("%d,%d: %v, %v, %v, %v", i, j, tc, expBlockGasUsed, blockGasUsed, result), 822 ) 823 824 require.NotNil(t, result, fmt.Sprintf("tc #%d; currDeliver: %d, result: %v, err: %s", i, j, result, err)) 825 require.False(t, ctx.BlockGasMeter().IsPastLimit()) 826 } 827 } 828 } 829 } 830 831 // Test custom panic handling within app.DeliverTx method 832 func TestCustomRunTxPanicHandler(t *testing.T) { 833 const customPanicMsg = "test panic" 834 anteErr := sdkerrors.Register("fakeModule", 100500, "fakeError") 835 836 anteOpt := func(bapp *BaseApp) { 837 bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { 838 panic(sdkerrors.Wrap(anteErr, "anteHandler")) 839 }) 840 } 841 routerOpt := func(bapp *BaseApp) { 842 r := sdk.NewRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 843 return &sdk.Result{}, nil 844 }) 845 bapp.Router().AddRoute(r) 846 } 847 848 app := setupBaseApp(t, anteOpt, routerOpt) 849 850 header := tmproto.Header{Height: 1} 851 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 852 853 app.AddRunTxRecoveryHandler(func(recoveryObj interface{}) error { 854 err, ok := recoveryObj.(error) 855 if !ok { 856 return nil 857 } 858 859 if anteErr.Is(err) { 860 panic(customPanicMsg) 861 } else { 862 return nil 863 } 864 }) 865 866 // Transaction should panic with custom handler above 867 { 868 tx := newTxCounter(0, 0) 869 870 require.PanicsWithValue(t, customPanicMsg, func() { app.Deliver(aminoTxEncoder(), tx) }) 871 } 872 } 873 874 func TestBaseAppAnteHandler(t *testing.T) { 875 anteKey := []byte("ante-key") 876 anteOpt := func(bapp *BaseApp) { 877 bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) 878 } 879 880 deliverKey := []byte("deliver-key") 881 routerOpt := func(bapp *BaseApp) { 882 r := sdk.NewRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey)) 883 bapp.Router().AddRoute(r) 884 } 885 886 cdc := codec.NewLegacyAmino() 887 app := setupBaseApp(t, anteOpt, routerOpt) 888 889 app.InitChain(abci.RequestInitChain{}) 890 registerTestCodec(cdc) 891 892 header := tmproto.Header{Height: app.LastBlockHeight() + 1} 893 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 894 895 // execute a tx that will fail ante handler execution 896 // 897 // NOTE: State should not be mutated here. This will be implicitly checked by 898 // the next txs ante handler execution (anteHandlerTxTest). 899 tx := newTxCounter(0, 0) 900 tx.setFailOnAnte(true) 901 txBytes, err := cdc.Marshal(tx) 902 require.NoError(t, err) 903 res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 904 require.Empty(t, res.Events) 905 require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) 906 907 ctx := app.deliverState.ctx 908 store := ctx.KVStore(capKey1) 909 require.Equal(t, int64(0), getIntFromStore(store, anteKey)) 910 911 // execute at tx that will pass the ante handler (the checkTx state should 912 // mutate) but will fail the message handler 913 tx = newTxCounter(0, 0) 914 tx.setFailOnHandler(true) 915 916 txBytes, err = cdc.Marshal(tx) 917 require.NoError(t, err) 918 919 res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 920 // should emit ante event 921 require.NotEmpty(t, res.Events) 922 require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) 923 924 ctx = app.deliverState.ctx 925 store = ctx.KVStore(capKey1) 926 require.Equal(t, int64(1), getIntFromStore(store, anteKey)) 927 require.Equal(t, int64(0), getIntFromStore(store, deliverKey)) 928 929 // execute a successful ante handler and message execution where state is 930 // implicitly checked by previous tx executions 931 tx = newTxCounter(1, 0) 932 933 txBytes, err = cdc.Marshal(tx) 934 require.NoError(t, err) 935 936 res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 937 require.NotEmpty(t, res.Events) 938 require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) 939 940 ctx = app.deliverState.ctx 941 store = ctx.KVStore(capKey1) 942 require.Equal(t, int64(2), getIntFromStore(store, anteKey)) 943 require.Equal(t, int64(1), getIntFromStore(store, deliverKey)) 944 945 // commit 946 app.EndBlock(abci.RequestEndBlock{}) 947 app.Commit() 948 } 949 950 func TestGasConsumptionBadTx(t *testing.T) { 951 gasWanted := uint64(5) 952 anteOpt := func(bapp *BaseApp) { 953 bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { 954 newCtx = ctx.WithGasMeter(sdk.NewGasMeter(gasWanted)) 955 956 defer func() { 957 if r := recover(); r != nil { 958 switch rType := r.(type) { 959 case sdk.ErrorOutOfGas: 960 log := fmt.Sprintf("out of gas in location: %v", rType.Descriptor) 961 err = sdkerrors.Wrap(sdkerrors.ErrOutOfGas, log) 962 default: 963 panic(r) 964 } 965 } 966 }() 967 968 txTest := tx.(*txTest) 969 newCtx.GasMeter().ConsumeGas(uint64(txTest.Counter), "counter-ante") 970 if txTest.FailOnAnte { 971 return newCtx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "ante handler failure") 972 } 973 974 return 975 }) 976 } 977 978 routerOpt := func(bapp *BaseApp) { 979 r := sdk.NewRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 980 count := msg.(*msgCounter).Counter 981 ctx.GasMeter().ConsumeGas(uint64(count), "counter-handler") 982 return &sdk.Result{}, nil 983 }) 984 bapp.Router().AddRoute(r) 985 } 986 987 cdc := codec.NewLegacyAmino() 988 registerTestCodec(cdc) 989 990 app := setupBaseApp(t, anteOpt, routerOpt) 991 app.InitChain(abci.RequestInitChain{ 992 ConsensusParams: &abci.ConsensusParams{ 993 Block: &abci.BlockParams{ 994 MaxGas: 9, 995 }, 996 }, 997 }) 998 999 app.InitChain(abci.RequestInitChain{}) 1000 1001 header := tmproto.Header{Height: app.LastBlockHeight() + 1} 1002 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 1003 1004 tx := newTxCounter(5, 0) 1005 tx.setFailOnAnte(true) 1006 txBytes, err := cdc.Marshal(tx) 1007 require.NoError(t, err) 1008 1009 res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 1010 require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) 1011 1012 // require next tx to fail due to black gas limit 1013 tx = newTxCounter(5, 0) 1014 txBytes, err = cdc.Marshal(tx) 1015 require.NoError(t, err) 1016 1017 res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 1018 require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) 1019 } 1020 1021 func TestInitChainer(t *testing.T) { 1022 name := t.Name() 1023 // keep the db and logger ourselves so 1024 // we can reload the same app later 1025 db := dbm.NewMemDB() 1026 logger := defaultLogger() 1027 app := NewBaseApp(name, logger, db, nil) 1028 capKey := sdk.NewKVStoreKey("main") 1029 capKey2 := sdk.NewKVStoreKey("key2") 1030 app.MountStores(capKey, capKey2) 1031 1032 // set a value in the store on init chain 1033 key, value := []byte("hello"), []byte("goodbye") 1034 var initChainer sdk.InitChainer = func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { 1035 store := ctx.KVStore(capKey) 1036 store.Set(key, value) 1037 return abci.ResponseInitChain{} 1038 } 1039 1040 query := abci.RequestQuery{ 1041 Path: "/store/main/key", 1042 Data: key, 1043 } 1044 1045 // initChainer is nil - nothing happens 1046 app.InitChain(abci.RequestInitChain{}) 1047 res := app.Query(query) 1048 require.Equal(t, 0, len(res.Value)) 1049 1050 // set initChainer and try again - should see the value 1051 app.SetInitChainer(initChainer) 1052 1053 // stores are mounted and private members are set - sealing baseapp 1054 err := app.LoadLatestVersion() // needed to make stores non-nil 1055 require.Nil(t, err) 1056 require.Equal(t, int64(0), app.LastBlockHeight()) 1057 1058 initChainRes := app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}"), ChainId: "test-chain-id"}) // must have valid JSON genesis file, even if empty 1059 1060 // The AppHash returned by a new chain is the sha256 hash of "". 1061 // $ echo -n '' | sha256sum 1062 // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 1063 require.Equal( 1064 t, 1065 []byte{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, 1066 initChainRes.AppHash, 1067 ) 1068 1069 // assert that chainID is set correctly in InitChain 1070 chainID := app.deliverState.ctx.ChainID() 1071 require.Equal(t, "test-chain-id", chainID, "ChainID in deliverState not set correctly in InitChain") 1072 1073 chainID = app.checkState.ctx.ChainID() 1074 require.Equal(t, "test-chain-id", chainID, "ChainID in checkState not set correctly in InitChain") 1075 1076 app.Commit() 1077 res = app.Query(query) 1078 require.Equal(t, int64(1), app.LastBlockHeight()) 1079 require.Equal(t, value, res.Value) 1080 1081 // reload app 1082 app = NewBaseApp(name, logger, db, nil) 1083 app.SetInitChainer(initChainer) 1084 app.MountStores(capKey, capKey2) 1085 err = app.LoadLatestVersion() // needed to make stores non-nil 1086 require.Nil(t, err) 1087 require.Equal(t, int64(1), app.LastBlockHeight()) 1088 1089 // ensure we can still query after reloading 1090 res = app.Query(query) 1091 require.Equal(t, value, res.Value) 1092 1093 // commit and ensure we can still query 1094 header := tmproto.Header{Height: app.LastBlockHeight() + 1} 1095 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 1096 app.Commit() 1097 1098 res = app.Query(query) 1099 require.Equal(t, value, res.Value) 1100 } 1101 1102 func TestInitChain_WithInitialHeight(t *testing.T) { 1103 name := t.Name() 1104 db := dbm.NewMemDB() 1105 logger := defaultLogger() 1106 app := NewBaseApp(name, logger, db, nil) 1107 1108 app.InitChain( 1109 abci.RequestInitChain{ 1110 InitialHeight: 3, 1111 }, 1112 ) 1113 app.Commit() 1114 1115 require.Equal(t, int64(3), app.LastBlockHeight()) 1116 } 1117 1118 func TestBeginBlock_WithInitialHeight(t *testing.T) { 1119 name := t.Name() 1120 db := dbm.NewMemDB() 1121 logger := defaultLogger() 1122 app := NewBaseApp(name, logger, db, nil) 1123 1124 app.InitChain( 1125 abci.RequestInitChain{ 1126 InitialHeight: 3, 1127 }, 1128 ) 1129 1130 require.PanicsWithError(t, "invalid height: 4; expected: 3", func() { 1131 app.BeginBlock(ocabci.RequestBeginBlock{ 1132 Header: tmproto.Header{ 1133 Height: 4, 1134 }, 1135 }) 1136 }) 1137 1138 app.BeginBlock(ocabci.RequestBeginBlock{ 1139 Header: tmproto.Header{ 1140 Height: 3, 1141 }, 1142 }) 1143 app.Commit() 1144 1145 require.Equal(t, int64(3), app.LastBlockHeight()) 1146 } 1147 1148 // Simple tx with a list of Msgs. 1149 type txTest struct { 1150 Msgs []sdk.Msg 1151 Counter int64 1152 FailOnAnte bool 1153 } 1154 1155 func (tx *txTest) setFailOnAnte(fail bool) { 1156 tx.FailOnAnte = fail 1157 } 1158 1159 func (tx *txTest) setFailOnHandler(fail bool) { 1160 for i, msg := range tx.Msgs { 1161 tx.Msgs[i] = msgCounter{msg.(msgCounter).Counter, fail} 1162 } 1163 } 1164 1165 // Implements Tx 1166 func (tx txTest) GetMsgs() []sdk.Msg { return tx.Msgs } 1167 func (tx txTest) ValidateBasic() error { return nil } 1168 1169 const ( 1170 routeMsgCounter = "msgCounter" 1171 routeMsgCounter2 = "msgCounter2" 1172 routeMsgKeyValue = "msgKeyValue" 1173 ) 1174 1175 // ValidateBasic() fails on negative counters. 1176 // Otherwise it's up to the handlers 1177 type msgCounter struct { 1178 Counter int64 1179 FailOnHandler bool 1180 } 1181 1182 // dummy implementation of proto.Message 1183 func (msg msgCounter) Reset() {} 1184 func (msg msgCounter) String() string { return "TODO" } 1185 func (msg msgCounter) ProtoMessage() {} 1186 1187 // Implements Msg 1188 func (msg msgCounter) Route() string { return routeMsgCounter } 1189 func (msg msgCounter) Type() string { return "counter1" } 1190 func (msg msgCounter) GetSignBytes() []byte { return nil } 1191 func (msg msgCounter) GetSigners() []sdk.AccAddress { return nil } 1192 func (msg msgCounter) ValidateBasic() error { 1193 if msg.Counter >= 0 { 1194 return nil 1195 } 1196 return sdkerrors.Wrap(sdkerrors.ErrInvalidSequence, "counter should be a non-negative integer") 1197 } 1198 1199 func newTxCounter(counter int64, msgCounters ...int64) *txTest { 1200 msgs := make([]sdk.Msg, 0, len(msgCounters)) 1201 for _, c := range msgCounters { 1202 msgs = append(msgs, msgCounter{c, false}) 1203 } 1204 1205 return &txTest{msgs, counter, false} 1206 } 1207 1208 // a msg we dont know how to route 1209 type msgNoRoute struct { 1210 msgCounter 1211 } 1212 1213 func (tx msgNoRoute) Route() string { return "noroute" } 1214 1215 // a msg we dont know how to decode 1216 type msgNoDecode struct { 1217 msgCounter 1218 } 1219 1220 func (tx msgNoDecode) Route() string { return routeMsgCounter } 1221 1222 // Another counter msg. Duplicate of msgCounter 1223 type msgCounter2 struct { 1224 Counter int64 1225 } 1226 1227 // dummy implementation of proto.Message 1228 func (msg msgCounter2) Reset() {} 1229 func (msg msgCounter2) String() string { return "TODO" } 1230 func (msg msgCounter2) ProtoMessage() {} 1231 1232 // Implements Msg 1233 func (msg msgCounter2) Route() string { return routeMsgCounter2 } 1234 func (msg msgCounter2) Type() string { return "counter2" } 1235 func (msg msgCounter2) GetSignBytes() []byte { return nil } 1236 func (msg msgCounter2) GetSigners() []sdk.AccAddress { return nil } 1237 func (msg msgCounter2) ValidateBasic() error { 1238 if msg.Counter >= 0 { 1239 return nil 1240 } 1241 return sdkerrors.Wrap(sdkerrors.ErrInvalidSequence, "counter should be a non-negative integer") 1242 } 1243 1244 // A msg that sets a key/value pair. 1245 type msgKeyValue struct { 1246 Key []byte 1247 Value []byte 1248 } 1249 1250 func (msg msgKeyValue) Reset() {} 1251 func (msg msgKeyValue) String() string { return "TODO" } 1252 func (msg msgKeyValue) ProtoMessage() {} 1253 func (msg msgKeyValue) Route() string { return routeMsgKeyValue } 1254 func (msg msgKeyValue) Type() string { return "keyValue" } 1255 func (msg msgKeyValue) GetSignBytes() []byte { return nil } 1256 func (msg msgKeyValue) GetSigners() []sdk.AccAddress { return nil } 1257 func (msg msgKeyValue) ValidateBasic() error { 1258 if msg.Key == nil { 1259 return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "key cannot be nil") 1260 } 1261 if msg.Value == nil { 1262 return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "value cannot be nil") 1263 } 1264 return nil 1265 } 1266 1267 // amino decode 1268 func testTxDecoder(cdc *codec.LegacyAmino) sdk.TxDecoder { 1269 return func(txBytes []byte) (sdk.Tx, error) { 1270 var tx txTest 1271 if len(txBytes) == 0 { 1272 return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") 1273 } 1274 1275 err := cdc.Unmarshal(txBytes, &tx) 1276 if err != nil { 1277 return nil, sdkerrors.ErrTxDecode 1278 } 1279 1280 return tx, nil 1281 } 1282 } 1283 1284 func anteHandlerTxTest(t *testing.T, capKey sdk.StoreKey, storeKey []byte) sdk.AnteHandler { 1285 return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { 1286 store := ctx.KVStore(capKey) 1287 txTest := tx.(txTest) 1288 1289 if txTest.FailOnAnte { 1290 return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "ante handler failure") 1291 } 1292 1293 _, err := incrementingCounter(t, store, storeKey, txTest.Counter) 1294 if err != nil { 1295 return ctx, err 1296 } 1297 1298 ctx.EventManager().EmitEvents( 1299 counterEvent("ante_handler", txTest.Counter), 1300 ) 1301 1302 return ctx, nil 1303 } 1304 } 1305 1306 // TODO(dudong2): remove this func after reverting CheckTx logic 1307 func anteHandlerTxTest2(t *testing.T, capKey sdk.StoreKey, storeKey []byte) sdk.AnteHandler { 1308 return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { 1309 store := ctx.KVStore(capKey) 1310 txTest := tx.(*txTest) 1311 1312 if txTest.FailOnAnte { 1313 return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "ante handler failure") 1314 } 1315 1316 _, err := incrementingCounter(t, store, storeKey, txTest.Counter) 1317 if err != nil { 1318 return ctx, err 1319 } 1320 1321 ctx.EventManager().EmitEvents( 1322 counterEvent("ante_handler", txTest.Counter), 1323 ) 1324 1325 return ctx, nil 1326 } 1327 } 1328 1329 func counterEvent(evType string, msgCount int64) sdk.Events { 1330 return sdk.Events{ 1331 sdk.NewEvent( 1332 evType, 1333 sdk.NewAttribute("update_counter", fmt.Sprintf("%d", msgCount)), 1334 ), 1335 } 1336 } 1337 1338 func handlerMsgCounter(t *testing.T, capKey sdk.StoreKey, deliverKey []byte) sdk.Handler { 1339 return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 1340 ctx = ctx.WithEventManager(sdk.NewEventManager()) 1341 store := ctx.KVStore(capKey) 1342 var msgCount int64 1343 1344 switch m := msg.(type) { 1345 case *msgCounter: 1346 if m.FailOnHandler { 1347 return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "message handler failure") 1348 } 1349 1350 msgCount = m.Counter 1351 case *msgCounter2: 1352 msgCount = m.Counter 1353 } 1354 1355 ctx.EventManager().EmitEvents( 1356 counterEvent(sdk.EventTypeMessage, msgCount), 1357 ) 1358 1359 res, err := incrementingCounter(t, store, deliverKey, msgCount) 1360 if err != nil { 1361 return nil, err 1362 } 1363 1364 res.Events = ctx.EventManager().Events().ToABCIEvents() 1365 return res, nil 1366 } 1367 } 1368 1369 func getIntFromStore(store sdk.KVStore, key []byte) int64 { 1370 bz := store.Get(key) 1371 if len(bz) == 0 { 1372 return 0 1373 } 1374 i, err := binary.ReadVarint(bytes.NewBuffer(bz)) 1375 if err != nil { 1376 panic(err) 1377 } 1378 return i 1379 } 1380 1381 func setIntOnStore(store sdk.KVStore, key []byte, i int64) { 1382 bz := make([]byte, 8) 1383 n := binary.PutVarint(bz, i) 1384 store.Set(key, bz[:n]) 1385 } 1386 1387 // check counter matches what's in store. 1388 // increment and store 1389 func incrementingCounter(t *testing.T, store sdk.KVStore, counterKey []byte, counter int64) (*sdk.Result, error) { 1390 storedCounter := getIntFromStore(store, counterKey) 1391 require.Equal(t, storedCounter, counter) 1392 setIntOnStore(store, counterKey, counter+1) 1393 return &sdk.Result{}, nil 1394 } 1395 1396 //--------------------------------------------------------------------- 1397 // Tx processing - CheckTx, DeliverTx, SimulateTx. 1398 // These tests use the serialized tx as input, while most others will use the 1399 // Check(), Deliver(), Simulate() methods directly. 1400 // Ensure that Check/Deliver/Simulate work as expected with the store. 1401 1402 // Test that successive CheckTx can see each others' effects 1403 // on the store within a block, and that the CheckTx state 1404 // gets reset to the latest committed state during Commit 1405 func TestCheckTx(t *testing.T) { 1406 // This ante handler reads the key and checks that the value matches the current counter. 1407 // This ensures changes to the kvstore persist across successive CheckTx. 1408 counterKey := []byte("counter-key") 1409 1410 anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest2(t, capKey1, counterKey)) } 1411 routerOpt := func(bapp *BaseApp) { 1412 // TODO: can remove this once CheckTx doesnt process msgs. 1413 bapp.Router().AddRoute(sdk.NewRoute(routeMsgCounter, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 1414 return &sdk.Result{}, nil 1415 })) 1416 } 1417 1418 app := setupBaseApp(t, anteOpt, routerOpt) 1419 1420 nTxs := int64(5) 1421 app.InitChain(abci.RequestInitChain{}) 1422 1423 // Create same codec used in txDecoder 1424 codec := codec.NewLegacyAmino() 1425 registerTestCodec(codec) 1426 1427 for i := int64(0); i < nTxs; i++ { 1428 tx := newTxCounter(i, 0) // no messages 1429 txBytes, err := codec.Marshal(tx) 1430 require.NoError(t, err) 1431 _, err = app.checkTx(txBytes, tx, false) 1432 require.NoError(t, err) 1433 } 1434 1435 checkStateStore := app.checkState.ctx.KVStore(capKey1) 1436 storedCounter := getIntFromStore(checkStateStore, counterKey) 1437 1438 // Ensure AnteHandler ran 1439 require.Equal(t, nTxs, storedCounter) 1440 1441 // If a block is committed, CheckTx state should be reset. 1442 header := tmproto.Header{Height: 1} 1443 app.BeginBlock(ocabci.RequestBeginBlock{Header: header, Hash: []byte("hash")}) 1444 1445 require.NotNil(t, app.checkState.ctx.BlockGasMeter(), "block gas meter should have been set to checkState") 1446 require.NotEmpty(t, app.checkState.ctx.HeaderHash()) 1447 1448 app.EndBlock(abci.RequestEndBlock{}) 1449 app.Commit() 1450 1451 // reset CheckTx state 1452 app.BeginRecheckTx(ocabci.RequestBeginRecheckTx{Header: header}) 1453 1454 checkStateStore = app.checkState.ctx.KVStore(capKey1) 1455 storedBytes := checkStateStore.Get(counterKey) 1456 require.Nil(t, storedBytes) 1457 } 1458 1459 // Test that successive DeliverTx can see each others' effects 1460 // on the store, both within and across blocks. 1461 func TestDeliverTx(t *testing.T) { 1462 // test increments in the ante 1463 anteKey := []byte("ante-key") 1464 anteOpt := func(bapp *BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) } 1465 1466 // test increments in the handler 1467 deliverKey := []byte("deliver-key") 1468 routerOpt := func(bapp *BaseApp) { 1469 r := sdk.NewRoute(routeMsgCounter, handlerMsgCounter(t, capKey1, deliverKey)) 1470 bapp.Router().AddRoute(r) 1471 } 1472 1473 app := setupBaseApp(t, anteOpt, routerOpt) 1474 app.InitChain(abci.RequestInitChain{}) 1475 1476 // Create same codec used in txDecoder 1477 codec := codec.NewLegacyAmino() 1478 registerTestCodec(codec) 1479 1480 nBlocks := 3 1481 txPerHeight := 5 1482 1483 for blockN := 0; blockN < nBlocks; blockN++ { 1484 header := tmproto.Header{Height: int64(blockN) + 1} 1485 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 1486 1487 for i := 0; i < txPerHeight; i++ { 1488 counter := int64(blockN*txPerHeight + i) 1489 tx := newTxCounter(counter, counter) 1490 1491 txBytes, err := codec.Marshal(tx) 1492 require.NoError(t, err) 1493 1494 res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 1495 require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) 1496 events := res.GetEvents() 1497 require.Len(t, events, 3, "should contain ante handler, message type and counter events respectively") 1498 require.Equal(t, sdk.MarkEventsToIndex(counterEvent("ante_handler", counter).ToABCIEvents(), map[string]struct{}{})[0], events[0], "ante handler event") 1499 require.Equal(t, sdk.MarkEventsToIndex(counterEvent(sdk.EventTypeMessage, counter).ToABCIEvents(), map[string]struct{}{})[0], events[2], "msg handler update counter event") 1500 } 1501 1502 app.EndBlock(abci.RequestEndBlock{}) 1503 app.Commit() 1504 } 1505 } 1506 1507 func TestOptionFunction(t *testing.T) { 1508 logger := defaultLogger() 1509 db := dbm.NewMemDB() 1510 bap := NewBaseApp("starting name", logger, db, nil, testChangeNameHelper("new name")) 1511 require.Equal(t, bap.name, "new name", "BaseApp should have had name changed via option function") 1512 } 1513 1514 func testChangeNameHelper(name string) func(*BaseApp) { 1515 return func(bap *BaseApp) { 1516 bap.name = name 1517 } 1518 } 1519 1520 // Test that txs can be unmarshalled and read and that 1521 // correct error codes are returned when not 1522 func TestTxDecoder(t *testing.T) { 1523 codec := codec.NewLegacyAmino() 1524 registerTestCodec(codec) 1525 1526 app := newBaseApp(t.Name()) 1527 tx := newTxCounter(1, 0) 1528 txBytes := codec.MustMarshal(tx) 1529 1530 dTx, err := app.txDecoder(txBytes) 1531 require.NoError(t, err) 1532 1533 cTx := dTx.(txTest) 1534 require.Equal(t, tx.Counter, cTx.Counter) 1535 } 1536 1537 // Test that Info returns the latest committed state. 1538 func TestInfo(t *testing.T) { 1539 app := newBaseApp(t.Name()) 1540 1541 // ----- test an empty response ------- 1542 reqInfo := abci.RequestInfo{} 1543 res := app.Info(reqInfo) 1544 1545 // should be empty 1546 assert.Equal(t, "", res.Version) 1547 assert.Equal(t, t.Name(), res.GetData()) 1548 assert.Equal(t, int64(0), res.LastBlockHeight) 1549 require.Equal(t, []uint8(nil), res.LastBlockAppHash) 1550 require.Equal(t, app.AppVersion(), res.AppVersion) 1551 // ----- test a proper response ------- 1552 // TODO 1553 } 1554 1555 func TestBaseAppOptionSeal(t *testing.T) { 1556 app := setupBaseApp(t) 1557 1558 require.Panics(t, func() { 1559 app.SetName("") 1560 }) 1561 require.Panics(t, func() { 1562 app.SetVersion("") 1563 }) 1564 require.Panics(t, func() { 1565 app.SetDB(nil) 1566 }) 1567 require.Panics(t, func() { 1568 app.SetCMS(nil) 1569 }) 1570 require.Panics(t, func() { 1571 app.SetInitChainer(nil) 1572 }) 1573 require.Panics(t, func() { 1574 app.SetBeginBlocker(nil) 1575 }) 1576 require.Panics(t, func() { 1577 app.SetEndBlocker(nil) 1578 }) 1579 require.Panics(t, func() { 1580 app.SetAnteHandler(nil) 1581 }) 1582 require.Panics(t, func() { 1583 app.SetAddrPeerFilter(nil) 1584 }) 1585 require.Panics(t, func() { 1586 app.SetIDPeerFilter(nil) 1587 }) 1588 require.Panics(t, func() { 1589 app.SetFauxMerkleMode() 1590 }) 1591 require.Panics(t, func() { 1592 app.SetRouter(NewRouter()) 1593 }) 1594 } 1595 1596 func TestVersionSetterGetter(t *testing.T) { 1597 logger := defaultLogger() 1598 pruningOpt := SetPruning(store.PruneDefault) 1599 db := dbm.NewMemDB() 1600 name := t.Name() 1601 app := NewBaseApp(name, logger, db, nil, pruningOpt) 1602 1603 require.Equal(t, "", app.Version()) 1604 res := app.Query(abci.RequestQuery{Path: "app/version"}) 1605 require.True(t, res.IsOK()) 1606 require.Equal(t, "", string(res.Value)) 1607 1608 versionString := "1.0.0" 1609 app.SetVersion(versionString) 1610 require.Equal(t, versionString, app.Version()) 1611 res = app.Query(abci.RequestQuery{Path: "app/version"}) 1612 require.True(t, res.IsOK()) 1613 require.Equal(t, versionString, string(res.Value)) 1614 } 1615 1616 func TestLoadVersionInvalid(t *testing.T) { 1617 logger := log.NewNopLogger() 1618 pruningOpt := SetPruning(store.PruneNothing) 1619 db := dbm.NewMemDB() 1620 name := t.Name() 1621 app := NewBaseApp(name, logger, db, nil, pruningOpt) 1622 1623 err := app.LoadLatestVersion() 1624 require.Nil(t, err) 1625 1626 // require error when loading an invalid version 1627 err = app.LoadVersion(-1) 1628 require.Error(t, err) 1629 1630 header := tmproto.Header{Height: 1} 1631 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 1632 res := app.Commit() 1633 commitID1 := sdk.CommitID{Version: 1, Hash: res.Data} 1634 1635 // create a new app with the stores mounted under the same cap key 1636 app = NewBaseApp(name, logger, db, nil, pruningOpt) 1637 1638 // require we can load the latest version 1639 err = app.LoadVersion(1) 1640 require.Nil(t, err) 1641 testLoadVersionHelper(t, app, int64(1), commitID1) 1642 1643 // require error when loading an invalid version 1644 err = app.LoadVersion(2) 1645 require.Error(t, err) 1646 } 1647 1648 // simple one store baseapp with data and snapshots. Each tx is 1 MB in size (uncompressed). 1649 func setupBaseAppWithSnapshots(t *testing.T, blocks uint, blockTxs int, options ...func(*BaseApp)) (*BaseApp, func()) { 1650 codec := codec.NewLegacyAmino() 1651 registerTestCodec(codec) 1652 routerOpt := func(bapp *BaseApp) { 1653 bapp.Router().AddRoute(sdk.NewRoute(routeMsgKeyValue, func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { 1654 kv := msg.(*msgKeyValue) 1655 bapp.cms.GetCommitKVStore(capKey2).Set(kv.Key, kv.Value) 1656 return &sdk.Result{}, nil 1657 })) 1658 } 1659 1660 snapshotInterval := uint64(2) 1661 snapshotTimeout := 1 * time.Minute 1662 snapshotDir, err := os.MkdirTemp("", "baseapp") 1663 require.NoError(t, err) 1664 snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), snapshotDir) 1665 require.NoError(t, err) 1666 teardown := func() { 1667 os.RemoveAll(snapshotDir) 1668 } 1669 1670 app := setupBaseApp(t, append(options, 1671 SetSnapshotStore(snapshotStore), 1672 SetSnapshotInterval(snapshotInterval), 1673 SetPruning(sdk.PruningOptions{KeepEvery: 1}), 1674 routerOpt)...) 1675 1676 app.InitChain(abci.RequestInitChain{}) 1677 1678 r := rand.New(rand.NewSource(3920758213583)) 1679 keyCounter := 0 1680 for height := int64(1); height <= int64(blocks); height++ { 1681 app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: height}}) 1682 for txNum := 0; txNum < blockTxs; txNum++ { 1683 tx := txTest{Msgs: []sdk.Msg{}} 1684 for msgNum := 0; msgNum < 100; msgNum++ { 1685 key := []byte(fmt.Sprintf("%v", keyCounter)) 1686 value := make([]byte, 10000) 1687 _, err := r.Read(value) 1688 require.NoError(t, err) 1689 tx.Msgs = append(tx.Msgs, msgKeyValue{Key: key, Value: value}) 1690 keyCounter++ 1691 } 1692 txBytes, err := codec.Marshal(tx) 1693 require.NoError(t, err) 1694 resp := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) 1695 require.True(t, resp.IsOK(), "%v", resp.String()) 1696 } 1697 app.EndBlock(abci.RequestEndBlock{Height: height}) 1698 app.Commit() 1699 1700 // Wait for snapshot to be taken, since it happens asynchronously. 1701 if uint64(height)%snapshotInterval == 0 { 1702 start := time.Now() 1703 for { 1704 if time.Since(start) > snapshotTimeout { 1705 t.Errorf("timed out waiting for snapshot after %v", snapshotTimeout) 1706 } 1707 snapshot, err := snapshotStore.Get(uint64(height), snapshottypes.CurrentFormat) 1708 require.NoError(t, err) 1709 if snapshot != nil { 1710 break 1711 } 1712 time.Sleep(100 * time.Millisecond) 1713 } 1714 } 1715 } 1716 1717 return app, teardown 1718 } 1719 1720 func TestMountStores(t *testing.T) { 1721 app := setupBaseApp(t) 1722 1723 // check both stores 1724 store1 := app.cms.GetCommitKVStore(capKey1) 1725 require.NotNil(t, store1) 1726 store2 := app.cms.GetCommitKVStore(capKey2) 1727 require.NotNil(t, store2) 1728 } 1729 1730 // Test that we can make commits and then reload old versions. 1731 // Test that LoadLatestVersion actually does. 1732 func TestLoadVersion(t *testing.T) { 1733 logger := defaultLogger() 1734 pruningOpt := SetPruning(store.PruneNothing) 1735 db := dbm.NewMemDB() 1736 name := t.Name() 1737 app := NewBaseApp(name, logger, db, nil, pruningOpt) 1738 1739 // make a cap key and mount the store 1740 err := app.LoadLatestVersion() // needed to make stores non-nil 1741 require.Nil(t, err) 1742 1743 emptyCommitID := sdk.CommitID{} 1744 1745 // fresh store has zero/empty last commit 1746 lastHeight := app.LastBlockHeight() 1747 lastID := app.LastCommitID() 1748 require.Equal(t, int64(0), lastHeight) 1749 require.Equal(t, emptyCommitID, lastID) 1750 1751 // execute a block, collect commit ID 1752 header := tmproto.Header{Height: 1} 1753 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 1754 res := app.Commit() 1755 commitID1 := sdk.CommitID{Version: 1, Hash: res.Data} 1756 1757 // execute a block, collect commit ID 1758 header = tmproto.Header{Height: 2} 1759 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 1760 res = app.Commit() 1761 commitID2 := sdk.CommitID{Version: 2, Hash: res.Data} 1762 1763 // reload with LoadLatestVersion 1764 app = NewBaseApp(name, logger, db, nil, pruningOpt) 1765 app.MountStores() 1766 err = app.LoadLatestVersion() 1767 require.Nil(t, err) 1768 testLoadVersionHelper(t, app, int64(2), commitID2) 1769 1770 // reload with LoadVersion, see if you can commit the same block and get 1771 // the same result 1772 app = NewBaseApp(name, logger, db, nil, pruningOpt) 1773 err = app.LoadVersion(1) 1774 require.Nil(t, err) 1775 testLoadVersionHelper(t, app, int64(1), commitID1) 1776 app.BeginBlock(ocabci.RequestBeginBlock{Header: header}) 1777 app.Commit() 1778 testLoadVersionHelper(t, app, int64(2), commitID2) 1779 } 1780 1781 func useDefaultLoader(app *BaseApp) { 1782 app.SetStoreLoader(DefaultStoreLoader) 1783 } 1784 1785 func initStore(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { 1786 rs := rootmulti.NewStore(db, log.NewNopLogger()) 1787 rs.SetPruning(store.PruneNothing) 1788 key := sdk.NewKVStoreKey(storeKey) 1789 rs.MountStoreWithDB(key, store.StoreTypeIAVL, nil) 1790 err := rs.LoadLatestVersion() 1791 require.Nil(t, err) 1792 require.Equal(t, int64(0), rs.LastCommitID().Version) 1793 1794 // write some data in substore 1795 kv, _ := rs.GetStore(key).(store.KVStore) 1796 require.NotNil(t, kv) 1797 kv.Set(k, v) 1798 commitID := rs.Commit() 1799 require.Equal(t, int64(1), commitID.Version) 1800 } 1801 1802 func checkStore(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) { 1803 rs := rootmulti.NewStore(db, log.NewNopLogger()) 1804 rs.SetPruning(store.PruneDefault) 1805 key := sdk.NewKVStoreKey(storeKey) 1806 rs.MountStoreWithDB(key, store.StoreTypeIAVL, nil) 1807 err := rs.LoadLatestVersion() 1808 require.Nil(t, err) 1809 require.Equal(t, ver, rs.LastCommitID().Version) 1810 1811 // query data in substore 1812 kv, _ := rs.GetStore(key).(store.KVStore) 1813 require.NotNil(t, kv) 1814 require.Equal(t, v, kv.Get(k)) 1815 } 1816 1817 // Test that we can make commits and then reload old versions. 1818 // Test that LoadLatestVersion actually does. 1819 func TestSetLoader(t *testing.T) { 1820 cases := map[string]struct { 1821 setLoader func(*BaseApp) 1822 origStoreKey string 1823 loadStoreKey string 1824 }{ 1825 "don't set loader": { 1826 origStoreKey: "foo", 1827 loadStoreKey: "foo", 1828 }, 1829 "default loader": { 1830 setLoader: useDefaultLoader, 1831 origStoreKey: "foo", 1832 loadStoreKey: "foo", 1833 }, 1834 } 1835 1836 k := []byte("key") 1837 v := []byte("value") 1838 1839 for name, tc := range cases { 1840 tc := tc 1841 t.Run(name, func(t *testing.T) { 1842 // prepare a db with some data 1843 db := dbm.NewMemDB() 1844 initStore(t, db, tc.origStoreKey, k, v) 1845 1846 // load the app with the existing db 1847 opts := []func(*BaseApp){SetPruning(store.PruneNothing)} 1848 if tc.setLoader != nil { 1849 opts = append(opts, tc.setLoader) 1850 } 1851 app := NewBaseApp(t.Name(), defaultLogger(), db, nil, opts...) 1852 app.MountStores(sdk.NewKVStoreKey(tc.loadStoreKey)) 1853 err := app.LoadLatestVersion() 1854 require.Nil(t, err) 1855 1856 // "execute" one block 1857 app.BeginBlock(ocabci.RequestBeginBlock{Header: tmproto.Header{Height: 2}}) 1858 res := app.Commit() 1859 require.NotNil(t, res.Data) 1860 1861 // check db is properly updated 1862 checkStore(t, db, 2, tc.loadStoreKey, k, v) 1863 checkStore(t, db, 2, tc.loadStoreKey, []byte("foo"), nil) 1864 }) 1865 } 1866 }