Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: expose InitChain tx responses #1941

Merged
merged 32 commits into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7be8225
feat: expose InitChain response
n0izn0iz Apr 17, 2024
667f8bd
Merge branch 'master' into expose-genesis-response
n0izn0iz Apr 17, 2024
9107f45
tmp: start try to store results like in ApplyBlock
n0izn0iz Jun 10, 2024
8bcee48
chore: Merge remote-tracking branch 'origin/master' into expose-genes…
n0izn0iz Jun 10, 2024
8fa79be
feat: save InitChain's ResponseDeliverTxs and add test
n0izn0iz Jun 10, 2024
e4dd0f6
chore: clean
n0izn0iz Jun 10, 2024
d0da512
fix: preserve existing getHeight behavior
n0izn0iz Jun 10, 2024
15e974b
chore: improve comment
n0izn0iz Jun 10, 2024
6c41220
chore: self-contained tests
n0izn0iz Jun 11, 2024
13be10f
chore: remove artifact
n0izn0iz Jun 11, 2024
366d229
chore: use testing utils
n0izn0iz Jun 11, 2024
404fcd5
chore: move MockApplication into testing package
n0izn0iz Jun 12, 2024
926e226
chore: inline asserts
n0izn0iz Jun 12, 2024
d625a9a
Merge branch 'master' into expose-genesis-response
n0izn0iz Jun 12, 2024
f2923e8
Merge branch 'master' into expose-genesis-response
n0izn0iz Jun 12, 2024
a182a3a
chore: update proto
n0izn0iz Jun 12, 2024
0d1a4bd
Merge branch 'master' into expose-genesis-response
n0izn0iz Jun 17, 2024
9d309b7
Merge branch 'master' into expose-genesis-response
n0izn0iz Jun 19, 2024
eda735b
Merge branch 'master' into expose-genesis-response
n0izn0iz Jun 19, 2024
c5357f1
Merge branch 'master' into expose-genesis-response
n0izn0iz Jun 19, 2024
d684021
Merge branch 'master' into expose-genesis-response
n0izn0iz Jul 17, 2024
87fe7d8
chore: use t.Cleanup
n0izn0iz Jul 17, 2024
8b33ffc
chore: use cast instead of generic
n0izn0iz Jul 17, 2024
bad682a
chore: add getHeight test
n0izn0iz Jul 17, 2024
409cd9d
Merge branch 'master' into expose-genesis-response
n0izn0iz Jul 17, 2024
5cec713
Merge branch 'master' into expose-genesis-response
n0izn0iz Jul 19, 2024
ecdf0f2
Merge branch 'master' into expose-genesis-response
n0izn0iz Jul 19, 2024
973a73f
Merge branch 'master' into expose-genesis-response
n0izn0iz Jul 22, 2024
110da7d
chore: revert getHeight
n0izn0iz Jul 22, 2024
01dc6f8
chore: remove MockApplication
n0izn0iz Jul 22, 2024
e649de5
chore: SaveABCIResponses internal usage note
n0izn0iz Jul 22, 2024
83dd5a0
Merge branch 'master' into expose-genesis-response
n0izn0iz Jul 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion gno.land/pkg/gnoland/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@
// InitChainer returns a function that can initialize the chain with genesis.
func InitChainer(baseApp *sdk.BaseApp, acctKpr auth.AccountKeeperI, bankKpr bank.BankKeeperI, resHandler GenesisTxHandler) func(sdk.Context, abci.RequestInitChain) abci.ResponseInitChain {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
txResponses := []abci.ResponseDeliverTx{}

Check warning on line 160 in gno.land/pkg/gnoland/app.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoland/app.go#L160

Added line #L160 was not covered by tests

if req.AppState != nil {
// Get genesis state
genState := req.AppState.(GnoGenesisState)
Expand All @@ -183,13 +185,20 @@
)
}

txResponses = append(txResponses, abci.ResponseDeliverTx{
ResponseBase: res.ResponseBase,
GasWanted: res.GasWanted,
GasUsed: res.GasUsed,
})

