Skip to content

Commit

Permalink
Implement fee receivers (#837)
Browse files Browse the repository at this point in the history
* WIP Implement fee receivers

* Fix l1 fee tests

* Fix tests

* Use prioirty fee vault as coinbase

* Small nit

---------

Co-authored-by: eyusufatik <[email protected]>
  • Loading branch information
ercecan and eyusufatik authored Jul 2, 2024
1 parent 621d59c commit dca67fd
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 120 deletions.
40 changes: 13 additions & 27 deletions crates/evm/src/evm/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use sov_modules_api::{native_debug, native_error, native_warn};
use tracing::instrument;

use crate::system_events::SYSTEM_SIGNER;
use crate::{BASE_FEE_VAULT, L1_FEE_VAULT};

#[derive(Copy, Clone, Default, Debug)]
pub struct TxInfo {
Expand Down Expand Up @@ -326,25 +327,18 @@ impl<SPEC: Spec, EXT: CitreaExternalExt, DB: Database> CitreaHandler<SPEC, EXT,
return Ok(());
}

let beneficiary = context.evm.env.block.coinbase;
let effective_gas_price = context.evm.env.effective_gas_price();
let gas_used = U256::from(gas.spent() - gas.refunded() as u64);

// EIP-1559 discard basefee for coinbase transfer.
// ^ But we don't do that.
// We don't sub block.basefee from effective_gas_price.
let coinbase_gas_price = effective_gas_price;

let (coinbase_account, _) = context
.evm
.inner
.journaled_state
.load_account(beneficiary, &mut context.evm.inner.db)?;
// Only add base fee if eip-1559 is enabled
if SPEC::enabled(SpecId::LONDON) {
// add base fee to base fee vault
let base_fee_per_gas = context.evm.env.block.basefee;
let base_fee = base_fee_per_gas * gas_used;
change_balance(context, base_fee, true, BASE_FEE_VAULT)?;
}

coinbase_account.mark_touch();
coinbase_account.info.balance = coinbase_account
.info
.balance
.saturating_add(coinbase_gas_price * U256::from(gas.spent() - gas.refunded() as u64));
// send priority fee to coinbase using revm mainnet behaviour
revm::handler::mainnet::reward_beneficiary::<SPEC, EXT, DB>(context, gas)?;

Ok(())
}
Expand All @@ -366,7 +360,8 @@ impl<SPEC: Spec, EXT: CitreaExternalExt, DB: Database> CitreaHandler<SPEC, EXT,
l1_fee
)));
}
increase_coinbase_balance(context, l1_fee)?;
// add l1 fee to l1 fee vault
change_balance(context, l1_fee, true, L1_FEE_VAULT)?;
}

revm::handler::mainnet::output(context, result)
Expand Down Expand Up @@ -553,12 +548,3 @@ fn decrease_caller_balance<EXT, DB: Database>(
let address = context.evm.env.tx.caller;
change_balance(context, amount, false, address)
}

fn increase_coinbase_balance<EXT, DB: Database>(
context: &mut Context<EXT, DB>,
amount: U256,
) -> Result<(), EVMError<DB::Error>> {
let address = context.evm.env.block.coinbase;
change_balance(context, amount, true, address)?;
Ok(())
}
14 changes: 13 additions & 1 deletion crates/evm/src/evm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use reth_primitives::{Address, BaseFeeParams, B256, KECCAK_EMPTY, U256};
use reth_primitives::{address, Address, BaseFeeParams, B256, KECCAK_EMPTY, U256};
use revm::primitives::specification::SpecId;
use serde::{Deserialize, Serialize};
use sov_modules_api::{StateMap, StateVec};
Expand Down Expand Up @@ -29,6 +29,18 @@ use sov_state::codec::BcsCodec;
#[cfg(test)]
use crate::tests::DEFAULT_CHAIN_ID;

/// Bitcoin light client contract address
pub const BITCOIN_LIGHT_CLIENT_CONTRACT_ADDRESS: Address =
address!("3100000000000000000000000000000000000001");
/// Bridge contract address
pub const BRIDGE_CONTRACT_ADDRESS: Address = address!("3100000000000000000000000000000000000002");
/// Base fee vault address
pub const BASE_FEE_VAULT: Address = address!("3100000000000000000000000000000000000003");
/// L1 fee vault address
pub const L1_FEE_VAULT: Address = address!("3100000000000000000000000000000000000004");
/// Priority fee vault address
pub const PRIORITY_FEE_VAULT: Address = address!("3100000000000000000000000000000000000005");

