Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Implement ABCI++ #1

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 55 additions & 23 deletions abci/src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ pub mod kvstore;

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,
ResponseApplySnapshotChunk, ResponseBeginBlock, ResponseCheckTx, ResponseCommit,
ResponseDeliverTx, ResponseEcho, ResponseEndBlock, ResponseFlush, ResponseInfo,
ResponseInitChain, ResponseListSnapshots, ResponseLoadSnapshotChunk, ResponseOfferSnapshot,
ResponseQuery, ResponseSetOption,
response, Request, RequestApplySnapshotChunk, RequestCheckTx, RequestEcho, RequestExtendVote,
RequestFinalizeBlock, RequestInfo, RequestInitChain, RequestLoadSnapshotChunk,
RequestOfferSnapshot, RequestPrepareProposal, RequestProcessProposal, RequestQuery,
RequestRevertProposal, RequestVerifyHeader, RequestVerifyVoteExtension, Response,
ResponseApplySnapshotChunk, ResponseCheckTx, ResponseCommit, ResponseEcho, ResponseExtendVote,
ResponseFinalizeBlock, ResponseFlush, ResponseInfo, ResponseInitChain, ResponseListSnapshots,
ResponseLoadSnapshotChunk, ResponseOfferSnapshot, ResponsePrepareProposal,
ResponseProcessProposal, ResponseQuery, ResponseRevertProposal, ResponseVerifyHeader,
ResponseVerifyVoteExtension,
};

/// An ABCI application.
Expand Down Expand Up @@ -52,18 +54,41 @@ pub trait Application: Send + Clone + 'static {
Default::default()
}

/// Signals the beginning of a new block, prior to any `DeliverTx` calls.
fn begin_block(&self, _request: RequestBeginBlock) -> ResponseBeginBlock {
/// Finalize block
fn finalize_block(&self, _request: RequestFinalizeBlock) -> ResponseFinalizeBlock {
Default::default()
}

/// Apply a transaction to the application's state.
fn deliver_tx(&self, _request: RequestDeliverTx) -> ResponseDeliverTx {
/// Prepare proposal
fn prepare_proposal(&self, _request: RequestPrepareProposal) -> ResponsePrepareProposal {
Default::default()
}

/// Signals the end of a block.
fn end_block(&self, _request: RequestEndBlock) -> ResponseEndBlock {
/// Verify header
fn verify_header(&self, _request: RequestVerifyHeader) -> ResponseVerifyHeader {
Default::default()
}

/// Process proposal
fn process_proposal(&self, _request: RequestProcessProposal) -> ResponseProcessProposal {
Default::default()
}

/// Process proposal
fn revert_proposal(&self, _request: RequestRevertProposal) -> ResponseRevertProposal {
Default::default()
}

/// Extend vote
fn extend_vote(&self, _request: RequestExtendVote) -> ResponseExtendVote {
Default::default()
}

/// Verify vote extension
fn verify_vote_extension(
&self,
_request: RequestVerifyVoteExtension,
) -> ResponseVerifyVoteExtension {
Default::default()
}

Expand All @@ -77,12 +102,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()
Expand Down Expand Up @@ -124,13 +143,9 @@ impl<A: Application> 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)),
Value::CheckTx(req) => response::Value::CheckTx(self.check_tx(req)),
Value::DeliverTx(req) => response::Value::DeliverTx(self.deliver_tx(req)),
Value::EndBlock(req) => response::Value::EndBlock(self.end_block(req)),
Value::Commit(_) => response::Value::Commit(self.commit()),
Value::ListSnapshots(_) => response::Value::ListSnapshots(self.list_snapshots()),
Value::OfferSnapshot(req) => {
Expand All @@ -142,6 +157,23 @@ impl<A: Application> RequestDispatcher for A {
Value::ApplySnapshotChunk(req) => {
response::Value::ApplySnapshotChunk(self.apply_snapshot_chunk(req))
}
Value::FinalizeBlock(req) => {
response::Value::FinalizeBlock(self.finalize_block(req))
}
Value::PrepareProposal(req) => {
response::Value::PrepareProposal(self.prepare_proposal(req))
}
Value::VerifyHeader(req) => response::Value::VerifyHeader(self.verify_header(req)),
Value::ProcessProposal(req) => {
response::Value::ProcessProposal(self.process_proposal(req))
}
Value::RevertProposal(req) => {
response::Value::RevertProposal(self.revert_proposal(req))
}
Value::ExtendVote(req) => response::Value::ExtendVote(self.extend_vote(req)),
Value::VerifyVoteExtension(req) => {
response::Value::VerifyVoteExtension(self.verify_vote_extension(req))
}
}),
}
}
Expand Down
4 changes: 2 additions & 2 deletions abci/src/application/kvstore.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! In-memory key/value store ABCI application.

