Skip to content

Commit 96f2b50

Browse files
authored
Split base fee and tip handling (#700)
* Split base fee and tip handling * Return `NegativeImbalance` * clippy
1 parent e6ebb90 commit 96f2b50

File tree

3 files changed

+72
-31
lines changed

3 files changed

+72
-31
lines changed

frame/evm/src/lib.rs

+25-12
Original file line numberDiff line numberDiff line change
@@ -673,15 +673,18 @@ pub trait OnChargeEVMTransaction<T: Config> {
673673

674674
/// After the transaction was executed the actual fee can be calculated.
675675
/// This function should refund any overpaid fees and optionally deposit
676-
/// the corrected amount.
676+
/// the corrected amount, and handles the base fee rationing using the provided
677+
/// `OnUnbalanced` implementation.
678+
/// Returns the `NegativeImbalance` - if any - produced by the priority fee.
677679
fn correct_and_deposit_fee(
678680
who: &H160,
679681
corrected_fee: U256,
682+
base_fee: U256,
680683
already_withdrawn: Self::LiquidityInfo,
681-
);
684+
) -> Self::LiquidityInfo;
682685

683-
/// Introduced in EIP1559 to handle the priority tip payment to the block Author.
684-
fn pay_priority_fee(tip: U256);
686+
/// Introduced in EIP1559 to handle the priority tip.
687+
fn pay_priority_fee(tip: Self::LiquidityInfo);
685688
}
686689

687690
/// Implements the transaction payment for a pallet implementing the `Currency`
@@ -725,8 +728,9 @@ where
725728
fn correct_and_deposit_fee(
726729
who: &H160,
727730
corrected_fee: U256,
731+
base_fee: U256,
728732
already_withdrawn: Self::LiquidityInfo,
729-
) {
733+
) -> Self::LiquidityInfo {
730734
if let Some(paid) = already_withdrawn {
731735
let account_id = T::AddressMapping::into_account_id(*who);
732736

@@ -763,13 +767,21 @@ where
763767
.offset(refund_imbalance)
764768
.same()
765769
.unwrap_or_else(|_| C::NegativeImbalance::zero());
766-
OU::on_unbalanced(adjusted_paid);
770+
771+
let (base_fee, tip) = adjusted_paid.split(base_fee.low_u128().unique_saturated_into());
772+
// Handle base fee. Can be either burned, rationed, etc ...
773+
OU::on_unbalanced(base_fee);
774+
return Some(tip);
767775
}
776+
None
768777
}
769778

770-
fn pay_priority_fee(tip: U256) {
771-
let account_id = T::AddressMapping::into_account_id(<Pallet<T>>::find_author());
772-
let _ = C::deposit_into_existing(&account_id, tip.low_u128().unique_saturated_into());
779+
fn pay_priority_fee(tip: Self::LiquidityInfo) {
780+
// Default Ethereum behaviour: issue the tip to the block author.
781+
if let Some(tip) = tip {
782+
let account_id = T::AddressMapping::into_account_id(<Pallet<T>>::find_author());
783+
let _ = C::deposit_into_existing(&account_id, tip.peek());
784+
}
773785
}
774786
}
775787

@@ -794,12 +806,13 @@ impl<T> OnChargeEVMTransaction<T> for ()
794806
fn correct_and_deposit_fee(
795807
who: &H160,
796808
corrected_fee: U256,
809+
base_fee: U256,
797810
already_withdrawn: Self::LiquidityInfo,
798-
) {
799-
<EVMCurrencyAdapter::<<T as Config>::Currency, ()> as OnChargeEVMTransaction<T>>::correct_and_deposit_fee(who, corrected_fee, already_withdrawn)
811+
) -> Self::LiquidityInfo {
812+
<EVMCurrencyAdapter::<<T as Config>::Currency, ()> as OnChargeEVMTransaction<T>>::correct_and_deposit_fee(who, corrected_fee, base_fee, already_withdrawn)
800813
}
801814

802-
fn pay_priority_fee(tip: U256) {
815+
fn pay_priority_fee(tip: Self::LiquidityInfo) {
803816
<EVMCurrencyAdapter::<<T as Config>::Currency, ()> as OnChargeEVMTransaction<T>>::pay_priority_fee(tip);
804817
}
805818
}

frame/evm/src/runner/stack.rs

+22-18
Original file line numberDiff line numberDiff line change
@@ -154,20 +154,18 @@ impl<T: Config> Runner<T> {
154154

155155
// Post execution.
156156
let used_gas = U256::from(executor.used_gas());
157-
let (actual_fee, actual_priority_fee) =
158-
if let Some(max_priority_fee) = max_priority_fee_per_gas {
159-
let actual_priority_fee = max_fee_per_gas
160-
.saturating_sub(base_fee)
161-
.min(max_priority_fee)
162-
.saturating_mul(used_gas);
163-
let actual_fee = executor
164-
.fee(base_fee)
165-
.checked_add(actual_priority_fee)
166-
.unwrap_or_else(U256::max_value);
167-
(actual_fee, Some(actual_priority_fee))
168-
} else {
169-
(executor.fee(base_fee), None)
170-
};
157+
let actual_fee = if let Some(max_priority_fee) = max_priority_fee_per_gas {
158+
let actual_priority_fee = max_fee_per_gas
159+
.saturating_sub(base_fee)
160+
.min(max_priority_fee)
161+
.saturating_mul(used_gas);
162+
executor
163+
.fee(base_fee)
164+
.checked_add(actual_priority_fee)
165+
.unwrap_or_else(U256::max_value)
166+
} else {
167+
executor.fee(base_fee)
168+
};
171169
log::debug!(
172170
target: "evm",
173171
"Execution {:?} [source: {:?}, value: {}, gas_limit: {}, actual_fee: {}, is_transactional: {}]",
@@ -199,10 +197,16 @@ impl<T: Config> Runner<T> {
199197
// Refunded 200 - 40 = 160.
200198
// Tip 5 * 6 = 30.
201199
// Burned 200 - (160 + 30) = 10. Which is equivalent to gas_used * base_fee.
202-
T::OnChargeTransaction::correct_and_deposit_fee(&source, actual_fee, fee);
203-
if let Some(actual_priority_fee) = actual_priority_fee {
204-
T::OnChargeTransaction::pay_priority_fee(actual_priority_fee);
205-
}
200+
let actual_priority_fee = T::OnChargeTransaction::correct_and_deposit_fee(
201+
&source,
202+
// Actual fee after evm execution, including tip.
203+
actual_fee,
204+
// Base fee.
205+
executor.fee(base_fee),
206+
// Fee initially withdrawn.
207+
fee,
208+
);
209+
T::OnChargeTransaction::pay_priority_fee(actual_priority_fee);
206210

207211
let state = executor.into_state();
208212

frame/evm/src/tests.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ fn fee_deduction() {
127127
assert_eq!(Balances::free_balance(&substrate_addr), 90);
128128

129129
// Refund fees as 5 units
130-
<<Test as Config>::OnChargeTransaction as OnChargeEVMTransaction<Test>>::correct_and_deposit_fee(&evm_addr, U256::from(5), imbalance);
130+
<<Test as Config>::OnChargeTransaction as OnChargeEVMTransaction<Test>>::correct_and_deposit_fee(&evm_addr, U256::from(5), U256::from(5), imbalance);
131131
assert_eq!(Balances::free_balance(&substrate_addr), 95);
132132
});
133133
}
@@ -249,6 +249,30 @@ fn author_should_get_tip() {
249249
});
250250
}
251251

252+
#[test]
253+
fn issuance_after_tip() {
254+
new_test_ext().execute_with(|| {
255+
let before_tip = <Test as Config>::Currency::total_issuance();
256+
let result = EVM::call(
257+
Origin::root(),
258+
H160::default(),
259+
H160::from_str("1000000000000000000000000000000000000001").unwrap(),
260+
Vec::new(),
261+
U256::from(1),
262+
1000000,
263+
U256::from(2_000_000_000),
264+
Some(U256::from(1)),
265+
None,
266+
Vec::new(),
267+
);
268+
result.expect("EVM can be called");
269+
let after_tip = <Test as Config>::Currency::total_issuance();
270+
// Only base fee is burned
271+
let (base_fee, _) = <Test as Config>::FeeCalculator::min_gas_price();
272+
assert_eq!(after_tip, (before_tip - (base_fee.low_u64() * 21_000)));
273+
});
274+
}
275+
252276
#[test]
253277
fn author_same_balance_without_tip() {
254278
new_test_ext().execute_with(|| {

0 commit comments

Comments
 (0)