// Stores information about an EVM account
#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
pub(crate) struct AccountInfo {
Expand Down
77 changes: 64 additions & 13 deletions crates/evm/src/tests/call_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ use crate::smart_contracts::{
use crate::tests::test_signer::TestSigner;
use crate::tests::utils::get_evm;
use crate::tests::DEFAULT_CHAIN_ID;
use crate::{AccountData, EvmConfig, RlpEvmTransaction};
use crate::{
AccountData, EvmConfig, RlpEvmTransaction, BASE_FEE_VAULT, L1_FEE_VAULT, PRIORITY_FEE_VAULT,
};

type C = DefaultContext;

Expand Down Expand Up @@ -629,6 +631,25 @@ pub(crate) fn create_contract_message_with_fee<T: TestContract>(
.unwrap()
}

pub(crate) fn create_contract_message_with_priority_fee<T: TestContract>(
dev_signer: &TestSigner,
nonce: u64,
contract: T,
max_fee_per_gas: u128,
max_priority_fee_per_gas: u128,
) -> RlpEvmTransaction {
dev_signer
.sign_default_transaction_with_priority_fee(
TxKind::Create,
contract.byte_code(),
nonce,
0,
max_fee_per_gas,
max_priority_fee_per_gas,
)
.unwrap()
}

pub(crate) fn create_contract_transaction<T: TestContract>(
dev_signer: &TestSigner,
nonce: u64,
Expand Down Expand Up @@ -783,16 +804,23 @@ pub(crate) fn get_evm_config_starting_base_fee(
spec: vec![(0, SpecId::SHANGHAI)].into_iter().collect(),
block_gas_limit: block_gas_limit.unwrap_or(ETHEREUM_BLOCK_GAS_LIMIT),
starting_base_fee,
coinbase: PRIORITY_FEE_VAULT,
..Default::default()
};
(config, dev_signer, contract_addr)
}

#[test]
fn test_l1_fee_success() {
fn run_tx(l1_fee_rate: u128, expected_balance: U256, expected_coinbase_balance: U256) {
fn run_tx(
l1_fee_rate: u128,
expected_balance: U256,
expected_coinbase_balance: U256,
expected_base_fee_vault_balance: U256,
expected_l1_fee_vault_balance: U256,
) {
let (config, dev_signer, _) =
get_evm_config_starting_base_fee(U256::from_str("1000000").unwrap(), None, 1);
get_evm_config_starting_base_fee(U256::from_str("10000000").unwrap(), None, 1);

let (evm, mut working_set) = get_evm(&config);

Expand All @@ -814,8 +842,13 @@ fn test_l1_fee_success() {
let sequencer_address = generate_address::<C>("sequencer");
let context = C::new(sender_address, sequencer_address, 1);

let deploy_message =
create_contract_message_with_fee(&dev_signer, 0, BlockHashContract::default(), 1);
let deploy_message = create_contract_message_with_priority_fee(
&dev_signer,
0,
BlockHashContract::default(),
2,
1,
);

evm.call(
CallMessage {
Expand All @@ -834,13 +867,19 @@ fn test_l1_fee_success() {
.get(&dev_signer.address(), &mut working_set)
.unwrap();

let base_fee_valut = evm.accounts.get(&BASE_FEE_VAULT, &mut working_set).unwrap();
let l1_fee_valut = evm.accounts.get(&L1_FEE_VAULT, &mut working_set).unwrap();

let coinbase_account = evm
.accounts
.get(&config.coinbase, &mut working_set)
.unwrap();
assert_eq!(config.coinbase, PRIORITY_FEE_VAULT);

assert_eq!(db_account.info.balance, expected_balance);
assert_eq!(base_fee_valut.info.balance, expected_base_fee_vault_balance);
assert_eq!(coinbase_account.info.balance, expected_coinbase_balance);
assert_eq!(l1_fee_valut.info.balance, expected_l1_fee_vault_balance);

assert_eq!(
evm.receipts
Expand All @@ -862,8 +901,22 @@ fn test_l1_fee_success() {

let gas_fee_paid = 114235;

run_tx(0, U256::from(885765), U256::from(gas_fee_paid));
run_tx(1, U256::from(885288), U256::from(gas_fee_paid + 477));
run_tx(
0,
U256::from(9771530),
// priority fee goes to coinbase
U256::from(gas_fee_paid),
U256::from(gas_fee_paid),
U256::from(0),
);
run_tx(
1,
U256::from(9771053),
// priority fee goes to coinbase
U256::from(gas_fee_paid),
U256::from(gas_fee_paid),
U256::from(477),
);
}

#[test]
Expand Down Expand Up @@ -1018,7 +1071,6 @@ fn test_l1_fee_halt() {
let expenses = 1106947 + // evm gas
445 + // l1 contract deploy fee
52; // l1 contract call fee

assert_eq!(
db_account.info.balance,
U256::from(
Expand All @@ -1027,10 +1079,9 @@ fn test_l1_fee_halt() {
)
);

let coinbase_account = evm
.accounts
.get(&config.coinbase, &mut working_set)
.unwrap();
let base_fee_valut = evm.accounts.get(&BASE_FEE_VAULT, &mut working_set).unwrap();
let l1_fee_valut = evm.accounts.get(&L1_FEE_VAULT, &mut working_set).unwrap();

assert_eq!(coinbase_account.info.balance, U256::from(expenses));
assert_eq!(base_fee_valut.info.balance, U256::from(1106947));
assert_eq!(l1_fee_valut.info.balance, U256::from(445 + 52));
}
28 changes: 19 additions & 9 deletions crates/evm/src/tests/queries/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod log_tests;

use std::str::FromStr;

use reth_primitives::{Address, Bytes};
use reth_primitives::{address, Address, Bytes};
use revm::primitives::{SpecId, KECCAK_EMPTY, U256};
use sov_modules_api::default_context::DefaultContext;
use sov_modules_api::hooks::HookSoftConfirmationInfo;
Expand Down Expand Up @@ -188,14 +188,24 @@ pub fn init_evm_single_block() -> (Evm<C>, WorkingSet<C>, TestSigner) {
let dev_signer: TestSigner = TestSigner::new_random();

let config = EvmConfig {
data: vec![AccountData {
address: dev_signer.address(),
balance: U256::from_str("100000000000000000000").unwrap(), // Setting initial balance
code_hash: KECCAK_EMPTY,
code: Bytes::default(),
nonce: 0,
storage: Default::default(),
}],
data: vec![
AccountData {
address: dev_signer.address(),
balance: U256::from_str("100000000000000000000").unwrap(), // Setting initial balance
code_hash: KECCAK_EMPTY,
code: Bytes::default(),
nonce: 0,
storage: Default::default(),
},
AccountData {
address: address!("0000000000000000000000000000000000000000"),
balance: U256::from_str("100000000000000000000").unwrap(), // Setting initial balance
code_hash: KECCAK_EMPTY,
code: Bytes::default(),
nonce: 0,
storage: Default::default(),
},
],
spec: vec![(0, SpecId::SHANGHAI)].into_iter().collect(),
..Default::default()
};
Expand Down
11 changes: 5 additions & 6 deletions crates/evm/src/tests/sys_tx_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::tests::call_tests::{
publish_event_message,
};
use crate::tests::utils::get_evm;
use crate::{AccountData, EvmConfig, SYSTEM_SIGNER};
use crate::{AccountData, EvmConfig, BASE_FEE_VAULT, L1_FEE_VAULT, SYSTEM_SIGNER};

type C = DefaultContext;

Expand Down Expand Up @@ -216,12 +216,11 @@ fn test_sys_bitcoin_light_client() {
},
]
);
let base_fee_vault = evm.accounts.get(&BASE_FEE_VAULT, &mut working_set).unwrap();
let l1_fee_vault = evm.accounts.get(&L1_FEE_VAULT, &mut working_set).unwrap();

let coinbase_account = evm
.accounts
.get(&config.coinbase, &mut working_set)
.unwrap();
assert_eq!(coinbase_account.info.balance, U256::from(114235 + 477));
assert_eq!(base_fee_vault.info.balance, U256::from(114235));
assert_eq!(l1_fee_vault.info.balance, U256::from(477));

let hash = evm
.get_call(
Expand Down
30 changes: 30 additions & 0 deletions crates/evm/src/tests/test_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,34 @@ impl TestSigner {
rlp: signed.envelope_encoded().to_vec(),
})
}

/// Signs default Eip1559 transaction with to, data and nonce overridden.
pub(crate) fn sign_default_transaction_with_priority_fee(
&self,
to: TxKind,
data: Vec<u8>,
nonce: u64,
value: u128,
max_fee_per_gas: u128,
max_priority_fee_per_gas: u128,
) -> Result<RlpEvmTransaction, SignError> {
let reth_tx = RethTxEip1559 {
to,
input: RethBytes::from(data),
nonce,
value: U256::from(value),
chain_id: DEFAULT_CHAIN_ID,
gas_limit: 1_000_000u64,
max_fee_per_gas,
max_priority_fee_per_gas,
..Default::default()
};

let reth_tx = RethTransaction::Eip1559(reth_tx);
let signed = self.signer.sign_transaction(reth_tx, self.address)?;

Ok(RlpEvmTransaction {
rlp: signed.envelope_encoded().to_vec(),
})
}
}
Loading

0 comments on commit dca67fd

Please sign in to comment.