Initial vote signing service implementation (#1996)
* Initial vote signing service implementation - Does not use enclave for secure signing * fix clippy errors * added some tests * more tests * Address review comments + more tests
This commit is contained in:
parent
da44b0f0f6
commit
2112c87e13
|
@ -1912,6 +1912,7 @@ dependencies = [
|
||||||
"bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bs58 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"solana-jsonrpc-core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"solana-jsonrpc-core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"solana-jsonrpc-http-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"solana-jsonrpc-http-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"solana-jsonrpc-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"solana-jsonrpc-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -10,6 +10,7 @@ license = "Apache-2.0"
|
||||||
bs58 = "0.2.0"
|
bs58 = "0.2.0"
|
||||||
clap = "2.31"
|
clap = "2.31"
|
||||||
log = "0.4.2"
|
log = "0.4.2"
|
||||||
|
serde_json = "1.0.10"
|
||||||
solana-sdk = { path = "../sdk", version = "0.11.0" }
|
solana-sdk = { path = "../sdk", version = "0.11.0" }
|
||||||
solana-metrics = { path = "../metrics", version = "0.11.0" }
|
solana-metrics = { path = "../metrics", version = "0.11.0" }
|
||||||
solana-jsonrpc-core = "0.3.0"
|
solana-jsonrpc-core = "0.3.0"
|
||||||
|
|
|
@ -8,3 +8,6 @@ extern crate solana_jsonrpc_http_server as jsonrpc_http_server;
|
||||||
extern crate solana_sdk;
|
extern crate solana_sdk;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate solana_jsonrpc_macros as jsonrpc_macros;
|
extern crate solana_jsonrpc_macros as jsonrpc_macros;
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate serde_json;
|
||||||
|
|
|
@ -4,11 +4,12 @@ use bs58;
|
||||||
use jsonrpc_core::*;
|
use jsonrpc_core::*;
|
||||||
use jsonrpc_http_server::*;
|
use jsonrpc_http_server::*;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::Signature;
|
use solana_sdk::signature::{Keypair, KeypairUtil, Signature};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, RwLock};
|
||||||
use std::thread::{self, sleep, Builder, JoinHandle};
|
use std::thread::{self, sleep, Builder, JoinHandle};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -32,7 +33,6 @@ impl VoteSignerRpcService {
|
||||||
let server =
|
let server =
|
||||||
ServerBuilder::with_meta_extractor(io, move |_req: &hyper::Request<hyper::Body>| Meta {
|
ServerBuilder::with_meta_extractor(io, move |_req: &hyper::Request<hyper::Body>| Meta {
|
||||||
request_processor: request_processor.clone(),
|
request_processor: request_processor.clone(),
|
||||||
rpc_addr,
|
|
||||||
}).threads(4)
|
}).threads(4)
|
||||||
.cors(DomainsValidation::AllowOnly(vec![
|
.cors(DomainsValidation::AllowOnly(vec![
|
||||||
AccessControlAllowOrigin::Any,
|
AccessControlAllowOrigin::Any,
|
||||||
|
@ -69,7 +69,6 @@ impl VoteSignerRpcService {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Meta {
|
pub struct Meta {
|
||||||
pub request_processor: VoteSignRequestProcessor,
|
pub request_processor: VoteSignRequestProcessor,
|
||||||
pub rpc_addr: SocketAddr,
|
|
||||||
}
|
}
|
||||||
impl Metadata for Meta {}
|
impl Metadata for Meta {}
|
||||||
|
|
||||||
|
@ -78,13 +77,13 @@ build_rpc_trait! {
|
||||||
type Metadata;
|
type Metadata;
|
||||||
|
|
||||||
#[rpc(meta, name = "registerNode")]
|
#[rpc(meta, name = "registerNode")]
|
||||||
fn register(&self, Self::Metadata, String) -> Result<Pubkey>;
|
fn register(&self, Self::Metadata, String, Signature, Vec<u8>) -> Result<Pubkey>;
|
||||||
|
|
||||||
#[rpc(meta, name = "signVote")]
|
#[rpc(meta, name = "signVote")]
|
||||||
fn sign(&self, Self::Metadata, String) -> Result<Signature>;
|
fn sign(&self, Self::Metadata, String, Signature, Vec<u8>) -> Result<Signature>;
|
||||||
|
|
||||||
#[rpc(meta, name = "deregisterNode")]
|
#[rpc(meta, name = "deregisterNode")]
|
||||||
fn deregister(&self, Self::Metadata, String) -> Result<()>;
|
fn deregister(&self, Self::Metadata, String, Signature, Vec<u8>) -> Result<()>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,49 +91,102 @@ pub struct VoteSignerRpcImpl;
|
||||||
impl VoteSignerRpc for VoteSignerRpcImpl {
|
impl VoteSignerRpc for VoteSignerRpcImpl {
|
||||||
type Metadata = Meta;
|
type Metadata = Meta;
|
||||||
|
|
||||||
fn register(&self, meta: Self::Metadata, id: String) -> Result<Pubkey> {
|
fn register(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
id: String,
|
||||||
|
sig: Signature,
|
||||||
|
signed_msg: Vec<u8>,
|
||||||
|
) -> Result<Pubkey> {
|
||||||
info!("register rpc request received: {:?}", id);
|
info!("register rpc request received: {:?}", id);
|
||||||
let pubkey = get_pubkey(id)?;
|
let pubkey = verify_pubkey(id)?;
|
||||||
|
verify_signature(&sig, &pubkey, &signed_msg)?;
|
||||||
meta.request_processor.register(pubkey)
|
meta.request_processor.register(pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign(&self, meta: Self::Metadata, id: String) -> Result<Signature> {
|
fn sign(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
id: String,
|
||||||
|
sig: Signature,
|
||||||
|
signed_msg: Vec<u8>,
|
||||||
|
) -> Result<Signature> {
|
||||||
info!("sign rpc request received: {:?}", id);
|
info!("sign rpc request received: {:?}", id);
|
||||||
let pubkey = get_pubkey(id)?;
|
let pubkey = verify_pubkey(id)?;
|
||||||
meta.request_processor.sign(pubkey)
|
verify_signature(&sig, &pubkey, &signed_msg)?;
|
||||||
|
meta.request_processor.sign(pubkey, &signed_msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deregister(&self, meta: Self::Metadata, id: String) -> Result<()> {
|
fn deregister(
|
||||||
|
&self,
|
||||||
|
meta: Self::Metadata,
|
||||||
|
id: String,
|
||||||
|
sig: Signature,
|
||||||
|
signed_msg: Vec<u8>,
|
||||||
|
) -> Result<()> {
|
||||||
info!("deregister rpc request received: {:?}", id);
|
info!("deregister rpc request received: {:?}", id);
|
||||||
let pubkey = get_pubkey(id)?;
|
let pubkey = verify_pubkey(id)?;
|
||||||
|
verify_signature(&sig, &pubkey, &signed_msg)?;
|
||||||
meta.request_processor.deregister(pubkey)
|
meta.request_processor.deregister(pubkey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
fn verify_signature(sig: &Signature, pubkey: &Pubkey, msg: &[u8]) -> Result<()> {
|
||||||
pub struct VoteSignRequestProcessor {}
|
if sig.verify(pubkey.as_ref(), msg) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::invalid_request())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VoteSignRequestProcessor {
|
||||||
|
nodes: Arc<RwLock<HashMap<Pubkey, Keypair>>>,
|
||||||
|
}
|
||||||
impl VoteSignRequestProcessor {
|
impl VoteSignRequestProcessor {
|
||||||
/// Process JSON-RPC request items sent via JSON-RPC.
|
/// Process JSON-RPC request items sent via JSON-RPC.
|
||||||
pub fn register(&self, pubkey: Pubkey) -> Result<Pubkey> {
|
pub fn register(&self, pubkey: Pubkey) -> Result<Pubkey> {
|
||||||
Ok(pubkey)
|
{
|
||||||
|
if let Some(voting_keypair) = self.nodes.read().unwrap().get(&pubkey) {
|
||||||
|
return Ok(voting_keypair.pubkey());
|
||||||
}
|
}
|
||||||
pub fn sign(&self, _pubkey: Pubkey) -> Result<Signature> {
|
|
||||||
let signature = [0u8; 16];
|
|
||||||
Ok(Signature::new(&signature))
|
|
||||||
}
|
}
|
||||||
pub fn deregister(&self, _pubkey: Pubkey) -> Result<()> {
|
let voting_keypair = Keypair::new();
|
||||||
|
let voting_pubkey = voting_keypair.pubkey();
|
||||||
|
self.nodes.write().unwrap().insert(pubkey, voting_keypair);
|
||||||
|
Ok(voting_pubkey)
|
||||||
|
}
|
||||||
|
pub fn sign(&self, pubkey: Pubkey, msg: &[u8]) -> Result<Signature> {
|
||||||
|
match self.nodes.read().unwrap().get(&pubkey) {
|
||||||
|
Some(voting_keypair) => {
|
||||||
|
let sig = Signature::new(&voting_keypair.sign(&msg).as_ref());
|
||||||
|
Ok(sig)
|
||||||
|
}
|
||||||
|
None => Err(Error::invalid_request()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn deregister(&self, pubkey: Pubkey) -> Result<()> {
|
||||||
|
self.nodes.write().unwrap().remove(&pubkey);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pubkey(input: String) -> Result<Pubkey> {
|
impl Default for VoteSignRequestProcessor {
|
||||||
|
fn default() -> Self {
|
||||||
|
VoteSignRequestProcessor {
|
||||||
|
nodes: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_pubkey(input: String) -> Result<Pubkey> {
|
||||||
let pubkey_vec = bs58::decode(input).into_vec().map_err(|err| {
|
let pubkey_vec = bs58::decode(input).into_vec().map_err(|err| {
|
||||||
info!("get_pubkey: invalid input: {:?}", err);
|
info!("verify_pubkey: invalid input: {:?}", err);
|
||||||
Error::invalid_request()
|
Error::invalid_request()
|
||||||
})?;
|
})?;
|
||||||
if pubkey_vec.len() != mem::size_of::<Pubkey>() {
|
if pubkey_vec.len() != mem::size_of::<Pubkey>() {
|
||||||
info!(
|
info!(
|
||||||
"get_pubkey: invalid pubkey_vec length: {}",
|
"verify_pubkey: invalid pubkey_vec length: {}",
|
||||||
pubkey_vec.len()
|
pubkey_vec.len()
|
||||||
);
|
);
|
||||||
Err(Error::invalid_request())
|
Err(Error::invalid_request())
|
||||||
|
@ -144,4 +196,308 @@ fn get_pubkey(input: String) -> Result<Pubkey> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {}
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use jsonrpc_core::Response;
|
||||||
|
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||||
|
|
||||||
|
fn start_rpc_handler() -> (MetaIoHandler<Meta>, Meta) {
|
||||||
|
let request_processor = VoteSignRequestProcessor::default();
|
||||||
|
let mut io = MetaIoHandler::default();
|
||||||
|
let rpc = VoteSignerRpcImpl;
|
||||||
|
io.extend_with(rpc.to_delegate());
|
||||||
|
let meta = Meta { request_processor };
|
||||||
|
(io, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_register_node() {
|
||||||
|
let (io, meta) = start_rpc_handler();
|
||||||
|
|
||||||
|
let node_keypair = Keypair::new();
|
||||||
|
let node_pubkey = node_keypair.pubkey();
|
||||||
|
let msg = "This is a test";
|
||||||
|
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref());
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "registerNode",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg.as_bytes()],
|
||||||
|
});
|
||||||
|
let res = io.handle_request_sync(&req.to_string(), meta);
|
||||||
|
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
if let Response::Single(out) = result {
|
||||||
|
if let Output::Success(succ) = out {
|
||||||
|
assert_eq!(succ.jsonrpc.unwrap(), Version::V2);
|
||||||
|
assert_eq!(succ.id, Id::Num(1));
|
||||||
|
assert!(succ.result.is_array());
|
||||||
|
assert_eq!(
|
||||||
|
succ.result.as_array().unwrap().len(),
|
||||||
|
mem::size_of::<Pubkey>()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_register_node_invalid_sig() {
|
||||||
|
let (io, meta) = start_rpc_handler();
|
||||||
|
|
||||||
|
let node_keypair = Keypair::new();
|
||||||
|
let node_pubkey = node_keypair.pubkey();
|
||||||
|
let msg = "This is a test";
|
||||||
|
let msg1 = "This is a Test1";
|
||||||
|
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref());
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "registerNode",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg1.as_bytes()],
|
||||||
|
});
|
||||||
|
let res = io.handle_request_sync(&req.to_string(), meta);
|
||||||
|
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
if let Response::Single(out) = result {
|
||||||
|
if let Output::Failure(succ) = out {
|
||||||
|
assert_eq!(succ.jsonrpc.unwrap(), Version::V2);
|
||||||
|
assert_eq!(succ.id, Id::Num(1));
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_deregister_node() {
|
||||||
|
let (io, meta) = start_rpc_handler();
|
||||||
|
|
||||||
|
let node_keypair = Keypair::new();
|
||||||
|
let node_pubkey = node_keypair.pubkey();
|
||||||
|
let msg = "This is a test";
|
||||||
|
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref());
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "deregisterNode",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg.as_bytes()],
|
||||||
|
});
|
||||||
|
let res = io.handle_request_sync(&req.to_string(), meta);
|
||||||
|
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
if let Response::Single(out) = result {
|
||||||
|
if let Output::Success(succ) = out {
|
||||||
|
assert_eq!(succ.jsonrpc.unwrap(), Version::V2);
|
||||||
|
assert_eq!(succ.id, Id::Num(1));
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_deregister_node_invalid_sig() {
|
||||||
|
let (io, meta) = start_rpc_handler();
|
||||||
|
|
||||||
|
let node_keypair = Keypair::new();
|
||||||
|
let node_pubkey = node_keypair.pubkey();
|
||||||
|
let msg = "This is a test";
|
||||||
|
let msg1 = "This is a Test1";
|
||||||
|
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref());
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "deregisterNode",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg1.as_bytes()],
|
||||||
|
});
|
||||||
|
let res = io.handle_request_sync(&req.to_string(), meta);
|
||||||
|
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
if let Response::Single(out) = result {
|
||||||
|
if let Output::Failure(succ) = out {
|
||||||
|
assert_eq!(succ.jsonrpc.unwrap(), Version::V2);
|
||||||
|
assert_eq!(succ.id, Id::Num(1));
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_sign_vote() {
|
||||||
|
let (io, meta) = start_rpc_handler();
|
||||||
|
|
||||||
|
let node_keypair = Keypair::new();
|
||||||
|
let node_pubkey = node_keypair.pubkey();
|
||||||
|
let msg = "This is a test";
|
||||||
|
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref());
|
||||||
|
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "registerNode",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg.as_bytes()],
|
||||||
|
});
|
||||||
|
let _res = io.handle_request_sync(&req.to_string(), meta.clone());
|
||||||
|
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "signVote",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg.as_bytes()],
|
||||||
|
});
|
||||||
|
let res = io.handle_request_sync(&req.to_string(), meta);
|
||||||
|
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
if let Response::Single(out) = result {
|
||||||
|
if let Output::Success(succ) = out {
|
||||||
|
assert_eq!(succ.jsonrpc.unwrap(), Version::V2);
|
||||||
|
assert_eq!(succ.id, Id::Num(1));
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_sign_vote_before_register() {
|
||||||
|
let (io, meta) = start_rpc_handler();
|
||||||
|
|
||||||
|
let node_keypair = Keypair::new();
|
||||||
|
let node_pubkey = node_keypair.pubkey();
|
||||||
|
let msg = "This is a test";
|
||||||
|
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref());
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "signVote",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg.as_bytes()],
|
||||||
|
});
|
||||||
|
let res = io.handle_request_sync(&req.to_string(), meta);
|
||||||
|
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
if let Response::Single(out) = result {
|
||||||
|
if let Output::Failure(succ) = out {
|
||||||
|
assert_eq!(succ.jsonrpc.unwrap(), Version::V2);
|
||||||
|
assert_eq!(succ.id, Id::Num(1));
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_sign_vote_after_deregister() {
|
||||||
|
let (io, meta) = start_rpc_handler();
|
||||||
|
|
||||||
|
let node_keypair = Keypair::new();
|
||||||
|
let node_pubkey = node_keypair.pubkey();
|
||||||
|
let msg = "This is a test";
|
||||||
|
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref());
|
||||||
|
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "registerNode",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg.as_bytes()],
|
||||||
|
});
|
||||||
|
let _res = io.handle_request_sync(&req.to_string(), meta.clone());
|
||||||
|
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "deregisterNode",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg.as_bytes()],
|
||||||
|
});
|
||||||
|
let _res = io.handle_request_sync(&req.to_string(), meta.clone());
|
||||||
|
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "signVote",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg.as_bytes()],
|
||||||
|
});
|
||||||
|
let res = io.handle_request_sync(&req.to_string(), meta);
|
||||||
|
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
if let Response::Single(out) = result {
|
||||||
|
if let Output::Failure(succ) = out {
|
||||||
|
assert_eq!(succ.jsonrpc.unwrap(), Version::V2);
|
||||||
|
assert_eq!(succ.id, Id::Num(1));
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rpc_sign_vote_invalid_sig() {
|
||||||
|
let (io, meta) = start_rpc_handler();
|
||||||
|
|
||||||
|
let node_keypair = Keypair::new();
|
||||||
|
let node_pubkey = node_keypair.pubkey();
|
||||||
|
let msg = "This is a test";
|
||||||
|
let msg1 = "This is a Test";
|
||||||
|
let sig = Signature::new(&node_keypair.sign(msg.as_bytes()).as_ref());
|
||||||
|
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "registerNode",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg.as_bytes()],
|
||||||
|
});
|
||||||
|
let _res = io.handle_request_sync(&req.to_string(), meta.clone());
|
||||||
|
|
||||||
|
let req = json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "signVote",
|
||||||
|
"params": [node_pubkey.to_string(), sig, msg1.as_bytes()],
|
||||||
|
});
|
||||||
|
let res = io.handle_request_sync(&req.to_string(), meta);
|
||||||
|
|
||||||
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
if let Response::Single(out) = result {
|
||||||
|
if let Output::Failure(succ) = out {
|
||||||
|
assert_eq!(succ.jsonrpc.unwrap(), Version::V2);
|
||||||
|
assert_eq!(succ.id, Id::Num(1));
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue