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

Fix: Support pre-658 status codes #848

Merged
merged 7 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 3 additions & 1 deletion crates/consensus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ mod header;
pub use header::{Header, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH};

mod receipt;
pub use receipt::{AnyReceiptEnvelope, Receipt, ReceiptEnvelope, ReceiptWithBloom, TxReceipt};
pub use receipt::{
AnyReceiptEnvelope, Eip658Value, Receipt, ReceiptEnvelope, ReceiptWithBloom, TxReceipt,
};

mod request;
pub use request::Request;
Expand Down
28 changes: 21 additions & 7 deletions crates/consensus/src/receipt/any.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{ReceiptWithBloom, TxReceipt};
use crate::{Eip658Value, ReceiptWithBloom, TxReceipt};
use alloy_eips::eip2718::{Decodable2718, Encodable2718};
use alloy_primitives::{bytes::BufMut, Bloom, Log};
use alloy_rlp::{Decodable, Encodable};
Expand Down Expand Up @@ -47,13 +47,27 @@ impl<T> AnyReceiptEnvelope<T> {
}

/// Return true if the transaction was successful.
///
/// ## Note
///
/// This method may not accurately reflect the status of the transaction
/// for transactions before [EIP-658].
///
/// [EIP-658]: https://eips.ethereum.org/EIPS/eip-658
pub const fn is_success(&self) -> bool {
self.status()
}

/// Returns the success status of the receipt's transaction.
///
/// ## Note
///
/// This method may not accurately reflect the status of the transaction
/// for transactions before [EIP-658].
///
/// [EIP-658]: https://eips.ethereum.org/EIPS/eip-658
pub const fn status(&self) -> bool {
self.inner.receipt.status
matches!(self.inner.receipt.status, Eip658Value::Eip658(true) | Eip658Value::PostState(_))
}

/// Return the receipt's bloom.
Expand All @@ -73,22 +87,22 @@ impl<T> AnyReceiptEnvelope<T> {
}

