Skip to content

Commit 486fecf

Browse files
authored
feat: implement ENRResponse encoding (#144)
This PR depends on #141 **Motivation** Implement discv4 protocol **Description** Enables `ENRResponse` encoding Closes #90
1 parent aba1d91 commit 486fecf

File tree

2 files changed

+107
-1
lines changed

2 files changed

+107
-1
lines changed

crates/core/src/rlp/structs.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use super::{
44
error::RLPDecodeError,
55
};
66
use bytes::BufMut;
7+
use bytes::Bytes;
78

89
/// # Struct decoding helper
910
///
@@ -190,6 +191,17 @@ impl<'a> Encoder<'a> {
190191
self
191192
}
192193

194+
/// Stores a (key, value) list where the values are already encoded (i.e. value = RLP prefix || payload)
195+
/// but the keys are not encoded
196+
pub fn encode_key_value_list<T: RLPEncode>(mut self, list: &Vec<(Bytes, Bytes)>) -> Self {
197+
for (key, value) in list {
198+
<Bytes>::encode(key, &mut self.temp_buf);
199+
// value is already encoded
200+
self.temp_buf.put_slice(value);
201+
}
202+
self
203+
}
204+
193205
/// Finishes encoding the struct and writes the result to the buffer.
194206
pub fn finish(self) {
195207
encode_length(self.temp_buf.len(), self.buf);

crates/net/src/discv4.rs

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ impl Message {
9696
Message::Pong(msg) => msg.encode(buf),
9797
Message::FindNode(msg) => msg.encode(buf),
9898
Message::ENRRequest(msg) => msg.encode(buf),
99+
Message::ENRResponse(msg) => msg.encode(buf),
99100
Message::Neighbors(msg) => msg.encode(buf),
100-
_ => todo!(),
101101
}
102102
}
103103

@@ -514,6 +514,25 @@ impl RLPEncode for ENRRequestMessage {
514514
}
515515
}
516516

517+
impl RLPEncode for ENRResponseMessage {
518+
fn encode(&self, buf: &mut dyn BufMut) {
519+
structs::Encoder::new(buf)
520+
.encode_field(&self.request_hash)
521+
.encode_field(&self.node_record)
522+
.finish();
523+
}
524+
}
525+
526+
impl RLPEncode for NodeRecord {
527+
fn encode(&self, buf: &mut dyn BufMut) {
528+
structs::Encoder::new(buf)
529+
.encode_field(&self.signature)
530+
.encode_field(&self.seq)
531+
.encode_key_value_list::<Bytes>(&self.pairs)
532+
.finish();
533+
}
534+
}
535+
517536
impl RLPEncode for Node {
518537
fn encode(&self, buf: &mut dyn BufMut) {
519538
structs::Encoder::new(buf)
@@ -719,6 +738,81 @@ mod tests {
719738
assert_eq!(result, expected);
720739
}
721740

741+
#[test]
742+
fn test_encode_enr_response() {
743+
let request_hash =
744+
H256::from_str("ebc0a41dfdf5499552fb7e61799c577360a442170dbed4cb0745d628f06d9f98")
745+
.unwrap();
746+
let signature = H512::from_str("131d8cbc28a2dee4cae36ee3c268c44877e77eb248758d5a204df36b29a13ee53100fd47d3d6fd498ea48349d822d0965904fabcdeeecd9f5133a6062abdfbe3").unwrap();
747+
let seq = 0x018cf3c3bd18;
748+
749+
// define optional fields
750+
let eth: Vec<Vec<u32>> = vec![vec![0x88cf81d9, 0]];
751+
let id = String::from("v4");
752+
let ip = Ipv4Addr::from_str("138.197.51.181").unwrap();
753+
let secp256k1 =
754+
H264::from_str("034e5e92199ee224a01932a377160aa432f31d0b351f84ab413a8e0a42f4f36476")
755+
.unwrap();
756+
let tcp: u16 = 30303;
757+
let udp: u16 = 30303;
758+
let snap: Vec<u32> = vec![];
759+
760+
// declare buffers for optional fields encoding
761+
let mut eth_rlp = Vec::new();
762+
let mut id_rlp = Vec::new();
763+
let mut ip_rlp = Vec::new();
764+
let mut secp256k1_rlp = Vec::new();
765+
let mut tcp_rlp = Vec::new();
766+
let mut udp_rlp = Vec::new();
767+
let mut snap_rlp = Vec::new();
768+
769+
// encode optional fields
770+
eth.encode(&mut eth_rlp);
771+
id.encode(&mut id_rlp);
772+
ip.encode(&mut ip_rlp);
773+
secp256k1.encode(&mut secp256k1_rlp);
774+
tcp.encode(&mut tcp_rlp);
775+
udp.encode(&mut udp_rlp);
776+
snap.encode(&mut snap_rlp);
777+
778+
// initialize vector with (key, value) pairs
779+
let pairs: Vec<(Bytes, Bytes)> = vec![
780+
(String::from("eth").into(), eth_rlp.into()),
781+
(String::from("id").into(), id_rlp.into()),
782+
(String::from("ip").into(), ip_rlp.into()),
783+
(String::from("secp256k1").into(), secp256k1_rlp.into()),
784+
(String::from("snap").into(), snap_rlp.into()),
785+
(String::from("tcp").into(), tcp_rlp.clone().into()),
786+
(String::from("udp").into(), udp_rlp.clone().into()),
787+
];
788+
let node_record = NodeRecord {
789+
signature,
790+
seq,
791+
id: String::from("v4"),
792+
pairs,
793+
};
794+
let msg = Message::ENRResponse(ENRResponseMessage {
795+
request_hash,
796+
node_record,
797+
});
798+
799+
let key_bytes =
800+
H256::from_str("2e6a09427ba14acc853cbbff291c75c3cb57754ac1e3df8df9cac086b3a83aa4")
801+
.unwrap();
802+
let signer = SigningKey::from_slice(key_bytes.as_bytes()).unwrap();
803+
let mut buf = Vec::new();
804+
msg.encode_with_header(&mut buf, &signer);
805+
let result = to_hex(&buf);
806+
807+
let hash = "85e7d3ee8494d23694e2cbcc495be900bb035969366c4b3267ba80eef6cc9b2a";
808+
let signature = "7b714d79b4f8ec780b27329a6a8cb8188b882ecf99be0f89feeab33ebbb76ecb3dcb5ab53a1c7f27a4fc9e6e70220e614de9a351c3f39e100f40b5d0e2a7331501";
809+
let packet_type = "06";
810+
let encoded_msg = "f8c6a0ebc0a41dfdf5499552fb7e61799c577360a442170dbed4cb0745d628f06d9f98f8a3b840131d8cbc28a2dee4cae36ee3c268c44877e77eb248758d5a204df36b29a13ee53100fd47d3d6fd498ea48349d822d0965904fabcdeeecd9f5133a6062abdfbe386018cf3c3bd1883657468c7c68488cf81d980826964827634826970848ac533b589736563703235366b31a1034e5e92199ee224a01932a377160aa432f31d0b351f84ab413a8e0a42f4f3647684736e6170c08374637082765f8375647082765f";
811+
let expected = [hash, signature, packet_type, encoded_msg].concat();
812+
813+
assert_eq!(result, expected);
814+
}
815+
722816
#[test]
723817
fn test_decode_pong_message_with_enr_seq() {
724818
let hash = "2e1fc2a02ad95a1742f6dd41fb7cbff1e08548ba87f63a72221e44026ab1c347";

0 commit comments

Comments
 (0)