Skip to content

Commit 45c3946

Browse files
committed
Add ABCI domain types.
These types mirror the generated types in tendermint_proto, but have better naming. The documentation is filled in from the ABCI methods & types documentation.
1 parent 5b9748f commit 45c3946

33 files changed

+3139
-0
lines changed

tendermint/src/abci.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//! Application BlockChain Interface ([ABCI]) is the interface between Tendermint
2+
//! (a consensus engine for Byzantine-fault-tolerant replication of a state
3+
//! machine) and an application (the state machine to be replicated).
4+
//!
5+
//! Using ABCI involves writing an application driven by ABCI methods, exposing
6+
//! that application as an ABCI server, and having Tendermint connect to the
7+
//! server as an ABCI client.
8+
//!
9+
//! This module does not include an ABCI server implementation itself. Instead,
10+
//! it provides a common set of Rust domain types that model the ABCI protocol,
11+
//! which can be used by both ABCI applications and ABCI server implementations.
12+
//!
13+
//! One ABCI server implementation is provided by the [`tendermint_abci`][tmabci]
14+
//! crate.
15+
//!
16+
//! Each ABCI method corresponds to a request/response pair. ABCI requests are
17+
//! modeled by the [`Request`] enum, and responses are modeled by the
18+
//! [`Response`] enum. As described in the [methods and types][mat] page, ABCI
19+
//! methods are split into four categories. Tendermint opens one ABCI connection
20+
//! for each category of messages. These categories are modeled by the
21+
//! [`MethodKind`] enum and by per-category request and response enums:
22+
//!
23+
//! * [`ConsensusRequest`] / [`ConsensusResponse`] for [`MethodKind::Consensus`] methods;
24+
//! * [`MempoolRequest`] / [`MempoolResponse`] for [`MethodKind::Mempool`] methods;
25+
//! * [`InfoRequest`] / [`InfoResponse`] for [`MethodKind::Info`] methods;
26+
//! * [`SnapshotRequest`] / [`SnapshotResponse`] for [`MethodKind::Snapshot`] methods.
27+
//!
28+
//! The domain types in this module have conversions to and from the Protobuf
29+
//! types defined in the [`tendermint_proto`] crate. These conversions are
30+
//! required for ABCI server implementations, which use the protobufs to
31+
//! communicate with Tendermint, but should not be required for ABCI
32+
//! applications, which should use the domain types in an interface defined by
33+
//! their choice of ABCI server implementation.
34+
//!
35+
//! [ABCI]: https://docs.tendermint.com/master/spec/abci/
36+
//! [mat]: https://docs.tendermint.com/master/spec/abci/abci.html
37+
//! [tmabci]: https://github.com/informalsystems/tendermint-rs/tree/master/abci
38+
39+
mod kind;
40+
41+
/// Events. Hide this later once types are merged.
42+
pub mod event;
43+
//pub use event::{Event, EventAttribute};
44+
45+
pub mod params;
46+
pub mod request;
47+
pub mod response;
48+
pub mod types;
49+
50+
#[doc(inline)]
51+
pub use self::{
52+
kind::MethodKind,
53+
request::{ConsensusRequest, InfoRequest, MempoolRequest, Request, SnapshotRequest},
54+
response::{ConsensusResponse, InfoResponse, MempoolResponse, Response, SnapshotResponse},
55+
};

