Skip to content

Commit

Permalink
Merge branch 'master' of github.com:DeFiCh/ain into evm/fix-used-gas
Browse files Browse the repository at this point in the history
  • Loading branch information
sieniven committed Jul 17, 2023
2 parents 2ed0ff8 + cee421c commit 2c33cd9
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 16 deletions.
10 changes: 10 additions & 0 deletions lib/ain-evm/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,16 @@ impl BlockService {
)
}

pub fn calculate_next_block_base_fee(&self) -> U256 {
let current_block_data = self.get_latest_block_hash_and_number();
let current_block_hash = match current_block_data {
None => H256::zero(),
Some((hash, _)) => hash,
};

self.calculate_base_fee(current_block_hash)
}

pub fn fee_history(
&self,
block_count: usize,
Expand Down
3 changes: 2 additions & 1 deletion lib/ain-evm/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ use crate::{
traits::{Executor, ExecutorContext},
transaction::SignedTx,
};
use anyhow::anyhow;

use ethereum::{AccessList, Account, Block, Log, PartialHeader, TransactionV2};
use ethereum_types::{Bloom, BloomInput, H160, U256};

use anyhow::anyhow;
use hex::FromHex;
use log::debug;
use std::error::Error;
Expand Down
29 changes: 26 additions & 3 deletions lib/ain-evm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@ use crate::backend::{EVMBackend, Vicinity};
use crate::block::BlockService;
use crate::core::{EVMCoreService, EVMError, NativeTxHash, MAX_GAS_PER_BLOCK};
use crate::executor::{AinExecutor, TxResponse};
use crate::fee::calculate_gas_fee;
use crate::fee::{calculate_gas_fee, get_tx_gas_price};
use crate::filters::FilterService;
use crate::log::LogService;
use crate::receipt::ReceiptService;
use crate::storage::traits::BlockStorage;
use crate::storage::Storage;
use crate::traits::Executor;
use crate::transaction::bridge::{BalanceUpdate, BridgeTx};
use crate::transaction::SignedTx;
use crate::trie::GENESIS_STATE_ROOT;
use crate::txqueue::QueueTx;

use anyhow::anyhow;
use ethereum::{Block, PartialHeader, ReceiptV3};
use ethereum::{Block, PartialHeader, ReceiptV3, TransactionV2};
use ethereum_types::{Bloom, H160, H64, U256};

use anyhow::anyhow;
use hex::FromHex;
use log::debug;
use primitive_types::H256;
use std::error::Error;
Expand Down Expand Up @@ -274,6 +277,26 @@ impl EVMServices {
}
}

pub fn verify_tx_fees(&self, tx: &str) -> Result<(), Box<dyn Error>> {
debug!("[verify_tx_fees] raw transaction : {:#?}", tx);
let buffer = <Vec<u8>>::from_hex(tx)?;
let tx: TransactionV2 = ethereum::EnvelopedDecodable::decode(&buffer)
.map_err(|_| anyhow!("Error: decoding raw tx to TransactionV2"))?;
debug!("[verify_tx_fees] TransactionV2 : {:#?}", tx);
let signed_tx: SignedTx = tx.try_into()?;

if ain_cpp_imports::past_changi_intermediate_height_4_height() {
let tx_gas_price = get_tx_gas_price(&signed_tx);
let next_block_fees = self.block.calculate_next_block_base_fee();
if tx_gas_price < next_block_fees {
debug!("[verify_tx_fees] tx gas price is lower than next block base fee");
return Err(anyhow!("tx gas price is lower than next block base fee").into());
}
}

Ok(())
}

