Skip to content

Commit

Permalink
Refactor RPC Request type (#821)
Browse files Browse the repository at this point in the history
Makes the inner types the `tendermint` domain types, rather than the
Protobuf types.

This should make it easier to support multiple Protobuf versions.
  • Loading branch information
tony-iqlusion authored Dec 14, 2023
1 parent 4e94ddf commit 9a42eb1
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 51 deletions.
3 changes: 2 additions & 1 deletion src/commands/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
use abscissa_core::{Command, Runnable};
use clap::{Parser, Subcommand};
use std::{path::PathBuf, process};
use tendermint::Vote;
use tendermint_proto as proto;

/// `ledger` subcommand
Expand Down Expand Up @@ -61,7 +62,7 @@ impl Runnable for InitCommand {
..Default::default()
};
println!("{vote:?}");
let sign_vote_req = SignableMsg::try_from(vote).unwrap();
let sign_vote_req = SignableMsg::from(Vote::try_from(vote).unwrap());
let to_sign = sign_vote_req
.signable_bytes(config.validator[0].chain_id.clone())
.unwrap();
Expand Down
22 changes: 19 additions & 3 deletions src/privval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,18 @@ impl SignableMsg {
}
}

impl From<Proposal> for SignableMsg {
fn from(proposal: Proposal) -> Self {
Self::Proposal(proposal)
}
}

impl From<Vote> for SignableMsg {
fn from(vote: Vote) -> Self {
Self::Vote(vote)
}
}