impl<T> TxReceipt<T> for AnyReceiptEnvelope<T> {
/// Returns the success status of the receipt's transaction.
fn status_or_post_state(&self) -> &Eip658Value {
self.inner.status_or_post_state()
}

fn status(&self) -> bool {
self.inner.receipt.status
self.inner.status()
}

/// Return the receipt's bloom.
fn bloom(&self) -> Bloom {
self.inner.logs_bloom
}

/// Returns the cumulative gas used at this receipt.
fn cumulative_gas_used(&self) -> u128 {
self.inner.receipt.cumulative_gas_used
}

/// Return the receipt logs.
fn logs(&self) -> &[T] {
&self.inner.receipt.logs
}
Expand Down
8 changes: 6 additions & 2 deletions crates/consensus/src/receipt/envelope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<T> ReceiptEnvelope<T> {

/// Returns the success status of the receipt's transaction.
pub fn status(&self) -> bool {
self.as_receipt().unwrap().status
self.as_receipt().unwrap().status.coerce_status()
}

/// Returns the cumulative gas used at this receipt.
Expand Down Expand Up @@ -96,8 +96,12 @@ impl<T> ReceiptEnvelope<T> {
}

impl<T> TxReceipt<T> for ReceiptEnvelope<T> {
fn status_or_post_state(&self) -> &crate::Eip658Value {
&self.as_receipt().unwrap().status
}

fn status(&self) -> bool {
self.as_receipt().unwrap().status
self.as_receipt().unwrap().status.coerce_status()
}

/// Return the receipt's bloom.
Expand Down
34 changes: 30 additions & 4 deletions crates/consensus/src/receipt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,36 @@ pub use envelope::ReceiptEnvelope;
mod receipts;
pub use receipts::{Receipt, ReceiptWithBloom};

mod status;
pub use status::Eip658Value;

/// Receipt is the result of a transaction execution.
#[doc(alias = "TransactionReceipt")]
pub trait TxReceipt<T = Log> {
/// Returns true if the transaction was successful.
/// Returns the status or post state of the transaction.
///
/// ## Note
///
/// Use this method instead of [`TxReceipt::status`] when the transaction
/// is pre-[EIP-658].
///
/// [EIP-658]: https://eips.ethereum.org/EIPS/eip-658
fn status_or_post_state(&self) -> &Eip658Value;

/// Returns true if the transaction was successful OR if the transaction is
/// pre-[EIP-658]. Results for transactions before [EIP-658] are not
/// reliable.
///
/// ## Note
///
/// Caution must be taken when using this method for deep-historical
/// receipts, as it may not accurately reflect the status of the
/// transaction. The transaction status is not knowable from the receipt
/// for transactions before [EIP-658].
///
/// This can be handled using [`TxReceipt::status_or_post_state`].
///
/// [EIP-658]: https://eips.ethereum.org/EIPS/eip-658
fn status(&self) -> bool;

/// Returns the bloom filter for the logs in the receipt. This operation
Expand Down Expand Up @@ -59,7 +85,7 @@ mod tests {
bytes!("0100ff"),
),
}],
status: false,
status: false.into(),
},
logs_bloom: [0; 256].into(),
});
Expand Down Expand Up @@ -91,7 +117,7 @@ mod tests {
bytes!("0100ff"),
),
}],
status: false,
status: false.into(),
},
logs_bloom: [0; 256].into(),
};
Expand All @@ -104,7 +130,7 @@ mod tests {
fn gigantic_receipt() {
let receipt = Receipt {
cumulative_gas_used: 16747627,
status: true,
status: true.into(),
logs: vec![
Log {
address: address!("4bf56695415f725e43c3e04354b604bcfb6dfb6e"),
Expand Down
50 changes: 41 additions & 9 deletions crates/consensus/src/receipt/receipts.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,55 @@
use core::borrow::Borrow;

use super::TxReceipt;
use alloy_primitives::{Bloom, Log};
use crate::receipt::{Eip658Value, TxReceipt};
use alloy_primitives::{Bloom, Log, U128};
use alloy_rlp::{length_of_length, BufMut, Decodable, Encodable};
use core::borrow::Borrow;

#[cfg(not(feature = "std"))]
use alloc::vec::Vec;

/// Receipt containing result of transaction execution.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
#[doc(alias = "TransactionReceipt", alias = "TxReceipt")]
pub struct Receipt<T = Log> {
/// If transaction is executed successfully.
///
/// This is the `statusCode`
#[cfg_attr(feature = "serde", serde(with = "alloy_serde::quantity_bool"))]
pub status: bool,
#[cfg_attr(feature = "serde", serde(alias = "name"))]
pub status: Eip658Value,
/// Gas used
prestwich marked this conversation as resolved.
Show resolved Hide resolved
#[cfg_attr(feature = "serde", serde(with = "alloy_serde::u128_via_ruint"))]
pub cumulative_gas_used: u128,
/// Log send from contracts.
pub logs: Vec<T>,
}

#[cfg(feature = "serde")]
impl<T> serde::Serialize for Receipt<T>
where
T: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;

let mut s = serializer.serialize_struct("Receipt", 3)?;

// If the status is EIP-658, serialize the status field.
// Otherwise, serialize the root field.
let key = if self.status.is_eip658() { "status" } else { "root" };
s.serialize_field(key, &self.status)?;

s.serialize_field("cumulativeGasUsed", &U128::from(self.cumulative_gas_used))?;
s.serialize_field("logs", &self.logs)?;

s.end()
}
}

impl<T> Receipt<T>
where
T: Borrow<Log>,
Expand All @@ -47,8 +71,12 @@ impl<T> TxReceipt<T> for Receipt<T>
where
T: Borrow<Log>,
{
fn status_or_post_state(&self) -> &Eip658Value {
&self.status
}

fn status(&self) -> bool {
self.status
self.status.coerce_status()
}

fn bloom(&self) -> Bloom {
Expand Down Expand Up @@ -90,8 +118,12 @@ pub struct ReceiptWithBloom<T = Log> {
}

impl<T> TxReceipt<T> for ReceiptWithBloom<T> {
fn status_or_post_state(&self) -> &Eip658Value {
&self.receipt.status
}

fn status(&self) -> bool {
self.receipt.status
matches!(self.receipt.status, Eip658Value::Eip658(true) | Eip658Value::PostState(_))
}

fn bloom(&self) -> Bloom {
Expand Down
Loading
Loading