Skip to content

Commit

Permalink
feat: add authorization list to rpc transaction and tx receipt types (a…
Browse files Browse the repository at this point in the history
…lloy-rs#1051)

* feat: add authorization list to rpc transaction and tx receipt types

* fix: add default impl

Co-authored-by: Matthias Seitz <[email protected]>

* fix: use signed authorization for rpc transaction type

* fix: enable arbitrary and k256 features for development

* fix: cargo hack fix

* chore: flatten signature

---------

Co-authored-by: Matthias Seitz <[email protected]>
  • Loading branch information
2 people authored and ben186 committed Jul 27, 2024
1 parent 22b635d commit 40e6f7e
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 4 deletions.
1 change: 1 addition & 0 deletions crates/eips/src/eip7702/auth_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ impl Authorization {
pub struct SignedAuthorization {
#[cfg_attr(feature = "serde", serde(flatten))]
inner: Authorization,
#[cfg_attr(feature = "serde", serde(flatten))]
signature: Signature,
}

Expand Down
2 changes: 2 additions & 0 deletions crates/rpc-types-eth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ alloy-primitives = { workspace = true, features = [
"arbitrary",
] }
alloy-consensus = { workspace = true, features = ["std", "arbitrary"] }
alloy-eips = { workspace = true, features = ["arbitrary", "k256"] }

arbitrary = { workspace = true, features = ["derive"] }
rand.workspace = true
Expand All @@ -57,6 +58,7 @@ arbitrary = [
"alloy-primitives/arbitrary",
"alloy-serde/arbitrary",
"alloy-eips/arbitrary",
"alloy-eips/k256",
]
jsonrpsee-types = ["dep:jsonrpsee-types"]
ssz = ["alloy-primitives/ssz", "alloy-eips/ssz"]
Expand Down
29 changes: 25 additions & 4 deletions crates/rpc-types-eth/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ use alloy_consensus::{
SignableTransaction, Signed, TxEip1559, TxEip2930, TxEip4844, TxEip4844Variant, TxEnvelope,
TxLegacy, TxType,
};
use alloy_eips::eip7702::SignedAuthorization;
use alloy_primitives::{Address, BlockHash, Bytes, ChainId, TxHash, TxKind, B256, U256};
use alloy_serde::OtherFields;
use serde::{Deserialize, Serialize};

pub use alloy_consensus::BlobTransactionSidecar;
pub use alloy_eips::eip2930::{AccessList, AccessListItem, AccessListWithGasUsed};
pub use alloy_eips::{
eip2930::{AccessList, AccessListItem, AccessListWithGasUsed},
eip7702::Authorization,
};

mod common;
pub use common::TransactionInfo;
Expand Down Expand Up @@ -103,7 +107,10 @@ pub struct Transaction {
)]
#[doc(alias = "tx_type")]
pub transaction_type: Option<u8>,

/// The signed authorization list is a list of tuples that store the address to code which the
/// signer desires to execute in the context of their EOA and their signature.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub authorization_list: Option<Vec<SignedAuthorization>>,
/// Arbitrary extra fields.
///
/// This captures fields that are not native to ethereum but included in ethereum adjacent networks, for example fields the [optimism `eth_getTransactionByHash` request](https://docs.alchemy.com/alchemy/apis/optimism/eth-gettransactionbyhash) returns additional fields that this type will capture
Expand Down Expand Up @@ -272,8 +279,10 @@ impl TryFrom<Transaction> for TxEnvelope {
#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::Signature as AlloySignature;
use arbitrary::Arbitrary;
use rand::Rng;
use std::str::FromStr;

#[test]
fn arbitrary_transaction() {
Expand Down Expand Up @@ -310,12 +319,18 @@ mod tests {
max_fee_per_gas: Some(21),
max_priority_fee_per_gas: Some(22),
max_fee_per_blob_gas: None,
authorization_list: Some(vec![(Authorization {
chain_id: 1u64,
address: Address::left_padding_from(&[6]),
nonce: Some(1u64).into(),
})
.into_signed(AlloySignature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap())]),
other: Default::default(),
};
let serialized = serde_json::to_string(&transaction).unwrap();
assert_eq!(
serialized,
r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","nonce":"0x2","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000003","blockNumber":"0x4","transactionIndex":"0x5","from":"0x0000000000000000000000000000000000000006","to":"0x0000000000000000000000000000000000000007","value":"0x8","gasPrice":"0x9","gas":"0xa","maxFeePerGas":"0x15","maxPriorityFeePerGas":"0x16","input":"0x0b0c0d","r":"0xe","s":"0xe","v":"0xe","chainId":"0x11","type":"0x14"}"#
r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","nonce":"0x2","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000003","blockNumber":"0x4","transactionIndex":"0x5","from":"0x0000000000000000000000000000000000000006","to":"0x0000000000000000000000000000000000000007","value":"0x8","gasPrice":"0x9","gas":"0xa","maxFeePerGas":"0x15","maxPriorityFeePerGas":"0x16","input":"0x0b0c0d","r":"0xe","s":"0xe","v":"0xe","chainId":"0x11","type":"0x14","authorizationList":[{"chainId":1,"address":"0x0000000000000000000000000000000000000006","nonce":1,"r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","v":27}]}"#
);
let deserialized: Transaction = serde_json::from_str(&serialized).unwrap();
assert_eq!(transaction, deserialized);
Expand Down Expand Up @@ -348,12 +363,18 @@ mod tests {
max_fee_per_gas: Some(21),
max_priority_fee_per_gas: Some(22),
max_fee_per_blob_gas: None,
authorization_list: Some(vec![(Authorization {
chain_id: 1u64,
address: Address::left_padding_from(&[6]),
nonce: Some(1u64).into(),
})
.into_signed(AlloySignature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap())]),
other: Default::default(),
};
let serialized = serde_json::to_string(&transaction).unwrap();
assert_eq!(
serialized,
r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","nonce":"0x2","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000003","blockNumber":"0x4","transactionIndex":"0x5","from":"0x0000000000000000000000000000000000000006","to":"0x0000000000000000000000000000000000000007","value":"0x8","gasPrice":"0x9","gas":"0xa","maxFeePerGas":"0x15","maxPriorityFeePerGas":"0x16","input":"0x0b0c0d","r":"0xe","s":"0xe","v":"0xe","yParity":"0x1","chainId":"0x11","type":"0x14"}"#
r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000001","nonce":"0x2","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000003","blockNumber":"0x4","transactionIndex":"0x5","from":"0x0000000000000000000000000000000000000006","to":"0x0000000000000000000000000000000000000007","value":"0x8","gasPrice":"0x9","gas":"0xa","maxFeePerGas":"0x15","maxPriorityFeePerGas":"0x16","input":"0x0b0c0d","r":"0xe","s":"0xe","v":"0xe","yParity":"0x1","chainId":"0x11","type":"0x14","authorizationList":[{"chainId":1,"address":"0x0000000000000000000000000000000000000006","nonce":1,"r":"0x48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353","s":"0xefffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804","v":27}]}"#
);
let deserialized: Transaction = serde_json::from_str(&serialized).unwrap();
assert_eq!(transaction, deserialized);
Expand Down
6 changes: 6 additions & 0 deletions crates/rpc-types-eth/src/transaction/receipt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::Log;
use alloy_consensus::{AnyReceiptEnvelope, ReceiptEnvelope, TxType};
use alloy_eips::eip7702::SignedAuthorization;
use alloy_primitives::{Address, BlockHash, TxHash, B256};
use alloy_serde::WithOtherFields;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -56,6 +57,10 @@ pub struct TransactionReceipt<T = ReceiptEnvelope<Log>> {
/// EIP98 makes this optional field, if it's missing then skip serializing it
#[serde(skip_serializing_if = "Option::is_none", rename = "root")]
pub state_root: Option<B256>,
/// The authorization list is a list of tuples that store the address to code which the signer
/// desires to execute in the context of their EOA.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub authorization_list: Option<Vec<SignedAuthorization>>,
}

impl AsRef<ReceiptEnvelope<Log>> for TransactionReceipt {
Expand Down Expand Up @@ -114,6 +119,7 @@ impl<T> TransactionReceipt<T> {
to: self.to,
contract_address: self.contract_address,
state_root: self.state_root,
authorization_list: self.authorization_list,
}
}
}
Expand Down

0 comments on commit 40e6f7e

Please sign in to comment.