impl TryFrom<proto::types::Proposal> for SignableMsg {
type Error = Error;

Expand Down Expand Up @@ -205,7 +217,7 @@ impl TryFrom<SignedMsgCode> for SignedMsgType {
#[cfg(test)]
mod tests {
use super::{chain, proto, SignableMsg, SignedMsgType};
use tendermint::Time;
use tendermint::{Proposal, Time, Vote};

fn example_chain_id() -> chain::Id {
chain::Id::try_from("test_chain_id").unwrap()
Expand All @@ -220,7 +232,7 @@ mod tests {
}
}

fn example_proposal() -> proto::types::Proposal {
fn example_proposal() -> Proposal {
proto::types::Proposal {
r#type: SignedMsgType::Proposal.into(),
height: 12345,
Expand All @@ -230,9 +242,11 @@ mod tests {
block_id: None,
signature: vec![],
}
.try_into()
.unwrap()
}

fn example_vote() -> proto::types::Vote {
fn example_vote() -> Vote {
proto::types::Vote {
r#type: 0x01,
height: 500001,
Expand All @@ -254,6 +268,8 @@ mod tests {
extension: vec![],
extension_signature: vec![],
}
.try_into()
.unwrap()
}

#[test]
Expand Down
80 changes: 41 additions & 39 deletions src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use crate::{keyring::Signature, privval::SignableMsg};
use prost::Message as _;
use std::io::Read;
use tendermint::chain;
use tendermint::{chain, Proposal, Vote};
use tendermint_proto as proto;

// TODO(tarcieri): use `tendermint_p2p::secret_connection::DATA_MAX_SIZE`
Expand All @@ -22,66 +22,68 @@ use crate::{
#[derive(Debug)]
pub enum Request {
/// Sign the given message
SignProposal(proto::privval::SignProposalRequest),
SignVote(proto::privval::SignVoteRequest),
ShowPublicKey(proto::privval::PubKeyRequest),
ReplyPing(proto::privval::PingRequest),
SignProposal(Proposal),
SignVote(Vote),
ShowPublicKey,
PingRequest,
}

impl Request {
/// Read a request from the given readable.
pub fn read(conn: &mut impl Read) -> Result<Self, Error> {
let msg = read_msg(conn)?;
pub fn read(conn: &mut impl Read, expected_chain_id: &chain::Id) -> Result<Self, Error> {
let msg_bytes = read_msg(conn)?;

// Parse Protobuf-encoded request message
let msg = proto::privval::Message::decode_length_delimited(msg.as_ref())
let msg = proto::privval::Message::decode_length_delimited(msg_bytes.as_ref())
.map_err(|e| format_err!(ErrorKind::ProtocolError, "malformed message packet: {}", e))?
.sum;

match msg {
Some(proto::privval::message::Sum::SignVoteRequest(req)) => Ok(Request::SignVote(req)),
Some(proto::privval::message::Sum::SignProposalRequest(req)) => {
Ok(Request::SignProposal(req))
}
let (req, chain_id) = match msg {
Some(proto::privval::message::Sum::SignVoteRequest(
proto::privval::SignVoteRequest {
vote: Some(vote),
chain_id,
},
)) => (Request::SignVote(vote.try_into()?), chain_id),
Some(proto::privval::message::Sum::SignProposalRequest(
proto::privval::SignProposalRequest {
proposal: Some(proposal),
chain_id,
},
)) => (Request::SignProposal(proposal.try_into()?), chain_id),
Some(proto::privval::message::Sum::PubKeyRequest(req)) => {
Ok(Request::ShowPublicKey(req))
(Request::ShowPublicKey, req.chain_id)
}
Some(proto::privval::message::Sum::PingRequest(_)) => {
return Ok(Request::PingRequest);
}
Some(proto::privval::message::Sum::PingRequest(req)) => Ok(Request::ReplyPing(req)),
_ => fail!(ErrorKind::ProtocolError, "invalid RPC message: {:?}", msg),
}
};

ensure!(
expected_chain_id == &chain::Id::try_from(chain_id.as_str())?,
ErrorKind::ChainIdError,
"got unexpected chain ID: {} (expecting: {})",
&chain_id,
expected_chain_id
);

Ok(req)
}

/// Convert this request into a [`SignableMsg`].
///
/// The expected `chain::Id` is used to validate the request.
pub fn into_signable_msg(self, expected_chain_id: &chain::Id) -> Result<SignableMsg, Error> {
let (signable_msg, chain_id) = match self {
Self::SignProposal(proto::privval::SignProposalRequest {
proposal: Some(proposal),
chain_id,
}) => (SignableMsg::try_from(proposal)?, chain_id),
Self::SignVote(proto::privval::SignVoteRequest {
vote: Some(vote),
chain_id,
}) => (SignableMsg::try_from(vote)?, chain_id),
pub fn into_signable_msg(self) -> Result<SignableMsg, Error> {
match self {
Self::SignProposal(proposal) => Ok(proposal.into()),
Self::SignVote(vote) => Ok(vote.into()),
_ => fail!(
ErrorKind::InvalidMessageError,
"expected a signable message type: {:?}",
self
),
};

let chain_id = chain::Id::try_from(chain_id)?;

ensure!(
expected_chain_id == &chain_id,
ErrorKind::ChainIdError,
"got unexpected chain ID: {} (expecting: {})",
&chain_id,
expected_chain_id
);

Ok(signable_msg)
}
}
}

Expand Down
13 changes: 5 additions & 8 deletions src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,19 @@ impl Session {

/// Handle an incoming request from the validator
fn handle_request(&mut self) -> Result<bool, Error> {
let request = Request::read(&mut self.connection)?;
let request = Request::read(&mut self.connection, &self.config.chain_id)?;
debug!(
"[{}@{}] received request: {:?}",
&self.config.chain_id, &self.config.addr, &request
);

let response = match request {
Request::SignProposal(_) | Request::SignVote(_) => {
self.sign(request.into_signable_msg(&self.config.chain_id)?)?
self.sign(request.into_signable_msg()?)?
}
// non-signable requests:
Request::ReplyPing(_) => Response::Ping(proto::privval::PingResponse {}),
Request::ShowPublicKey(ref req) => self.get_public_key(req)?,
Request::PingRequest => Response::Ping(proto::privval::PingResponse {}),
Request::ShowPublicKey => self.get_public_key()?,
};

debug!(
Expand Down Expand Up @@ -203,10 +203,7 @@ impl Session {
}

/// Get the public key for (the only) public key in the keyring
fn get_public_key(
&mut self,
_request: &proto::privval::PubKeyRequest,
) -> Result<Response, Error> {
fn get_public_key(&mut self) -> Result<Response, Error> {
let registry = chain::REGISTRY.get();

let chain = registry
Expand Down

0 comments on commit 9a42eb1

Please sign in to comment.