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:
Georgios Konstantopoulos
2022-10-19 20:24:50 -07:00
committed by GitHub
parent e7851492b1
commit c277015f5c
17 changed files with 1575 additions and 111 deletions

View File

@ -12,5 +12,6 @@ pub use tokio_util::codec::{
pub mod error;
mod stream;
pub mod types;
pub use types::*;
pub use stream::EthStream;

View 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);
}
}

View File

@ -1,4 +1,5 @@
//! Types for broadcasting new data.
use reth_primitives::{Header, TransactionSigned, H256, U128};
use reth_rlp::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper};
/// 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)]
pub struct BlockHashNumber {
/// The block hash
pub hash: reth_primitives::H256,
pub hash: H256,
/// The block number
pub number: u64,
}
@ -29,3 +30,60 @@ impl From<NewBlockHashes> for Vec<BlockHashNumber> {
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)
}
}

View File

@ -1,5 +1,9 @@
#![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 reth_rlp::{length_of_length, Decodable, Encodable, Header};
use std::fmt::Debug;
@ -22,52 +26,51 @@ impl ProtocolMessage {
EthMessageID::NewBlockHashes => {
EthMessage::NewBlockHashes(NewBlockHashes::decode(buf)?)
}
_ => unimplemented!(),
// EthMessageID::NewBlock => EthMessage::NewBlock(Box::new(NewBlock::decode(buf)?)),
// EthMessageID::Transactions => EthMessage::Transactions(Transactions::decode(buf)?),
// EthMessageID::NewPooledTransactionHashes => {
// EthMessage::NewPooledTransactionHashes(NewPooledTransactionHashes::decode(buf)?)
// }
// EthMessageID::GetBlockHeaders => {
// let request_pair = RequestPair::<GetBlockHeaders>::decode(buf)?;
// EthMessage::GetBlockHeaders(request_pair)
// }
// EthMessageID::BlockHeaders => {
// let request_pair = RequestPair::<BlockHeaders>::decode(buf)?;
// EthMessage::BlockHeaders(request_pair)
// }
// EthMessageID::GetBlockBodies => {
// let request_pair = RequestPair::<GetBlockBodies>::decode(buf)?;
// EthMessage::GetBlockBodies(request_pair)
// }
// EthMessageID::BlockBodies => {
// let request_pair = RequestPair::<BlockBodies>::decode(buf)?;
// EthMessage::BlockBodies(request_pair)
// }
// EthMessageID::GetPooledTransactions => {
// let request_pair = RequestPair::<GetPooledTransactions>::decode(buf)?;
// EthMessage::GetPooledTransactions(request_pair)
// }
// EthMessageID::PooledTransactions => {
// let request_pair = RequestPair::<PooledTransactions>::decode(buf)?;
// EthMessage::PooledTransactions(request_pair)
// }
// EthMessageID::GetNodeData => {
// let request_pair = RequestPair::<GetNodeData>::decode(buf)?;
// EthMessage::GetNodeData(request_pair)
// }
// EthMessageID::NodeData => {
// let request_pair = RequestPair::<NodeData>::decode(buf)?;
// EthMessage::NodeData(request_pair)
// }
// EthMessageID::GetReceipts => {
// let request_pair = RequestPair::<GetReceipts>::decode(buf)?;
// EthMessage::GetReceipts(request_pair)
// }
// EthMessageID::Receipts => {
// let request_pair = RequestPair::<Receipts>::decode(buf)?;
// EthMessage::Receipts(request_pair)
// }
EthMessageID::NewBlock => EthMessage::NewBlock(Box::new(NewBlock::decode(buf)?)),
EthMessageID::Transactions => EthMessage::Transactions(Transactions::decode(buf)?),
EthMessageID::NewPooledTransactionHashes => {
EthMessage::NewPooledTransactionHashes(NewPooledTransactionHashes::decode(buf)?)
}
EthMessageID::GetBlockHeaders => {
let request_pair = RequestPair::<GetBlockHeaders>::decode(buf)?;
EthMessage::GetBlockHeaders(request_pair)
}
EthMessageID::BlockHeaders => {
let request_pair = RequestPair::<BlockHeaders>::decode(buf)?;
EthMessage::BlockHeaders(request_pair)
}
EthMessageID::GetBlockBodies => {
let request_pair = RequestPair::<GetBlockBodies>::decode(buf)?;
EthMessage::GetBlockBodies(request_pair)
}
EthMessageID::BlockBodies => {
let request_pair = RequestPair::<BlockBodies>::decode(buf)?;
EthMessage::BlockBodies(request_pair)
}
EthMessageID::GetPooledTransactions => {
let request_pair = RequestPair::<GetPooledTransactions>::decode(buf)?;
EthMessage::GetPooledTransactions(request_pair)
}
EthMessageID::PooledTransactions => {
let request_pair = RequestPair::<PooledTransactions>::decode(buf)?;
EthMessage::PooledTransactions(request_pair)
}
EthMessageID::GetNodeData => {
let request_pair = RequestPair::<GetNodeData>::decode(buf)?;
EthMessage::GetNodeData(request_pair)
}
EthMessageID::NodeData => {
let request_pair = RequestPair::<NodeData>::decode(buf)?;
EthMessage::NodeData(request_pair)
}
EthMessageID::GetReceipts => {
let request_pair = RequestPair::<GetReceipts>::decode(buf)?;
EthMessage::GetReceipts(request_pair)
}
EthMessageID::Receipts => {
let request_pair = RequestPair::<Receipts>::decode(buf)?;
EthMessage::Receipts(request_pair)
}
};
Ok(ProtocolMessage { message_type, message })
}
@ -116,23 +119,23 @@ impl From<EthMessage> for ProtocolMessage {
pub enum EthMessage {
// Status is required for the protocol handshake
Status(Status),
// // The following messages are broadcast to the network
// The following messages are broadcast to the network
NewBlockHashes(NewBlockHashes),
// NewBlock(Box<NewBlock>),
// Transactions(Transactions),
// NewPooledTransactionHashes(NewPooledTransactionHashes),
NewBlock(Box<NewBlock>),
Transactions(Transactions),
NewPooledTransactionHashes(NewPooledTransactionHashes),
// // The following messages are request-response message pairs
// GetBlockHeaders(RequestPair<GetBlockHeaders>),
// BlockHeaders(RequestPair<BlockHeaders>),
// GetBlockBodies(RequestPair<GetBlockBodies>),
// BlockBodies(RequestPair<BlockBodies>),
// GetPooledTransactions(RequestPair<GetPooledTransactions>),
// PooledTransactions(RequestPair<PooledTransactions>),
// GetNodeData(RequestPair<GetNodeData>),
// NodeData(RequestPair<NodeData>),
// GetReceipts(RequestPair<GetReceipts>),
// Receipts(RequestPair<Receipts>),
// The following messages are request-response message pairs
GetBlockHeaders(RequestPair<GetBlockHeaders>),
BlockHeaders(RequestPair<BlockHeaders>),
GetBlockBodies(RequestPair<GetBlockBodies>),
BlockBodies(RequestPair<BlockBodies>),
GetPooledTransactions(RequestPair<GetPooledTransactions>),
PooledTransactions(RequestPair<PooledTransactions>),
GetNodeData(RequestPair<GetNodeData>),
NodeData(RequestPair<NodeData>),
GetReceipts(RequestPair<GetReceipts>),
Receipts(RequestPair<Receipts>),
}
impl EthMessage {
@ -141,20 +144,19 @@ impl EthMessage {
match self {
EthMessage::Status(_) => EthMessageID::Status,
EthMessage::NewBlockHashes(_) => EthMessageID::NewBlockHashes,
// EthMessage::NewBlock(_) => EthMessageID::NewBlock,
// EthMessage::Transactions(_) => EthMessageID::Transactions,
// EthMessage::NewPooledTransactionHashes(_) =>
// EthMessageID::NewPooledTransactionHashes, EthMessage::GetBlockHeaders(_)
// => EthMessageID::GetBlockHeaders, EthMessage::BlockHeaders(_) =>
// EthMessageID::BlockHeaders, EthMessage::GetBlockBodies(_) =>
// EthMessageID::GetBlockBodies, EthMessage::BlockBodies(_) =>
// EthMessageID::BlockBodies, EthMessage::GetPooledTransactions(_) =>
// EthMessageID::GetPooledTransactions, EthMessage::PooledTransactions(_) =>
// EthMessageID::PooledTransactions, EthMessage::GetNodeData(_) =>
// EthMessageID::GetNodeData, EthMessage::NodeData(_) =>
// EthMessageID::NodeData, EthMessage::GetReceipts(_) =>
// EthMessageID::GetReceipts, EthMessage::Receipts(_) =>
// EthMessageID::Receipts,
EthMessage::NewBlock(_) => EthMessageID::NewBlock,
EthMessage::Transactions(_) => EthMessageID::Transactions,
EthMessage::NewPooledTransactionHashes(_) => EthMessageID::NewPooledTransactionHashes,
EthMessage::GetBlockHeaders(_) => EthMessageID::GetBlockHeaders,
EthMessage::BlockHeaders(_) => EthMessageID::BlockHeaders,
EthMessage::GetBlockBodies(_) => EthMessageID::GetBlockBodies,
EthMessage::BlockBodies(_) => EthMessageID::BlockBodies,
EthMessage::GetPooledTransactions(_) => EthMessageID::GetPooledTransactions,
EthMessage::PooledTransactions(_) => EthMessageID::PooledTransactions,
EthMessage::GetNodeData(_) => EthMessageID::GetNodeData,
EthMessage::NodeData(_) => EthMessageID::NodeData,
EthMessage::GetReceipts(_) => EthMessageID::GetReceipts,
EthMessage::Receipts(_) => EthMessageID::Receipts,
}
}
}
@ -164,38 +166,38 @@ impl Encodable for EthMessage {
match self {
EthMessage::Status(status) => status.length(),
EthMessage::NewBlockHashes(new_block_hashes) => new_block_hashes.length(),
// EthMessage::NewBlock(new_block) => new_block.length(),
// EthMessage::Transactions(transactions) => transactions.length(),
// EthMessage::NewPooledTransactionHashes(hashes) => hashes.length(),
// EthMessage::GetBlockHeaders(request) => request.length(),
// EthMessage::BlockHeaders(headers) => headers.length(),
// EthMessage::GetBlockBodies(request) => request.length(),
// EthMessage::BlockBodies(bodies) => bodies.length(),
// EthMessage::GetPooledTransactions(request) => request.length(),
// EthMessage::PooledTransactions(transactions) => transactions.length(),
// EthMessage::GetNodeData(request) => request.length(),
// EthMessage::NodeData(data) => data.length(),
// EthMessage::GetReceipts(request) => request.length(),
// EthMessage::Receipts(receipts) => receipts.length(),
EthMessage::NewBlock(new_block) => new_block.length(),
EthMessage::Transactions(transactions) => transactions.length(),
EthMessage::NewPooledTransactionHashes(hashes) => hashes.length(),
EthMessage::GetBlockHeaders(request) => request.length(),
EthMessage::BlockHeaders(headers) => headers.length(),
EthMessage::GetBlockBodies(request) => request.length(),
EthMessage::BlockBodies(bodies) => bodies.length(),
EthMessage::GetPooledTransactions(request) => request.length(),
EthMessage::PooledTransactions(transactions) => transactions.length(),
EthMessage::GetNodeData(request) => request.length(),
EthMessage::NodeData(data) => data.length(),
EthMessage::GetReceipts(request) => request.length(),
EthMessage::Receipts(receipts) => receipts.length(),
}
}
fn encode(&self, out: &mut dyn bytes::BufMut) {
match self {
EthMessage::Status(status) => status.encode(out),
EthMessage::NewBlockHashes(new_block_hashes) => new_block_hashes.encode(out),
// EthMessage::NewBlock(new_block) => new_block.encode(out),
// EthMessage::Transactions(transactions) => transactions.encode(out),
// EthMessage::NewPooledTransactionHashes(hashes) => hashes.encode(out),
// EthMessage::GetBlockHeaders(request) => request.encode(out),
// EthMessage::BlockHeaders(headers) => headers.encode(out),
// EthMessage::GetBlockBodies(request) => request.encode(out),
// EthMessage::BlockBodies(bodies) => bodies.encode(out),
// EthMessage::GetPooledTransactions(request) => request.encode(out),
// EthMessage::PooledTransactions(transactions) => transactions.encode(out),
// EthMessage::GetNodeData(request) => request.encode(out),
// EthMessage::NodeData(data) => data.encode(out),
// EthMessage::GetReceipts(request) => request.encode(out),
// EthMessage::Receipts(receipts) => receipts.encode(out),
EthMessage::NewBlock(new_block) => new_block.encode(out),
EthMessage::Transactions(transactions) => transactions.encode(out),
EthMessage::NewPooledTransactionHashes(hashes) => hashes.encode(out),
EthMessage::GetBlockHeaders(request) => request.encode(out),
EthMessage::BlockHeaders(headers) => headers.encode(out),
EthMessage::GetBlockBodies(request) => request.encode(out),
EthMessage::BlockBodies(bodies) => bodies.encode(out),
EthMessage::GetPooledTransactions(request) => request.encode(out),
EthMessage::PooledTransactions(transactions) => transactions.encode(out),
EthMessage::GetNodeData(request) => request.encode(out),
EthMessage::NodeData(data) => data.encode(out),
EthMessage::GetReceipts(request) => request.encode(out),
EthMessage::Receipts(receipts) => receipts.encode(out),
}
}
}

