|
| 1 | +//! ABCI application interface. |
| 2 | +
|
| 3 | +#[cfg(feature = "echo-app")] |
| 4 | +pub mod echo; |
| 5 | +#[cfg(feature = "kvstore-app")] |
| 6 | +pub mod kvstore; |
| 7 | + |
| 8 | +use tendermint_proto::abci::request::Value; |
| 9 | +use tendermint_proto::abci::{ |
| 10 | + response, Request, RequestApplySnapshotChunk, RequestBeginBlock, RequestCheckTx, |
| 11 | + RequestDeliverTx, RequestEcho, RequestEndBlock, RequestInfo, RequestInitChain, |
| 12 | + RequestLoadSnapshotChunk, RequestOfferSnapshot, RequestQuery, RequestSetOption, Response, |
| 13 | + ResponseApplySnapshotChunk, ResponseBeginBlock, ResponseCheckTx, ResponseCommit, |
| 14 | + ResponseDeliverTx, ResponseEcho, ResponseEndBlock, ResponseFlush, ResponseInfo, |
| 15 | + ResponseInitChain, ResponseListSnapshots, ResponseLoadSnapshotChunk, ResponseOfferSnapshot, |
| 16 | + ResponseQuery, ResponseSetOption, |
| 17 | +}; |
| 18 | + |
| 19 | +/// An ABCI application. |
| 20 | +/// |
| 21 | +/// Applications are `Send` + `Clone` + `'static` because they are cloned for |
| 22 | +/// each incoming connection to the ABCI [`Server`]. It is up to the |
| 23 | +/// application developer to manage shared state between these clones of their |
| 24 | +/// application. |
| 25 | +/// |
| 26 | +/// [`Server`]: crate::Server |
| 27 | +pub trait Application: Send + Clone + 'static { |
| 28 | + /// Echo back the same message as provided in the request. |
| 29 | + fn echo(&self, request: RequestEcho) -> ResponseEcho { |
| 30 | + ResponseEcho { |
| 31 | + message: request.message, |
| 32 | + } |
| 33 | + } |
| 34 | + |
| 35 | + /// Provide information about the ABCI application. |
| 36 | + fn info(&self, _request: RequestInfo) -> ResponseInfo { |
| 37 | + Default::default() |
| 38 | + } |
| 39 | + |
| 40 | + /// Called once upon genesis. |
| 41 | + fn init_chain(&self, _request: RequestInitChain) -> ResponseInitChain { |
| 42 | + Default::default() |
| 43 | + } |
| 44 | + |
| 45 | + /// Query the application for data at the current or past height. |
| 46 | + fn query(&self, _request: RequestQuery) -> ResponseQuery { |
| 47 | + Default::default() |
| 48 | + } |
| 49 | + |
| 50 | + /// Check the given transaction before putting it into the local mempool. |
| 51 | + fn check_tx(&self, _request: RequestCheckTx) -> ResponseCheckTx { |
| 52 | + Default::default() |
| 53 | + } |
| 54 | + |
| 55 | + /// Signals the beginning of a new block, prior to any `DeliverTx` calls. |
| 56 | + fn begin_block(&self, _request: RequestBeginBlock) -> ResponseBeginBlock { |
| 57 | + Default::default() |
| 58 | + } |
| 59 | + |
| 60 | + /// Apply a transaction to the application's state. |
| 61 | + fn deliver_tx(&self, _request: RequestDeliverTx) -> ResponseDeliverTx { |
| 62 | + Default::default() |
| 63 | + } |
| 64 | + |
| 65 | + /// Signals the end of a block. |
| 66 | + fn end_block(&self, _request: RequestEndBlock) -> ResponseEndBlock { |
| 67 | + Default::default() |
| 68 | + } |
| 69 | + |
| 70 | + /// Signals that messages queued on the client should be flushed to the server. |
| 71 | + fn flush(&self) -> ResponseFlush { |
| 72 | + ResponseFlush {} |
| 73 | + } |
| 74 | + |
| 75 | + /// Commit the current state at the current height. |
| 76 | + fn commit(&self) -> ResponseCommit { |
| 77 | + Default::default() |
| 78 | + } |
| 79 | + |
| 80 | + /// Allows the Tendermint node to request that the application set an |
| 81 | + /// option to a particular value. |
| 82 | + fn set_option(&self, _request: RequestSetOption) -> ResponseSetOption { |
| 83 | + Default::default() |
| 84 | + } |
| 85 | + |
| 86 | + /// Used during state sync to discover available snapshots on peers. |
| 87 | + fn list_snapshots(&self) -> ResponseListSnapshots { |
| 88 | + Default::default() |
| 89 | + } |
| 90 | + |
| 91 | + /// Called when bootstrapping the node using state sync. |
| 92 | + fn offer_snapshot(&self, _request: RequestOfferSnapshot) -> ResponseOfferSnapshot { |
| 93 | + Default::default() |
| 94 | + } |
| 95 | + |
| 96 | + /// Used during state sync to retrieve chunks of snapshots from peers. |
| 97 | + fn load_snapshot_chunk(&self, _request: RequestLoadSnapshotChunk) -> ResponseLoadSnapshotChunk { |
| 98 | + Default::default() |
| 99 | + } |
| 100 | + |
| 101 | + /// Apply the given snapshot chunk to the application's state. |
| 102 | + fn apply_snapshot_chunk( |
| 103 | + &self, |
| 104 | + _request: RequestApplySnapshotChunk, |
| 105 | + ) -> ResponseApplySnapshotChunk { |
| 106 | + Default::default() |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +/// Provides a mechanism for the [`Server`] to execute incoming requests while |
| 111 | +/// expecting the correct response types. |
| 112 | +pub trait RequestDispatcher { |
| 113 | + /// Executes the relevant application method based on the type of the |
| 114 | + /// request, and produces the corresponding response. |
| 115 | + fn handle(&self, request: Request) -> Response; |
| 116 | +} |
| 117 | + |
| 118 | +// Implement `RequestDispatcher` for all `Application`s. |
| 119 | +impl<A: Application> RequestDispatcher for A { |
| 120 | + fn handle(&self, request: Request) -> Response { |
| 121 | + tracing::debug!("Incoming request: {:?}", request); |
| 122 | + Response { |
| 123 | + value: Some(match request.value.unwrap() { |
| 124 | + Value::Echo(req) => response::Value::Echo(self.echo(req)), |
| 125 | + Value::Flush(_) => response::Value::Flush(self.flush()), |
| 126 | + Value::Info(req) => response::Value::Info(self.info(req)), |
| 127 | + Value::SetOption(req) => response::Value::SetOption(self.set_option(req)), |
| 128 | + Value::InitChain(req) => response::Value::InitChain(self.init_chain(req)), |
| 129 | + Value::Query(req) => response::Value::Query(self.query(req)), |
| 130 | + Value::BeginBlock(req) => response::Value::BeginBlock(self.begin_block(req)), |
| 131 | + Value::CheckTx(req) => response::Value::CheckTx(self.check_tx(req)), |
| 132 | + Value::DeliverTx(req) => response::Value::DeliverTx(self.deliver_tx(req)), |
| 133 | + Value::EndBlock(req) => response::Value::EndBlock(self.end_block(req)), |
| 134 | + Value::Commit(_) => response::Value::Commit(self.commit()), |
| 135 | + Value::ListSnapshots(_) => response::Value::ListSnapshots(self.list_snapshots()), |
| 136 | + Value::OfferSnapshot(req) => { |
| 137 | + response::Value::OfferSnapshot(self.offer_snapshot(req)) |
| 138 | + } |
| 139 | + Value::LoadSnapshotChunk(req) => { |
| 140 | + response::Value::LoadSnapshotChunk(self.load_snapshot_chunk(req)) |
| 141 | + } |
| 142 | + Value::ApplySnapshotChunk(req) => { |
| 143 | + response::Value::ApplySnapshotChunk(self.apply_snapshot_chunk(req)) |
| 144 | + } |
| 145 | + }), |
| 146 | + } |
| 147 | + } |
| 148 | +} |
0 commit comments