Skip to content
This repository has been archived by the owner on Jun 3, 2020. It is now read-only.

tendermint-rs: Initial "rpc" feature #235

Merged
merged 10 commits into from
Apr 21, 2019
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ jobs:
rustc --version
cargo --version
cargo test --all --all-features -- --test-threads 1
cd tendermint-rs && cargo test --release --all-features
- run:
name: audit
command: |
Expand Down
25 changes: 14 additions & 11 deletions src/chain/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ use std::{
io::{self, prelude::*},
path::{Path, PathBuf},
};
use tendermint::chain::ConsensusState;
use tendermint::consensus;

/// State tracking for double signing prevention
pub struct State {
consensus_state: ConsensusState,
consensus_state: consensus::State,
state_file_path: PathBuf,
}

Expand All @@ -30,7 +30,7 @@ impl State {
P: AsRef<Path>,
{
let mut lst = State {
consensus_state: ConsensusState::default(),
consensus_state: consensus::State::default(),
state_file_path: path.as_ref().to_owned(),
};

Expand Down Expand Up @@ -58,8 +58,11 @@ impl State {
}

/// Check and update the chain's height, round, and step
pub fn update_consensus_state(&mut self, new_state: ConsensusState) -> Result<(), StateError> {
// TODO(tarcieri): impl `PartialOrd` on `ConsensusState` to simplify this logic?
pub fn update_consensus_state(
&mut self,
new_state: consensus::State,
) -> Result<(), StateError> {
// TODO(tarcieri): rewrite this using `Ord` impl on `consensus::State`
if new_state.height < self.consensus_state.height {
fail!(
StateErrorKind::HeightRegression,
Expand Down Expand Up @@ -98,7 +101,7 @@ impl State {
new_state.height,
new_state.round,
new_state.step,
self.consensus_state.block_id.unwrap(),
self.consensus_state.block_id.as_ref().unwrap(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer Copy

new_state.block_id.unwrap()
)
}
Expand Down Expand Up @@ -127,7 +130,7 @@ impl State {
let delta = hook_height - last_height;

if delta < hook::BLOCK_HEIGHT_SANITY_LIMIT {
let mut new_state = ConsensusState::default();
let mut new_state = consensus::State::default();
new_state.height = output.latest_block_height;
self.consensus_state = new_state;

Expand Down Expand Up @@ -178,7 +181,7 @@ mod tests {
#[test]
fn hrs_test() {
let mut last_sign_state = State {
consensus_state: ConsensusState {
consensus_state: consensus::State {
height: 1i64.into(),
round: 1,
step: 0,
Expand All @@ -189,7 +192,7 @@ mod tests {

assert_eq!(
last_sign_state
.update_consensus_state(ConsensusState {
.update_consensus_state(consensus::State {
height: 2i64.into(),
round: 0,
step: 0,
Expand All @@ -203,7 +206,7 @@ mod tests {
#[test]
fn hrs_test_double_sign() {
let mut last_sign_state = State {
consensus_state: ConsensusState {
consensus_state: consensus::State {
height: 1i64.into(),
round: 1,
step: 0,
Expand All @@ -212,7 +215,7 @@ mod tests {
state_file_path: EXAMPLE_PATH.into(),
};
let double_sign_block = block::Id::from_str(EXAMPLE_DOUBLE_SIGN_BLOCK_ID).unwrap();
let err = last_sign_state.update_consensus_state(ConsensusState {
let err = last_sign_state.update_consensus_state(consensus::State {
height: 1i64.into(),
round: 1,
step: 1,
Expand Down
30 changes: 14 additions & 16 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@ use crate::{
};
use signatory::{ed25519, Decode, Encode, PublicKeyed};
use signatory_dalek::Ed25519Signer;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::{
panic,
path::Path,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::{self, JoinHandle},
time::Duration,
};
use tendermint::{chain, node, secret_connection, Address};
use tendermint::{chain, net, node, secret_connection};

/// How long to wait after a crash before respawning (in seconds)
pub const RESPAWN_DELAY: u64 = 1;
Expand Down Expand Up @@ -68,21 +70,15 @@ fn client_loop(config: ValidatorConfig, should_term: &Arc<AtomicBool>) {
return;
}

let session_result = match &addr {
Address::Tcp {
let session_result = match addr {
net::Address::Tcp {
peer_id,
host,
ref host,
port,
} => match &secret_key {
Some(path) => tcp_session(
chain_id,
max_height,
*peer_id,
host,
*port,
path,
should_term,
),
Some(path) => {
tcp_session(chain_id, max_height, peer_id, host, port, path, should_term)
}
None => {
error!(
"config error: missing field `secret_key` for validator {}",
Expand All @@ -91,7 +87,9 @@ fn client_loop(config: ValidatorConfig, should_term: &Arc<AtomicBool>) {
return;
}
},
Address::Unix { path } => unix_session(chain_id, max_height, path, should_term),
net::Address::Unix { ref path } => {
unix_session(chain_id, max_height, path, should_term)
}
};

if let Err(e) = session_result {
Expand Down
4 changes: 2 additions & 2 deletions src/config/validator.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::path::PathBuf;
use tendermint::{chain, Address};
use tendermint::{chain, net};

/// Validator configuration
#[derive(Clone, Deserialize, Debug)]
pub struct ValidatorConfig {
/// Address of the validator (`tcp://` or `unix://`)
pub addr: Address,
pub addr: net::Address,

/// Chain ID of the Tendermint network this validator is part of
pub chain_id: chain::Id,
Expand Down
7 changes: 5 additions & 2 deletions tendermint-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ edition = "2018"
description = """
Tendermint is a high-performance blockchain consensus engine that powers
Byzantine fault tolerant applications written in any programming language.
This crate provides types for representing information about Tendermint
blockchain networks, including chain IDs, block IDs, and block heights.
This crate provides core types for representing information about Tendermint
blockchain networks, including chain information types, secret connections,
and remote procedure calls (JSONRPC).
"""

authors = [
Expand All @@ -38,6 +39,7 @@ prost-amino-derive = { version = "0.4.0", optional = true }
rand_os = { version = "0.1", optional = true }
ring = { version = "0.14", optional = true }
serde = { version = "1", optional = true, features = ["derive"] }
serde_json = { version = "1", optional = true }
signatory = { version = "0.11.2", features = ["ed25519", "ecdsa"] }
signatory-dalek = { version = "0.11", optional = true }
sha2 = { version = "0.8", default-features = false }
Expand All @@ -53,6 +55,7 @@ serde_json = "1"
[features]
default = ["serde", "tai64"]
amino-types = ["prost-amino", "prost-amino-derive"]
rpc = ["serde", "serde_json"]
secret-connection = [
"amino-types",
"byteorder",
Expand Down
10 changes: 8 additions & 2 deletions tendermint-rs/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use sha2::{Digest, Sha256};
use signatory::ecdsa::curve::secp256k1;
use std::{
fmt::{self, Display},
fmt::{self, Debug, Display},
str::FromStr,
};
use subtle::{self, ConstantTimeEq};
Expand All @@ -16,7 +16,7 @@ use subtle_encoding::hex;
pub const ID_LENGTH: usize = 20;

/// Account IDs
#[derive(Copy, Clone, Debug, Hash)]
#[derive(Copy, Clone, Hash)]
pub struct Id([u8; ID_LENGTH]);

impl Id {
Expand Down Expand Up @@ -53,6 +53,12 @@ impl Display for Id {
}
}

impl Debug for Id {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "account::Id({})", self)
}
}

impl From<secp256k1::PublicKey> for Id {
fn from(pk: secp256k1::PublicKey) -> Id {
let digest = Sha256::digest(pk.as_bytes());
Expand Down
18 changes: 0 additions & 18 deletions tendermint-rs/src/algorithm.rs

This file was deleted.

34 changes: 29 additions & 5 deletions tendermint-rs/src/amino_types/block_id.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use super::validate::{ConsensusMessage, ValidationError, ValidationErrorKind::*};
use crate::{
algorithm::HashAlgorithm,
block,
error::Error,
hash,
hash::{Hash, SHA256_HASH_SIZE},
};

Expand All @@ -16,8 +16,12 @@ pub struct BlockId {

impl block::ParseId for BlockId {
fn parse_block_id(&self) -> Result<block::Id, Error> {
let hash = Hash::new(HashAlgorithm::Sha256, &self.hash)?;
Ok(block::Id::new(hash))
let hash = Hash::new(hash::Algorithm::Sha256, &self.hash)?;
let parts_header = self
.parts_header
.as_ref()
.and_then(PartsSetHeader::parse_parts_header);
Ok(block::Id::new(hash, parts_header))
}
}

Expand All @@ -43,8 +47,12 @@ pub struct CanonicalBlockId {

impl block::ParseId for CanonicalBlockId {
fn parse_block_id(&self) -> Result<block::Id, Error> {
let hash = Hash::new(HashAlgorithm::Sha256, &self.hash)?;
Ok(block::Id::new(hash))
let hash = Hash::new(hash::Algorithm::Sha256, &self.hash)?;
let parts_header = self
.parts_header
.as_ref()
.and_then(CanonicalPartSetHeader::parse_parts_header);
Ok(block::Id::new(hash, parts_header))
}
}

Expand All @@ -56,6 +64,14 @@ pub struct PartsSetHeader {
pub hash: Vec<u8>,
}

impl PartsSetHeader {
fn parse_parts_header(&self) -> Option<block::parts::Header> {
Hash::new(hash::Algorithm::Sha256, &self.hash)
.map(|hash| block::parts::Header::new(self.total as u64, hash))
.ok()
}
}

impl ConsensusMessage for PartsSetHeader {
fn validate_basic(&self) -> Result<(), ValidationError> {
if self.total < 0 {
Expand All @@ -76,3 +92,11 @@ pub struct CanonicalPartSetHeader {
#[prost(int64, tag = "2")]
pub total: i64,
}

impl CanonicalPartSetHeader {
fn parse_parts_header(&self) -> Option<block::parts::Header> {
Hash::new(hash::Algorithm::Sha256, &self.hash)
.map(|hash| block::parts::Header::new(self.total as u64, hash))
.ok()
}
}
2 changes: 1 addition & 1 deletion tendermint-rs/src/amino_types/ed25519.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::public_keys::PublicKey;
use crate::public_key::PublicKey;
use signatory::ed25519::PUBLIC_KEY_SIZE;

// Note:On the golang side this is generic in the sense that it could everything that implements
Expand Down
6 changes: 3 additions & 3 deletions tendermint-rs/src/amino_types/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use super::{
};
use crate::{
block::{self, ParseId},
chain::{self, ConsensusState},
chain, consensus,
error::Error,
};
use bytes::BufMut;
Expand Down Expand Up @@ -133,9 +133,9 @@ impl SignableMsg for SignProposalRequest {
None => Err(MissingConsensusMessage.into()),
}
}
fn consensus_state(&self) -> Option<ConsensusState> {
fn consensus_state(&self) -> Option<consensus::State> {
match self.proposal {
Some(ref p) => Some(ConsensusState {
Some(ref p) => Some(consensus::State {
height: match block::Height::try_from_i64(p.height) {
Ok(h) => h,
Err(_err) => return None, // TODO(tarcieri): return an error?
Expand Down
4 changes: 2 additions & 2 deletions tendermint-rs/src/amino_types/signature.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::validate::ValidationError;
use crate::chain::{self, ConsensusState};
use crate::{chain, consensus};
use bytes::BufMut;
use prost::{DecodeError, EncodeError};
use signatory::ed25519;
Expand All @@ -16,7 +16,7 @@ pub trait SignableMsg {
/// Set the Ed25519 signature on the underlying message
fn set_signature(&mut self, sig: &ed25519::Signature);
fn validate(&self) -> Result<(), ValidationError>;
fn consensus_state(&self) -> Option<ConsensusState>;
fn consensus_state(&self) -> Option<consensus::State>;
fn height(&self) -> Option<i64>;
}

Expand Down
10 changes: 5 additions & 5 deletions tendermint-rs/src/amino_types/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
error::Error,
timestamp::{ParseTimestamp, Timestamp},
time::{ParseTimestamp, Time},
};
use chrono::{TimeZone, Utc};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
Expand All @@ -19,15 +19,15 @@ pub struct TimeMsg {
}

impl ParseTimestamp for TimeMsg {
fn parse_timestamp(&self) -> Result<Timestamp, Error> {
fn parse_timestamp(&self) -> Result<Time, Error> {
Ok(Utc.timestamp(self.seconds, self.nanos as u32).into())
}
}

impl From<Timestamp> for TimeMsg {
fn from(ts: Timestamp) -> TimeMsg {
impl From<Time> for TimeMsg {
fn from(ts: Time) -> TimeMsg {
// TODO: non-panicking method for getting this?
let duration = ts.duration_since(Timestamp::unix_epoch()).unwrap();
let duration = ts.duration_since(Time::unix_epoch()).unwrap();
let seconds = duration.as_secs() as i64;
let nanos = duration.subsec_nanos() as i32;

Expand Down
Loading