1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#![allow(missing_docs)]
use bytes::Bytes;
use once_cell::sync::Lazy;
use prost_amino::{
encoding::{decode_varint, encoded_len_varint},
Message,
};
use sha2::{Digest, Sha256};
use std::io::{self, Error, ErrorKind, Read};
use tendermint::amino_types::*;
pub const MAX_MSG_LEN: usize = 1024;
#[derive(Debug)]
pub enum Request {
SignProposal(SignProposalRequest),
SignVote(SignVoteRequest),
ShowPublicKey(PubKeyRequest),
ReplyPing(PingRequest),
}
#[derive(Debug)]
pub enum Response {
SignedVote(SignedVoteResponse),
SignedProposal(SignedProposalResponse),
Ping(PingResponse),
PublicKey(PubKeyResponse),
}
pub trait TendermintRequest: SignableMsg {
fn build_response(self, error: Option<RemoteError>) -> Response;
}
fn compute_prefix(name: &str) -> Vec<u8> {
let mut sh = Sha256::default();
sh.update(name.as_bytes());
let output = sh.finalize();
output
.iter()
.filter(|&x| *x != 0x00)
.skip(3)
.filter(|&x| *x != 0x00)
.cloned()
.take(4)
.collect()
}
static VOTE_PREFIX: Lazy<Vec<u8>> = Lazy::new(|| compute_prefix(VOTE_AMINO_NAME));
static PROPOSAL_PREFIX: Lazy<Vec<u8>> = Lazy::new(|| compute_prefix(PROPOSAL_AMINO_NAME));
static PUBKEY_PREFIX: Lazy<Vec<u8>> = Lazy::new(|| compute_prefix(PUBKEY_AMINO_NAME));
static PING_PREFIX: Lazy<Vec<u8>> = Lazy::new(|| compute_prefix(PING_AMINO_NAME));
impl Request {
pub fn read<R: Read>(r: &mut R) -> io::Result<Self> {
let mut buf = vec![0; MAX_MSG_LEN];
let bytes_read = r.read(&mut buf)?;
if bytes_read < 4 {
return Err(Error::new(
ErrorKind::InvalidData,
"Did not read enough bytes to continue.",
));
}
let mut buf_amino: Bytes = Bytes::from(buf.clone());
let len = decode_varint(&mut buf_amino).unwrap();
if len > MAX_MSG_LEN as u64 {
return Err(Error::new(ErrorKind::InvalidData, "RPC message too large."));
}
let amino_pre = buf_amino.slice(0..4);
let buf: Bytes = Bytes::from(buf);
let total_len = encoded_len_varint(len).checked_add(len as usize).unwrap();
let rem = buf.as_ref()[..total_len].to_vec();
match amino_pre {
ref vt if *vt == *VOTE_PREFIX => {
Ok(Request::SignVote(SignVoteRequest::decode(rem.as_ref())?))
}
ref pr if *pr == *PROPOSAL_PREFIX => Ok(Request::SignProposal(
SignProposalRequest::decode(rem.as_ref())?,
)),
ref pubk if *pubk == *PUBKEY_PREFIX => {
Ok(Request::ShowPublicKey(PubKeyRequest::decode(rem.as_ref())?))
}
ref ping if *ping == *PING_PREFIX => {
Ok(Request::ReplyPing(PingRequest::decode(rem.as_ref())?))
}
_ => Err(Error::new(
ErrorKind::InvalidData,
"Received unknown RPC message.",
)),
}
}
}
impl TendermintRequest for SignVoteRequest {
fn build_response(self, error: Option<RemoteError>) -> Response {
let response = if let Some(e) = error {
SignedVoteResponse {
vote: None,
err: Some(e),
}
} else {
SignedVoteResponse {
vote: self.vote,
err: None,
}
};
Response::SignedVote(response)
}
}
impl TendermintRequest for SignProposalRequest {
fn build_response(self, error: Option<RemoteError>) -> Response {
let response = if let Some(e) = error {
SignedProposalResponse {
proposal: None,
err: Some(e),
}
} else {
SignedProposalResponse {
proposal: self.proposal,
err: None,
}
};
Response::SignedProposal(response)
}
}