Skip to content

Commit 236c1a1

Browse files
fmolettaElFantasma
andauthored
feat(l1): implement TrieIterator + GetAccountRange snap request handling logic (#960)
**Motivation** Handling snap capability message `GetAccountRange` <!-- Why does this pull request exist? What are its goals? --> **Description** * Add functionality to iterate the Trie (TrieIterator) * Add functionality to iterate over all accounts in the state (Store::iter_accounts) * Add logic to handle `GetAccountRange` snap request * Fix slim encoding of `AccountState` * Remove unneeded trait `RLPEncodeSlim` **Notes** * ~We don't have the listen loop implemented so this PR only adds the standalone logic for handling the request and creating a response, we still need to plug it in to the main loop.~ * ~We are not able to run the hive test suite due to missing listen loop + old blocks being used by the test suite. I instead copied the state from a Geth execution (loading genesis + importing chain) and used that state to replicate hive tests as unit tests. These tests could be removed once we fix those two problems~ <!-- A clear and concise general description of the changes this PR introduces --> <!-- Link to issues: Resolves #111, Resolves #222 --> Partially addresses #184 --------- Co-authored-by: Esteban Dimitroff Hodi <esteban.dimitroff@lambdaclass.com>
1 parent 9c85075 commit 236c1a1

File tree

17 files changed

+1139
-141
lines changed

17 files changed

+1139
-141
lines changed

.github/workflows/hive.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ jobs:
3636
- simulation: discv4
3737
name: "Devp2p discv4 tests"
3838
run_command: make run-hive SIMULATION=devp2p TEST_PATTERN="discv4"
39+
- simulation: snap
40+
name: "Devp2p snap tests"
41+
run_command: make run-hive SIMULATION=devp2p TEST_PATTERN="/AccountRange"
3942
- simulation: engine
4043
name: "Engine tests"
4144
run_command: make run-hive SIMULATION=ethereum/engine TEST_PATTERN="/Blob Transactions On Block 1, Cancun Genesis|Blob Transactions On Block 1, Shanghai Genesis|Blob Transaction Ordering, Single Account, Single Blob|Blob Transaction Ordering, Single Account, Dual Blob|Blob Transaction Ordering, Multiple Accounts|Replace Blob Transactions|Parallel Blob Transactions|ForkchoiceUpdatedV3 Modifies Payload ID on Different Beacon Root|NewPayloadV3 After Cancun|NewPayloadV3 Versioned Hashes|ForkchoiceUpdated Version on Payload Request"

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ stop-localnet-silent:
7171
@kurtosis enclave stop lambdanet >/dev/null 2>&1 || true
7272
@kurtosis enclave rm lambdanet --force >/dev/null 2>&1 || true
7373

74-
HIVE_REVISION := ccf28e5c3e940b2bc4b4f387317ee6a46f5d15c8
74+
HIVE_REVISION := 421852ec25e4e608fe5460656f4bf0637649619e
7575
# Shallow clones can't specify a single revision, but at least we avoid working
7676
# the whole history by making it shallow since a given date (one day before our
7777
# target revision).

crates/common/rlp/encode.rs

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,6 @@ pub trait RLPEncode {
2929
}
3030
}
3131

