Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: broken decoding #75

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 82 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,10 @@ impl<K: EnrKey> Enr<K> {
self.seq
}

/// Reads a custom key from the record if it exists, decoded as data.
/// Reads a custom key from the record if it exists, decoded as data. Caution! Only use for
/// data that is not an aggregate type. Default to using [`get_decodable`](Enr::get_decodable).
#[allow(clippy::missing_panics_doc)]
pub fn get(&self, key: impl AsRef<[u8]>) -> Option<Bytes> {
// It's ok to decode any valid RLP value as data
self.get_raw_rlp(key).map(|mut rlp_data| {
let raw_data = &mut rlp_data;
let header = Header::decode(raw_data).expect("All data is sanitized");
Expand Down Expand Up @@ -1031,10 +1031,10 @@ impl<K: EnrKey> Decodable for Enr<K> {
let keys = Header::decode_bytes(payload, false)?;
alloy_rlp::encode(keys)
}
b"eth" => {
let eth_header = Header::decode(payload)?;
let value = &mut &payload[..eth_header.payload_length];
payload.advance(eth_header.payload_length);
_ => {
let other_header = Header::decode(payload)?;
let value = &mut &payload[..other_header.payload_length];
payload.advance(other_header.payload_length);
let val_header = Header {
list: true,
payload_length: value.len(),
Expand All @@ -1044,12 +1044,6 @@ impl<K: EnrKey> Decodable for Enr<K> {
out.extend_from_slice(value);
out
}
_ => {
let other_header = Header::decode(payload)?;
let value = &payload[..other_header.payload_length];
payload.advance(other_header.payload_length);
alloy_rlp::encode(value)
}
};
content.insert(key.to_vec(), Bytes::from(value));
}
Expand Down Expand Up @@ -1143,10 +1137,28 @@ fn check_spec_reserved_keys(key: &[u8], mut value: &[u8]) -> Result<(), Error> {
#[cfg(feature = "k256")]
mod tests {
use super::*;
use alloy_rlp::{RlpDecodable, RlpEncodable};
use std::convert::TryFrom;

type DefaultEnr = Enr<k256::ecdsa::SigningKey>;

#[derive(RlpEncodable, RlpDecodable, Debug, PartialEq, Eq)]
struct EnrForkId {
fork_digest: [u8; 4],
next_fork_version: [u8; 4],
next_fork_epoch: u64,
}

impl EnrForkId {
fn gen_random() -> Self {
Self {
fork_digest: rand::random(),
next_fork_version: rand::random(),
next_fork_epoch: rand::random(),
}
}
}

#[cfg(feature = "k256")]
#[test]
fn test_vector_k256() {
Expand Down Expand Up @@ -1456,8 +1468,14 @@ mod tests {
let key = k256::ecdsa::SigningKey::random(&mut rand::rngs::OsRng);
let ip = Ipv4Addr::new(127, 0, 0, 1);
let tcp = 3000;
let fork_id = EnrForkId::gen_random();

let enr = Enr::builder().ip4(ip).tcp4(tcp).build(&key).unwrap();
let enr = Enr::builder()
.ip4(ip)
.tcp4(tcp)
.add_value("eth2", &fork_id)
.build(&key)
.unwrap();

let mut encoded_enr = BytesMut::new();
enr.encode(&mut encoded_enr);
Expand All @@ -1468,6 +1486,13 @@ mod tests {
assert_eq!(decoded_enr.id(), Some("v4".into()));
assert_eq!(decoded_enr.ip4(), Some(ip));
assert_eq!(decoded_enr.tcp4(), Some(tcp));
assert_eq!(
decoded_enr
.get_decodable::<EnrForkId>("eth2")
.unwrap()
.unwrap(),
fork_id
);
// Must compare encoding as the public key itself can be different
assert_eq!(decoded_enr.public_key().encode(), key.public().encode());
decoded_enr.public_key().encode_uncompressed();
Expand All @@ -1481,8 +1506,14 @@ mod tests {
let key = ed25519_dalek::SigningKey::generate(&mut rng);
let ip = Ipv4Addr::new(10, 0, 0, 1);
let tcp = 30303;
let fork_id = EnrForkId::gen_random();

let enr = Enr::builder().ip4(ip).tcp4(tcp).build(&key).unwrap();
let enr = Enr::builder()
.ip4(ip)
.tcp4(tcp)
.add_value("eth2", &fork_id)
.build(&key)
.unwrap();

let mut out = BytesMut::new();
enr.encode(&mut out);
Expand All @@ -1491,6 +1522,13 @@ mod tests {
assert_eq!(decoded_enr.id(), Some("v4".into()));
assert_eq!(decoded_enr.ip4(), Some(ip));
assert_eq!(decoded_enr.tcp4(), Some(tcp));
assert_eq!(
decoded_enr
.get_decodable::<EnrForkId>("eth2")
.unwrap()
.unwrap(),
fork_id
);
assert_eq!(decoded_enr.public_key().encode(), key.public().encode());
assert!(decoded_enr.verify());
}
Expand Down Expand Up @@ -1519,6 +1557,36 @@ mod tests {
assert_eq!(decoded_proto, proto);
}

#[test]
fn test_add_content_value_decoding() {
#[derive(PartialEq, Eq, Debug, alloy_rlp::RlpEncodable, alloy_rlp::RlpDecodable)]
struct Proto {
name: String,
version: u64,
}

let mut rng = rand::thread_rng();
let key = k256::ecdsa::SigningKey::random(&mut rng);
let proto = Proto {
name: "test".to_string(),
version: 1,
};

let enr = Enr::builder()
.add_value("proto", &proto)
.build(&key)
.unwrap();

let encoded_enr = alloy_rlp::encode(enr.clone());
let decoded_enr = Enr::<k256::ecdsa::SigningKey>::decode(&mut &encoded_enr[..]).unwrap();

let decoded_proto = decoded_enr
.get_decodable::<Proto>("proto")
.unwrap()
.unwrap();
assert_eq!(decoded_proto, proto);
}

#[test]
fn test_add_key() {
let mut rng = rand::thread_rng();
Expand Down
Loading