Skip to content

Commit

Permalink
Keep track of state_root changes in transaction queue
Browse files Browse the repository at this point in the history
  • Loading branch information
Jouzo committed Sep 5, 2023
1 parent 433267c commit 1277f74
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 53 deletions.
6 changes: 6 additions & 0 deletions lib/ain-evm/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ impl EVMBackend {
.unwrap_or_default()
}

pub fn get_balance(&self, address: &H160) -> U256 {
self.get_account(address)
.map(|acc| acc.balance)
.unwrap_or_default()
}

pub fn get_contract_storage(&self, contract: H160, storage_index: &[u8]) -> Result<U256> {
let Some(account) = self.get_account(&contract) else {
return Ok(U256::zero());
Expand Down
89 changes: 57 additions & 32 deletions lib/ain-evm/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::sync::Arc;
use anyhow::format_err;
use ethereum::{AccessList, Account, Block, Log, PartialHeader, TransactionV2};
use ethereum_types::{Bloom, BloomInput, H160, U256};
use log::debug;
use log::{debug, trace};
use primitive_types::H256;
use vsdb_core::vsdb_set_base_dir;

Expand Down Expand Up @@ -51,6 +51,7 @@ pub struct ValidateTxInfo {
pub signed_tx: SignedTx,
pub prepay_fee: U256,
pub used_gas: u64,
pub state_root: H256,
}

fn init_vsdb(path: PathBuf) {
Expand Down Expand Up @@ -220,17 +221,28 @@ impl EVMCoreService {
signed_tx.transaction
);

let block_number = self
.storage
.get_latest_block()?
.map(|block| block.header.number)
.unwrap_or_default();
debug!("[validate_raw_tx] block_number : {:#?}", block_number);
let state_root = if queue_id != 0 {
match self.tx_queues.get_latest_state_root_in(queue_id)? {
Some(state_root) => state_root,
None => self
.storage
.get_latest_block()?
.map(|block| block.header.state_root)
.unwrap_or_default(),
}
} else {
self.storage
.get_latest_block()?
.map(|block| block.header.state_root)
.unwrap_or_default()
};
debug!("[validate_raw_tx] state_root : {:#?}", state_root);

// Has to be mutable to obtain new state root
let mut backend = self.get_backend(state_root)?;

let signed_tx: SignedTx = tx.try_into()?;
let nonce = self
.get_nonce(signed_tx.sender, block_number)
.map_err(|e| format_err!("Error getting nonce {e}"))?;
let nonce = backend.get_nonce(&signed_tx.sender);
debug!(
"[validate_raw_tx] signed_tx.sender : {:#?}",
signed_tx.sender
Expand Down Expand Up @@ -264,9 +276,7 @@ impl EVMCoreService {
return Err(format_err!("value more than money range").into());
}

let balance = self
.get_balance(signed_tx.sender, block_number)
.map_err(|e| format_err!("Error getting balance {e}"))?;
let balance = backend.get_balance(&signed_tx.sender);
let prepay_fee = calculate_prepay_gas_fee(&signed_tx)?;
debug!("[validate_raw_tx] Account balance : {:x?}", balance);
debug!("[validate_raw_tx] prepay_fee : {:x?}", prepay_fee);
Expand All @@ -289,22 +299,25 @@ impl EVMCoreService {
}

let use_queue = queue_id != 0;
let used_gas = if use_queue {
let TxResponse { used_gas, .. } = self.call(EthCallArgs {
caller: Some(signed_tx.sender),
to: signed_tx.to(),
value: signed_tx.value(),
data: signed_tx.data(),
gas_limit: signed_tx.gas_limit().as_u64(),
access_list: signed_tx.access_list(),
block_number,
gas_price: Some(tx_gas_price),
max_fee_per_gas: signed_tx.max_fee_per_gas(),
transaction_type: Some(signed_tx.get_tx_type()),
})?;
used_gas
let (used_gas, state_root) = if use_queue {
let mut executor = AinExecutor::new(&mut backend);

let (
TxResponse {
exit_reason,
used_gas,
..
},
receipt,
) = executor.exec(&signed_tx, prepay_fee);

let state_root = backend.root();
debug!("exit_reason : {:#?}", exit_reason);

debug!("[validate_raw_tx] new state_root : {:#x}", state_root);
(used_gas, state_root)
} else {
u64::default()
(u64::default(), H256::default())
};

// Validate total gas usage in queued txs exceeds block size
Expand All @@ -325,6 +338,7 @@ impl EVMCoreService {
signed_tx,
prepay_fee,
used_gas,
state_root,
})
}

Expand Down Expand Up @@ -357,7 +371,7 @@ impl EVMCoreService {
direction: TransferDirection::EvmIn,
}));
self.tx_queues
.push_in(queue_id, queue_tx, hash, U256::zero())?;
.push_in(queue_id, queue_tx, hash, U256::zero(), H256::default())?;
Ok(())
}

