Skip to content

Commit

Permalink
fix: 4844 fee fixes (#8963)
Browse files Browse the repository at this point in the history
* fix: use zero blob fee for estimate

* add basic test

* fix gas_price

* support EIP-4844 with with_max_fee_per_blob_gas None

* this should run succesfully once Alloy counterpart has been merged

* undo max_fee_per_blob_gas != 0 check, not necessary anymore

* clean up

* fix setup bug from Matt

* add test with signer, currently failing on Result::unwrap()` on an `Err` value: ErrorResp(ErrorPayload { code: -32003, message: "Block `blob_versioned_hashes` is not supported before the Cancun hardfork", data: None })

* able to reproduce

* apply hotfix by Matt

* remove debugs

* use or_else, only need to do this if the blob_versioned hashes are non zero

* move blob_hashes out

---------

Co-authored-by: zerosnacks <[email protected]>
Co-authored-by: zerosnacks <[email protected]>
  • Loading branch information
3 people authored Sep 27, 2024
1 parent dd86b30 commit 25f24e6
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 26 deletions.
2 changes: 1 addition & 1 deletion crates/anvil/core/src/eth/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub fn transaction_request_to_typed(
}))
}
// EIP4844
(Some(3), None, _, _, _, Some(_), Some(_), Some(sidecar), to) => {
(Some(3), None, _, _, _, _, Some(_), Some(sidecar), to) => {
let tx = TxEip4844 {
nonce: nonce.unwrap_or_default(),
max_fee_per_gas: max_fee_per_gas.unwrap_or_default(),
Expand Down
3 changes: 2 additions & 1 deletion crates/anvil/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,8 @@ impl NodeConfig {
{
BlobExcessGasAndPrice::new(excess_blob_gas as u64)
} else {
BlobExcessGasAndPrice { blob_gasprice: 0, excess_blob_gas: 0 }
// If no excess blob gas is configured, default to 0
BlobExcessGasAndPrice::new(0)
}
}

Expand Down
50 changes: 30 additions & 20 deletions crates/anvil/src/eth/backend/mem/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,26 +1227,36 @@ impl Backend {
});
let caller = from.unwrap_or_default();
let to = to.as_ref().and_then(TxKind::to);
env.tx = TxEnv {
caller,
gas_limit: gas_limit as u64,
gas_price: U256::from(gas_price),
gas_priority_fee: max_priority_fee_per_gas.map(U256::from),
max_fee_per_blob_gas: max_fee_per_blob_gas.map(U256::from),
transact_to: match to {
Some(addr) => TxKind::Call(*addr),
None => TxKind::Create,
},
value: value.unwrap_or_default(),
data: input.into_input().unwrap_or_default(),
chain_id: None,
// set nonce to None so that the correct nonce is chosen by the EVM
nonce: None,
access_list: access_list.unwrap_or_default().into(),
blob_hashes: blob_versioned_hashes.unwrap_or_default(),
optimism: OptimismFields { enveloped_tx: Some(Bytes::new()), ..Default::default() },
authorization_list: authorization_list.map(Into::into),
};
let blob_hashes = blob_versioned_hashes.unwrap_or_default();
env.tx =
TxEnv {
caller,
gas_limit: gas_limit as u64,
gas_price: U256::from(gas_price),
gas_priority_fee: max_priority_fee_per_gas.map(U256::from),
max_fee_per_blob_gas: max_fee_per_blob_gas
.or_else(|| {
if !blob_hashes.is_empty() {
env.block.get_blob_gasprice()
} else {
None
}
})
.map(U256::from),
transact_to: match to {
Some(addr) => TxKind::Call(*addr),
None => TxKind::Create,
},
value: value.unwrap_or_default(),
data: input.into_input().unwrap_or_default(),
chain_id: None,
// set nonce to None so that the correct nonce is chosen by the EVM
nonce: None,
access_list: access_list.unwrap_or_default().into(),
blob_hashes,
optimism: OptimismFields { enveloped_tx: Some(Bytes::new()), ..Default::default() },
authorization_list: authorization_list.map(Into::into),
};

if env.block.basefee.is_zero() {
// this is an edge case because the evm fails if `tx.effective_gas_price < base_fee`
Expand Down
2 changes: 1 addition & 1 deletion crates/anvil/src/eth/fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,7 @@ impl FeeDetails {
impl fmt::Debug for FeeDetails {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "Fees {{ ")?;
write!(fmt, "gaPrice: {:?}, ", self.gas_price)?;
write!(fmt, "gas_price: {:?}, ", self.gas_price)?;
write!(fmt, "max_fee_per_gas: {:?}, ", self.max_fee_per_gas)?;
write!(fmt, "max_priority_fee_per_gas: {:?}, ", self.max_priority_fee_per_gas)?;
write!(fmt, "}}")?;
Expand Down
93 changes: 90 additions & 3 deletions crates/anvil/tests/it/eip4844.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::utils::http_provider;
use crate::utils::{http_provider, http_provider_with_signer};
use alloy_consensus::{SidecarBuilder, SimpleCoder};
use alloy_eips::eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK};
use alloy_network::{TransactionBuilder, TransactionBuilder4844};
use alloy_eips::eip4844::{BLOB_TX_MIN_BLOB_GASPRICE, DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK};
use alloy_network::{EthereumWallet, TransactionBuilder, TransactionBuilder4844};
use alloy_primitives::U256;
use alloy_provider::Provider;
use alloy_rpc_types::{BlockId, TransactionRequest};
Expand Down Expand Up @@ -204,3 +204,90 @@ async fn can_check_blob_fields_on_genesis() {
assert_eq!(block.header.blob_gas_used, Some(0));
assert_eq!(block.header.excess_blob_gas, Some(0));
}

#[tokio::test(flavor = "multi_thread")]
async fn can_correctly_estimate_blob_gas_with_recommended_fillers() {
let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));
let (_api, handle) = spawn(node_config).await;

let provider = http_provider(&handle.http_endpoint());

let accounts = provider.get_accounts().await.unwrap();
let alice = accounts[0];
let bob = accounts[1];

let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b"Blobs are fun!");
let sidecar = sidecar.build().unwrap();

let tx = TransactionRequest::default().with_to(bob).with_blob_sidecar(sidecar);
let tx = WithOtherFields::new(tx);

// Send the transaction and wait for the broadcast.
let pending_tx = provider.send_transaction(tx).await.unwrap();

println!("Pending transaction... {}", pending_tx.tx_hash());

// Wait for the transaction to be included and get the receipt.
let receipt = pending_tx.get_receipt().await.unwrap();

// Grab the processed transaction.
let tx = provider.get_transaction_by_hash(receipt.transaction_hash).await.unwrap().unwrap();

println!(
"Transaction included in block {}",
receipt.block_number.expect("Failed to get block number")
);

assert!(tx.max_fee_per_blob_gas.unwrap() >= BLOB_TX_MIN_BLOB_GASPRICE);
assert_eq!(receipt.from, alice);
assert_eq!(receipt.to, Some(bob));
assert_eq!(
receipt.blob_gas_used.expect("Expected to be EIP-4844 transaction"),
DATA_GAS_PER_BLOB as u128
);
}

#[tokio::test(flavor = "multi_thread")]
async fn can_correctly_estimate_blob_gas_with_recommended_fillers_with_signer() {
let node_config = NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into()));
let (_api, handle) = spawn(node_config).await;

let signer = handle.dev_wallets().next().unwrap();
let wallet: EthereumWallet = signer.clone().into();

let provider = http_provider_with_signer(&handle.http_endpoint(), wallet);

let accounts = provider.get_accounts().await.unwrap();
let alice = accounts[0];
let bob = accounts[1];

let sidecar: SidecarBuilder<SimpleCoder> = SidecarBuilder::from_slice(b"Blobs are fun!");
let sidecar = sidecar.build().unwrap();

let tx = TransactionRequest::default().with_to(bob).with_blob_sidecar(sidecar);
let tx = WithOtherFields::new(tx);

// Send the transaction and wait for the broadcast.
let pending_tx = provider.send_transaction(tx).await.unwrap();

println!("Pending transaction... {}", pending_tx.tx_hash());

// Wait for the transaction to be included and get the receipt.
let receipt = pending_tx.get_receipt().await.unwrap();

// Grab the processed transaction.
let tx = provider.get_transaction_by_hash(receipt.transaction_hash).await.unwrap().unwrap();

println!(
"Transaction included in block {}",
receipt.block_number.expect("Failed to get block number")
);

assert!(tx.max_fee_per_blob_gas.unwrap() >= BLOB_TX_MIN_BLOB_GASPRICE);
assert_eq!(receipt.from, alice);
assert_eq!(receipt.to, Some(bob));
assert_eq!(
receipt.blob_gas_used.expect("Expected to be EIP-4844 transaction"),
DATA_GAS_PER_BLOB as u128
);
}

0 comments on commit 25f24e6

Please sign in to comment.