Skip to content

Commit

Permalink
Add ChangiIntermediateHeight5 fork (#2233)
Browse files Browse the repository at this point in the history
* Add ChangiIntermediateHeight5 fork

* Fix safe conversion to u64

* Fix lint

* add forkguard for total fees calculation check when adding to txqueue

* Fix lint

* Add ChangiIntermediateHeight5 values

* Switch to U256

---------

Co-authored-by: Niven <[email protected]>
Co-authored-by: Bushstar <[email protected]>
  • Loading branch information
3 people authored Jul 27, 2023
1 parent 1eeb32c commit f9da6d6
Show file tree
Hide file tree
Showing 12 changed files with 143 additions and 58 deletions.
1 change: 1 addition & 0 deletions lib/ain-cpp-imports/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub mod ffi {
fn pastChangiIntermediateHeight2() -> bool;
fn pastChangiIntermediateHeight3() -> bool;
fn pastChangiIntermediateHeight4() -> bool;
fn pastChangiIntermediateHeight5() -> bool;
fn CppLogPrintf(message: String);
}
}
7 changes: 7 additions & 0 deletions lib/ain-cpp-imports/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ mod ffi {
pub fn pastChangiIntermediateHeight4() -> bool {
unimplemented!("{}", UNIMPL_MSG)
}
pub fn pastChangiIntermediateHeight5() -> bool {
unimplemented!("{}", UNIMPL_MSG)
}

pub fn CppLogPrintf(_message: String) {
// Intentionally left empty, so it can be used from everywhere.
Expand Down Expand Up @@ -156,6 +159,10 @@ pub fn past_changi_intermediate_height_4_height() -> bool {
ffi::pastChangiIntermediateHeight4()
}

pub fn past_changi_intermediate_height_5_height() -> bool {
ffi::pastChangiIntermediateHeight5()
}

pub fn log_print(message: &str) {
// TODO: Switch to u8 to avoid intermediate string conversions
ffi::CppLogPrintf(message.to_owned());
Expand Down
17 changes: 11 additions & 6 deletions lib/ain-evm/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,14 @@ impl EVMCoreService {
return Err(anyhow!("insufficient balance to pay fees").into());
}

// Validate tx gas limit with intrinsic gas
check_tx_intrinsic_gas(&signed_tx)?;
} else if balance < MIN_GAS_PER_TX.into() || balance < prepay_fee {
if ain_cpp_imports::past_changi_intermediate_height_5_height() {
// Validate tx gas limit with intrinsic gas
check_tx_intrinsic_gas(&signed_tx)?;
} else if gas_limit < MIN_GAS_PER_TX {
debug!("[validate_raw_tx] gas limit is below the minimum gas per tx");
return Err(anyhow!("gas limit is below the minimum gas per tx").into());
}
} else if balance < MIN_GAS_PER_TX || balance < prepay_fee {
debug!("[validate_raw_tx] insufficient balance to pay fees");
return Err(anyhow!("insufficient balance to pay fees").into());
}
Expand Down Expand Up @@ -259,7 +264,7 @@ impl EVMCoreService {
.get_total_gas_used(queue_id)
.unwrap_or_default();

if U256::from(total_current_gas_used + used_gas) > MAX_GAS_PER_BLOCK {
if total_current_gas_used + U256::from(used_gas) > MAX_GAS_PER_BLOCK {
return Err(anyhow!("Block size limit is more than MAX_GAS_PER_BLOCK").into());
}
}
Expand Down Expand Up @@ -292,7 +297,7 @@ impl EVMCoreService {
) -> Result<(), EVMError> {
let queue_tx = QueueTx::BridgeTx(BridgeTx::EvmIn(BalanceUpdate { address, amount }));
self.tx_queues
.queue_tx(queue_id, queue_tx, hash, 0u64, U256::zero())?;
.queue_tx(queue_id, queue_tx, hash, U256::zero(), U256::zero())?;
Ok(())
}

Expand All @@ -318,7 +323,7 @@ impl EVMCoreService {
} else {
let queue_tx = QueueTx::BridgeTx(BridgeTx::EvmOut(BalanceUpdate { address, amount }));
self.tx_queues
.queue_tx(queue_id, queue_tx, hash, 0u64, U256::zero())?;
.queue_tx(queue_id, queue_tx, hash, U256::zero(), U256::zero())?;
Ok(())
}
}
Expand Down
26 changes: 14 additions & 12 deletions lib/ain-evm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,18 +267,20 @@ impl EVMServices {
total_priority_fees
);

match self.core.tx_queues.get_total_fees(queue_id) {
Some(total_fees) => {
if (total_burnt_fees + total_priority_fees) != U256::from(total_fees) {
return Err(anyhow!("EVM block rejected because block total fees != (burnt fees + priority fees). Burnt fees: {}, priority fees: {}, total fees: {}", total_burnt_fees, total_priority_fees, total_fees).into());
if ain_cpp_imports::past_changi_intermediate_height_5_height() {
match self.core.tx_queues.get_total_fees(queue_id) {
Some(total_fees) => {
if (total_burnt_fees + total_priority_fees) != total_fees {
return Err(anyhow!("EVM block rejected because block total fees != (burnt fees + priority fees). Burnt fees: {}, priority fees: {}, total fees: {}", total_burnt_fees, total_priority_fees, total_fees).into());
}
}
None => {
return Err(anyhow!(
"EVM block rejected because failed to get total fees from queue_id: {}",
queue_id
)
.into())
}
}
None => {
return Err(anyhow!(
"EVM block rejected because failed to get total fees from queue_id: {}",
queue_id
)
.into())
}
}

Expand Down Expand Up @@ -335,7 +337,7 @@ impl EVMServices {
queue_id: u64,
tx: QueueTx,
hash: NativeTxHash,
gas_used: u64,
gas_used: U256,
) -> Result<(), EVMError> {
let parent_data = self.block.get_latest_block_hash_and_number();
let parent_hash = match parent_data {
Expand Down
3 changes: 2 additions & 1 deletion lib/ain-evm/src/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ use evm::{
};

use anyhow::anyhow;
use ethereum_types::U256;
use log::debug;
use std::error::Error;

// Changi intermediate constant
pub const MIN_GAS_PER_TX: u64 = 21_000;
pub const MIN_GAS_PER_TX: U256 = U256([21_000, 0, 0, 0]);

fn get_tx_cost(signed_tx: &SignedTx) -> TransactionCost {
let access_list = signed_tx
Expand Down
128 changes: 92 additions & 36 deletions lib/ain-evm/src/txqueue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl TransactionQueueMap {
queue_id: u64,
tx: QueueTx,
hash: NativeTxHash,
gas_used: u64,
gas_used: U256,
base_fee: U256,
) -> Result<(), QueueError> {
self.queues
Expand Down Expand Up @@ -150,15 +150,15 @@ impl TransactionQueueMap {
.and_then(|queue| queue.get_next_valid_nonce(address))
}

pub fn get_total_gas_used(&self, queue_id: u64) -> Option<u64> {
pub fn get_total_gas_used(&self, queue_id: u64) -> Option<U256> {
self.queues
.read()
.unwrap()
.get(&queue_id)
.map(|queue| queue.get_total_gas_used())
}

pub fn get_total_fees(&self, queue_id: u64) -> Option<u64> {
pub fn get_total_fees(&self, queue_id: u64) -> Option<U256> {
self.queues
.read()
.unwrap()
Expand All @@ -177,8 +177,8 @@ pub enum QueueTx {
pub struct QueueTxItem {
pub queue_tx: QueueTx,
pub tx_hash: NativeTxHash,
pub tx_fee: u64,
pub gas_used: u64,
pub tx_fee: U256,
pub gas_used: U256,
}

/// The `TransactionQueueData` holds a queue of transactions with a map of the account nonces,
Expand All @@ -189,17 +189,17 @@ pub struct QueueTxItem {
struct TransactionQueueData {
transactions: Vec<QueueTxItem>,
account_nonces: HashMap<H160, U256>,
total_fees: u64,
total_gas_used: u64,
total_fees: U256,
total_gas_used: U256,
}

impl TransactionQueueData {
pub fn new() -> Self {
Self {
transactions: Vec::new(),
account_nonces: HashMap::new(),
total_fees: 0u64,
total_gas_used: 0u64,
total_fees: U256::zero(),
total_gas_used: U256::zero(),
}
}
}
Expand All @@ -218,15 +218,15 @@ impl TransactionQueue {

pub fn clear(&self) {
let mut data = self.data.lock().unwrap();
data.total_fees = 0u64;
data.total_gas_used = 0u64;
data.total_fees = U256::zero();
data.total_gas_used = U256::zero();
data.transactions.clear();
}

pub fn drain_all(&self) -> Vec<QueueTxItem> {
let mut data = self.data.lock().unwrap();
data.total_fees = 0u64;
data.total_gas_used = 0u64;
data.total_fees = U256::zero();
data.total_gas_used = U256::zero();
data.transactions.drain(..).collect::<Vec<QueueTxItem>>()
}

Expand All @@ -238,10 +238,10 @@ impl TransactionQueue {
&self,
tx: QueueTx,
tx_hash: NativeTxHash,
gas_used: u64,
gas_used: U256,
base_fee: U256,
) -> Result<(), QueueError> {
let mut gas_fee: u64 = 0;
let mut gas_fee = U256::zero();
let mut data = self.data.lock().unwrap();
if let QueueTx::SignedTx(signed_tx) = &tx {
if let Some(nonce) = data.account_nonces.get(&signed_tx.sender) {
Expand All @@ -252,12 +252,13 @@ impl TransactionQueue {
data.account_nonces
.insert(signed_tx.sender, signed_tx.nonce());

gas_fee = match calculate_gas_fee(signed_tx, gas_used.into(), base_fee) {
Ok(fee) => fee.as_u64(),
Err(_) => return Err(QueueError::InvalidFee),
};

data.total_fees += gas_fee;
if ain_cpp_imports::past_changi_intermediate_height_5_height() {
gas_fee = match calculate_gas_fee(signed_tx, gas_used, base_fee) {
Ok(fee) => fee,
Err(_) => return Err(QueueError::InvalidFee),
};
data.total_fees += gas_fee;
}
data.total_gas_used += gas_used;
}
data.transactions.push(QueueTxItem {
Expand All @@ -275,8 +276,8 @@ impl TransactionQueue {

pub fn remove_txs_by_sender(&self, sender: H160) {
let mut data = self.data.lock().unwrap();
let mut fees_to_remove = 0;
let mut gas_used_to_remove = 0;
let mut fees_to_remove = U256::zero();
let mut gas_used_to_remove = U256::zero();
data.transactions.retain(|item| {
let tx_sender = match &item.queue_tx {
QueueTx::SignedTx(tx) => tx.sender,
Expand Down Expand Up @@ -304,11 +305,11 @@ impl TransactionQueue {
.map(|nonce| nonce + 1)
}

pub fn get_total_fees(&self) -> u64 {
pub fn get_total_fees(&self) -> U256 {
self.data.lock().unwrap().total_fees
}

pub fn get_total_gas_used(&self) -> u64 {
pub fn get_total_gas_used(&self) -> U256 {
self.data.lock().unwrap().total_gas_used
}
}
Expand Down Expand Up @@ -361,10 +362,25 @@ mod tests {
// Nonce 0, sender 0xe61a3a6eb316d773c773f4ce757a542f673023c6
let tx3 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869808502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa03d28d24808c3de08c606c5544772ded91913f648ad56556f181905208e206c85a00ecd0ba938fb89fc4a17ea333ea842c7305090dee9236e2b632578f9e5045cb3").unwrap()));

queue.queue_tx(tx1, H256::from_low_u64_be(1).into(), 0u64, U256::zero())?;
queue.queue_tx(tx2, H256::from_low_u64_be(2).into(), 0u64, U256::zero())?;
queue.queue_tx(
tx1,
H256::from_low_u64_be(1).into(),
U256::zero(),
U256::zero(),
)?;
queue.queue_tx(
tx2,
H256::from_low_u64_be(2).into(),
U256::zero(),
U256::zero(),
)?;
// Should fail as nonce 2 is already queued for this sender
let queued = queue.queue_tx(tx3, H256::from_low_u64_be(3).into(), 0u64, U256::zero());
let queued = queue.queue_tx(
tx3,
H256::from_low_u64_be(3).into(),
U256::zero(),
U256::zero(),
);
assert!(matches!(queued, Err(QueueError::InvalidNonce { .. })));
Ok(())
}
Expand All @@ -388,11 +404,31 @@ mod tests {
// Nonce 0, sender 0xe61a3a6eb316d773c773f4ce757a542f673023c6
let tx4 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869808502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa03d28d24808c3de08c606c5544772ded91913f648ad56556f181905208e206c85a00ecd0ba938fb89fc4a17ea333ea842c7305090dee9236e2b632578f9e5045cb3").unwrap()));

queue.queue_tx(tx1, H256::from_low_u64_be(1).into(), 0u64, U256::zero())?;
queue.queue_tx(tx2, H256::from_low_u64_be(2).into(), 0u64, U256::zero())?;
queue.queue_tx(tx3, H256::from_low_u64_be(3).into(), 0u64, U256::zero())?;
queue.queue_tx(
tx1,
H256::from_low_u64_be(1).into(),
U256::zero(),
U256::zero(),
)?;
queue.queue_tx(
tx2,
H256::from_low_u64_be(2).into(),
U256::zero(),
U256::zero(),
)?;
queue.queue_tx(
tx3,
H256::from_low_u64_be(3).into(),
U256::zero(),
U256::zero(),
)?;
// Should fail as nonce 2 is already queued for this sender
let queued = queue.queue_tx(tx4, H256::from_low_u64_be(4).into(), 0u64, U256::zero());
let queued = queue.queue_tx(
tx4,
H256::from_low_u64_be(4).into(),
U256::zero(),
U256::zero(),
);
assert!(matches!(queued, Err(QueueError::InvalidNonce { .. })));
Ok(())
}
Expand All @@ -413,10 +449,30 @@ mod tests {
// Nonce 2, sender 0x6bc42fd533d6cb9d973604155e1f7197a3b0e703
let tx4 = QueueTx::SignedTx(Box::new(SignedTx::try_from("f869028502540be400832dc6c0943e338e722607a8c1eab615579ace4f6dedfa19fa80840adb1a9a2aa09588b47d2cd3f474d6384309cca5cb8e360cb137679f0a1589a1c184a15cb27ca0453ddbf808b83b279cac3226b61a9d83855aba60ae0d3a8407cba0634da7459d").unwrap()));

queue.queue_tx(tx1, H256::from_low_u64_be(1).into(), 0u64, U256::zero())?;
queue.queue_tx(tx2, H256::from_low_u64_be(2).into(), 0u64, U256::zero())?;
queue.queue_tx(tx3, H256::from_low_u64_be(3).into(), 0u64, U256::zero())?;
queue.queue_tx(tx4, H256::from_low_u64_be(4).into(), 0u64, U256::zero())?;
queue.queue_tx(
tx1,
H256::from_low_u64_be(1).into(),
U256::zero(),
U256::zero(),
)?;
queue.queue_tx(
tx2,
H256::from_low_u64_be(2).into(),
U256::zero(),
U256::zero(),
)?;
queue.queue_tx(
tx3,
H256::from_low_u64_be(3).into(),
U256::zero(),
U256::zero(),
)?;
queue.queue_tx(
tx4,
H256::from_low_u64_be(4).into(),
U256::zero(),
U256::zero(),
)?;
Ok(())
}
}
2 changes: 1 addition & 1 deletion lib/ain-rs-exports/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ pub fn evm_try_queue_tx(
Ok(signed_tx) => {
match SERVICES
.evm
.queue_tx(queue_id, signed_tx.into(), hash, gas_used)
.queue_tx(queue_id, signed_tx.into(), hash, U256::from(gas_used))
{
Ok(_) => cross_boundary_success(result),
Err(e) => cross_boundary_error_return(result, e.to_string()),
Expand Down
Loading

0 comments on commit f9da6d6

Please sign in to comment.