Skip to content

Commit

Permalink
Fix account creation reversion in decoder processing (#480)
Browse files Browse the repository at this point in the history
* Fix account creation reversion in decoder processing

* Also prune storage if account is removed

* Handle all reverts cases together

* Pacify mighty clippy
  • Loading branch information
Nashtare authored Aug 9, 2024
1 parent 16baa98 commit cf222f0
Show file tree
Hide file tree
Showing 4 changed files with 414 additions and 9 deletions.
12 changes: 11 additions & 1 deletion evm_arithmetization/src/generation/mpt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ impl LegacyReceiptRlp {
}
}

pub(crate) fn parse_receipts(rlp: &[u8]) -> Result<Vec<U256>, ProgramError> {
/// Decodes a transaction receipt from an RLP string, outputting a tuple
/// consisting of:
/// - the receipt's [`PayloadInfo`],
/// - the transaction type,
/// - the decoded [`LegacyReceiptRlp`].
pub fn decode_receipt(rlp: &[u8]) -> Result<(PayloadInfo, usize, LegacyReceiptRlp), ProgramError> {
let txn_type = match rlp.first().ok_or(ProgramError::InvalidRlp)? {
1 => 1,
2 => 2,
Expand All @@ -82,6 +87,11 @@ pub(crate) fn parse_receipts(rlp: &[u8]) -> Result<Vec<U256>, ProgramError> {
let decoded_receipt: LegacyReceiptRlp =
rlp::decode(rlp).map_err(|_| ProgramError::InvalidRlp)?;

Ok((payload_info, txn_type, decoded_receipt))
}

pub(crate) fn parse_receipts(rlp: &[u8]) -> Result<Vec<U256>, ProgramError> {
let (payload_info, txn_type, decoded_receipt) = decode_receipt(rlp)?;
let mut parsed_receipt = if txn_type == 0 {
Vec::new()
} else {
Expand Down
54 changes: 46 additions & 8 deletions trace_decoder/src/decoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use std::{

use ethereum_types::{Address, BigEndianHash, H256, U256, U512};
use evm_arithmetization::{
generation::{mpt::AccountRlp, GenerationInputs, TrieInputs},
generation::{
mpt::{decode_receipt, AccountRlp},
GenerationInputs, TrieInputs,
},
proof::{BlockMetadata, ExtraBlockData, TrieRoots},
testing_utils::{BEACON_ROOTS_CONTRACT_ADDRESS_HASHED, HISTORY_BUFFER_LENGTH},
};
Expand Down Expand Up @@ -152,6 +155,10 @@ pub enum TraceParsingErrorReason {
#[error("Failed to decode RLP bytes ({0}) as an Ethereum account due to the error: {1}")]
AccountDecode(String, String),

/// Failure to decode a transaction receipt.
#[error("Failed to decode RLP bytes ({0}) as a transaction receipt due to the error: {1}")]
ReceiptDecode(String, String),

/// Failure due to trying to access or delete a storage trie missing
/// from the base trie.
#[error("Missing account storage trie in base trie when constructing subset partial trie for txn (account: {0:x})")]
Expand Down Expand Up @@ -470,6 +477,7 @@ impl ProcessedBlockTrace {
fn apply_deltas_to_trie_state(
trie_state: &mut PartialTrieState,
deltas: &NodesUsedByTxn,
meta: &TxnMetaState,
) -> TraceParsingResult<TrieDeltaApplicationOutput> {
let mut out = TrieDeltaApplicationOutput::default();

Expand Down Expand Up @@ -517,11 +525,11 @@ impl ProcessedBlockTrace {
for (hashed_acc_addr, s_trie_writes) in deltas.state_writes.iter() {
let val_k = Nibbles::from_h256_be(*hashed_acc_addr);

// If the account was created, then it will not exist in the trie.
let val_bytes = trie_state
.state
.get(val_k)
.unwrap_or(&EMPTY_ACCOUNT_BYTES_RLPED);
// If the account was created, then it will not exist yet in the trie.
let (is_created, val_bytes) = match trie_state.state.get(val_k) {
Some(bytes) => (false, bytes),
None => (true, &EMPTY_ACCOUNT_BYTES_RLPED[..]),
};

let mut account = account_from_rlped_bytes(val_bytes)?;

Expand All @@ -532,6 +540,33 @@ impl ProcessedBlockTrace {
)?;

let updated_account_bytes = rlp::encode(&account);
if is_created {
// If the account did not exist prior this transaction, we
// need to make sure the transaction didn't revert.

// Check status in the receipt.
let (_, _, receipt) = decode_receipt(&meta.receipt_node_bytes).map_err(|err| {
Box::new(TraceParsingError::new(
TraceParsingErrorReason::ReceiptDecode(
hex::encode(&meta.receipt_node_bytes),
format!("{:?}", err),
),
))
})?;

if !receipt.status {
// The transaction failed, hence any created account should be removed.
trie_state
.state
.delete(val_k)
.map_err(TraceParsingError::from)?;

trie_state.storage.remove(hashed_acc_addr);

continue;
}
}

trie_state
.state
.insert(val_k, updated_account_bytes.to_vec())
Expand Down Expand Up @@ -705,8 +740,11 @@ impl ProcessedBlockTrace {
Self::update_txn_and_receipt_tries(curr_block_tries, &txn_info.meta, txn_idx)
.map_err(TraceParsingError::from)?;

let mut delta_out =
Self::apply_deltas_to_trie_state(curr_block_tries, &txn_info.nodes_used_by_txn)?;
let mut delta_out = Self::apply_deltas_to_trie_state(
curr_block_tries,
&txn_info.nodes_used_by_txn,
&txn_info.meta,
)?;

let nodes_used_by_txn = if is_initial_payload {
let mut nodes_used = txn_info.nodes_used_by_txn;
Expand Down
Loading

0 comments on commit cf222f0

Please sign in to comment.