diff --git a/abci/src/application.rs b/abci/src/application.rs index b4a848608..5cfe154d6 100644 --- a/abci/src/application.rs +++ b/abci/src/application.rs @@ -9,11 +9,11 @@ use tendermint_proto::abci::request::Value; use tendermint_proto::abci::{ response, Request, RequestApplySnapshotChunk, RequestBeginBlock, RequestCheckTx, RequestDeliverTx, RequestEcho, RequestEndBlock, RequestInfo, RequestInitChain, - RequestLoadSnapshotChunk, RequestOfferSnapshot, RequestQuery, RequestSetOption, Response, + RequestLoadSnapshotChunk, RequestOfferSnapshot, RequestQuery, Response, ResponseApplySnapshotChunk, ResponseBeginBlock, ResponseCheckTx, ResponseCommit, ResponseDeliverTx, ResponseEcho, ResponseEndBlock, ResponseFlush, ResponseInfo, ResponseInitChain, ResponseListSnapshots, ResponseLoadSnapshotChunk, ResponseOfferSnapshot, - ResponseQuery, ResponseSetOption, + ResponseQuery, }; /// An ABCI application. @@ -77,12 +77,6 @@ pub trait Application: Send + Clone + 'static { Default::default() } - /// Allows the Tendermint node to request that the application set an - /// option to a particular value. - fn set_option(&self, _request: RequestSetOption) -> ResponseSetOption { - Default::default() - } - /// Used during state sync to discover available snapshots on peers. fn list_snapshots(&self) -> ResponseListSnapshots { Default::default() @@ -124,7 +118,6 @@ impl RequestDispatcher for A { Value::Echo(req) => response::Value::Echo(self.echo(req)), Value::Flush(_) => response::Value::Flush(self.flush()), Value::Info(req) => response::Value::Info(self.info(req)), - Value::SetOption(req) => response::Value::SetOption(self.set_option(req)), Value::InitChain(req) => response::Value::InitChain(self.init_chain(req)), Value::Query(req) => response::Value::Query(self.query(req)), Value::BeginBlock(req) => response::Value::BeginBlock(self.begin_block(req)), diff --git a/abci/src/application/kvstore.rs b/abci/src/application/kvstore.rs index 57a687345..b3ffdb429 100644 --- a/abci/src/application/kvstore.rs +++ b/abci/src/application/kvstore.rs @@ -123,17 +123,17 @@ impl Application for KeyValueStoreApp { version: "0.1.0".to_string(), app_version: 1, last_block_height, - last_block_app_hash, + last_block_app_hash: last_block_app_hash.into(), } } fn query(&self, request: RequestQuery) -> ResponseQuery { - let key = match String::from_utf8(request.data.clone()) { + let key = match std::str::from_utf8(&request.data) { Ok(s) => s, Err(e) => panic!("Failed to intepret key as UTF-8: {}", e), }; debug!("Attempting to get key: {}", key); - match self.get(key.clone()) { + match self.get(key) { Ok((height, value_opt)) => match value_opt { Some(value) => ResponseQuery { code: 0, @@ -141,7 +141,7 @@ impl Application for KeyValueStoreApp { info: "".to_string(), index: 0, key: request.data, - value: value.into_bytes(), + value: value.into_bytes().into(), proof_ops: None, height, codespace: "".to_string(), @@ -152,7 +152,7 @@ impl Application for KeyValueStoreApp { info: "".to_string(), index: 0, key: request.data, - value: vec![], + value: Default::default(), proof_ops: None, height, codespace: "".to_string(), @@ -165,18 +165,21 @@ impl Application for KeyValueStoreApp { fn check_tx(&self, _request: RequestCheckTx) -> ResponseCheckTx { ResponseCheckTx { code: 0, - data: vec![], + data: Default::default(), log: "".to_string(), info: "".to_string(), gas_wanted: 1, gas_used: 0, events: vec![], codespace: "".to_string(), + mempool_error: "".to_string(), + priority: 0, + sender: "".to_string(), } } fn deliver_tx(&self, request: RequestDeliverTx) -> ResponseDeliverTx { - let tx = String::from_utf8(request.tx).unwrap(); + let tx = std::str::from_utf8(&request.tx).unwrap(); let tx_parts = tx.split('=').collect::>(); let (key, value) = if tx_parts.len() == 2 { (tx_parts[0], tx_parts[1]) @@ -186,7 +189,7 @@ impl Application for KeyValueStoreApp { let _ = self.set(key, value).unwrap(); ResponseDeliverTx { code: 0, - data: vec![], + data: Default::default(), log: "".to_string(), info: "".to_string(), gas_wanted: 0, @@ -195,18 +198,18 @@ impl Application for KeyValueStoreApp { r#type: "app".to_string(), attributes: vec![ EventAttribute { - key: "key".as_bytes().to_owned(), - value: key.as_bytes().to_owned(), + key: "key".to_string(), + value: key.to_string(), index: true, }, EventAttribute { - key: "index_key".as_bytes().to_owned(), - value: "index is working".as_bytes().to_owned(), + key: "index_key".to_string(), + value: "index is working".to_string(), index: true, }, EventAttribute { - key: "noindex_key".as_bytes().to_owned(), - value: "index is working".as_bytes().to_owned(), + key: "noindex_key".to_string(), + value: "index is working".to_string(), index: false, }, ], @@ -221,7 +224,7 @@ impl Application for KeyValueStoreApp { let (height, app_hash) = channel_recv(&result_rx).unwrap(); info!("Committed height {}", height); ResponseCommit { - data: app_hash, + data: app_hash.into(), retain_height: height - 1, } } diff --git a/abci/src/client.rs b/abci/src/client.rs index c5146f88a..c2e11ddba 100644 --- a/abci/src/client.rs +++ b/abci/src/client.rs @@ -7,10 +7,9 @@ use tendermint_proto::abci::{ request, response, RequestApplySnapshotChunk, RequestBeginBlock, RequestCheckTx, RequestCommit, RequestDeliverTx, RequestEndBlock, RequestFlush, RequestInfo, RequestInitChain, RequestListSnapshots, RequestLoadSnapshotChunk, RequestOfferSnapshot, RequestQuery, - RequestSetOption, ResponseApplySnapshotChunk, ResponseBeginBlock, ResponseCheckTx, - ResponseCommit, ResponseDeliverTx, ResponseEndBlock, ResponseFlush, ResponseInfo, - ResponseInitChain, ResponseListSnapshots, ResponseLoadSnapshotChunk, ResponseOfferSnapshot, - ResponseQuery, ResponseSetOption, + ResponseApplySnapshotChunk, ResponseBeginBlock, ResponseCheckTx, ResponseCommit, + ResponseDeliverTx, ResponseEndBlock, ResponseFlush, ResponseInfo, ResponseInitChain, + ResponseListSnapshots, ResponseLoadSnapshotChunk, ResponseOfferSnapshot, ResponseQuery, }; use tendermint_proto::abci::{Request, RequestEcho, ResponseEcho}; @@ -113,11 +112,6 @@ impl Client { perform!(self, Commit, RequestCommit {}) } - /// Request that the application set an option to a particular value. - pub fn set_option(&mut self, req: RequestSetOption) -> Result { - perform!(self, SetOption, req) - } - /// Used during state sync to discover available snapshots on peers. pub fn list_snapshots(&mut self) -> Result { perform!(self, ListSnapshots, RequestListSnapshots {}) diff --git a/abci/tests/kvstore_app.rs b/abci/tests/kvstore_app.rs index 62a1c51d6..060a6cc7f 100644 --- a/abci/tests/kvstore_app.rs +++ b/abci/tests/kvstore_app.rs @@ -24,19 +24,19 @@ mod kvstore_app_integration { client .deliver_tx(RequestDeliverTx { - tx: "test-key=test-value".as_bytes().to_owned(), + tx: "test-key=test-value".as_bytes().into(), }) .unwrap(); client.commit().unwrap(); let res = client .query(RequestQuery { - data: "test-key".as_bytes().to_owned(), + data: "test-key".as_bytes().into(), path: "".to_string(), height: 0, prove: false, }) .unwrap(); - assert_eq!(res.value, "test-value".as_bytes().to_owned()); + assert_eq!(res.value, "test-value".as_bytes()); } } diff --git a/light-client/src/evidence.rs b/light-client/src/evidence.rs index 279fb9501..3da3538d1 100644 --- a/light-client/src/evidence.rs +++ b/light-client/src/evidence.rs @@ -2,7 +2,7 @@ use crate::{components::io::IoError, types::PeerId}; -use tendermint::abci::transaction::Hash; +use tendermint_rpc::abci::transaction::Hash; use contracts::contract_trait; diff --git a/light-client/src/tests.rs b/light-client/src/tests.rs index 660c09a8b..093d4fa79 100644 --- a/light-client/src/tests.rs +++ b/light-client/src/tests.rs @@ -3,8 +3,8 @@ use crate::types::{Height, LightBlock, PeerId, SignedHeader, Time, TrustThreshold, ValidatorSet}; use serde::{Deserialize, Serialize}; -use tendermint::abci::transaction::Hash; use tendermint_rpc as rpc; +use tendermint_rpc::abci::transaction::Hash; use crate::components::clock::Clock; use crate::components::io::{AtHeight, Io, IoError}; diff --git a/p2p/src/secret_connection.rs b/p2p/src/secret_connection.rs index 18581a1b6..28c165891 100644 --- a/p2p/src/secret_connection.rs +++ b/p2p/src/secret_connection.rs @@ -185,7 +185,7 @@ impl Handshake { proto::crypto::public_key::Sum::Ed25519(ref bytes) => { ed25519::PublicKey::from_bytes(bytes).map_err(Error::signature) } - proto::crypto::public_key::Sum::Secp256k1(_) => Err(Error::unsupported_key()), + _ => Err(Error::unsupported_key()), }?; let remote_sig = diff --git a/proto/Cargo.toml b/proto/Cargo.toml index 6fdede136..3b836564e 100644 --- a/proto/Cargo.toml +++ b/proto/Cargo.toml @@ -19,7 +19,7 @@ all-features = true [dependencies] prost = { version = "0.9", default-features = false } prost-types = { version = "0.9", default-features = false } -bytes = { version = "1.0", default-features = false } +bytes = { version = "1.0", default-features = false, features = ["serde"] } serde = { version = "1.0", default-features = false, features = ["derive"] } serde_bytes = { version = "0.11", default-features = false, features = ["alloc"] } subtle-encoding = { version = "0.5", default-features = false, features = ["hex", "base64", "alloc"] } diff --git a/proto/src/chrono.rs b/proto/src/chrono.rs new file mode 100644 index 000000000..3b969f0f0 --- /dev/null +++ b/proto/src/chrono.rs @@ -0,0 +1,53 @@ +use core::convert::TryInto; + +use chrono::{DateTime, Duration, TimeZone, Utc}; + +use crate::google::protobuf as pb; + +impl From> for pb::Timestamp { + fn from(dt: DateTime) -> pb::Timestamp { + pb::Timestamp { + seconds: dt.timestamp(), + // This can exceed 1_000_000_000 in the case of a leap second, but + // even with a leap second it should be under 2_147_483_647. + nanos: dt + .timestamp_subsec_nanos() + .try_into() + .expect("timestamp_subsec_nanos bigger than i32::MAX"), + } + } +} + +impl From for DateTime { + fn from(ts: pb::Timestamp) -> DateTime { + Utc.timestamp(ts.seconds, ts.nanos as u32) + } +} + +// Note: we convert a protobuf::Duration into a chrono::Duration, not a +// std::time::Duration, because std::time::Durations are unsigned, but the +// protobuf duration is signed. + +impl From for pb::Duration { + fn from(d: Duration) -> pb::Duration { + // chrono's Duration stores the fractional part as `nanos: i32` + // internally but doesn't provide a way to access it, only a way to get + // the *total* number of nanoseconds. so we have to do this cool and fun + // hoop-jumping maneuver + let seconds = d.num_seconds(); + let nanos = (d - Duration::seconds(seconds)) + .num_nanoseconds() + .expect("we computed the fractional part, so there's no overflow") + .try_into() + .expect("the fractional part fits in i32"); + + pb::Duration { seconds, nanos } + } +} + +impl From for Duration { + fn from(d: pb::Duration) -> Duration { + // there's no constructor that supplies both at once + Duration::seconds(d.seconds) + Duration::nanoseconds(d.nanos as i64) + } +} diff --git a/proto/src/lib.rs b/proto/src/lib.rs index 018ea6216..f306f87ab 100644 --- a/proto/src/lib.rs +++ b/proto/src/lib.rs @@ -20,6 +20,7 @@ pub mod google { } } +mod chrono; mod error; #[allow(warnings)] mod tendermint; diff --git a/proto/src/prost/tendermint.abci.rs b/proto/src/prost/tendermint.abci.rs index 4e5142286..2a42bbd53 100644 --- a/proto/src/prost/tendermint.abci.rs +++ b/proto/src/prost/tendermint.abci.rs @@ -7,7 +7,7 @@ #[derive(Clone, PartialEq, ::prost::Message)] pub struct Request { - #[prost(oneof="request::Value", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15")] + #[prost(oneof="request::Value", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14")] pub value: ::core::option::Option, } /// Nested message and enum types in `Request`. @@ -21,28 +21,26 @@ pub mod request { #[prost(message, tag="3")] Info(super::RequestInfo), #[prost(message, tag="4")] - SetOption(super::RequestSetOption), - #[prost(message, tag="5")] InitChain(super::RequestInitChain), - #[prost(message, tag="6")] + #[prost(message, tag="5")] Query(super::RequestQuery), - #[prost(message, tag="7")] + #[prost(message, tag="6")] BeginBlock(super::RequestBeginBlock), - #[prost(message, tag="8")] + #[prost(message, tag="7")] CheckTx(super::RequestCheckTx), - #[prost(message, tag="9")] + #[prost(message, tag="8")] DeliverTx(super::RequestDeliverTx), - #[prost(message, tag="10")] + #[prost(message, tag="9")] EndBlock(super::RequestEndBlock), - #[prost(message, tag="11")] + #[prost(message, tag="10")] Commit(super::RequestCommit), - #[prost(message, tag="12")] + #[prost(message, tag="11")] ListSnapshots(super::RequestListSnapshots), - #[prost(message, tag="13")] + #[prost(message, tag="12")] OfferSnapshot(super::RequestOfferSnapshot), - #[prost(message, tag="14")] + #[prost(message, tag="13")] LoadSnapshotChunk(super::RequestLoadSnapshotChunk), - #[prost(message, tag="15")] + #[prost(message, tag="14")] ApplySnapshotChunk(super::RequestApplySnapshotChunk), } } @@ -62,14 +60,8 @@ pub struct RequestInfo { pub block_version: u64, #[prost(uint64, tag="3")] pub p2p_version: u64, -} -/// nondeterministic -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RequestSetOption { - #[prost(string, tag="1")] - pub key: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub value: ::prost::alloc::string::String, + #[prost(string, tag="4")] + pub abci_version: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestInitChain { @@ -78,18 +70,18 @@ pub struct RequestInitChain { #[prost(string, tag="2")] pub chain_id: ::prost::alloc::string::String, #[prost(message, optional, tag="3")] - pub consensus_params: ::core::option::Option, + pub consensus_params: ::core::option::Option, #[prost(message, repeated, tag="4")] pub validators: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="5")] - pub app_state_bytes: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="5")] + pub app_state_bytes: ::prost::bytes::Bytes, #[prost(int64, tag="6")] pub initial_height: i64, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestQuery { - #[prost(bytes="vec", tag="1")] - pub data: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="1")] + pub data: ::prost::bytes::Bytes, #[prost(string, tag="2")] pub path: ::prost::alloc::string::String, #[prost(int64, tag="3")] @@ -99,8 +91,8 @@ pub struct RequestQuery { } #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestBeginBlock { - #[prost(bytes="vec", tag="1")] - pub hash: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="1")] + pub hash: ::prost::bytes::Bytes, #[prost(message, optional, tag="2")] pub header: ::core::option::Option, #[prost(message, optional, tag="3")] @@ -110,15 +102,15 @@ pub struct RequestBeginBlock { } #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestCheckTx { - #[prost(bytes="vec", tag="1")] - pub tx: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="1")] + pub tx: ::prost::bytes::Bytes, #[prost(enumeration="CheckTxType", tag="2")] pub r#type: i32, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestDeliverTx { - #[prost(bytes="vec", tag="1")] - pub tx: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="1")] + pub tx: ::prost::bytes::Bytes, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct RequestEndBlock { @@ -139,8 +131,8 @@ pub struct RequestOfferSnapshot { #[prost(message, optional, tag="1")] pub snapshot: ::core::option::Option, /// light client-verified app hash for snapshot height - #[prost(bytes="vec", tag="2")] - pub app_hash: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="2")] + pub app_hash: ::prost::bytes::Bytes, } /// loads a snapshot chunk #[derive(Clone, PartialEq, ::prost::Message)] @@ -157,8 +149,8 @@ pub struct RequestLoadSnapshotChunk { pub struct RequestApplySnapshotChunk { #[prost(uint32, tag="1")] pub index: u32, - #[prost(bytes="vec", tag="2")] - pub chunk: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="2")] + pub chunk: ::prost::bytes::Bytes, #[prost(string, tag="3")] pub sender: ::prost::alloc::string::String, } @@ -167,7 +159,7 @@ pub struct RequestApplySnapshotChunk { #[derive(Clone, PartialEq, ::prost::Message)] pub struct Response { - #[prost(oneof="response::Value", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16")] + #[prost(oneof="response::Value", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15")] pub value: ::core::option::Option, } /// Nested message and enum types in `Response`. @@ -183,28 +175,26 @@ pub mod response { #[prost(message, tag="4")] Info(super::ResponseInfo), #[prost(message, tag="5")] - SetOption(super::ResponseSetOption), - #[prost(message, tag="6")] InitChain(super::ResponseInitChain), - #[prost(message, tag="7")] + #[prost(message, tag="6")] Query(super::ResponseQuery), - #[prost(message, tag="8")] + #[prost(message, tag="7")] BeginBlock(super::ResponseBeginBlock), - #[prost(message, tag="9")] + #[prost(message, tag="8")] CheckTx(super::ResponseCheckTx), - #[prost(message, tag="10")] + #[prost(message, tag="9")] DeliverTx(super::ResponseDeliverTx), - #[prost(message, tag="11")] + #[prost(message, tag="10")] EndBlock(super::ResponseEndBlock), - #[prost(message, tag="12")] + #[prost(message, tag="11")] Commit(super::ResponseCommit), - #[prost(message, tag="13")] + #[prost(message, tag="12")] ListSnapshots(super::ResponseListSnapshots), - #[prost(message, tag="14")] + #[prost(message, tag="13")] OfferSnapshot(super::ResponseOfferSnapshot), - #[prost(message, tag="15")] + #[prost(message, tag="14")] LoadSnapshotChunk(super::ResponseLoadSnapshotChunk), - #[prost(message, tag="16")] + #[prost(message, tag="15")] ApplySnapshotChunk(super::ResponseApplySnapshotChunk), } } @@ -227,6 +217,7 @@ pub struct ResponseFlush { pub struct ResponseInfo { #[prost(string, tag="1")] pub data: ::prost::alloc::string::String, + /// this is the software version of the application. TODO: remove? #[prost(string, tag="2")] pub version: ::prost::alloc::string::String, #[prost(uint64, tag="3")] @@ -235,29 +226,18 @@ pub struct ResponseInfo { #[prost(int64, tag="4")] #[serde(with = "crate::serializers::from_str")] pub last_block_height: i64, - #[prost(bytes="vec", tag="5")] - #[serde(skip_serializing_if = "::prost::alloc::vec::Vec::is_empty", with = "serde_bytes")] - pub last_block_app_hash: ::prost::alloc::vec::Vec, -} -/// nondeterministic -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ResponseSetOption { - #[prost(uint32, tag="1")] - pub code: u32, - /// bytes data = 2; - #[prost(string, tag="3")] - pub log: ::prost::alloc::string::String, - #[prost(string, tag="4")] - pub info: ::prost::alloc::string::String, + #[prost(bytes="bytes", tag="5")] + #[serde(skip_serializing_if = "bytes::Bytes::is_empty")] + pub last_block_app_hash: ::prost::bytes::Bytes, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseInitChain { #[prost(message, optional, tag="1")] - pub consensus_params: ::core::option::Option, + pub consensus_params: ::core::option::Option, #[prost(message, repeated, tag="2")] pub validators: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="3")] - pub app_hash: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="3")] + pub app_hash: ::prost::bytes::Bytes, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseQuery { @@ -273,10 +253,10 @@ pub struct ResponseQuery { pub info: ::prost::alloc::string::String, #[prost(int64, tag="5")] pub index: i64, - #[prost(bytes="vec", tag="6")] - pub key: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="7")] - pub value: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="6")] + pub key: ::prost::bytes::Bytes, + #[prost(bytes="bytes", tag="7")] + pub value: ::prost::bytes::Bytes, #[prost(message, optional, tag="8")] pub proof_ops: ::core::option::Option, #[prost(int64, tag="9")] @@ -293,8 +273,8 @@ pub struct ResponseBeginBlock { pub struct ResponseCheckTx { #[prost(uint32, tag="1")] pub code: u32, - #[prost(bytes="vec", tag="2")] - pub data: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="2")] + pub data: ::prost::bytes::Bytes, /// nondeterministic #[prost(string, tag="3")] pub log: ::prost::alloc::string::String, @@ -309,13 +289,21 @@ pub struct ResponseCheckTx { pub events: ::prost::alloc::vec::Vec, #[prost(string, tag="8")] pub codespace: ::prost::alloc::string::String, + #[prost(string, tag="9")] + pub sender: ::prost::alloc::string::String, + #[prost(int64, tag="10")] + pub priority: i64, + /// mempool_error is set by Tendermint. + /// ABCI applictions creating a ResponseCheckTX should not set mempool_error. + #[prost(string, tag="11")] + pub mempool_error: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseDeliverTx { #[prost(uint32, tag="1")] pub code: u32, - #[prost(bytes="vec", tag="2")] - pub data: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="2")] + pub data: ::prost::bytes::Bytes, /// nondeterministic #[prost(string, tag="3")] pub log: ::prost::alloc::string::String, @@ -337,15 +325,15 @@ pub struct ResponseEndBlock { #[prost(message, repeated, tag="1")] pub validator_updates: ::prost::alloc::vec::Vec, #[prost(message, optional, tag="2")] - pub consensus_param_updates: ::core::option::Option, + pub consensus_param_updates: ::core::option::Option, #[prost(message, repeated, tag="3")] pub events: ::prost::alloc::vec::Vec, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseCommit { /// reserve 1 - #[prost(bytes="vec", tag="2")] - pub data: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="2")] + pub data: ::prost::bytes::Bytes, #[prost(int64, tag="3")] pub retain_height: i64, } @@ -380,8 +368,8 @@ pub mod response_offer_snapshot { } #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseLoadSnapshotChunk { - #[prost(bytes="vec", tag="1")] - pub chunk: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="1")] + pub chunk: ::prost::bytes::Bytes, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct ResponseApplySnapshotChunk { @@ -416,29 +404,6 @@ pub mod response_apply_snapshot_chunk { //---------------------------------------- // Misc. -/// ConsensusParams contains all consensus-relevant parameters -/// that can be adjusted by the abci app -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ConsensusParams { - #[prost(message, optional, tag="1")] - pub block: ::core::option::Option, - #[prost(message, optional, tag="2")] - pub evidence: ::core::option::Option, - #[prost(message, optional, tag="3")] - pub validator: ::core::option::Option, - #[prost(message, optional, tag="4")] - pub version: ::core::option::Option, -} -/// BlockParams contains limits on the block size. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockParams { - /// Note: must be greater than 0 - #[prost(int64, tag="1")] - pub max_bytes: i64, - /// Note: must be greater or equal to -1 - #[prost(int64, tag="2")] - pub max_gas: i64, -} #[derive(Clone, PartialEq, ::prost::Message)] pub struct LastCommitInfo { #[prost(int32, tag="1")] @@ -459,10 +424,10 @@ pub struct Event { /// EventAttribute is a single key-value pair, associated with an event. #[derive(Clone, PartialEq, ::prost::Message)] pub struct EventAttribute { - #[prost(bytes="vec", tag="1")] - pub key: ::prost::alloc::vec::Vec, - #[prost(bytes="vec", tag="2")] - pub value: ::prost::alloc::vec::Vec, + #[prost(string, tag="1")] + pub key: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub value: ::prost::alloc::string::String, /// nondeterministic #[prost(bool, tag="3")] pub index: bool, @@ -476,8 +441,8 @@ pub struct TxResult { pub height: i64, #[prost(uint32, tag="2")] pub index: u32, - #[prost(bytes="vec", tag="3")] - pub tx: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="3")] + pub tx: ::prost::bytes::Bytes, #[prost(message, optional, tag="4")] pub result: ::core::option::Option, } @@ -488,8 +453,8 @@ pub struct TxResult { #[derive(Clone, PartialEq, ::prost::Message)] pub struct Validator { /// The first 20 bytes of SHA256(public key) - #[prost(bytes="vec", tag="1")] - pub address: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="1")] + pub address: ::prost::bytes::Bytes, /// PubKey pub_key = 2 \[(gogoproto.nullable)=false\]; /// /// The voting power @@ -546,11 +511,11 @@ pub struct Snapshot { #[prost(uint32, tag="3")] pub chunks: u32, /// Arbitrary snapshot hash, equal only if identical - #[prost(bytes="vec", tag="4")] - pub hash: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="4")] + pub hash: ::prost::bytes::Bytes, /// Arbitrary application metadata - #[prost(bytes="vec", tag="5")] - pub metadata: ::prost::alloc::vec::Vec, + #[prost(bytes="bytes", tag="5")] + pub metadata: ::prost::bytes::Bytes, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] diff --git a/proto/src/prost/tendermint.blockchain.rs b/proto/src/prost/tendermint.blocksync.rs similarity index 100% rename from proto/src/prost/tendermint.blockchain.rs rename to proto/src/prost/tendermint.blocksync.rs diff --git a/proto/src/prost/tendermint.crypto.rs b/proto/src/prost/tendermint.crypto.rs index 4b47ef593..4bb7a72e8 100644 --- a/proto/src/prost/tendermint.crypto.rs +++ b/proto/src/prost/tendermint.crypto.rs @@ -1,24 +1,3 @@ -/// PublicKey defines the keys available for use with Tendermint Validators -#[derive(::serde::Deserialize, ::serde::Serialize)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PublicKey { - #[prost(oneof="public_key::Sum", tags="1, 2")] - pub sum: ::core::option::Option, -} -/// Nested message and enum types in `PublicKey`. -pub mod public_key { - #[derive(::serde::Deserialize, ::serde::Serialize)] - #[serde(tag = "type", content = "value")] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Sum { - #[prost(bytes, tag="1")] - #[serde(rename = "tendermint/PubKeyEd25519", with = "crate::serializers::bytes::base64string")] - Ed25519(::prost::alloc::vec::Vec), - #[prost(bytes, tag="2")] - #[serde(rename = "tendermint/PubKeySecp256k1", with = "crate::serializers::bytes::base64string")] - Secp256k1(::prost::alloc::vec::Vec), - } -} #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, PartialEq, ::prost::Message)] pub struct Proof { @@ -71,3 +50,27 @@ pub struct ProofOps { #[prost(message, repeated, tag="1")] pub ops: ::prost::alloc::vec::Vec, } +/// PublicKey defines the keys available for use with Tendermint Validators +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PublicKey { + #[prost(oneof="public_key::Sum", tags="1, 2, 3")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `PublicKey`. +pub mod public_key { + #[derive(::serde::Deserialize, ::serde::Serialize)] + #[serde(tag = "type", content = "value")] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(bytes, tag="1")] + #[serde(rename = "tendermint/PubKeyEd25519", with = "crate::serializers::bytes::base64string")] + Ed25519(::prost::alloc::vec::Vec), + #[prost(bytes, tag="2")] + #[serde(rename = "tendermint/PubKeySecp256k1", with = "crate::serializers::bytes::base64string")] + Secp256k1(::prost::alloc::vec::Vec), + #[prost(bytes, tag="3")] + #[serde(rename = "tendermint/PubKeySr25519", with = "crate::serializers::bytes::base64string")] + Sr25519(::prost::alloc::vec::Vec), + } +} diff --git a/proto/src/prost/tendermint.p2p.rs b/proto/src/prost/tendermint.p2p.rs index 8ed7b702f..4f1e500c4 100644 --- a/proto/src/prost/tendermint.p2p.rs +++ b/proto/src/prost/tendermint.p2p.rs @@ -1,13 +1,4 @@ #[derive(Clone, PartialEq, ::prost::Message)] -pub struct NetAddress { - #[prost(string, tag="1")] - pub id: ::prost::alloc::string::String, - #[prost(string, tag="2")] - pub ip: ::prost::alloc::string::String, - #[prost(uint32, tag="3")] - pub port: u32, -} -#[derive(Clone, PartialEq, ::prost::Message)] pub struct ProtocolVersion { #[prost(uint64, tag="1")] pub p2p: u64, @@ -17,11 +8,11 @@ pub struct ProtocolVersion { pub app: u64, } #[derive(Clone, PartialEq, ::prost::Message)] -pub struct DefaultNodeInfo { +pub struct NodeInfo { #[prost(message, optional, tag="1")] pub protocol_version: ::core::option::Option, #[prost(string, tag="2")] - pub default_node_id: ::prost::alloc::string::String, + pub node_id: ::prost::alloc::string::String, #[prost(string, tag="3")] pub listen_addr: ::prost::alloc::string::String, #[prost(string, tag="4")] @@ -33,37 +24,34 @@ pub struct DefaultNodeInfo { #[prost(string, tag="7")] pub moniker: ::prost::alloc::string::String, #[prost(message, optional, tag="8")] - pub other: ::core::option::Option, + pub other: ::core::option::Option, } #[derive(Clone, PartialEq, ::prost::Message)] -pub struct DefaultNodeInfoOther { +pub struct NodeInfoOther { #[prost(string, tag="1")] pub tx_index: ::prost::alloc::string::String, #[prost(string, tag="2")] pub rpc_address: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, ::prost::Message)] -pub struct PexRequest { -} -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PexAddrs { - #[prost(message, repeated, tag="1")] - pub addrs: ::prost::alloc::vec::Vec, +pub struct PeerInfo { + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + #[prost(message, repeated, tag="2")] + pub address_info: ::prost::alloc::vec::Vec, + #[prost(message, optional, tag="3")] + pub last_connected: ::core::option::Option, } #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Message { - #[prost(oneof="message::Sum", tags="1, 2")] - pub sum: ::core::option::Option, -} -/// Nested message and enum types in `Message`. -pub mod message { - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Sum { - #[prost(message, tag="1")] - PexRequest(super::PexRequest), - #[prost(message, tag="2")] - PexAddrs(super::PexAddrs), - } +pub struct PeerAddressInfo { + #[prost(string, tag="1")] + pub address: ::prost::alloc::string::String, + #[prost(message, optional, tag="2")] + pub last_dial_success: ::core::option::Option, + #[prost(message, optional, tag="3")] + pub last_dial_failure: ::core::option::Option, + #[prost(uint32, tag="4")] + pub dial_failures: u32, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct PacketPing { @@ -104,3 +92,52 @@ pub struct AuthSigMessage { #[prost(bytes="vec", tag="2")] pub sig: ::prost::alloc::vec::Vec, } +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PexAddress { + #[prost(string, tag="1")] + pub id: ::prost::alloc::string::String, + #[prost(string, tag="2")] + pub ip: ::prost::alloc::string::String, + #[prost(uint32, tag="3")] + pub port: u32, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PexRequest { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PexResponse { + #[prost(message, repeated, tag="1")] + pub addresses: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PexAddressV2 { + #[prost(string, tag="1")] + pub url: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PexRequestV2 { +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PexResponseV2 { + #[prost(message, repeated, tag="1")] + pub addresses: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct PexMessage { + #[prost(oneof="pex_message::Sum", tags="1, 2, 3, 4")] + pub sum: ::core::option::Option, +} +/// Nested message and enum types in `PexMessage`. +pub mod pex_message { + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag="1")] + PexRequest(super::PexRequest), + #[prost(message, tag="2")] + PexResponse(super::PexResponse), + #[prost(message, tag="3")] + PexRequestV2(super::PexRequestV2), + #[prost(message, tag="4")] + PexResponseV2(super::PexResponseV2), + } +} diff --git a/proto/src/prost/tendermint.privval.rs b/proto/src/prost/tendermint.privval.rs index 8a86b3369..04fac20e6 100644 --- a/proto/src/prost/tendermint.privval.rs +++ b/proto/src/prost/tendermint.privval.rs @@ -86,6 +86,16 @@ pub mod message { PingResponse(super::PingResponse), } } +/// AuthSigMessage is duplicated from p2p prior to the P2P refactor. +/// It is used for the SecretConnection until we migrate privval to gRPC. +/// +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct AuthSigMessage { + #[prost(message, optional, tag="1")] + pub pub_key: ::core::option::Option, + #[prost(bytes="vec", tag="2")] + pub sig: ::prost::alloc::vec::Vec, +} #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum Errors { diff --git a/proto/src/prost/tendermint.statesync.rs b/proto/src/prost/tendermint.statesync.rs index 593bd0222..c7e8d7f8a 100644 --- a/proto/src/prost/tendermint.statesync.rs +++ b/proto/src/prost/tendermint.statesync.rs @@ -1,6 +1,6 @@ #[derive(Clone, PartialEq, ::prost::Message)] pub struct Message { - #[prost(oneof="message::Sum", tags="1, 2, 3, 4")] + #[prost(oneof="message::Sum", tags="1, 2, 3, 4, 5, 6, 7, 8")] pub sum: ::core::option::Option, } /// Nested message and enum types in `Message`. @@ -15,6 +15,14 @@ pub mod message { ChunkRequest(super::ChunkRequest), #[prost(message, tag="4")] ChunkResponse(super::ChunkResponse), + #[prost(message, tag="5")] + LightBlockRequest(super::LightBlockRequest), + #[prost(message, tag="6")] + LightBlockResponse(super::LightBlockResponse), + #[prost(message, tag="7")] + ParamsRequest(super::ParamsRequest), + #[prost(message, tag="8")] + ParamsResponse(super::ParamsResponse), } } #[derive(Clone, PartialEq, ::prost::Message)] @@ -55,3 +63,25 @@ pub struct ChunkResponse { #[prost(bool, tag="5")] pub missing: bool, } +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LightBlockRequest { + #[prost(uint64, tag="1")] + pub height: u64, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct LightBlockResponse { + #[prost(message, optional, tag="1")] + pub light_block: ::core::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ParamsRequest { + #[prost(uint64, tag="1")] + pub height: u64, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ParamsResponse { + #[prost(uint64, tag="1")] + pub height: u64, + #[prost(message, optional, tag="2")] + pub consensus_params: ::core::option::Option, +} diff --git a/proto/src/prost/tendermint.store.rs b/proto/src/prost/tendermint.store.rs deleted file mode 100644 index a4c2799d9..000000000 --- a/proto/src/prost/tendermint.store.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockStoreState { - #[prost(int64, tag="1")] - pub base: i64, - #[prost(int64, tag="2")] - pub height: i64, -} diff --git a/proto/src/prost/tendermint.types.rs b/proto/src/prost/tendermint.types.rs index 61c23229e..384b9f147 100644 --- a/proto/src/prost/tendermint.types.rs +++ b/proto/src/prost/tendermint.types.rs @@ -277,69 +277,75 @@ pub enum SignedMsgType { Proposal = 32, } #[derive(::serde::Deserialize, ::serde::Serialize)] +#[serde(from = "crate::serializers::evidence::EvidenceVariant", into = "crate::serializers::evidence::EvidenceVariant")] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct CanonicalBlockId { - #[prost(bytes="vec", tag="1")] - pub hash: ::prost::alloc::vec::Vec, - #[prost(message, optional, tag="2")] - #[serde(alias = "parts")] - pub part_set_header: ::core::option::Option, +pub struct Evidence { + #[prost(oneof="evidence::Sum", tags="1, 2")] + pub sum: ::core::option::Option, } -#[derive(::serde::Deserialize, ::serde::Serialize)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CanonicalPartSetHeader { - #[prost(uint32, tag="1")] - pub total: u32, - #[prost(bytes="vec", tag="2")] - pub hash: ::prost::alloc::vec::Vec, +/// Nested message and enum types in `Evidence`. +pub mod evidence { + #[derive(::serde::Deserialize, ::serde::Serialize)] + #[serde(tag = "type", content = "value")] + #[serde(from = "crate::serializers::evidence::EvidenceVariant", into = "crate::serializers::evidence::EvidenceVariant")] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Sum { + #[prost(message, tag="1")] + #[serde(rename = "tendermint/DuplicateVoteEvidence")] + DuplicateVoteEvidence(super::DuplicateVoteEvidence), + #[prost(message, tag="2")] + #[serde(rename = "tendermint/LightClientAttackEvidence")] + LightClientAttackEvidence(super::LightClientAttackEvidence), + } } +/// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes. +#[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct CanonicalProposal { - /// type alias for byte - #[prost(enumeration="SignedMsgType", tag="1")] - pub r#type: i32, - /// canonicalization requires fixed size encoding here - #[prost(sfixed64, tag="2")] - pub height: i64, - /// canonicalization requires fixed size encoding here - #[prost(sfixed64, tag="3")] - pub round: i64, +pub struct DuplicateVoteEvidence { + #[prost(message, optional, tag="1")] + pub vote_a: ::core::option::Option, + #[prost(message, optional, tag="2")] + pub vote_b: ::core::option::Option, + #[prost(int64, tag="3")] + pub total_voting_power: i64, #[prost(int64, tag="4")] - pub pol_round: i64, + pub validator_power: i64, #[prost(message, optional, tag="5")] - pub block_id: ::core::option::Option, - #[prost(message, optional, tag="6")] pub timestamp: ::core::option::Option, - #[prost(string, tag="7")] - pub chain_id: ::prost::alloc::string::String, } +/// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client. #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct CanonicalVote { - /// type alias for byte - #[prost(enumeration="SignedMsgType", tag="1")] - pub r#type: i32, - /// canonicalization requires fixed size encoding here - #[prost(sfixed64, tag="2")] - pub height: i64, - /// canonicalization requires fixed size encoding here - #[prost(sfixed64, tag="3")] - pub round: i64, - #[prost(message, optional, tag="4")] - pub block_id: ::core::option::Option, +pub struct LightClientAttackEvidence { + #[prost(message, optional, tag="1")] + pub conflicting_block: ::core::option::Option, + #[prost(int64, tag="2")] + pub common_height: i64, + #[prost(message, repeated, tag="3")] + pub byzantine_validators: ::prost::alloc::vec::Vec, + #[prost(int64, tag="4")] + pub total_voting_power: i64, #[prost(message, optional, tag="5")] pub timestamp: ::core::option::Option, - #[prost(string, tag="6")] - pub chain_id: ::prost::alloc::string::String, } +#[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct EventDataRoundState { - #[prost(int64, tag="1")] - pub height: i64, - #[prost(int32, tag="2")] - pub round: i32, - #[prost(string, tag="3")] - pub step: ::prost::alloc::string::String, +pub struct EvidenceList { + #[prost(message, repeated, tag="1")] + #[serde(with = "crate::serializers::nullable")] + pub evidence: ::prost::alloc::vec::Vec, +} +#[derive(::serde::Deserialize, ::serde::Serialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Block { + #[prost(message, optional, tag="1")] + pub header: ::core::option::Option
, + #[prost(message, optional, tag="2")] + pub data: ::core::option::Option, + #[prost(message, optional, tag="3")] + pub evidence: ::core::option::Option, + #[prost(message, optional, tag="4")] + pub last_commit: ::core::option::Option, } /// ConsensusParams contains consensus critical parameters that determine the /// validity of blocks. @@ -365,12 +371,6 @@ pub struct BlockParams { /// Note: must be greater or equal to -1 #[prost(int64, tag="2")] pub max_gas: i64, - /// Minimum time increment between consecutive blocks (in milliseconds) If the - /// block header timestamp is ahead of the system clock, decrease this value. - /// - /// Not exposed to the application. - #[prost(int64, tag="3")] - pub time_iota_ms: i64, } /// EvidenceParams determine how we handle evidence of malfeasance. #[derive(::serde::Deserialize, ::serde::Serialize)] @@ -419,74 +419,68 @@ pub struct HashedParams { #[prost(int64, tag="2")] pub block_max_gas: i64, } -#[derive(::serde::Deserialize, ::serde::Serialize)] -#[serde(from = "crate::serializers::evidence::EvidenceVariant", into = "crate::serializers::evidence::EvidenceVariant")] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Evidence { - #[prost(oneof="evidence::Sum", tags="1, 2")] - pub sum: ::core::option::Option, -} -/// Nested message and enum types in `Evidence`. -pub mod evidence { - #[derive(::serde::Deserialize, ::serde::Serialize)] - #[serde(tag = "type", content = "value")] - #[serde(from = "crate::serializers::evidence::EvidenceVariant", into = "crate::serializers::evidence::EvidenceVariant")] - #[derive(Clone, PartialEq, ::prost::Oneof)] - pub enum Sum { - #[prost(message, tag="1")] - #[serde(rename = "tendermint/DuplicateVoteEvidence")] - DuplicateVoteEvidence(super::DuplicateVoteEvidence), - #[prost(message, tag="2")] - #[serde(rename = "tendermint/LightClientAttackEvidence")] - LightClientAttackEvidence(super::LightClientAttackEvidence), - } +pub struct EventDataRoundState { + #[prost(int64, tag="1")] + pub height: i64, + #[prost(int32, tag="2")] + pub round: i32, + #[prost(string, tag="3")] + pub step: ::prost::alloc::string::String, } -/// DuplicateVoteEvidence contains evidence of a validator signed two conflicting votes. #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct DuplicateVoteEvidence { - #[prost(message, optional, tag="1")] - pub vote_a: ::core::option::Option, +pub struct CanonicalBlockId { + #[prost(bytes="vec", tag="1")] + pub hash: ::prost::alloc::vec::Vec, #[prost(message, optional, tag="2")] - pub vote_b: ::core::option::Option, - #[prost(int64, tag="3")] - pub total_voting_power: i64, - #[prost(int64, tag="4")] - pub validator_power: i64, - #[prost(message, optional, tag="5")] - pub timestamp: ::core::option::Option, + #[serde(alias = "parts")] + pub part_set_header: ::core::option::Option, } -/// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client. #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct LightClientAttackEvidence { - #[prost(message, optional, tag="1")] - pub conflicting_block: ::core::option::Option, - #[prost(int64, tag="2")] - pub common_height: i64, - #[prost(message, repeated, tag="3")] - pub byzantine_validators: ::prost::alloc::vec::Vec, +pub struct CanonicalPartSetHeader { + #[prost(uint32, tag="1")] + pub total: u32, + #[prost(bytes="vec", tag="2")] + pub hash: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CanonicalProposal { + /// type alias for byte + #[prost(enumeration="SignedMsgType", tag="1")] + pub r#type: i32, + /// canonicalization requires fixed size encoding here + #[prost(sfixed64, tag="2")] + pub height: i64, + /// canonicalization requires fixed size encoding here + #[prost(sfixed64, tag="3")] + pub round: i64, #[prost(int64, tag="4")] - pub total_voting_power: i64, + pub pol_round: i64, #[prost(message, optional, tag="5")] + pub block_id: ::core::option::Option, + #[prost(message, optional, tag="6")] pub timestamp: ::core::option::Option, + #[prost(string, tag="7")] + pub chain_id: ::prost::alloc::string::String, } #[derive(::serde::Deserialize, ::serde::Serialize)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct EvidenceList { - #[prost(message, repeated, tag="1")] - #[serde(with = "crate::serializers::nullable")] - pub evidence: ::prost::alloc::vec::Vec, -} -#[derive(::serde::Deserialize, ::serde::Serialize)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Block { - #[prost(message, optional, tag="1")] - pub header: ::core::option::Option
, - #[prost(message, optional, tag="2")] - pub data: ::core::option::Option, - #[prost(message, optional, tag="3")] - pub evidence: ::core::option::Option, +pub struct CanonicalVote { + /// type alias for byte + #[prost(enumeration="SignedMsgType", tag="1")] + pub r#type: i32, + /// canonicalization requires fixed size encoding here + #[prost(sfixed64, tag="2")] + pub height: i64, + /// canonicalization requires fixed size encoding here + #[prost(sfixed64, tag="3")] + pub round: i64, #[prost(message, optional, tag="4")] - pub last_commit: ::core::option::Option, + pub block_id: ::core::option::Option, + #[prost(message, optional, tag="5")] + pub timestamp: ::core::option::Option, + #[prost(string, tag="6")] + pub chain_id: ::prost::alloc::string::String, } diff --git a/proto/src/prost/tendermint.version.rs b/proto/src/prost/tendermint.version.rs index bd1227266..f9b227c15 100644 --- a/proto/src/prost/tendermint.version.rs +++ b/proto/src/prost/tendermint.version.rs @@ -1,13 +1,3 @@ -/// App includes the protocol and software version for the application. -/// This information is included in ResponseInfo. The App.Protocol can be -/// updated in ResponseEndBlock. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct App { - #[prost(uint64, tag="1")] - pub protocol: u64, - #[prost(string, tag="2")] - pub software: ::prost::alloc::string::String, -} /// Consensus captures the consensus rules for processing a block in the blockchain, /// including all blockchain data structures and the rules of the application's /// state transition machine. diff --git a/proto/src/tendermint.rs b/proto/src/tendermint.rs index 335cb2877..cba47f38a 100644 --- a/proto/src/tendermint.rs +++ b/proto/src/tendermint.rs @@ -1,66 +1,62 @@ //! Tendermint-proto auto-generated sub-modules for Tendermint -pub mod consensus { - include!("prost/tendermint.consensus.rs"); -} - -pub mod types { - include!("prost/tendermint.types.rs"); +pub mod statesync { + include!("prost/tendermint.statesync.rs"); } -pub mod mempool { - include!("prost/tendermint.mempool.rs"); +pub mod abci { + include!("prost/tendermint.abci.rs"); } -pub mod rpc { - pub mod grpc { - include!("prost/tendermint.rpc.grpc.rs"); - } +pub mod version { + include!("prost/tendermint.version.rs"); } -pub mod blockchain { - include!("prost/tendermint.blockchain.rs"); +pub mod types { + include!("prost/tendermint.types.rs"); } -pub mod libs { - pub mod bits { - include!("prost/tendermint.libs.bits.rs"); - } +pub mod consensus { + include!("prost/tendermint.consensus.rs"); } -pub mod state { - include!("prost/tendermint.state.rs"); +pub mod p2p { + include!("prost/tendermint.p2p.rs"); } -pub mod version { - include!("prost/tendermint.version.rs"); +pub mod privval { + include!("prost/tendermint.privval.rs"); } -pub mod store { - include!("prost/tendermint.store.rs"); +pub mod crypto { + include!("prost/tendermint.crypto.rs"); } -pub mod privval { - include!("prost/tendermint.privval.rs"); +pub mod mempool { + include!("prost/tendermint.mempool.rs"); } -pub mod statesync { - include!("prost/tendermint.statesync.rs"); +pub mod blocksync { + include!("prost/tendermint.blocksync.rs"); } -pub mod p2p { - include!("prost/tendermint.p2p.rs"); +pub mod state { + include!("prost/tendermint.state.rs"); } -pub mod abci { - include!("prost/tendermint.abci.rs"); +pub mod libs { + pub mod bits { + include!("prost/tendermint.libs.bits.rs"); + } } -pub mod crypto { - include!("prost/tendermint.crypto.rs"); +pub mod rpc { + pub mod grpc { + include!("prost/tendermint.rpc.grpc.rs"); + } } pub mod meta { pub const REPOSITORY: &str = "https://github.com/tendermint/tendermint"; - pub const COMMITISH: &str = "v0.34.9"; + pub const COMMITISH: &str = "v0.35.0-rc3"; } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index d97e62813..753b983ce 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -78,6 +78,7 @@ subtle-encoding = { version = "0.5", default-features = false, features = ["bech url = { version = "2.2", default-features = false } walkdir = { version = "2.3", default-features = false } flex-error = { version = "0.4.4", default-features = false } +subtle = { version = "2", default-features = false } # Optional dependencies async-trait = { version = "0.1", optional = true, default-features = false } diff --git a/rpc/src/abci.rs b/rpc/src/abci.rs new file mode 100644 index 000000000..2cbb63df4 --- /dev/null +++ b/rpc/src/abci.rs @@ -0,0 +1,34 @@ +//! Old ABCI structures, formerly defined in `tendermint::abci`. +//! +//! The original contents of `tendermint::abci` were created only to model RPC +//! responses, not to model ABCI itself: +//! +//! > NOTE: This module contains types for ABCI responses as consumed from RPC +//! endpoints. It does not contain an ABCI protocol implementation. +//! +//! The old types should be eliminated and +//! merged with the new ABCI domain types. Moving them here in the meantime +//! disentangles improving the ABCI domain modeling from changes to the RPC +//! interface. + +mod code; +mod data; +mod gas; +mod info; +mod log; +mod path; + +pub mod responses; +pub mod tag; +pub mod transaction; + +pub use self::{ + code::Code, + data::Data, + gas::Gas, + info::Info, + log::Log, + path::Path, + responses::{DeliverTx, Event, Responses}, + transaction::Transaction, +}; diff --git a/tendermint/src/abci/code.rs b/rpc/src/abci/code.rs similarity index 91% rename from tendermint/src/abci/code.rs rename to rpc/src/abci/code.rs index 5a10dedfc..ccc53958a 100644 --- a/tendermint/src/abci/code.rs +++ b/rpc/src/abci/code.rs @@ -1,4 +1,4 @@ -use core::fmt; +use core::{fmt, num::NonZeroU32}; use serde::de::{Deserialize, Deserializer, Visitor}; use serde::{Serialize, Serializer}; @@ -15,7 +15,7 @@ pub enum Code { Ok, /// Error codes - Err(u32), + Err(NonZeroU32), } impl Default for Code { @@ -46,9 +46,9 @@ impl Code { impl From for Code { fn from(value: u32) -> Code { - match value { - 0 => Code::Ok, - err => Code::Err(err), + match NonZeroU32::new(value) { + Some(value) => Code::Err(value), + None => Code::Ok, } } } @@ -57,7 +57,7 @@ impl From for u32 { fn from(code: Code) -> u32 { match code { Code::Ok => 0, - Code::Err(err) => err, + Code::Err(err) => err.get(), } } } diff --git a/tendermint/src/abci/data.rs b/rpc/src/abci/data.rs similarity index 94% rename from tendermint/src/abci/data.rs rename to rpc/src/abci/data.rs index 5fc93f00f..a2c47bf32 100644 --- a/tendermint/src/abci/data.rs +++ b/rpc/src/abci/data.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; /// application-specific rules. #[derive(Clone, Debug, Eq, PartialEq, Default, Serialize, Deserialize)] #[serde(transparent)] -pub struct Data(#[serde(with = "crate::serializers::bytes::base64string")] Vec); +pub struct Data(#[serde(with = "tendermint::serializers::bytes::base64string")] Vec); impl From> for Data { fn from(value: Vec) -> Self { diff --git a/tendermint/src/abci/gas.rs b/rpc/src/abci/gas.rs similarity index 98% rename from tendermint/src/abci/gas.rs rename to rpc/src/abci/gas.rs index af7721d27..d6fe98e9d 100644 --- a/tendermint/src/abci/gas.rs +++ b/rpc/src/abci/gas.rs @@ -5,13 +5,13 @@ //! //! -use crate::error::Error; use crate::prelude::*; use core::{ fmt::{self, Display}, str::FromStr, }; use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}; +use tendermint::error::Error; /// Gas: representation of transaction processing resource costs #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, PartialOrd, Ord)] diff --git a/tendermint/src/abci/info.rs b/rpc/src/abci/info.rs similarity index 100% rename from tendermint/src/abci/info.rs rename to rpc/src/abci/info.rs diff --git a/tendermint/src/abci/log.rs b/rpc/src/abci/log.rs similarity index 100% rename from tendermint/src/abci/log.rs rename to rpc/src/abci/log.rs diff --git a/tendermint/src/abci/path.rs b/rpc/src/abci/path.rs similarity index 94% rename from tendermint/src/abci/path.rs rename to rpc/src/abci/path.rs index a49eabc3b..b5b3c8ff2 100644 --- a/tendermint/src/abci/path.rs +++ b/rpc/src/abci/path.rs @@ -1,12 +1,12 @@ //! Paths to ABCI data -use crate::error::Error; use crate::prelude::*; use core::{ fmt::{self, Display}, str::FromStr, }; use serde::{Deserialize, Serialize}; +use tendermint::error::Error; /// Path to ABCI data #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] diff --git a/tendermint/src/abci/responses.rs b/rpc/src/abci/responses.rs similarity index 98% rename from tendermint/src/abci/responses.rs rename to rpc/src/abci/responses.rs index 4a112fcfa..614e1f447 100644 --- a/tendermint/src/abci/responses.rs +++ b/rpc/src/abci/responses.rs @@ -2,9 +2,9 @@ use super::{code::Code, data::Data, gas::Gas, info::Info, log::Log, tag::Tag}; use crate::prelude::*; -use crate::{consensus, serializers, validator}; use core::fmt::{self, Display}; use serde::{Deserialize, Deserializer, Serialize}; +use tendermint::{consensus, serializers, validator}; /// Responses for ABCI calls which occur during block processing. /// diff --git a/tendermint/src/abci/tag.rs b/rpc/src/abci/tag.rs similarity index 98% rename from tendermint/src/abci/tag.rs rename to rpc/src/abci/tag.rs index 50601c5dd..8136af43e 100644 --- a/tendermint/src/abci/tag.rs +++ b/rpc/src/abci/tag.rs @@ -1,9 +1,9 @@ //! Tags -use crate::error::Error; use crate::prelude::*; use core::{fmt, str::FromStr}; use serde::{Deserialize, Serialize}; +use tendermint::error::Error; use tendermint_proto::serializers::bytes::base64string; /// Tags diff --git a/tendermint/src/abci/transaction.rs b/rpc/src/abci/transaction.rs similarity index 100% rename from tendermint/src/abci/transaction.rs rename to rpc/src/abci/transaction.rs diff --git a/tendermint/src/abci/transaction/hash.rs b/rpc/src/abci/transaction/hash.rs similarity index 98% rename from tendermint/src/abci/transaction/hash.rs rename to rpc/src/abci/transaction/hash.rs index b9b00136f..5e0c47c2d 100644 --- a/tendermint/src/abci/transaction/hash.rs +++ b/rpc/src/abci/transaction/hash.rs @@ -1,6 +1,5 @@ //! Transaction hashes -use crate::error::Error; use crate::prelude::*; use core::{ fmt::{self, Debug, Display}, @@ -9,6 +8,7 @@ use core::{ use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use subtle::{self, ConstantTimeEq}; use subtle_encoding::hex; +use tendermint::error::Error; /// Size of a transaction hash in bytes pub const LENGTH: usize = 32; diff --git a/rpc/src/client.rs b/rpc/src/client.rs index a1ce9ad3a..150bf42a3 100644 --- a/rpc/src/client.rs +++ b/rpc/src/client.rs @@ -14,6 +14,7 @@ pub use transport::websocket::{ WebSocketClient, WebSocketClientDriver, WebSocketClientUrl, WebSocketConfig, }; +use crate::abci::{self, Transaction}; use crate::endpoint::validators::DEFAULT_VALIDATORS_PER_PAGE; use crate::endpoint::*; use crate::paging::Paging; @@ -22,7 +23,6 @@ use crate::query::Query; use crate::{Error, Order, SimpleRequest}; use async_trait::async_trait; use core::time::Duration; -use tendermint::abci::{self, Transaction}; use tendermint::block::Height; use tendermint::evidence::Evidence; use tendermint::Genesis; diff --git a/rpc/src/client/bin/main.rs b/rpc/src/client/bin/main.rs index eab7664f0..b6f559a15 100644 --- a/rpc/src/client/bin/main.rs +++ b/rpc/src/client/bin/main.rs @@ -3,8 +3,7 @@ use core::str::FromStr; use futures::StreamExt; use structopt::StructOpt; -use tendermint::abci::transaction::Hash; -use tendermint::abci::{Path, Transaction}; +use tendermint_rpc::abci::{transaction::Hash, Path, Transaction}; use tendermint_rpc::query::Query; use tendermint_rpc::{ Client, Error, HttpClient, Order, Paging, Scheme, Subscription, SubscriptionClient, Url, diff --git a/rpc/src/endpoint/abci_info.rs b/rpc/src/endpoint/abci_info.rs index 37e6fd90a..212d58a4c 100644 --- a/rpc/src/endpoint/abci_info.rs +++ b/rpc/src/endpoint/abci_info.rs @@ -1,8 +1,9 @@ //! `/abci_info` endpoint JSON-RPC wrapper -use serde::{Deserialize, Serialize}; - use core::convert::{TryFrom, TryInto}; + +use bytes::Bytes; +use serde::{Deserialize, Serialize}; use tendermint::block; use tendermint::Error; use tendermint_proto::abci::ResponseInfo; @@ -49,7 +50,7 @@ pub struct AbciInfo { pub last_block_height: block::Height, /// Last app hash for the block - pub last_block_app_hash: Vec, + pub last_block_app_hash: Bytes, } impl TryFrom for AbciInfo { diff --git a/rpc/src/endpoint/abci_query.rs b/rpc/src/endpoint/abci_query.rs index c4dacc5fc..cd4841895 100644 --- a/rpc/src/endpoint/abci_query.rs +++ b/rpc/src/endpoint/abci_query.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; -use tendermint::abci::{Code, Log, Path}; +use crate::abci::{Code, Log, Path}; use tendermint::block; use tendermint::merkle::proof::Proof; use tendermint::serializers; diff --git a/rpc/src/endpoint/block_results.rs b/rpc/src/endpoint/block_results.rs index 0f2c8fcb6..8bf8df1f3 100644 --- a/rpc/src/endpoint/block_results.rs +++ b/rpc/src/endpoint/block_results.rs @@ -2,7 +2,8 @@ use serde::{Deserialize, Serialize}; -use tendermint::{abci, block, consensus, validator}; +use crate::abci; +use tendermint::{block, consensus, validator}; use crate::prelude::*; diff --git a/rpc/src/endpoint/broadcast/tx_async.rs b/rpc/src/endpoint/broadcast/tx_async.rs index 2cd5bd8ae..0de93113e 100644 --- a/rpc/src/endpoint/broadcast/tx_async.rs +++ b/rpc/src/endpoint/broadcast/tx_async.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; -use tendermint::abci::{transaction, Code, Data, Log, Transaction}; +use crate::abci::{transaction, Code, Data, Log, Transaction}; /// `/broadcast_tx_async`: broadcast a transaction and return immediately. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] diff --git a/rpc/src/endpoint/broadcast/tx_commit.rs b/rpc/src/endpoint/broadcast/tx_commit.rs index bb4cf93a5..4e0a60bfb 100644 --- a/rpc/src/endpoint/broadcast/tx_commit.rs +++ b/rpc/src/endpoint/broadcast/tx_commit.rs @@ -3,12 +3,10 @@ use serde::{Deserialize, Serialize}; -use tendermint::abci::responses::Codespace; -use tendermint::abci::{Event, Gas, Info}; -use tendermint::{ - abci::{transaction, Code, Data, Log, Transaction}, - block, +use crate::abci::{ + responses::Codespace, transaction, Code, Data, Event, Gas, Info, Log, Transaction, }; +use tendermint::block; use crate::prelude::*; diff --git a/rpc/src/endpoint/broadcast/tx_sync.rs b/rpc/src/endpoint/broadcast/tx_sync.rs index 706d9d125..e188525a4 100644 --- a/rpc/src/endpoint/broadcast/tx_sync.rs +++ b/rpc/src/endpoint/broadcast/tx_sync.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; -use tendermint::abci::{transaction, Code, Data, Log, Transaction}; +use crate::abci::{transaction, Code, Data, Log, Transaction}; /// `/broadcast_tx_sync`: returns with the response from `CheckTx`. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] diff --git a/rpc/src/endpoint/evidence.rs b/rpc/src/endpoint/evidence.rs index 98bcb3158..c9e387b81 100644 --- a/rpc/src/endpoint/evidence.rs +++ b/rpc/src/endpoint/evidence.rs @@ -2,8 +2,9 @@ use crate::Method; +use crate::abci::transaction; use serde::{Deserialize, Serialize}; -use tendermint::{abci::transaction, evidence::Evidence}; +use tendermint::evidence::Evidence; /// `/broadcast_evidence`: broadcast an evidence. #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] diff --git a/rpc/src/endpoint/tx.rs b/rpc/src/endpoint/tx.rs index e3de3ebb5..dfdec475b 100644 --- a/rpc/src/endpoint/tx.rs +++ b/rpc/src/endpoint/tx.rs @@ -1,8 +1,9 @@ //! `/tx` endpoint JSON-RPC wrapper +use crate::abci; use crate::Method; use serde::{Deserialize, Serialize}; -use tendermint::{abci, block}; +use tendermint::block; use tendermint_proto::types::TxProof; /// Request for finding a transaction by its hash. @@ -12,7 +13,7 @@ pub struct Request { /// /// Serialized internally into a base64-encoded string before sending to /// the RPC server. - #[serde(with = "tendermint::serializers::hash_base64")] + #[serde(with = "crate::serializers::hash_base64")] pub hash: abci::transaction::Hash, /// Whether or not to include the proofs of the transaction's inclusion in /// the block. diff --git a/rpc/src/event.rs b/rpc/src/event.rs index cae0c62fd..0c6757bc8 100644 --- a/rpc/src/event.rs +++ b/rpc/src/event.rs @@ -1,8 +1,8 @@ //! RPC subscription event-related data structures. +use crate::abci::responses::{BeginBlock, EndBlock}; use alloc::collections::BTreeMap as HashMap; use serde::{Deserialize, Serialize}; -use tendermint::abci::responses::{BeginBlock, EndBlock}; use tendermint::Block; use crate::prelude::*; @@ -73,5 +73,5 @@ pub struct TxResult { pub log: Option, pub gas_wanted: Option, pub gas_used: Option, - pub events: Vec, + pub events: Vec, } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 9ab6b672f..be7c381a5 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -45,6 +45,7 @@ pub use client::{HttpClient, HttpClientUrl}; #[cfg(feature = "websocket-client")] pub use client::{WebSocketClient, WebSocketClientDriver, WebSocketClientUrl, WebSocketConfig}; +pub mod abci; pub mod endpoint; pub mod error; pub mod event; @@ -57,6 +58,7 @@ pub mod request; pub mod response; pub mod response_error; mod rpc_url; +mod serializers; mod utils; mod version; diff --git a/rpc/src/serializers.rs b/rpc/src/serializers.rs new file mode 100644 index 000000000..b31d8207e --- /dev/null +++ b/rpc/src/serializers.rs @@ -0,0 +1 @@ +pub mod hash_base64; diff --git a/tendermint/src/serializers/hash_base64.rs b/rpc/src/serializers/hash_base64.rs similarity index 100% rename from tendermint/src/serializers/hash_base64.rs rename to rpc/src/serializers/hash_base64.rs diff --git a/rpc/tests/kvstore_fixtures.rs b/rpc/tests/kvstore_fixtures.rs index 1fb40251d..5cacb19eb 100644 --- a/rpc/tests/kvstore_fixtures.rs +++ b/rpc/tests/kvstore_fixtures.rs @@ -3,10 +3,10 @@ use core::str::FromStr; use std::{fs, path::PathBuf}; use subtle_encoding::{base64, hex}; -use tendermint::abci::transaction::Hash; use tendermint::evidence::Duration; use tendermint::public_key; use tendermint_config::net::Address; +use tendermint_rpc::abci::transaction::Hash; use tendermint_rpc::{ endpoint, error::{Error, ErrorDetail}, @@ -318,7 +318,7 @@ fn incoming_fixtures() { let result = endpoint::abci_info::Response::from_string(content).unwrap(); assert_eq!(result.response.app_version, 1); assert_eq!(result.response.data, "{\"size\":0}"); - assert_eq!(result.response.last_block_app_hash, b"AAAAAAAAAAA="); + assert_eq!(result.response.last_block_app_hash, b"AAAAAAAAAAA="[..]); assert_eq!(result.response.version, "0.17.0"); } "abci_query_with_existing_key" => { @@ -550,21 +550,21 @@ fn incoming_fixtures() { } "broadcast_tx_async" => { let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, tendermint::abci::Code::Ok); + assert_eq!(result.code, tendermint_rpc::abci::Code::Ok); assert!(result.data.value().is_empty()); assert_ne!( result.hash, - tendermint::abci::transaction::Hash::new([0; 32]) + tendermint_rpc::abci::transaction::Hash::new([0; 32]) ); assert!(result.log.value().is_empty()); } "broadcast_tx_commit" => { let result = endpoint::broadcast::tx_commit::Response::from_string(content).unwrap(); - assert_eq!(result.check_tx.code, tendermint::abci::Code::Ok); + assert_eq!(result.check_tx.code, tendermint_rpc::abci::Code::Ok); assert_eq!( result.check_tx.codespace, - tendermint::abci::responses::Codespace::default() + tendermint_rpc::abci::responses::Codespace::default() ); assert!(result.check_tx.data.is_none()); assert!(result.check_tx.events.is_empty()); @@ -573,10 +573,10 @@ fn incoming_fixtures() { //assert_eq!(result.check_tx.gas_wanted.value(), 1); assert!(result.check_tx.info.to_string().is_empty()); assert!(result.check_tx.log.value().is_empty()); - assert_eq!(result.deliver_tx.code, tendermint::abci::Code::Ok); + assert_eq!(result.deliver_tx.code, tendermint_rpc::abci::Code::Ok); assert_eq!( result.deliver_tx.codespace, - tendermint::abci::responses::Codespace::default() + tendermint_rpc::abci::responses::Codespace::default() ); assert!(result.deliver_tx.data.is_none()); assert_eq!(result.deliver_tx.events.len(), 1); @@ -644,16 +644,16 @@ fn incoming_fixtures() { assert!(result.deliver_tx.log.value().is_empty()); assert_ne!( result.hash, - tendermint::abci::transaction::Hash::new([0; 32]) + tendermint_rpc::abci::transaction::Hash::new([0; 32]) ); } "broadcast_tx_sync" => { let result = endpoint::broadcast::tx_sync::Response::from_string(content).unwrap(); - assert_eq!(result.code, tendermint::abci::Code::Ok); + assert_eq!(result.code, tendermint_rpc::abci::Code::Ok); assert!(result.data.value().is_empty()); assert_ne!( result.hash, - tendermint::abci::transaction::Hash::new([0; 32]) + tendermint_rpc::abci::transaction::Hash::new([0; 32]) ); assert!(result.log.value().is_empty()); } @@ -1353,61 +1353,61 @@ fn incoming_fixtures() { } "subscribe_txs_broadcast_tx_0" => { let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, tendermint::abci::Code::Ok); + assert_eq!(result.code, tendermint_rpc::abci::Code::Ok); assert!(result.data.value().is_empty()); assert_ne!( result.hash, - tendermint::abci::transaction::Hash::new([0; 32]) + tendermint_rpc::abci::transaction::Hash::new([0; 32]) ); assert!(result.log.value().is_empty()); } "subscribe_txs_broadcast_tx_1" => { let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, tendermint::abci::Code::Ok); + assert_eq!(result.code, tendermint_rpc::abci::Code::Ok); assert!(result.data.value().is_empty()); assert_ne!( result.hash, - tendermint::abci::transaction::Hash::new([0; 32]) + tendermint_rpc::abci::transaction::Hash::new([0; 32]) ); assert!(result.log.value().is_empty()); } "subscribe_txs_broadcast_tx_2" => { let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, tendermint::abci::Code::Ok); + assert_eq!(result.code, tendermint_rpc::abci::Code::Ok); assert!(result.data.value().is_empty()); assert_ne!( result.hash, - tendermint::abci::transaction::Hash::new([0; 32]) + tendermint_rpc::abci::transaction::Hash::new([0; 32]) ); assert!(result.log.value().is_empty()); } "subscribe_txs_broadcast_tx_3" => { let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, tendermint::abci::Code::Ok); + assert_eq!(result.code, tendermint_rpc::abci::Code::Ok); assert!(result.data.value().is_empty()); assert_ne!( result.hash, - tendermint::abci::transaction::Hash::new([0; 32]) + tendermint_rpc::abci::transaction::Hash::new([0; 32]) ); assert!(result.log.value().is_empty()); } "subscribe_txs_broadcast_tx_4" => { let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, tendermint::abci::Code::Ok); + assert_eq!(result.code, tendermint_rpc::abci::Code::Ok); assert!(result.data.value().is_empty()); assert_ne!( result.hash, - tendermint::abci::transaction::Hash::new([0; 32]) + tendermint_rpc::abci::transaction::Hash::new([0; 32]) ); assert!(result.log.value().is_empty()); } "subscribe_txs_broadcast_tx_5" => { let result = endpoint::broadcast::tx_async::Response::from_string(content).unwrap(); - assert_eq!(result.code, tendermint::abci::Code::Ok); + assert_eq!(result.code, tendermint_rpc::abci::Code::Ok); assert!(result.data.value().is_empty()); assert_ne!( result.hash, - tendermint::abci::transaction::Hash::new([0; 32]) + tendermint_rpc::abci::transaction::Hash::new([0; 32]) ); assert!(result.log.value().is_empty()); } @@ -1428,7 +1428,7 @@ fn incoming_fixtures() { // Test a few selected attributes of the results. for tx in result.txs { assert_ne!(tx.hash.as_bytes(), [0; 32]); - assert_eq!(tx.tx_result.code, tendermint::abci::Code::Ok); + assert_eq!(tx.tx_result.code, tendermint_rpc::abci::Code::Ok); assert_eq!(tx.tx_result.events.len(), 1); assert_eq!(tx.tx_result.events[0].type_str, "app"); assert_eq!(tx.tx_result.gas_used.value(), 0); @@ -1444,7 +1444,7 @@ fn incoming_fixtures() { // Test a few selected attributes of the results. for tx in result.txs { assert_ne!(tx.hash.as_bytes(), [0; 32]); - assert_eq!(tx.tx_result.code, tendermint::abci::Code::Ok); + assert_eq!(tx.tx_result.code, tendermint_rpc::abci::Code::Ok); assert_eq!(tx.tx_result.events.len(), 1); assert_eq!(tx.tx_result.events[0].type_str, "app"); assert_eq!(tx.tx_result.gas_used.value(), 0); diff --git a/rpc/tests/parse_response.rs b/rpc/tests/parse_response.rs index 6acc0c345..cd5ee2cad 100644 --- a/rpc/tests/parse_response.rs +++ b/rpc/tests/parse_response.rs @@ -1,7 +1,7 @@ //! Tendermint RPC endpoint testing. use std::{fs, path::PathBuf}; -use tendermint::abci::Code; +use tendermint_rpc::abci::Code; use core::str::FromStr; use tendermint::vote; diff --git a/tendermint/Cargo.toml b/tendermint/Cargo.toml index d29e95fdf..ca84f2ee5 100644 --- a/tendermint/Cargo.toml +++ b/tendermint/Cargo.toml @@ -34,7 +34,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] async-trait = { version = "0.1", default-features = false } -bytes = { version = "1.0", default-features = false } +bytes = { version = "1.0", default-features = false, features = ["serde"] } chrono = { version = "0.4.19", default-features = false, features = ["serde"] } ed25519 = { version = "1", default-features = false } ed25519-dalek = { version = "1", default-features = false, features = ["u64_backend"] } diff --git a/tendermint/src/abci.rs b/tendermint/src/abci.rs index 9a0f84761..cb039806d 100644 --- a/tendermint/src/abci.rs +++ b/tendermint/src/abci.rs @@ -1,29 +1,53 @@ -//! Application BlockChain Interface (ABCI) +//! Application BlockChain Interface ([ABCI]) is the interface between Tendermint +//! (a consensus engine for Byzantine-fault-tolerant replication of a state +//! machine) and an application (the state machine to be replicated). //! -//! NOTE: This module contains types for ABCI responses as consumed from RPC -//! endpoints. It does not contain an ABCI protocol implementation. +//! Using ABCI involves writing an application driven by ABCI methods, exposing +//! that application as an ABCI server, and having Tendermint connect to the +//! server as an ABCI client. //! -//! For that, see: +//! This module does not include an ABCI server implementation itself. Instead, +//! it provides a common set of Rust domain types that model the ABCI protocol, +//! which can be used by both ABCI applications and ABCI server implementations. //! -//! +//! One ABCI server implementation is provided by the [`tendermint_abci`][tmabci] +//! crate. +//! +//! Each ABCI method corresponds to a request/response pair. ABCI requests are +//! modeled by the [`Request`] enum, and responses are modeled by the +//! [`Response`] enum. As described in the [methods and types][mat] page, ABCI +//! methods are split into four categories. Tendermint opens one ABCI connection +//! for each category of messages. These categories are modeled by the +//! [`MethodKind`] enum and by per-category request and response enums: +//! +//! * [`ConsensusRequest`] / [`ConsensusResponse`] for [`MethodKind::Consensus`] methods; +//! * [`MempoolRequest`] / [`MempoolResponse`] for [`MethodKind::Mempool`] methods; +//! * [`InfoRequest`] / [`InfoResponse`] for [`MethodKind::Info`] methods; +//! * [`SnapshotRequest`] / [`SnapshotResponse`] for [`MethodKind::Snapshot`] methods. +//! +//! The domain types in this module have conversions to and from the Protobuf +//! types defined in the [`tendermint_proto`] crate. These conversions are +//! required for ABCI server implementations, which use the protobufs to +//! communicate with Tendermint, but should not be required for ABCI +//! applications, which should use the domain types in an interface defined by +//! their choice of ABCI server implementation. +//! +//! [ABCI]: https://docs.tendermint.com/master/spec/abci/ +//! [mat]: https://docs.tendermint.com/master/spec/abci/abci.html +//! [tmabci]: https://github.com/informalsystems/tendermint-rs/tree/master/abci + +mod event; +mod kind; + +pub mod request; +pub mod response; +pub mod types; -mod code; -mod data; -mod gas; -mod info; -mod log; -mod path; -pub mod responses; -pub mod tag; -pub mod transaction; +pub use event::{Event, EventAttribute, EventAttributeIndexExt}; +#[doc(inline)] pub use self::{ - code::Code, - data::Data, - gas::Gas, - info::Info, - log::Log, - path::Path, - responses::{DeliverTx, Event, Responses}, - transaction::Transaction, + kind::MethodKind, + request::{ConsensusRequest, InfoRequest, MempoolRequest, Request, SnapshotRequest}, + response::{ConsensusResponse, InfoResponse, MempoolResponse, Response, SnapshotResponse}, }; diff --git a/tendermint/src/abci/doc/request-applysnapshotchunk.md b/tendermint/src/abci/doc/request-applysnapshotchunk.md new file mode 100644 index 000000000..fe1c35598 --- /dev/null +++ b/tendermint/src/abci/doc/request-applysnapshotchunk.md @@ -0,0 +1,21 @@ +Applies a snapshot chunk. + +The application can choose to refetch chunks and/or ban P2P peers as +appropriate. Tendermint will not do this unless instructed by the +application. + +The application may want to verify each chunk, e.g., by attaching chunk +hashes in [`Snapshot::metadata`] and/or incrementally verifying contents +against `app_hash`. + +When all chunks have been accepted, Tendermint will make an ABCI [`Info`] +request to verify that `last_block_app_hash` and `last_block_height` match +the expected values, and record the `app_version` in the node state. It then +switches to fast sync or consensus and joins the network. + +If Tendermint is unable to retrieve the next chunk after some time (e.g., +because no suitable peers are available), it will reject the snapshot and try +a different one via `OfferSnapshot`. The application should be prepared to +reset and accept it or abort as appropriate. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#applysnapshotchunk) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-beginblock.md b/tendermint/src/abci/doc/request-beginblock.md new file mode 100644 index 000000000..44b98920a --- /dev/null +++ b/tendermint/src/abci/doc/request-beginblock.md @@ -0,0 +1,6 @@ +Signals the beginning of a new block. + +Called prior to any [`DeliverTx`]s. The `header` contains the height, +timestamp, and more -- it exactly matches the Tendermint block header. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#beginblock) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-checktx.md b/tendermint/src/abci/doc/request-checktx.md new file mode 100644 index 000000000..7d97a6287 --- /dev/null +++ b/tendermint/src/abci/doc/request-checktx.md @@ -0,0 +1,11 @@ +Check whether a transaction should be included in the mempool. + +`CheckTx` is not involved in processing blocks, only in deciding whether a +transaction should be included in the mempool. Every node runs `CheckTx` +before adding a transaction to its local mempool. The transaction may come +from an external user or another node. `CheckTx` need not execute the +transaction in full, but can instead perform lightweight or statateful +validation (e.g., checking signatures or account balances) instead of more +expensive checks (like running code in a virtual machine). + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#checktx) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-commit.md b/tendermint/src/abci/doc/request-commit.md new file mode 100644 index 000000000..0013b8302 --- /dev/null +++ b/tendermint/src/abci/doc/request-commit.md @@ -0,0 +1,4 @@ +Signals the application that it can write the queued state transitions +from the block to its state. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#commit) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-delivertx.md b/tendermint/src/abci/doc/request-delivertx.md new file mode 100644 index 000000000..4d449cc56 --- /dev/null +++ b/tendermint/src/abci/doc/request-delivertx.md @@ -0,0 +1,3 @@ +Execute a transaction against the application state. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#delivertx) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-echo.md b/tendermint/src/abci/doc/request-echo.md new file mode 100644 index 000000000..92658169f --- /dev/null +++ b/tendermint/src/abci/doc/request-echo.md @@ -0,0 +1,3 @@ +Echoes a string to test an ABCI implementation. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#echo) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-endblock.md b/tendermint/src/abci/doc/request-endblock.md new file mode 100644 index 000000000..6e23b6d7c --- /dev/null +++ b/tendermint/src/abci/doc/request-endblock.md @@ -0,0 +1,5 @@ +Signals the end of a block. + +Called after all transactions, and prior to each `Commit`. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#endblock) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-flush.md b/tendermint/src/abci/doc/request-flush.md new file mode 100644 index 000000000..c556d8b2d --- /dev/null +++ b/tendermint/src/abci/doc/request-flush.md @@ -0,0 +1,3 @@ +Indicates that any pending requests should be completed and their responses flushed. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#flush) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-info.md b/tendermint/src/abci/doc/request-info.md new file mode 100644 index 000000000..471ec36c7 --- /dev/null +++ b/tendermint/src/abci/doc/request-info.md @@ -0,0 +1,3 @@ +Requests information about the application state. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#info) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-initchain.md b/tendermint/src/abci/doc/request-initchain.md new file mode 100644 index 000000000..49180f351 --- /dev/null +++ b/tendermint/src/abci/doc/request-initchain.md @@ -0,0 +1,3 @@ +Called on genesis to initialize chain state. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#initchain) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-listsnapshots.md b/tendermint/src/abci/doc/request-listsnapshots.md new file mode 100644 index 000000000..bc89accad --- /dev/null +++ b/tendermint/src/abci/doc/request-listsnapshots.md @@ -0,0 +1,3 @@ +Asks the application for a list of snapshots. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#listsnapshots) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-loadsnapshotchunk.md b/tendermint/src/abci/doc/request-loadsnapshotchunk.md new file mode 100644 index 000000000..70b686d41 --- /dev/null +++ b/tendermint/src/abci/doc/request-loadsnapshotchunk.md @@ -0,0 +1,3 @@ +Used during state sync to retrieve snapshot chunks from peers. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#loadsnapshotchunk) \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-offersnapshot.md b/tendermint/src/abci/doc/request-offersnapshot.md new file mode 100644 index 000000000..db0e60b17 --- /dev/null +++ b/tendermint/src/abci/doc/request-offersnapshot.md @@ -0,0 +1,20 @@ +Offers a list of snapshots to the application. + +`OfferSnapshot` is called when bootstrapping a node using state sync. The +application may accept or reject snapshots as appropriate. Upon accepting, +Tendermint will retrieve and apply snapshot chunks via +[`ApplySnapshotChunk`]. The application may also choose to reject a snapshot +in the chunk response, in which case it should be prepared to accept further +`OfferSnapshot` calls. + +Only `app_hash` can be trusted, as it has been verified by the light client. +Any other data can be spoofed by adversaries, so applications should employ +additional verification schemes to avoid denial-of-service attacks. The +verified `app_hash` is automatically checked against the restored application +at the end of snapshot restoration. + +See also the [`Snapshot`] data type and the [ABCI state sync documentation][ssd]. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#offersnapshot) + +[ssd]: https://docs.tendermint.com/master/spec/abci/apps.html#state-sync \ No newline at end of file diff --git a/tendermint/src/abci/doc/request-query.md b/tendermint/src/abci/doc/request-query.md new file mode 100644 index 000000000..5d061c54e --- /dev/null +++ b/tendermint/src/abci/doc/request-query.md @@ -0,0 +1,3 @@ +Queries for data from the application at current or past height. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#query) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-applysnapshotchunk.md b/tendermint/src/abci/doc/response-applysnapshotchunk.md new file mode 100644 index 000000000..bffabe7af --- /dev/null +++ b/tendermint/src/abci/doc/response-applysnapshotchunk.md @@ -0,0 +1,7 @@ +Returns the result of applying a snapshot chunk and associated data. + +The application can choose to refetch chunks and/or ban P2P peers as +appropriate. Tendermint will not do this unless instructed by the +application. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#applysnapshotchunk) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-beginblock.md b/tendermint/src/abci/doc/response-beginblock.md new file mode 100644 index 000000000..255efd098 --- /dev/null +++ b/tendermint/src/abci/doc/response-beginblock.md @@ -0,0 +1,3 @@ +Returns events that occurred when beginning a new block. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#beginblock) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-checktx.md b/tendermint/src/abci/doc/response-checktx.md new file mode 100644 index 000000000..cd31b1703 --- /dev/null +++ b/tendermint/src/abci/doc/response-checktx.md @@ -0,0 +1,3 @@ +Returns the result of checking a transaction for mempool inclusion. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#checktx) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-commit.md b/tendermint/src/abci/doc/response-commit.md new file mode 100644 index 000000000..822aab48d --- /dev/null +++ b/tendermint/src/abci/doc/response-commit.md @@ -0,0 +1,3 @@ +Returns the result of persisting the application state. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#commit) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-delivertx.md b/tendermint/src/abci/doc/response-delivertx.md new file mode 100644 index 000000000..cb83a6fd9 --- /dev/null +++ b/tendermint/src/abci/doc/response-delivertx.md @@ -0,0 +1,4 @@ +Returns events that occurred while executing a transaction against the +application state. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#delivertx) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-echo.md b/tendermint/src/abci/doc/response-echo.md new file mode 100644 index 000000000..92658169f --- /dev/null +++ b/tendermint/src/abci/doc/response-echo.md @@ -0,0 +1,3 @@ +Echoes a string to test an ABCI implementation. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#echo) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-endblock.md b/tendermint/src/abci/doc/response-endblock.md new file mode 100644 index 000000000..062cabb84 --- /dev/null +++ b/tendermint/src/abci/doc/response-endblock.md @@ -0,0 +1,3 @@ +Returns validator updates that occur after the end of a block. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#endblock) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-exception.md b/tendermint/src/abci/doc/response-exception.md new file mode 100644 index 000000000..5d8fb6c67 --- /dev/null +++ b/tendermint/src/abci/doc/response-exception.md @@ -0,0 +1 @@ +Returns an exception (undocumented, nondeterministic). \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-flush.md b/tendermint/src/abci/doc/response-flush.md new file mode 100644 index 000000000..6c411e1bf --- /dev/null +++ b/tendermint/src/abci/doc/response-flush.md @@ -0,0 +1,3 @@ +Indicates that all pending requests have been completed with their responses flushed. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#flush) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-info.md b/tendermint/src/abci/doc/response-info.md new file mode 100644 index 000000000..e0c64b1f5 --- /dev/null +++ b/tendermint/src/abci/doc/response-info.md @@ -0,0 +1,3 @@ +Returns information about the application state. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#info) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-initchain.md b/tendermint/src/abci/doc/response-initchain.md new file mode 100644 index 000000000..b7ea62de7 --- /dev/null +++ b/tendermint/src/abci/doc/response-initchain.md @@ -0,0 +1,3 @@ +Returned on genesis after initializing chain state. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#initchain) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-listsnapshots.md b/tendermint/src/abci/doc/response-listsnapshots.md new file mode 100644 index 000000000..48255b800 --- /dev/null +++ b/tendermint/src/abci/doc/response-listsnapshots.md @@ -0,0 +1,3 @@ +Returns a list of local state snapshots. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#listsnapshots) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-loadsnapshotchunk.md b/tendermint/src/abci/doc/response-loadsnapshotchunk.md new file mode 100644 index 000000000..2eaf1c614 --- /dev/null +++ b/tendermint/src/abci/doc/response-loadsnapshotchunk.md @@ -0,0 +1,3 @@ +Returns a snapshot chunk from the application. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#loadsnapshotchunk) \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-offersnapshot.md b/tendermint/src/abci/doc/response-offersnapshot.md new file mode 100644 index 000000000..0da7a66fa --- /dev/null +++ b/tendermint/src/abci/doc/response-offersnapshot.md @@ -0,0 +1,7 @@ +Returns the application's response to a snapshot offer. + +See also the [`Snapshot`] data type and the [ABCI state sync documentation][ssd]. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#offersnapshot) + +[ssd]: https://docs.tendermint.com/master/spec/abci/apps.html#state-sync \ No newline at end of file diff --git a/tendermint/src/abci/doc/response-query.md b/tendermint/src/abci/doc/response-query.md new file mode 100644 index 000000000..57eb3bf4a --- /dev/null +++ b/tendermint/src/abci/doc/response-query.md @@ -0,0 +1,3 @@ +Returns data queried from the application. + +[ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#query) \ No newline at end of file diff --git a/tendermint/src/abci/event.rs b/tendermint/src/abci/event.rs new file mode 100644 index 000000000..76677572b --- /dev/null +++ b/tendermint/src/abci/event.rs @@ -0,0 +1,183 @@ +use crate::prelude::*; + +/// An event that occurred while processing a request. +/// +/// Application developers can attach additional information to +/// [`BeginBlock`](super::response::BeginBlock), +/// [`EndBlock`](super::response::EndBlock), +/// [`CheckTx`](super::response::CheckTx), and +/// [`DeliverTx`](super::response::DeliverTx) responses. Later, transactions may +/// be queried using these events. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#events) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Event { + /// The kind of event. + /// + /// Tendermint calls this the `type`, but we use `kind` to avoid confusion + /// with Rust types and follow Rust conventions. + pub kind: String, + /// A list of [`EventAttribute`]s describing the event. + pub attributes: Vec, +} + +impl Event { + /// Construct an event from generic data. + /// + /// The `From` impls on [`EventAttribute`] and the [`EventAttributeIndexExt`] + /// trait allow ergonomic event construction, as in this example: + /// + /// ``` + /// use tendermint::abci::{Event, EventAttributeIndexExt}; + /// + /// let event = Event::new( + /// "app", + /// vec![ + /// ("key1", "value1").index(), + /// ("key2", "value2").index(), + /// ("key3", "value3").no_index(), // will not be indexed + /// ], + /// ); + /// ``` + // XXX(hdevalence): remove vec! from example after https://github.com/rust-lang/rust/pull/65819 + pub fn new(kind: K, attributes: I) -> Self + where + K: Into, + I: IntoIterator, + I::Item: Into, + { + Self { + kind: kind.into(), + attributes: attributes.into_iter().map(Into::into).collect(), + } + } +} + +/// A key-value pair describing an [`Event`]. +/// +/// Generic methods are provided for more ergonomic attribute construction, see +/// [`Event::new`] for details. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#events) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct EventAttribute { + /// The event key. + pub key: String, + /// The event value. + pub value: String, + /// Whether Tendermint's indexer should index this event. + /// + /// **This field is nondeterministic**. + pub index: bool, +} + +impl, V: Into> From<(K, V, bool)> for EventAttribute { + fn from((key, value, index): (K, V, bool)) -> Self { + EventAttribute { + key: key.into(), + value: value.into(), + index, + } + } +} + +/// Adds convenience methods to tuples for more ergonomic [`EventAttribute`] +/// construction. +/// +/// See [`Event::new`] for details. +#[allow(missing_docs)] +pub trait EventAttributeIndexExt: private::Sealed { + type Key; + type Value; + + /// Indicate that this key/value pair should be indexed by Tendermint. + fn index(self) -> (Self::Key, Self::Value, bool); + /// Indicate that this key/value pair should not be indexed by Tendermint. + fn no_index(self) -> (Self::Key, Self::Value, bool); +} + +impl, V: Into> EventAttributeIndexExt for (K, V) { + type Key = K; + type Value = V; + fn index(self) -> (K, V, bool) { + let (key, value) = self; + (key, value, true) + } + fn no_index(self) -> (K, V, bool) { + let (key, value) = self; + (key, value, false) + } +} + +mod private { + use crate::prelude::*; + + pub trait Sealed {} + + impl, V: Into> Sealed for (K, V) {} +} + +impl, V: Into> From<(K, V)> for EventAttribute { + fn from((key, value): (K, V)) -> Self { + (key, value, false).into() + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; + +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::EventAttribute { + fn from(event: EventAttribute) -> Self { + Self { + key: event.key, + value: event.value, + index: event.index, + } + } +} + +impl TryFrom for EventAttribute { + type Error = crate::Error; + + fn try_from(event: pb::EventAttribute) -> Result { + Ok(Self { + key: event.key, + value: event.value, + index: event.index, + }) + } +} + +impl Protobuf for EventAttribute {} + +impl From for pb::Event { + fn from(event: Event) -> Self { + Self { + r#type: event.kind, + attributes: event.attributes.into_iter().map(Into::into).collect(), + } + } +} + +impl TryFrom for Event { + type Error = crate::Error; + + fn try_from(event: pb::Event) -> Result { + Ok(Self { + kind: event.r#type, + attributes: event + .attributes + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } +} + +impl Protobuf for Event {} diff --git a/tendermint/src/abci/kind.rs b/tendermint/src/abci/kind.rs new file mode 100644 index 000000000..065a01c9a --- /dev/null +++ b/tendermint/src/abci/kind.rs @@ -0,0 +1,23 @@ +/// A category of ABCI method. +/// +/// ABCI methods are split into four categories. Tendermint opens one ABCI +/// connection for each category and refers to these categories as *connections*, +/// but nothing actually restricts an ABCI connection from calling methods in +/// multiple categories. +/// +/// This enum breaks out the `Flush` method as a distinct category, since it is +/// used to control the execution of other methods. +pub enum MethodKind { + /// A consensus method, driven by the consensus protocol and responsible for + /// block execution. + Consensus, + /// A mempool method, used for validating new transactions before they're + /// shared or included in a block. + Mempool, + /// A snapshot method, used for serving and restoring state snapshots. + Snapshot, + /// An info method, used for initialization and user queries. + Info, + /// The flush method requests that all pending method requests are fully executed. + Flush, +} diff --git a/tendermint/src/abci/request.rs b/tendermint/src/abci/request.rs new file mode 100644 index 000000000..f37397de3 --- /dev/null +++ b/tendermint/src/abci/request.rs @@ -0,0 +1,304 @@ +//! ABCI requests and request data. +//! +//! The [`Request`] enum records all possible ABCI requests. Requests that +//! contain data are modeled as a separate struct, to avoid duplication of field +//! definitions. + +use crate::prelude::*; + +// IMPORTANT NOTE ON DOCUMENTATION: +// +// The documentation for each request type is adapted from the ABCI Methods and +// Types spec document. However, the same logical request may appear three +// times, as a struct with the request data, as a Request variant, and as a +// CategoryRequest variant. +// +// To avoid duplication, this documentation is stored in the doc/ folder in +// individual .md files, which are pasted onto the relevant items using #[doc = +// include_str!(...)]. +// +// This is also why certain submodules have #[allow(unused)] imports to bring +// items into scope for doc links, rather than changing the doc links -- it +// allows the doc comments to be copied without editing. + +use core::convert::{TryFrom, TryInto}; + +use super::MethodKind; +use crate::Error; + +// bring into scope for doc links +#[allow(unused)] +use super::types::Snapshot; + +mod apply_snapshot_chunk; +mod begin_block; +mod check_tx; +mod deliver_tx; +mod echo; +mod end_block; +mod info; +mod init_chain; +mod load_snapshot_chunk; +mod offer_snapshot; +mod query; + +pub use apply_snapshot_chunk::ApplySnapshotChunk; +pub use begin_block::BeginBlock; +pub use check_tx::{CheckTx, CheckTxKind}; +pub use deliver_tx::DeliverTx; +pub use echo::Echo; +pub use end_block::EndBlock; +pub use info::Info; +pub use init_chain::InitChain; +pub use load_snapshot_chunk::LoadSnapshotChunk; +pub use offer_snapshot::OfferSnapshot; +pub use query::Query; + +/// All possible ABCI requests. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Request { + #[doc = include_str!("doc/request-echo.md")] + Echo(Echo), + #[doc = include_str!("doc/request-flush.md")] + Flush, + #[doc = include_str!("doc/request-info.md")] + Info(Info), + #[doc = include_str!("doc/request-initchain.md")] + InitChain(InitChain), + #[doc = include_str!("doc/request-query.md")] + Query(Query), + #[doc = include_str!("doc/request-beginblock.md")] + BeginBlock(BeginBlock), + #[doc = include_str!("doc/request-checktx.md")] + CheckTx(CheckTx), + #[doc = include_str!("doc/request-delivertx.md")] + DeliverTx(DeliverTx), + #[doc = include_str!("doc/request-endblock.md")] + EndBlock(EndBlock), + #[doc = include_str!("doc/request-commit.md")] + Commit, + #[doc = include_str!("doc/request-listsnapshots.md")] + ListSnapshots, + #[doc = include_str!("doc/request-offersnapshot.md")] + OfferSnapshot(OfferSnapshot), + #[doc = include_str!("doc/request-loadsnapshotchunk.md")] + LoadSnapshotChunk(LoadSnapshotChunk), + #[doc = include_str!("doc/request-applysnapshotchunk.md")] + ApplySnapshotChunk(ApplySnapshotChunk), +} + +impl Request { + /// Get the method kind for this request. + pub fn kind(&self) -> MethodKind { + use Request::*; + match self { + Flush => MethodKind::Flush, + InitChain(_) => MethodKind::Consensus, + BeginBlock(_) => MethodKind::Consensus, + DeliverTx(_) => MethodKind::Consensus, + EndBlock(_) => MethodKind::Consensus, + Commit => MethodKind::Consensus, + CheckTx(_) => MethodKind::Mempool, + ListSnapshots => MethodKind::Snapshot, + OfferSnapshot(_) => MethodKind::Snapshot, + LoadSnapshotChunk(_) => MethodKind::Snapshot, + ApplySnapshotChunk(_) => MethodKind::Snapshot, + Info(_) => MethodKind::Info, + Query(_) => MethodKind::Info, + Echo(_) => MethodKind::Info, + } + } +} + +/// The consensus category of ABCI requests. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ConsensusRequest { + #[doc = include_str!("doc/request-initchain.md")] + InitChain(InitChain), + #[doc = include_str!("doc/request-beginblock.md")] + BeginBlock(BeginBlock), + #[doc = include_str!("doc/request-delivertx.md")] + DeliverTx(DeliverTx), + #[doc = include_str!("doc/request-endblock.md")] + EndBlock(EndBlock), + #[doc = include_str!("doc/request-commit.md")] + Commit, +} + +impl From for Request { + fn from(req: ConsensusRequest) -> Self { + match req { + ConsensusRequest::InitChain(x) => Self::InitChain(x), + ConsensusRequest::BeginBlock(x) => Self::BeginBlock(x), + ConsensusRequest::DeliverTx(x) => Self::DeliverTx(x), + ConsensusRequest::EndBlock(x) => Self::EndBlock(x), + ConsensusRequest::Commit => Self::Commit, + } + } +} + +impl TryFrom for ConsensusRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::InitChain(x) => Ok(Self::InitChain(x)), + Request::BeginBlock(x) => Ok(Self::BeginBlock(x)), + Request::DeliverTx(x) => Ok(Self::DeliverTx(x)), + Request::EndBlock(x) => Ok(Self::EndBlock(x)), + Request::Commit => Ok(Self::Commit), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +/// The mempool category of ABCI requests. +#[derive(Clone, PartialEq, Debug)] +pub enum MempoolRequest { + #[doc = include_str!("doc/request-checktx.md")] + CheckTx(CheckTx), +} + +impl From for Request { + fn from(req: MempoolRequest) -> Self { + match req { + MempoolRequest::CheckTx(x) => Self::CheckTx(x), + } + } +} + +impl TryFrom for MempoolRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::CheckTx(x) => Ok(Self::CheckTx(x)), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +/// The info category of ABCI requests. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum InfoRequest { + #[doc = include_str!("doc/request-info.md")] + Info(Info), + #[doc = include_str!("doc/request-query.md")] + Query(Query), + #[doc = include_str!("doc/request-echo.md")] + Echo(Echo), +} + +impl From for Request { + fn from(req: InfoRequest) -> Self { + match req { + InfoRequest::Info(x) => Self::Info(x), + InfoRequest::Query(x) => Self::Query(x), + InfoRequest::Echo(x) => Self::Echo(x), + } + } +} + +impl TryFrom for InfoRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::Info(x) => Ok(Self::Info(x)), + Request::Query(x) => Ok(Self::Query(x)), + Request::Echo(x) => Ok(Self::Echo(x)), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +/// The snapshot category of ABCI requests. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum SnapshotRequest { + #[doc = include_str!("doc/request-listsnapshots.md")] + ListSnapshots, + #[doc = include_str!("doc/request-offersnapshot.md")] + OfferSnapshot(OfferSnapshot), + #[doc = include_str!("doc/request-loadsnapshotchunk.md")] + LoadSnapshotChunk(LoadSnapshotChunk), + #[doc = include_str!("doc/request-applysnapshotchunk.md")] + ApplySnapshotChunk(ApplySnapshotChunk), +} + +impl From for Request { + fn from(req: SnapshotRequest) -> Self { + match req { + SnapshotRequest::ListSnapshots => Self::ListSnapshots, + SnapshotRequest::OfferSnapshot(x) => Self::OfferSnapshot(x), + SnapshotRequest::LoadSnapshotChunk(x) => Self::LoadSnapshotChunk(x), + SnapshotRequest::ApplySnapshotChunk(x) => Self::ApplySnapshotChunk(x), + } + } +} + +impl TryFrom for SnapshotRequest { + type Error = Error; + fn try_from(req: Request) -> Result { + match req { + Request::ListSnapshots => Ok(Self::ListSnapshots), + Request::OfferSnapshot(x) => Ok(Self::OfferSnapshot(x)), + Request::LoadSnapshotChunk(x) => Ok(Self::LoadSnapshotChunk(x)), + Request::ApplySnapshotChunk(x) => Ok(Self::ApplySnapshotChunk(x)), + _ => Err(Error::invalid_abci_request_type()), + } + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::Request { + fn from(request: Request) -> pb::Request { + use pb::request::Value; + let value = match request { + Request::Echo(x) => Some(Value::Echo(x.into())), + Request::Flush => Some(Value::Flush(Default::default())), + Request::Info(x) => Some(Value::Info(x.into())), + Request::InitChain(x) => Some(Value::InitChain(x.into())), + Request::Query(x) => Some(Value::Query(x.into())), + Request::BeginBlock(x) => Some(Value::BeginBlock(x.into())), + Request::CheckTx(x) => Some(Value::CheckTx(x.into())), + Request::DeliverTx(x) => Some(Value::DeliverTx(x.into())), + Request::EndBlock(x) => Some(Value::EndBlock(x.into())), + Request::Commit => Some(Value::Commit(Default::default())), + Request::ListSnapshots => Some(Value::ListSnapshots(Default::default())), + Request::OfferSnapshot(x) => Some(Value::OfferSnapshot(x.into())), + Request::LoadSnapshotChunk(x) => Some(Value::LoadSnapshotChunk(x.into())), + Request::ApplySnapshotChunk(x) => Some(Value::ApplySnapshotChunk(x.into())), + }; + pb::Request { value } + } +} + +impl TryFrom for Request { + type Error = Error; + + fn try_from(request: pb::Request) -> Result { + use pb::request::Value; + match request.value { + Some(Value::Echo(x)) => Ok(Request::Echo(x.try_into()?)), + Some(Value::Flush(pb::RequestFlush {})) => Ok(Request::Flush), + Some(Value::Info(x)) => Ok(Request::Info(x.try_into()?)), + Some(Value::InitChain(x)) => Ok(Request::InitChain(x.try_into()?)), + Some(Value::Query(x)) => Ok(Request::Query(x.try_into()?)), + Some(Value::BeginBlock(x)) => Ok(Request::BeginBlock(x.try_into()?)), + Some(Value::CheckTx(x)) => Ok(Request::CheckTx(x.try_into()?)), + Some(Value::DeliverTx(x)) => Ok(Request::DeliverTx(x.try_into()?)), + Some(Value::EndBlock(x)) => Ok(Request::EndBlock(x.try_into()?)), + Some(Value::Commit(pb::RequestCommit {})) => Ok(Request::Commit), + Some(Value::ListSnapshots(pb::RequestListSnapshots {})) => Ok(Request::ListSnapshots), + Some(Value::OfferSnapshot(x)) => Ok(Request::OfferSnapshot(x.try_into()?)), + Some(Value::LoadSnapshotChunk(x)) => Ok(Request::LoadSnapshotChunk(x.try_into()?)), + Some(Value::ApplySnapshotChunk(x)) => Ok(Request::ApplySnapshotChunk(x.try_into()?)), + None => Err(crate::Error::missing_data()), + } + } +} + +impl Protobuf for Request {} diff --git a/tendermint/src/abci/request/apply_snapshot_chunk.rs b/tendermint/src/abci/request/apply_snapshot_chunk.rs new file mode 100644 index 000000000..aca95daf2 --- /dev/null +++ b/tendermint/src/abci/request/apply_snapshot_chunk.rs @@ -0,0 +1,70 @@ +use crate::prelude::*; + +use bytes::Bytes; + +// bring into scope for doc links +#[allow(unused)] +use super::{super::types::Snapshot, Info, LoadSnapshotChunk}; + +/// Applies a snapshot chunk. +/// +/// The application can choose to refetch chunks and/or ban P2P peers as +/// appropriate. Tendermint will not do this unless instructed by the +/// application. +/// +/// The application may want to verify each chunk, e.g., by attaching chunk +/// hashes in [`Snapshot::metadata`] and/or incrementally verifying contents +/// against `app_hash`. +/// +/// When all chunks have been accepted, Tendermint will make an ABCI [`Info`] +/// request to verify that `last_block_app_hash` and `last_block_height` match +/// the expected values, and record the `app_version` in the node state. It then +/// switches to fast sync or consensus and joins the network. +/// +/// If Tendermint is unable to retrieve the next chunk after some time (e.g., +/// because no suitable peers are available), it will reject the snapshot and try +/// a different one via `OfferSnapshot`. The application should be prepared to +/// reset and accept it or abort as appropriate. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#applysnapshotchunk) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ApplySnapshotChunk { + /// The chunk index, starting from `0`. Tendermint applies chunks sequentially. + pub index: u32, + /// The binary chunk contents, as returned by [`LoadSnapshotChunk`]. + pub chunk: Bytes, + /// The P2P ID of the node who sent this chunk. + pub sender: String, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestApplySnapshotChunk { + fn from(apply_snapshot_chunk: ApplySnapshotChunk) -> Self { + Self { + index: apply_snapshot_chunk.index, + chunk: apply_snapshot_chunk.chunk, + sender: apply_snapshot_chunk.sender, + } + } +} + +impl TryFrom for ApplySnapshotChunk { + type Error = crate::Error; + + fn try_from(apply_snapshot_chunk: pb::RequestApplySnapshotChunk) -> Result { + Ok(Self { + index: apply_snapshot_chunk.index, + chunk: apply_snapshot_chunk.chunk, + sender: apply_snapshot_chunk.sender, + }) + } +} + +impl Protobuf for ApplySnapshotChunk {} diff --git a/tendermint/src/abci/request/begin_block.rs b/tendermint/src/abci/request/begin_block.rs new file mode 100644 index 000000000..814038b7d --- /dev/null +++ b/tendermint/src/abci/request/begin_block.rs @@ -0,0 +1,78 @@ +use crate::prelude::*; + +use bytes::Bytes; + +use crate::block; + +use super::super::types::{Evidence, LastCommitInfo}; +use crate::Error; + +// bring into scope for doc links +#[allow(unused)] +use super::DeliverTx; + +#[doc = include_str!("../doc/request-beginblock.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct BeginBlock { + /// The block's hash. + /// + /// This can be derived from the block header. + pub hash: Bytes, + /// The block header. + pub header: block::Header, + /// Information about the last commit. + /// + /// This includes the round, the list of validators, and which validators + /// signed the last block. + pub last_commit_info: LastCommitInfo, + /// Evidence of validator misbehavior. + pub byzantine_validators: Vec, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestBeginBlock { + fn from(begin_block: BeginBlock) -> Self { + Self { + hash: begin_block.hash, + header: Some(begin_block.header.into()), + last_commit_info: Some(begin_block.last_commit_info.into()), + byzantine_validators: begin_block + .byzantine_validators + .into_iter() + .map(Into::into) + .collect(), + } + } +} + +impl TryFrom for BeginBlock { + type Error = Error; + + fn try_from(begin_block: pb::RequestBeginBlock) -> Result { + Ok(Self { + hash: begin_block.hash, + header: begin_block + .header + .ok_or(Error::missing_header())? + .try_into()?, + last_commit_info: begin_block + .last_commit_info + .ok_or(Error::missing_last_commit_info())? + .try_into()?, + byzantine_validators: begin_block + .byzantine_validators + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } +} + +impl Protobuf for BeginBlock {} diff --git a/tendermint/src/abci/request/check_tx.rs b/tendermint/src/abci/request/check_tx.rs new file mode 100644 index 000000000..0a82dc030 --- /dev/null +++ b/tendermint/src/abci/request/check_tx.rs @@ -0,0 +1,71 @@ +use crate::prelude::*; + +use bytes::Bytes; + +#[doc = include_str!("../doc/request-checktx.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct CheckTx { + /// The transaction bytes. + pub tx: Bytes, + /// The kind of check to perform. + /// + /// Note: this field is called `type` in the protobuf, but we call it `kind` + /// to avoid the Rust keyword. + pub kind: CheckTxKind, +} + +/// The possible kinds of [`CheckTx`] checks. +/// +/// Note: the +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#checktx) +/// calls this `CheckTxType`, but we follow the Rust convention and name it `CheckTxKind` +/// to avoid confusion with Rust types. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[repr(i32)] +pub enum CheckTxKind { + /// A full check is required (the default). + New = 0, + /// Indicates that the mempool is initiating a recheck of the transaction. + Recheck = 1, +} + +impl Default for CheckTxKind { + fn default() -> Self { + CheckTxKind::New + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestCheckTx { + fn from(check_tx: CheckTx) -> Self { + Self { + tx: check_tx.tx, + r#type: check_tx.kind as i32, + } + } +} + +impl TryFrom for CheckTx { + type Error = crate::Error; + + fn try_from(check_tx: pb::RequestCheckTx) -> Result { + let kind = match check_tx.r#type { + 0 => CheckTxKind::New, + 1 => CheckTxKind::Recheck, + _ => Err(crate::Error::unsupported_check_tx_type())?, + }; + Ok(Self { + tx: check_tx.tx, + kind, + }) + } +} + +impl Protobuf for CheckTx {} diff --git a/tendermint/src/abci/request/deliver_tx.rs b/tendermint/src/abci/request/deliver_tx.rs new file mode 100644 index 000000000..456e45733 --- /dev/null +++ b/tendermint/src/abci/request/deliver_tx.rs @@ -0,0 +1,34 @@ +use crate::prelude::*; + +use bytes::Bytes; + +#[doc = include_str!("../doc/request-delivertx.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct DeliverTx { + /// The bytes of the transaction to execute. + pub tx: Bytes, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestDeliverTx { + fn from(deliver_tx: DeliverTx) -> Self { + Self { tx: deliver_tx.tx } + } +} + +impl TryFrom for DeliverTx { + type Error = crate::Error; + + fn try_from(deliver_tx: pb::RequestDeliverTx) -> Result { + Ok(Self { tx: deliver_tx.tx }) + } +} + +impl Protobuf for DeliverTx {} diff --git a/tendermint/src/abci/request/echo.rs b/tendermint/src/abci/request/echo.rs new file mode 100644 index 000000000..7da97b61a --- /dev/null +++ b/tendermint/src/abci/request/echo.rs @@ -0,0 +1,36 @@ +use crate::prelude::*; + +#[doc = include_str!("../doc/request-echo.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Echo { + /// The message to send back. + pub message: String, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestEcho { + fn from(echo: Echo) -> Self { + Self { + message: echo.message, + } + } +} + +impl TryFrom for Echo { + type Error = crate::Error; + + fn try_from(echo: pb::RequestEcho) -> Result { + Ok(Self { + message: echo.message, + }) + } +} + +impl Protobuf for Echo {} diff --git a/tendermint/src/abci/request/end_block.rs b/tendermint/src/abci/request/end_block.rs new file mode 100644 index 000000000..3d72341ae --- /dev/null +++ b/tendermint/src/abci/request/end_block.rs @@ -0,0 +1,36 @@ +use crate::prelude::*; + +#[doc = include_str!("../doc/request-endblock.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct EndBlock { + /// The height of the block just executed. + pub height: i64, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestEndBlock { + fn from(end_block: EndBlock) -> Self { + Self { + height: end_block.height, + } + } +} + +impl TryFrom for EndBlock { + type Error = crate::Error; + + fn try_from(end_block: pb::RequestEndBlock) -> Result { + Ok(Self { + height: end_block.height, + }) + } +} + +impl Protobuf for EndBlock {} diff --git a/tendermint/src/abci/request/info.rs b/tendermint/src/abci/request/info.rs new file mode 100644 index 000000000..a110337fd --- /dev/null +++ b/tendermint/src/abci/request/info.rs @@ -0,0 +1,48 @@ +use crate::prelude::*; + +#[doc = include_str!("../doc/request-info.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Info { + /// The Tendermint software semantic version. + pub version: String, + /// The Tendermint block protocol version. + pub block_version: u64, + /// The Tendermint p2p protocol version. + pub p2p_version: u64, + /// The Tendermint ABCI semantic version. + pub abci_version: String, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestInfo { + fn from(info: Info) -> Self { + Self { + version: info.version, + block_version: info.block_version, + p2p_version: info.p2p_version, + abci_version: info.abci_version, + } + } +} + +impl TryFrom for Info { + type Error = crate::Error; + + fn try_from(info: pb::RequestInfo) -> Result { + Ok(Self { + version: info.version, + block_version: info.block_version, + p2p_version: info.p2p_version, + abci_version: info.abci_version, + }) + } +} + +impl Protobuf for Info {} diff --git a/tendermint/src/abci/request/init_chain.rs b/tendermint/src/abci/request/init_chain.rs new file mode 100644 index 000000000..4b85e4848 --- /dev/null +++ b/tendermint/src/abci/request/init_chain.rs @@ -0,0 +1,74 @@ +use bytes::Bytes; +use chrono::{DateTime, Utc}; + +use crate::{block, consensus, prelude::*}; + +use super::super::types::ValidatorUpdate; + +/// Called on genesis to initialize chain state. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#initchain) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct InitChain { + /// The genesis time. + pub time: DateTime, + /// The ID of the blockchain. + pub chain_id: String, + /// Initial consensus-critical parameters. + pub consensus_params: consensus::Params, + /// Initial genesis validators, sorted by voting power. + pub validators: Vec, + /// Serialized JSON bytes containing the initial application state. + pub app_state_bytes: Bytes, + /// Height of the initial block (typically `1`). + pub initial_height: block::Height, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use crate::Error; +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestInitChain { + fn from(init_chain: InitChain) -> Self { + Self { + time: Some(init_chain.time.into()), + chain_id: init_chain.chain_id, + consensus_params: Some(init_chain.consensus_params.into()), + validators: init_chain.validators.into_iter().map(Into::into).collect(), + app_state_bytes: init_chain.app_state_bytes, + initial_height: init_chain.initial_height.into(), + } + } +} + +impl TryFrom for InitChain { + type Error = Error; + + fn try_from(init_chain: pb::RequestInitChain) -> Result { + Ok(Self { + time: init_chain + .time + .ok_or(Error::missing_genesis_time())? + .try_into()?, + chain_id: init_chain.chain_id, + consensus_params: init_chain + .consensus_params + .ok_or(Error::missing_consensus_params())? + .try_into()?, + validators: init_chain + .validators + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + app_state_bytes: init_chain.app_state_bytes, + initial_height: init_chain.initial_height.try_into()?, + }) + } +} + +impl Protobuf for InitChain {} diff --git a/tendermint/src/abci/request/load_snapshot_chunk.rs b/tendermint/src/abci/request/load_snapshot_chunk.rs new file mode 100644 index 000000000..d88885cd0 --- /dev/null +++ b/tendermint/src/abci/request/load_snapshot_chunk.rs @@ -0,0 +1,44 @@ +use crate::{block, prelude::*}; + +#[doc = include_str!("../doc/request-loadsnapshotchunk.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct LoadSnapshotChunk { + /// The height of the snapshot the chunks belong to. + pub height: block::Height, + /// An application-specific identifier of the format of the snapshot chunk. + pub format: u32, + /// The chunk index, starting from `0` for the initial chunk. + pub chunk: u32, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestLoadSnapshotChunk { + fn from(load_snapshot_chunk: LoadSnapshotChunk) -> Self { + Self { + height: load_snapshot_chunk.height.into(), + format: load_snapshot_chunk.format, + chunk: load_snapshot_chunk.chunk, + } + } +} + +impl TryFrom for LoadSnapshotChunk { + type Error = crate::Error; + + fn try_from(load_snapshot_chunk: pb::RequestLoadSnapshotChunk) -> Result { + Ok(Self { + height: load_snapshot_chunk.height.try_into()?, + format: load_snapshot_chunk.format, + chunk: load_snapshot_chunk.chunk, + }) + } +} + +impl Protobuf for LoadSnapshotChunk {} diff --git a/tendermint/src/abci/request/offer_snapshot.rs b/tendermint/src/abci/request/offer_snapshot.rs new file mode 100644 index 000000000..2c959e694 --- /dev/null +++ b/tendermint/src/abci/request/offer_snapshot.rs @@ -0,0 +1,52 @@ +use crate::prelude::*; + +use bytes::Bytes; + +use super::super::types::Snapshot; + +// bring into scope for doc links +#[allow(unused)] +use super::ApplySnapshotChunk; + +#[doc = include_str!("../doc/request-offersnapshot.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct OfferSnapshot { + /// The snapshot offered for restoration. + pub snapshot: Snapshot, + /// The light client verified app hash for this height. + // XXX(hdevalence): replace with apphash + pub app_hash: Bytes, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestOfferSnapshot { + fn from(offer_snapshot: OfferSnapshot) -> Self { + Self { + snapshot: Some(offer_snapshot.snapshot.into()), + app_hash: offer_snapshot.app_hash, + } + } +} + +impl TryFrom for OfferSnapshot { + type Error = crate::Error; + + fn try_from(offer_snapshot: pb::RequestOfferSnapshot) -> Result { + Ok(Self { + snapshot: offer_snapshot + .snapshot + .ok_or(crate::Error::missing_data())? + .try_into()?, + app_hash: offer_snapshot.app_hash, + }) + } +} + +impl Protobuf for OfferSnapshot {} diff --git a/tendermint/src/abci/request/query.rs b/tendermint/src/abci/request/query.rs new file mode 100644 index 000000000..1530f69d2 --- /dev/null +++ b/tendermint/src/abci/request/query.rs @@ -0,0 +1,63 @@ +use bytes::Bytes; + +use crate::{block, prelude::*}; + +#[doc = include_str!("../doc/request-query.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Query { + /// Raw query bytes. + /// + /// Can be used with or in lieu of `path`. + pub data: Bytes, + /// Path of the request, like an HTTP `GET` path. + /// + /// Can be used with or in lieu of `data`. + /// + /// Applications MUST interpret `/store` as a query by key on the underlying + /// store. The key SHOULD be specified in the Data field. Applications SHOULD + /// allow queries over specific types like `/accounts/...` or `/votes/...`. + pub path: String, + /// The block height for which the query should be executed. + /// + /// The default `0` returns data for the latest committed block. Note that + /// this is the height of the block containing the application's Merkle root + /// hash, which represents the state as it was after committing the block at + /// `height - 1`. + pub height: block::Height, + /// Whether to return a Merkle proof with the response, if possible. + pub prove: bool, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::RequestQuery { + fn from(query: Query) -> Self { + Self { + data: query.data, + path: query.path, + height: query.height.into(), + prove: query.prove, + } + } +} + +impl TryFrom for Query { + type Error = crate::Error; + + fn try_from(query: pb::RequestQuery) -> Result { + Ok(Self { + data: query.data, + path: query.path, + height: query.height.try_into()?, + prove: query.prove, + }) + } +} + +impl Protobuf for Query {} diff --git a/tendermint/src/abci/response.rs b/tendermint/src/abci/response.rs new file mode 100644 index 000000000..eed823f9b --- /dev/null +++ b/tendermint/src/abci/response.rs @@ -0,0 +1,289 @@ +//! ABCI responses and response data. +//! +//! The [`Response`] enum records all possible ABCI responses. Responses that +//! contain data are modeled as a separate struct, to avoid duplication of field +//! definitions. + +use crate::prelude::*; + +// IMPORTANT NOTE ON DOCUMENTATION: +// +// The documentation for each request type is adapted from the ABCI Methods and +// Types spec document. However, the same logical request may appear three +// times, as a struct with the request data, as a Request variant, and as a +// CategoryRequest variant. +// +// To avoid duplication, this documentation is stored in the doc/ folder in +// individual .md files, which are pasted onto the relevant items using #[doc = +// include_str!(...)]. +// +// This is also why certain submodules have #[allow(unused)] imports to bring +// items into scope for doc links, rather than changing the doc links -- it +// allows the doc comments to be copied without editing. + +use core::convert::{TryFrom, TryInto}; + +use crate::Error; +// bring into scope for doc links +#[allow(unused)] +use super::types::Snapshot; + +mod apply_snapshot_chunk; +mod begin_block; +mod check_tx; +mod commit; +mod deliver_tx; +mod echo; +mod end_block; +mod exception; +mod info; +mod init_chain; +mod list_snapshots; +mod load_snapshot_chunk; +mod offer_snapshot; +mod query; + +pub use apply_snapshot_chunk::{ApplySnapshotChunk, ApplySnapshotChunkResult}; +pub use begin_block::BeginBlock; +pub use check_tx::CheckTx; +pub use commit::Commit; +pub use deliver_tx::DeliverTx; +pub use echo::Echo; +pub use end_block::EndBlock; +pub use exception::Exception; +pub use info::Info; +pub use init_chain::InitChain; +pub use list_snapshots::ListSnapshots; +pub use load_snapshot_chunk::LoadSnapshotChunk; +pub use offer_snapshot::OfferSnapshot; +pub use query::Query; + +/// All possible ABCI responses. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum Response { + #[doc = include_str!("doc/response-exception.md")] + Exception(Exception), + #[doc = include_str!("doc/response-echo.md")] + Echo(Echo), + #[doc = include_str!("doc/response-flush.md")] + Flush, + #[doc = include_str!("doc/response-info.md")] + Info(Info), + #[doc = include_str!("doc/response-initchain.md")] + InitChain(InitChain), + #[doc = include_str!("doc/response-query.md")] + Query(Query), + #[doc = include_str!("doc/response-beginblock.md")] + BeginBlock(BeginBlock), + #[doc = include_str!("doc/response-checktx.md")] + CheckTx(CheckTx), + #[doc = include_str!("doc/response-delivertx.md")] + DeliverTx(DeliverTx), + #[doc = include_str!("doc/response-endblock.md")] + EndBlock(EndBlock), + #[doc = include_str!("doc/response-commit.md")] + Commit(Commit), + #[doc = include_str!("doc/response-listsnapshots.md")] + ListSnapshots(ListSnapshots), + #[doc = include_str!("doc/response-offersnapshot.md")] + OfferSnapshot(OfferSnapshot), + #[doc = include_str!("doc/response-loadsnapshotchunk.md")] + LoadSnapshotChunk(LoadSnapshotChunk), + #[doc = include_str!("doc/response-applysnapshotchunk.md")] + ApplySnapshotChunk(ApplySnapshotChunk), +} + +/// The consensus category of ABCI responses. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum ConsensusResponse { + #[doc = include_str!("doc/response-initchain.md")] + InitChain(InitChain), + #[doc = include_str!("doc/response-beginblock.md")] + BeginBlock(BeginBlock), + #[doc = include_str!("doc/response-delivertx.md")] + DeliverTx(DeliverTx), + #[doc = include_str!("doc/response-endblock.md")] + EndBlock(EndBlock), + #[doc = include_str!("doc/response-commit.md")] + Commit(Commit), +} + +impl From for Response { + fn from(req: ConsensusResponse) -> Self { + match req { + ConsensusResponse::InitChain(x) => Self::InitChain(x), + ConsensusResponse::BeginBlock(x) => Self::BeginBlock(x), + ConsensusResponse::DeliverTx(x) => Self::DeliverTx(x), + ConsensusResponse::EndBlock(x) => Self::EndBlock(x), + ConsensusResponse::Commit(x) => Self::Commit(x), + } + } +} + +impl TryFrom for ConsensusResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::InitChain(x) => Ok(Self::InitChain(x)), + Response::BeginBlock(x) => Ok(Self::BeginBlock(x)), + Response::DeliverTx(x) => Ok(Self::DeliverTx(x)), + Response::EndBlock(x) => Ok(Self::EndBlock(x)), + Response::Commit(x) => Ok(Self::Commit(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +/// The mempool category of ABCI responses. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum MempoolResponse { + #[doc = include_str!("doc/response-checktx.md")] + CheckTx(CheckTx), +} + +impl From for Response { + fn from(req: MempoolResponse) -> Self { + match req { + MempoolResponse::CheckTx(x) => Self::CheckTx(x), + } + } +} + +impl TryFrom for MempoolResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::CheckTx(x) => Ok(Self::CheckTx(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +/// The info category of ABCI responses. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum InfoResponse { + #[doc = include_str!("doc/response-echo.md")] + Echo(Echo), + #[doc = include_str!("doc/response-info.md")] + Info(Info), + #[doc = include_str!("doc/response-query.md")] + Query(Query), +} + +impl From for Response { + fn from(req: InfoResponse) -> Self { + match req { + InfoResponse::Echo(x) => Self::Echo(x), + InfoResponse::Info(x) => Self::Info(x), + InfoResponse::Query(x) => Self::Query(x), + } + } +} + +impl TryFrom for InfoResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::Echo(x) => Ok(Self::Echo(x)), + Response::Info(x) => Ok(Self::Info(x)), + Response::Query(x) => Ok(Self::Query(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +/// The snapshot category of ABCI responses. +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum SnapshotResponse { + #[doc = include_str!("doc/response-listsnapshots.md")] + ListSnapshots(ListSnapshots), + #[doc = include_str!("doc/response-offersnapshot.md")] + OfferSnapshot(OfferSnapshot), + #[doc = include_str!("doc/response-loadsnapshotchunk.md")] + LoadSnapshotChunk(LoadSnapshotChunk), + #[doc = include_str!("doc/response-applysnapshotchunk.md")] + ApplySnapshotChunk(ApplySnapshotChunk), +} + +impl From for Response { + fn from(req: SnapshotResponse) -> Self { + match req { + SnapshotResponse::ListSnapshots(x) => Self::ListSnapshots(x), + SnapshotResponse::OfferSnapshot(x) => Self::OfferSnapshot(x), + SnapshotResponse::LoadSnapshotChunk(x) => Self::LoadSnapshotChunk(x), + SnapshotResponse::ApplySnapshotChunk(x) => Self::ApplySnapshotChunk(x), + } + } +} + +impl TryFrom for SnapshotResponse { + type Error = Error; + fn try_from(req: Response) -> Result { + match req { + Response::ListSnapshots(x) => Ok(Self::ListSnapshots(x)), + Response::OfferSnapshot(x) => Ok(Self::OfferSnapshot(x)), + Response::LoadSnapshotChunk(x) => Ok(Self::LoadSnapshotChunk(x)), + Response::ApplySnapshotChunk(x) => Ok(Self::ApplySnapshotChunk(x)), + _ => Err(Error::invalid_abci_response_type()), + } + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::Response { + fn from(response: Response) -> pb::Response { + use pb::response::Value; + let value = match response { + Response::Exception(x) => Some(Value::Exception(x.into())), + Response::Echo(x) => Some(Value::Echo(x.into())), + Response::Flush => Some(Value::Flush(Default::default())), + Response::Info(x) => Some(Value::Info(x.into())), + Response::InitChain(x) => Some(Value::InitChain(x.into())), + Response::Query(x) => Some(Value::Query(x.into())), + Response::BeginBlock(x) => Some(Value::BeginBlock(x.into())), + Response::CheckTx(x) => Some(Value::CheckTx(x.into())), + Response::DeliverTx(x) => Some(Value::DeliverTx(x.into())), + Response::EndBlock(x) => Some(Value::EndBlock(x.into())), + Response::Commit(x) => Some(Value::Commit(x.into())), + Response::ListSnapshots(x) => Some(Value::ListSnapshots(x.into())), + Response::OfferSnapshot(x) => Some(Value::OfferSnapshot(x.into())), + Response::LoadSnapshotChunk(x) => Some(Value::LoadSnapshotChunk(x.into())), + Response::ApplySnapshotChunk(x) => Some(Value::ApplySnapshotChunk(x.into())), + }; + pb::Response { value } + } +} + +impl TryFrom for Response { + type Error = Error; + + fn try_from(response: pb::Response) -> Result { + use pb::response::Value; + match response.value { + Some(Value::Exception(x)) => Ok(Response::Exception(x.try_into()?)), + Some(Value::Echo(x)) => Ok(Response::Echo(x.try_into()?)), + Some(Value::Flush(_)) => Ok(Response::Flush), + Some(Value::Info(x)) => Ok(Response::Info(x.try_into()?)), + Some(Value::InitChain(x)) => Ok(Response::InitChain(x.try_into()?)), + Some(Value::Query(x)) => Ok(Response::Query(x.try_into()?)), + Some(Value::BeginBlock(x)) => Ok(Response::BeginBlock(x.try_into()?)), + Some(Value::CheckTx(x)) => Ok(Response::CheckTx(x.try_into()?)), + Some(Value::DeliverTx(x)) => Ok(Response::DeliverTx(x.try_into()?)), + Some(Value::EndBlock(x)) => Ok(Response::EndBlock(x.try_into()?)), + Some(Value::Commit(x)) => Ok(Response::Commit(x.try_into()?)), + Some(Value::ListSnapshots(x)) => Ok(Response::ListSnapshots(x.try_into()?)), + Some(Value::OfferSnapshot(x)) => Ok(Response::OfferSnapshot(x.try_into()?)), + Some(Value::LoadSnapshotChunk(x)) => Ok(Response::LoadSnapshotChunk(x.try_into()?)), + Some(Value::ApplySnapshotChunk(x)) => Ok(Response::ApplySnapshotChunk(x.try_into()?)), + None => Err(crate::Error::missing_data()), + } + } +} + +impl Protobuf for Response {} diff --git a/tendermint/src/abci/response/apply_snapshot_chunk.rs b/tendermint/src/abci/response/apply_snapshot_chunk.rs new file mode 100644 index 000000000..fc8eef903 --- /dev/null +++ b/tendermint/src/abci/response/apply_snapshot_chunk.rs @@ -0,0 +1,88 @@ +use crate::prelude::*; + +#[doc = include_str!("../doc/response-applysnapshotchunk.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct ApplySnapshotChunk { + /// The result of applying the snapshot chunk. + pub result: ApplySnapshotChunkResult, + /// Refetch and reapply the given chunks, regardless of `result`. + /// + /// Only the listed chunks will be refetched, and reapplied in sequential + /// order. + pub refetch_chunks: Vec, + /// Reject the given P2P senders, regardless of `result`. + /// + /// Any chunks already applied will not be refetched unless explicitly + /// requested, but queued chunks from these senders will be discarded, and + /// new chunks or other snapshots rejected. + pub reject_senders: Vec, +} + +/// The result of applying a snapshot chunk. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[repr(i32)] +pub enum ApplySnapshotChunkResult { + /// Unknown result, abort all snapshot restoration. + Unknown = 0, + /// The chunk was accepted. + Accept = 1, + /// Abort snapshot restoration, and don't try any other snapshots. + Abort = 2, + /// Reapply this chunk, combine with + /// [`refetch_chunks`](ApplySnapshotChunk::refetch_chunks) and + /// [`reject_senders`](ApplySnapshotChunk::reject_senders) as appropriate. + Retry = 3, + /// Restart this snapshot from + /// [`OfferSnapshot`](super::super::request::OfferSnapshot), + /// reusing chunks unless instructed otherwise. + RetrySnapshot = 4, + /// Reject this snapshot, try a different one. + RejectSnapshot = 5, +} + +impl Default for ApplySnapshotChunkResult { + fn default() -> Self { + Self::Unknown + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseApplySnapshotChunk { + fn from(apply_snapshot_chunk: ApplySnapshotChunk) -> Self { + Self { + result: apply_snapshot_chunk.result as i32, + refetch_chunks: apply_snapshot_chunk.refetch_chunks, + reject_senders: apply_snapshot_chunk.reject_senders, + } + } +} + +impl TryFrom for ApplySnapshotChunk { + type Error = crate::Error; + + fn try_from(apply_snapshot_chunk: pb::ResponseApplySnapshotChunk) -> Result { + let result = match apply_snapshot_chunk.result { + 0 => ApplySnapshotChunkResult::Unknown, + 1 => ApplySnapshotChunkResult::Accept, + 2 => ApplySnapshotChunkResult::Abort, + 3 => ApplySnapshotChunkResult::Retry, + 4 => ApplySnapshotChunkResult::RetrySnapshot, + 5 => ApplySnapshotChunkResult::RejectSnapshot, + _ => Err(crate::Error::unsupported_apply_snapshot_chunk_result())?, + }; + Ok(Self { + result, + refetch_chunks: apply_snapshot_chunk.refetch_chunks, + reject_senders: apply_snapshot_chunk.reject_senders, + }) + } +} + +impl Protobuf for ApplySnapshotChunk {} diff --git a/tendermint/src/abci/response/begin_block.rs b/tendermint/src/abci/response/begin_block.rs new file mode 100644 index 000000000..2335becfb --- /dev/null +++ b/tendermint/src/abci/response/begin_block.rs @@ -0,0 +1,42 @@ +use crate::prelude::*; + +use super::super::Event; + +#[doc = include_str!("../doc/response-beginblock.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct BeginBlock { + /// Events that occurred while beginning the block. + pub events: Vec, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseBeginBlock { + fn from(begin_block: BeginBlock) -> Self { + Self { + events: begin_block.events.into_iter().map(Into::into).collect(), + } + } +} + +impl TryFrom for BeginBlock { + type Error = crate::Error; + + fn try_from(begin_block: pb::ResponseBeginBlock) -> Result { + Ok(Self { + events: begin_block + .events + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } +} + +impl Protobuf for BeginBlock {} diff --git a/tendermint/src/abci/response/check_tx.rs b/tendermint/src/abci/response/check_tx.rs new file mode 100644 index 000000000..500b9699e --- /dev/null +++ b/tendermint/src/abci/response/check_tx.rs @@ -0,0 +1,92 @@ +use crate::prelude::*; + +use bytes::Bytes; + +use super::super::Event; + +#[doc = include_str!("../doc/response-checktx.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct CheckTx { + /// The response code. + /// + /// Transactions where `code != 0` will be rejected; these transactions will + /// not be broadcast to other nodes or included in a proposal block. + /// Tendermint attributes no other value to the response code. + pub code: u32, + /// Result bytes, if any. + pub data: Bytes, + /// The output of the application's logger. + /// + /// **May be non-deterministic**. + pub log: String, + /// Additional information. + /// + /// **May be non-deterministic**. + pub info: String, + /// Amount of gas requested for the transaction. + pub gas_wanted: i64, + /// Amount of gas consumed by the transaction. + pub gas_used: i64, + /// Events that occurred while checking the transaction. + pub events: Vec, + /// The namespace for the `code`. + pub codespace: String, + /// The transaction's sender (e.g. the signer). + pub sender: String, + /// The transaction's priority (for mempool ordering). + pub priority: i64, + /* mempool_error is contained in the proto, but skipped here: + * > mempool_error is set by Tendermint. + * > ABCI applictions creating a ResponseCheckTX should not set mempool_error. */ +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseCheckTx { + fn from(check_tx: CheckTx) -> Self { + Self { + code: check_tx.code, + data: check_tx.data, + log: check_tx.log, + info: check_tx.info, + gas_wanted: check_tx.gas_wanted, + gas_used: check_tx.gas_used, + events: check_tx.events.into_iter().map(Into::into).collect(), + codespace: check_tx.codespace, + sender: check_tx.sender, + priority: check_tx.priority, + mempool_error: String::default(), + } + } +} + +impl TryFrom for CheckTx { + type Error = crate::Error; + + fn try_from(check_tx: pb::ResponseCheckTx) -> Result { + Ok(Self { + code: check_tx.code, + data: check_tx.data, + log: check_tx.log, + info: check_tx.info, + gas_wanted: check_tx.gas_wanted, + gas_used: check_tx.gas_used, + events: check_tx + .events + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + codespace: check_tx.codespace, + sender: check_tx.sender, + priority: check_tx.priority, + }) + } +} + +impl Protobuf for CheckTx {} diff --git a/tendermint/src/abci/response/commit.rs b/tendermint/src/abci/response/commit.rs new file mode 100644 index 000000000..9cded2e26 --- /dev/null +++ b/tendermint/src/abci/response/commit.rs @@ -0,0 +1,45 @@ +use crate::{block, prelude::*}; + +use bytes::Bytes; + +#[doc = include_str!("../doc/response-commit.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct Commit { + /// The Merkle root hash of the application state + /// + /// XXX(hdevalence) - is this different from an app hash? + /// XXX(hdevalence) - rename to app_hash ? + pub data: Bytes, + /// Blocks below this height may be removed. + pub retain_height: block::Height, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseCommit { + fn from(commit: Commit) -> Self { + Self { + data: commit.data, + retain_height: commit.retain_height.into(), + } + } +} + +impl TryFrom for Commit { + type Error = crate::Error; + + fn try_from(commit: pb::ResponseCommit) -> Result { + Ok(Self { + data: commit.data, + retain_height: commit.retain_height.try_into()?, + }) + } +} + +impl Protobuf for Commit {} diff --git a/tendermint/src/abci/response/deliver_tx.rs b/tendermint/src/abci/response/deliver_tx.rs new file mode 100644 index 000000000..271f82457 --- /dev/null +++ b/tendermint/src/abci/response/deliver_tx.rs @@ -0,0 +1,80 @@ +use crate::prelude::*; + +use bytes::Bytes; + +use super::super::Event; + +#[doc = include_str!("../doc/response-delivertx.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct DeliverTx { + /// The response code. + /// + /// This code should be `0` only if the transaction is fully valid. However, + /// invalid transactions included in a block will still be executed against + /// the application state. + pub code: u32, + /// Result bytes, if any. + pub data: Bytes, + /// The output of the application's logger. + /// + /// **May be non-deterministic**. + pub log: String, + /// Additional information. + /// + /// **May be non-deterministic**. + pub info: String, + /// Amount of gas requested for the transaction. + pub gas_wanted: i64, + /// Amount of gas consumed by the transaction. + pub gas_used: i64, + /// Events that occurred while executing the transaction. + pub events: Vec, + /// The namespace for the `code`. + pub codespace: String, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseDeliverTx { + fn from(deliver_tx: DeliverTx) -> Self { + Self { + code: deliver_tx.code, + data: deliver_tx.data, + log: deliver_tx.log, + info: deliver_tx.info, + gas_wanted: deliver_tx.gas_wanted, + gas_used: deliver_tx.gas_used, + events: deliver_tx.events.into_iter().map(Into::into).collect(), + codespace: deliver_tx.codespace, + } + } +} + +impl TryFrom for DeliverTx { + type Error = crate::Error; + + fn try_from(deliver_tx: pb::ResponseDeliverTx) -> Result { + Ok(Self { + code: deliver_tx.code, + data: deliver_tx.data, + log: deliver_tx.log, + info: deliver_tx.info, + gas_wanted: deliver_tx.gas_wanted, + gas_used: deliver_tx.gas_used, + events: deliver_tx + .events + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + codespace: deliver_tx.codespace, + }) + } +} + +impl Protobuf for DeliverTx {} diff --git a/tendermint/src/abci/response/echo.rs b/tendermint/src/abci/response/echo.rs new file mode 100644 index 000000000..03cdcb185 --- /dev/null +++ b/tendermint/src/abci/response/echo.rs @@ -0,0 +1,36 @@ +use crate::prelude::*; + +#[doc = include_str!("../doc/response-echo.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct Echo { + /// The message sent in the request. + pub message: String, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseEcho { + fn from(echo: Echo) -> Self { + Self { + message: echo.message, + } + } +} + +impl TryFrom for Echo { + type Error = crate::Error; + + fn try_from(echo: pb::ResponseEcho) -> Result { + Ok(Self { + message: echo.message, + }) + } +} + +impl Protobuf for Echo {} diff --git a/tendermint/src/abci/response/end_block.rs b/tendermint/src/abci/response/end_block.rs new file mode 100644 index 000000000..521a44978 --- /dev/null +++ b/tendermint/src/abci/response/end_block.rs @@ -0,0 +1,63 @@ +use crate::{consensus, prelude::*}; + +use super::super::{types::ValidatorUpdate, Event}; + +#[doc = include_str!("../doc/response-endblock.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct EndBlock { + /// Changes to the validator set, if any. + /// + /// Setting the voting power to 0 removes a validator. + pub validator_updates: Vec, + /// Changes to consensus parameters (optional). + pub consensus_param_updates: Option, + /// Events that occurred while ending the block. + pub events: Vec, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseEndBlock { + fn from(end_block: EndBlock) -> Self { + Self { + validator_updates: end_block + .validator_updates + .into_iter() + .map(Into::into) + .collect(), + consensus_param_updates: end_block.consensus_param_updates.map(Into::into), + events: end_block.events.into_iter().map(Into::into).collect(), + } + } +} + +impl TryFrom for EndBlock { + type Error = crate::Error; + + fn try_from(end_block: pb::ResponseEndBlock) -> Result { + Ok(Self { + validator_updates: end_block + .validator_updates + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + consensus_param_updates: end_block + .consensus_param_updates + .map(TryInto::try_into) + .transpose()?, + events: end_block + .events + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } +} + +impl Protobuf for EndBlock {} diff --git a/tendermint/src/abci/response/exception.rs b/tendermint/src/abci/response/exception.rs new file mode 100644 index 000000000..cbb607c5d --- /dev/null +++ b/tendermint/src/abci/response/exception.rs @@ -0,0 +1,36 @@ +use crate::prelude::*; + +#[doc = include_str!("../doc/response-exception.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Exception { + /// Undocumented. + pub error: String, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseException { + fn from(exception: Exception) -> Self { + Self { + error: exception.error, + } + } +} + +impl TryFrom for Exception { + type Error = crate::Error; + + fn try_from(exception: pb::ResponseException) -> Result { + Ok(Self { + error: exception.error, + }) + } +} + +impl Protobuf for Exception {} diff --git a/tendermint/src/abci/response/info.rs b/tendermint/src/abci/response/info.rs new file mode 100644 index 000000000..02bc6e9a1 --- /dev/null +++ b/tendermint/src/abci/response/info.rs @@ -0,0 +1,55 @@ +use crate::{block, prelude::*, Error}; + +use bytes::Bytes; + +#[doc = include_str!("../doc/response-info.md")] +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Info { + /// Some arbitrary information. + pub data: String, + /// The application software semantic version. + pub version: String, + /// The application protocol version. + pub app_version: u64, + /// The latest block for which the app has called [`Commit`](super::super::Request::Commit). + pub last_block_height: block::Height, + /// The latest result of [`Commit`](super::super::Request::Commit). + // XXX(hdevalence): fix this, should be apphash? + pub last_block_app_hash: Bytes, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseInfo { + fn from(info: Info) -> Self { + Self { + data: info.data, + version: info.version, + app_version: info.app_version, + last_block_height: info.last_block_height.into(), + last_block_app_hash: info.last_block_app_hash, + } + } +} + +impl TryFrom for Info { + type Error = Error; + + fn try_from(info: pb::ResponseInfo) -> Result { + Ok(Self { + data: info.data, + version: info.version, + app_version: info.app_version, + last_block_height: info.last_block_height.try_into()?, + last_block_app_hash: info.last_block_app_hash, + }) + } +} + +impl Protobuf for Info {} diff --git a/tendermint/src/abci/response/init_chain.rs b/tendermint/src/abci/response/init_chain.rs new file mode 100644 index 000000000..6d443b71d --- /dev/null +++ b/tendermint/src/abci/response/init_chain.rs @@ -0,0 +1,62 @@ +use bytes::Bytes; + +use crate::{consensus, prelude::*}; + +use super::super::types::ValidatorUpdate; + +#[doc = include_str!("../doc/response-initchain.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct InitChain { + /// Initial consensus-critical parameters (optional). + pub consensus_params: Option, + /// Initial validator set (optional). + /// + /// If this list is empty, the initial validator set will be the one given in + /// [`request::InitChain::validators`](super::super::request::InitChain::validators). + /// + /// If this list is nonempty, it will be the initial validator set, instead + /// of the one given in + /// [`request::InitChain::validators`](super::super::request::InitChain::validators). + pub validators: Vec, + /// Initial application hash. + pub app_hash: Bytes, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseInitChain { + fn from(init_chain: InitChain) -> Self { + Self { + consensus_params: init_chain.consensus_params.map(Into::into), + validators: init_chain.validators.into_iter().map(Into::into).collect(), + app_hash: init_chain.app_hash, + } + } +} + +impl TryFrom for InitChain { + type Error = crate::Error; + + fn try_from(init_chain: pb::ResponseInitChain) -> Result { + Ok(Self { + consensus_params: init_chain + .consensus_params + .map(TryInto::try_into) + .transpose()?, + validators: init_chain + .validators + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + app_hash: init_chain.app_hash, + }) + } +} + +impl Protobuf for InitChain {} diff --git a/tendermint/src/abci/response/list_snapshots.rs b/tendermint/src/abci/response/list_snapshots.rs new file mode 100644 index 000000000..ef5353f73 --- /dev/null +++ b/tendermint/src/abci/response/list_snapshots.rs @@ -0,0 +1,46 @@ +use crate::prelude::*; + +use super::super::types::Snapshot; + +#[doc = include_str!("../doc/response-listsnapshots.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct ListSnapshots { + /// A list of local state snapshots. + pub snapshots: Vec, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseListSnapshots { + fn from(list_snapshots: ListSnapshots) -> Self { + Self { + snapshots: list_snapshots + .snapshots + .into_iter() + .map(Into::into) + .collect(), + } + } +} + +impl TryFrom for ListSnapshots { + type Error = crate::Error; + + fn try_from(list_snapshots: pb::ResponseListSnapshots) -> Result { + Ok(Self { + snapshots: list_snapshots + .snapshots + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } +} + +impl Protobuf for ListSnapshots {} diff --git a/tendermint/src/abci/response/load_snapshot_chunk.rs b/tendermint/src/abci/response/load_snapshot_chunk.rs new file mode 100644 index 000000000..406a4470a --- /dev/null +++ b/tendermint/src/abci/response/load_snapshot_chunk.rs @@ -0,0 +1,41 @@ +use crate::prelude::*; + +use bytes::Bytes; + +#[doc = include_str!("../doc/response-loadsnapshotchunk.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct LoadSnapshotChunk { + /// The binary chunk contents, in an arbitrary format. + /// + /// Chunk messages cannot be larger than 16MB *including metadata*, so 10MB + /// is a good starting point. + pub chunk: Bytes, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseLoadSnapshotChunk { + fn from(load_snapshot_chunk: LoadSnapshotChunk) -> Self { + Self { + chunk: load_snapshot_chunk.chunk, + } + } +} + +impl TryFrom for LoadSnapshotChunk { + type Error = crate::Error; + + fn try_from(load_snapshot_chunk: pb::ResponseLoadSnapshotChunk) -> Result { + Ok(Self { + chunk: load_snapshot_chunk.chunk, + }) + } +} + +impl Protobuf for LoadSnapshotChunk {} diff --git a/tendermint/src/abci/response/offer_snapshot.rs b/tendermint/src/abci/response/offer_snapshot.rs new file mode 100644 index 000000000..a59ba9fac --- /dev/null +++ b/tendermint/src/abci/response/offer_snapshot.rs @@ -0,0 +1,63 @@ +use crate::prelude::*; + +// bring into scope for doc links +#[allow(unused)] +use super::super::types::Snapshot; + +#[doc = include_str!("../doc/response-offersnapshot.md")] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[repr(i32)] +pub enum OfferSnapshot { + /// Unknown result, abort all snapshot restoration + Unknown = 0, + /// Snapshot accepted, apply chunks + Accept = 1, + /// Abort all snapshot restoration + Abort = 2, + /// Reject this specific snapshot, try others + Reject = 3, + /// Reject all snapshots of this format, try others + RejectFormat = 4, + /// Reject all snapshots from the sender(s), try others + RejectSender = 5, +} + +impl Default for OfferSnapshot { + fn default() -> Self { + Self::Unknown + } +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::TryFrom; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseOfferSnapshot { + fn from(offer_snapshot: OfferSnapshot) -> Self { + Self { + result: offer_snapshot as i32, + } + } +} + +impl TryFrom for OfferSnapshot { + type Error = crate::Error; + + fn try_from(offer_snapshot: pb::ResponseOfferSnapshot) -> Result { + Ok(match offer_snapshot.result { + 0 => OfferSnapshot::Unknown, + 1 => OfferSnapshot::Accept, + 2 => OfferSnapshot::Abort, + 3 => OfferSnapshot::Reject, + 4 => OfferSnapshot::RejectFormat, + 5 => OfferSnapshot::RejectSender, + _ => Err(crate::Error::unsupported_offer_snapshot_chunk_result())?, + }) + } +} + +impl Protobuf for OfferSnapshot {} diff --git a/tendermint/src/abci/response/query.rs b/tendermint/src/abci/response/query.rs new file mode 100644 index 000000000..fd1b9655d --- /dev/null +++ b/tendermint/src/abci/response/query.rs @@ -0,0 +1,81 @@ +use bytes::Bytes; + +/// XXX(hdevalence): hide merkle::proof and re-export its contents from merkle? +use crate::merkle::proof as merkle; +use crate::{block, prelude::*}; + +#[doc = include_str!("../doc/response-query.md")] +#[derive(Clone, PartialEq, Eq, Debug, Default)] +pub struct Query { + /// The response code for the query. + pub code: u32, + /// The output of the application's logger. + /// + /// **May be non-deterministic**. + pub log: String, + /// Additional information. + /// + /// **May be non-deterministic**. + pub info: String, + /// The index of the key in the tree. + pub index: i64, + /// The key of the matching data. + pub key: Bytes, + /// The value of the matching data. + pub value: Bytes, + /// Serialized proof for the value data, if requested, to be verified against + /// the app hash for the given `height`. + pub proof: Option, + /// The block height from which data was derived. + /// + /// Note that this is the height of the block containing the application's + /// Merkle root hash, which represents the state as it was after committing + /// the block at `height - 1`. + pub height: block::Height, + /// The namespace for the `code`. + pub codespace: String, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use core::convert::{TryFrom, TryInto}; +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::ResponseQuery { + fn from(query: Query) -> Self { + Self { + code: query.code, + log: query.log, + info: query.info, + index: query.index, + key: query.key, + value: query.value, + proof_ops: query.proof.map(Into::into), + height: query.height.into(), + codespace: query.codespace, + } + } +} + +impl TryFrom for Query { + type Error = crate::Error; + + fn try_from(query: pb::ResponseQuery) -> Result { + Ok(Self { + code: query.code, + log: query.log, + info: query.info, + index: query.index, + key: query.key, + value: query.value, + proof: query.proof_ops.map(TryInto::try_into).transpose()?, + height: query.height.try_into()?, + codespace: query.codespace, + }) + } +} + +impl Protobuf for Query {} diff --git a/tendermint/src/abci/types.rs b/tendermint/src/abci/types.rs new file mode 100644 index 000000000..30dc0cded --- /dev/null +++ b/tendermint/src/abci/types.rs @@ -0,0 +1,304 @@ +//! ABCI-specific data types used in requests and responses. +//! +//! These types have changes from the core data structures to better accomodate +//! ABCI applications. +//! +//! [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#data-types) + +use core::convert::{TryFrom, TryInto}; + +use bytes::Bytes; +use chrono::{DateTime, Utc}; + +use crate::{block, prelude::*, vote, Error, PublicKey}; + +/// A validator address with voting power. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#validator) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Validator { + /// The validator's address (the first 20 bytes of `SHA256(public_key)`). + pub address: [u8; 20], + /// The voting power of the validator. + pub power: vote::Power, +} + +/// A change to the validator set. +/// +/// Used to inform Tendermint of changes to the validator set. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#validatorupdate) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct ValidatorUpdate { + /// The validator's public key. + pub pub_key: PublicKey, + /// The validator's voting power. + pub power: vote::Power, +} + +/// Information about a whether a validator signed the last block. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#voteinfo) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct VoteInfo { + /// Identifies the validator. + pub validator: Validator, + /// Whether or not the validator signed the last block. + pub signed_last_block: bool, +} + +/// The possible kinds of [`Evidence`]. +/// +/// Note: the +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#evidencetype-2) +/// calls this `EvidenceType`, but we follow the Rust convention and name it `EvidenceKind` +/// to avoid confusion with Rust types. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[repr(i32)] +pub enum EvidenceKind { + /// Unknown evidence type (proto default value). + Unknown = 0, + /// Evidence that the validator voted for two different blocks in the same + /// round of the same height. + DuplicateVote = 1, + /// Evidence that a validator attacked a light client. + LightClientAttack = 2, +} + +/// Evidence of validator misbehavior. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#evidence) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Evidence { + /// The kind of evidence. + /// + /// Note: this field is called `type` in the protobuf, but we call it `kind` + /// to avoid the Rust keyword. + pub kind: EvidenceKind, + /// The offending validator. + pub validator: Validator, + /// The height when the offense occurred. + pub height: block::Height, + /// The corresponding time when the offense occurred. + pub time: DateTime, + /// Total voting power of the validator set at `height`. + /// + /// This is included in case the ABCI application does not store historical + /// validators, cf. + /// [#4581](https://github.com/tendermint/tendermint/issues/4581) + pub total_voting_power: vote::Power, +} + +/// Information on the last block commit. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#lastcommitinfo) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct LastCommitInfo { + /// The commit round. + /// + /// Reflects the total number of rounds it took to come to consensus for the + /// current block. + pub round: block::Round, + /// The list of validator addresses in the last validator set, with their + /// voting power and whether or not they signed a vote. + pub votes: Vec, +} + +/// Used for state sync snapshots. +/// +/// When sent across the network, a `Snapshot` can be at most 4 MB. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#snapshot) +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Snapshot { + /// The height at which the snapshot was taken + pub height: block::Height, + /// The application-specific snapshot format identifier. + /// + /// This allows applications to version their snapshot data format and make + /// backwards-incompatible changes. Tendermint does not interpret this field. + pub format: u32, + /// The number of chunks in the snapshot. Must be at least 1. + pub chunks: u32, + /// An arbitrary snapshot hash. + /// + /// This hash must be equal only for identical snapshots across nodes. + /// Tendermint does not interpret the hash, only compares it with other + /// hashes. + pub hash: Bytes, + /// Arbitrary application metadata, e.g., chunk hashes or other verification data. + pub metadata: Bytes, +} + +// ============================================================================= +// Protobuf conversions +// ============================================================================= + +use tendermint_proto::abci as pb; +use tendermint_proto::Protobuf; + +impl From for pb::Validator { + fn from(v: Validator) -> Self { + Self { + address: Bytes::copy_from_slice(&v.address[..]), + power: v.power.into(), + } + } +} + +impl TryFrom for Validator { + type Error = Error; + + fn try_from(vu: pb::Validator) -> Result { + let address = if vu.address.len() == 20 { + let mut bytes = [0u8; 20]; + bytes.copy_from_slice(&vu.address); + bytes + } else { + return Err(Error::invalid_account_id_length()); + }; + + Ok(Self { + address, + power: vu.power.try_into()?, + }) + } +} + +impl Protobuf for Validator {} + +impl From for pb::ValidatorUpdate { + fn from(vu: ValidatorUpdate) -> Self { + Self { + pub_key: Some(vu.pub_key.into()), + power: vu.power.into(), + } + } +} + +impl TryFrom for ValidatorUpdate { + type Error = Error; + + fn try_from(vu: pb::ValidatorUpdate) -> Result { + Ok(Self { + pub_key: vu.pub_key.ok_or(Error::missing_public_key())?.try_into()?, + power: vu.power.try_into()?, + }) + } +} + +impl Protobuf for ValidatorUpdate {} + +impl From for pb::VoteInfo { + fn from(vi: VoteInfo) -> Self { + Self { + validator: Some(vi.validator.into()), + signed_last_block: vi.signed_last_block, + } + } +} + +impl TryFrom for VoteInfo { + type Error = Error; + + fn try_from(vi: pb::VoteInfo) -> Result { + Ok(Self { + validator: vi.validator.ok_or(Error::missing_validator())?.try_into()?, + signed_last_block: vi.signed_last_block, + }) + } +} + +impl Protobuf for VoteInfo {} + +impl From for pb::Evidence { + fn from(evidence: Evidence) -> Self { + Self { + r#type: evidence.kind as i32, + validator: Some(evidence.validator.into()), + height: evidence.height.into(), + time: Some(evidence.time.into()), + total_voting_power: evidence.total_voting_power.into(), + } + } +} + +impl TryFrom for Evidence { + type Error = Error; + + fn try_from(evidence: pb::Evidence) -> Result { + let kind = match evidence.r#type { + 0 => EvidenceKind::Unknown, + 1 => EvidenceKind::DuplicateVote, + 2 => EvidenceKind::LightClientAttack, + _ => Err(Error::invalid_evidence())?, + }; + + Ok(Self { + kind, + validator: evidence + .validator + .ok_or(Error::missing_validator())? + .try_into()?, + height: evidence.height.try_into()?, + time: evidence.time.ok_or(Error::missing_timestamp())?.into(), + total_voting_power: evidence.total_voting_power.try_into()?, + }) + } +} + +impl Protobuf for Evidence {} + +impl From for pb::LastCommitInfo { + fn from(lci: LastCommitInfo) -> Self { + Self { + round: lci.round.into(), + votes: lci.votes.into_iter().map(Into::into).collect(), + } + } +} + +impl TryFrom for LastCommitInfo { + type Error = Error; + + fn try_from(lci: pb::LastCommitInfo) -> Result { + Ok(Self { + round: lci.round.try_into()?, + votes: lci + .votes + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } +} + +impl Protobuf for LastCommitInfo {} + +impl From for pb::Snapshot { + fn from(snapshot: Snapshot) -> Self { + Self { + height: snapshot.height.into(), + format: snapshot.format, + chunks: snapshot.chunks, + hash: snapshot.hash, + metadata: snapshot.metadata, + } + } +} + +impl TryFrom for Snapshot { + type Error = Error; + + fn try_from(snapshot: pb::Snapshot) -> Result { + Ok(Self { + height: snapshot.height.try_into()?, + format: snapshot.format, + chunks: snapshot.chunks, + hash: snapshot.hash, + metadata: snapshot.metadata, + }) + } +} + +impl Protobuf for Snapshot {} diff --git a/tendermint/src/block.rs b/tendermint/src/block.rs index d16d29944..b95b65f13 100644 --- a/tendermint/src/block.rs +++ b/tendermint/src/block.rs @@ -22,7 +22,7 @@ pub use self::{ size::Size, }; use crate::prelude::*; -use crate::{abci::transaction, error::Error, evidence}; +use crate::{error::Error, evidence}; use core::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; use tendermint_proto::types::Block as RawBlock; @@ -35,18 +35,18 @@ use tendermint_proto::Protobuf; // Default serialization - all fields serialize; used by /block endpoint #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[non_exhaustive] +#[serde(try_from = "RawBlock", into = "RawBlock")] pub struct Block { /// Block header pub header: Header, /// Transaction data - pub data: transaction::Data, + pub data: Vec>, /// Evidence of malfeasance pub evidence: evidence::Data, /// Last commit - #[serde(with = "crate::serializers::optional")] pub last_commit: Option, } @@ -75,7 +75,7 @@ impl TryFrom for Block { //} Ok(Block { header, - data: value.data.ok_or_else(Error::missing_data)?.into(), + data: value.data.ok_or_else(Error::missing_data)?.txs, evidence: value .evidence .ok_or_else(Error::missing_evidence)? @@ -87,9 +87,10 @@ impl TryFrom for Block { impl From for RawBlock { fn from(value: Block) -> Self { + use tendermint_proto::types::Data as RawData; RawBlock { header: Some(value.header.into()), - data: Some(value.data.into()), + data: Some(RawData { txs: value.data }), evidence: Some(value.evidence.into()), last_commit: value.last_commit.map(Into::into), } @@ -100,7 +101,7 @@ impl Block { /// constructor pub fn new( header: Header, - data: transaction::Data, + data: Vec>, evidence: evidence::Data, last_commit: Option, ) -> Result { @@ -128,7 +129,7 @@ impl Block { } /// Get data - pub fn data(&self) -> &transaction::Data { + pub fn data(&self) -> &Vec> { &self.data } diff --git a/tendermint/src/block/size.rs b/tendermint/src/block/size.rs index 0781e9058..3260bfeb6 100644 --- a/tendermint/src/block/size.rs +++ b/tendermint/src/block/size.rs @@ -6,7 +6,7 @@ use tendermint_proto::Protobuf; use { crate::serializers, serde::{Deserialize, Serialize}, - tendermint_proto::abci::BlockParams as RawSize, + tendermint_proto::types::BlockParams as RawSize, }; /// Block size parameters diff --git a/tendermint/src/consensus/params.rs b/tendermint/src/consensus/params.rs index 25e2af838..fbc73a6f1 100644 --- a/tendermint/src/consensus/params.rs +++ b/tendermint/src/consensus/params.rs @@ -5,23 +5,23 @@ use crate::prelude::*; use crate::{block, evidence, public_key}; use core::convert::{TryFrom, TryInto}; use serde::{Deserialize, Serialize}; -use tendermint_proto::abci::ConsensusParams as RawParams; +use tendermint_proto::types::ConsensusParams as RawParams; use tendermint_proto::types::ValidatorParams as RawValidatorParams; use tendermint_proto::types::VersionParams as RawVersionParams; use tendermint_proto::Protobuf; -/// Tendermint consensus parameters +/// All consensus-relevant parameters that can be adjusted by the ABCI app. +/// +/// [ABCI documentation](https://docs.tendermint.com/master/spec/abci/abci.html#consensusparams) #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] pub struct Params { - /// Block size parameters + /// Parameters limiting the size of a block and time between consecutive blocks. pub block: block::Size, - - /// Evidence parameters + /// Parameters limiting the validity of evidence of byzantine behaviour. pub evidence: evidence::Params, - - /// Validator parameters + /// Parameters limiting the types of public keys validators can use. pub validator: ValidatorParams, - + /// The ABCI application version. /// Version parameters #[serde(skip)] // Todo: FIXME kvstore /genesis returns '{}' instead of '{app_version: "0"}' pub version: Option, @@ -62,10 +62,12 @@ impl From for RawParams { } } -/// Validator consensus parameters +/// ValidatorParams restrict the public key types validators can use. +/// +/// [Tendermint documentation](https://docs.tendermint.com/master/spec/core/data_structures.html#validatorparams) #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] pub struct ValidatorParams { - /// Allowed algorithms for validator signing + /// List of accepted public key types. pub pub_key_types: Vec, } @@ -108,10 +110,13 @@ impl From for RawValidatorParams { } /// Version Parameters +/// +/// [Tendermint documentation](https://docs.tendermint.com/master/spec/core/data_structures.html#versionparams) #[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq, Default)] pub struct VersionParams { + /// The ABCI application version. #[serde(with = "crate::serializers::from_str")] - app_version: u64, + pub app_version: u64, } impl Protobuf for VersionParams {} diff --git a/tendermint/src/error.rs b/tendermint/src/error.rs index 85cdfd7a7..62eed778e 100644 --- a/tendermint/src/error.rs +++ b/tendermint/src/error.rs @@ -112,6 +112,27 @@ define_error! { MissingTimestamp |_| { format_args!("missing timestamp field") }, + MissingVersion + |_| { format_args!("missing version") }, + + MissingMaxAgeDuration + |_| { format_args!("missing max_age_duration") }, + + MissingPublicKey + |_| { format_args!("missing public key") }, + + MissingValidator + |_| { format_args!("missing validator") }, + + MissingLastCommitInfo + |_| { format_args!("missing last commit info") }, + + MissingGenesisTime + |_| { format_args!("missing genesis time") }, + + MissingConsensusParams + |_| { format_args!("missing consensus params") }, + InvalidTimestamp { reason: String } | e | { format_args!("invalid timestamp: {}", e.reason) }, @@ -120,9 +141,6 @@ define_error! { { reason: String } | e | { format_args!("invalid block: {}", e.reason) }, - MissingVersion - |_| { format_args!("missing version") }, - InvalidFirstHeader |_| { format_args!("last_block_id is not null on first height") }, @@ -139,6 +157,18 @@ define_error! { InvalidEvidence |_| { format_args!("invalid evidence") }, + InvalidValidatorParams + |_| { format_args!("invalid validator parameters") }, + + InvalidVersionParams + |_| { format_args!("invalid version parameters") }, + + InvalidAbciRequestType + |_| { format_args!("invalid ABCI request type") }, + + InvalidAbciResponseType + |_| { format_args!("invalid ABCI response type") }, + BlockIdFlag |_| { format_args!("invalid block id flag") }, @@ -149,26 +179,23 @@ define_error! { UnsupportedKeyType |_| { format_args!("unsupported key type" ) }, - RawVotingPowerMismatch - { raw: vote::Power, computed: vote::Power } - |e| { format_args!("mismatch between raw voting ({0:?}) and computed one ({1:?})", e.raw, e.computed) }, + UnsupportedCheckTxType + |_| { format_args!("unsupported CheckTx type" ) }, - MissingPublicKey - |_| { format_args!("missing public key") }, + UnsupportedApplySnapshotChunkResult + |_| { format_args!("unsupported ApplySnapshotChunkResult type" ) }, - InvalidValidatorParams - |_| { format_args!("invalid validator parameters") }, + UnsupportedOfferSnapshotChunkResult + |_| { format_args!("unsupported OfferSnapshotChunkResult type" ) }, - InvalidVersionParams - |_| { format_args!("invalid version parameters") }, + RawVotingPowerMismatch + { raw: vote::Power, computed: vote::Power } + |e| { format_args!("mismatch between raw voting ({0:?}) and computed one ({1:?})", e.raw, e.computed) }, NegativeMaxAgeNum [ DisplayOnly ] |_| { format_args!("negative max_age_num_blocks") }, - MissingMaxAgeDuration - |_| { format_args!("missing max_age_duration") }, - ProposerNotFound { account: account::Id } |e| { format_args!("proposer with address '{0}' no found in validator set", e.account) }, @@ -195,3 +222,9 @@ define_error! { |_| { "trust threshold too small (must be >= 1/3)" }, } } + +impl From for Error { + fn from(_never: core::convert::Infallible) -> Error { + unreachable!("Infallible can never be constructed") + } +} diff --git a/tendermint/src/evidence.rs b/tendermint/src/evidence.rs index 66ac5465f..767b7e385 100644 --- a/tendermint/src/evidence.rs +++ b/tendermint/src/evidence.rs @@ -207,19 +207,28 @@ impl AsRef<[Evidence]> for Data { } } -/// Evidence collection parameters +/// EvidenceParams determine how we handle evidence of malfeasance. +/// +/// [Tendermint documentation](https://docs.tendermint.com/master/spec/core/data_structures.html#evidenceparams) #[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)] // Todo: This struct is ready to be converted through tendermint_proto::types::EvidenceParams. // https://github.com/informalsystems/tendermint-rs/issues/741 pub struct Params { - /// Maximum allowed age for evidence to be collected + /// Max age of evidence, in blocks. #[serde(with = "serializers::from_str")] pub max_age_num_blocks: u64, - /// Max age duration + /// Max age of evidence, in time. + /// + /// It should correspond with an app's "unbonding period" or other similar + /// mechanism for handling [Nothing-At-Stake attacks][nas]. + /// + /// [nas]: https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ#what-is-the-nothing-at-stake-problem-and-how-can-it-be-fixed pub max_age_duration: Duration, - /// Max bytes + /// This sets the maximum size of total evidence in bytes that can be + /// committed in a single block, and should fall comfortably under the max + /// block bytes. The default is 1048576 or 1MB. #[serde(with = "serializers::from_str", default)] pub max_bytes: i64, } diff --git a/tendermint/src/hash.rs b/tendermint/src/hash.rs index 237e640d4..b00271bb9 100644 --- a/tendermint/src/hash.rs +++ b/tendermint/src/hash.rs @@ -233,7 +233,11 @@ impl AsRef<[u8]> for AppHash { impl Debug for AppHash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "hash::AppHash({:?})", self.0) + write!( + f, + "AppHash({})", + Hex::upper_case().encode_to_string(&self.0).unwrap() + ) } } diff --git a/tendermint/src/prelude.rs b/tendermint/src/prelude.rs index 9ff42a989..3aee8bcda 100644 --- a/tendermint/src/prelude.rs +++ b/tendermint/src/prelude.rs @@ -9,3 +9,6 @@ pub use alloc::vec::Vec; pub use alloc::format; pub use alloc::vec; + +// will be included in 2021 edition. +pub use core::convert::{TryFrom, TryInto}; diff --git a/tendermint/src/serializers.rs b/tendermint/src/serializers.rs index 697ceaa1c..8a0efc8b9 100644 --- a/tendermint/src/serializers.rs +++ b/tendermint/src/serializers.rs @@ -9,6 +9,5 @@ pub use tendermint_proto::serializers::*; pub mod apphash; pub mod hash; -pub mod hash_base64; pub mod option_hash; pub mod time; diff --git a/tools/proto-compiler/src/constants.rs b/tools/proto-compiler/src/constants.rs index 6a0fa439c..e65c0e083 100644 --- a/tools/proto-compiler/src/constants.rs +++ b/tools/proto-compiler/src/constants.rs @@ -6,7 +6,7 @@ pub const TENDERMINT_REPO: &str = "https://github.com/tendermint/tendermint"; // Tag: v0.34.0-rc4 // Branch: master // Commit ID (full length): d7d0ffea13c60c98b812d243ba5a2c375f341c15 -pub const TENDERMINT_COMMITISH: &str = "v0.34.9"; +pub const TENDERMINT_COMMITISH: &str = "v0.35.0-rc3"; /// Predefined custom attributes for message annotations const PRIMITIVE_ENUM: &str = r#"#[derive(::num_derive::FromPrimitive, ::num_derive::ToPrimitive)]"#; @@ -20,8 +20,7 @@ const HEXSTRING: &str = r#"#[serde(with = "crate::serializers::bytes::hexstring" const BASE64STRING: &str = r#"#[serde(with = "crate::serializers::bytes::base64string")]"#; const VEC_BASE64STRING: &str = r#"#[serde(with = "crate::serializers::bytes::vec_base64string")]"#; const OPTIONAL: &str = r#"#[serde(with = "crate::serializers::optional")]"#; -const VEC_SKIP_IF_EMPTY: &str = - r#"#[serde(skip_serializing_if = "::prost::alloc::vec::Vec::is_empty", with = "serde_bytes")]"#; +const BYTES_SKIP_IF_EMPTY: &str = r#"#[serde(skip_serializing_if = "bytes::Bytes::is_empty")]"#; const NULLABLEVECARRAY: &str = r#"#[serde(with = "crate::serializers::txs")]"#; const NULLABLE: &str = r#"#[serde(with = "crate::serializers::nullable")]"#; const ALIAS_POWER_QUOTED: &str = @@ -30,6 +29,7 @@ const PART_SET_HEADER_TOTAL: &str = r#"#[serde(with = "crate::serializers::part_set_header_total")]"#; const RENAME_EDPUBKEY: &str = r#"#[serde(rename = "tendermint/PubKeyEd25519", with = "crate::serializers::bytes::base64string")]"#; const RENAME_SECPPUBKEY: &str = r#"#[serde(rename = "tendermint/PubKeySecp256k1", with = "crate::serializers::bytes::base64string")]"#; +const RENAME_SRPUBKEY: &str = r#"#[serde(rename = "tendermint/PubKeySr25519", with = "crate::serializers::bytes::base64string")]"#; const RENAME_DUPLICATEVOTE: &str = r#"#[serde(rename = "tendermint/DuplicateVoteEvidence")]"#; const RENAME_LIGHTCLIENTATTACK: &str = r#"#[serde(rename = "tendermint/LightClientAttackEvidence")]"#; @@ -90,7 +90,7 @@ pub static CUSTOM_FIELD_ATTRIBUTES: &[(&str, &str)] = &[ (".tendermint.version.Consensus.app", QUOTED_WITH_DEFAULT), ( ".tendermint.abci.ResponseInfo.last_block_app_hash", - VEC_SKIP_IF_EMPTY, + BYTES_SKIP_IF_EMPTY, ), (".tendermint.abci.ResponseInfo.app_version", QUOTED), (".tendermint.types.BlockID.hash", HEXSTRING), @@ -144,6 +144,7 @@ pub static CUSTOM_FIELD_ATTRIBUTES: &[(&str, &str)] = &[ ".tendermint.crypto.PublicKey.sum.secp256k1", RENAME_SECPPUBKEY, ), + (".tendermint.crypto.PublicKey.sum.sr25519", RENAME_SRPUBKEY), ( ".tendermint.types.Evidence.sum.duplicate_vote_evidence", RENAME_DUPLICATEVOTE, diff --git a/tools/proto-compiler/src/main.rs b/tools/proto-compiler/src/main.rs index 8be0203d4..7de037997 100644 --- a/tools/proto-compiler/src/main.rs +++ b/tools/proto-compiler/src/main.rs @@ -55,8 +55,12 @@ fn main() { // List available proto files let protos = find_proto_files(proto_paths); - // Compile proto files with added annotations, exchange prost_types to our own let mut pb = prost_build::Config::new(); + + // Use shared Bytes buffers for ABCI messages: + pb.bytes(&[".tendermint.abci"]); + + // Compile proto files with added annotations, exchange prost_types to our own pb.out_dir(&out_dir); for type_attribute in CUSTOM_TYPE_ATTRIBUTES { pb.type_attribute(type_attribute.0, type_attribute.1);