Implement eth/66 (#467)
* Allow eth/66 * Add eth/66 request ids * fmt * Remove some leftovers * fmt * Change behaviour in case of missing peer info - Assume eth/66 protocol, not earlier one - Log just a trace, not an error
This commit is contained in:
parent
fdaee51ca0
commit
43ee520904
@ -33,7 +33,7 @@ use std::{
|
||||
use chain::{
|
||||
fork_filter::ForkFilterApi, ChainSyncApi, SyncState, SyncStatus as EthSyncStatus,
|
||||
ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_64, ETH_PROTOCOL_VERSION_65,
|
||||
PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2,
|
||||
ETH_PROTOCOL_VERSION_66, PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2,
|
||||
};
|
||||
use ethcore::{
|
||||
client::{BlockChainClient, ChainMessageType, ChainNotify, NewBlocks},
|
||||
@ -571,6 +571,7 @@ impl ChainNotify for EthSync {
|
||||
ETH_PROTOCOL_VERSION_63,
|
||||
ETH_PROTOCOL_VERSION_64,
|
||||
ETH_PROTOCOL_VERSION_65,
|
||||
ETH_PROTOCOL_VERSION_66,
|
||||
],
|
||||
)
|
||||
.unwrap_or_else(|e| warn!("Error registering ethereum protocol: {:?}", e));
|
||||
|
@ -32,14 +32,17 @@ use std::{cmp, mem, time::Instant};
|
||||
use sync_io::SyncIo;
|
||||
use types::{block_status::BlockStatus, ids::BlockId, BlockNumber};
|
||||
|
||||
use super::sync_packet::{
|
||||
use super::{
|
||||
request_id::strip_request_id,
|
||||
sync_packet::{
|
||||
PacketInfo,
|
||||
SyncPacket::{self, *},
|
||||
},
|
||||
};
|
||||
|
||||
use super::{
|
||||
BlockSet, ChainSync, ForkConfirmation, PacketProcessError, PeerAsking, PeerInfo, SyncRequester,
|
||||
SyncState, ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_64, ETH_PROTOCOL_VERSION_65,
|
||||
SyncState, ETH_PROTOCOL_VERSION_63, ETH_PROTOCOL_VERSION_64, ETH_PROTOCOL_VERSION_66,
|
||||
MAX_NEW_BLOCK_AGE, MAX_NEW_HASHES, PAR_PROTOCOL_VERSION_1, PAR_PROTOCOL_VERSION_2,
|
||||
};
|
||||
|
||||
@ -55,9 +58,11 @@ impl SyncHandler {
|
||||
packet_id: u8,
|
||||
data: &[u8],
|
||||
) {
|
||||
let rlp = Rlp::new(data);
|
||||
if let Some(packet_id) = SyncPacket::from_u8(packet_id) {
|
||||
let result = match packet_id {
|
||||
let rlp_result = strip_request_id(data, sync, &peer, &packet_id);
|
||||
|
||||
let result = match rlp_result {
|
||||
Ok((rlp, _)) => match packet_id {
|
||||
StatusPacket => SyncHandler::on_peer_status(sync, io, peer, &rlp),
|
||||
BlockHeadersPacket => SyncHandler::on_peer_block_headers(sync, io, peer, &rlp),
|
||||
BlockBodiesPacket => SyncHandler::on_peer_block_bodies(sync, io, peer, &rlp),
|
||||
@ -70,12 +75,16 @@ impl SyncHandler {
|
||||
PooledTransactionsPacket => {
|
||||
SyncHandler::on_peer_pooled_transactions(sync, io, peer, &rlp)
|
||||
}
|
||||
SnapshotManifestPacket => SyncHandler::on_snapshot_manifest(sync, io, peer, &rlp),
|
||||
SnapshotManifestPacket => {
|
||||
SyncHandler::on_snapshot_manifest(sync, io, peer, &rlp)
|
||||
}
|
||||
SnapshotDataPacket => SyncHandler::on_snapshot_data(sync, io, peer, &rlp),
|
||||
_ => {
|
||||
debug!(target: "sync", "{}: Unknown packet {}", peer, packet_id.id());
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
Err(e) => Err(e.into()),
|
||||
};
|
||||
|
||||
match result {
|
||||
@ -797,7 +806,7 @@ impl SyncHandler {
|
||||
|| peer.protocol_version > PAR_PROTOCOL_VERSION_2.0))
|
||||
|| (!warp_protocol
|
||||
&& (peer.protocol_version < ETH_PROTOCOL_VERSION_63.0
|
||||
|| peer.protocol_version > ETH_PROTOCOL_VERSION_65.0))
|
||||
|| peer.protocol_version > ETH_PROTOCOL_VERSION_66.0))
|
||||
{
|
||||
trace!(target: "sync", "Peer {} unsupported eth protocol ({})", peer_id, peer.protocol_version);
|
||||
return Err(DownloaderImportError::Invalid);
|
||||
|
@ -90,6 +90,7 @@
|
||||
pub mod fork_filter;
|
||||
mod handler;
|
||||
mod propagator;
|
||||
pub mod request_id;
|
||||
mod requester;
|
||||
mod supplier;
|
||||
pub mod sync_packet;
|
||||
@ -153,6 +154,8 @@ impl From<DecoderError> for PacketProcessError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Version 66 of the Ethereum protocol and number of packet IDs reserved by the protocol (packet count).
|
||||
pub const ETH_PROTOCOL_VERSION_66: (u8, u8) = (66, 0x11);
|
||||
/// Version 65 of the Ethereum protocol and number of packet IDs reserved by the protocol (packet count).
|
||||
pub const ETH_PROTOCOL_VERSION_65: (u8, u8) = (65, 0x11);
|
||||
/// 64 version of Ethereum protocol.
|
||||
|
148
crates/ethcore/sync/src/chain/request_id.rs
Normal file
148
crates/ethcore/sync/src/chain/request_id.rs
Normal file
@ -0,0 +1,148 @@
|
||||
use bytes::Bytes;
|
||||
use chain::{
|
||||
sync_packet::{PacketInfo, SyncPacket},
|
||||
ChainSync, PeerInfo,
|
||||
};
|
||||
use network::PeerId;
|
||||
use rlp::{DecoderError, Rlp, RlpStream};
|
||||
|
||||
pub type RequestId = u64;
|
||||
|
||||
// Separate the eth/66 request id from a packet, if it exists.
|
||||
pub fn strip_request_id<'a>(
|
||||
data: &'a [u8],
|
||||
sync: &ChainSync,
|
||||
peer: &PeerId,
|
||||
packet_id: &SyncPacket,
|
||||
) -> Result<(Rlp<'a>, Option<RequestId>), DecoderError> {
|
||||
let protocol_version = if let Some(peer_info) = sync.peers.get(peer) {
|
||||
peer_info.protocol_version
|
||||
} else {
|
||||
trace!(
|
||||
"Peer info missing for peer {}, assuming protocol version 66",
|
||||
peer
|
||||
);
|
||||
66
|
||||
};
|
||||
|
||||
let has_request_id = protocol_version >= 66 && packet_id.has_request_id_in_eth_66();
|
||||
|
||||
do_strip_request_id(data, has_request_id)
|
||||
}
|
||||
|
||||
fn do_strip_request_id<'a>(
|
||||
data: &'a [u8],
|
||||
has_request_id: bool,
|
||||
) -> Result<(Rlp<'a>, Option<RequestId>), DecoderError> {
|
||||
let rlp = Rlp::new(data);
|
||||
|
||||
if has_request_id {
|
||||
let request_id: RequestId = rlp.val_at(0)?;
|
||||
let stripped_rlp = rlp.at(1)?;
|
||||
Ok((stripped_rlp, Some(request_id)))
|
||||
} else {
|
||||
Ok((rlp, None))
|
||||
}
|
||||
}
|
||||
|
||||
// Add a given eth/66 request id to a packet being built.
|
||||
pub fn prepend_request_id(rlp: RlpStream, request_id: Option<RequestId>) -> RlpStream {
|
||||
match request_id {
|
||||
Some(ref id) => {
|
||||
let mut stream = RlpStream::new_list(2);
|
||||
stream.append(id);
|
||||
stream.append_raw(&rlp.out(), 1);
|
||||
stream
|
||||
}
|
||||
None => rlp,
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepend a new eth/66 request id to the packet if appropriate.
|
||||
pub fn generate_request_id(
|
||||
packet: Bytes,
|
||||
peer: &PeerInfo,
|
||||
packet_id: SyncPacket,
|
||||
) -> (Bytes, Option<RequestId>) {
|
||||
if peer.protocol_version >= 66 && packet_id.has_request_id_in_eth_66() {
|
||||
do_generate_request_id(&packet)
|
||||
} else {
|
||||
(packet, None)
|
||||
}
|
||||
}
|
||||
|
||||
fn do_generate_request_id(packet: &Bytes) -> (Bytes, Option<RequestId>) {
|
||||
let request_id: RequestId = rand::random();
|
||||
|
||||
let mut rlp = RlpStream::new_list(2);
|
||||
rlp.append(&request_id);
|
||||
rlp.append_raw(packet, 1);
|
||||
|
||||
(rlp.out(), Some(request_id))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ethereum_types::H256;
|
||||
|
||||
#[test]
|
||||
fn test_prepend_request_id() {
|
||||
let mut request = RlpStream::new_list(2);
|
||||
request.append(&H256::from_low_u64_be(1));
|
||||
request.append(&H256::from_low_u64_be(2));
|
||||
|
||||
let with_id = prepend_request_id(request, Some(10));
|
||||
let rlp = Rlp::new(with_id.as_raw());
|
||||
let recovered_id: RequestId = rlp.val_at(0).unwrap();
|
||||
let recovered_request: Vec<H256> = rlp.at(1).unwrap().as_list().unwrap();
|
||||
|
||||
assert_eq!(recovered_id, 10);
|
||||
assert_eq!(
|
||||
recovered_request,
|
||||
[H256::from_low_u64_be(1), H256::from_low_u64_be(2)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_request_id() {
|
||||
let request = vec![
|
||||
H256::from_low_u64_be(1),
|
||||
H256::from_low_u64_be(2),
|
||||
H256::from_low_u64_be(3),
|
||||
];
|
||||
|
||||
let mut request_with_id = RlpStream::new_list(2);
|
||||
request_with_id.append(&20u64);
|
||||
request_with_id.append_list(&request);
|
||||
let data = request_with_id.out();
|
||||
|
||||
let (rlp, id) = do_strip_request_id(&data, true).unwrap();
|
||||
|
||||
assert_eq!(id, Some(20));
|
||||
assert_eq!(rlp.as_list::<H256>().unwrap(), request);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_request_id() {
|
||||
let request = vec![
|
||||
H256::from_low_u64_be(1),
|
||||
H256::from_low_u64_be(2),
|
||||
H256::from_low_u64_be(3),
|
||||
];
|
||||
|
||||
let mut stream = RlpStream::new_list(3);
|
||||
for hash in &request {
|
||||
stream.append(hash);
|
||||
}
|
||||
let data = stream.out();
|
||||
|
||||
let (new_data, id) = do_generate_request_id(&data);
|
||||
|
||||
let recovered = Rlp::new(&new_data);
|
||||
let recovered_id: RequestId = recovered.val_at(0).unwrap();
|
||||
let recovered_request: Vec<H256> = recovered.at(1).unwrap().as_list().unwrap();
|
||||
assert_eq!(recovered_id, id.unwrap());
|
||||
assert_eq!(recovered_request, request);
|
||||
}
|
||||
}
|
@ -23,7 +23,10 @@ use std::time::Instant;
|
||||
use sync_io::SyncIo;
|
||||
use types::BlockNumber;
|
||||
|
||||
use super::sync_packet::{SyncPacket::*, *};
|
||||
use super::{
|
||||
request_id::generate_request_id,
|
||||
sync_packet::{SyncPacket::*, *},
|
||||
};
|
||||
|
||||
use super::{BlockSet, ChainSync, PeerAsking};
|
||||
|
||||
@ -243,6 +246,8 @@ impl SyncRequester {
|
||||
peer.asking = asking;
|
||||
peer.ask_time = Instant::now();
|
||||
|
||||
let (packet, _) = generate_request_id(packet, peer, packet_id);
|
||||
|
||||
let result = io.send(peer_id, packet_id, packet);
|
||||
|
||||
if let Err(e) = result {
|
||||
|
@ -31,12 +31,16 @@ use types::{ids::BlockId, BlockNumber};
|
||||
|
||||
use sync_io::SyncIo;
|
||||
|
||||
use super::sync_packet::{PacketInfo, SyncPacket, SyncPacket::*};
|
||||
use super::{
|
||||
request_id::{prepend_request_id, strip_request_id, RequestId},
|
||||
sync_packet::{PacketInfo, SyncPacket, SyncPacket::*},
|
||||
};
|
||||
|
||||
use super::{
|
||||
ChainSync, PacketProcessError, RlpResponseResult, SyncHandler, MAX_BODIES_TO_SEND,
|
||||
MAX_HEADERS_TO_SEND, MAX_RECEIPTS_HEADERS_TO_SEND,
|
||||
};
|
||||
use std::borrow::Borrow;
|
||||
|
||||
/// The Chain Sync Supplier: answers requests from peers with available data
|
||||
pub struct SyncSupplier;
|
||||
@ -52,14 +56,16 @@ impl SyncSupplier {
|
||||
packet_id: u8,
|
||||
data: &[u8],
|
||||
) {
|
||||
let rlp = Rlp::new(data);
|
||||
|
||||
if let Some(id) = SyncPacket::from_u8(packet_id) {
|
||||
let result = match id {
|
||||
let rlp_result = strip_request_id(data, sync.read().borrow(), &peer, &id);
|
||||
|
||||
let result = match rlp_result {
|
||||
Ok((rlp, request_id)) => match id {
|
||||
GetPooledTransactionsPacket => SyncSupplier::return_rlp(
|
||||
io,
|
||||
&rlp,
|
||||
peer,
|
||||
request_id,
|
||||
SyncSupplier::return_pooled_transactions,
|
||||
|e| format!("Error sending pooled transactions: {:?}", e),
|
||||
),
|
||||
@ -68,6 +74,7 @@ impl SyncSupplier {
|
||||
io,
|
||||
&rlp,
|
||||
peer,
|
||||
request_id,
|
||||
SyncSupplier::return_block_bodies,
|
||||
|e| format!("Error sending block bodies: {:?}", e),
|
||||
),
|
||||
@ -76,19 +83,25 @@ impl SyncSupplier {
|
||||
io,
|
||||
&rlp,
|
||||
peer,
|
||||
request_id,
|
||||
SyncSupplier::return_block_headers,
|
||||
|e| format!("Error sending block headers: {:?}", e),
|
||||
),
|
||||
|
||||
GetReceiptsPacket => {
|
||||
SyncSupplier::return_rlp(io, &rlp, peer, SyncSupplier::return_receipts, |e| {
|
||||
format!("Error sending receipts: {:?}", e)
|
||||
})
|
||||
}
|
||||
GetReceiptsPacket => SyncSupplier::return_rlp(
|
||||
io,
|
||||
&rlp,
|
||||
peer,
|
||||
request_id,
|
||||
SyncSupplier::return_receipts,
|
||||
|e| format!("Error sending receipts: {:?}", e),
|
||||
),
|
||||
|
||||
GetSnapshotManifestPacket => SyncSupplier::return_rlp(
|
||||
io,
|
||||
&rlp,
|
||||
peer,
|
||||
request_id,
|
||||
SyncSupplier::return_snapshot_manifest,
|
||||
|e| format!("Error sending snapshot manifest: {:?}", e),
|
||||
),
|
||||
@ -97,6 +110,7 @@ impl SyncSupplier {
|
||||
io,
|
||||
&rlp,
|
||||
peer,
|
||||
request_id,
|
||||
SyncSupplier::return_snapshot_data,
|
||||
|e| format!("Error sending snapshot data: {:?}", e),
|
||||
),
|
||||
@ -130,9 +144,10 @@ impl SyncSupplier {
|
||||
sync.write().on_packet(io, peer, packet_id, data);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
Err(e) => Err(e.into()),
|
||||
};
|
||||
|
||||
match result {
|
||||
@ -156,14 +171,16 @@ impl SyncSupplier {
|
||||
packet_id: u8,
|
||||
data: &[u8],
|
||||
) {
|
||||
let rlp = Rlp::new(data);
|
||||
|
||||
if let Some(id) = SyncPacket::from_u8(packet_id) {
|
||||
let result = match id {
|
||||
let rlp_result = strip_request_id(data, sync.read().borrow(), &peer, &id);
|
||||
|
||||
let result = match rlp_result {
|
||||
Ok((rlp, request_id)) => match id {
|
||||
GetBlockHeadersPacket => SyncSupplier::send_rlp(
|
||||
io,
|
||||
&rlp,
|
||||
peer,
|
||||
request_id,
|
||||
SyncSupplier::return_block_headers,
|
||||
|e| format!("Error sending block headers: {:?}", e),
|
||||
),
|
||||
@ -172,6 +189,8 @@ impl SyncSupplier {
|
||||
debug!(target: "sync", "Unexpected packet {} was dispatched for delayed processing", packet_id);
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
Err(e) => Err(e.into()),
|
||||
};
|
||||
|
||||
match result {
|
||||
@ -394,6 +413,7 @@ impl SyncSupplier {
|
||||
io: &mut dyn SyncIo,
|
||||
rlp: &Rlp,
|
||||
peer: PeerId,
|
||||
request_id: Option<RequestId>,
|
||||
rlp_func: FRlp,
|
||||
error_func: FError,
|
||||
) -> Result<(), PacketProcessError>
|
||||
@ -403,6 +423,7 @@ impl SyncSupplier {
|
||||
{
|
||||
let response = rlp_func(io, rlp, peer);
|
||||
if let Some((packet_id, rlp_stream)) = response? {
|
||||
let rlp_stream = prepend_request_id(rlp_stream, request_id);
|
||||
io.respond(packet_id.id(), rlp_stream.out())
|
||||
.unwrap_or_else(|e| debug!(target: "sync", "{:?}", error_func(e)));
|
||||
}
|
||||
@ -413,6 +434,7 @@ impl SyncSupplier {
|
||||
io: &mut dyn SyncIo,
|
||||
rlp: &Rlp,
|
||||
peer: PeerId,
|
||||
request_id: Option<RequestId>,
|
||||
rlp_func: FRlp,
|
||||
error_func: FError,
|
||||
) -> Result<(), PacketProcessError>
|
||||
@ -424,6 +446,7 @@ impl SyncSupplier {
|
||||
match response {
|
||||
Err(e) => Err(e),
|
||||
Ok(Some((packet_id, rlp_stream))) => {
|
||||
let rlp_stream = prepend_request_id(rlp_stream, request_id);
|
||||
io.send(peer, packet_id, rlp_stream.out())
|
||||
.unwrap_or_else(|e| debug!(target: "sync", "{:?}", error_func(e)));
|
||||
Ok(())
|
||||
|
@ -68,6 +68,7 @@ use self::SyncPacket::*;
|
||||
pub trait PacketInfo {
|
||||
fn id(&self) -> PacketId;
|
||||
fn protocol(&self) -> ProtocolId;
|
||||
fn has_request_id_in_eth_66(&self) -> bool;
|
||||
}
|
||||
|
||||
// The mechanism to match packet ids and protocol may be improved
|
||||
@ -102,6 +103,21 @@ impl PacketInfo for SyncPacket {
|
||||
fn id(&self) -> PacketId {
|
||||
(*self) as PacketId
|
||||
}
|
||||
|
||||
fn has_request_id_in_eth_66(&self) -> bool {
|
||||
// Note: NodeDataPacket and GetNodeDataPacket also get a request id in eth-66.
|
||||
match self {
|
||||
GetBlockHeadersPacket
|
||||
| BlockHeadersPacket
|
||||
| GetBlockBodiesPacket
|
||||
| BlockBodiesPacket
|
||||
| GetPooledTransactionsPacket
|
||||
| PooledTransactionsPacket
|
||||
| GetReceiptsPacket
|
||||
| ReceiptsPacket => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -18,7 +18,7 @@ use api::PAR_PROTOCOL;
|
||||
use bytes::Bytes;
|
||||
use chain::{
|
||||
sync_packet::{PacketInfo, SyncPacket},
|
||||
ChainSync, ForkFilterApi, SyncSupplier, ETH_PROTOCOL_VERSION_65, PAR_PROTOCOL_VERSION_2,
|
||||
ChainSync, ForkFilterApi, SyncSupplier, ETH_PROTOCOL_VERSION_66, PAR_PROTOCOL_VERSION_2,
|
||||
};
|
||||
use ethcore::{
|
||||
client::{
|
||||
@ -172,7 +172,7 @@ where
|
||||
if protocol == PAR_PROTOCOL {
|
||||
PAR_PROTOCOL_VERSION_2.0
|
||||
} else {
|
||||
ETH_PROTOCOL_VERSION_65.0
|
||||
ETH_PROTOCOL_VERSION_66.0
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user