tendermint/src/abci/event.rs

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/// An event that occurred while processing a request.
2+
///
3+
/// Application developers can attach additional information to
4+
/// [`BeginBlock`](super::response::BeginBlock),
5+
/// [`EndBlock`](super::response::EndBlock),
6+
/// [`CheckTx`](super::response::CheckTx), and
7+
/// [`DeliverTx`](super::response::DeliverTx) responses. Later, transactions may
8+
/// be queried using these events.
9+
///
10+
/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#events)
11+
#[derive(Clone, PartialEq, Eq, Debug)]
12+
pub struct Event {
13+
/// The kind of event.
14+
///
15+
/// Tendermint calls this the `type`, but we use `kind` to avoid confusion
16+
/// with Rust types and follow Rust conventions.
17+
pub kind: String,
18+
/// A list of [`EventAttribute`]s describing the event.
19+
pub attributes: Vec<EventAttribute>,
20+
}
21+
22+
impl Event {
23+
/// Construct an event from generic data.
24+
///
25+
/// The `From` impls on [`EventAttribute`] and the [`EventAttributeIndexExt`]
26+
/// trait allow ergonomic event construction, as in this example:
27+
///
28+
/// ```
29+
/// use tendermint::abci::event::{Event, EventAttributeIndexExt};
30+
///
31+
/// let event = Event::new(
32+
/// "app",
33+
/// vec![
34+
/// ("key1", "value1").index(),
35+
/// ("key2", "value2").index(),
36+
/// ("key3", "value3").no_index(), // will not be indexed
37+
/// ],
38+
/// );
39+
/// ```
40+
// XXX(hdevalence): remove vec! from example after https://github.com/rust-lang/rust/pull/65819
41+
pub fn new<K, I>(kind: K, attributes: I) -> Self
42+
where
43+
K: Into<String>,
44+
I: IntoIterator,
45+
I::Item: Into<EventAttribute>,
46+
{
47+
Self {
48+
kind: kind.into(),
49+
attributes: attributes.into_iter().map(Into::into).collect(),
50+
}
51+
}
52+
}
53+
54+
/// A key-value pair describing an [`Event`].
55+
///
56+
/// Generic methods are provided for more ergonomic attribute construction, see
57+
/// [`Event::new`] for details.
58+
///
59+
/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#events)
60+
#[derive(Clone, PartialEq, Eq, Debug)]
61+
pub struct EventAttribute {
62+
/// The event key.
63+
pub key: String,
64+
/// The event value.
65+
pub value: String,
66+
/// Whether Tendermint's indexer should index this event.
67+
///
68+
/// **This field is nondeterministic**.
69+
pub index: bool,
70+
}
71+
72+
impl<K: Into<String>, V: Into<String>> From<(K, V, bool)> for EventAttribute {
73+
fn from((key, value, index): (K, V, bool)) -> Self {
74+
EventAttribute {
75+
key: key.into(),
76+
value: value.into(),
77+
index,
78+
}
79+
}
80+
}
81+
82+
/// Adds convenience methods to tuples for more ergonomic [`EventAttribute`]
83+
/// construction.
84+
///
85+
/// See [`Event::new`] for details.
86+
#[allow(missing_docs)]
87+
pub trait EventAttributeIndexExt: private::Sealed {
88+
type Key;
89+
type Value;
90+
91+
/// Indicate that this key/value pair should be indexed by Tendermint.
92+
fn index(self) -> (Self::Key, Self::Value, bool);
93+
/// Indicate that this key/value pair should not be indexed by Tendermint.
94+
fn no_index(self) -> (Self::Key, Self::Value, bool);
95+
}
96+
97+
impl<K: Into<String>, V: Into<String>> EventAttributeIndexExt for (K, V) {
98+
type Key = K;
99+
type Value = V;
100+
fn index(self) -> (K, V, bool) {
101+
let (key, value) = self;
102+
(key, value, true)
103+
}
104+
fn no_index(self) -> (K, V, bool) {
105+
let (key, value) = self;
106+
(key, value, false)
107+
}
108+
}
109+
110+
mod private {
111+
pub trait Sealed {}
112+
113+
impl<K: Into<String>, V: Into<String>> Sealed for (K, V) {}
114+
}
115+
116+
impl<K: Into<String>, V: Into<String>> From<(K, V)> for EventAttribute {
117+
fn from((key, value): (K, V)) -> Self {
118+
(key, value, false).into()
119+
}
120+
}
121+
122+
// =============================================================================
123+
// Protobuf conversions
124+
// =============================================================================
125+
126+
// XXX(hdevalence): these all use &'static str for now, this should be fixed
127+
// to align with the crate's error-handling strategy.
128+
129+
use std::convert::{TryFrom, TryInto};
130+
131+
use tendermint_proto::abci as pb;
132+
use tendermint_proto::Protobuf;
133+
134+
impl From<EventAttribute> for pb::EventAttribute {
135+
fn from(event: EventAttribute) -> Self {
136+
Self {
137+
key: event.key,
138+
value: event.value,
139+
index: event.index,
140+
}
141+
}
142+
}
143+
144+
impl TryFrom<pb::EventAttribute> for EventAttribute {
145+
type Error = crate::Error;
146+
147+
fn try_from(event: pb::EventAttribute) -> Result<Self, Self::Error> {
148+
Ok(Self {
149+
key: event.key,
150+
value: event.value,
151+
index: event.index,
152+
})
153+
}
154+
}
155+
156+
impl Protobuf<pb::EventAttribute> for EventAttribute {}
157+
158+
impl From<Event> for pb::Event {
159+
fn from(event: Event) -> Self {
160+
Self {
161+
r#type: event.kind,
162+
attributes: event.attributes.into_iter().map(Into::into).collect(),
163+
}
164+
}
165+
}
166+
167+
impl TryFrom<pb::Event> for Event {
168+
type Error = crate::Error;
169+
170+
fn try_from(event: pb::Event) -> Result<Self, Self::Error> {
171+
Ok(Self {
172+
kind: event.r#type,
173+
attributes: event
174+
.attributes
175+
.into_iter()
176+
.map(TryInto::try_into)
177+
.collect::<Result<_, _>>()?,
178+
})
179+
}
180+
}
181+
182+
impl Protobuf<pb::Event> for Event {}

tendermint/src/abci/kind.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// A category of ABCI method.
2+
///
3+
/// ABCI methods are split into four categories. Tendermint opens one ABCI
4+
/// connection for each category and refers to these categories as *connections*,
5+
/// but nothing actually restricts an ABCI connection from calling methods in
6+
/// multiple categories.
7+
///
8+
/// This enum breaks out the `Flush` method as a distinct category, since it is
9+
/// used to control the execution of other methods.
10+
pub enum MethodKind {
11+
/// A consensus method, driven by the consensus protocol and responsible for
12+
/// block execution.
13+
Consensus,
14+
/// A mempool method, used for validating new transactions before they're
15+
/// shared or included in a block.
16+
Mempool,
17+
/// A snapshot method, used for serving and restoring state snapshots.
18+
Snapshot,
19+
/// An info method, used for initialization and user queries.
20+
Info,
21+
/// The flush method requests that all pending method requests are fully executed.
22+
Flush,
23+
}

0 commit comments

Comments
 (0)