Files
tendermint/rpc/client/mock/abci_test.go
T
William BanfieldandGitHub 0b8a62c87b abci: Synchronize FinalizeBlock with the updated specification (#7983)
This change set implements the most recent version of `FinalizeBlock`. 

# What does this change actually contain?

* This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name.
* The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock`
* The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous.
* Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across.
* Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created.

# Questions for reviewers
* We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable?
* Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? 


closes: #7658
2022-03-04 22:32:37 +00:00

204 lines
5.6 KiB
Go

package mock_test
import (
"context"
"errors"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/abci/example/kvstore"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/rpc/client/mock"
"github.com/tendermint/tendermint/rpc/coretypes"
"github.com/tendermint/tendermint/types"
)
func TestABCIMock(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
key, value := []byte("foo"), []byte("bar")
height := int64(10)
goodTx := types.Tx{0x01, 0xff}
badTx := types.Tx{0x12, 0x21}
m := mock.ABCIMock{
Info: mock.Call{Error: errors.New("foobar")},
Query: mock.Call{Response: abci.ResponseQuery{
Key: key,
Value: value,
Height: height,
}},
// Broadcast commit depends on call
BroadcastCommit: mock.Call{
Args: goodTx,
Response: &coretypes.ResultBroadcastTxCommit{
CheckTx: abci.ResponseCheckTx{Data: bytes.HexBytes("stand")},
TxResult: abci.ExecTxResult{Data: bytes.HexBytes("deliver")},
},
Error: errors.New("bad tx"),
},
Broadcast: mock.Call{Error: errors.New("must commit")},
}
// now, let's try to make some calls
_, err := m.ABCIInfo(ctx)
require.Error(t, err)
assert.Equal(t, "foobar", err.Error())
// query always returns the response
_query, err := m.ABCIQueryWithOptions(ctx, "/", nil, client.ABCIQueryOptions{Prove: false})
query := _query.Response
require.NoError(t, err)
require.NotNil(t, query)
assert.EqualValues(t, key, query.Key)
assert.EqualValues(t, value, query.Value)
assert.Equal(t, height, query.Height)
// non-commit calls always return errors
_, err = m.BroadcastTxSync(ctx, goodTx)
require.Error(t, err)
assert.Equal(t, "must commit", err.Error())
_, err = m.BroadcastTxAsync(ctx, goodTx)
require.Error(t, err)
assert.Equal(t, "must commit", err.Error())
// commit depends on the input
_, err = m.BroadcastTxCommit(ctx, badTx)
require.Error(t, err)
assert.Equal(t, "bad tx", err.Error())
bres, err := m.BroadcastTxCommit(ctx, goodTx)
require.NoError(t, err, "%+v", err)
assert.EqualValues(t, 0, bres.CheckTx.Code)
assert.EqualValues(t, "stand", bres.CheckTx.Data)
assert.EqualValues(t, "deliver", bres.TxResult.Data)
}
func TestABCIRecorder(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// This mock returns errors on everything but Query
m := mock.ABCIMock{
Info: mock.Call{Response: abci.ResponseInfo{
Data: "data",
Version: "v0.9.9",
}},
Query: mock.Call{Error: errors.New("query")},
Broadcast: mock.Call{Error: errors.New("broadcast")},
BroadcastCommit: mock.Call{Error: errors.New("broadcast_commit")},
}
r := mock.NewABCIRecorder(m)
require.Equal(t, 0, len(r.Calls))
_, err := r.ABCIInfo(ctx)
assert.NoError(t, err, "expected no err on info")
_, err = r.ABCIQueryWithOptions(
ctx,
"path",
bytes.HexBytes("data"),
client.ABCIQueryOptions{Prove: false},
)
assert.Error(t, err, "expected error on query")
require.Equal(t, 2, len(r.Calls))
info := r.Calls[0]
assert.Equal(t, "abci_info", info.Name)
assert.Nil(t, info.Error)
assert.Nil(t, info.Args)
require.NotNil(t, info.Response)
ir, ok := info.Response.(*coretypes.ResultABCIInfo)
require.True(t, ok)
assert.Equal(t, "data", ir.Response.Data)
assert.Equal(t, "v0.9.9", ir.Response.Version)
query := r.Calls[1]
assert.Equal(t, "abci_query", query.Name)
assert.Nil(t, query.Response)
require.NotNil(t, query.Error)
assert.Equal(t, "query", query.Error.Error())
require.NotNil(t, query.Args)
qa, ok := query.Args.(mock.QueryArgs)
require.True(t, ok)
assert.Equal(t, "path", qa.Path)
assert.EqualValues(t, "data", qa.Data)
assert.False(t, qa.Prove)
// now add some broadcasts (should all err)
txs := []types.Tx{{1}, {2}, {3}}
_, err = r.BroadcastTxCommit(ctx, txs[0])
assert.Error(t, err, "expected err on broadcast")
_, err = r.BroadcastTxSync(ctx, txs[1])
assert.Error(t, err, "expected err on broadcast")
_, err = r.BroadcastTxAsync(ctx, txs[2])
assert.Error(t, err, "expected err on broadcast")
require.Equal(t, 5, len(r.Calls))
bc := r.Calls[2]
assert.Equal(t, "broadcast_tx_commit", bc.Name)
assert.Nil(t, bc.Response)
require.NotNil(t, bc.Error)
assert.EqualValues(t, bc.Args, txs[0])
bs := r.Calls[3]
assert.Equal(t, "broadcast_tx_sync", bs.Name)
assert.Nil(t, bs.Response)
require.NotNil(t, bs.Error)
assert.EqualValues(t, bs.Args, txs[1])
ba := r.Calls[4]
assert.Equal(t, "broadcast_tx_async", ba.Name)
assert.Nil(t, ba.Response)
require.NotNil(t, ba.Error)
assert.EqualValues(t, ba.Args, txs[2])
}
func TestABCIApp(t *testing.T) {
app := kvstore.NewApplication()
m := mock.ABCIApp{app}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// get some info
info, err := m.ABCIInfo(ctx)
require.NoError(t, err)
assert.Equal(t, `{"size":0}`, info.Response.GetData())
// add a key
key, value := "foo", "bar"
tx := fmt.Sprintf("%s=%s", key, value)
res, err := m.BroadcastTxCommit(ctx, types.Tx(tx))
require.NoError(t, err)
assert.True(t, res.CheckTx.IsOK())
require.NotNil(t, res.TxResult)
assert.True(t, res.TxResult.IsOK())
// commit
// TODO: This may not be necessary in the future
if res.Height == -1 {
m.App.Commit()
}
// check the key
_qres, err := m.ABCIQueryWithOptions(
ctx,
"/key",
bytes.HexBytes(key),
client.ABCIQueryOptions{Prove: true},
)
qres := _qres.Response
require.NoError(t, err)
assert.EqualValues(t, value, qres.Value)
// XXX Check proof
}