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