Skip to main content

hotmint_consensus/
application.rs

1use ruc::*;
2
3use hotmint_types::Block;
4use hotmint_types::context::{BlockContext, TxContext};
5use hotmint_types::evidence::EquivocationProof;
6use hotmint_types::validator_update::EndBlockResponse;
7
8/// Application interface for the consensus engine.
9///
10/// The lifecycle for each committed block:
11/// 1. `execute_block` — receives all decoded transactions at once; returns
12///    validator updates and events
13/// 2. `on_commit` — notification after the block is finalized
14///
15/// For block proposal:
16/// - `create_payload` — build the payload bytes for a new block
17///
18/// For validation (before voting):
19/// - `validate_block` — full block validation
20/// - `validate_tx` — individual transaction validation for mempool
21///
22/// For evidence:
23/// - `on_evidence` — called when equivocation is detected
24///
25/// All methods have default no-op implementations.
26pub trait Application: Send + Sync {
27    /// Create a payload for a new block proposal.
28    /// Typically pulls transactions from the mempool.
29    ///
30    /// If your mempool is async, use `tokio::runtime::Handle::current().block_on(..)`
31    /// to bridge into this synchronous callback.
32    fn create_payload(&self, _ctx: &BlockContext) -> Vec<u8> {
33        vec![]
34    }
35
36    /// Validate a proposed block before voting.
37    fn validate_block(&self, _block: &Block, _ctx: &BlockContext) -> bool {
38        true
39    }
40
41    /// Validate a single transaction for mempool admission.
42    ///
43    /// An optional [`TxContext`] provides the current chain height and epoch,
44    /// which can be useful for state-dependent validation (nonce checks, etc.).
45    fn validate_tx(&self, _tx: &[u8], _ctx: Option<&TxContext>) -> bool {
46        true
47    }
48
49    /// Execute an entire block in one call.
50    ///
51    /// Receives all decoded transactions from the block payload at once,
52    /// allowing batch-optimised processing (bulk DB writes, parallel
53    /// signature verification, etc.).
54    ///
55    /// Return [`EndBlockResponse`] with `validator_updates` to schedule an
56    /// epoch transition, and/or `events` to emit application-defined events.
57    fn execute_block(&self, _txs: &[&[u8]], _ctx: &BlockContext) -> Result<EndBlockResponse> {
58        Ok(EndBlockResponse::default())
59    }
60
61    /// Called when a block is committed to the chain (notification).
62    fn on_commit(&self, _block: &Block, _ctx: &BlockContext) -> Result<()> {
63        Ok(())
64    }
65
66    /// Called when equivocation (double-voting) is detected.
67    /// The application can use this to implement slashing.
68    fn on_evidence(&self, _proof: &EquivocationProof) -> Result<()> {
69        Ok(())
70    }
71
72    /// Query application state (returns opaque bytes).
73    fn query(&self, _path: &str, _data: &[u8]) -> Result<Vec<u8>> {
74        Ok(vec![])
75    }
76
77    /// Whether this application produces and verifies `app_hash` state roots.
78    ///
79    /// Applications that do not maintain a deterministic state root (e.g. the
80    /// embedded [`NoopApplication`] used by fullnodes without an ABCI backend)
81    /// should return `false`.  Sync will then bypass the app_hash equality
82    /// check and accept the chain's authoritative value, allowing the node to
83    /// follow a chain produced by peers running a real application.
84    fn tracks_app_hash(&self) -> bool {
85        true
86    }
87}
88
89/// No-op application stub for testing and fullnode-without-ABCI mode.
90pub struct NoopApplication;
91
92impl Application for NoopApplication {
93    /// NoopApplication does not maintain state, so app_hash tracking is skipped.
94    fn tracks_app_hash(&self) -> bool {
95        false
96    }
97}