async_abci/
state.rs

1use tm_abci::{request, Request, RequestBeginBlock, RequestDeliverTx, RequestFinalizedBlock};
2
3use crate::{Error, Result};
4
5use std::mem;
6
7#[derive(Debug)]
8pub enum ConsensusState {
9    Begin,
10    ConsensusBegin,
11    ConsensusBeginFlush,
12    BlockBegin,
13    BlockBeginFlush,
14    TxReceived,
15    BlockEnd,
16    DeliverBlock,
17    BlockCommit,
18    BlockCommitFlush,
19}
20
21impl Default for ConsensusState {
22    fn default() -> Self {
23        Self::Begin
24    }
25}
26
27#[derive(Default)]
28pub struct ConsensusQueue {
29    pub block: RequestBeginBlock,
30    pub txs: Vec<RequestDeliverTx>,
31    pub state: ConsensusState,
32    pub packet: Option<Request>,
33    pub flushed: bool,
34}
35
36impl ConsensusQueue {
37    pub fn new(pkt: Request) -> Result<Self> {
38        match pkt.value.ok_or(Error::ABCIFormatError)? {
39            request::Value::InitChain(_) => Ok(Default::default()),
40            request::Value::BeginBlock(block) => {
41                let cq = ConsensusQueue {
42                    block,
43                    txs: Vec::new(),
44                    state: ConsensusState::Begin,
45                    packet: None,
46                    flushed: false,
47                };
48                Ok(cq)
49            }
50            _ => Err(Error::ABCIPacketError),
51        }
52    }
53
54    pub fn is_consensus(pkt: &Request) -> bool {
55        matches!(pkt.value, Some(request::Value::InitChain(_)))
56    }
57
58    pub fn is_deliver_block(&self) -> bool {
59        matches!(self.state, ConsensusState::DeliverBlock)
60    }
61
62    pub fn is_sendable(&self) -> bool {
63        matches!(self.state, ConsensusState::ConsensusBeginFlush)
64    }
65
66    pub fn is_begin_block_flush(&self) -> bool {
67        matches!(self.state, ConsensusState::BlockBeginFlush)
68    }
69
70    pub fn is_commit(&self) -> bool {
71        matches!(self.state, ConsensusState::BlockCommit)
72    }
73
74    pub fn is_commit_flush(&self) -> bool {
75        matches!(self.state, ConsensusState::BlockCommitFlush)
76    }
77
78    pub fn add_pkt(&mut self, pkt: Request) -> Result<()> {
79        match (&self.state, pkt.value.ok_or(Error::ABCIFormatError)?) {
80            // Begin -> ConsensusBegin
81            (ConsensusState::Begin, request::Value::InitChain(p)) => {
82                self.packet = Some(Request {
83                    value: Some(request::Value::InitChain(p)),
84                });
85                self.state = ConsensusState::ConsensusBegin;
86            }
87            // ConsensusBegin -> ConsensusBeginFlush
88            (ConsensusState::ConsensusBegin, request::Value::Flush(_)) => {
89                self.state = ConsensusState::ConsensusBeginFlush;
90                self.flushed = false;
91            }
92            // ConsensusBeginFlush -> ConsensusBeginFlush
93            (ConsensusState::ConsensusBeginFlush, request::Value::Flush(_)) => {
94                self.state = ConsensusState::ConsensusBeginFlush;
95                self.flushed = true;
96            }
97            // ConsensusBeginFlush -> BlockBegin
98            (ConsensusState::ConsensusBeginFlush, request::Value::BeginBlock(p)) => {
99                self.block = p;
100                self.state = ConsensusState::BlockBegin;
101                self.flushed = false;
102            }
103            // Begin -> BlockBegin
104            (ConsensusState::Begin, request::Value::BeginBlock(p)) => {
105                self.block = p;
106                self.state = ConsensusState::BlockBegin;
107            }
108            // BlockBegin -> BlockBeginFlush
109            (ConsensusState::BlockBegin, request::Value::Flush(_)) => {
110                self.state = ConsensusState::BlockBeginFlush;
111                self.flushed = false;
112            }
113            // BlockBeginFlush -> BlockBeginFlush
114            (ConsensusState::BlockBeginFlush, request::Value::Flush(_)) => {
115                self.state = ConsensusState::BlockBeginFlush;
116                self.flushed = true;
117            }
118            // BlockBeginFlush -> TxReceived
119            (ConsensusState::BlockBeginFlush, request::Value::DeliverTx(p)) => {
120                self.txs.push(p);
121                self.state = ConsensusState::TxReceived;
122                self.flushed = false;
123            }
124            // TxReceived -> TxReceived
125            (ConsensusState::TxReceived, request::Value::DeliverTx(p)) => {
126                self.txs.push(p);
127            }
128            // TxReceived -> BlockEnd
129            (ConsensusState::TxReceived, request::Value::EndBlock(_)) => {
130                self.state = ConsensusState::BlockEnd;
131            }
132            // BlockBeginFlush -> BlockEnd
133            (ConsensusState::BlockBeginFlush, request::Value::EndBlock(_)) => {
134                self.state = ConsensusState::BlockEnd;
135                self.flushed = false;
136            }
137            // BlockEnd -> DeliverBlock
138            (ConsensusState::BlockEnd, request::Value::Flush(_)) => {
139                self.state = ConsensusState::DeliverBlock;
140                self.flushed = false;
141            }
142            // DeliverBlock -> DeliverBlock
143            (ConsensusState::DeliverBlock, request::Value::Flush(_)) => {
144                self.state = ConsensusState::DeliverBlock;
145                self.flushed = true;
146            }
147            // DeliverBlock -> BlockCommit
148            (ConsensusState::DeliverBlock, request::Value::Commit(_)) => {
149                self.state = ConsensusState::BlockCommit;
150                self.flushed = false;
151            }
152            // BlockCommit -> BlockCommitFlush
153            (ConsensusState::BlockCommit, request::Value::Flush(_)) => {
154                self.state = ConsensusState::BlockCommitFlush;
155                self.flushed = false;
156            }
157            // BlockCommitFlush -> BlockCommitFlush
158            (ConsensusState::BlockCommitFlush, request::Value::Flush(_)) => {
159                self.state = ConsensusState::BlockCommitFlush;
160                self.flushed = true;
161            }
162            // BlockCommitFlush -> BlockBegin
163            (ConsensusState::BlockCommitFlush, request::Value::BeginBlock(p)) => {
164                self.block = p;
165                self.state = ConsensusState::BlockBegin;
166                self.flushed = false;
167            }
168            _ => return Err(Error::ABCIPacketError),
169        }
170
171        Ok(())
172    }
173
174    pub fn to_block(&mut self) -> Result<RequestFinalizedBlock> {
175        if let ConsensusState::DeliverBlock = self.state {
176            let block = mem::take(&mut self.block);
177            let txs = mem::take(&mut self.txs);
178
179            Ok(RequestFinalizedBlock::new(block, txs))
180        } else {
181            Err(Error::StateError)
182        }
183    }
184
185    pub fn to_packet(&mut self) -> Result<Request> {
186        let request = mem::replace(&mut self.packet, None);
187        request.ok_or(Error::ABCIPacketError)
188    }
189}