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: Clean up construct block validation #2526

Merged
merged 29 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d337a60
Fix tx receipt for system txs
sieniven Oct 2, 2023
edda1c2
Fix rust lint
sieniven Oct 2, 2023
5188952
Merge branch 'master' into evm/fix-receipt-gas-used
sieniven Oct 2, 2023
f35fa1a
Housekeeping
sieniven Oct 2, 2023
6ffab92
Add test for td tx receipt for zero gas used
sieniven Oct 2, 2023
3493c95
Set correct timestamp in queue backend
Jouzo Oct 2, 2023
b5166ee
Merge branch 'master' into fix_queue_timestamp
sieniven Oct 3, 2023
ff4f997
Update mutexes
sieniven Oct 3, 2023
6a8b94d
Shift block gas limit check into executor, check in construct block
sieniven Oct 3, 2023
808e000
Fix rust lint
sieniven Oct 3, 2023
2711121
Merge branch master into evm/fix-receipt-gas-used
Jouzo Oct 3, 2023
9536872
Merge branch 'master' into evm/construct-block-validation
sieniven Oct 3, 2023
8ae2c35
Fix naming
sieniven Oct 3, 2023
44515d4
Merge branch 'master' into evm/fix-receipt-gas-used
sieniven Oct 3, 2023
4ddbfd6
Merge branch 'evm/fix-receipt-gas-used' of github.com:DeFiCh/ain into…
sieniven Oct 3, 2023
23f391e
Fix rust lint
sieniven Oct 3, 2023
225e302
Restrict block gas limit check to only signed txs
sieniven Oct 3, 2023
1bee0a4
Better refactor
sieniven Oct 3, 2023
4cfb3e0
Merge branch 'evm/fix-receipt-gas-used' of github.com:DeFiCh/ain into…
sieniven Oct 3, 2023
18b78cb
Merge branch 'evm/fix-receipt-gas-used' of github.com:DeFiCh/ain into…
sieniven Oct 3, 2023
f04a914
Use txtype
sieniven Oct 3, 2023
09fd806
Fix construct block to return vector of failed tx hashes
sieniven Oct 3, 2023
7890272
Fix error msg
sieniven Oct 3, 2023
f499090
Merge branch 'master' into evm/construct-block-validation
prasannavl Oct 4, 2023
9b601b2
Merge branch 'master' into fix_queue_timestamp
prasannavl Oct 4, 2023
037d513
Revert changes in connect block
sieniven Oct 4, 2023
cf08bd9
Merge branch 'fix_queue_timestamp' of github.com:DeFiCh/ain into fix_…
sieniven Oct 4, 2023
ddef5c1
Merge branch 'fix_queue_timestamp' of github.com:DeFiCh/ain into evm/…
sieniven Oct 4, 2023
a83b505
Merge branch 'master' of github.com:DeFiCh/ain into evm/construct-blo…
sieniven Oct 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion lib/ain-evm/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub struct Vicinity {
pub block_number: U256,
pub timestamp: U256,
pub gas_limit: U256,
pub total_gas_used: U256,
pub block_gas_limit: U256,
pub block_base_fee_per_gas: U256,
pub block_randomness: Option<H256>,
}
Expand Down Expand Up @@ -145,6 +147,13 @@ impl EVMBackend {
};
}

pub fn update_vicinity_with_gas_used(&mut self, gas_used: U256) {
self.vicinity = Vicinity {
total_gas_used: gas_used,
..self.vicinity
};
}