View File

@ -11,4 +11,17 @@ pub mod forkid;
pub mod message;
pub use message::{EthMessage, EthMessageID, ProtocolMessage};
pub mod blocks;
pub use blocks::*;
pub mod broadcast;
pub use broadcast::*;
pub mod transactions;
pub use transactions::*;
pub mod state;
pub use state::*;
pub mod receipts;
pub use receipts::*;

View 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,
},
],
]),
}
);
}
}

View 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>),
}

View 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(),
])
}
);
}
}

View 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);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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();
}

View 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();
}

View File

@ -24,7 +24,7 @@ pub use jsonu256::JsonU256;
pub use log::Log;
pub use receipt::Receipt;
pub use transaction::{
AccessList, AccessListItem, Transaction, TransactionKind, TransactionSigned, TxType,
AccessList, AccessListItem, Signature, Transaction, TransactionKind, TransactionSigned, TxType,
};
/// Block hash.

View File

@ -7,7 +7,7 @@ pub use access_list::{AccessList, AccessListItem};
use bytes::Buf;
use ethers_core::utils::keccak256;
use reth_rlp::{length_of_length, Decodable, DecodeError, Encodable, Header, EMPTY_STRING_CODE};
use signature::Signature;
pub use signature::Signature;
use std::ops::Deref;
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
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 !header.list {
if !first_header.list {
let tx_type = *buf
.first()
.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)?,
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 {
let mut transaction = Transaction::Legacy {
nonce: Decodable::decode(buf)?,
@ -562,8 +565,10 @@ impl Decodable for TransactionSigned {
transaction.set_chain_id(id);
}
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)
}
}
}