#![allow(missing_docs)]
use crate::privval::SignableMsg;
use prost::Message as _;
use std::io::Read;
use tendermint::{chain, Proposal, Vote};
use tendermint_proto as proto;
const DATA_MAX_SIZE: usize = 262144;
use crate::{
error::{Error, ErrorKind},
prelude::*,
};
#[derive(Debug)]
pub enum Request {
SignProposal(Proposal),
SignVote(Vote),
ShowPublicKey,
PingRequest,
}
impl Request {
pub fn read(conn: &mut impl Read, expected_chain_id: &chain::Id) -> Result<Self, Error> {
let msg_bytes = read_msg(conn)?;
let msg = proto::privval::Message::decode_length_delimited(msg_bytes.as_ref())
.map_err(|e| format_err!(ErrorKind::ProtocolError, "malformed message packet: {}", e))?
.sum;
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)) => {
(Request::ShowPublicKey, req.chain_id)
}
Some(proto::privval::message::Sum::PingRequest(_)) => {
return Ok(Request::PingRequest);
}
_ => 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)
}
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
),
}
}
}
#[derive(Debug)]
pub enum Response {
SignedVote(proto::privval::SignedVoteResponse),
SignedProposal(proto::privval::SignedProposalResponse),
Ping(proto::privval::PingResponse),
PublicKey(proto::privval::PubKeyResponse),
}
impl Response {
pub fn encode(self) -> Result<Vec<u8>, Error> {
let mut buf = Vec::new();
let msg = match self {
Response::SignedVote(resp) => proto::privval::message::Sum::SignedVoteResponse(resp),
Response::SignedProposal(resp) => {
proto::privval::message::Sum::SignedProposalResponse(resp)
}
Response::Ping(resp) => proto::privval::message::Sum::PingResponse(resp),
Response::PublicKey(resp) => proto::privval::message::Sum::PubKeyResponse(resp),
};
proto::privval::Message { sum: Some(msg) }.encode_length_delimited(&mut buf)?;
Ok(buf)
}
pub fn error(msg: SignableMsg, error: proto::privval::RemoteSignerError) -> Response {
match msg {
SignableMsg::Proposal(_) => {
Response::SignedProposal(proto::privval::SignedProposalResponse {
proposal: None,
error: Some(error),
})
}
SignableMsg::Vote(_) => Response::SignedVote(proto::privval::SignedVoteResponse {
vote: None,
error: Some(error),
}),
}
}
}
impl From<SignableMsg> for Response {
fn from(msg: SignableMsg) -> Response {
match msg {
SignableMsg::Proposal(proposal) => {
Response::SignedProposal(proto::privval::SignedProposalResponse {
proposal: Some(proposal.into()),
error: None,
})
}
SignableMsg::Vote(vote) => Response::SignedVote(proto::privval::SignedVoteResponse {
vote: Some(vote.into()),
error: None,
}),
}
}
}
fn read_msg(conn: &mut impl Read) -> Result<Vec<u8>, Error> {
let mut buf = vec![0; DATA_MAX_SIZE];
let buf_read = conn.read(&mut buf)?;
buf.truncate(buf_read);
Ok(buf)
}