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

feat(l1): support snap capability message GetStorageRanges #1025

Merged
merged 90 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
02fe744
Corrupted History Fix
fmoletta Oct 22, 2024
a2a2aac
Fix slim encoding for AccountState
fmoletta Oct 22, 2024
aef7441
Fix slim encoding for AccountState
fmoletta Oct 22, 2024
13d9bc3
Commit progress
fmoletta Oct 22, 2024
0ca3589
Commit progress
fmoletta Oct 22, 2024
66b6f90
Add snap as supported cap
fmoletta Oct 22, 2024
41dcaff
Push missing changes
fmoletta Oct 23, 2024
a526c10
Initial peer listen loop
ElFantasma Oct 23, 2024
562bc49
Deprecate `RLPEncodeSlim` trait and use `AccountStateSlim` instead
fmoletta Oct 23, 2024
3893b05
Fix logic
fmoletta Oct 23, 2024
dbe110f
Remove debug print
fmoletta Oct 23, 2024
8b8eacb
Limit response bytes
fmoletta Oct 23, 2024
4ee1790
Add test
fmoletta Oct 23, 2024
d87b1ca
Add more tests
fmoletta Oct 23, 2024
89621bf
Cleanup test code + Fix logic + add test
fmoletta Oct 23, 2024
3a14cdd
Add test
fmoletta Oct 23, 2024
c354321
Add test
fmoletta Oct 23, 2024
7abd4f7
Add test
fmoletta Oct 23, 2024
7cee2b7
Add test
fmoletta Oct 23, 2024
579309f
Also fetch limit proof
fmoletta Oct 23, 2024
9fccb07
Trim test state 408 -> 100
fmoletta Oct 24, 2024
38a7d5b
Simplify logic
fmoletta Oct 24, 2024
574299b
Merge branch 'main' into 840-rlpx-listen-loop
ElFantasma Oct 24, 2024
704da4c
Encode accounts while building range so we do not encode twice
fmoletta Oct 24, 2024
b55294b
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Oct 24, 2024
6d5cc45
Clippy
fmoletta Oct 24, 2024
9514037
Add allow tag
fmoletta Oct 24, 2024
a5b3934
Remove comment
fmoletta Oct 24, 2024
68dcef6
Fix typo
fmoletta Oct 24, 2024
f23077e
Sending eth Status message first
ElFantasma Oct 24, 2024
122778d
Small fixes
ElFantasma Oct 25, 2024
7a4f9cf
Merge branch 'main' into 840-rlpx-listen-loop
ElFantasma Oct 25, 2024
5ae41fe
Small fixes
ElFantasma Oct 25, 2024
66b0bd8
Added TODO comments for pending tasks
ElFantasma Oct 25, 2024
6a5f580
Refactored code to separate encoding/decoding from backend logic
ElFantasma Oct 25, 2024
6c04bb6
Merge branch '840-rlpx-listen-loop' of github.com:lambdaclass/lambda_…
fmoletta Oct 25, 2024
05c9a5e
Replaced hardcoded capabilities strings with enums
ElFantasma Oct 25, 2024
f011aa6
Merge branch 'main' into 840-rlpx-listen-loop
ElFantasma Oct 25, 2024
8ea2644
Add snap messages to liste loop
fmoletta Oct 25, 2024
42049ab
Made Status test to pass
ElFantasma Oct 28, 2024
34e0d9c
Merge branch 'main' into 840-rlpx-listen-loop
ElFantasma Oct 28, 2024
940b6f3
Fixed format
ElFantasma Oct 28, 2024
8047f41
Removed required Debug format on error printing
ElFantasma Oct 28, 2024
f474617
Trying previous commit from hive to see if CI works
ElFantasma Oct 28, 2024
1d5223b
Fix `AccountRange message decoding
fmoletta Oct 28, 2024
80329c7
Fix
fmoletta Oct 28, 2024
297a37b
fix
fmoletta Oct 28, 2024
f25fb1a
Fix: build proof for last account not limit hash
fmoletta Oct 28, 2024
0fdf562
Using apply_fork_choice to set last block number and make blocks cann…
ElFantasma Oct 28, 2024
c989418
Merge branch 'main' into 840-rlpx-listen-loop
ElFantasma Oct 28, 2024
12010b3
Fmt + Return error instead of pancking if invalid root is used
fmoletta Oct 28, 2024
ed0186f
Calling apply_fork_choice only once for the whole chain
ElFantasma Oct 28, 2024
42f2af3
Revert change
fmoletta Oct 28, 2024
61ad329
Return empty proof if root is missing
fmoletta Oct 28, 2024
13c44cf
Calling apply_fork_choice only once for the whole chain
ElFantasma Oct 28, 2024
ecb682f
Clippy fix
ElFantasma Oct 28, 2024
f8bd1dc
use trait method
fmoletta Oct 28, 2024
b890f60
Merge remote-tracking branch 'origin/840-rlpx-listen-loop' into trie_…
fmoletta Oct 28, 2024
31aa8ac
Update hive revision
fmoletta Oct 28, 2024
34d8d84
Reorganize module
fmoletta Oct 28, 2024
9b85c69
Merge branch 'main' into 840-rlpx-listen-loop
ElFantasma Oct 29, 2024
013a977
Update hive revision
fmoletta Oct 29, 2024
66f759a
Add hive snap worflow
fmoletta Oct 29, 2024
67cb57a
Merge branch 'main' into 840-rlpx-listen-loop
ElFantasma Oct 29, 2024
b1ea882
Reverting hive version
ElFantasma Oct 29, 2024
58da873
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Oct 29, 2024
fe2fb77
Removed unnecessary info! messages
ElFantasma Oct 29, 2024
50ca190
Merge branch '840-rlpx-listen-loop' into trie_iter
fmoletta Oct 29, 2024
7062b1b
Add messages + inner structs
fmoletta Oct 29, 2024
d609cae
progress
fmoletta Oct 29, 2024
c69690d
Bump hive version
fmoletta Oct 29, 2024
65f8c77
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Oct 29, 2024
b7c0211
Fix bug in response bytes length calculation
fmoletta Oct 29, 2024
74173d2
Restore Makefile
fmoletta Oct 29, 2024
777732a
Identify storage tries by hashed account address
fmoletta Oct 29, 2024
0e3e276
Merge branch 'trie_iter' into snap-storage-range
fmoletta Oct 29, 2024
abb28cf
Impl logic
fmoletta Oct 29, 2024
fea174d
Connect to main loop
fmoletta Oct 30, 2024
dc6752c
Compute proofs
fmoletta Oct 30, 2024
03d9928
Clippy
fmoletta Oct 30, 2024
c791a89
Chamge type
fmoletta Oct 30, 2024
9fd88d3
Add test
fmoletta Oct 30, 2024
3b7d70e
Fix
fmoletta Oct 31, 2024
384eff7
Merge branch 'trie_iter' into snap-storage-range
fmoletta Oct 31, 2024
d02e8f2
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Oct 31, 2024
0575a44
Merge branch 'snap-storage-range' of github.com:lambdaclass/lambda_et…
fmoletta Oct 31, 2024
aa29e5f
Fix lingering conflicts
fmoletta Oct 31, 2024
200d014
Merge branch 'main' of github.com:lambdaclass/lambda_ethereum_rust in…
fmoletta Nov 4, 2024
b270580
Update workflow
fmoletta Nov 4, 2024
09f688b
Clippy
fmoletta Nov 5, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/hive_and_assertoor.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
run_command: make run-hive-on-latest SIMULATION=devp2p TEST_PATTERN="discv4"
- simulation: snap
name: "Devp2p snap tests"
run_command: make run-hive-on-latest SIMULATION=devp2p TEST_PATTERN="/AccountRange"
run_command: make run-hive-on-latest SIMULATION=devp2p TEST_PATTERN="/AccountRange|StorageRanges"
- simulation: engine
name: "Engine tests"
run_command: make run-hive-on-latest 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"
Expand Down
7 changes: 6 additions & 1 deletion crates/networking/p2p/rlpx/connection.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
rlpx::{eth::backend, handshake::encode_ack_message, message::Message, p2p, utils::id2pubkey},
snap::process_account_range_request,
snap::{process_account_range_request, process_storage_ranges_request},
MAX_DISC_PACKET_SIZE,
};

Expand Down Expand Up @@ -150,6 +150,11 @@ impl<S: AsyncWrite + AsyncRead + std::marker::Unpin> RLPxConnection<S> {
process_account_range_request(req, self.storage.clone())?;
self.send(Message::AccountRange(response)).await
}
Message::GetStorageRanges(req) => {
let response =
process_storage_ranges_request(req, self.storage.clone())?;
self.send(Message::StorageRanges(response)).await
}
// TODO: Add new message types and handlers as they are implemented
message => return Err(RLPxError::UnexpectedMessage(message)),
};
Expand Down
18 changes: 17 additions & 1 deletion crates/networking/p2p/rlpx/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::fmt::Display;

use super::eth::status::StatusMessage;
use super::p2p::{DisconnectMessage, HelloMessage, PingMessage, PongMessage};
use super::snap::{AccountRange, GetAccountRange};
use super::snap::{AccountRange, GetAccountRange, GetStorageRanges, StorageRanges};

use ethereum_rust_rlp::encode::RLPEncode;

Expand All @@ -23,6 +23,8 @@ pub(crate) enum Message {
// snap capability
GetAccountRange(GetAccountRange),
AccountRange(AccountRange),
GetStorageRanges(GetStorageRanges),
StorageRanges(StorageRanges),
}

impl Message {
Expand All @@ -35,6 +37,10 @@ impl Message {
0x10 => Ok(Message::Status(StatusMessage::decode(msg_data)?)),
0x21 => Ok(Message::GetAccountRange(GetAccountRange::decode(msg_data)?)),
0x22 => Ok(Message::AccountRange(AccountRange::decode(msg_data)?)),
0x23 => Ok(Message::GetStorageRanges(GetStorageRanges::decode(
msg_data,
)?)),
0x24 => Ok(Message::StorageRanges(StorageRanges::decode(msg_data)?)),
_ => Err(RLPDecodeError::MalformedData),
}
}
Expand All @@ -54,6 +60,14 @@ impl Message {
0x22_u8.encode(buf);
msg.encode(buf)
}
Message::GetStorageRanges(msg) => {
0x23_u8.encode(buf);
msg.encode(buf)
}
Message::StorageRanges(msg) => {
0x24_u8.encode(buf);
msg.encode(buf)
}
}
}
}
Expand All @@ -68,6 +82,8 @@ impl Display for Message {
Message::Status(_) => "eth:Status".fmt(f),
Message::GetAccountRange(_) => "snap:GetAccountRange".fmt(f),
Message::AccountRange(_) => "snap:AccountRange".fmt(f),
Message::GetStorageRanges(_) => "snap:GetStorageRanges".fmt(f),
Message::StorageRanges(_) => "snap:StorageRanges".fmt(f),
}
}
}
123 changes: 118 additions & 5 deletions crates/networking/p2p/rlpx/snap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ pub(crate) struct AccountRange {
pub proof: Vec<Bytes>,
}

#[derive(Debug)]
pub(crate) struct GetStorageRanges {
pub id: u64,
pub root_hash: H256,
pub account_hashes: Vec<H256>,
pub starting_hash: H256,
pub limit_hash: H256,
pub response_bytes: u64,
}

#[derive(Debug)]
pub(crate) struct StorageRanges {
pub id: u64,
pub slots: Vec<Vec<StorageSlot>>,
pub proof: Vec<Bytes>,
}

impl RLPxMessage for GetAccountRange {
fn encode(&self, buf: &mut dyn BufMut) -> Result<(), RLPEncodeError> {
let mut encoded_data = vec![];
Expand All @@ -55,11 +72,12 @@ impl RLPxMessage for GetAccountRange {
.decompress_vec(msg_data)
.map_err(|e| RLPDecodeError::Custom(e.to_string()))?;
let decoder = Decoder::new(&decompressed_data)?;
let (id, decoder): (u64, _) = decoder.decode_field("request-id")?;
let (root_hash, decoder): (H256, _) = decoder.decode_field("rootHash")?;
let (starting_hash, decoder): (H256, _) = decoder.decode_field("startingHash")?;
let (limit_hash, decoder): (H256, _) = decoder.decode_field("limitHash")?;
let (response_bytes, _): (u64, _) = decoder.decode_field("responseBytes")?;
let (id, decoder) = decoder.decode_field("request-id")?;
let (root_hash, decoder) = decoder.decode_field("rootHash")?;
let (starting_hash, decoder) = decoder.decode_field("startingHash")?;
let (limit_hash, decoder) = decoder.decode_field("limitHash")?;
let (response_bytes, decoder) = decoder.decode_field("responseBytes")?;
decoder.finish()?;

Ok(Self {
id,
Expand Down Expand Up @@ -104,6 +122,77 @@ impl RLPxMessage for AccountRange {
}
}

impl RLPxMessage for GetStorageRanges {
fn encode(&self, buf: &mut dyn BufMut) -> Result<(), RLPEncodeError> {
let mut encoded_data = vec![];
Encoder::new(&mut encoded_data)
.encode_field(&self.id)
.encode_field(&self.root_hash)
.encode_field(&self.account_hashes)
.encode_field(&self.starting_hash)
.encode_field(&self.limit_hash)
.encode_field(&self.response_bytes)
.finish();

let msg_data = snappy_encode(encoded_data)?;
buf.put_slice(&msg_data);
Ok(())
}

fn decode(msg_data: &[u8]) -> Result<Self, RLPDecodeError> {
let mut snappy_decoder = SnappyDecoder::new();
let decompressed_data = snappy_decoder
.decompress_vec(msg_data)
.map_err(|e| RLPDecodeError::Custom(e.to_string()))?;
let decoder = Decoder::new(&decompressed_data)?;
let (id, decoder) = decoder.decode_field("request-id")?;
let (root_hash, decoder) = decoder.decode_field("rootHash")?;
let (account_hashes, decoder) = decoder.decode_field("accountHashes")?;
let (starting_hash, decoder) = decoder.decode_field("startingHash")?;
let (limit_hash, decoder) = decoder.decode_field("limitHash")?;
let (response_bytes, decoder) = decoder.decode_field("responseBytes")?;
decoder.finish()?;

Ok(Self {
id,
root_hash,
starting_hash,
account_hashes,
limit_hash,
response_bytes,
})
}
}

impl RLPxMessage for StorageRanges {
fn encode(&self, buf: &mut dyn BufMut) -> Result<(), RLPEncodeError> {
let mut encoded_data = vec![];
Encoder::new(&mut encoded_data)
.encode_field(&self.id)
.encode_field(&self.slots)
.encode_field(&self.proof)
.finish();

let msg_data = snappy_encode(encoded_data)?;
buf.put_slice(&msg_data);
Ok(())
}

fn decode(msg_data: &[u8]) -> Result<Self, RLPDecodeError> {
let mut snappy_decoder = SnappyDecoder::new();
let decompressed_data = snappy_decoder
.decompress_vec(msg_data)
.map_err(|e| RLPDecodeError::Custom(e.to_string()))?;
let decoder = Decoder::new(&decompressed_data)?;
let (id, decoder) = decoder.decode_field("request-id")?;
let (slots, decoder) = decoder.decode_field("slots")?;
let (proof, decoder) = decoder.decode_field("proof")?;
decoder.finish()?;

Ok(Self { id, slots, proof })
}
}

// Intermediate structures

#[derive(Debug)]
Expand All @@ -120,6 +209,12 @@ pub struct AccountStateSlim {
pub code_hash: Bytes,
}

#[derive(Debug)]
pub struct StorageSlot {
pub hash: H256,
pub data: U256,
}

impl RLPEncode for AccountRangeUnit {
fn encode(&self, buf: &mut dyn BufMut) {
Encoder::new(buf)
Expand Down Expand Up @@ -209,3 +304,21 @@ impl From<AccountStateSlim> for AccountState {
}
}
}

impl RLPEncode for StorageSlot {
fn encode(&self, buf: &mut dyn BufMut) {
Encoder::new(buf)
.encode_field(&self.hash)
.encode_field(&self.data)
.finish();
}
}

impl RLPDecode for StorageSlot {
fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
let decoder = Decoder::new(rlp)?;
let (hash, decoder) = decoder.decode_field("hash")?;
let (data, decoder) = decoder.decode_field("data")?;
Ok((Self { hash, data }, decoder.finish()?))
}
}
64 changes: 63 additions & 1 deletion crates/networking/p2p/snap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ use bytes::Bytes;
use ethereum_rust_rlp::encode::RLPEncode;
use ethereum_rust_storage::{error::StoreError, Store};

use crate::rlpx::snap::{AccountRange, AccountRangeUnit, AccountStateSlim, GetAccountRange};
use crate::rlpx::snap::{
AccountRange, AccountRangeUnit, AccountStateSlim, GetAccountRange, GetStorageRanges,
StorageRanges, StorageSlot,
};

pub fn process_account_range_request(
request: GetAccountRange,
Expand Down Expand Up @@ -36,6 +39,65 @@ pub fn process_account_range_request(
})
}

pub fn process_storage_ranges_request(
request: GetStorageRanges,
store: Store,
) -> Result<StorageRanges, StoreError> {
let mut slots = vec![];
let mut proof = vec![];
let mut bytes_used = 0;

for hashed_address in request.account_hashes {
let mut account_slots = vec![];
let mut res_capped = false;

if let Some(storage_iter) = store.iter_storage(request.root_hash, hashed_address)? {
for (hash, data) in storage_iter {
if hash >= request.starting_hash {
bytes_used += 64_u64; // slot size
account_slots.push(StorageSlot { hash, data });
}
if hash >= request.limit_hash || bytes_used >= request.response_bytes {
if bytes_used >= request.response_bytes {
res_capped = true;
}
break;
}
}
}

// Generate proofs only if the response doesn't contain the full storage range for the account
// Aka if the starting hash is not zero or if the response was capped due to byte limit
if !request.starting_hash.is_zero() || res_capped && !account_slots.is_empty() {
proof.extend(
store
.get_storage_range_proof(
request.root_hash,
hashed_address,
request.starting_hash,
account_slots.last().map(|acc| acc.hash),
)?
.unwrap_or_default()
.iter()
.map(|bytes| Bytes::copy_from_slice(bytes)),
);
}

if !account_slots.is_empty() {
slots.push(account_slots);
}

if bytes_used >= request.response_bytes {
break;
}
}
Ok(StorageRanges {
id: request.id,
slots,
proof,
})
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down
4 changes: 2 additions & 2 deletions crates/storage/store/engines/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bytes::Bytes;
use ethereum_rust_core::types::{
Block, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig, Index, Receipt, Transaction,
};
use ethereum_types::{Address, H256, U256};
use ethereum_types::{H256, U256};
use std::{fmt::Debug, panic::RefUnwindSafe};

use crate::error::StoreError;
Expand Down Expand Up @@ -201,7 +201,7 @@ pub trait StoreEngine: Debug + Send + Sync + RefUnwindSafe {
// Obtain a storage trie from the given address and storage_root
// Doesn't check if the account is stored
// Used for internal store operations
fn open_storage_trie(&self, address: Address, storage_root: H256) -> Trie;
fn open_storage_trie(&self, hashed_address: H256, storage_root: H256) -> Trie;

// Obtain a state trie from the given state root
// Doesn't check if the state root is valid
Expand Down
9 changes: 5 additions & 4 deletions crates/storage/store/engines/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ethereum_rust_core::types::{
Block, BlockBody, BlockHash, BlockHeader, BlockNumber, ChainConfig, Index, Receipt,
};
use ethereum_rust_trie::{InMemoryTrieDB, Trie};
use ethereum_types::{Address, H256, U256};
use ethereum_types::{H256, U256};
use std::{
collections::HashMap,
fmt::Debug,
Expand All @@ -31,7 +31,8 @@ struct StoreInner {
transaction_locations: HashMap<H256, Vec<(BlockNumber, BlockHash, Index)>>,
receipts: HashMap<BlockHash, HashMap<Index, Receipt>>,
state_trie_nodes: NodeMap,
storage_trie_nodes: HashMap<Address, NodeMap>,
// A storage trie for each hashed account address
storage_trie_nodes: HashMap<H256, NodeMap>,
// TODO (#307): Remove TotalDifficulty.
block_total_difficulties: HashMap<BlockHash, U256>,
// Stores local blocks by payload id
Expand Down Expand Up @@ -295,9 +296,9 @@ impl StoreEngine for Store {
Ok(self.inner().chain_data.pending_block_number)
}

fn open_storage_trie(&self, address: Address, storage_root: H256) -> Trie {
fn open_storage_trie(&self, hashed_address: H256, storage_root: H256) -> Trie {
let mut store = self.inner();
let trie_backend = store.storage_trie_nodes.entry(address).or_default();
let trie_backend = store.storage_trie_nodes.entry(hashed_address).or_default();
let db = Box::new(InMemoryTrieDB::new(trie_backend.clone()));
Trie::open(db, storage_root)
}
Expand Down
12 changes: 6 additions & 6 deletions crates/storage/store/engines/libmdbx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use ethereum_rust_core::types::{
use ethereum_rust_rlp::decode::RLPDecode;
use ethereum_rust_rlp::encode::RLPEncode;
use ethereum_rust_trie::{LibmdbxDupsortTrieDB, LibmdbxTrieDB, Trie};
use ethereum_types::{Address, H256, U256};
use ethereum_types::{H256, U256};
use libmdbx::orm::{Decodable, Encodable, Table};
use libmdbx::{
dupsort,
Expand Down Expand Up @@ -324,10 +324,10 @@ impl StoreEngine for Store {
}
}

fn open_storage_trie(&self, address: Address, storage_root: H256) -> Trie {
let db = Box::new(LibmdbxDupsortTrieDB::<StorageTriesNodes, [u8; 20]>::new(
fn open_storage_trie(&self, hashed_address: H256, storage_root: H256) -> Trie {
let db = Box::new(LibmdbxDupsortTrieDB::<StorageTriesNodes, [u8; 32]>::new(
self.db.clone(),
address.0,
hashed_address.0,
));
Trie::open(db, storage_root)
}
Expand Down Expand Up @@ -466,8 +466,8 @@ dupsort!(

dupsort!(
/// Table containing all storage trie's nodes
/// Each node is stored by address and node hash in order to keep different storage trie's nodes separate
( StorageTriesNodes ) ([u8;20], [u8;33])[[u8;20]] => Vec<u8>
/// Each node is stored by hashed account address and node hash in order to keep different storage trie's nodes separate
( StorageTriesNodes ) ([u8;32], [u8;33])[[u8;32]] => Vec<u8>
);

dupsort!(
Expand Down
Loading
Loading