pub fn queue_tx(
&self,
context: u64,
Expand Down
11 changes: 11 additions & 0 deletions lib/ain-evm/src/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use ethereum_types::U256;

use crate::transaction::SignedTx;

// Gas prices are denoted in wei
pub fn calculate_prepay_gas(signed_tx: &SignedTx) -> U256 {
match &signed_tx.transaction {
ethereum::TransactionV2::Legacy(tx) => tx.gas_limit.saturating_mul(tx.gas_price),
Expand All @@ -10,10 +11,20 @@ pub fn calculate_prepay_gas(signed_tx: &SignedTx) -> U256 {
}
}

// Gas prices are denoted in wei
pub fn calculate_gas_fee(signed_tx: &SignedTx, used_gas: U256) -> U256 {
match &signed_tx.transaction {
ethereum::TransactionV2::Legacy(tx) => used_gas.saturating_mul(tx.gas_price),
ethereum::TransactionV2::EIP2930(tx) => used_gas.saturating_mul(tx.gas_price),
ethereum::TransactionV2::EIP1559(tx) => used_gas.saturating_mul(tx.max_fee_per_gas),
}
}

// Gas prices are denoted in wei
pub fn get_tx_gas_price(signed_tx: &SignedTx) -> U256 {
match &signed_tx.transaction {
ethereum::TransactionV2::Legacy(tx) => tx.gas_price,
ethereum::TransactionV2::EIP2930(tx) => tx.gas_price,
ethereum::TransactionV2::EIP1559(tx) => tx.max_fee_per_gas,
}
}
17 changes: 14 additions & 3 deletions lib/ain-rs-exports/src/evm.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use ain_evm::{
evm::FinalizedBlockInfo,
services::SERVICES,
storage::traits::Rollback,
transaction::{self, SignedTx},
};

use ain_evm::services::SERVICES;
use log::debug;

use ethereum::{EnvelopedEncodable, TransactionAction, TransactionSignature};
use log::debug;
use primitive_types::{H160, H256, U256};
use transaction::{LegacyUnsignedTransaction, TransactionError, LOWER_H256};

Expand Down Expand Up @@ -197,6 +196,7 @@ pub fn evm_sub_balance(context: u64, address: &str, amount: [u8; 32], hash: [u8;
/// - The EVM transaction is invalid
/// - Could not fetch the underlying EVM account
/// - Account's nonce does not match raw tx's nonce
/// - Transaction gas fee is lower than the next block's base fee
///
/// # Returns
///
Expand All @@ -208,6 +208,17 @@ pub fn evm_try_prevalidate_raw_tx(
call_tx: bool,
context: u64,
) -> ffi::ValidateTxCompletion {
match SERVICES.evm.verify_tx_fees(tx) {
Ok(_) => (),
Err(e) => {
debug!("evm_try_prevalidate_raw_tx failed with error: {e}");
result.ok = false;
result.reason = e.to_string();

return ffi::ValidateTxCompletion::default();
}
}

match SERVICES.evm.core.validate_raw_tx(tx, call_tx, context) {
Ok((signed_tx, tx_fees, gas_used)) => {
result.ok = true;
Expand Down
36 changes: 27 additions & 9 deletions test/functional/feature_evm_fee.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
self.extra_args = [
['-dummypos=0', '-txnotokens=0', '-amkheight=50', '-bayfrontheight=51', '-eunosheight=80', '-fortcanningheight=82', '-fortcanninghillheight=84', '-fortcanningroadheight=86', '-fortcanningcrunchheight=88', '-fortcanningspringheight=90', '-fortcanninggreatworldheight=94', '-fortcanningepilogueheight=96', '-grandcentralheight=101', '-nextnetworkupgradeheight=105', '-changiintermediateheight=105', '-subsidytest=1', '-txindex=1'],
['-dummypos=0', '-txnotokens=0', '-amkheight=50', '-bayfrontheight=51', '-eunosheight=80', '-fortcanningheight=82', '-fortcanninghillheight=84', '-fortcanningroadheight=86', '-fortcanningcrunchheight=88', '-fortcanningspringheight=90', '-fortcanninggreatworldheight=94', '-fortcanningepilogueheight=96', '-grandcentralheight=101', '-nextnetworkupgradeheight=105', '-changiintermediateheight=105', '-changiintermediate4height=105', '-subsidytest=1', '-txindex=1'],
]

def setup(self):
Expand Down Expand Up @@ -50,13 +50,29 @@ def test_fee_deduction(self):
'to': self.toAddress,
'value': '0x7148', # 29_000
'gas': '0x7a120',
'gasPrice': '0x1',
'gasPrice': '0x2540BE400', # 10_000_000_000
})
self.nodes[0].generate(1)

balance = self.nodes[0].eth_getBalance(self.ethAddress, "latest")
# Deduct 50000. 29000 value + min 21000 call fee
assert_equal(int(balance[2:], 16), 99999999999999950000)
assert_equal(int(balance[2:], 16), 99999789999999971000)

self.rollback_to(height)

def test_low_gas_price(self):
height = self.nodes[0].getblockcount()

balance = self.nodes[0].eth_getBalance(self.ethAddress, "latest")
assert_equal(int(balance[2:], 16), 100000000000000000000)

assert_raises_rpc_error(-32001, "tx gas price is lower than next block base fee", self.nodes[0].eth_sendTransaction, {
'from': self.ethAddress,
'to': self.toAddress,
'value': '0x7148', # 29_000
'gas': '0x7a120',
'gasPrice': '0x3B9ACA00', # 1_000_000_000
})

self.rollback_to(height)

Expand All @@ -71,13 +87,13 @@ def test_high_gas_price(self):
'to': self.toAddress,
'value': '0x7148', # 29_000
'gas': '0x7a120',
'gasPrice': '0x3B9ACA00', # 1_000_000_000
'gasPrice': '0x2540BE400', # 10_000_000_000
})
self.nodes[0].generate(1)

balance = self.nodes[0].eth_getBalance(self.ethAddress, "latest")
# Deduct 21_000_000_029_000. 29_000 value + 21_000 * 1_000_000_000
assert_equal(int(balance[2:], 16), 99999978999999971000)
assert_equal(int(balance[2:], 16), 99999789999999971000)

self.rollback_to(height)

Expand Down Expand Up @@ -108,7 +124,7 @@ def test_gas_limit_higher_than_block_limit(self):
'to': self.toAddress,
'value': '0x7148', # 29_000
'gas': '0x1C9C381', # 30_000_001
'gasPrice': '0x1',
'gasPrice': '0x2540BE400', # 10_000_000_000
})

self.rollback_to(height)
Expand All @@ -125,7 +141,7 @@ def test_fee_deduction_empty_balance(self):
'to': self.toAddress,
'value': '0x7148', # 29_000
'gas': '0x7a120',
'gasPrice': '0x1',
'gasPrice': '0x2540BE400', # 10_000_000_000
})

self.rollback_to(height)
Expand All @@ -141,15 +157,15 @@ def test_fee_deduction_send_full_balance(self):
'to': self.toAddress,
'value': balance,
'gas': '0x7a120',
'gasPrice': '0x1',
'gasPrice': '0x2540BE400', # 10_000_000_000
})
self.nodes[0].generate(1)

balance = self.nodes[0].eth_getBalance(self.ethAddress, "latest")

# Don't consume balance as not enough to cover send value + fee.
# Deduct only 21000 call fee
assert_equal(int(balance[2:], 16), 99999999999999979000)
assert_equal(int(balance[2:], 16), 99999790000000000000)

self.rollback_to(height)

Expand All @@ -161,6 +177,8 @@ def run_test(self):

self.test_fee_deduction()

self.test_low_gas_price()

self.test_high_gas_price()

self.test_max_gas_price()
Expand Down

0 comments on commit 2c33cd9

Please sign in to comment.