1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use async_trait::async_trait;
use cnidarium::StateWrite;
use filament_chain::genesis::AppState;
use tendermint::abci::request;

pub mod accounts;
pub mod assets;
pub mod staking;

pub use accounts::Accounts;
pub use assets::Assets;
pub use staking::Staking;

pub enum Component {
    Accounts(Accounts),
    Assets(Assets),
    Staking(Staking),
}

#[async_trait]
impl ABCIComponent for Component {
    async fn init_chain<S: StateWrite>(&self, state: &mut S, app_state: &AppState) {
        match self {
            Component::Accounts(cmp) => cmp.init_chain(state, app_state),
            Component::Assets(cmp) => cmp.init_chain(state, app_state),
            Component::Staking(cmp) => cmp.init_chain(state, app_state),
        }
        .await
    }

    async fn begin_block<S: StateWrite>(&self, state: &mut S, begin_block: &request::BeginBlock) {
        match self {
            Component::Accounts(cmp) => cmp.begin_block(state, begin_block),
            Component::Assets(cmp) => cmp.begin_block(state, begin_block),
            Component::Staking(cmp) => cmp.begin_block(state, begin_block),
        }
        .await
    }

    async fn end_block<S: StateWrite>(&self, state: &mut S, end_block: &request::EndBlock) {
        match self {
            Component::Accounts(cmp) => cmp.end_block(state, end_block),
            Component::Assets(cmp) => cmp.end_block(state, end_block),
            Component::Staking(cmp) => cmp.end_block(state, end_block),
        }
        .await
    }
}

/// A component to be called for chain and block related ABCI calls.
#[async_trait]
pub trait ABCIComponent: Send + Sync + 'static {
    /// * Called once upon genesis.
    /// * If ResponseInitChain.Validators is empty, the initial validator set will be the
    ///   RequestInitChain.Validators
    /// * If ResponseInitChain.Validators is not empty, it will be the initial validator set
    ///   (regardless of what is in RequestInitChain.Validators).
    /// * This allows the app to decide if it wants to accept the initial validator set proposed by
    ///   tendermint (ie. in the genesis file), or if it wants to use a different one (perhaps
    ///   computed based on some application specific information in the genesis file).
    ///
    /// <https://github.com/tendermint/tendermint/blob/main/spec/abci/abci.md#initchain>
    async fn init_chain<S: StateWrite>(&self, state: &mut S, app_state: &AppState);

    /// * Signals the beginning of a new block.
    /// * Called prior to any `DeliverTx` method calls.
    /// * The header contains the height, timestamp, and more - it exactly matches the Tendermint
    ///   block header. We may seek to generalize this in the future.
    /// * The `LastCommitInfo` and `ByzantineValidators` can be used to determine rewards and
    ///   punishments for the validators.
    ///
    /// <https://github.com/tendermint/tendermint/blob/main/spec/abci/abci.md#initchain>
    async fn begin_block<S: StateWrite>(&self, state: &mut S, begin_block: &request::BeginBlock);

    /// * Signals the end of a block.
    /// * Called after all the transactions for the current block have been delivered, prior to the
    ///   block's `Commit` message.
    /// * Optional `validator_updates` triggered by block `H`. These updates affect validation for
    ///   blocks `H+1`, `H+2`, and `H+3`.
    /// * Heights following a validator update are affected in the following way:
    /// * `H+1`: `NextValidatorsHash` includes the new `validator_updates` value.
    /// * `H+2`: The validator set change takes effect and `ValidatorsHash` is updated.
    /// * `H+3`: `LastCommitInfo` is changed to include the altered validator set.
    /// * `consensus_param_updates` returned for block `H` apply to the consensus params for block `H+1`. For more information on the consensus parameters, see the [application spec entry on consensus parameters](https://github.com/tendermint/tendermint/blob/main/spec/abci/apps.md#consensus-parameters).
    ///
    /// <https://github.com/tendermint/tendermint/blob/main/spec/abci/abci.md#endblock>
    async fn end_block<S: StateWrite>(&self, state: &mut S, end_block: &request::EndBlock);
}