github.com/vipernet-xyz/tm@v0.34.24/rpc/client/mock/abci.go (about)

     1  package mock
     2  
     3  import (
     4  	"context"
     5  
     6  	abci "github.com/vipernet-xyz/tm/abci/types"
     7  	"github.com/vipernet-xyz/tm/libs/bytes"
     8  	"github.com/vipernet-xyz/tm/proxy"
     9  	"github.com/vipernet-xyz/tm/rpc/client"
    10  	ctypes "github.com/vipernet-xyz/tm/rpc/core/types"
    11  	"github.com/vipernet-xyz/tm/types"
    12  )
    13  
    14  // ABCIApp will send all abci related request to the named app,
    15  // so you can test app behavior from a client without needing
    16  // an entire tendermint node
    17  type ABCIApp struct {
    18  	App abci.Application
    19  }
    20  
    21  var (
    22  	_ client.ABCIClient = ABCIApp{}
    23  	_ client.ABCIClient = ABCIMock{}
    24  	_ client.ABCIClient = (*ABCIRecorder)(nil)
    25  )
    26  
    27  func (a ABCIApp) ABCIInfo(ctx context.Context) (*ctypes.ResultABCIInfo, error) {
    28  	return &ctypes.ResultABCIInfo{Response: a.App.Info(proxy.RequestInfo)}, nil
    29  }
    30  
    31  func (a ABCIApp) ABCIQuery(ctx context.Context, path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
    32  	return a.ABCIQueryWithOptions(ctx, path, data, client.DefaultABCIQueryOptions)
    33  }
    34  
    35  func (a ABCIApp) ABCIQueryWithOptions(
    36  	ctx context.Context,
    37  	path string,
    38  	data bytes.HexBytes,
    39  	opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
    40  	q := a.App.Query(abci.RequestQuery{
    41  		Data:   data,
    42  		Path:   path,
    43  		Height: opts.Height,
    44  		Prove:  opts.Prove,
    45  	})
    46  	return &ctypes.ResultABCIQuery{Response: q}, nil
    47  }
    48  
    49  // NOTE: Caller should call a.App.Commit() separately,
    50  // this function does not actually wait for a commit.
    51  // TODO: Make it wait for a commit and set res.Height appropriately.
    52  func (a ABCIApp) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
    53  	res := ctypes.ResultBroadcastTxCommit{}
    54  	res.CheckTx = a.App.CheckTx(abci.RequestCheckTx{Tx: tx})
    55  	if res.CheckTx.IsErr() {
    56  		return &res, nil
    57  	}
    58  	res.DeliverTx = a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx})
    59  	res.Height = -1 // TODO
    60  	return &res, nil
    61  }
    62  
    63  func (a ABCIApp) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    64  	c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx})
    65  	// and this gets written in a background thread...
    66  	if !c.IsErr() {
    67  		go func() { a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx}) }()
    68  	}
    69  	return &ctypes.ResultBroadcastTx{
    70  		Code:      c.Code,
    71  		Data:      c.Data,
    72  		Log:       c.Log,
    73  		Codespace: c.Codespace,
    74  		Hash:      tx.Hash(),
    75  	}, nil
    76  }
    77  
    78  func (a ABCIApp) BroadcastTxSync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    79  	c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx})
    80  	// and this gets written in a background thread...
    81  	if !c.IsErr() {
    82  		go func() { a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx}) }()
    83  	}
    84  	return &ctypes.ResultBroadcastTx{
    85  		Code:      c.Code,
    86  		Data:      c.Data,
    87  		Log:       c.Log,
    88  		Codespace: c.Codespace,
    89  		Hash:      tx.Hash(),
    90  	}, nil
    91  }
    92  
    93  // ABCIMock will send all abci related request to the named app,
    94  // so you can test app behavior from a client without needing
    95  // an entire tendermint node
    96  type ABCIMock struct {
    97  	Info            Call
    98  	Query           Call
    99  	BroadcastCommit Call
   100  	Broadcast       Call
   101  }
   102  
   103  func (m ABCIMock) ABCIInfo(ctx context.Context) (*ctypes.ResultABCIInfo, error) {
   104  	res, err := m.Info.GetResponse(nil)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	return &ctypes.ResultABCIInfo{Response: res.(abci.ResponseInfo)}, nil
   109  }
   110  
   111  func (m ABCIMock) ABCIQuery(ctx context.Context, path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) {
   112  	return m.ABCIQueryWithOptions(ctx, path, data, client.DefaultABCIQueryOptions)
   113  }
   114  
   115  func (m ABCIMock) ABCIQueryWithOptions(
   116  	ctx context.Context,
   117  	path string,
   118  	data bytes.HexBytes,
   119  	opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
   120  	res, err := m.Query.GetResponse(QueryArgs{path, data, opts.Height, opts.Prove})
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  	resQuery := res.(abci.ResponseQuery)
   125  	return &ctypes.ResultABCIQuery{Response: resQuery}, nil
   126  }
   127  
   128  func (m ABCIMock) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
   129  	res, err := m.BroadcastCommit.GetResponse(tx)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	return res.(*ctypes.ResultBroadcastTxCommit), nil
   134  }
   135  
   136  func (m ABCIMock) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   137  	res, err := m.Broadcast.GetResponse(tx)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	return res.(*ctypes.ResultBroadcastTx), nil
   142  }
   143  
   144  func (m ABCIMock) BroadcastTxSync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   145  	res, err := m.Broadcast.GetResponse(tx)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  	return res.(*ctypes.ResultBroadcastTx), nil
   150  }
   151  
   152  // ABCIRecorder can wrap another type (ABCIApp, ABCIMock, or Client)
   153  // and record all ABCI related calls.
   154  type ABCIRecorder struct {
   155  	Client client.ABCIClient
   156  	Calls  []Call
   157  }
   158  
   159  func NewABCIRecorder(client client.ABCIClient) *ABCIRecorder {
   160  	return &ABCIRecorder{
   161  		Client: client,
   162  		Calls:  []Call{},
   163  	}
   164  }
   165  
   166  type QueryArgs struct {
   167  	Path   string
   168  	Data   bytes.HexBytes
   169  	Height int64
   170  	Prove  bool
   171  }
   172  
   173  func (r *ABCIRecorder) addCall(call Call) {
   174  	r.Calls = append(r.Calls, call)
   175  }
   176  
   177  func (r *ABCIRecorder) ABCIInfo(ctx context.Context) (*ctypes.ResultABCIInfo, error) {
   178  	res, err := r.Client.ABCIInfo(ctx)
   179  	r.addCall(Call{
   180  		Name:     "abci_info",
   181  		Response: res,
   182  		Error:    err,
   183  	})
   184  	return res, err
   185  }
   186  
   187  func (r *ABCIRecorder) ABCIQuery(
   188  	ctx context.Context,
   189  	path string,
   190  	data bytes.HexBytes,
   191  ) (*ctypes.ResultABCIQuery, error) {
   192  	return r.ABCIQueryWithOptions(ctx, path, data, client.DefaultABCIQueryOptions)
   193  }
   194  
   195  func (r *ABCIRecorder) ABCIQueryWithOptions(
   196  	ctx context.Context,
   197  	path string,
   198  	data bytes.HexBytes,
   199  	opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) {
   200  	res, err := r.Client.ABCIQueryWithOptions(ctx, path, data, opts)
   201  	r.addCall(Call{
   202  		Name:     "abci_query",
   203  		Args:     QueryArgs{path, data, opts.Height, opts.Prove},
   204  		Response: res,
   205  		Error:    err,
   206  	})
   207  	return res, err
   208  }
   209  
   210  func (r *ABCIRecorder) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
   211  	res, err := r.Client.BroadcastTxCommit(ctx, tx)
   212  	r.addCall(Call{
   213  		Name:     "broadcast_tx_commit",
   214  		Args:     tx,
   215  		Response: res,
   216  		Error:    err,
   217  	})
   218  	return res, err
   219  }
   220  
   221  func (r *ABCIRecorder) BroadcastTxAsync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   222  	res, err := r.Client.BroadcastTxAsync(ctx, tx)
   223  	r.addCall(Call{
   224  		Name:     "broadcast_tx_async",
   225  		Args:     tx,
   226  		Response: res,
   227  		Error:    err,
   228  	})
   229  	return res, err
   230  }
   231  
   232  func (r *ABCIRecorder) BroadcastTxSync(ctx context.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
   233  	res, err := r.Client.BroadcastTxSync(ctx, tx)
   234  	r.addCall(Call{
   235  		Name:     "broadcast_tx_sync",
   236  		Args:     tx,
   237  		Response: res,
   238  		Error:    err,
   239  	})
   240  	return res, err
   241  }