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

Txn and receipt tries #6

Merged
merged 4 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ eth_trie_utils = "0.6.0"
hex = { workspace = true }
keccak-hash = "0.10.0"
log = { workspace = true }
plonky_block_proof_gen = { git = "https://github.com/mir-protocol/plonky-block-proof-gen.git", rev = "0223001b5dc0ebfc77918bb502811eeea0487edc" }
plonky_block_proof_gen = { git = "https://github.com/mir-protocol/plonky-block-proof-gen.git", rev = "44b24560e63367b7f161923e62e1da8bf998c5c8" }
plonky2_evm = { workspace = true }
rlp = { workspace = true }
rlp-derive = "0.1.0"
Expand Down
39 changes: 29 additions & 10 deletions parser/src/edge_payloads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,14 @@ pub struct TxnBytesAndTraces {
/// The root of the receipt trie after the txn has been executed.
pub receipt_root: H256,

// ReceiptNodeHash is the hash of the new receipt node added by the txn.
pub receipt: Vec<u8>,

// GasUsed is the amount of gas used by the transaction
pub gas_used: u64,

// Bloom is the bloom filter for the transaction
#[serde_as(as = "FromInto<BloomWrapper>")]
pub bloom: [U256; 8],

#[serde(rename(deserialize = "delta"))]
Expand Down Expand Up @@ -183,33 +187,48 @@ fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D:
where
E: Error,
{
FromHex::from_hex(Self::remove_prefix_if_present(data)).map_err(Error::custom)
FromHex::from_hex(remove_hex_prefix_if_present(data)).map_err(Error::custom)
}

fn visit_borrowed_str<E>(self, data: &'de str) -> Result<Self::Value, E>
where
E: Error,
{
FromHex::from_hex(Self::remove_prefix_if_present(data)).map_err(Error::custom)
FromHex::from_hex(remove_hex_prefix_if_present(data)).map_err(Error::custom)
}

fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "a hex encoded string with a prefix")
}
}

