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

Commit

Permalink
Merge pull request #238 from tendermint/zaki/max_height
Browse files Browse the repository at this point in the history
Zaki/max height
  • Loading branch information
tarcieri authored Apr 21, 2019
2 parents 9353fa2 + 83f0dad commit 5fe1117
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 7 deletions.
27 changes: 22 additions & 5 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ fn client_loop(config: ValidatorConfig, should_term: &Arc<AtomicBool>) {
chain_id,
reconnect,
secret_key,
max_height,
} = config;

loop {
Expand All @@ -73,7 +74,15 @@ fn client_loop(config: ValidatorConfig, should_term: &Arc<AtomicBool>) {
host,
port,
} => match &secret_key {
Some(path) => tcp_session(chain_id, *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 @@ -82,7 +91,7 @@ fn client_loop(config: ValidatorConfig, should_term: &Arc<AtomicBool>) {
return;
}
},
Address::Unix { path } => unix_session(chain_id, path, should_term),
Address::Unix { path } => unix_session(chain_id, max_height, path, should_term),
};

if let Err(e) = session_result {
Expand All @@ -107,6 +116,7 @@ fn client_loop(config: ValidatorConfig, should_term: &Arc<AtomicBool>) {
/// Create a TCP connection to a validator (encrypted with SecretConnection)
fn tcp_session(
chain_id: chain::Id,
max_height: Option<tendermint::block::Height>,
validator_peer_id: Option<node::Id>,
host: &str,
port: u16,
Expand All @@ -121,8 +131,14 @@ fn tcp_session(
info!("KMS node ID: {}", &node_public_key);

panic::catch_unwind(move || {
let mut session =
Session::connect_tcp(chain_id, validator_peer_id, host, port, &secret_key)?;
let mut session = Session::connect_tcp(
chain_id,
max_height,
validator_peer_id,
host,
port,
&secret_key,
)?;

info!(
"[{}@tcp://{}:{}] connected to validator successfully",
Expand All @@ -137,11 +153,12 @@ fn tcp_session(
/// Create a validator session over a Unix domain socket
fn unix_session(
chain_id: chain::Id,
max_height: Option<tendermint::block::Height>,
socket_path: &Path,
should_term: &Arc<AtomicBool>,
) -> Result<(), KmsError> {
panic::catch_unwind(move || {
let mut session = Session::connect_unix(chain_id, socket_path)?;
let mut session = Session::connect_unix(chain_id, max_height, socket_path)?;

info!(
"[{}@unix://{}] connected to validator successfully",
Expand Down
3 changes: 3 additions & 0 deletions src/config/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ pub struct ValidatorConfig {

/// Path to our Ed25519 identity key (if applicable)
pub secret_key: Option<PathBuf>,

/// Height at which to stop signing
pub max_height: Option<tendermint::block::Height>,
}

/// Default value for the `ValidatorConfig` reconnect field
Expand Down
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ pub enum KmsErrorKind {
/// Signature invalid
#[fail(display = "attempted double sign")]
DoubleSign,

///Request a Signature above max height
#[fail(display = "requested signature above stop height")]
ExceedMaxHeight,
}

impl Display for KmsError {
Expand Down
30 changes: 28 additions & 2 deletions src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
use crate::{
chain,
error::{KmsError, KmsErrorKind::VerificationError},
error::{
KmsError,
KmsErrorKind::{ExceedMaxHeight, VerificationError},
},
prost::Message,
rpc::{Request, Response, TendermintRequest},
unix_connection::UnixConnection,
Expand Down Expand Up @@ -33,6 +36,9 @@ pub struct Session<Connection> {
/// Chain ID for this session
chain_id: chain::Id,

// Do not sign blocks greates than this height
max_height: Option<tendermint::block::Height>,

/// TCP connection to a validator node
connection: Connection,
}
Expand All @@ -41,6 +47,7 @@ impl Session<SecretConnection<TcpStream>> {
/// Create a new session with the validator at the given address/port
pub fn connect_tcp(
chain_id: chain::Id,
max_height: Option<tendermint::block::Height>,
validator_peer_id: Option<node::Id>,
host: &str,
port: u16,
Expand Down Expand Up @@ -76,13 +83,18 @@ impl Session<SecretConnection<TcpStream>> {

Ok(Self {
chain_id,
max_height,
connection,
})
}
}

impl Session<UnixConnection<UnixStream>> {
pub fn connect_unix(chain_id: chain::Id, socket_path: &Path) -> Result<Self, KmsError> {
pub fn connect_unix(
chain_id: chain::Id,
max_height: Option<tendermint::block::Height>,
socket_path: &Path,
) -> Result<Self, KmsError> {
debug!(
"{}: Connecting to socket at {}...",
chain_id,
Expand All @@ -94,6 +106,7 @@ impl Session<UnixConnection<UnixStream>> {

Ok(Self {
chain_id,
max_height,
connection,
})
}
Expand Down Expand Up @@ -152,6 +165,19 @@ where
chain_state.update_consensus_state(request_state.clone())?;
}

if let Some(max_height) = self.max_height {
if let Some(height) = request.height() {
if height > max_height.value() as i64 {
fail!(
ExceedMaxHeight,
"attempted to sign at height {} which is greater than {}",
height,
max_height,
);
}
}
}

let mut to_sign = vec![];
request.sign_bytes(self.chain_id, &mut to_sign)?;

Expand Down
4 changes: 4 additions & 0 deletions tendermint-rs/src/amino_types/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ impl SignableMsg for SignProposalRequest {
None => None,
}
}

fn height(&self) -> Option<i64> {
self.proposal.as_ref().map(|proposal| proposal.height)
}
}

impl ConsensusMessage for Proposal {
Expand Down
1 change: 1 addition & 0 deletions tendermint-rs/src/amino_types/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub trait SignableMsg {
fn set_signature(&mut self, sig: &ed25519::Signature);
fn validate(&self) -> Result<(), ValidationError>;
fn consensus_state(&self) -> Option<ConsensusState>;
fn height(&self) -> Option<i64>;
}

/// Signed message types. This follows:
Expand Down
3 changes: 3 additions & 0 deletions tendermint-rs/src/amino_types/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ impl SignableMsg for SignVoteRequest {
None => None,
}
}
fn height(&self) -> Option<i64> {
self.vote.as_ref().map(|vote| vote.height)
}
}

impl ConsensusMessage for Vote {
Expand Down
70 changes: 70 additions & 0 deletions tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ impl KmsProcess {
[[validator]]
addr = "tcp://{}@127.0.0.1:{}"
chain_id = "test_chain_id"
max_height = "500000"
reconnect = false
secret_key = "tests/support/secret_connection.key"
Expand Down Expand Up @@ -165,6 +166,8 @@ impl KmsProcess {
[[validator]]
addr = "unix://{}"
chain_id = "test_chain_id"
max_height = "500000"
[[providers.softsign]]
chain_ids = ["test_chain_id"]
Expand Down Expand Up @@ -415,6 +418,73 @@ fn test_handle_and_sign_vote() {
});
}

#[test]
#[should_panic]
fn test_exceed_max_height() {
let chain_id = "test_chain_id";
let (pub_key, _) = test_key();

let dt = "2018-02-11T07:09:22.765Z".parse::<DateTime<Utc>>().unwrap();
let t = TimeMsg {
seconds: dt.timestamp(),
nanos: dt.timestamp_subsec_nanos() as i32,
};

ProtocolTester::apply(|mut pt| {
let vote_msg = amino_types::vote::Vote {
vote_type: 0x01,
height: 500001,
round: 2,
timestamp: Some(t),
block_id: Some(BlockId {
hash: b"some hash00000000000000000000000".to_vec(),
parts_header: Some(PartsSetHeader {
total: 1000000,
hash: b"parts_hash0000000000000000000000".to_vec(),
}),
}),
validator_address: vec![
0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, 0xf4,
0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35,
],
validator_index: 56789,
signature: vec![],
};

let svr = amino_types::vote::SignVoteRequest {
vote: Some(vote_msg),
};
let mut buf = vec![];
svr.encode(&mut buf).unwrap();
pt.write_all(&buf).unwrap();

// receive response:
let mut resp_buf = vec![0u8; 1024];
pt.read(&mut resp_buf).unwrap();

let actual_len = extract_actual_len(&resp_buf).unwrap();
let mut resp = vec![0u8; actual_len as usize];
resp.copy_from_slice(&resp_buf[..actual_len as usize]);

let v_resp = vote::SignedVoteResponse::decode(&resp).expect("decoding vote failed");
let mut sign_bytes: Vec<u8> = vec![];
svr.sign_bytes(chain_id.into(), &mut sign_bytes).unwrap();

let vote_msg: amino_types::vote::Vote = v_resp
.vote
.expect("vote should be embedded int the response but none was found");

let sig: Vec<u8> = vote_msg.signature;
assert_ne!(sig.len(), 0);

let verifier = Ed25519Verifier::from(&pub_key);
let signature = ed25519::Signature::from_bytes(sig).unwrap();
let msg: &[u8] = sign_bytes.as_slice();

ed25519::verify(&verifier, msg, &signature).unwrap();
});
}

#[test]
fn test_handle_and_sign_get_publickey() {
ProtocolTester::apply(|mut pt| {
Expand Down
1 change: 1 addition & 0 deletions tmkms.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ addr = "tcp://[email protected]:2665
chain_id = "cosmoshub-1"
reconnect = true # true is the default
secret_key = "path/to/secret_connection.key"
# max_height = "500000"

# Provider configuration
[[providers.softsign]]
Expand Down

0 comments on commit 5fe1117

Please sign in to comment.