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: Checked U256 casting #2567

Merged
merged 10 commits into from
Oct 12, 2023
Merged
Next Next commit
Checked U256 casting
shohamc1 committed Oct 11, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit c803aeeac3f10ed8cf12e0ca89193b7d8943842d
24 changes: 14 additions & 10 deletions lib/ain-evm/src/block.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ use statrs::statistics::{Data, OrderStatistics};

use crate::{
storage::{traits::BlockStorage, Storage},
Result,
utils, Result,
};

pub struct BlockService {
@@ -135,9 +135,9 @@ impl BlockService {
.get_block_by_hash(&parent_hash)?
.ok_or(format_err!("Parent block not found"))?;
let parent_base_fee = parent_block.header.base_fee;
let parent_gas_used = parent_block.header.gas_used.as_u64();
let parent_gas_target =
parent_block.header.gas_limit.as_u64() / elasticity_multiplier.as_u64();
let parent_gas_used = utils::checked_as_u64(parent_block.header.gas_used)?;
let parent_gas_target = utils::checked_as_u64(parent_block.header.gas_limit)?
/ utils::checked_as_u64(elasticity_multiplier)?;

Ok(self.get_base_fee(
parent_gas_used,
@@ -189,11 +189,14 @@ impl BlockService {
let gas_ratio = if block.header.gas_limit == U256::zero() {
f64::default() // empty block
} else {
block.header.gas_used.as_u64() as f64 / block.header.gas_limit.as_u64() as f64
utils::checked_as_u64(block.header.gas_used)? as f64
/ utils::checked_as_u64(block.header.gas_limit)? as f64
};

(base_fee, gas_ratio)
Ok((base_fee, gas_ratio))
})
.collect::<Result<Vec<(U256, f64)>>>()?
.into_iter()
.unzip();
shohamc1 marked this conversation as resolved.
Show resolved Hide resolved

let reward = if priority_fee_percentile.is_empty() {
@@ -233,10 +236,10 @@ impl BlockService {
}

let mut block_rewards = Vec::new();
let priority_fees = block_eip_tx
let priority_fees: Vec<f64> = block_eip_tx
Jouzo marked this conversation as resolved.
Show resolved Hide resolved
.iter()
.map(|tx| tx.max_priority_fee_per_gas.as_u64() as f64)
.collect::<Vec<f64>>();
.map(|tx| Ok(utils::checked_as_u64(tx.max_priority_fee_per_gas)? as f64))
.collect::<Result<Vec<f64>>>()?;
let mut data = Data::new(priority_fees);

for pct in &priority_fee_percentile {
@@ -317,7 +320,8 @@ impl BlockService {
continue;
}
TransactionAny::EIP1559(t) => {
priority_fees.push(t.max_priority_fee_per_gas.as_u64() as f64);
priority_fees
.push(utils::checked_as_u64(t.max_priority_fee_per_gas)? as f64);
}
}
}
3 changes: 2 additions & 1 deletion lib/ain-evm/src/core.rs
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ use crate::{
transaction::SignedTx,
trie::{TrieDBStore, GENESIS_STATE_ROOT},
txqueue::TransactionQueueMap,
utils,
weiamount::{try_from_satoshi, WeiAmount},
Result,
};
@@ -220,7 +221,7 @@ impl EVMCoreService {
parent_hash: genesis.parent_hash.unwrap_or_default(),
mix_hash: genesis.mix_hash.unwrap_or_default(),
nonce: genesis.nonce.unwrap_or_default(),
timestamp: genesis.timestamp.unwrap_or_default().as_u64(),
timestamp: utils::checked_as_u64(genesis.timestamp.unwrap_or_default())?,
difficulty: genesis.difficulty.unwrap_or_default(),
base_fee: genesis.base_fee.unwrap_or(INITIAL_BASE_FEE),
},
4 changes: 2 additions & 2 deletions lib/ain-evm/src/gas.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ use evm::{
};
use log::debug;

use crate::{transaction::SignedTx, Result};
use crate::{transaction::SignedTx, utils, Result};

fn get_tx_cost(signed_tx: &SignedTx) -> TransactionCost {
let access_list = signed_tx
@@ -23,7 +23,7 @@ fn get_tx_cost(signed_tx: &SignedTx) -> TransactionCost {

pub fn check_tx_intrinsic_gas(signed_tx: &SignedTx) -> Result<()> {
const CONFIG: Config = Config::shanghai();
let mut gasometer = Gasometer::new(signed_tx.gas_limit().as_u64(), &CONFIG);
let mut gasometer = Gasometer::new(utils::checked_as_u64(signed_tx.gas_limit())?, &CONFIG);

let tx_cost = get_tx_cost(signed_tx);
match gasometer.record_transaction(tx_cost) {
1 change: 1 addition & 0 deletions lib/ain-evm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ pub mod storage;
pub mod transaction;
mod trie;
pub mod txqueue;
pub mod utils;
pub mod weiamount;

pub use anyhow::{format_err, Ok};
63 changes: 63 additions & 0 deletions lib/ain-evm/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use anyhow::{format_err, Error};
use sp_core::U256;

fn fits_word(arr: &[u64; 4]) -> bool {
for &i in arr.iter().skip(1) {
if i != 0_u64 {
return false;
}
}

true
}
pub fn checked_as_u64(num: U256) -> Result<u64, Error> {
let U256(ref arr) = num;
if !fits_word(arr) {
return Err(format_err!("Cannot cast U256 to u64"));
}

Ok(num.as_u64())
}

pub fn checked_as_usize(num: U256) -> Result<usize, Error> {
let U256(ref arr) = num;
if !fits_word(arr) || arr[0] > usize::MAX as u64 {
return Err(format_err!("Cannot cast U256 to usize"));
}

Ok(num.as_usize())
}

#[cfg(test)]
mod tests {
use crate::utils::{checked_as_u64, checked_as_usize};
use sp_core::U256;

#[test]
fn test_should_throw_error_u64() {
let num = U256::MAX;

assert!(checked_as_u64(num).is_err());
}

#[test]
fn test_should_throw_error_usize() {
let num = U256::MAX;

assert!(checked_as_usize(num).is_err());
}

#[test]
fn test_u64() {
let num = U256::one();

assert_eq!(checked_as_u64(num).unwrap(), 1_u64);
}

#[test]
fn test_usize() {
let num = U256::one();

assert_eq!(checked_as_usize(num).unwrap(), 1_usize);
}
}
26 changes: 15 additions & 11 deletions lib/ain-grpc/src/rpc/eth.rs
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ use ain_evm::{
log::FilterType,
storage::traits::{BlockStorage, ReceiptStorage, TransactionStorage},
transaction::SignedTx,
utils,
};
use ethereum::{EnvelopedEncodable, TransactionV2};
use ethereum_types::{H160, H256, U256};
@@ -350,7 +351,7 @@ impl MetachainRPCServer for MetachainRPCModule {
data: &input
.map(|d| d.0)
.unwrap_or(data.map(|d| d.0).unwrap_or_default()),
gas_limit: gas.unwrap_or(U256::from(max_gas_per_block)).as_u64(),
gas_limit: utils::checked_as_u64(gas.unwrap_or(U256::from(max_gas_per_block)))?,
gas_price,
max_fee_per_gas,
access_list: access_list.unwrap_or_default(),
@@ -539,7 +540,7 @@ impl MetachainRPCServer for MetachainRPCModule {
) -> RpcResult<Option<EthTransactionInfo>> {
self.handler
.storage
.get_transaction_by_block_hash_and_index(&hash, index.as_usize())
.get_transaction_by_block_hash_and_index(&hash, utils::checked_as_usize(index)?)
.map_err(to_jsonrpsee_custom_error)?
.map_or(Ok(None), |tx| {
let tx_hash = &tx.hash();
@@ -572,7 +573,7 @@ impl MetachainRPCServer for MetachainRPCModule {
) -> RpcResult<Option<EthTransactionInfo>> {
self.handler
.storage
.get_transaction_by_block_number_and_index(&number, index.as_usize())
.get_transaction_by_block_number_and_index(&number, utils::checked_as_usize(index)?)
.map_err(to_jsonrpsee_custom_error)?
.map_or(Ok(None), |tx| {
let tx_hash = &tx.hash();
@@ -816,7 +817,7 @@ impl MetachainRPCServer for MetachainRPCModule {
to,
value: value.unwrap_or_default(),
data: &data.map(|d| d.0).unwrap_or_default(),
gas_limit: gas.unwrap_or(U256::from(gas_limit)).as_u64(),
gas_limit: utils::checked_as_u64(gas.unwrap_or(U256::from(gas_limit)))?,
gas_price,
max_fee_per_gas,
access_list: access_list.unwrap_or_default(),
@@ -874,7 +875,7 @@ impl MetachainRPCServer for MetachainRPCModule {
.handler
.block
.fee_history(
block_count.as_usize(),
utils::checked_as_usize(block_count)?,
first_block_number,
priority_fee_percentile,
)
@@ -1030,7 +1031,7 @@ impl MetachainRPCServer for MetachainRPCModule {
let filter = self
.handler
.filters
.get_filter(filter_id.as_usize())
.get_filter(utils::checked_as_usize(filter_id)?)
.map_err(to_jsonrpsee_custom_error)?;

let res = match filter {
@@ -1056,21 +1057,21 @@ impl MetachainRPCServer for MetachainRPCModule {

self.handler
.filters
.update_last_block(filter_id.as_usize(), current_block_height)
.update_last_block(utils::checked_as_usize(filter_id)?, current_block_height)
.map_err(to_jsonrpsee_custom_error)?;

GetFilterChangesResult::Logs(logs)
}
Filter::NewBlock(_) => GetFilterChangesResult::NewBlock(
self.handler
.filters
.get_entries_from_filter(filter_id.as_usize())
.get_entries_from_filter(utils::checked_as_usize(filter_id)?)
.map_err(to_jsonrpsee_custom_error)?,
),
Filter::NewPendingTransactions(_) => GetFilterChangesResult::NewPendingTransactions(
self.handler
.filters
.get_entries_from_filter(filter_id.as_usize())
.get_entries_from_filter(utils::checked_as_usize(filter_id)?)
.map_err(to_jsonrpsee_custom_error)?,
),
};
@@ -1079,14 +1080,17 @@ impl MetachainRPCServer for MetachainRPCModule {
}

fn uninstall_filter(&self, filter_id: U256) -> RpcResult<bool> {
Ok(self.handler.filters.delete_filter(filter_id.as_usize()))
Ok(self
.handler
.filters
.delete_filter(utils::checked_as_usize(filter_id)?))
}

fn get_filter_logs(&self, filter_id: U256) -> RpcResult<Vec<LogResult>> {
let filter = self
.handler
.filters
.get_filter(filter_id.as_usize())
.get_filter(utils::checked_as_usize(filter_id)?)
.map_err(to_jsonrpsee_custom_error)?;

match filter {
5 changes: 3 additions & 2 deletions lib/ain-rs-exports/src/evm.rs
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ use ain_evm::{
system::{DST20Data, DeployContractData, SystemTx, TransferDirection, TransferDomainData},
},
txqueue::QueueTx,
utils,
weiamount::{try_from_gwei, try_from_satoshi, WeiAmount},
Result,
};
@@ -509,7 +510,7 @@ fn unsafe_construct_block_in_q(
failed_transactions,
total_burnt_fees,
total_priority_fees,
block_number: block_number.as_u64(),
block_number: utils::checked_as_u64(block_number)?,
})
}
}
@@ -829,7 +830,7 @@ fn get_tx_hash(raw_tx: &str) -> Result<String> {
#[ffi_fallible]
fn unsafe_get_target_block_in_q(queue_id: u64) -> Result<u64> {
let target_block = unsafe { SERVICES.evm.core.get_target_block_in(queue_id)? };
Ok(target_block.as_u64())
Ok(utils::checked_as_u64(target_block)?)
}

/// Checks if the given address is a smart contract