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 (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 (ConsensusState::ConsensusBegin, request::Value::Flush(_)) => {
89 self.state = ConsensusState::ConsensusBeginFlush;
90 self.flushed = false;
91 }
92 (ConsensusState::ConsensusBeginFlush, request::Value::Flush(_)) => {
94 self.state = ConsensusState::ConsensusBeginFlush;
95 self.flushed = true;
96 }
97 (ConsensusState::ConsensusBeginFlush, request::Value::BeginBlock(p)) => {
99 self.block = p;
100 self.state = ConsensusState::BlockBegin;
101 self.flushed = false;
102 }
103 (ConsensusState::Begin, request::Value::BeginBlock(p)) => {
105 self.block = p;
106 self.state = ConsensusState::BlockBegin;
107 }
108 (ConsensusState::BlockBegin, request::Value::Flush(_)) => {
110 self.state = ConsensusState::BlockBeginFlush;
111 self.flushed = false;
112 }
113 (ConsensusState::BlockBeginFlush, request::Value::Flush(_)) => {
115 self.state = ConsensusState::BlockBeginFlush;
116 self.flushed = true;
117 }
118 (ConsensusState::BlockBeginFlush, request::Value::DeliverTx(p)) => {
120 self.txs.push(p);
121 self.state = ConsensusState::TxReceived;
122 self.flushed = false;
123 }
124 (ConsensusState::TxReceived, request::Value::DeliverTx(p)) => {
126 self.txs.push(p);
127 }
128 (ConsensusState::TxReceived, request::Value::EndBlock(_)) => {
130 self.state = ConsensusState::BlockEnd;
131 }
132 (ConsensusState::BlockBeginFlush, request::Value::EndBlock(_)) => {
134 self.state = ConsensusState::BlockEnd;
135 self.flushed = false;
136 }
137 (ConsensusState::BlockEnd, request::Value::Flush(_)) => {
139 self.state = ConsensusState::DeliverBlock;
140 self.flushed = false;
141 }
142 (ConsensusState::DeliverBlock, request::Value::Flush(_)) => {
144 self.state = ConsensusState::DeliverBlock;
145 self.flushed = true;
146 }
147 (ConsensusState::DeliverBlock, request::Value::Commit(_)) => {
149 self.state = ConsensusState::BlockCommit;
150 self.flushed = false;
151 }
152 (ConsensusState::BlockCommit, request::Value::Flush(_)) => {
154 self.state = ConsensusState::BlockCommitFlush;
155 self.flushed = false;
156 }
157 (ConsensusState::BlockCommitFlush, request::Value::Flush(_)) => {
159 self.state = ConsensusState::BlockCommitFlush;
160 self.flushed = true;
161 }
162 (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}