diff --git a/beacon_node/eth2-libp2p/src/rpc/methods.rs b/beacon_node/eth2-libp2p/src/rpc/methods.rs index b1897f9f5c..066da13514 100644 --- a/beacon_node/eth2-libp2p/src/rpc/methods.rs +++ b/beacon_node/eth2-libp2p/src/rpc/methods.rs @@ -32,8 +32,8 @@ pub struct HelloMessage { /// The reason given for a `Goodbye` message. /// -/// Note: any unknown `u64::into(n)` will resolve to `GoodbyeReason::Unknown` for any unknown `n`, -/// however `GoodbyeReason::Unknown.into()` will go into `0_u64`. Therefore de-serializing then +/// Note: any unknown `u64::into(n)` will resolve to `Goodbye::Unknown` for any unknown `n`, +/// however `Goodbye::Unknown.into()` will go into `0_u64`. Therefore de-serializing then /// re-serializing may not return the same bytes. #[derive(Debug, Clone)] pub enum Goodbye { @@ -61,6 +61,13 @@ impl From for Goodbye { } } +impl Into for Goodbye { + fn into(self) -> u64 { + self as u64 + } +} + +impl_encode_via_from!(Goodbye, u64); impl_decode_via_from!(Goodbye, u64); /// Request a number of beacon block roots from a peer. diff --git a/beacon_node/eth2-libp2p/src/rpc/protocol.rs b/beacon_node/eth2-libp2p/src/rpc/protocol.rs index a1c948b2a0..4d1f0b021c 100644 --- a/beacon_node/eth2-libp2p/src/rpc/protocol.rs +++ b/beacon_node/eth2-libp2p/src/rpc/protocol.rs @@ -3,6 +3,7 @@ use super::request_response::{rpc_request_response, RPCRequestResponse}; use futures::future::Future; use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, UpgradeInfo}; use ssz::{Decode, Encode}; +use ssz_derive::{Decode, Encode}; use std::io; use std::time::Duration; use tokio::io::{AsyncRead, AsyncWrite}; @@ -26,12 +27,12 @@ impl UpgradeInfo for RPCProtocol { fn protocol_info(&self) -> Self::InfoIter { vec![ - b"/eth/serenity/rpc/hello/1/ssz", - b"/eth/serenity/rpc/goodbye/1/ssz", - b"/eth/serenity/rpc/beacon_block_roots/1/ssz", - b"/eth/serenity/rpc/beacon_block_headers/1/ssz", - b"/eth/serenity/rpc/beacon_block_bodies/1/ssz", - b"/eth/serenity/rpc/beacon_chain_state/1/ssz", + b"/eth/serenity/rpc/hello/1.0.0/ssz", + b"/eth/serenity/rpc/goodbye/1.0.0/ssz", + b"/eth/serenity/rpc/beacon_block_roots/1.0.0/ssz", + b"/eth/serenity/rpc/beacon_block_headers/1.0.0/ssz", + b"/eth/serenity/rpc/beacon_block_bodies/1.0.0/ssz", + b"/eth/serenity/rpc/beacon_chain_state/1.0.0/ssz", ] } } @@ -45,7 +46,7 @@ pub struct ProtocolId { pub message_name: String, /// The version of the RPC. - pub version: usize, + pub version: String, /// The encoding of the RPC. pub encoding: String, @@ -53,10 +54,10 @@ pub struct ProtocolId { /// An RPC protocol ID. impl ProtocolId { - pub fn new(message_name: &str, version: usize, encoding: &str) -> Self { + pub fn new(message_name: &str, version: &str, encoding: &str) -> Self { ProtocolId { message_name: message_name.into(), - version, + version: version.into(), encoding: encoding.into(), } } @@ -73,9 +74,7 @@ impl ProtocolId { Ok(ProtocolId { message_name: protocol_list[3].into(), - version: protocol_list[4] - .parse() - .map_err(|_| RPCError::InvalidProtocol("Invalid version"))?, + version: protocol_list[4].into(), encoding: protocol_list[5].into(), }) } @@ -172,19 +171,19 @@ impl RPCRequest { pub fn supported_protocols(&self) -> Vec { match self { // add more protocols when versions/encodings are supported - RPCRequest::Hello(_) => vec![ProtocolId::new("hello", 1, "ssz").into()], - RPCRequest::Goodbye(_) => vec![ProtocolId::new("goodbye", 1, "ssz").into()], + RPCRequest::Hello(_) => vec![ProtocolId::new("hello", "1.0.0", "ssz").into()], + RPCRequest::Goodbye(_) => vec![ProtocolId::new("goodbye", "1.0.0", "ssz").into()], RPCRequest::BeaconBlockRoots(_) => { - vec![ProtocolId::new("beacon_block_roots", 1, "ssz").into()] + vec![ProtocolId::new("beacon_block_roots", "1.0.0", "ssz").into()] } RPCRequest::BeaconBlockHeaders(_) => { - vec![ProtocolId::new("beacon_block_headers", 1, "ssz").into()] + vec![ProtocolId::new("beacon_block_headers", "1.0.0", "ssz").into()] } RPCRequest::BeaconBlockBodies(_) => { - vec![ProtocolId::new("beacon_block_bodies", 1, "ssz").into()] + vec![ProtocolId::new("beacon_block_bodies", "1.0.0", "ssz").into()] } RPCRequest::BeaconChainState(_) => { - vec![ProtocolId::new("beacon_block_state", 1, "ssz").into()] + vec![ProtocolId::new("beacon_block_state", "1.0.0", "ssz").into()] } } } @@ -216,30 +215,26 @@ impl RPCRequest { // This function can be extended to provide further logic for supporting various protocol versions/encoding /// Decodes a request received from our peer. - pub fn decode(packet: Vec, protocol: ProtocolId, response_code: ResponseCode) -> Result { - - match response_code { - ResponseCode:: - - - + pub fn decode(packet: Vec, protocol: ProtocolId) -> Result { match protocol.message_name.as_str() { - "hello" => match protocol.version { - 1 => match protocol.encoding.as_str() { + "hello" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { "ssz" => Ok(RPCRequest::Hello(HelloMessage::from_ssz_bytes(&packet)?)), _ => Err(RPCError::InvalidProtocol("Unknown HELLO encoding")), }, _ => Err(RPCError::InvalidProtocol("Unknown HELLO version")), }, - "goodbye" => match protocol.version { - 1 => match protocol.encoding.as_str() { + "goodbye" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { "ssz" => Ok(RPCRequest::Goodbye(Goodbye::from_ssz_bytes(&packet)?)), _ => Err(RPCError::InvalidProtocol("Unknown GOODBYE encoding")), }, - _ => Err(RPCError::InvalidProtocol("Unknown GOODBYE version")), + _ => Err(RPCError::InvalidProtocol( + "Unknown GOODBYE version.as_str()", + )), }, - "beacon_block_roots" => match protocol.version { - 1 => match protocol.encoding.as_str() { + "beacon_block_roots" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { "ssz" => Ok(RPCRequest::BeaconBlockRoots( BeaconBlockRootsRequest::from_ssz_bytes(&packet)?, )), @@ -248,11 +243,11 @@ impl RPCRequest { )), }, _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_BLOCK_ROOTS version", + "Unknown BEACON_BLOCK_ROOTS version.", )), }, - "beacon_block_headers" => match protocol.version { - 1 => match protocol.encoding.as_str() { + "beacon_block_headers" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { "ssz" => Ok(RPCRequest::BeaconBlockHeaders( BeaconBlockHeadersRequest::from_ssz_bytes(&packet)?, )), @@ -261,11 +256,11 @@ impl RPCRequest { )), }, _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_BLOCK_HEADERS version", + "Unknown BEACON_BLOCK_HEADERS version.", )), }, - "beacon_block_bodies" => match protocol.version { - 1 => match protocol.encoding.as_str() { + "beacon_block_bodies" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { "ssz" => Ok(RPCRequest::BeaconBlockBodies( BeaconBlockBodiesRequest::from_ssz_bytes(&packet)?, )), @@ -274,11 +269,11 @@ impl RPCRequest { )), }, _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_BLOCK_BODIES version", + "Unknown BEACON_BLOCK_BODIES version.", )), }, - "beacon_chain_state" => match protocol.version { - 1 => match protocol.encoding.as_str() { + "beacon_chain_state" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { "ssz" => Ok(RPCRequest::BeaconChainState( BeaconChainStateRequest::from_ssz_bytes(&packet)?, )), @@ -287,7 +282,7 @@ impl RPCRequest { )), }, _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_CHAIN_STATE version", + "Unknown BEACON_CHAIN_STATE version.", )), }, } @@ -319,12 +314,11 @@ pub enum ResponseCode { EncodingError = 1, InvalidRequest = 2, ServerError = 3, - Unknown, + Unknown = 255, } - -impl From for ResponseCode { - fn from(val: u64) -> ResponseCode { +impl From for ResponseCode { + fn from(val: u8) -> ResponseCode { match val { 0 => ResponseCode::Success, 1 => ResponseCode::EncodingError, @@ -335,72 +329,110 @@ impl From for ResponseCode { } } +impl Into for ResponseCode { + fn into(self) -> u8 { + self as u8 + } +} + +#[derive(Encode, Decode)] +struct ErrorResponse { + error_message: String, +} + impl RPCResponse { /// Decodes a response that was received on the same stream as a request. The response type should /// therefore match the request protocol type. - fn decode(packet: Vec, protocol: ProtocolId) -> Result { - match protocol.message_name.as_str() { - "hello" => match protocol.version { - 1 => match protocol.encoding.as_str() { - "ssz" => Ok(RPCResponse::Hello(HelloMessage::from_ssz_bytes(&packet)?)), - _ => Err(RPCError::InvalidProtocol("Unknown HELLO encoding")), + pub fn decode( + packet: Vec, + protocol: ProtocolId, + response_code: ResponseCode, + ) -> Result { + match response_code { + ResponseCode::EncodingError => Ok(RPCResponse::Error("Encoding error".into())), + ResponseCode::InvalidRequest => { + let response = match protocol.encoding.as_str() { + "ssz" => ErrorResponse::from_ssz_bytes(&packet)?, + _ => return Err(RPCError::InvalidProtocol("Unknown Encoding")), + }; + Ok(RPCResponse::Error(format!( + "Invalid Request: {}", + response.error_message + ))) + } + ResponseCode::ServerError => { + let response = match protocol.encoding.as_str() { + "ssz" => ErrorResponse::from_ssz_bytes(&packet)?, + _ => return Err(RPCError::InvalidProtocol("Unknown Encoding")), + }; + Ok(RPCResponse::Error(format!( + "Remote Server Error: {}", + response.error_message + ))) + } + ResponseCode::Success => match protocol.message_name.as_str() { + "hello" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { + "ssz" => Ok(RPCResponse::Hello(HelloMessage::from_ssz_bytes(&packet)?)), + _ => Err(RPCError::InvalidProtocol("Unknown HELLO encoding")), + }, + _ => Err(RPCError::InvalidProtocol("Unknown HELLO version.")), }, - _ => Err(RPCError::InvalidProtocol("Unknown HELLO version")), - }, - "goodbye" => Err(RPCError::Custom( - "GOODBYE should not have a response".into(), - )), - "beacon_block_roots" => match protocol.version { - 1 => match protocol.encoding.as_str() { - "ssz" => Ok(RPCResponse::BeaconBlockRoots( - BeaconBlockRootsResponse::from_ssz_bytes(&packet)?, - )), - _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_BLOCK_ROOTS encoding", - )), - }, - _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_BLOCK_ROOTS version", + "goodbye" => Err(RPCError::Custom( + "GOODBYE should not have a response".into(), )), - }, - "beacon_block_headers" => match protocol.version { - 1 => match protocol.encoding.as_str() { - "ssz" => Ok(RPCResponse::BeaconBlockHeaders( - BeaconBlockHeadersResponse { headers: packet }, - )), + "beacon_block_roots" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { + "ssz" => Ok(RPCResponse::BeaconBlockRoots( + BeaconBlockRootsResponse::from_ssz_bytes(&packet)?, + )), + _ => Err(RPCError::InvalidProtocol( + "Unknown BEACON_BLOCK_ROOTS encoding", + )), + }, _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_BLOCK_HEADERS encoding", + "Unknown BEACON_BLOCK_ROOTS version.", )), }, - _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_BLOCK_HEADERS version", - )), - }, - "beacon_block_bodies" => match protocol.version { - 1 => match protocol.encoding.as_str() { - "ssz" => Ok(RPCResponse::BeaconBlockBodies(BeaconBlockBodiesResponse { - block_bodies: packet, - })), + "beacon_block_headers" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { + "ssz" => Ok(RPCResponse::BeaconBlockHeaders( + BeaconBlockHeadersResponse { headers: packet }, + )), + _ => Err(RPCError::InvalidProtocol( + "Unknown BEACON_BLOCK_HEADERS encoding", + )), + }, _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_BLOCK_BODIES encoding", + "Unknown BEACON_BLOCK_HEADERS version.", )), }, - _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_BLOCK_BODIES version", - )), - }, - "beacon_chain_state" => match protocol.version { - 1 => match protocol.encoding.as_str() { - "ssz" => Ok(RPCResponse::BeaconChainState( - BeaconChainStateResponse::from_ssz_bytes(&packet)?, - )), + "beacon_block_bodies" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { + "ssz" => Ok(RPCResponse::BeaconBlockBodies(BeaconBlockBodiesResponse { + block_bodies: packet, + })), + _ => Err(RPCError::InvalidProtocol( + "Unknown BEACON_BLOCK_BODIES encoding", + )), + }, _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_CHAIN_STATE encoding", + "Unknown BEACON_BLOCK_BODIES version.", + )), + }, + "beacon_chain_state" => match protocol.version.as_str() { + "1.0.0" => match protocol.encoding.as_str() { + "ssz" => Ok(RPCResponse::BeaconChainState( + BeaconChainStateResponse::from_ssz_bytes(&packet)?, + )), + _ => Err(RPCError::InvalidProtocol( + "Unknown BEACON_CHAIN_STATE encoding", + )), + }, + _ => Err(RPCError::InvalidProtocol( + "Unknown BEACON_CHAIN_STATE version.", )), }, - _ => Err(RPCError::InvalidProtocol( - "Unknown BEACON_CHAIN_STATE version", - )), }, } } @@ -503,7 +535,6 @@ impl From for RPCError { RPCError::SSZDecodeError(err) } } - impl From> for RPCError { fn from(err: tokio::timer::timeout::Error) -> Self { if err.is_elapsed() { diff --git a/beacon_node/eth2-libp2p/src/rpc/request_response.rs b/beacon_node/eth2-libp2p/src/rpc/request_response.rs index cd8ed92804..e511bfe9f7 100644 --- a/beacon_node/eth2-libp2p/src/rpc/request_response.rs +++ b/beacon_node/eth2-libp2p/src/rpc/request_response.rs @@ -91,8 +91,11 @@ where RPCRequestResponseInner::ReadResponseCode(mut inner, max_size) => { match inner.poll()? { Async::Ready((socket, data)) => { + let resp_code_byte = [0; 1]; + // data must be only 1-byte - this cannot panic + resp_code_byte.copy_from_slice(&data.into_inner()); let response_code = - ResponseCode::from(u64::from_be_bytes(data.into_inner())); + ResponseCode::from(u8::from_be_bytes(resp_code_byte)); // known response codes match response_code { ResponseCode::Success @@ -113,7 +116,7 @@ where // unknown response code let response = RPCResponse::Error(format!( "Unknown response code: {}", - response_code + (response_code as u8) )); return Ok(Async::Ready(response)); }