Skip to content

Commit

Permalink
feat: resolve default transaction fees
Browse files Browse the repository at this point in the history
  • Loading branch information
Wodann committed Nov 28, 2023
1 parent 96b165e commit 253e07d
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 42 deletions.
45 changes: 39 additions & 6 deletions crates/edr_provider/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use edr_evm::{
Blockchain, BlockchainError, ForkedBlockchain, ForkedCreationError, LocalBlockchain,
LocalCreationError, SyncBlockchain,
},
mine_block,
calculate_next_base_fee, mempool, mine_block,
state::{AccountModifierFn, IrregularState, StateDiff, StateError, StateOverride, SyncState},
Account, AccountInfo, Block, Bytecode, CfgEnv, HashMap, HashSet, MemPool, MineBlockResult,
MineBlockResultAndState, MineOrdering, PendingTransaction, RandomHashGenerator, StorageSlot,
Expand Down Expand Up @@ -121,8 +121,8 @@ impl ProviderData {

/// Retrieves the last pending nonce of the account corresponding to the
/// provided address, if it exists.
pub fn account_last_pending_nonce(&self, address: &Address) -> Option<u64> {
self.mem_pool.last_pending_nonce(address)
pub fn account_next_nonce(&self, address: &Address) -> Result<u64, StateError> {
mempool::account_next_nonce(&self.mem_pool, &self.state, address)
}

pub fn accounts(&self) -> impl Iterator<Item = &Address> {
Expand Down Expand Up @@ -369,6 +369,39 @@ impl ProviderData {
filter_id
}

pub fn next_block_base_fee_per_gas(&self) -> Result<Option<U256>, BlockchainError> {
if self.spec_id() < SpecId::LONDON {
return Ok(None);
}

self.next_block_base_fee_per_gas
.map_or_else(
|| {
let last_block = self.last_block()?;

let base_fee = last_block
.header()
.base_fee_per_gas
.unwrap_or_else(|| calculate_next_base_fee(last_block.header()));

Ok(base_fee)
},
Ok,
)
.map(Some)
}

/// Calculates the gas price for the next block.
pub fn next_gas_price(&self) -> Result<U256, BlockchainError> {
if let Some(next_block_base_fee_per_gas) = self.next_block_base_fee_per_gas()? {
let suggested_priority_fee_per_gas = U256::from(1_000_000_000u64);
Ok(next_block_base_fee_per_gas + suggested_priority_fee_per_gas)
} else {
// We return a hardcoded value for networks without EIP-1559
Ok(U256::from(8_000_000_000u64))
}
}

pub fn remove_filter(&mut self, filter_id: &U256) -> bool {
self.remove_filter_impl::</* IS_SUBSCRIPTION */ false>(filter_id)
}
Expand Down Expand Up @@ -839,10 +872,10 @@ impl ProviderData {
) -> Result<(), ProviderError> {
let TransactionRequestAndSender { request, sender } = transaction_request;

let last_pending_nonce = self.account_last_pending_nonce(sender).unwrap_or(0);
if request.nonce() > last_pending_nonce {
let next_nonce = self.account_next_nonce(sender)?;
if request.nonce() > next_nonce {
return Err(ProviderError::AutoMineNonceTooHigh {
expected: last_pending_nonce,
expected: next_nonce,
actual: request.nonce(),
});
}
Expand Down
110 changes: 74 additions & 36 deletions crates/edr_provider/src/requests/eth/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,21 @@ fn resolve_transaction_request(
data: &ProviderData,
transaction_request: EthTransactionRequest,
) -> Result<TransactionRequestAndSender, ProviderError> {
const DEFAULT_MAX_PRIORITY_FEE_PER_GAS: u64 = 1_000_000_000;

/// # Panics
///
/// Panics if `data.spec_id()` is less than `SpecId::LONDON`.
fn calculate_max_fee_per_gas(
data: &ProviderData,
max_priority_fee_per_gas: U256,
) -> Result<U256, BlockchainError> {
let base_fee_per_gas = data
.next_block_base_fee_per_gas()?
.expect("We already validated that the block is post-London.");
Ok(U256::from(2) * base_fee_per_gas + max_priority_fee_per_gas)
}

let EthTransactionRequest {
from,
to,
Expand All @@ -203,33 +218,51 @@ fn resolve_transaction_request(
value,
data: input,
nonce,
mut access_list,
access_list,
..
} = transaction_request;

let gas_limit = gas.unwrap_or_else(|| data.block_gas_limit());
let input = input.unwrap_or_default();
let nonce = nonce.unwrap_or_else(|| data.account_last_pending_nonce(&from).unwrap_or(0));
let nonce = nonce.map_or_else(|| data.account_next_nonce(&from), Ok)?;
let value = value.unwrap_or(U256::ZERO);

let request = match (gas_price, max_fee_per_gas, access_list.take()) {
// legacy transaction
(Some(_), None, None) => Some(TransactionRequest::Legacy(LegacyTransactionRequest {
nonce,
gas_price: gas_price.unwrap_or_default(),
gas_limit,
value,
input,
kind: match to {
Some(to) => TransactionKind::Call(to),
None => TransactionKind::Create,
},
})),
// EIP2930
(_, None, Some(access_list)) => {
Some(TransactionRequest::Eip2930(Eip2930TransactionRequest {
let request = match (
gas_price,
max_fee_per_gas,
max_priority_fee_per_gas,
access_list,
) {
(None, max_fee_per_gas, max_priority_fee_per_gas, access_list)
if data.spec_id() >= SpecId::LONDON
&& (max_fee_per_gas.is_some() || max_priority_fee_per_gas.is_some()) =>
{
let (max_fee_per_gas, max_priority_fee_per_gas) =
match (max_fee_per_gas, max_priority_fee_per_gas) {
(Some(max_fee_per_gas), Some(max_priority_fee_per_gas)) => {
(max_fee_per_gas, max_priority_fee_per_gas)
}
(Some(max_fee_per_gas), None) => (
max_fee_per_gas,
max_fee_per_gas.min(U256::from(DEFAULT_MAX_PRIORITY_FEE_PER_GAS)),
),
(None, Some(max_priority_fee_per_gas)) => {
let max_fee_per_gas =
calculate_max_fee_per_gas(data, max_priority_fee_per_gas)?;
(max_fee_per_gas, max_priority_fee_per_gas)
}
(None, None) => {
let max_priority_fee_per_gas = U256::from(DEFAULT_MAX_PRIORITY_FEE_PER_GAS);
let max_fee_per_gas =
calculate_max_fee_per_gas(data, max_priority_fee_per_gas)?;
(max_fee_per_gas, max_priority_fee_per_gas)
}
};

TransactionRequest::Eip1559(Eip1559TransactionRequest {
nonce,
gas_price: gas_price.unwrap_or_default(),
max_priority_fee_per_gas,
max_fee_per_gas,
gas_limit,
value,
input,
Expand All @@ -238,16 +271,13 @@ fn resolve_transaction_request(
None => TransactionKind::Create,
},
chain_id: 0,
access_list,
}))
access_list: access_list.unwrap_or_default(),
})
}
// EIP1559
(None, Some(_), access_list) | (None, None, access_list @ None) => {
// Empty fields fall back to the canonical transaction schema.
Some(TransactionRequest::Eip1559(Eip1559TransactionRequest {
(gas_price, _, _, Some(access_list)) => {
TransactionRequest::Eip2930(Eip2930TransactionRequest {
nonce,
max_fee_per_gas: max_fee_per_gas.unwrap_or_default(),
max_priority_fee_per_gas: max_priority_fee_per_gas.unwrap_or(U256::ZERO),
gas_price: gas_price.map_or_else(|| data.next_gas_price(), Ok)?,
gas_limit,
value,
input,
Expand All @@ -256,16 +286,24 @@ fn resolve_transaction_request(
None => TransactionKind::Create,
},
chain_id: 0,
access_list: access_list.unwrap_or_default(),
}))
access_list,
})
}
_ => None,
(gas_price, _, _, _) => TransactionRequest::Legacy(LegacyTransactionRequest {
nonce,
gas_price: gas_price.map_or_else(|| data.next_gas_price(), Ok)?,
gas_limit,
value,
input,
kind: match to {
Some(to) => TransactionKind::Call(to),
None => TransactionKind::Create,
},
}),
};

request
.ok_or_else(|| ProviderError::InvalidTransactionRequest)
.map(|request| TransactionRequestAndSender {
request,
sender: from,
})
Ok(TransactionRequestAndSender {
request,
sender: from,
})
}

0 comments on commit 253e07d

Please sign in to comment.