Expand Down Expand Up @@ -391,7 +405,7 @@ impl EVMCoreService {
direction: TransferDirection::EvmOut,
}));
self.tx_queues
.push_in(queue_id, queue_tx, hash, U256::zero())?;
.push_in(queue_id, queue_tx, hash, U256::zero(), H256::default())?;
Ok(())
}
}
Expand Down Expand Up @@ -584,9 +598,10 @@ impl EVMCoreService {
.map(|block| (block.header.state_root, block.header.number))
.unwrap_or_default();

debug!(
trace!(
"[get_latest_block_backend] At block number : {:#x}, state_root : {:#x}",
block_number, state_root
block_number,
state_root
);
EVMBackend::from_root(
state_root,
Expand All @@ -595,4 +610,14 @@ impl EVMCoreService {
Vicinity::default(),
)
}

pub fn get_backend(&self, state_root: H256) -> Result<EVMBackend> {
trace!("[get_backend] state_root : {:#x}", state_root);
EVMBackend::from_root(
state_root,
Arc::clone(&self.trie_store),
Arc::clone(&self.storage),
Vicinity::default(),
)
}
}
4 changes: 3 additions & 1 deletion lib/ain-evm/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,10 +559,11 @@ impl EVMServices {
tx: QueueTx,
hash: XHash,
gas_used: U256,
state_root: H256,
) -> Result<()> {
self.core
.tx_queues
.push_in(queue_id, tx.clone(), hash, gas_used)?;
.push_in(queue_id, tx.clone(), hash, gas_used, state_root)?;

if let QueueTx::SignedTx(signed_tx) = tx {
self.filters.add_tx_to_filters(signed_tx.transaction.hash());
Expand Down Expand Up @@ -702,6 +703,7 @@ fn get_dst20_migration_txs(mnview_ptr: usize) -> Result<Vec<QueueTxItem>> {
tx,
tx_hash: Default::default(),
gas_used: U256::zero(),
state_root: H256::default(),
});
}
Ok(txs)
Expand Down
46 changes: 43 additions & 3 deletions lib/ain-evm/src/txqueue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::{

use ethereum::{Block, TransactionV2};
use ethereum_types::{H160, U256};
use primitive_types::H256;
use rand::Rng;

use crate::core::XHash;
Expand Down Expand Up @@ -119,9 +120,12 @@ impl TransactionQueueMap {
tx: QueueTx,
hash: XHash,
gas_used: U256,
state_root: H256,
) -> Result<()> {
self.with_transaction_queue(queue_id, |queue| queue.queue_tx(tx, hash, gas_used))
.and_then(|res| res)
self.with_transaction_queue(queue_id, |queue| {
queue.queue_tx(tx, hash, gas_used, state_root)
})
.and_then(|res| res)
}

/// Removes all transactions in the queue whose sender matches the provided sender address.
Expand Down Expand Up @@ -190,6 +194,15 @@ impl TransactionQueueMap {
self.with_transaction_queue(queue_id, |queue| queue.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_latest_state_root_in(&self, queue_id: u64) -> Result<Option<H256>> {
self.with_transaction_queue(queue_id, |queue| queue.get_latest_state_root())
}

/// Apply the closure to the queue associated with the queue ID.
/// # Errors
///
Expand All @@ -216,6 +229,7 @@ pub struct QueueTxItem {
pub tx: QueueTx,
pub tx_hash: XHash,
pub gas_used: U256,
pub state_root: H256,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -265,7 +279,13 @@ impl TransactionQueue {
}
}

pub fn queue_tx(&self, tx: QueueTx, tx_hash: XHash, gas_used: U256) -> Result<()> {
pub fn queue_tx(
&self,
tx: QueueTx,
tx_hash: XHash,
gas_used: U256,
state_root: H256,
) -> Result<()> {
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 @@ -281,6 +301,7 @@ impl TransactionQueue {
tx,
tx_hash,
gas_used,
state_root,
});
Ok(())
}
Expand Down Expand Up @@ -325,6 +346,25 @@ impl TransactionQueue {
self.data.lock().unwrap().target_block
}

pub fn get_state_root_from_native_hash(&self, hash: XHash) -> Option<H256> {
self.data
.lock()
.unwrap()
.transactions
.iter()
.find(|tx_item| tx_item.tx_hash == hash)
.map(|tx_item| tx_item.state_root)
}

pub fn get_latest_state_root(&self) -> Option<H256> {
self.data
.lock()
.unwrap()
.transactions
.last()
.map(|tx_item| tx_item.state_root)
}

pub fn is_queued(&self, tx: QueueTx) -> bool {
self.data
.lock()
Expand Down
Loading

0 comments on commit 1277f74

Please sign in to comment.