fix: make discv4 packets adhere to eip-8 (#8039)

This commit is contained in:
Oliver Nordbjerg
2024-05-02 15:58:17 +02:00
committed by GitHub
parent f6649c31b2
commit 14d91c3ba0
4 changed files with 275 additions and 8 deletions

View File

@ -4,7 +4,7 @@
use crate::Head;
use alloy_primitives::{hex, BlockNumber, B256};
use alloy_rlp::*;
use alloy_rlp::{Error as RlpError, *};
#[cfg(any(test, feature = "arbitrary"))]
use arbitrary::Arbitrary;
use crc::*;
@ -116,19 +116,51 @@ pub struct ForkId {
}
/// Represents a forward-compatible ENR entry for including the forkid in a node record via
/// EIP-868. Forward compatibility is achieved by allowing trailing fields.
/// EIP-868. Forward compatibility is achieved via EIP-8.
///
/// See:
/// <https://github.com/ethereum/devp2p/blob/master/enr-entries/eth.md#entry-format>
///
/// for how geth implements ForkId values and forward compatibility.
#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable, RlpDecodable)]
#[rlp(trailing)]
#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable)]
pub struct EnrForkIdEntry {
/// The inner forkid
pub fork_id: ForkId,
}
impl Decodable for EnrForkIdEntry {
// NOTE(onbjerg): Manual implementation to satisfy EIP-8.
//
// See https://eips.ethereum.org/EIPS/eip-8
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let b = &mut &**buf;
let rlp_head = Header::decode(b)?;
if !rlp_head.list {
return Err(RlpError::UnexpectedString)
}
let started_len = b.len();
let this = Self { fork_id: Decodable::decode(b)? };
// NOTE(onbjerg): Because of EIP-8, we only check that we did not consume *more* than the
// payload length, i.e. it is ok if payload length is greater than what we consumed, as we
// just discard the remaining list items
let consumed = started_len - b.len();
if consumed > rlp_head.payload_length {
return Err(RlpError::ListLengthMismatch {
expected: rlp_head.payload_length,
got: consumed,
})
}
let rem = rlp_head.payload_length - consumed;
b.advance(rem);
*buf = *b;
Ok(this)
}
}
impl From<ForkId> for EnrForkIdEntry {
fn from(fork_id: ForkId) -> Self {
Self { fork_id }
@ -652,4 +684,39 @@ mod tests {
assert!(fork_filter.set_head_priv(Head { number: b2, ..Default::default() }).is_some());
assert_eq!(fork_filter.current(), h2);
}
mod eip8 {
use super::*;
fn junk_enr_fork_id_entry() -> Vec<u8> {
let mut buf = Vec::new();
// enr request is just an expiration
let fork_id = ForkId { hash: ForkHash(hex!("deadbeef")), next: 0xBADDCAFE };
// add some junk
let junk: u64 = 112233;
// rlp header encoding
let payload_length = fork_id.length() + junk.length();
alloy_rlp::Header { list: true, payload_length }.encode(&mut buf);
// fields
fork_id.encode(&mut buf);
junk.encode(&mut buf);
buf
}
#[test]
fn eip8_decode_enr_fork_id_entry() {
let enr_fork_id_entry_with_junk = junk_enr_fork_id_entry();
let mut buf = enr_fork_id_entry_with_junk.as_slice();
let decoded = EnrForkIdEntry::decode(&mut buf).unwrap();
assert_eq!(
decoded.fork_id,
ForkId { hash: ForkHash(hex!("deadbeef")), next: 0xBADDCAFE }
);
}
}
}