github.com/Oyster-zx/tendermint@v0.34.24-fork/rpc/client/mock/abci.go (about) 1 package mock 2 3 import ( 4 "context" 5 6 abci "github.com/tendermint/tendermint/abci/types" 7 "github.com/tendermint/tendermint/libs/bytes" 8 "github.com/tendermint/tendermint/proxy" 9 "github.com/tendermint/tendermint/rpc/client" 10 ctypes "github.com/tendermint/tendermint/rpc/core/types" 11 "github.com/tendermint/tendermint/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 }