mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(eth): add remaining eth protocol message types (#82)
* chore: port over remaining types from ethp2p https://github.com/Rjected/ethp2p/ * replace fastrlp with reth_rlp * use correct type for tx messages * encoding / decoding still todo * derive Default for AccessList * export receipts * also add Hash to more types * fix receipts tests * remove unused receipts test imports * add convenience methods on transaction * add block body * move blockbody to eth-wire, uncomment wire type * uncomment rest of messages * TODO: refactor tests and make tests pass * use U128 instead of Uint for td * expose wire types * use reth_eth_wire instead of ethp2p * expose Signature * refactor pooled transaction tests * fix hash calculation * do not hash the entire buffer * uncomment block test and make clippy happy * module-level documentation for message types * apply a clippy fix * cargo fmt * actually make clippy happy * use H256 instead of [u8; 32] * use partition in split_transaction_by_hashes instead of peekable Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
e7851492b1
commit
c277015f5c
@ -12,5 +12,6 @@ pub use tokio_util::codec::{
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
mod stream;
|
mod stream;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub use types::*;
|
||||||
|
|
||||||
pub use stream::EthStream;
|
pub use stream::EthStream;
|
||||||
|
|||||||
545
crates/net/eth-wire/src/types/blocks.rs
Normal file
545
crates/net/eth-wire/src/types/blocks.rs
Normal file
@ -0,0 +1,545 @@
|
|||||||
|
//! Implements the `GetBlockHeaders`, `GetBlockBodies`, `BlockHeaders`, and `BlockBodies` message
|
||||||
|
//! types.
|
||||||
|
use reth_primitives::{Header, TransactionSigned, H256};
|
||||||
|
use reth_rlp::{
|
||||||
|
Decodable, DecodeError, Encodable, RlpDecodable, RlpDecodableWrapper, RlpEncodable,
|
||||||
|
RlpEncodableWrapper,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::RawBlockBody;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
/// Either a block hash _or_ a block number
|
||||||
|
pub enum BlockHashOrNumber {
|
||||||
|
/// A block hash
|
||||||
|
Hash(H256),
|
||||||
|
/// A block number
|
||||||
|
Number(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows for RLP encoding of either a block hash or block number
|
||||||
|
impl Encodable for BlockHashOrNumber {
|
||||||
|
fn length(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
Self::Hash(block_hash) => block_hash.length(),
|
||||||
|
Self::Number(block_number) => block_number.length(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn encode(&self, out: &mut dyn bytes::BufMut) {
|
||||||
|
match self {
|
||||||
|
Self::Hash(block_hash) => block_hash.encode(out),
|
||||||
|
Self::Number(block_number) => block_number.encode(out),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Allows for RLP decoding of a block hash or block number
|
||||||
|
impl Decodable for BlockHashOrNumber {
|
||||||
|
fn decode(buf: &mut &[u8]) -> Result<Self, DecodeError> {
|
||||||
|
let header: u8 = *buf.first().ok_or(DecodeError::InputTooShort)?;
|
||||||
|
// if the byte string is exactly 32 bytes, decode it into a Hash
|
||||||
|
// 0xa0 = 0x80 (start of string) + 0x20 (32, length of string)
|
||||||
|
if header == 0xa0 {
|
||||||
|
// strip the first byte, parsing the rest of the string.
|
||||||
|
// If the rest of the string fails to decode into 32 bytes, we'll bubble up the
|
||||||
|
// decoding error.
|
||||||
|
let hash = H256::decode(buf)?;
|
||||||
|
Ok(Self::Hash(hash))
|
||||||
|
} else {
|
||||||
|
// a block number when encoded as bytes ranges from 0 to any number of bytes - we're
|
||||||
|
// going to accept numbers which fit in less than 64 bytes.
|
||||||
|
// Any data larger than this which is not caught by the Hash decoding should error and
|
||||||
|
// is considered an invalid block number.
|
||||||
|
Ok(Self::Number(u64::decode(buf)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A request for a peer to return block headers starting at the requested block.
|
||||||
|
/// The peer must return at most [`limit`](#structfield.limit) headers.
|
||||||
|
/// If the [`reverse`](#structfield.reverse) field is `true`, the headers will be returned starting
|
||||||
|
/// at [`start_block`](#structfield.start_block), traversing towards the genesis block.
|
||||||
|
/// Otherwise, headers will be returned starting at [`start_block`](#structfield.start_block),
|
||||||
|
/// traversing towards the latest block.
|
||||||
|
///
|
||||||
|
/// If the [`skip`](#structfield.skip) field is non-zero, the peer must skip that amount of headers
|
||||||
|
/// in the the direction specified by [`reverse`](#structfield.reverse).
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable)]
|
||||||
|
pub struct GetBlockHeaders {
|
||||||
|
/// The block number or hash that the peer should start returning headers from.
|
||||||
|
pub start_block: BlockHashOrNumber,
|
||||||
|
|
||||||
|
/// The maximum number of headers to return.
|
||||||
|
pub limit: u64,
|
||||||
|
|
||||||
|
/// The number of blocks that the node should skip while traversing and returning headers.
|
||||||
|
/// A skip value of zero denotes that the peer should return contiguous heaaders, starting from
|
||||||
|
/// [`start_block`](#structfield.start_block) and returning at most
|
||||||
|
/// [`limit`](#structfield.limit) headers.
|
||||||
|
pub skip: u32,
|
||||||
|
|
||||||
|
/// Whether or not the headers should be returned in reverse order.
|
||||||
|
pub reverse: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The response to [`GetBlockHeaders`], containing headers if any headers were found.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct BlockHeaders(
|
||||||
|
/// The requested headers.
|
||||||
|
pub Vec<Header>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl From<Vec<Header>> for BlockHeaders {
|
||||||
|
fn from(headers: Vec<Header>) -> Self {
|
||||||
|
BlockHeaders(headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A request for a peer to return block bodies for the given block hashes.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct GetBlockBodies(
|
||||||
|
/// The block hashes to request bodies for.
|
||||||
|
pub Vec<H256>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl From<Vec<H256>> for GetBlockBodies {
|
||||||
|
fn from(hashes: Vec<H256>) -> Self {
|
||||||
|
GetBlockBodies(hashes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A response to [`GetBlockBodies`], containing bodies if any bodies were found.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable)]
|
||||||
|
pub struct BlockBody {
|
||||||
|
/// Transactions in the block
|
||||||
|
pub transactions: Vec<TransactionSigned>,
|
||||||
|
/// Uncle headers for the given block
|
||||||
|
pub ommers: Vec<Header>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockBody {
|
||||||
|
/// Create a [`Block`] from the body and its header.
|
||||||
|
pub fn create_block(&self, header: &Header) -> RawBlockBody {
|
||||||
|
RawBlockBody {
|
||||||
|
header: header.clone(),
|
||||||
|
transactions: self.transactions.clone(),
|
||||||
|
ommers: self.ommers.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The response to [`GetBlockBodies`], containing the block bodies that the peer knows about if
|
||||||
|
/// any were found.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct BlockBodies(
|
||||||
|
/// The requested block bodies, each of which should correspond to a hash in the request.
|
||||||
|
pub Vec<BlockBody>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl From<Vec<BlockBody>> for BlockBodies {
|
||||||
|
fn from(bodies: Vec<BlockBody>) -> Self {
|
||||||
|
BlockBodies(bodies)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crate::types::{
|
||||||
|
message::RequestPair, BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders,
|
||||||
|
};
|
||||||
|
use hex_literal::hex;
|
||||||
|
use reth_primitives::{
|
||||||
|
Header, Signature, Transaction, TransactionKind, TransactionSigned, U256,
|
||||||
|
};
|
||||||
|
use reth_rlp::{Decodable, Encodable};
|
||||||
|
|
||||||
|
use super::{BlockBody, BlockHashOrNumber};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_hash() {
|
||||||
|
// this is a valid 32 byte rlp string
|
||||||
|
let rlp = hex!("a0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
let decoded_number = BlockHashOrNumber::decode(&mut &rlp[..]).unwrap();
|
||||||
|
let full_bytes = [0xff; 32].into();
|
||||||
|
let expected = BlockHashOrNumber::Hash(full_bytes);
|
||||||
|
assert_eq!(expected, decoded_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_number() {
|
||||||
|
// this is a valid 64 bit number
|
||||||
|
let rlp = hex!("88ffffffffffffffff");
|
||||||
|
let decoded_number = BlockHashOrNumber::decode(&mut &rlp[..]).unwrap();
|
||||||
|
let expected = BlockHashOrNumber::Number(u64::MAX);
|
||||||
|
assert_eq!(expected, decoded_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_largest_single_byte() {
|
||||||
|
// the largest single byte is 0x7f, so we should be able to decode this into a u64
|
||||||
|
let rlp = hex!("7f");
|
||||||
|
let decoded_number = BlockHashOrNumber::decode(&mut &rlp[..]).unwrap();
|
||||||
|
let expected = BlockHashOrNumber::Number(0x7fu64);
|
||||||
|
assert_eq!(expected, decoded_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_long_hash() {
|
||||||
|
// let's try a 33 byte long string
|
||||||
|
// 0xa1 = 0x80 (start of string) + 0x21 (33, length of string)
|
||||||
|
let long_rlp = hex!("a1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
let decode_result = BlockHashOrNumber::decode(&mut &long_rlp[..]);
|
||||||
|
if decode_result.is_ok() {
|
||||||
|
panic!("Decoding a bytestring longer than 32 bytes should not decode successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_long_number() {
|
||||||
|
// let's try a 72 bit number
|
||||||
|
// 0x89 = 0x80 (start of string) + 0x09 (9, length of string)
|
||||||
|
let long_number = hex!("89ffffffffffffffffff");
|
||||||
|
let decode_result = BlockHashOrNumber::decode(&mut &long_number[..]);
|
||||||
|
if decode_result.is_ok() {
|
||||||
|
panic!("Decoding a number longer than 64 bits (but not exactly 32 bytes) should not decode successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_get_block_header() {
|
||||||
|
let expected = hex!(
|
||||||
|
"e8820457e4a000000000000000000000000000000000000000000000000000000000deadc0de050580"
|
||||||
|
);
|
||||||
|
let mut data = vec![];
|
||||||
|
RequestPair::<GetBlockHeaders> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetBlockHeaders {
|
||||||
|
start_block: BlockHashOrNumber::Hash(
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
),
|
||||||
|
limit: 5,
|
||||||
|
skip: 5,
|
||||||
|
reverse: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_get_block_header() {
|
||||||
|
let data = hex!(
|
||||||
|
"e8820457e4a000000000000000000000000000000000000000000000000000000000deadc0de050580"
|
||||||
|
);
|
||||||
|
let expected = RequestPair::<GetBlockHeaders> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetBlockHeaders {
|
||||||
|
start_block: BlockHashOrNumber::Hash(
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
),
|
||||||
|
limit: 5,
|
||||||
|
skip: 5,
|
||||||
|
reverse: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let result = RequestPair::decode(&mut &data[..]);
|
||||||
|
assert_eq!(result.unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_get_block_header_number() {
|
||||||
|
let expected = hex!("ca820457c682270f050580");
|
||||||
|
let mut data = vec![];
|
||||||
|
RequestPair::<GetBlockHeaders> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetBlockHeaders {
|
||||||
|
start_block: BlockHashOrNumber::Number(9999),
|
||||||
|
limit: 5,
|
||||||
|
skip: 5,
|
||||||
|
reverse: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_get_block_header_number() {
|
||||||
|
let data = hex!("ca820457c682270f050580");
|
||||||
|
let expected = RequestPair::<GetBlockHeaders> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetBlockHeaders {
|
||||||
|
start_block: BlockHashOrNumber::Number(9999),
|
||||||
|
limit: 5,
|
||||||
|
skip: 5,
|
||||||
|
reverse: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let result = RequestPair::decode(&mut &data[..]);
|
||||||
|
assert_eq!(result.unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_block_header() {
|
||||||
|
// [ (f90202) 0x0457 = 1111, [ (f901fc) [ (f901f9) header ] ] ]
|
||||||
|
let expected = hex!("f90202820457f901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000");
|
||||||
|
let mut data = vec![];
|
||||||
|
RequestPair::<BlockHeaders> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: BlockHeaders(vec![
|
||||||
|
Header {
|
||||||
|
parent_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
ommers_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
beneficiary: hex!("0000000000000000000000000000000000000000").into(),
|
||||||
|
state_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
transactions_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
receipts_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
difficulty: 0x8aeu64.into(),
|
||||||
|
number: 0xd05u64,
|
||||||
|
gas_limit: 0x115cu64,
|
||||||
|
gas_used: 0x15b3u64,
|
||||||
|
timestamp: 0x1a0au64,
|
||||||
|
extra_data: hex!("7788")[..].into(),
|
||||||
|
mix_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
nonce: 0x0000000000000000u64,
|
||||||
|
base_fee_per_gas: None,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
}.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_block_header() {
|
||||||
|
let data = hex!("f90202820457f901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000");
|
||||||
|
let expected = RequestPair::<BlockHeaders> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: BlockHeaders(vec![
|
||||||
|
Header {
|
||||||
|
parent_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
ommers_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
beneficiary: hex!("0000000000000000000000000000000000000000").into(),
|
||||||
|
state_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
transactions_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
receipts_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
logs_bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
difficulty: 0x8aeu64.into(),
|
||||||
|
number: 0xd05u64,
|
||||||
|
gas_limit: 0x115cu64,
|
||||||
|
gas_used: 0x15b3u64,
|
||||||
|
timestamp: 0x1a0au64,
|
||||||
|
extra_data: hex!("7788")[..].into(),
|
||||||
|
mix_hash: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
nonce: 0x0000000000000000u64,
|
||||||
|
base_fee_per_gas: None,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
let result = RequestPair::decode(&mut &data[..]);
|
||||||
|
assert_eq!(result.unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_get_block_bodies() {
|
||||||
|
let expected = hex!("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef");
|
||||||
|
let mut data = vec![];
|
||||||
|
RequestPair::<GetBlockBodies> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetBlockBodies(vec![
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_get_block_bodies() {
|
||||||
|
let data = hex!("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef");
|
||||||
|
let expected = RequestPair::<GetBlockBodies> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetBlockBodies(vec![
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
let result = RequestPair::decode(&mut &data[..]);
|
||||||
|
assert_eq!(result.unwrap(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_block_bodies() {
|
||||||
|
let expected =
|
||||||
|
hex!("f902dc820457f902d6f902d3f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afbf901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
|
||||||
|
);
|
||||||
|
let mut data = vec![];
|
||||||
|
let request = RequestPair::<BlockBodies> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: BlockBodies(vec![
|
||||||
|
BlockBody {
|
||||||
|
transactions: vec![
|
||||||
|
TransactionSigned::from_transaction_and_signature(Transaction::Legacy {
|
||||||
|
chain_id: Some(1),
|
||||||
|
nonce: 0x8u64,
|
||||||
|
gas_price: 0x4a817c808u64,
|
||||||
|
gas_limit: 0x2e248u64,
|
||||||
|
to:
|
||||||
|
TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()),
|
||||||
|
value: 0x200u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r:
|
||||||
|
U256::from_str("64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
|
||||||
|
s:
|
||||||
|
U256::from_str("64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(Transaction::Legacy {
|
||||||
|
chain_id: Some(1),
|
||||||
|
nonce: 0x9u64,
|
||||||
|
gas_price: 0x4a817c809u64,
|
||||||
|
gas_limit: 0x33450u64,
|
||||||
|
to:
|
||||||
|
TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()),
|
||||||
|
value: 0x2d9u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
}, Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r:
|
||||||
|
U256::from_str("52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||||
|
s:
|
||||||
|
U256::from_str("52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ommers: vec![
|
||||||
|
Header {
|
||||||
|
parent_hash:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
ommers_hash:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
beneficiary: hex!("0000000000000000000000000000000000000000").into(),
|
||||||
|
state_root:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
transactions_root:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
receipts_root:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
logs_bloom:
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
).into(), difficulty: 0x8aeu64.into(),
|
||||||
|
number: 0xd05u64,
|
||||||
|
gas_limit: 0x115cu64,
|
||||||
|
gas_used: 0x15b3u64,
|
||||||
|
timestamp: 0x1a0au64,
|
||||||
|
extra_data: hex!("7788")[..].into(),
|
||||||
|
mix_hash:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
nonce: 0x0000000000000000u64,
|
||||||
|
base_fee_per_gas: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
request.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_block_bodies() {
|
||||||
|
let data =
|
||||||
|
hex!("f902dc820457f902d6f902d3f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afbf901fcf901f9a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000940000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008208ae820d0582115c8215b3821a0a827788a00000000000000000000000000000000000000000000000000000000000000000880000000000000000"
|
||||||
|
);
|
||||||
|
let expected = RequestPair::<BlockBodies> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: BlockBodies(vec![
|
||||||
|
BlockBody {
|
||||||
|
transactions: vec![
|
||||||
|
TransactionSigned::from_transaction_and_signature(Transaction::Legacy {
|
||||||
|
chain_id: Some(1),
|
||||||
|
nonce: 0x8u64,
|
||||||
|
gas_price: 0x4a817c808u64,
|
||||||
|
gas_limit: 0x2e248u64,
|
||||||
|
to:
|
||||||
|
TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()),
|
||||||
|
value: 0x200u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r:
|
||||||
|
U256::from_str("64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12").unwrap(),
|
||||||
|
s:
|
||||||
|
U256::from_str("64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10").unwrap(),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(Transaction::Legacy {
|
||||||
|
chain_id: Some(1),
|
||||||
|
nonce: 0x9u64,
|
||||||
|
gas_price: 0x4a817c809u64,
|
||||||
|
gas_limit: 0x33450u64,
|
||||||
|
to:
|
||||||
|
TransactionKind::Call(hex!("3535353535353535353535353535353535353535").into()),
|
||||||
|
value: 0x2d9u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r:
|
||||||
|
U256::from_str("52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||||
|
s:
|
||||||
|
U256::from_str("52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb").unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ommers: vec![
|
||||||
|
Header {
|
||||||
|
parent_hash:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
ommers_hash:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
beneficiary: hex!("0000000000000000000000000000000000000000").into(),
|
||||||
|
state_root:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
transactions_root:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
receipts_root:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
logs_bloom:
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
).into(), difficulty: 0x8aeu64.into(),
|
||||||
|
number: 0xd05u64,
|
||||||
|
gas_limit: 0x115cu64,
|
||||||
|
gas_used: 0x15b3u64,
|
||||||
|
timestamp: 0x1a0au64,
|
||||||
|
extra_data: hex!("7788")[..].into(),
|
||||||
|
mix_hash:
|
||||||
|
hex!("0000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
nonce: 0x0000000000000000u64,
|
||||||
|
base_fee_per_gas: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
let result = RequestPair::decode(&mut &data[..]).unwrap();
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
//! Types for broadcasting new data.
|
//! Types for broadcasting new data.
|
||||||
|
use reth_primitives::{Header, TransactionSigned, H256, U128};
|
||||||
use reth_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
|
use reth_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
|
||||||
|
|
||||||
/// This informs peers of new blocks that have appeared on the network.
|
/// This informs peers of new blocks that have appeared on the network.
|
||||||
@ -13,7 +14,7 @@ pub struct NewBlockHashes(
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable)]
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable)]
|
||||||
pub struct BlockHashNumber {
|
pub struct BlockHashNumber {
|
||||||
/// The block hash
|
/// The block hash
|
||||||
pub hash: reth_primitives::H256,
|
pub hash: H256,
|
||||||
/// The block number
|
/// The block number
|
||||||
pub number: u64,
|
pub number: u64,
|
||||||
}
|
}
|
||||||
@ -29,3 +30,60 @@ impl From<NewBlockHashes> for Vec<BlockHashNumber> {
|
|||||||
v.0
|
v.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A block body, including transactions and uncle headers.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
|
||||||
|
pub struct RawBlockBody {
|
||||||
|
/// This block's header
|
||||||
|
pub header: Header,
|
||||||
|
/// Transactions in this block.
|
||||||
|
pub transactions: Vec<TransactionSigned>,
|
||||||
|
/// Uncle block headers.
|
||||||
|
pub ommers: Vec<Header>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A new block with the current total difficulty, which includes the difficulty of the returned
|
||||||
|
/// block.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodable, RlpDecodable)]
|
||||||
|
pub struct NewBlock {
|
||||||
|
/// A new block.
|
||||||
|
pub block: RawBlockBody,
|
||||||
|
/// The current total difficulty.
|
||||||
|
pub td: U128,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This informs peers of transactions that have appeared on the network and are not yet included
|
||||||
|
/// in a block.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct Transactions(
|
||||||
|
/// New transactions for the peer to include in its mempool.
|
||||||
|
pub Vec<TransactionSigned>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl From<Vec<TransactionSigned>> for Transactions {
|
||||||
|
fn from(txs: Vec<TransactionSigned>) -> Self {
|
||||||
|
Transactions(txs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Transactions> for Vec<TransactionSigned> {
|
||||||
|
fn from(txs: Transactions) -> Self {
|
||||||
|
txs.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This informs peers of transaction hashes for transactions that have appeared on the network,
|
||||||
|
/// but have not been included in a block.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct NewPooledTransactionHashes(
|
||||||
|
/// Transaction hashes for new transactions that have appeared on the network.
|
||||||
|
/// Clients should request the transactions with the given hashes using a
|
||||||
|
/// [`GetPooledTransactions`](crate::GetPooledTransactions) message.
|
||||||
|
pub Vec<H256>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl From<Vec<H256>> for NewPooledTransactionHashes {
|
||||||
|
fn from(v: Vec<H256>) -> Self {
|
||||||
|
NewPooledTransactionHashes(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
#![allow(missing_docs)]
|
#![allow(missing_docs)]
|
||||||
use super::{broadcast::NewBlockHashes, Status};
|
use super::{
|
||||||
|
broadcast::NewBlockHashes, BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders,
|
||||||
|
GetNodeData, GetPooledTransactions, GetReceipts, NewBlock, NewPooledTransactionHashes,
|
||||||
|
NodeData, PooledTransactions, Receipts, Status, Transactions,
|
||||||
|
};
|
||||||
use bytes::Buf;
|
use bytes::Buf;
|
||||||
use reth_rlp::{length_of_length, Decodable, Encodable, Header};
|
use reth_rlp::{length_of_length, Decodable, Encodable, Header};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@ -22,52 +26,51 @@ impl ProtocolMessage {
|
|||||||
EthMessageID::NewBlockHashes => {
|
EthMessageID::NewBlockHashes => {
|
||||||
EthMessage::NewBlockHashes(NewBlockHashes::decode(buf)?)
|
EthMessage::NewBlockHashes(NewBlockHashes::decode(buf)?)
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
EthMessageID::NewBlock => EthMessage::NewBlock(Box::new(NewBlock::decode(buf)?)),
|
||||||
// EthMessageID::NewBlock => EthMessage::NewBlock(Box::new(NewBlock::decode(buf)?)),
|
EthMessageID::Transactions => EthMessage::Transactions(Transactions::decode(buf)?),
|
||||||
// EthMessageID::Transactions => EthMessage::Transactions(Transactions::decode(buf)?),
|
EthMessageID::NewPooledTransactionHashes => {
|
||||||
// EthMessageID::NewPooledTransactionHashes => {
|
EthMessage::NewPooledTransactionHashes(NewPooledTransactionHashes::decode(buf)?)
|
||||||
// EthMessage::NewPooledTransactionHashes(NewPooledTransactionHashes::decode(buf)?)
|
}
|
||||||
// }
|
EthMessageID::GetBlockHeaders => {
|
||||||
// EthMessageID::GetBlockHeaders => {
|
let request_pair = RequestPair::<GetBlockHeaders>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<GetBlockHeaders>::decode(buf)?;
|
EthMessage::GetBlockHeaders(request_pair)
|
||||||
// EthMessage::GetBlockHeaders(request_pair)
|
}
|
||||||
// }
|
EthMessageID::BlockHeaders => {
|
||||||
// EthMessageID::BlockHeaders => {
|
let request_pair = RequestPair::<BlockHeaders>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<BlockHeaders>::decode(buf)?;
|
EthMessage::BlockHeaders(request_pair)
|
||||||
// EthMessage::BlockHeaders(request_pair)
|
}
|
||||||
// }
|
EthMessageID::GetBlockBodies => {
|
||||||
// EthMessageID::GetBlockBodies => {
|
let request_pair = RequestPair::<GetBlockBodies>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<GetBlockBodies>::decode(buf)?;
|
EthMessage::GetBlockBodies(request_pair)
|
||||||
// EthMessage::GetBlockBodies(request_pair)
|
}
|
||||||
// }
|
EthMessageID::BlockBodies => {
|
||||||
// EthMessageID::BlockBodies => {
|
let request_pair = RequestPair::<BlockBodies>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<BlockBodies>::decode(buf)?;
|
EthMessage::BlockBodies(request_pair)
|
||||||
// EthMessage::BlockBodies(request_pair)
|
}
|
||||||
// }
|
EthMessageID::GetPooledTransactions => {
|
||||||
// EthMessageID::GetPooledTransactions => {
|
let request_pair = RequestPair::<GetPooledTransactions>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<GetPooledTransactions>::decode(buf)?;
|
EthMessage::GetPooledTransactions(request_pair)
|
||||||
// EthMessage::GetPooledTransactions(request_pair)
|
}
|
||||||
// }
|
EthMessageID::PooledTransactions => {
|
||||||
// EthMessageID::PooledTransactions => {
|
let request_pair = RequestPair::<PooledTransactions>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<PooledTransactions>::decode(buf)?;
|
EthMessage::PooledTransactions(request_pair)
|
||||||
// EthMessage::PooledTransactions(request_pair)
|
}
|
||||||
// }
|
EthMessageID::GetNodeData => {
|
||||||
// EthMessageID::GetNodeData => {
|
let request_pair = RequestPair::<GetNodeData>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<GetNodeData>::decode(buf)?;
|
EthMessage::GetNodeData(request_pair)
|
||||||
// EthMessage::GetNodeData(request_pair)
|
}
|
||||||
// }
|
EthMessageID::NodeData => {
|
||||||
// EthMessageID::NodeData => {
|
let request_pair = RequestPair::<NodeData>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<NodeData>::decode(buf)?;
|
EthMessage::NodeData(request_pair)
|
||||||
// EthMessage::NodeData(request_pair)
|
}
|
||||||
// }
|
EthMessageID::GetReceipts => {
|
||||||
// EthMessageID::GetReceipts => {
|
let request_pair = RequestPair::<GetReceipts>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<GetReceipts>::decode(buf)?;
|
EthMessage::GetReceipts(request_pair)
|
||||||
// EthMessage::GetReceipts(request_pair)
|
}
|
||||||
// }
|
EthMessageID::Receipts => {
|
||||||
// EthMessageID::Receipts => {
|
let request_pair = RequestPair::<Receipts>::decode(buf)?;
|
||||||
// let request_pair = RequestPair::<Receipts>::decode(buf)?;
|
EthMessage::Receipts(request_pair)
|
||||||
// EthMessage::Receipts(request_pair)
|
}
|
||||||
// }
|
|
||||||
};
|
};
|
||||||
Ok(ProtocolMessage { message_type, message })
|
Ok(ProtocolMessage { message_type, message })
|
||||||
}
|
}
|
||||||
@ -116,23 +119,23 @@ impl From<EthMessage> for ProtocolMessage {
|
|||||||
pub enum EthMessage {
|
pub enum EthMessage {
|
||||||
// Status is required for the protocol handshake
|
// Status is required for the protocol handshake
|
||||||
Status(Status),
|
Status(Status),
|
||||||
// // The following messages are broadcast to the network
|
// The following messages are broadcast to the network
|
||||||
NewBlockHashes(NewBlockHashes),
|
NewBlockHashes(NewBlockHashes),
|
||||||
// NewBlock(Box<NewBlock>),
|
NewBlock(Box<NewBlock>),
|
||||||
// Transactions(Transactions),
|
Transactions(Transactions),
|
||||||
// NewPooledTransactionHashes(NewPooledTransactionHashes),
|
NewPooledTransactionHashes(NewPooledTransactionHashes),
|
||||||
|
|
||||||
// // The following messages are request-response message pairs
|
// The following messages are request-response message pairs
|
||||||
// GetBlockHeaders(RequestPair<GetBlockHeaders>),
|
GetBlockHeaders(RequestPair<GetBlockHeaders>),
|
||||||
// BlockHeaders(RequestPair<BlockHeaders>),
|
BlockHeaders(RequestPair<BlockHeaders>),
|
||||||
// GetBlockBodies(RequestPair<GetBlockBodies>),
|
GetBlockBodies(RequestPair<GetBlockBodies>),
|
||||||
// BlockBodies(RequestPair<BlockBodies>),
|
BlockBodies(RequestPair<BlockBodies>),
|
||||||
// GetPooledTransactions(RequestPair<GetPooledTransactions>),
|
GetPooledTransactions(RequestPair<GetPooledTransactions>),
|
||||||
// PooledTransactions(RequestPair<PooledTransactions>),
|
PooledTransactions(RequestPair<PooledTransactions>),
|
||||||
// GetNodeData(RequestPair<GetNodeData>),
|
GetNodeData(RequestPair<GetNodeData>),
|
||||||
// NodeData(RequestPair<NodeData>),
|
NodeData(RequestPair<NodeData>),
|
||||||
// GetReceipts(RequestPair<GetReceipts>),
|
GetReceipts(RequestPair<GetReceipts>),
|
||||||
// Receipts(RequestPair<Receipts>),
|
Receipts(RequestPair<Receipts>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EthMessage {
|
impl EthMessage {
|
||||||
@ -141,20 +144,19 @@ impl EthMessage {
|
|||||||
match self {
|
match self {
|
||||||
EthMessage::Status(_) => EthMessageID::Status,
|
EthMessage::Status(_) => EthMessageID::Status,
|
||||||
EthMessage::NewBlockHashes(_) => EthMessageID::NewBlockHashes,
|
EthMessage::NewBlockHashes(_) => EthMessageID::NewBlockHashes,
|
||||||
// EthMessage::NewBlock(_) => EthMessageID::NewBlock,
|
EthMessage::NewBlock(_) => EthMessageID::NewBlock,
|
||||||
// EthMessage::Transactions(_) => EthMessageID::Transactions,
|
EthMessage::Transactions(_) => EthMessageID::Transactions,
|
||||||
// EthMessage::NewPooledTransactionHashes(_) =>
|
EthMessage::NewPooledTransactionHashes(_) => EthMessageID::NewPooledTransactionHashes,
|
||||||
// EthMessageID::NewPooledTransactionHashes, EthMessage::GetBlockHeaders(_)
|
EthMessage::GetBlockHeaders(_) => EthMessageID::GetBlockHeaders,
|
||||||
// => EthMessageID::GetBlockHeaders, EthMessage::BlockHeaders(_) =>
|
EthMessage::BlockHeaders(_) => EthMessageID::BlockHeaders,
|
||||||
// EthMessageID::BlockHeaders, EthMessage::GetBlockBodies(_) =>
|
EthMessage::GetBlockBodies(_) => EthMessageID::GetBlockBodies,
|
||||||
// EthMessageID::GetBlockBodies, EthMessage::BlockBodies(_) =>
|
EthMessage::BlockBodies(_) => EthMessageID::BlockBodies,
|
||||||
// EthMessageID::BlockBodies, EthMessage::GetPooledTransactions(_) =>
|
EthMessage::GetPooledTransactions(_) => EthMessageID::GetPooledTransactions,
|
||||||
// EthMessageID::GetPooledTransactions, EthMessage::PooledTransactions(_) =>
|
EthMessage::PooledTransactions(_) => EthMessageID::PooledTransactions,
|
||||||
// EthMessageID::PooledTransactions, EthMessage::GetNodeData(_) =>
|
EthMessage::GetNodeData(_) => EthMessageID::GetNodeData,
|
||||||
// EthMessageID::GetNodeData, EthMessage::NodeData(_) =>
|
EthMessage::NodeData(_) => EthMessageID::NodeData,
|
||||||
// EthMessageID::NodeData, EthMessage::GetReceipts(_) =>
|
EthMessage::GetReceipts(_) => EthMessageID::GetReceipts,
|
||||||
// EthMessageID::GetReceipts, EthMessage::Receipts(_) =>
|
EthMessage::Receipts(_) => EthMessageID::Receipts,
|
||||||
// EthMessageID::Receipts,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,38 +166,38 @@ impl Encodable for EthMessage {
|
|||||||
match self {
|
match self {
|
||||||
EthMessage::Status(status) => status.length(),
|
EthMessage::Status(status) => status.length(),
|
||||||
EthMessage::NewBlockHashes(new_block_hashes) => new_block_hashes.length(),
|
EthMessage::NewBlockHashes(new_block_hashes) => new_block_hashes.length(),
|
||||||
// EthMessage::NewBlock(new_block) => new_block.length(),
|
EthMessage::NewBlock(new_block) => new_block.length(),
|
||||||
// EthMessage::Transactions(transactions) => transactions.length(),
|
EthMessage::Transactions(transactions) => transactions.length(),
|
||||||
// EthMessage::NewPooledTransactionHashes(hashes) => hashes.length(),
|
EthMessage::NewPooledTransactionHashes(hashes) => hashes.length(),
|
||||||
// EthMessage::GetBlockHeaders(request) => request.length(),
|
EthMessage::GetBlockHeaders(request) => request.length(),
|
||||||
// EthMessage::BlockHeaders(headers) => headers.length(),
|
EthMessage::BlockHeaders(headers) => headers.length(),
|
||||||
// EthMessage::GetBlockBodies(request) => request.length(),
|
EthMessage::GetBlockBodies(request) => request.length(),
|
||||||
// EthMessage::BlockBodies(bodies) => bodies.length(),
|
EthMessage::BlockBodies(bodies) => bodies.length(),
|
||||||
// EthMessage::GetPooledTransactions(request) => request.length(),
|
EthMessage::GetPooledTransactions(request) => request.length(),
|
||||||
// EthMessage::PooledTransactions(transactions) => transactions.length(),
|
EthMessage::PooledTransactions(transactions) => transactions.length(),
|
||||||
// EthMessage::GetNodeData(request) => request.length(),
|
EthMessage::GetNodeData(request) => request.length(),
|
||||||
// EthMessage::NodeData(data) => data.length(),
|
EthMessage::NodeData(data) => data.length(),
|
||||||
// EthMessage::GetReceipts(request) => request.length(),
|
EthMessage::GetReceipts(request) => request.length(),
|
||||||
// EthMessage::Receipts(receipts) => receipts.length(),
|
EthMessage::Receipts(receipts) => receipts.length(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn encode(&self, out: &mut dyn bytes::BufMut) {
|
fn encode(&self, out: &mut dyn bytes::BufMut) {
|
||||||
match self {
|
match self {
|
||||||
EthMessage::Status(status) => status.encode(out),
|
EthMessage::Status(status) => status.encode(out),
|
||||||
EthMessage::NewBlockHashes(new_block_hashes) => new_block_hashes.encode(out),
|
EthMessage::NewBlockHashes(new_block_hashes) => new_block_hashes.encode(out),
|
||||||
// EthMessage::NewBlock(new_block) => new_block.encode(out),
|
EthMessage::NewBlock(new_block) => new_block.encode(out),
|
||||||
// EthMessage::Transactions(transactions) => transactions.encode(out),
|
EthMessage::Transactions(transactions) => transactions.encode(out),
|
||||||
// EthMessage::NewPooledTransactionHashes(hashes) => hashes.encode(out),
|
EthMessage::NewPooledTransactionHashes(hashes) => hashes.encode(out),
|
||||||
// EthMessage::GetBlockHeaders(request) => request.encode(out),
|
EthMessage::GetBlockHeaders(request) => request.encode(out),
|
||||||
// EthMessage::BlockHeaders(headers) => headers.encode(out),
|
EthMessage::BlockHeaders(headers) => headers.encode(out),
|
||||||
// EthMessage::GetBlockBodies(request) => request.encode(out),
|
EthMessage::GetBlockBodies(request) => request.encode(out),
|
||||||
// EthMessage::BlockBodies(bodies) => bodies.encode(out),
|
EthMessage::BlockBodies(bodies) => bodies.encode(out),
|
||||||
// EthMessage::GetPooledTransactions(request) => request.encode(out),
|
EthMessage::GetPooledTransactions(request) => request.encode(out),
|
||||||
// EthMessage::PooledTransactions(transactions) => transactions.encode(out),
|
EthMessage::PooledTransactions(transactions) => transactions.encode(out),
|
||||||
// EthMessage::GetNodeData(request) => request.encode(out),
|
EthMessage::GetNodeData(request) => request.encode(out),
|
||||||
// EthMessage::NodeData(data) => data.encode(out),
|
EthMessage::NodeData(data) => data.encode(out),
|
||||||
// EthMessage::GetReceipts(request) => request.encode(out),
|
EthMessage::GetReceipts(request) => request.encode(out),
|
||||||
// EthMessage::Receipts(receipts) => receipts.encode(out),
|
EthMessage::Receipts(receipts) => receipts.encode(out),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,4 +11,17 @@ pub mod forkid;
|
|||||||
pub mod message;
|
pub mod message;
|
||||||
pub use message::{EthMessage, EthMessageID, ProtocolMessage};
|
pub use message::{EthMessage, EthMessageID, ProtocolMessage};
|
||||||
|
|
||||||
|
pub mod blocks;
|
||||||
|
pub use blocks::*;
|
||||||
|
|
||||||
pub mod broadcast;
|
pub mod broadcast;
|
||||||
|
pub use broadcast::*;
|
||||||
|
|
||||||
|
pub mod transactions;
|
||||||
|
pub use transactions::*;
|
||||||
|
|
||||||
|
pub mod state;
|
||||||
|
pub use state::*;
|
||||||
|
|
||||||
|
pub mod receipts;
|
||||||
|
pub use receipts::*;
|
||||||
|
|||||||
124
crates/net/eth-wire/src/types/receipts.rs
Normal file
124
crates/net/eth-wire/src/types/receipts.rs
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
//! Implements the `GetReceipts` and `Receipts` message types.
|
||||||
|
use reth_primitives::{Receipt, H256};
|
||||||
|
use reth_rlp::{RlpDecodableWrapper, RlpEncodableWrapper};
|
||||||
|
|
||||||
|
/// A request for transaction receipts from the given block hashes.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct GetReceipts(
|
||||||
|
/// The block hashes to request receipts for.
|
||||||
|
pub Vec<H256>,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// The response to [`GetReceipts`], containing receipt lists that correspond to each block
|
||||||
|
/// requested.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct Receipts(
|
||||||
|
/// Each receipt hash should correspond to a block hash in the request.
|
||||||
|
pub Vec<Vec<Receipt>>,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::types::{message::RequestPair, GetReceipts, Receipts};
|
||||||
|
use hex_literal::hex;
|
||||||
|
use reth_primitives::{Log, Receipt, TxType};
|
||||||
|
use reth_rlp::{Decodable, Encodable};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_get_receipts() {
|
||||||
|
let expected = hex!("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef");
|
||||||
|
let mut data = vec![];
|
||||||
|
let request = RequestPair::<GetReceipts> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetReceipts(vec![
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
request.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_get_receipts() {
|
||||||
|
let data = hex!("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef");
|
||||||
|
let request = RequestPair::<GetReceipts>::decode(&mut &data[..]).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
request,
|
||||||
|
RequestPair::<GetReceipts> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetReceipts(vec![
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_receipts() {
|
||||||
|
let expected = hex!("f90172820457f9016cf90169f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
|
||||||
|
let mut data = vec![];
|
||||||
|
let request = RequestPair::<Receipts> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: Receipts(vec![
|
||||||
|
vec![
|
||||||
|
Receipt {
|
||||||
|
tx_type: TxType::Legacy,
|
||||||
|
bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
cumulative_gas_used: 0x1u64,
|
||||||
|
logs: vec![
|
||||||
|
Log {
|
||||||
|
address: hex!("0000000000000000000000000000000000000011").into(),
|
||||||
|
topics: vec![
|
||||||
|
hex!("000000000000000000000000000000000000000000000000000000000000dead").into(),
|
||||||
|
hex!("000000000000000000000000000000000000000000000000000000000000beef").into(),
|
||||||
|
],
|
||||||
|
data: hex!("0100ff")[..].into(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
success: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
request.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_receipts() {
|
||||||
|
let data = hex!("f90172820457f9016cf90169f901668001b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff");
|
||||||
|
let request = RequestPair::<Receipts>::decode(&mut &data[..]).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
request,
|
||||||
|
RequestPair::<Receipts> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: Receipts(vec![
|
||||||
|
vec![
|
||||||
|
Receipt {
|
||||||
|
tx_type: TxType::Legacy,
|
||||||
|
bloom: hex!("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into(),
|
||||||
|
cumulative_gas_used: 0x1u64,
|
||||||
|
logs: vec![
|
||||||
|
Log {
|
||||||
|
address: hex!("0000000000000000000000000000000000000011").into(),
|
||||||
|
topics: vec![
|
||||||
|
hex!("000000000000000000000000000000000000000000000000000000000000dead").into(),
|
||||||
|
hex!("000000000000000000000000000000000000000000000000000000000000beef").into(),
|
||||||
|
],
|
||||||
|
data: hex!("0100ff")[..].into(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
success: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
crates/net/eth-wire/src/types/response.rs
Normal file
29
crates/net/eth-wire/src/types/response.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use crate::{
|
||||||
|
BlockBodies, BlockHeaders, NodeData, PooledTransactions, Receipts, RequestPair, Status,
|
||||||
|
};
|
||||||
|
|
||||||
|
// This type is analogous to the `zebra_network::Response` type.
|
||||||
|
/// An ethereum network response for version 66.
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum Response {
|
||||||
|
/// The request does not have a response.
|
||||||
|
Nil,
|
||||||
|
|
||||||
|
/// The [`Status`](super::Status) message response in the eth protocol handshake.
|
||||||
|
Status(Status),
|
||||||
|
|
||||||
|
/// The response to a [`Request::GetBlockHeaders`](super::Request::GetBlockHeaders) request.
|
||||||
|
BlockHeaders(RequestPair<BlockHeaders>),
|
||||||
|
|
||||||
|
/// The response to a [`Request::GetBlockBodies`](super::Request::GetBlockBodies) request.
|
||||||
|
BlockBodies(RequestPair<BlockBodies>),
|
||||||
|
|
||||||
|
/// The response to a [`Request::GetPooledTransactions`](super::Request::GetPooledTransactions) request.
|
||||||
|
PooledTransactions(RequestPair<PooledTransactions>),
|
||||||
|
|
||||||
|
/// The response to a [`Request::GetNodeData`](super::Request::GetNodeData) request.
|
||||||
|
NodeData(RequestPair<NodeData>),
|
||||||
|
|
||||||
|
/// The response to a [`Request::GetReceipts`](super::Request::GetReceipts) request.
|
||||||
|
Receipts(RequestPair<Receipts>),
|
||||||
|
}
|
||||||
91
crates/net/eth-wire/src/types/state.rs
Normal file
91
crates/net/eth-wire/src/types/state.rs
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
//! Implements the `GetNodeData` and `NodeData` message types.
|
||||||
|
use reth_primitives::H256;
|
||||||
|
use reth_rlp::{RlpDecodableWrapper, RlpEncodableWrapper};
|
||||||
|
|
||||||
|
/// A request for state tree nodes corresponding to the given hashes.
|
||||||
|
/// This message was removed in `eth/67`, only clients running `eth/66` or earlier will respond to
|
||||||
|
/// this message.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct GetNodeData(pub Vec<H256>);
|
||||||
|
|
||||||
|
/// The response to [`GetNodeData`], containing the state tree nodes or contract bytecode
|
||||||
|
/// corresponding to the requested hashes.
|
||||||
|
///
|
||||||
|
/// Not all nodes are guaranteed to be returned by the peer.
|
||||||
|
/// This message was removed in `eth/67`.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct NodeData(pub Vec<bytes::Bytes>);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use hex_literal::hex;
|
||||||
|
|
||||||
|
use crate::{message::RequestPair, GetNodeData, NodeData};
|
||||||
|
use reth_rlp::{Decodable, Encodable};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_get_node_data() {
|
||||||
|
let expected = hex!("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef");
|
||||||
|
let mut data = vec![];
|
||||||
|
let request = RequestPair::<GetNodeData> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetNodeData(vec![
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
request.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_get_node_data() {
|
||||||
|
let data = hex!("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef");
|
||||||
|
let request = RequestPair::<GetNodeData>::decode(&mut &data[..]).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
request,
|
||||||
|
RequestPair::<GetNodeData> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetNodeData(vec![
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_node_data() {
|
||||||
|
let expected = hex!("ce820457ca84deadc0de84feedbeef");
|
||||||
|
let mut data = vec![];
|
||||||
|
let request = RequestPair::<NodeData> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: NodeData(vec![
|
||||||
|
hex!("deadc0de").as_slice().into(),
|
||||||
|
hex!("feedbeef").as_slice().into(),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
request.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_node_data() {
|
||||||
|
let data = hex!("ce820457ca84deadc0de84feedbeef");
|
||||||
|
let request = RequestPair::<NodeData>::decode(&mut &data[..]).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
request,
|
||||||
|
RequestPair::<NodeData> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: NodeData(vec![
|
||||||
|
hex!("deadc0de").as_slice().into(),
|
||||||
|
hex!("feedbeef").as_slice().into(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
548
crates/net/eth-wire/src/types/transactions.rs
Normal file
548
crates/net/eth-wire/src/types/transactions.rs
Normal file
@ -0,0 +1,548 @@
|
|||||||
|
//! Implements the `GetPooledTransactions` and `PooledTransactions` message types.
|
||||||
|
use reth_primitives::{TransactionSigned, H256};
|
||||||
|
use reth_rlp::{RlpDecodableWrapper, RlpEncodableWrapper};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// A list of transaction hashes that the peer would like transaction bodies for.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct GetPooledTransactions(
|
||||||
|
/// The transaction hashes to request transaction bodies for.
|
||||||
|
pub Vec<H256>,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl<T> From<Vec<T>> for GetPooledTransactions
|
||||||
|
where
|
||||||
|
T: Into<H256>,
|
||||||
|
{
|
||||||
|
fn from(hashes: Vec<T>) -> Self {
|
||||||
|
GetPooledTransactions(hashes.into_iter().map(|h| h.into()).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The response to [`GetPooledTransactions`], containing the transaction bodies associated with
|
||||||
|
/// the requested hashes.
|
||||||
|
///
|
||||||
|
/// This response may not contain all bodies requested, but the bodies should be in the same order
|
||||||
|
/// as the request's hashes. Hashes may be skipped, and the client should ensure that each body
|
||||||
|
/// corresponds to a requested hash. Hashes may need to be re-requested if the bodies are not
|
||||||
|
/// included in the response.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, RlpEncodableWrapper, RlpDecodableWrapper)]
|
||||||
|
pub struct PooledTransactions(
|
||||||
|
/// The transaction bodies, each of which should correspond to a requested hash.
|
||||||
|
pub Vec<TransactionSigned>,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// An error that may occur while matching a [`GetPooledTransactions`] request to a
|
||||||
|
/// [`PooledTransactions`] response.
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum PooledTransactionsError {
|
||||||
|
/// Thrown if there are transactions that do not match a requested hash.
|
||||||
|
#[error("one or more transactions do not match a requested hash")]
|
||||||
|
UnmatchedTransactions,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PooledTransactions {
|
||||||
|
/// Given a list of hashes, split the hashes into those that match a transaction in the
|
||||||
|
/// response, and those that do not.
|
||||||
|
/// Assumes the transactions are in the same order as the request's hashes.
|
||||||
|
pub fn split_transactions_by_hashes<T: Clone + Into<H256>>(
|
||||||
|
&self,
|
||||||
|
hashes: Vec<T>,
|
||||||
|
) -> Result<(Vec<H256>, Vec<H256>), PooledTransactionsError> {
|
||||||
|
// we need to loop through each transaction, skipping over hashes that we don't have a
|
||||||
|
// transaction for
|
||||||
|
let mut missing_hashes = Vec::new();
|
||||||
|
let mut hash_iter = hashes.iter();
|
||||||
|
let (matched_transactions, unmatched_transactions): (
|
||||||
|
Vec<&TransactionSigned>,
|
||||||
|
Vec<&TransactionSigned>,
|
||||||
|
) = self.0.iter().partition(|tx| {
|
||||||
|
for hash in &mut hash_iter {
|
||||||
|
let curr_hash = hash.clone().into();
|
||||||
|
if tx.hash() == curr_hash {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
missing_hashes.push(curr_hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
});
|
||||||
|
|
||||||
|
// this means we have been sent transactions that we did not request
|
||||||
|
if !unmatched_transactions.is_empty() {
|
||||||
|
return Err(PooledTransactionsError::UnmatchedTransactions)
|
||||||
|
}
|
||||||
|
|
||||||
|
let matched_hashes = matched_transactions.iter().map(|tx| tx.hash()).collect::<Vec<H256>>();
|
||||||
|
|
||||||
|
Ok((matched_hashes, missing_hashes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<TransactionSigned>> for PooledTransactions {
|
||||||
|
fn from(txs: Vec<TransactionSigned>) -> Self {
|
||||||
|
PooledTransactions(txs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<PooledTransactions> for Vec<TransactionSigned> {
|
||||||
|
fn from(txs: PooledTransactions) -> Self {
|
||||||
|
txs.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use crate::{message::RequestPair, GetPooledTransactions, PooledTransactions};
|
||||||
|
use hex_literal::hex;
|
||||||
|
use reth_primitives::{Signature, Transaction, TransactionKind, TransactionSigned, U256};
|
||||||
|
use reth_rlp::{Decodable, Encodable};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_get_pooled_transactions() {
|
||||||
|
let expected = hex!("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef");
|
||||||
|
let mut data = vec![];
|
||||||
|
let request = RequestPair::<GetPooledTransactions> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetPooledTransactions(vec![
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
request.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_get_pooled_transactions() {
|
||||||
|
let data = hex!("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef");
|
||||||
|
let request = RequestPair::<GetPooledTransactions>::decode(&mut &data[..]).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
request,
|
||||||
|
RequestPair::<GetPooledTransactions> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: GetPooledTransactions(vec![
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000deadc0de").into(),
|
||||||
|
hex!("00000000000000000000000000000000000000000000000000000000feedbeef").into(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn encode_pooled_transactions() {
|
||||||
|
let expected = hex!("f8d7820457f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb");
|
||||||
|
let mut data = vec![];
|
||||||
|
let request = RequestPair::<PooledTransactions> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: vec![
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(1),
|
||||||
|
nonce: 0x8u64.into(),
|
||||||
|
gas_price: 0x4a817c808u64.into(),
|
||||||
|
gas_limit: 0x2e248u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("3535353535353535353535353535353535353535").into(),
|
||||||
|
),
|
||||||
|
value: 0x200u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(1),
|
||||||
|
nonce: 0x09u64.into(),
|
||||||
|
gas_price: 0x4a817c809u64.into(),
|
||||||
|
gas_limit: 0x33450u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("3535353535353535353535353535353535353535").into(),
|
||||||
|
),
|
||||||
|
value: 0x2d9u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
};
|
||||||
|
request.encode(&mut data);
|
||||||
|
assert_eq!(data, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// Test vector from: https://eips.ethereum.org/EIPS/eip-2481
|
||||||
|
fn decode_pooled_transactions() {
|
||||||
|
let data = hex!("f8d7820457f8d2f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb");
|
||||||
|
let expected = RequestPair::<PooledTransactions> {
|
||||||
|
request_id: 1111,
|
||||||
|
message: vec![
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(1),
|
||||||
|
nonce: 0x8u64.into(),
|
||||||
|
gas_price: 0x4a817c808u64.into(),
|
||||||
|
gas_limit: 0x2e248u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("3535353535353535353535353535353535353535").into(),
|
||||||
|
),
|
||||||
|
value: 0x200u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(1),
|
||||||
|
nonce: 0x09u64.into(),
|
||||||
|
gas_price: 0x4a817c809u64.into(),
|
||||||
|
gas_limit: 0x33450u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("3535353535353535353535353535353535353535").into(),
|
||||||
|
),
|
||||||
|
value: 0x2d9u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let request = RequestPair::<PooledTransactions>::decode(&mut &data[..]).unwrap();
|
||||||
|
assert_eq!(request, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_pooled_transactions_network() {
|
||||||
|
let data = hex!("f9022980f90225f8650f84832156008287fb94cf7f9e66af820a19257a2108375b180b0ec491678204d2802ca035b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981a0612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860b87502f872041a8459682f008459682f0d8252089461815774383099e24810ab832a5b2a5425c154d58829a2241af62c000080c001a059e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafda0016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469f86b0384773594008398968094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba0ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071a03ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88f86b01843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac3960468702769bb01b2a00802ba0e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0aa05406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631daf86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18");
|
||||||
|
let decoded_transactions =
|
||||||
|
RequestPair::<PooledTransactions>::decode(&mut &data[..]).unwrap();
|
||||||
|
|
||||||
|
let expected_transactions = RequestPair::<PooledTransactions> {
|
||||||
|
request_id: 0,
|
||||||
|
message: vec![
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(4),
|
||||||
|
nonce: 15u64.into(),
|
||||||
|
gas_price: 2200000000u64.into(),
|
||||||
|
gas_limit: 34811u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("cf7f9e66af820a19257a2108375b180b0ec49167").into(),
|
||||||
|
),
|
||||||
|
value: 1234u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: true,
|
||||||
|
r: U256::from_str(
|
||||||
|
"35b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Eip1559 {
|
||||||
|
chain_id: 4,
|
||||||
|
nonce: 26u64.into(),
|
||||||
|
max_priority_fee_per_gas: 1500000000u64.into(),
|
||||||
|
max_fee_per_gas: 1500000013u64.into(),
|
||||||
|
gas_limit: 21000u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("61815774383099e24810ab832a5b2a5425c154d5").into(),
|
||||||
|
),
|
||||||
|
value: 3000000000000000000u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
access_list: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: true,
|
||||||
|
r: U256::from_str(
|
||||||
|
"59e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafd",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(4),
|
||||||
|
nonce: 3u64.into(),
|
||||||
|
gas_price: 2000000000u64.into(),
|
||||||
|
gas_limit: 10000000u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(),
|
||||||
|
),
|
||||||
|
value: 1000000000000000u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"3ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(4),
|
||||||
|
nonce: 1u64.into(),
|
||||||
|
gas_price: 1000000000u64.into(),
|
||||||
|
gas_limit: 100000u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(),
|
||||||
|
),
|
||||||
|
value: 693361000000000u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"5406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(4),
|
||||||
|
nonce: 2u64.into(),
|
||||||
|
gas_price: 1000000000u64.into(),
|
||||||
|
gas_limit: 100000u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(),
|
||||||
|
),
|
||||||
|
value: 1000000000000000u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// checking tx by tx for easier debugging if there are any regressions
|
||||||
|
for (expected, decoded) in
|
||||||
|
decoded_transactions.message.0.iter().zip(expected_transactions.message.0.iter())
|
||||||
|
{
|
||||||
|
assert_eq!(expected, decoded);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(decoded_transactions, expected_transactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encode_pooled_transactions_network() {
|
||||||
|
let expected = hex!("f9022980f90225f8650f84832156008287fb94cf7f9e66af820a19257a2108375b180b0ec491678204d2802ca035b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981a0612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860b87502f872041a8459682f008459682f0d8252089461815774383099e24810ab832a5b2a5425c154d58829a2241af62c000080c001a059e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafda0016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469f86b0384773594008398968094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba0ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071a03ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88f86b01843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac3960468702769bb01b2a00802ba0e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0aa05406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631daf86b02843b9aca00830186a094d3e8763675e4c425df46cc3b5c0f6cbdac39604687038d7ea4c68000802ba00eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5aea03a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18");
|
||||||
|
|
||||||
|
let transactions = RequestPair::<PooledTransactions> {
|
||||||
|
request_id: 0,
|
||||||
|
message: vec![
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(4),
|
||||||
|
nonce: 15u64.into(),
|
||||||
|
gas_price: 2200000000u64.into(),
|
||||||
|
gas_limit: 34811u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("cf7f9e66af820a19257a2108375b180b0ec49167").into(),
|
||||||
|
),
|
||||||
|
value: 1234u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: true,
|
||||||
|
r: U256::from_str(
|
||||||
|
"35b7bfeb9ad9ece2cbafaaf8e202e706b4cfaeb233f46198f00b44d4a566a981",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"612638fb29427ca33b9a3be2a0a561beecfe0269655be160d35e72d366a6a860",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Eip1559 {
|
||||||
|
chain_id: 4,
|
||||||
|
nonce: 26u64.into(),
|
||||||
|
max_priority_fee_per_gas: 1500000000u64.into(),
|
||||||
|
max_fee_per_gas: 1500000013u64.into(),
|
||||||
|
gas_limit: 21000u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("61815774383099e24810ab832a5b2a5425c154d5").into(),
|
||||||
|
),
|
||||||
|
value: 3000000000000000000u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
access_list: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: true,
|
||||||
|
r: U256::from_str(
|
||||||
|
"59e6b67f48fb32e7e570dfb11e042b5ad2e55e3ce3ce9cd989c7e06e07feeafd",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"016b83f4f980694ed2eee4d10667242b1f40dc406901b34125b008d334d47469",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(4),
|
||||||
|
nonce: 3u64.into(),
|
||||||
|
gas_price: 2000000000u64.into(),
|
||||||
|
gas_limit: 10000000u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(),
|
||||||
|
),
|
||||||
|
value: 1000000000000000u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"ce6834447c0a4193c40382e6c57ae33b241379c5418caac9cdc18d786fd12071",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"3ca3ae86580e94550d7c071e3a02eadb5a77830947c9225165cf9100901bee88",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(4),
|
||||||
|
nonce: 1u64.into(),
|
||||||
|
gas_price: 1000000000u64.into(),
|
||||||
|
gas_limit: 100000u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(),
|
||||||
|
),
|
||||||
|
value: 693361000000000u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"e24d8bd32ad906d6f8b8d7741e08d1959df021698b19ee232feba15361587d0a",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"5406ad177223213df262cb66ccbb2f46bfdccfdfbbb5ffdda9e2c02d977631da",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
TransactionSigned::from_transaction_and_signature(
|
||||||
|
Transaction::Legacy {
|
||||||
|
chain_id: Some(4),
|
||||||
|
nonce: 2u64.into(),
|
||||||
|
gas_price: 1000000000u64.into(),
|
||||||
|
gas_limit: 100000u64.into(),
|
||||||
|
to: TransactionKind::Call(
|
||||||
|
hex!("d3e8763675e4c425df46cc3b5c0f6cbdac396046").into(),
|
||||||
|
),
|
||||||
|
value: 1000000000000000u64.into(),
|
||||||
|
input: Default::default(),
|
||||||
|
},
|
||||||
|
Signature {
|
||||||
|
odd_y_parity: false,
|
||||||
|
r: U256::from_str(
|
||||||
|
"eb96ca19e8a77102767a41fc85a36afd5c61ccb09911cec5d3e86e193d9c5ae",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
s: U256::from_str(
|
||||||
|
"3a456401896b1b6055311536bf00a718568c744d8c1f9df59879e8350220ca18",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut encoded = vec![];
|
||||||
|
transactions.encode(&mut encoded);
|
||||||
|
assert_eq!(encoded.len(), transactions.length());
|
||||||
|
let encoded_str = hex::encode(encoded);
|
||||||
|
let expected_str = hex::encode(expected);
|
||||||
|
assert_eq!(encoded_str.len(), expected_str.len());
|
||||||
|
assert_eq!(encoded_str, expected_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
crates/net/eth-wire/testdata/bsc_new_block_network_one
vendored
Normal file
1
crates/net/eth-wire/testdata/bsc_new_block_network_one
vendored
Normal file
File diff suppressed because one or more lines are too long
1
crates/net/eth-wire/testdata/bsc_new_block_network_two
vendored
Normal file
1
crates/net/eth-wire/testdata/bsc_new_block_network_two
vendored
Normal file
File diff suppressed because one or more lines are too long
1
crates/net/eth-wire/testdata/new_block_network_rlp
vendored
Normal file
1
crates/net/eth-wire/testdata/new_block_network_rlp
vendored
Normal file
File diff suppressed because one or more lines are too long
1
crates/net/eth-wire/testdata/new_pooled_transactions_network_rlp
vendored
Normal file
1
crates/net/eth-wire/testdata/new_pooled_transactions_network_rlp
vendored
Normal file
File diff suppressed because one or more lines are too long
31
crates/net/eth-wire/tests/new_block.rs
Normal file
31
crates/net/eth-wire/tests/new_block.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//! Decoding tests for [`NewBlock`]
|
||||||
|
use reth_eth_wire::NewBlock;
|
||||||
|
use reth_rlp::Decodable;
|
||||||
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_new_block_network() {
|
||||||
|
let network_data_path =
|
||||||
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata/new_block_network_rlp");
|
||||||
|
let data = fs::read_to_string(network_data_path).expect("Unable to read file");
|
||||||
|
let hex_data = hex::decode(data.trim()).unwrap();
|
||||||
|
let _txs = NewBlock::decode(&mut &hex_data[..]).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_new_block_network_bsc_one() {
|
||||||
|
let network_data_path =
|
||||||
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata/bsc_new_block_network_one");
|
||||||
|
let data = fs::read_to_string(network_data_path).expect("Unable to read file");
|
||||||
|
let hex_data = hex::decode(data.trim()).unwrap();
|
||||||
|
let _txs = NewBlock::decode(&mut &hex_data[..]).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_new_block_network_bsc_two() {
|
||||||
|
let network_data_path =
|
||||||
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata/bsc_new_block_network_two");
|
||||||
|
let data = fs::read_to_string(network_data_path).expect("Unable to read file");
|
||||||
|
let hex_data = hex::decode(data.trim()).unwrap();
|
||||||
|
let _txs = NewBlock::decode(&mut &hex_data[..]).unwrap();
|
||||||
|
}
|
||||||
13
crates/net/eth-wire/tests/new_pooled_transactions.rs
Normal file
13
crates/net/eth-wire/tests/new_pooled_transactions.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//! Decoding tests for [`NewPooledTransactions`]
|
||||||
|
use reth_eth_wire::NewPooledTransactionHashes;
|
||||||
|
use reth_rlp::Decodable;
|
||||||
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_new_pooled_transaction_hashes_network() {
|
||||||
|
let network_data_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||||
|
.join("testdata/new_pooled_transactions_network_rlp");
|
||||||
|
let data = fs::read_to_string(network_data_path).expect("Unable to read file");
|
||||||
|
let hex_data = hex::decode(data.trim()).unwrap();
|
||||||
|
let _txs = NewPooledTransactionHashes::decode(&mut &hex_data[..]).unwrap();
|
||||||
|
}
|
||||||
@ -24,7 +24,7 @@ pub use jsonu256::JsonU256;
|
|||||||
pub use log::Log;
|
pub use log::Log;
|
||||||
pub use receipt::Receipt;
|
pub use receipt::Receipt;
|
||||||
pub use transaction::{
|
pub use transaction::{
|
||||||
AccessList, AccessListItem, Transaction, TransactionKind, TransactionSigned, TxType,
|
AccessList, AccessListItem, Signature, Transaction, TransactionKind, TransactionSigned, TxType,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Block hash.
|
/// Block hash.
|
||||||
|
|||||||
@ -7,7 +7,7 @@ pub use access_list::{AccessList, AccessListItem};
|
|||||||
use bytes::Buf;
|
use bytes::Buf;
|
||||||
use ethers_core::utils::keccak256;
|
use ethers_core::utils::keccak256;
|
||||||
use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header, EMPTY_STRING_CODE};
|
use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header, EMPTY_STRING_CODE};
|
||||||
use signature::Signature;
|
pub use signature::Signature;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
pub use tx_type::TxType;
|
pub use tx_type::TxType;
|
||||||
|
|
||||||
@ -501,9 +501,9 @@ impl Decodable for TransactionSigned {
|
|||||||
// keep this around so we can use it to calculate the hash
|
// keep this around so we can use it to calculate the hash
|
||||||
let original_encoding = *buf;
|
let original_encoding = *buf;
|
||||||
|
|
||||||
let header = Header::decode(buf)?;
|
let first_header = Header::decode(buf)?;
|
||||||
// if the transaction is encoded as a string then it is a typed transaction
|
// if the transaction is encoded as a string then it is a typed transaction
|
||||||
if !header.list {
|
if !first_header.list {
|
||||||
let tx_type = *buf
|
let tx_type = *buf
|
||||||
.first()
|
.first()
|
||||||
.ok_or(DecodeError::Custom("typed tx cannot be decoded from an empty slice"))?;
|
.ok_or(DecodeError::Custom("typed tx cannot be decoded from an empty slice"))?;
|
||||||
@ -545,8 +545,11 @@ impl Decodable for TransactionSigned {
|
|||||||
r: Decodable::decode(buf)?,
|
r: Decodable::decode(buf)?,
|
||||||
s: Decodable::decode(buf)?,
|
s: Decodable::decode(buf)?,
|
||||||
};
|
};
|
||||||
let hash = keccak256(original_encoding).into();
|
|
||||||
Ok(TransactionSigned { transaction, hash, signature })
|
let mut signed = TransactionSigned { transaction, hash: Default::default(), signature };
|
||||||
|
let tx_length = first_header.payload_length + first_header.length();
|
||||||
|
signed.hash = keccak256(&original_encoding[..tx_length]).into();
|
||||||
|
Ok(signed)
|
||||||
} else {
|
} else {
|
||||||
let mut transaction = Transaction::Legacy {
|
let mut transaction = Transaction::Legacy {
|
||||||
nonce: Decodable::decode(buf)?,
|
nonce: Decodable::decode(buf)?,
|
||||||
@ -562,8 +565,10 @@ impl Decodable for TransactionSigned {
|
|||||||
transaction.set_chain_id(id);
|
transaction.set_chain_id(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash = keccak256(original_encoding).into();
|
let mut signed = TransactionSigned { transaction, hash: Default::default(), signature };
|
||||||
Ok(TransactionSigned { transaction, hash, signature })
|
let tx_length = first_header.payload_length + first_header.length();
|
||||||
|
signed.hash = keccak256(&original_encoding[..tx_length]).into();
|
||||||
|
Ok(signed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user