Files
tendermint/rpc/client/mock/abci.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

243 lines
6.8 KiB
Go

package mock
import (
"context"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/internal/proxy"
"github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/rpc/coretypes"
"github.com/tendermint/tendermint/types"
)
// ABCIApp will send all abci related request to the named app,
// so you can test app behavior from a client without needing
// an entire tendermint node
type ABCIApp struct {
App abci.Application
}
var (
_ client.ABCIClient = ABCIApp{}
_ client.ABCIClient = ABCIMock{}
_ client.ABCIClient = (*ABCIRecorder)(nil)
)
func (a ABCIApp) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) {
return &coretypes.ResultABCIInfo{Response: a.App.Info(proxy.RequestInfo)}, nil
}
func (a ABCIApp) ABCIQuery(ctx context.Context, path string, data bytes.HexBytes) (*coretypes.ResultABCIQuery, error) {
return a.ABCIQueryWithOptions(ctx, path, data, client.DefaultABCIQueryOptions)
}
func (a ABCIApp) ABCIQueryWithOptions(
ctx context.Context,
path string,
data bytes.HexBytes,
opts client.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) {
q := a.App.Query(abci.RequestQuery{
Data: data,
Path: path,
Height: opts.Height,
Prove: opts.Prove,
})
return &coretypes.ResultABCIQuery{Response: q}, nil
}
// NOTE: Caller should call a.App.Commit() separately,
// this function does not actually wait for a commit.
// TODO: Make it wait for a commit and set res.Height appropriately.
func (a ABCIApp) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) {
res := coretypes.ResultBroadcastTxCommit{}
res.CheckTx = a.App.CheckTx(abci.RequestCheckTx{Tx: tx})
if res.CheckTx.IsErr() {
return &res, nil
}
fb := a.App.FinalizeBlock(abci.RequestFinalizeBlock{Txs: [][]byte{tx}})
res.TxResult = *fb.TxResults[0]
res.Height = -1 // TODO
return &res, nil
}
func (a ABCIApp) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) {
c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx})
// and this gets written in a background thread...
if !c.IsErr() {
go func() { a.App.FinalizeBlock(abci.RequestFinalizeBlock{Txs: [][]byte{tx}}) }()
}
return &coretypes.ResultBroadcastTx{
Code: c.Code,
Data: c.Data,
Log: c.Log,
Codespace: c.Codespace,
Hash: tx.Hash(),
}, nil
}
func (a ABCIApp) BroadcastTxSync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) {
c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx})
// and this gets written in a background thread...
if !c.IsErr() {
go func() { a.App.FinalizeBlock(abci.RequestFinalizeBlock{Txs: [][]byte{tx}}) }()
}
return &coretypes.ResultBroadcastTx{
Code: c.Code,
Data: c.Data,
Log: c.Log,
Codespace: c.Codespace,
Hash: tx.Hash(),
}, nil
}
// ABCIMock will send all abci related request to the named app,
// so you can test app behavior from a client without needing
// an entire tendermint node
type ABCIMock struct {
Info Call
Query Call
BroadcastCommit Call
Broadcast Call
}
func (m ABCIMock) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) {
res, err := m.Info.GetResponse(nil)
if err != nil {
return nil, err
}
return &coretypes.ResultABCIInfo{Response: res.(abci.ResponseInfo)}, nil
}
func (m ABCIMock) ABCIQuery(ctx context.Context, path string, data bytes.HexBytes) (*coretypes.ResultABCIQuery, error) {
return m.ABCIQueryWithOptions(ctx, path, data, client.DefaultABCIQueryOptions)
}
func (m ABCIMock) ABCIQueryWithOptions(
ctx context.Context,
path string,
data bytes.HexBytes,
opts client.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) {
res, err := m.Query.GetResponse(QueryArgs{path, data, opts.Height, opts.Prove})
if err != nil {
return nil, err
}
resQuery := res.(abci.ResponseQuery)
return &coretypes.ResultABCIQuery{Response: resQuery}, nil
}
func (m ABCIMock) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) {
res, err := m.BroadcastCommit.GetResponse(tx)
if err != nil {
return nil, err
}
return res.(*coretypes.ResultBroadcastTxCommit), nil
}
func (m ABCIMock) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) {
res, err := m.Broadcast.GetResponse(tx)
if err != nil {
return nil, err
}
return res.(*coretypes.ResultBroadcastTx), nil
}
func (m ABCIMock) BroadcastTxSync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) {
res, err := m.Broadcast.GetResponse(tx)
if err != nil {
return nil, err
}
return res.(*coretypes.ResultBroadcastTx), nil
}
// ABCIRecorder can wrap another type (ABCIApp, ABCIMock, or Client)
// and record all ABCI related calls.
type ABCIRecorder struct {
Client client.ABCIClient
Calls []Call
}
func NewABCIRecorder(client client.ABCIClient) *ABCIRecorder {
return &ABCIRecorder{
Client: client,
Calls: []Call{},
}
}
type QueryArgs struct {
Path string
Data bytes.HexBytes
Height int64
Prove bool
}
func (r *ABCIRecorder) addCall(call Call) {
r.Calls = append(r.Calls, call)
}
func (r *ABCIRecorder) ABCIInfo(ctx context.Context) (*coretypes.ResultABCIInfo, error) {
res, err := r.Client.ABCIInfo(ctx)
r.addCall(Call{
Name: "abci_info",
Response: res,
Error: err,
})
return res, err
}
func (r *ABCIRecorder) ABCIQuery(
ctx context.Context,
path string,
data bytes.HexBytes,
) (*coretypes.ResultABCIQuery, error) {
return r.ABCIQueryWithOptions(ctx, path, data, client.DefaultABCIQueryOptions)
}
func (r *ABCIRecorder) ABCIQueryWithOptions(
ctx context.Context,
path string,
data bytes.HexBytes,
opts client.ABCIQueryOptions) (*coretypes.ResultABCIQuery, error) {
res, err := r.Client.ABCIQueryWithOptions(ctx, path, data, opts)
r.addCall(Call{
Name: "abci_query",
Args: QueryArgs{path, data, opts.Height, opts.Prove},
Response: res,
Error: err,
})
return res, err
}
func (r *ABCIRecorder) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTxCommit, error) {
res, err := r.Client.BroadcastTxCommit(ctx, tx)
r.addCall(Call{
Name: "broadcast_tx_commit",
Args: tx,
Response: res,
Error: err,
})
return res, err
}
func (r *ABCIRecorder) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) {
res, err := r.Client.BroadcastTxAsync(ctx, tx)
r.addCall(Call{
Name: "broadcast_tx_async",
Args: tx,
Response: res,
Error: err,
})
return res, err
}
func (r *ABCIRecorder) BroadcastTxSync(ctx context.Context, tx types.Tx) (*coretypes.ResultBroadcastTx, error) {
res, err := r.Client.BroadcastTxSync(ctx, tx)
r.addCall(Call{
Name: "broadcast_tx_sync",
Args: tx,
Response: res,
Error: err,
})
return res, err
}