Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EVM: Fix gas used for system txs in tx receipts #2516

Merged
merged 11 commits into from
Oct 4, 2023
10 changes: 5 additions & 5 deletions lib/ain-evm/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,11 @@ impl EVMBackend {
self.state.ro_handle(root)
}

pub fn deduct_prepay_gas(&mut self, sender: H160, prepay_gas: U256) -> Result<()> {
debug!(target: "backend", "[deduct_prepay_gas] Deducting {:#x} from {:#x}", prepay_gas, sender);
pub fn deduct_prepay_gas_fee(&mut self, sender: H160, prepay_fee: U256) -> Result<()> {
debug!(target: "backend", "[deduct_prepay_gas_fee] Deducting {:#x} from {:#x}", prepay_fee, sender);

let basic = self.basic(sender);
let balance = basic.balance.checked_sub(prepay_gas).ok_or_else(|| {
let balance = basic.balance.checked_sub(prepay_fee).ok_or_else(|| {
BackendError::DeductPrepayGasFailed(String::from(
"failed checked sub prepay gas with account balance",
))
Expand All @@ -169,7 +169,7 @@ impl EVMBackend {
Ok(())
}

pub fn refund_unused_gas(
pub fn refund_unused_gas_fee(
&mut self,
signed_tx: &SignedTx,
used_gas: U256,
Expand All @@ -182,7 +182,7 @@ impl EVMBackend {
})?;
let refund_amount = calculate_gas_fee(signed_tx, refund_gas, base_fee)?;

debug!(target: "backend", "[refund_unused_gas] Refunding {:#x} to {:#x}", refund_amount, signed_tx.sender);
debug!(target: "backend", "[refund_unused_gas_fee] Refunding {:#x} to {:#x}", refund_amount, signed_tx.sender);

let basic = self.basic(signed_tx.sender);
let balance = basic.balance.checked_add(refund_amount).ok_or_else(|| {
Expand Down
9 changes: 7 additions & 2 deletions lib/ain-evm/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,13 @@ impl EVMCoreService {

// Execute tx
let mut executor = AinExecutor::new(&mut backend);
let (tx_response, ..) =
executor.exec(&signed_tx, signed_tx.gas_limit(), prepay_fee, block_fee)?;
let (tx_response, ..) = executor.exec(
&signed_tx,
signed_tx.gas_limit(),
prepay_fee,
block_fee,
false,
)?;

// Validate total gas usage in queued txs exceeds block size
debug!("[validate_raw_tx] used_gas: {:#?}", tx_response.used_gas);
Expand Down
31 changes: 20 additions & 11 deletions lib/ain-evm/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,9 @@ impl<'backend> AinExecutor<'backend> {
&mut self,
signed_tx: &SignedTx,
gas_limit: U256,
prepay_gas: U256,
prepay_fee: U256,
base_fee: U256,
system_tx: bool,
) -> Result<(TxResponse, ReceiptV3)> {
self.backend.update_vicinity_from_tx(signed_tx, base_fee);
trace!(
Expand All @@ -146,8 +147,10 @@ impl<'backend> AinExecutor<'backend> {
access_list: signed_tx.access_list(),
};

self.backend
.deduct_prepay_gas(signed_tx.sender, prepay_gas)?;
if !system_tx && prepay_fee != U256::zero() {
self.backend
.deduct_prepay_gas_fee(signed_tx.sender, prepay_fee)?;
}

let metadata = StackSubstateMetadata::new(ctx.gas_limit, &Self::CONFIG);
let state = MemoryStackState::new(metadata, self.backend);
Expand Down Expand Up @@ -177,16 +180,16 @@ impl<'backend> AinExecutor<'backend> {
),
};

let used_gas = executor.used_gas();
let used_gas = if system_tx { 0u64 } else { executor.used_gas() };
let (values, logs) = executor.into_state().deconstruct();
let logs = logs.into_iter().collect::<Vec<_>>();

ApplyBackend::apply(self.backend, values, logs.clone(), true);
self.backend.commit();

if prepay_gas != U256::zero() {
if !system_tx && prepay_fee != U256::zero() {
self.backend
.refund_unused_gas(signed_tx, U256::from(used_gas), base_fee)?;
.refund_unused_gas_fee(signed_tx, U256::from(used_gas), base_fee)?;
}

let receipt = ReceiptV3::EIP1559(EIP658ReceiptData {
Expand Down Expand Up @@ -225,9 +228,15 @@ impl<'backend> AinExecutor<'backend> {
.into());
}

let prepay_gas = calculate_current_prepay_gas_fee(&signed_tx, base_fee)?;
let (tx_response, receipt) =
self.exec(&signed_tx, signed_tx.gas_limit(), prepay_gas, base_fee)?;
let prepay_fee = calculate_current_prepay_gas_fee(&signed_tx, base_fee)?;
let (tx_response, receipt) = self.exec(
&signed_tx,
signed_tx.gas_limit(),
prepay_fee,
base_fee,
false,
)?;

debug!(
"[apply_queue_tx]receipt : {:?}, exit_reason {:#?} for signed_tx : {:#x}",
receipt,
Expand Down Expand Up @@ -292,7 +301,7 @@ impl<'backend> AinExecutor<'backend> {
}

let (tx_response, receipt) =
self.exec(&signed_tx, U256::MAX, U256::zero(), U256::zero())?;
self.exec(&signed_tx, U256::MAX, U256::zero(), U256::zero(), true)?;
if !tx_response.exit_reason.is_succeed() {
return Err(format_err!(
"[apply_queue_tx] Transfer domain failed VM execution {:?}",
Expand Down Expand Up @@ -349,7 +358,7 @@ impl<'backend> AinExecutor<'backend> {
self.commit();

let (tx_response, receipt) =
self.exec(&signed_tx, U256::MAX, U256::zero(), U256::zero())?;
self.exec(&signed_tx, U256::MAX, U256::zero(), U256::zero(), true)?;
if !tx_response.exit_reason.is_succeed() {
debug!(
"[apply_queue_tx] DST20 bridge failed VM execution {:?}, data {}",
Expand Down
25 changes: 24 additions & 1 deletion test/functional/feature_evm_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
"""Test EVM contract"""

from test_framework.util import assert_equal
from test_framework.util import (
assert_equal,
int_to_eth_u256,
)
from test_framework.test_framework import DefiTestFramework
from test_framework.evm_contract import EVMContract
from test_framework.evm_key_pair import EvmKeyPair
Expand Down Expand Up @@ -140,13 +143,33 @@ def should_contract_store_and_emit_logs(self):
event_data = get_event_data(node.w3.codec, self.event_abi, logs[0])
assert_equal(event_data["event"], "NumberStored")

def transferdomain_receipt_gas_used(self):
dvmHash = self.nodes[0].transferdomain(
[
{
"src": {"address": self.address, "amount": "50@DFI", "domain": 2},
"dst": {
"address": self.evm_key_pair.address,
"amount": "50@DFI",
"domain": 3,
},
}
]
)
self.nodes[0].generate(1)
evmHash = self.nodes[0].vmmap(dvmHash, 5)["output"]
receipt = self.nodes[0].eth_getTransactionReceipt(evmHash)
assert_equal(receipt["gasUsed"], int_to_eth_u256(0))

def run_test(self):
self.setup()

self.should_create_contract()

self.should_contract_store_and_emit_logs()

self.transferdomain_receipt_gas_used()


if __name__ == "__main__":
EVMTestLogs().main()