use crate::codec::{encode_varint, MAX_VARINT_LENGTH};
use crate::codec::MAX_VARINT_LENGTH;
use crate::{Application, Error, Result};
use bytes::BytesMut;
use std::collections::HashMap;
Expand Down Expand Up @@ -236,7 +236,7 @@ impl KeyValueStoreDriver {
// As in the Go-based key/value store, simply encode the number of
// items as the "app hash"
let mut app_hash = BytesMut::with_capacity(MAX_VARINT_LENGTH);
encode_varint(self.store.len() as u64, &mut app_hash);
prost::encoding::encode_varint(self.store.len() as u64, &mut app_hash);
self.app_hash = app_hash.to_vec();
self.height += 1;
channel_send(&result_tx, (self.height, self.app_hash.clone()))
Expand Down
17 changes: 3 additions & 14 deletions abci/src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ where
let mut buf = BytesMut::new();
message.encode(&mut buf)?;
let buf = buf.freeze();
encode_varint(buf.len() as u64, &mut dst);
prost::encoding::encode_varint(buf.len() as u64, &mut dst);
dst.put(buf);
Ok(())
}
Expand All @@ -131,11 +131,11 @@ where
{
let src_len = src.len();
let mut tmp = src.clone().freeze();
let encoded_len = match decode_varint(&mut tmp) {
let encoded_len = match prost::encoding::decode_varint(&mut tmp) {
Ok(len) => len,
// We've potentially only received a partial length delimiter
Err(_) if src_len <= MAX_VARINT_LENGTH => return Ok(None),
Err(e) => return Err(e),
Err(e) => return Err(e.into()),
};
let remaining = tmp.remaining() as u64;
if remaining < encoded_len {
Expand All @@ -151,14 +151,3 @@ where
Ok(Some(M::decode(&mut result_bytes)?))
}
}

// encode_varint and decode_varint will be removed once
// https://github.com/tendermint/tendermint/issues/5783 lands in Tendermint.
pub fn encode_varint<B: BufMut>(val: u64, mut buf: &mut B) {
prost::encoding::encode_varint(val << 1, &mut buf);
}

pub fn decode_varint<B: Buf>(mut buf: &mut B) -> Result<u64> {
let len = prost::encoding::decode_varint(&mut buf)?;
Ok(len >> 1)
}
2 changes: 1 addition & 1 deletion abci/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! have them interact. In practice, the client interaction will be performed
//! by a full Tendermint node.
//!
//! ```rust
//! ```rust,ignore
//! use tendermint_abci::{KeyValueStoreApp, ServerBuilder, ClientBuilder};
//! use tendermint_proto::abci::{RequestEcho, RequestDeliverTx, RequestQuery};
//!
Expand Down
4 changes: 2 additions & 2 deletions light-client/src/light_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ impl LightClient {
/// should be trusted based on a previously verified light block.
/// - When doing _forward_ verification, the Scheduler component decides which height to try to
/// verify next, in case the current block pass verification but cannot be trusted yet.
/// - When doing _backward_ verification, the Hasher component is used to determine
/// whether the `last_block_id` hash of a block matches the hash of the block right below it.
/// - When doing _backward_ verification, the Hasher component is used to determine whether the
/// `last_block_id` hash of a block matches the hash of the block right below it.
///
/// ## Implements
/// - [LCV-DIST-SAFE.1]
Expand Down
1 change: 1 addition & 0 deletions p2p/src/secret_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ impl Handshake<AwaitingAuthSig> {
ed25519::PublicKey::from_bytes(bytes).ok()
}
proto::crypto::public_key::Sum::Secp256k1(_) => None,
proto::crypto::public_key::Sum::Sr25519(_) => None,
})
.ok_or(Error::CryptoError)?;

Expand Down
2 changes: 1 addition & 1 deletion proto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ all-features = true
[dependencies]
prost = "0.7"
prost-types = "0.7"
bytes = "1.0"
bytes = { version = "1.0", features = ["serde"] }
anomaly = "0.2"
thiserror = "1.0"
serde = { version = "1.0", features = ["derive"] }
Expand Down
53 changes: 53 additions & 0 deletions proto/src/chrono.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use std::convert::TryInto;

use chrono::{DateTime, Duration, TimeZone, Utc};

use crate::google::protobuf as pb;

impl From<DateTime<Utc>> for pb::Timestamp {
fn from(dt: DateTime<Utc>) -> 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<pb::Timestamp> for DateTime<Utc> {
fn from(ts: pb::Timestamp) -> DateTime<Utc> {
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<Duration> 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<pb::Duration> 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)
}
}
1 change: 1 addition & 0 deletions proto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod google {
mod tendermint;
pub use tendermint::*;

mod chrono;
mod error;
use anomaly::BoxError;
use bytes::{Buf, BufMut};
Expand Down
Loading