Check warning on line 192 in gno.land/pkg/gnoland/app.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoland/app.go#L188-L192

Added lines #L188 - L192 were not covered by tests

resHandler(ctx, tx, res)
}
}

// Done!
return abci.ResponseInitChain{
Validators: req.Validators,
Validators: req.Validators,
TxResponses: txResponses,

Check warning on line 201 in gno.land/pkg/gnoland/app.go

View check run for this annotation

Codecov / codecov/patch

gno.land/pkg/gnoland/app.go#L200-L201

Added lines #L200 - L201 were not covered by tests
}
}
}
Expand Down
89 changes: 89 additions & 0 deletions tm2/pkg/bft/abci/types/mock_application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package abci
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved

type MockApplication struct {
BaseApplication
InfoFn func(RequestInfo) ResponseInfo
SetOptionFn func(RequestSetOption) ResponseSetOption
QueryFn func(RequestQuery) ResponseQuery
CheckTxFn func(RequestCheckTx) ResponseCheckTx
InitChainFn func(RequestInitChain) ResponseInitChain
BeginBlockFn func(RequestBeginBlock) ResponseBeginBlock
DeliverTxFn func(RequestDeliverTx) ResponseDeliverTx
EndBlockFn func(RequestEndBlock) ResponseEndBlock
CommitFn func() ResponseCommit
CloseFn func() error
}

// Info/Query Connection
func (app *MockApplication) Info(req RequestInfo) ResponseInfo {
if app.InfoFn != nil {
return app.InfoFn(req)

Check warning on line 20 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L20

Added line #L20 was not covered by tests
}
return ResponseInfo{}
}

func (app *MockApplication) SetOption(req RequestSetOption) ResponseSetOption {
if app.SetOptionFn != nil {
return app.SetOptionFn(req)

Check warning on line 27 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L25-L27

Added lines #L25 - L27 were not covered by tests
}
return ResponseSetOption{}

Check warning on line 29 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L29

Added line #L29 was not covered by tests
}

func (app *MockApplication) Query(req RequestQuery) ResponseQuery {
if app.QueryFn != nil {
return app.QueryFn(req)

Check warning on line 34 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L32-L34

Added lines #L32 - L34 were not covered by tests
}
return ResponseQuery{}

Check warning on line 36 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L36

Added line #L36 was not covered by tests
}

// Mempool Connection
func (app *MockApplication) CheckTx(req RequestCheckTx) ResponseCheckTx {
if app.CheckTxFn != nil {
return app.CheckTxFn(req)

Check warning on line 42 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L40-L42

Added lines #L40 - L42 were not covered by tests
}
return ResponseCheckTx{}

Check warning on line 44 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L44

Added line #L44 was not covered by tests
}

// Consensus Connection
func (app *MockApplication) InitChain(req RequestInitChain) ResponseInitChain {
if app.InitChainFn != nil {
return app.InitChainFn(req)
}
return ResponseInitChain{}

Check warning on line 52 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L52

Added line #L52 was not covered by tests
}

func (app *MockApplication) BeginBlock(req RequestBeginBlock) ResponseBeginBlock {
if app.BeginBlockFn != nil {
return app.BeginBlockFn(req)

Check warning on line 57 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L55-L57

Added lines #L55 - L57 were not covered by tests
}
return ResponseBeginBlock{}

Check warning on line 59 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L59

Added line #L59 was not covered by tests
}

func (app *MockApplication) DeliverTx(req RequestDeliverTx) ResponseDeliverTx {
if app.DeliverTxFn != nil {
return app.DeliverTxFn(req)

Check warning on line 64 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L62-L64

Added lines #L62 - L64 were not covered by tests
}
return ResponseDeliverTx{}

Check warning on line 66 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L66

Added line #L66 was not covered by tests
}

func (app *MockApplication) EndBlock(req RequestEndBlock) ResponseEndBlock {
if app.EndBlockFn != nil {
return app.EndBlockFn(req)

Check warning on line 71 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L69-L71

Added lines #L69 - L71 were not covered by tests
}
return ResponseEndBlock{}

Check warning on line 73 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L73

Added line #L73 was not covered by tests
}

