github.com/okex/exchain@v1.8.0/libs/tendermint/rpc/client/mock/abci.go (about) 1 package mock 2 3 import ( 4 abci "github.com/okex/exchain/libs/tendermint/abci/types" 5 "github.com/okex/exchain/libs/tendermint/libs/bytes" 6 "github.com/okex/exchain/libs/tendermint/proxy" 7 "github.com/okex/exchain/libs/tendermint/rpc/client" 8 ctypes "github.com/okex/exchain/libs/tendermint/rpc/core/types" 9 "github.com/okex/exchain/libs/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 a.ABCIInfo() 62 c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx}) 63 // and this gets written in a background thread... 64 if !c.IsErr() { 65 go func() { a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx}) }() // nolint: errcheck 66 } 67 resp := a.App.Info(abci.RequestInfo{}) 68 return &ctypes.ResultBroadcastTx{ 69 Code: c.Code, 70 Data: c.Data, 71 Log: c.Log, 72 Codespace: c.Codespace, 73 Hash: tx.Hash(resp.LastBlockHeight), 74 }, nil 75 } 76 77 func (a ABCIApp) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 78 c := a.App.CheckTx(abci.RequestCheckTx{Tx: tx}) 79 // and this gets written in a background thread... 80 if !c.IsErr() { 81 go func() { a.App.DeliverTx(abci.RequestDeliverTx{Tx: tx}) }() // nolint: errcheck 82 } 83 resp := a.App.Info(abci.RequestInfo{}) 84 return &ctypes.ResultBroadcastTx{ 85 Code: c.Code, 86 Data: c.Data, 87 Log: c.Log, 88 Codespace: c.Codespace, 89 Hash: tx.Hash(resp.LastBlockHeight), 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() (*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(path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) { 112 return m.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions) 113 } 114 115 func (m ABCIMock) ABCIQueryWithOptions( 116 path string, 117 data bytes.HexBytes, 118 opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 119 res, err := m.Query.GetResponse(QueryArgs{path, data, opts.Height, opts.Prove}) 120 if err != nil { 121 return nil, err 122 } 123 resQuery := res.(abci.ResponseQuery) 124 return &ctypes.ResultABCIQuery{Response: resQuery}, nil 125 } 126 127 func (m ABCIMock) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) { 128 res, err := m.BroadcastCommit.GetResponse(tx) 129 if err != nil { 130 return nil, err 131 } 132 return res.(*ctypes.ResultBroadcastTxCommit), nil 133 } 134 135 func (m ABCIMock) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 136 res, err := m.Broadcast.GetResponse(tx) 137 if err != nil { 138 return nil, err 139 } 140 return res.(*ctypes.ResultBroadcastTx), nil 141 } 142 143 func (m ABCIMock) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 144 res, err := m.Broadcast.GetResponse(tx) 145 if err != nil { 146 return nil, err 147 } 148 return res.(*ctypes.ResultBroadcastTx), nil 149 } 150 151 // ABCIRecorder can wrap another type (ABCIApp, ABCIMock, or Client) 152 // and record all ABCI related calls. 153 type ABCIRecorder struct { 154 Client client.ABCIClient 155 Calls []Call 156 } 157 158 func NewABCIRecorder(client client.ABCIClient) *ABCIRecorder { 159 return &ABCIRecorder{ 160 Client: client, 161 Calls: []Call{}, 162 } 163 } 164 165 type QueryArgs struct { 166 Path string 167 Data bytes.HexBytes 168 Height int64 169 Prove bool 170 } 171 172 func (r *ABCIRecorder) addCall(call Call) { 173 r.Calls = append(r.Calls, call) 174 } 175 176 func (r *ABCIRecorder) ABCIInfo() (*ctypes.ResultABCIInfo, error) { 177 res, err := r.Client.ABCIInfo() 178 r.addCall(Call{ 179 Name: "abci_info", 180 Response: res, 181 Error: err, 182 }) 183 return res, err 184 } 185 186 func (r *ABCIRecorder) ABCIQuery(path string, data bytes.HexBytes) (*ctypes.ResultABCIQuery, error) { 187 return r.ABCIQueryWithOptions(path, data, client.DefaultABCIQueryOptions) 188 } 189 190 func (r *ABCIRecorder) ABCIQueryWithOptions( 191 path string, 192 data bytes.HexBytes, 193 opts client.ABCIQueryOptions) (*ctypes.ResultABCIQuery, error) { 194 res, err := r.Client.ABCIQueryWithOptions(path, data, opts) 195 r.addCall(Call{ 196 Name: "abci_query", 197 Args: QueryArgs{path, data, opts.Height, opts.Prove}, 198 Response: res, 199 Error: err, 200 }) 201 return res, err 202 } 203 204 func (r *ABCIRecorder) BroadcastTxCommit(tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) { 205 res, err := r.Client.BroadcastTxCommit(tx) 206 r.addCall(Call{ 207 Name: "broadcast_tx_commit", 208 Args: tx, 209 Response: res, 210 Error: err, 211 }) 212 return res, err 213 } 214 215 func (r *ABCIRecorder) BroadcastTxAsync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 216 res, err := r.Client.BroadcastTxAsync(tx) 217 r.addCall(Call{ 218 Name: "broadcast_tx_async", 219 Args: tx, 220 Response: res, 221 Error: err, 222 }) 223 return res, err 224 } 225 226 func (r *ABCIRecorder) BroadcastTxSync(tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 227 res, err := r.Client.BroadcastTxSync(tx) 228 r.addCall(Call{ 229 Name: "broadcast_tx_sync", 230 Args: tx, 231 Response: res, 232 Error: err, 233 }) 234 return res, err 235 }