impl PrefixHexStrVisitor {
fn remove_prefix_if_present(data: &str) -> &str {
let prefix = &data[..2];
deserializer.deserialize_string(PrefixHexStrVisitor())
}

#[derive(Debug, Deserialize)]
struct BloomWrapper(String);

match matches!(prefix, "0x" | "0X") {
false => data,
true => &data[2..],
}
impl From<BloomWrapper> for [U256; 8] {
fn from(v: BloomWrapper) -> Self {
let bytes = hex::decode(remove_hex_prefix_if_present(&v.0)).unwrap();
let mut bloom = [U256::zero(); 8];

// Note that bloom can be empty.
for (i, v) in bytes.into_iter().array_chunks::<32>().enumerate() {
bloom[i] = U256::from_big_endian(v.as_slice());
}

bloom
}
}

deserializer.deserialize_string(PrefixHexStrVisitor())
fn remove_hex_prefix_if_present(data: &str) -> &str {
let prefix = &data[..2];

match matches!(prefix, "0x" | "0X") {
false => data,
true => &data[2..],
}
}

#[derive(Clone, Debug)]
Expand Down
2 changes: 2 additions & 0 deletions parser/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![feature(iter_array_chunks)]

pub mod edge_payloads;
pub mod plonky2;
pub mod plonky3;
Expand Down
94 changes: 84 additions & 10 deletions parser/src/plonky2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{
collections::{HashMap, HashSet},
fmt::{Display, Formatter},
iter::once,
str::FromStr,
};

Expand Down Expand Up @@ -243,6 +244,7 @@ impl EdgeBlockTrace {
let txn_partial_tries = Self::create_minimal_partial_tries_needed_by_txn(
&block_tries,
processed_txn_traces.nodes_used_by_txn,
txn_idx,
)?;

println!("Base storage tries:");
Expand Down Expand Up @@ -278,6 +280,16 @@ impl EdgeBlockTrace {
&mut addrs_to_code,
)?;

Self::update_receipt_and_txn_tries(
&mut block_tries.receipt,
&mut block_tries.txn,
txn_trace_info.txn.clone(),
txn_trace_info.receipt,
txn_idx,
);
assert_eq!(block_tries.receipt.hash(), txn_trace_info.receipt_root);
assert_eq!(block_tries.txn.hash(), txn_trace_info.txn_root);

let trie_roots_after = TrieRoots {
state_root: block_tries.state.hash(),
transactions_root: txn_trace_info.txn_root,
Expand Down Expand Up @@ -311,18 +323,51 @@ impl EdgeBlockTrace {
.collect::<TraceParsingResult<Vec<_>>>()?;

Ok(match tx_proof_gen_ir.len() {
0 => vec![
TxnProofGenIR::create_dummy(b_height, 0),
TxnProofGenIR::create_dummy(b_height, 1),
],
0 => {
let (mut receipt_trie, mut txn_trie) =
(HashedPartialTrie::default(), HashedPartialTrie::default());
let dummy_txn_0 = Self::update_txn_receipt_tries_and_create_dummy_txn(
&mut receipt_trie,
&mut txn_trie,
b_height,
0,
);
let dummy_txn_1 = Self::update_txn_receipt_tries_and_create_dummy_txn(
&mut receipt_trie,
&mut txn_trie,
b_height,
1,
);

vec![dummy_txn_0, dummy_txn_1]
}
1 => {
tx_proof_gen_ir.push(tx_proof_gen_ir[0].dummy_with_at(b_height, 1));
let (mut receipt_trie, mut txn_trie) =
(HashedPartialTrie::default(), HashedPartialTrie::default());
let dummy_txn = Self::update_txn_receipt_tries_and_create_dummy_txn(
&mut receipt_trie,
&mut txn_trie,
b_height,
1,
);

tx_proof_gen_ir.push(dummy_txn);
tx_proof_gen_ir
}
_ => tx_proof_gen_ir,
})
}

fn update_txn_receipt_tries_and_create_dummy_txn(
receipt_trie: &mut HashedPartialTrie,
txn_trie: &mut HashedPartialTrie,
b_height: BlockHeight,
txn_idx: usize,
) -> TxnProofGenIR {
Self::update_receipt_and_txn_tries(receipt_trie, txn_trie, vec![], vec![], txn_idx);
TxnProofGenIR::create_dummy(b_height, txn_idx, receipt_trie, txn_trie).unwrap()
}

/// Edge gives us contract bytecode that was accessed
fn extract_all_contract_bytecode_from_txn_traces(&self) -> HashMap<H256, Vec<u8>> {
// TODO: Clean up and move to a map...
Expand Down Expand Up @@ -411,6 +456,8 @@ impl EdgeBlockTrace {
BlockPartialTries {
state: state_trie,
storage: acc_storage_tries,
receipt: HashedPartialTrie::default(),
txn: HashedPartialTrie::default(),
},
accounts_to_code,
))
Expand Down Expand Up @@ -534,6 +581,7 @@ impl EdgeBlockTrace {
fn create_minimal_partial_tries_needed_by_txn(
curr_block_tries: &BlockPartialTries,
nodes_used_by_txn: NodesUsedByTxn,
txn_idx: usize,
) -> TraceParsingResult<TrieInputs> {
let subset_state_trie = create_trie_subset(
&curr_block_tries.state,
Expand Down Expand Up @@ -578,15 +626,24 @@ impl EdgeBlockTrace {

Ok(TrieInputs {
state_trie: subset_state_trie,
transactions_trie: HashedPartialTrie::default(), /* TODO: Wait for full node &
* Plonky2
* support... */
receipts_trie: HashedPartialTrie::default(), /* TODO: Wait for full node & Plonky2
* support... */
transactions_trie: Self::construct_partial_trie_from_idx(
&curr_block_tries.receipt,
txn_idx,
),
receipts_trie: Self::construct_partial_trie_from_idx(&curr_block_tries.txn, txn_idx),
storage_tries: subset_storage_tries,
})
}

fn construct_partial_trie_from_idx(
full_trie: &HashedPartialTrie,
idx: usize,
) -> HashedPartialTrie {
// Should be doing better errors here but this is currently just a hack.
create_trie_subset(full_trie, once(idx as u64))
.expect("Unable to create single element partial trie from an index")
}

fn apply_deltas_to_trie_state(
trie_state: &mut BlockPartialTries,
deltas: Vec<ProcessedTxnTrace>,
Expand Down Expand Up @@ -634,6 +691,21 @@ impl EdgeBlockTrace {
Ok(())
}

fn update_receipt_and_txn_tries(
receipt_trie: &mut HashedPartialTrie,
txn_trie: &mut HashedPartialTrie,
receipt_node: Vec<u8>,
txn_node: Vec<u8>,
txn_idx: usize,
) {
Self::add_indexed_node_to_trie(receipt_trie, receipt_node, txn_idx);
Self::add_indexed_node_to_trie(txn_trie, txn_node, txn_idx);
}

fn add_indexed_node_to_trie(trie: &mut HashedPartialTrie, node: Vec<u8>, txn_idx: usize) {
trie.insert(txn_idx as u64, node)
}

pub fn num_txns(&self) -> usize {
self.txn_bytes_and_traces.len()
}
Expand All @@ -653,6 +725,8 @@ fn update_val_if_some<T>(target: &mut T, opt: Option<T>) {
struct BlockPartialTries {
state: HashedPartialTrie,
storage: HashMap<H256, HashedPartialTrie>,
receipt: HashedPartialTrie,
txn: HashedPartialTrie,
}

#[derive(Debug)]
Expand Down
Loading