Implement ETH P2P (#81)

* refactor: move things to types

* feat(ethwire): bring in message type from ethp2p

30c11138d5/src/message.rs

* feat(ethwire): add eth-stream with Stream/Sink impls

* feat(ethwire): make Sink error an EthStreamError

* feat(ecies): expose util module

* add more deps

* feat: add broadcast newblockhashes

* fix: rlp serialize with message-id first

* chore: cleanup doc

* wip: test eth connection

* bump cargo lock

* feat: add rlp codec and get stream tests working

* fix: convert RlpCodec to PassthroughCodec

we were rlp encoding twice

* Revert "fix: convert RlpCodec to PassthroughCodec"

This reverts commit 6e6e0a58112c14d7ffba62dc83f9747ddc280641.

This does not handle framing, which would fail decoding if a partial
write happened to the socket.

* add tracing

* refactor: add handshake error

* feat(ethwire): add status handshake

* test(ethwire): handshake works

* refactor: expose EthStream::new

* chore: clippy lints

* fix: get rid of rlp codec

we can instead use LengthLimitedCodec from Tokio IO, which we re-export
as PassthroughCodec

* fix(eth): add handshake + msg error checks

1. 10MB message lengths
2. Same Genesis, Version, Chain on Status Handshake

* chore: ignore result_large_err

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Georgios Konstantopoulos
2022-10-16 20:10:25 -07:00
committed by GitHub
parent 5dfe5ac29b
commit 8009d997c0
18 changed files with 805 additions and 27 deletions

View File

@ -2,7 +2,7 @@ use crate::{
algorithm::{ECIES, MAX_BODY_SIZE},
ECIESError, EgressECIESValue, IngressECIESValue,
};
use bytes::{Bytes, BytesMut};
use bytes::BytesMut;
use reth_primitives::H512 as PeerId;
use secp256k1::SecretKey;
use std::{fmt::Debug, io};
@ -105,7 +105,8 @@ impl Decoder for ECIESCodec {
}
let mut data = buf.split_to(self.ecies.body_len());
let ret = Bytes::copy_from_slice(self.ecies.read_body(&mut data)?);
let mut ret = BytesMut::new();
ret.extend_from_slice(self.ecies.read_body(&mut data)?);
self.state = ECIESState::Header;
return Ok(Some(IngressECIESValue::Message(ret)))

View File

@ -1,6 +1,5 @@
use thiserror::Error;
use crate::IngressECIESValue;
use thiserror::Error;
/// An error that occurs while reading or writing to an ECIES stream.
#[derive(Debug, Error)]

View File

@ -1,3 +1,4 @@
#![allow(clippy::result_large_err)]
#![warn(missing_docs, unreachable_pub)]
#![deny(unused_must_use, rust_2018_idioms)]
#![doc(test(
@ -10,7 +11,7 @@
pub mod algorithm;
pub mod mac;
pub mod stream;
mod util;
pub mod util;
mod error;
pub use error::ECIESError;
@ -38,5 +39,5 @@ pub enum IngressECIESValue {
/// Receiving an ACK message
Ack,
/// Receiving a message
Message(bytes::Bytes),
Message(bytes::BytesMut),
}

View File

@ -1,5 +1,5 @@
//! The ECIES Stream implementation which wraps over [`AsyncRead`] and [`AsyncWrite`].
use crate::{ECIESError, EgressECIESValue, IngressECIESValue};
use crate::{codec::ECIESCodec, ECIESError, EgressECIESValue, IngressECIESValue};
use bytes::Bytes;
use futures::{ready, Sink, SinkExt};
use reth_primitives::H512 as PeerId;
@ -19,8 +19,6 @@ use tokio_stream::{Stream, StreamExt};
use tokio_util::codec::{Decoder, Framed};
use tracing::{debug, instrument, trace};
use crate::codec::ECIESCodec;
/// `ECIES` stream over TCP exchanging raw bytes
#[derive(Debug)]
pub struct ECIESStream<Io> {
@ -106,7 +104,7 @@ impl<Io> Stream for ECIESStream<Io>
where
Io: AsyncRead + Unpin,
{
type Item = Result<Bytes, io::Error>;
type Item = Result<bytes::BytesMut, io::Error>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match ready!(Pin::new(&mut self.get_mut().stream).poll_next(cx)) {
@ -156,8 +154,6 @@ mod tests {
use super::*;
#[tokio::test]
// TODO: implement test for the proposed
// API: https://github.com/foundry-rs/reth/issues/64#issue-1408708420
async fn can_write_and_read() {
let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
let server_key = SecretKey::new(&mut rand::thread_rng());

View File

@ -1,3 +1,5 @@
//! Utility functions for hashing and encoding.
use hmac::{Hmac, Mac};
use reth_primitives::{H256, H512 as PeerId};
use secp256k1::PublicKey;
@ -22,7 +24,7 @@ pub(crate) fn hmac_sha256(key: &[u8], input: &[&[u8]], auth_data: &[u8]) -> H256
/// Converts a [secp256k1::PublicKey] to a [PeerId] by stripping the
/// SECP256K1_TAG_PUBKEY_UNCOMPRESSED tag and storing the rest of the slice in the [PeerId].
pub(crate) fn pk2id(pk: &PublicKey) -> PeerId {
pub fn pk2id(pk: &PublicKey) -> PeerId {
PeerId::from_slice(&pk.serialize_uncompressed()[1..])
}