Skip to content

Commit

Permalink
more updates
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby committed Apr 21, 2024
1 parent cc0089c commit a4486f7
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 51 deletions.
10 changes: 5 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 21 additions & 5 deletions crates/mpt/src/list_walker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,18 +132,19 @@ impl<PreimageFetcher> Iterator for OrderedListWalker<PreimageFetcher> {

#[cfg(test)]
mod test {
extern crate std;

use super::*;
use crate::test_util::{get_live_derivable_receipts_list, ordered_trie_with_encoder};
use crate::test_util::{
get_live_derivable_receipts_list, get_live_derivable_transactions_list,
ordered_trie_with_encoder,
};
use alloc::{collections::BTreeMap, string::String, vec::Vec};
use alloy_consensus::ReceiptEnvelope;
use alloy_consensus::{ReceiptEnvelope, TxEnvelope};
use alloy_primitives::keccak256;
use alloy_provider::network::eip2718::Decodable2718;
use alloy_rlp::Encodable;

#[tokio::test]
async fn test_list_walker_online() {
async fn test_list_walker_online_receipts() {
let (root, preimages, envelopes) = get_live_derivable_receipts_list().await.unwrap();
let list =
OrderedListWalker::try_new_hydrated(root, |f| Ok(preimages.get(&f).unwrap().clone()))
Expand All @@ -157,6 +158,21 @@ mod test {
);
}

#[tokio::test]
async fn test_list_walker_online_transactions() {
let (root, preimages, envelopes) = get_live_derivable_transactions_list().await.unwrap();
let list =
OrderedListWalker::try_new_hydrated(root, |f| Ok(preimages.get(&f).unwrap().clone()))
.unwrap();

assert_eq!(
list.into_iter()
.map(|rlp| TxEnvelope::decode(&mut rlp.as_ref()).unwrap())
.collect::<Vec<_>>(),
envelopes
);
}

#[test]
fn test_list_walker() {
const VALUES: [&str; 3] = ["test one", "test two", "test three"];
Expand Down
64 changes: 27 additions & 37 deletions crates/mpt/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ pub enum TrieNode {
},
}

impl TrieNode {
/// Attempts to convert a `path` and `value` into a [TrieNode], if they correspond to a
/// [TrieNode::Leaf] or [TrieNode::Extension].
pub fn try_from_path_and_value(path: Bytes, value: Bytes) -> Result<Self> {
match path[0] >> 4 {
PREFIX_EXTENSION_EVEN | PREFIX_EXTENSION_ODD => {
// extension node
Ok(TrieNode::Extension { prefix: path, node: value })
}
PREFIX_LEAF_EVEN | PREFIX_LEAF_ODD => {
// leaf node
Ok(TrieNode::Leaf { key: path, value })
}
_ => {
anyhow::bail!("Unexpected path identifier in high-order nibble")
}
}
}
}

impl Decodable for TrieNode {
/// Attempts to decode the [TrieNode].
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
Expand All @@ -59,28 +79,12 @@ impl Decodable for TrieNode {
let Some(NodeElement::String(path)) = list.pop_front() else {
return Err(alloy_rlp::Error::UnexpectedList);
};
let Some(NodeElement::String(value)) = list.pop_front() else {
return Err(alloy_rlp::Error::UnexpectedList);
};

match path[0] >> 4 {
PREFIX_EXTENSION_EVEN | PREFIX_EXTENSION_ODD => {
// extension node
let Some(NodeElement::String(node)) = list.pop_front() else {
return Err(alloy_rlp::Error::UnexpectedList);
};

Ok(Self::Extension { prefix: path, node })
}
PREFIX_LEAF_EVEN | PREFIX_LEAF_ODD => {
// leaf node
let Some(NodeElement::String(value)) = list.pop_front() else {
return Err(alloy_rlp::Error::UnexpectedList);
};

Ok(Self::Leaf { key: path, value })
}
_ => Err(alloy_rlp::Error::Custom(
"Unexpected path identifier in high-order nibble",
)),
}
Self::try_from_path_and_value(path, value)
.map_err(|_| alloy_rlp::Error::UnexpectedList)
}
_ => Err(alloy_rlp::Error::UnexpectedLength),
}
Expand Down Expand Up @@ -110,22 +114,8 @@ impl NodeElement {
}

let path = list.pop_front().ok_or(anyhow!("List is empty; Impossible case"))?;
match path[0] >> 4 {
0 | 1 => {
// extension node
let node = list.pop_front().ok_or(anyhow!("List is empty; Impossible case"))?;
Ok(TrieNode::Extension { prefix: path, node })
}
2 | 3 => {
// leaf node
let value =
list.pop_front().ok_or(anyhow!("List is empty; Impossible case"))?;
Ok(TrieNode::Leaf { key: path, value })
}
_ => {
anyhow::bail!("Unexpected path identifier in high-order nibble")
}
}
let value = list.pop_front().ok_or(anyhow!("List is empty; Impossible case"))?;
TrieNode::try_from_path_and_value(path, value)
} else {
anyhow::bail!("Self is not a list")
}
Expand Down
51 changes: 47 additions & 4 deletions crates/mpt/src/test_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,26 @@
extern crate std;

use alloc::{collections::BTreeMap, vec::Vec};
use alloy_consensus::{Receipt, ReceiptEnvelope, ReceiptWithBloom, TxType};
use alloy_consensus::{Receipt, ReceiptEnvelope, ReceiptWithBloom, TxEnvelope, TxType};
use alloy_primitives::{keccak256, Bytes, Log, B256};
use alloy_provider::{network::eip2718::Encodable2718, Provider, ProviderBuilder};
use alloy_rlp::{BufMut, Encodable};
use alloy_rpc_types::BlockTransactions;
use alloy_trie::{HashBuilder, Nibbles};
use anyhow::{anyhow, Result};
use reqwest::Url;

const RPC_URL: &str = "https://docs-demo.quiknode.pro/";

/// Grabs a live merkleized receipts list within a block header.
pub(crate) async fn get_live_derivable_receipts_list(
) -> Result<(B256, BTreeMap<B256, Bytes>, Vec<ReceiptEnvelope>)> {
// Initialize the provider.
let rpc_url = "http://anton.clab.by:8545";
let provider = ProviderBuilder::new()
.on_http(Url::parse(rpc_url).expect("invalid rpc url"))
.on_http(Url::parse(RPC_URL).expect("invalid rpc url"))
.map_err(|e| anyhow!(e))?;

let block_number = provider.get_block_number().await.map_err(|e| anyhow!(e))?;
let block_number = 19005266;
let block = provider
.get_block(block_number.into(), true)
.await
Expand Down Expand Up @@ -77,6 +79,47 @@ pub(crate) async fn get_live_derivable_receipts_list(
Ok((root, preimages, consensus_receipts))
}

/// Grabs a live merkleized transactions list within a block header.
pub(crate) async fn get_live_derivable_transactions_list(
) -> Result<(B256, BTreeMap<B256, Bytes>, Vec<TxEnvelope>)> {
// Initialize the provider.
let provider = ProviderBuilder::new()
.on_http(Url::parse(RPC_URL).expect("invalid rpc url"))
.map_err(|e| anyhow!(e))?;

let block_number = 19005266;
let block = provider
.get_block(block_number.into(), true)
.await
.map_err(|e| anyhow!(e))?
.ok_or(anyhow!("Missing block"))?;

let BlockTransactions::Full(txs) = block.transactions else {
anyhow::bail!("Did not fetch full block");
};
let consensus_txs = txs
.into_iter()
.map(|tx| TxEnvelope::try_from(tx).map_err(|e| anyhow!(e)))
.collect::<Result<Vec<_>>>()?;

// Compute the derivable list
let mut list =
ordered_trie_with_encoder(consensus_txs.as_ref(), |rlp, buf| rlp.encode_2718(buf));
let root = list.root();

// Sanity check transaction root is correct
assert_eq!(block.header.transactions_root, root);

// Construct the mapping of hashed intermediates -> raw intermediates
let preimages =
list.take_proofs().into_iter().fold(BTreeMap::default(), |mut acc, (_, value)| {
acc.insert(keccak256(value.as_ref()), value);
acc
});

Ok((root, preimages, consensus_txs))
}

/// Compute a trie root of the collection of items with a custom encoder.
pub(crate) fn ordered_trie_with_encoder<T, F>(items: &[T], mut encode: F) -> HashBuilder
where
Expand Down

0 comments on commit a4486f7

Please sign in to comment.