func (app *MockApplication) Commit() ResponseCommit {
if app.CommitFn != nil {
return app.CommitFn()

Check warning on line 78 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L76-L78

Added lines #L76 - L78 were not covered by tests
}
return ResponseCommit{}

Check warning on line 80 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L80

Added line #L80 was not covered by tests
}

// Cleanup
func (app *MockApplication) Close() error {
if app.CloseFn != nil {
return app.CloseFn()

Check warning on line 86 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L84-L86

Added lines #L84 - L86 were not covered by tests
}
return nil

Check warning on line 88 in tm2/pkg/bft/abci/types/mock_application.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/abci/types/mock_application.go#L88

Added line #L88 was not covered by tests
}
1 change: 1 addition & 0 deletions tm2/pkg/bft/abci/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ type ResponseInitChain struct {
ResponseBase
ConsensusParams *ConsensusParams
Validators []ValidatorUpdate
TxResponses []ResponseDeliverTx
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved
}

type ResponseQuery struct {
Expand Down
7 changes: 7 additions & 0 deletions tm2/pkg/bft/consensus/replay.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,13 @@ func (h *Handshaker) ReplayBlocks(
return nil, err
}

// Save the results by height
abciResponse := sm.NewABCIResponsesFromNum(len(res.TxResponses))
copy(abciResponse.DeliverTxs, res.TxResponses)
sm.SaveABCIResponses(h.stateDB, 0, abciResponse)

// NOTE: we don't save results by tx hash since the transactions are in the AppState opaque type
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved

if stateBlockHeight == 0 { // we only update state when we are in initial state
// If the app returned validators or consensus params, update the state.
if len(res.Validators) > 0 {
Expand Down
60 changes: 44 additions & 16 deletions tm2/pkg/bft/consensus/replay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,15 @@ func TestHandshakeUpdatesValidators(t *testing.T) {

val, _ := types.RandValidator(true, 10)
vals := types.NewValidatorSet([]*types.Validator{val})
app := &initChainApp{vals: vals.ABCIValidatorUpdates()}
appVals := vals.ABCIValidatorUpdates()
// returns the vals on InitChain
app := &abci.MockApplication{
InitChainFn: func(req abci.RequestInitChain) abci.ResponseInitChain {
return abci.ResponseInitChain{
Validators: appVals,
}
},
}
clientCreator := proxy.NewLocalClientCreator(app)

config, genesisFile := ResetConfig("handshake_test_")
Expand All @@ -1144,13 +1152,11 @@ func TestHandshakeUpdatesValidators(t *testing.T) {
genDoc, _ := sm.MakeGenesisDocFromFile(genesisFile)
handshaker := NewHandshaker(stateDB, state, store, genDoc)
proxyApp := appconn.NewAppConns(clientCreator)
if err := proxyApp.Start(); err != nil {
t.Fatalf("Error starting proxy app connections: %v", err)
}
defer proxyApp.Stop()
if err := handshaker.Handshake(proxyApp); err != nil {
t.Fatalf("Error on abci handshake: %v", err)
}
err := proxyApp.Start()
require.NoError(t, err, "Error starting proxy app connections")
defer func() { err := proxyApp.Stop(); require.NoError(t, err) }()
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved
err = handshaker.Handshake(proxyApp)
require.NoError(t, err, "Error on abci handshake")
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved

// reload the state, check the validator set was updated
state = sm.LoadState(stateDB)
Expand All @@ -1161,14 +1167,36 @@ func TestHandshakeUpdatesValidators(t *testing.T) {
assert.Equal(t, newValAddr, expectValAddr)
}

// returns the vals on InitChain
type initChainApp struct {
abci.BaseApplication
vals []abci.ValidatorUpdate
}
func TestHandshakeGenesisResponseDeliverTx(t *testing.T) {
t.Parallel()

func (ica *initChainApp) InitChain(req abci.RequestInitChain) abci.ResponseInitChain {
return abci.ResponseInitChain{
Validators: ica.vals,
const numInitResponses = 42

app := &abci.MockApplication{
InitChainFn: func(req abci.RequestInitChain) abci.ResponseInitChain {
return abci.ResponseInitChain{
TxResponses: make([]abci.ResponseDeliverTx, numInitResponses),
}
},
}
clientCreator := proxy.NewLocalClientCreator(app)

config, genesisFile := ResetConfig("handshake_test_")
defer os.RemoveAll(config.RootDir)
thehowl marked this conversation as resolved.
Show resolved Hide resolved
stateDB, state, store := makeStateAndStore(config, genesisFile, "v0.0.0-test")

// now start the app using the handshake - it should sync
genDoc, _ := sm.MakeGenesisDocFromFile(genesisFile)
handshaker := NewHandshaker(stateDB, state, store, genDoc)
proxyApp := appconn.NewAppConns(clientCreator)
err := proxyApp.Start()
require.NoError(t, err, "Error starting proxy app connections")
defer func() { err := proxyApp.Stop(); require.NoError(t, err) }()
err = handshaker.Handshake(proxyApp)
require.NoError(t, err, "Error on abci handshake")

// check that the genesis transaction results are saved
res, err := sm.LoadABCIResponses(stateDB, 0)
require.NoError(t, err, "Failed to load genesis ABCI responses")
assert.Len(t, res.DeliverTxs, numInitResponses)
}
12 changes: 6 additions & 6 deletions tm2/pkg/bft/rpc/core/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@
// ```
func Block(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlock, error) {
storeHeight := blockStore.Height()
height, err := getHeight(storeHeight, heightPtr)
height, err := getHeight(storeHeight, heightPtr, 1)

Check warning on line 239 in tm2/pkg/bft/rpc/core/blocks.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/rpc/core/blocks.go#L239

Added line #L239 was not covered by tests
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -327,7 +327,7 @@
// ```
func Commit(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultCommit, error) {
storeHeight := blockStore.Height()
height, err := getHeight(storeHeight, heightPtr)
height, err := getHeight(storeHeight, heightPtr, 1)

Check warning on line 330 in tm2/pkg/bft/rpc/core/blocks.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/rpc/core/blocks.go#L330

Added line #L330 was not covered by tests
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -400,7 +400,7 @@
// ```
func BlockResults(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultBlockResults, error) {
storeHeight := blockStore.Height()
height, err := getHeight(storeHeight, heightPtr)
height, err := getHeight(storeHeight, heightPtr, 0)

Check warning on line 403 in tm2/pkg/bft/rpc/core/blocks.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/rpc/core/blocks.go#L403

Added line #L403 was not covered by tests
thehowl marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}
Expand All @@ -417,11 +417,11 @@
return res, nil
}

func getHeight(currentHeight int64, heightPtr *int64) (int64, error) {
func getHeight(currentHeight int64, heightPtr *int64, min int64) (int64, error) {
if heightPtr != nil {
height := *heightPtr
if height <= 0 {
return 0, fmt.Errorf("height must be greater than 0")
if height < min {
return 0, fmt.Errorf("height must be greater than or equal to %d", min)

Check warning on line 424 in tm2/pkg/bft/rpc/core/blocks.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/rpc/core/blocks.go#L424

Added line #L424 was not covered by tests
ajnavarro marked this conversation as resolved.
Show resolved Hide resolved
}
if height > currentHeight {
ajnavarro marked this conversation as resolved.
Show resolved Hide resolved
return 0, fmt.Errorf("height must be less than or equal to the current blockchain height")
Expand Down
4 changes: 2 additions & 2 deletions tm2/pkg/bft/rpc/core/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
// The latest validator that we know is the
// NextValidator of the last block.
height := consensusState.GetState().LastBlockHeight + 1
height, err := getHeight(height, heightPtr)
height, err := getHeight(height, heightPtr, 1)

Check warning on line 61 in tm2/pkg/bft/rpc/core/consensus.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/rpc/core/consensus.go#L61

Added line #L61 was not covered by tests
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -344,7 +344,7 @@
// ```
func ConsensusParams(ctx *rpctypes.Context, heightPtr *int64) (*ctypes.ResultConsensusParams, error) {
height := consensusState.GetState().LastBlockHeight + 1
height, err := getHeight(height, heightPtr)
height, err := getHeight(height, heightPtr, 1)

Check warning on line 347 in tm2/pkg/bft/rpc/core/consensus.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/bft/rpc/core/consensus.go#L347

Added line #L347 was not covered by tests
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion tm2/pkg/bft/rpc/core/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func Tx(_ *rpctypes.Context, hash []byte) (*ctypes.ResultTx, error) {
}

// Sanity check the block height
height, err := getHeight(blockStore.Height(), &resultIndex.BlockNum)
height, err := getHeight(blockStore.Height(), &resultIndex.BlockNum, 1)
if err != nil {
return nil, err
}
Expand Down
6 changes: 3 additions & 3 deletions tm2/pkg/bft/state/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,10 @@ func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, b

fail.Fail() // XXX

// Save the results before we commit.
saveABCIResponses(blockExec.db, block.Height, abciResponses)
// Save the results by height
SaveABCIResponses(blockExec.db, block.Height, abciResponses)

// Save the transaction results
// Save the results by tx hash
for index, tx := range block.Txs {
saveTxResultIndex(
blockExec.db,
Expand Down
6 changes: 0 additions & 6 deletions tm2/pkg/bft/state/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ func CalcValidatorsKey(height int64) []byte {
return calcValidatorsKey(height)
}

// SaveABCIResponses is an alias for the private saveABCIResponses method in
// store.go, exported exclusively and explicitly for testing.
func SaveABCIResponses(db dbm.DB, height int64, abciResponses *ABCIResponses) {
saveABCIResponses(db, height, abciResponses)
}

// SaveConsensusParamsInfo is an alias for the private saveConsensusParamsInfo
// method in store.go, exported exclusively and explicitly for testing.
func SaveConsensusParamsInfo(db dbm.DB, nextHeight, changeHeight int64, params abci.ConsensusParams) {
Expand Down
12 changes: 9 additions & 3 deletions tm2/pkg/bft/state/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/gnolang/gno/tm2/pkg/bft/types"
dbm "github.com/gnolang/gno/tm2/pkg/db"
osm "github.com/gnolang/gno/tm2/pkg/os"
"golang.org/x/exp/constraints"
)

const (
Expand Down Expand Up @@ -131,8 +132,13 @@ type ABCIResponses struct {

// NewABCIResponses returns a new ABCIResponses
func NewABCIResponses(block *types.Block) *ABCIResponses {
resDeliverTxs := make([]abci.ResponseDeliverTx, block.NumTxs)
if block.NumTxs == 0 {
return NewABCIResponsesFromNum(block.NumTxs)
}

// NewABCIResponsesFromNum returns a new ABCIResponses with a set number of txs
func NewABCIResponsesFromNum[N constraints.Integer](numTxs N) *ABCIResponses {
thehowl marked this conversation as resolved.
Show resolved Hide resolved
resDeliverTxs := make([]abci.ResponseDeliverTx, numTxs)
if numTxs == 0 {
// This makes Amino encoding/decoding consistent.
resDeliverTxs = nil
}
Expand Down Expand Up @@ -175,7 +181,7 @@ func LoadABCIResponses(db dbm.DB, height int64) (*ABCIResponses, error) {
// SaveABCIResponses persists the ABCIResponses to the database.
// This is useful in case we crash after app.Commit and before s.Save().
// Responses are indexed by height so they can also be loaded later to produce Merkle proofs.
func saveABCIResponses(db dbm.DB, height int64, abciResponses *ABCIResponses) {
func SaveABCIResponses(db dbm.DB, height int64, abciResponses *ABCIResponses) {
thehowl marked this conversation as resolved.
Show resolved Hide resolved
db.Set(CalcABCIResponsesKey(height), abciResponses.Bytes())
}

Expand Down
Loading