// Read-only handle
pub fn ro_handle(&self) -> MptRo {
let root = self.state.root();
Expand Down Expand Up @@ -300,7 +309,7 @@ impl Backend for EVMBackend {
}

fn block_gas_limit(&self) -> U256 {
self.vicinity.gas_limit
self.vicinity.block_gas_limit
}

fn block_base_fee_per_gas(&self) -> U256 {
Expand Down
44 changes: 26 additions & 18 deletions lib/ain-evm/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ use ain_contracts::{
FixedContract,
};
use anyhow::format_err;
use ethereum::EnvelopedEncodable;
use ethereum::{AccessList, Account, Block, Log, PartialHeader, TransactionAction, TransactionV2};
use ethereum::{
AccessList, Account, Block, EnvelopedEncodable, Log, PartialHeader, TransactionAction,
TransactionV2,
};
use ethereum_types::{Bloom, BloomInput, H160, H256, U256};
use log::{debug, trace};
use lru::LruCache;
Expand Down Expand Up @@ -272,6 +274,8 @@ impl EVMCoreService {
block_number,
origin: caller.unwrap_or_default(),
gas_limit: U256::from(gas_limit),
total_gas_used: U256::zero(),
block_gas_limit: U256::from(self.storage.get_attributes_or_default()?.block_gas_limit),
gas_price: if transaction_type == Some(U256::from(2)) {
max_fee_per_gas.unwrap_or_default()
} else {
Expand Down Expand Up @@ -465,19 +469,10 @@ impl EVMCoreService {
.into());
}

// Execute tx
// Execute tx and validate total gas usage in queued txs do not exceed block size
let mut executor = AinExecutor::new(&mut backend);
let (tx_response, ..) =
executor.exec(&signed_tx, signed_tx.gas_limit(), prepay_fee, block_fee)?;

// Validate total gas usage in queued txs exceeds block size
debug!("[validate_raw_tx] used_gas: {:#?}", tx_response.used_gas);
let block_gas_limit = self.storage.get_attributes_or_default()?.block_gas_limit;
if total_current_gas_used + U256::from(tx_response.used_gas)
> U256::from(block_gas_limit)
{
return Err(format_err!("Tx can't make it in block. Block size limit {}, pending block gas used : {:x?}, tx used gas : {:x?}, total : {:x?}", block_gas_limit, total_current_gas_used, U256::from(tx_response.used_gas), total_current_gas_used + U256::from(tx_response.used_gas)).into());
}
executor.update_total_gas_used(total_current_gas_used);
executor.exec(&signed_tx, signed_tx.gas_limit(), prepay_fee, block_fee)?;
}

Ok(self.tx_validation_cache.set(
Expand Down Expand Up @@ -807,12 +802,15 @@ impl EVMCoreService {
/// Result cannot be used safety unless `cs_main` lock is taken on C++ side
/// across all usages. Note: To be replaced with a proper lock flow later.
///
pub unsafe fn create_queue(&self) -> Result<u64> {
pub unsafe fn create_queue(&self, timestamp: u64) -> Result<u64> {
let (target_block, initial_state_root) = match self.storage.get_latest_block()? {
None => (U256::zero(), GENESIS_STATE_ROOT), // Genesis queue
Some(block) => (block.header.number + 1, block.header.state_root),
};
let queue_id = self.tx_queues.create(target_block, initial_state_root);

let queue_id = self
.tx_queues
.create(target_block, initial_state_root, timestamp);
Ok(queue_id)
}

Expand Down Expand Up @@ -997,7 +995,12 @@ impl EVMCoreService {
state_root,
Arc::clone(&self.trie_store),
Arc::clone(&self.storage),
Vicinity::default(),
Vicinity {
block_gas_limit: U256::from(
self.storage.get_attributes_or_default()?.block_gas_limit,
),
..Vicinity::default()
},
)
}

Expand All @@ -1007,7 +1010,12 @@ impl EVMCoreService {
state_root,
Arc::clone(&self.trie_store),
Arc::clone(&self.storage),
Vicinity::default(),
Vicinity {
block_gas_limit: U256::from(
self.storage.get_attributes_or_default()?.block_gas_limit,
),
..Vicinity::default()
},
)
}

Expand Down
64 changes: 59 additions & 5 deletions lib/ain-evm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{
},
trie::GENESIS_STATE_ROOT,
txqueue::{BlockData, QueueTx},
Result,
EVMError, Result,
};

pub struct EVMServices {
Expand All @@ -44,6 +44,7 @@ pub struct EVMServices {

pub struct FinalizedBlockInfo {
pub block_hash: XHash,
pub failed_transaction: Option<XHash>,
pub total_burnt_fees: U256,
pub total_priority_fees: U256,
pub block_number: U256,
Expand Down Expand Up @@ -127,6 +128,7 @@ impl EVMServices {

let queue_txs_len = queue.transactions.len();
let mut all_transactions = Vec::with_capacity(queue_txs_len);
let mut failed_transaction = None;
let mut receipts_v3: Vec<ReceiptAndOptionalContractAddress> =
Vec::with_capacity(queue_txs_len);
let mut total_gas_used = 0u64;
Expand All @@ -147,6 +149,9 @@ impl EVMServices {
beneficiary,
timestamp: U256::from(timestamp),
block_number: U256::zero(),
block_gas_limit: U256::from(
self.storage.get_attributes_or_default()?.block_gas_limit,
),
..Vicinity::default()
},
H256::zero(),
Expand All @@ -157,6 +162,9 @@ impl EVMServices {
beneficiary,
timestamp: U256::from(timestamp),
block_number: number + 1,
block_gas_limit: U256::from(
self.storage.get_attributes_or_default()?.block_gas_limit,
),
..Vicinity::default()
},
hash,
Expand Down Expand Up @@ -291,7 +299,18 @@ impl EVMServices {
);

for queue_item in queue.transactions.clone() {
let apply_result = executor.apply_queue_tx(queue_item.tx, base_fee)?;
executor.update_total_gas_used(U256::from(total_gas_used));
let apply_result = match executor.apply_queue_tx(queue_item.tx, base_fee) {
Ok(result) => result,
Err(EVMError::BlockSizeLimit(message)) => {
failed_transaction = Some(queue_item.tx_hash);
debug!("[construct_block] {}", message);
break;
}
Err(e) => {
return Err(e);
}
};

all_transactions.push(apply_result.tx);
EVMCoreService::logs_bloom(apply_result.logs, &mut logs_bloom);
Expand Down Expand Up @@ -356,6 +375,7 @@ impl EVMServices {

Ok(FinalizedBlockInfo {
block_hash,
failed_transaction,
total_burnt_fees,
total_priority_fees,
block_number: current_block_number,
Expand Down Expand Up @@ -404,14 +424,38 @@ impl EVMServices {
queue_id: u64,
tx: QueueTx,
) -> Result<(SignedTx, U256, H256)> {
let state_root = self.core.tx_queues.get_latest_state_root_in(queue_id)?;
let (target_block, state_root, timestamp, is_first_tx) = {
let queue = self.core.tx_queues.get(queue_id)?;

let state_root = queue.get_latest_state_root();
let data = queue.data.lock();

(
data.target_block,
state_root,
data.timestamp,
data.transactions.is_empty(),
)
};
debug!(
"[update_queue_state_from_tx] state_root : {:#?}",
state_root
);

// Has to be mutable to obtain new state root
let mut backend = self.core.get_backend(state_root)?;
let mut backend = EVMBackend::from_root(
state_root,
Arc::clone(&self.core.trie_store),
Arc::clone(&self.storage),
Vicinity {
timestamp: U256::from(timestamp),
block_number: target_block,
block_gas_limit: U256::from(
self.storage.get_attributes_or_default()?.block_gas_limit,
),
..Vicinity::default()
},
)?;

let mut executor = AinExecutor::new(&mut backend);

let (parent_hash, _) = self
Expand All @@ -420,6 +464,16 @@ impl EVMServices {
.unwrap_or_default(); // Safe since calculate_base_fee will default to INITIAL_BASE_FEE
let base_fee = self.block.calculate_base_fee(parent_hash)?;

// Update instrinsics contract to reproduce construct_block behaviour
if is_first_tx {
let (current_native_height, _) = ain_cpp_imports::get_sync_status().unwrap();
let DeployContractInfo {
address, storage, ..
} = dfi_intrinsics_v1_deploy_info((current_native_height + 1) as u64, target_block)?;
executor.update_storage(address, storage)?;
executor.commit();
}

let apply_tx = executor.apply_queue_tx(tx, base_fee)?;

Ok((
Expand Down
13 changes: 12 additions & 1 deletion lib/ain-evm/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::{
SignedTx,
},
txqueue::QueueTx,
Result,
EVMError, Result,
};

#[derive(Debug)]
Expand Down Expand Up @@ -68,6 +68,10 @@ impl<'backend> AinExecutor<'backend> {
self.backend.update_storage(&address, storage)
}

pub fn update_total_gas_used(&mut self, gas_used: U256) {
self.backend.update_vicinity_with_gas_used(gas_used)
}

pub fn commit(&mut self) -> H256 {
self.backend.commit()
}
Expand Down Expand Up @@ -178,6 +182,13 @@ impl<'backend> AinExecutor<'backend> {
};

let used_gas = executor.used_gas();
let total_gas_used = self.backend.vicinity.total_gas_used;
let block_gas_limit = self.backend.vicinity.block_gas_limit;
if total_gas_used + U256::from(used_gas) > block_gas_limit {
return Err(EVMError::BlockSizeLimit(
"Block size limit exceeded, tx cannot make it into the block".to_string(),
));
}
let (values, logs) = executor.into_state().deconstruct();
let logs = logs.into_iter().collect::<Vec<_>>();

Expand Down
2 changes: 2 additions & 0 deletions lib/ain-evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ pub enum EVMError {
QueueError(#[from] QueueError),
#[error("EVM: Queue invalid nonce error {0:?}")]
QueueInvalidNonce((Box<transaction::SignedTx>, ethereum_types::U256)),
#[error("EVM: Exceed block size limit")]
BlockSizeLimit(String),
#[error("EVM: IO error")]
IoError(#[from] std::io::Error),
#[error("EVM: Hex error")]
Expand Down
33 changes: 28 additions & 5 deletions lib/ain-evm/src/txqueue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl TransactionQueueMap {
/// Result cannot be used safety unless `cs_main` lock is taken on C++ side
/// across all usages. Note: To be replaced with a proper lock flow later.
///
pub unsafe fn create(&self, target_block: U256, state_root: H256) -> u64 {
pub unsafe fn create(&self, target_block: U256, state_root: H256, timestamp: u64) -> u64 {
let mut rng = rand::thread_rng();
loop {
let queue_id = rng.gen();
Expand All @@ -54,7 +54,11 @@ impl TransactionQueueMap {
let mut write_guard = self.queues.write();

if let std::collections::hash_map::Entry::Vacant(e) = write_guard.entry(queue_id) {
e.insert(Arc::new(TransactionQueue::new(target_block, state_root)));
e.insert(Arc::new(TransactionQueue::new(
target_block,
state_root,
timestamp,
)));
return queue_id;
}
}
Expand Down Expand Up @@ -174,6 +178,15 @@ impl TransactionQueueMap {
self.with_transaction_queue(queue_id, TransactionQueue::get_target_block)
}

/// # Safety
///
/// Result cannot be used safety unless `cs_main` lock is taken on C++ side
/// across all usages. Note: To be replaced with a proper lock flow later.
///
pub unsafe fn get_timestamp_in(&self, queue_id: u64) -> Result<u64> {
self.with_transaction_queue(queue_id, TransactionQueue::get_timestamp)
}

/// # Safety
///
/// Result cannot be used safety unless `cs_main` lock is taken on C++ side
Expand Down Expand Up @@ -233,16 +246,18 @@ pub struct TransactionQueueData {
pub total_gas_used: U256,
pub target_block: U256,
pub initial_state_root: H256,
pub timestamp: u64,
}

impl TransactionQueueData {
pub fn new(target_block: U256, state_root: H256) -> Self {
pub fn new(target_block: U256, state_root: H256, timestamp: u64) -> Self {
Self {
transactions: Vec::new(),
total_gas_used: U256::zero(),
block_data: None,
target_block,
initial_state_root: state_root,
timestamp,
}
}
}
Expand All @@ -253,9 +268,13 @@ pub struct TransactionQueue {
}

impl TransactionQueue {
fn new(target_block: U256, state_root: H256) -> Self {
fn new(target_block: U256, state_root: H256, timestamp: u64) -> Self {
Self {
data: Mutex::new(TransactionQueueData::new(target_block, state_root)),
data: Mutex::new(TransactionQueueData::new(
target_block,
state_root,
timestamp,
)),
}
}

Expand Down Expand Up @@ -315,6 +334,10 @@ impl TransactionQueue {
self.data.lock().target_block
}

pub fn get_timestamp(&self) -> u64 {
self.data.lock().timestamp
}

pub fn get_state_root_from_native_hash(&self, hash: XHash) -> Option<H256> {
self.data
.lock()
Expand Down
Loading