32-
pub trait RLPEncodeSlim {
33-
fn encode(&self, buf: &mut dyn BufMut);
34-
35-
fn length(&self) -> usize {
36-
let mut buf = Vec::new();
37-
self.encode(&mut buf);
38-
buf.len()
39-
}
40-
}
41-
4232
impl RLPEncode for bool {
4333
#[inline(always)]
4434
fn encode(&self, buf: &mut dyn BufMut) {
@@ -378,38 +368,6 @@ impl RLPEncode for ethereum_types::H256 {
378368
}
379369
}
380370

381-
impl RLPEncodeSlim for ethereum_types::H256 {
382-
fn encode(&self, buf: &mut dyn BufMut) {
383-
self.as_bytes().encode(buf)
384-
}
385-
}
386-
387-
impl<T: RLPEncodeSlim> RLPEncodeSlim for Vec<T> {
388-
fn encode(&self, buf: &mut dyn BufMut) {
389-
if self.is_empty() {
390-
buf.put_u8(0xc0);
391-
} else {
392-
let mut total_len = 0;
393-
for item in self {
394-
total_len += item.length();
395-
}
396-
encode_length(total_len, buf);
397-
for item in self {
398-
item.encode(buf);
399-
}
400-
}
401-
}
402-
}
403-
404-
impl<S: RLPEncodeSlim, T: RLPEncodeSlim> RLPEncodeSlim for (S, T) {
405-
fn encode(&self, buf: &mut dyn BufMut) {
406-
let total_len = self.0.length() + self.1.length();
407-
encode_length(total_len, buf);
408-
self.0.encode(buf);
409-
self.1.encode(buf);
410-
}
411-
}
412-
413371
impl RLPEncode for ethereum_types::H264 {
414372
fn encode(&self, buf: &mut dyn BufMut) {
415373
self.as_bytes().encode(buf)

crates/common/rlp/structs.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use crate::encode::RLPEncodeSlim;
2-
31
use super::{
42
decode::{decode_rlp_item, get_item_with_prefix, RLPDecode},
53
encode::{encode_length, RLPEncode},
@@ -185,13 +183,6 @@ impl<'a> Encoder<'a> {
185183
self
186184
}
187185

188-
/// Stores a field to be encoded, but in slim format
189-
/// https://github.com/ethereum/devp2p/blob/master/caps/snap.md#data-format
190-
pub fn encode_slim_field<T: RLPEncodeSlim>(mut self, value: &T) -> Self {
191-
<T as RLPEncodeSlim>::encode(value, &mut self.temp_buf);
192-
self
193-
}
194-
195186
/// If `Some`, stores a field to be encoded, else does nothing.
196187
pub fn encode_optional_field<T: RLPEncode>(mut self, opt_value: &Option<T>) -> Self {
197188
if let Some(value) = opt_value {

crates/common/types/account.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use ethereum_types::{H256, U256};
66
use sha3::{Digest as _, Keccak256};
77

88
use ethereum_rust_rlp::{
9-
constants::{RLP_EMPTY_LIST, RLP_NULL},
9+
constants::RLP_NULL,
1010
decode::RLPDecode,
11-
encode::{RLPEncode, RLPEncodeSlim},
11+
encode::RLPEncode,
1212
error::RLPDecodeError,
1313
structs::{Decoder, Encoder},
1414
};
@@ -100,17 +100,6 @@ impl RLPEncode for AccountInfo {
100100
}
101101
}
102102

103-
impl RLPEncodeSlim for AccountInfo {
104-
fn encode(&self, buf: &mut dyn bytes::BufMut) {
105-
// TODO: check if it's okay to use RLP_EMPTY_LIST
106-
Encoder::new(buf)
107-
.encode_field(&RLP_EMPTY_LIST)
108-
.encode_field(&self.balance)
109-
.encode_field(&self.nonce)
110-
.finish();
111-
}
112-
}
113-
114103
impl RLPDecode for AccountInfo {
115104
fn decode_unfinished(rlp: &[u8]) -> Result<(AccountInfo, &[u8]), RLPDecodeError> {
116105
let decoder = Decoder::new(rlp)?;
@@ -137,18 +126,6 @@ impl RLPEncode for AccountState {
137126
}
138127
}
139128

140-
impl RLPEncodeSlim for AccountState {
141-
fn encode(&self, buf: &mut dyn bytes::BufMut) {
142-
// TODO: check if it's okay to use RLP_EMPTY_LIST
143-
Encoder::new(buf)
144-
.encode_field(&self.nonce)
145-
.encode_field(&self.balance)
146-
.encode_field(&RLP_EMPTY_LIST)
147-
.encode_field(&self.code_hash)
148-
.finish();
149-
}
150-
}
151-
152129
impl RLPDecode for AccountState {
153130
fn decode_unfinished(rlp: &[u8]) -> Result<(AccountState, &[u8]), RLPDecodeError> {
154131
let decoder = Decoder::new(rlp)?;

crates/networking/p2p/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ tokio.workspace = true
1515
bytes.workspace = true
1616
hex.workspace = true
1717
thiserror.workspace = true
18+
lazy_static.workspace = true
1819

1920
k256 = { version = "0.13.3", features = ["ecdh"] }
2021
sha3 = "0.10.8"

crates/networking/p2p/net.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub mod bootnode;
3131
pub(crate) mod discv4;
3232
pub(crate) mod kademlia;
3333
pub mod rlpx;
34+
pub(crate) mod snap;
3435
pub mod types;
3536

3637
const MAX_DISC_PACKET_SIZE: usize = 1280;

crates/networking/p2p/rlpx/connection.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::{
22
rlpx::{eth::backend, handshake::encode_ack_message, message::Message, p2p, utils::id2pubkey},
3+
snap::process_account_range_request,
34
MAX_DISC_PACKET_SIZE,
45
};
56

@@ -25,9 +26,8 @@ use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
2526
use tracing::{error, info};
2627
const CAP_P2P: (Capability, u8) = (Capability::P2p, 5);
2728
const CAP_ETH: (Capability, u8) = (Capability::Eth, 68);
28-
//const CAP_SNAP: (Capability, u8) = (Capability::Snap, 1);
29-
const SUPPORTED_CAPABILITIES: [(Capability, u8); 2] = [CAP_P2P, CAP_ETH];
30-
// pub const SUPPORTED_CAPABILITIES: [(&str, u8); 3] = [CAP_P2P, CAP_ETH, CAP_SNAP)];
29+
const CAP_SNAP: (Capability, u8) = (Capability::Snap, 1);
30+
const SUPPORTED_CAPABILITIES: [(Capability, u8); 3] = [CAP_P2P, CAP_ETH, CAP_SNAP];
3131

3232
pub(crate) type Aes256Ctr64BE = ctr::Ctr64BE<aes::Aes256>;
3333

@@ -145,6 +145,11 @@ impl<S: AsyncWrite + AsyncRead + std::marker::Unpin> RLPxConnection<S> {
145145
Message::Ping(_) => info!("Received Ping"),
146146
Message::Pong(_) => info!("Received Pong"),
147147
Message::Status(_) => info!("Received Status"),
148+
Message::GetAccountRange(req) => {
149+
let response =
150+
process_account_range_request(req, self.storage.clone())?;
151+
self.send(Message::AccountRange(response)).await
152+
}
148153
// TODO: Add new message types and handlers as they are implemented
149154
message => return Err(RLPxError::UnexpectedMessage(message)),
150155
};

crates/networking/p2p/rlpx/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::rlpx::message::Message;
2+
use ethereum_rust_storage::error::StoreError;
23
use thiserror::Error;
34

45
// TODO improve errors
@@ -10,4 +11,6 @@ pub(crate) enum RLPxError {
1011
InvalidState(String),
1112
#[error("Unexpected message: {0}")]
1213
UnexpectedMessage(Message),
14+
#[error(transparent)]
15+
Store(#[from] StoreError),
1316
}

crates/networking/p2p/rlpx/frame.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ pub(crate) async fn write<S: AsyncWrite + std::marker::Unpin>(
6565
};
6666
state.egress_mac.update(frame_mac_seed);
6767
let frame_mac = state.egress_mac.clone().finalize();
68-
6968
// Send frame-mac
7069
stream.write_all(&frame_mac[..16]).await.unwrap();
7170
}

crates/networking/p2p/rlpx/message.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use std::fmt::Display;
44

55
use super::eth::status::StatusMessage;
66
use super::p2p::{DisconnectMessage, HelloMessage, PingMessage, PongMessage};
7+
use super::snap::{AccountRange, GetAccountRange};
8+
9+
use ethereum_rust_rlp::encode::RLPEncode;
710

811
pub trait RLPxMessage: Sized {
912
fn encode(&self, buf: &mut dyn BufMut) -> Result<(), RLPEncodeError>;
@@ -17,6 +20,9 @@ pub(crate) enum Message {
1720
Ping(PingMessage),
1821
Pong(PongMessage),
1922
Status(StatusMessage),
23+
// snap capability
24+
GetAccountRange(GetAccountRange),
25+
AccountRange(AccountRange),
2026
}
2127

2228
impl Message {
@@ -27,6 +33,8 @@ impl Message {
2733
0x02 => Ok(Message::Ping(PingMessage::decode(msg_data)?)),
2834
0x03 => Ok(Message::Pong(PongMessage::decode(msg_data)?)),
2935
0x10 => Ok(Message::Status(StatusMessage::decode(msg_data)?)),
36+
0x21 => Ok(Message::GetAccountRange(GetAccountRange::decode(msg_data)?)),
37+
0x22 => Ok(Message::AccountRange(AccountRange::decode(msg_data)?)),
3038
_ => Err(RLPDecodeError::MalformedData),
3139
}
3240
}
@@ -38,6 +46,14 @@ impl Message {
3846
Message::Ping(msg) => msg.encode(buf),
3947
Message::Pong(msg) => msg.encode(buf),
4048
Message::Status(msg) => msg.encode(buf),
49+
Message::GetAccountRange(msg) => {
50+
0x21_u8.encode(buf);
51+
msg.encode(buf)
52+
}
53+
Message::AccountRange(msg) => {
54+
0x22_u8.encode(buf);
55+
msg.encode(buf)
56+
}
4157
}
4258
}
4359
}
@@ -50,6 +66,8 @@ impl Display for Message {
5066
Message::Ping(_) => "p2p:Ping".fmt(f),
5167
Message::Pong(_) => "p2p:Pong".fmt(f),
5268
Message::Status(_) => "eth:Status".fmt(f),
69+
Message::GetAccountRange(_) => "snap:GetAccountRange".fmt(f),
70+
Message::AccountRange(_) => "snap:AccountRange".fmt(f),
5371
}
5472
}
5573
}

0 commit comments

Comments
 (0)