diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 28cefd311d..439d10f05d 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -181,11 +181,16 @@ impl EVMCoreService { /// # Returns /// /// Returns the signed tx, tx prepay gas fees and the gas used to call the tx. - pub fn validate_raw_tx( + /// + /// # 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 validate_raw_tx( &self, tx: &str, queue_id: u64, - use_context: bool, ) -> Result> { debug!("[validate_raw_tx] raw transaction : {:#?}", tx); let signed_tx = SignedTx::try_from(tx) @@ -256,7 +261,8 @@ impl EVMCoreService { return Err(format_err!("gas limit higher than MAX_GAS_PER_BLOCK").into()); } - let used_gas = if use_context { + 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(), @@ -272,11 +278,11 @@ impl EVMCoreService { }; // Validate total gas usage in queued txs exceeds block size - if use_context { + if use_queue { debug!("[validate_raw_tx] used_gas: {:#?}", used_gas); let total_current_gas_used = self .tx_queues - .get_total_gas_used(queue_id) + .get_total_gas_used_in(queue_id) .unwrap_or_default(); if total_current_gas_used + U256::from(used_gas) > MAX_GAS_PER_BLOCK { @@ -303,7 +309,13 @@ impl EVMCoreService { // Transaction queue methods impl EVMCoreService { - pub fn add_balance( + /// + /// # 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 add_balance( &self, queue_id: u64, address: H160, @@ -312,11 +324,17 @@ impl EVMCoreService { ) -> Result<(), EVMError> { let queue_tx = QueueTx::SystemTx(SystemTx::EvmIn(BalanceUpdate { address, amount })); self.tx_queues - .queue_tx(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; + .push_in(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; Ok(()) } - pub fn sub_balance( + /// + /// # 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 sub_balance( &self, queue_id: u64, address: H160, @@ -338,21 +356,43 @@ impl EVMCoreService { } else { let queue_tx = QueueTx::SystemTx(SystemTx::EvmOut(BalanceUpdate { address, amount })); self.tx_queues - .queue_tx(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; + .push_in(queue_id, queue_tx, hash, U256::zero(), U256::zero())?; Ok(()) } } - pub fn get_queue_id(&self) -> u64 { - self.tx_queues.get_queue_id() + /// + /// # 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 create_queue(&self) -> u64 { + self.tx_queues.create() } - pub fn remove(&self, queue_id: u64) { + /// + /// # 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 remove_queue(&self, queue_id: u64) { self.tx_queues.remove(queue_id); } - pub fn remove_txs_by_sender(&self, queue_id: u64, address: H160) -> Result<(), EVMError> { - self.tx_queues.remove_txs_by_sender(queue_id, address)?; + /// + /// # 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 remove_txs_by_sender_in( + &self, + queue_id: u64, + address: H160, + ) -> Result<(), EVMError> { + self.tx_queues.remove_by_sender_in(queue_id, address)?; Ok(()) } @@ -375,14 +415,20 @@ impl EVMCoreService { /// # Returns /// /// Returns the next valid nonce as a `U256`. Defaults to U256::zero() - pub fn get_next_valid_nonce_in_queue( + /// + /// # 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_next_valid_nonce_in_queue( &self, queue_id: u64, address: H160, ) -> Result { let nonce = self .tx_queues - .get_next_valid_nonce(queue_id, address)? + .get_next_valid_nonce_in(queue_id, address)? .unwrap_or_else(|| { let latest_block = self .storage diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 521c1bb278..7bbbd7a46e 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -99,7 +99,13 @@ impl EVMServices { } } - pub fn construct_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 construct_block_in_queue( &self, queue_id: u64, difficulty: u32, @@ -107,12 +113,12 @@ impl EVMServices { timestamp: u64, dvm_block_number: u64, ) -> Result> { - let tx_queue = self.core.tx_queues.get_queue(queue_id)?; + let tx_queue = self.core.tx_queues.get(queue_id)?; let mut queue = tx_queue.data.lock().unwrap(); - let queue_len = queue.transactions.len(); - let mut all_transactions = Vec::with_capacity(queue_len); - let mut failed_transactions = Vec::with_capacity(queue_len); - let mut receipts_v3: Vec = Vec::with_capacity(queue_len); + let queue_txs_len = queue.transactions.len(); + let mut all_transactions = Vec::with_capacity(queue_txs_len); + let mut failed_transactions = Vec::with_capacity(queue_txs_len); + let mut receipts_v3: Vec = Vec::with_capacity(queue_txs_len); let mut total_gas_used = 0u64; let mut total_gas_fees = U256::zero(); let mut logs_bloom: Bloom = Bloom::default(); @@ -340,9 +346,15 @@ impl EVMServices { }) } - pub fn finalize_block(&self, queue_id: u64) -> Result<(), Box> { + /// + /// # 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 commit_queue(&self, queue_id: u64) -> Result<(), Box> { { - let tx_queue = self.core.tx_queues.get_queue(queue_id)?; + let tx_queue = self.core.tx_queues.get(queue_id)?; let queue = tx_queue.data.lock().unwrap(); let Some(BlockData { block, receipts }) = queue.block_data.clone() else { return Err(format_err!("no constructed EVM block exist in queue id").into()); @@ -383,7 +395,13 @@ impl EVMServices { Ok(()) } - pub fn queue_tx( + /// + /// # 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 push_tx_in_queue( &self, queue_id: u64, tx: QueueTx, @@ -399,7 +417,7 @@ impl EVMServices { self.core .tx_queues - .queue_tx(queue_id, tx.clone(), hash, gas_used, base_fee)?; + .push_in(queue_id, tx.clone(), hash, gas_used, base_fee)?; if let QueueTx::SignedTx(signed_tx) = tx { self.filters.add_tx_to_filters(signed_tx.transaction.hash()); diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index ae54083272..37881813cf 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -37,7 +37,13 @@ impl TransactionQueueMap { /// `get_queue_id` generates a unique random ID, creates a new `TransactionQueue` for that ID, /// and then returns the ID. - pub fn get_queue_id(&self) -> u64 { + /// + /// # 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 create(&self) -> u64 { let mut rng = rand::thread_rng(); loop { let queue_id = rng.gen(); @@ -56,7 +62,13 @@ impl TransactionQueueMap { /// Try to remove and return the `TransactionQueue` associated with the provided /// queue ID. - pub fn remove(&self, queue_id: u64) -> Option> { + /// + /// # 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 remove(&self, queue_id: u64) -> Option> { self.queues.write().unwrap().remove(&queue_id) } @@ -69,7 +81,12 @@ impl TransactionQueueMap { /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. /// - pub fn get_queue(&self, queue_id: u64) -> Result> { + /// # 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(&self, queue_id: u64) -> Result> { Ok(Arc::clone( self.queues .read() @@ -93,7 +110,12 @@ impl TransactionQueueMap { /// previous nonce of transactions from the same sender in the queue. /// Returns `QueueError::InvalidFee` if the fee calculation overflows. /// - pub fn queue_tx( + /// # 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 push_in( &self, queue_id: u64, tx: QueueTx, @@ -112,12 +134,23 @@ impl TransactionQueueMap { /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. /// - pub fn remove_txs_by_sender(&self, queue_id: u64, sender: H160) -> Result<()> { + /// # 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 remove_by_sender_in(&self, queue_id: u64, sender: H160) -> Result<()> { self.with_transaction_queue(queue_id, |queue| queue.remove_txs_by_sender(sender)) } - pub fn get_tx_queue_items(&self, queue_id: u64) -> Result> { - self.with_transaction_queue(queue_id, TransactionQueue::get_tx_queue_items) + /// + /// # 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_txs_cloned_in(&self, queue_id: u64) -> Result> { + self.with_transaction_queue(queue_id, TransactionQueue::get_queue_txs_cloned) } /// `get_next_valid_nonce` returns the next valid nonce for the account with the provided address @@ -131,11 +164,25 @@ impl TransactionQueueMap { /// Returns None when the address does not have any transaction queued or /// Some(nonce) with the next valid nonce (current + 1) for the associated address /// - pub fn get_next_valid_nonce(&self, queue_id: u64, address: H160) -> Result> { + /// # 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_next_valid_nonce_in( + &self, + queue_id: u64, + address: H160, + ) -> Result> { self.with_transaction_queue(queue_id, |queue| queue.get_next_valid_nonce(address)) } - pub fn get_total_gas_used(&self, queue_id: u64) -> Result { + /// # 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_total_gas_used_in(&self, queue_id: u64) -> Result { self.with_transaction_queue(queue_id, |queue| queue.get_total_gas_used()) } @@ -143,7 +190,7 @@ impl TransactionQueueMap { /// # Errors /// /// Returns `QueueError::NoSuchQueue` if no queue is associated with the given queue ID. - pub fn with_transaction_queue(&self, queue_id: u64, f: F) -> Result + unsafe fn with_transaction_queue(&self, queue_id: u64, f: F) -> Result where F: FnOnce(&TransactionQueue) -> T, { @@ -271,7 +318,7 @@ impl TransactionQueue { data.account_nonces.remove(&sender); } - pub fn get_tx_queue_items(&self) -> Vec { + pub fn get_queue_txs_cloned(&self) -> Vec { self.data.lock().unwrap().transactions.clone() } diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 59cb207c92..b4e74deec8 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -78,7 +78,7 @@ pub fn evm_try_create_and_sign_tx( /// # Returns /// /// Returns the balance of the account as a `u64` on success. -pub fn evm_get_balance(address: [u8; 20]) -> u64 { +pub fn evm_try_get_balance(result: &mut ffi::CrossBoundaryResult, address: [u8; 20]) -> u64 { let account = H160::from(address); let (_, latest_block_number) = SERVICES .evm @@ -91,7 +91,8 @@ pub fn evm_get_balance(address: [u8; 20]) -> u64 { .core .get_balance(account, latest_block_number) .unwrap_or_default(), - ); // convert to try_evm_get_balance - Default to 0 for now + ); // convert to evm_try_get_balance - Default to 0 for now + cross_boundary_success(result); balance.to_satoshi().as_u64() } @@ -105,19 +106,21 @@ pub fn evm_get_balance(address: [u8; 20]) -> u64 { /// # Returns /// /// Returns the next valid nonce of the account in a specific queue_id as a `u64` -pub fn evm_try_get_next_valid_nonce_in_queue( +pub fn evm_unsafe_try_get_next_valid_nonce_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: [u8; 20], ) -> u64 { let address = H160::from(address); - match SERVICES - .evm - .core - .get_next_valid_nonce_in_queue(queue_id, address) - { - Ok(nonce) => cross_boundary_success_return(result, nonce.as_u64()), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match SERVICES + .evm + .core + .get_next_valid_nonce_in_queue(queue_id, address) + { + Ok(nonce) => cross_boundary_success_return(result, nonce.as_u64()), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -128,15 +131,17 @@ pub fn evm_try_get_next_valid_nonce_in_queue( /// * `queue_id` - The queue ID. /// * `address` - The EVM address of the account. /// -pub fn evm_try_remove_txs_by_sender( +pub fn evm_unsafe_try_remove_txs_by_sender_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: [u8; 20], ) { let address = H160::from(address); - match SERVICES.evm.core.remove_txs_by_sender(queue_id, address) { - Ok(_) => cross_boundary_success_return(result, ()), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match SERVICES.evm.core.remove_txs_by_sender_in(queue_id, address) { + Ok(_) => cross_boundary_success_return(result, ()), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -149,7 +154,7 @@ pub fn evm_try_remove_txs_by_sender( /// * `amount` - The amount to add as a byte array. /// * `hash` - The hash value as a byte array. /// -pub fn evm_try_add_balance( +pub fn evm_unsafe_try_add_balance_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: &str, @@ -160,13 +165,15 @@ pub fn evm_try_add_balance( return cross_boundary_error_return(result, "Invalid address"); }; - match SERVICES - .evm - .core - .add_balance(queue_id, address, amount.into(), hash) - { - Ok(_) => cross_boundary_success_return(result, ()), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match SERVICES + .evm + .core + .add_balance(queue_id, address, amount.into(), hash) + { + Ok(_) => cross_boundary_success_return(result, ()), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -189,7 +196,7 @@ pub fn evm_try_add_balance( /// # Returns /// /// Returns `true` if the balance subtraction is successful, `false` otherwise. -pub fn evm_try_sub_balance( +pub fn evm_unsafe_try_sub_balance_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: &str, @@ -200,13 +207,15 @@ pub fn evm_try_sub_balance( return cross_boundary_error_return(result, "Invalid address"); }; - match SERVICES - .evm - .core - .sub_balance(queue_id, address, amount.into(), hash) - { - Ok(_) => cross_boundary_success_return(result, true), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match SERVICES + .evm + .core + .sub_balance(queue_id, address, amount.into(), hash) + { + Ok(_) => cross_boundary_success_return(result, true), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -232,27 +241,29 @@ pub fn evm_try_sub_balance( /// /// Returns the transaction nonce, sender address and transaction fees if valid. /// Logs and set the error reason to result object otherwise. -pub fn evm_try_prevalidate_raw_tx( +pub fn evm_unsafe_try_prevalidate_raw_tx( result: &mut ffi::CrossBoundaryResult, tx: &str, ) -> ffi::PreValidateTxCompletion { let queue_id = 0; - match SERVICES.evm.core.validate_raw_tx(tx, queue_id, false) { - Ok(ValidateTxInfo { - signed_tx, - prepay_fee, - used_gas: _, - }) => cross_boundary_success_return( - result, - ffi::PreValidateTxCompletion { - nonce: signed_tx.nonce().as_u64(), - sender: signed_tx.sender.to_fixed_bytes(), - prepay_fee: prepay_fee.try_into().unwrap_or_default(), - }, - ), - Err(e) => { - debug!("evm_try_prevalidate_raw_tx failed with error: {e}"); - cross_boundary_error_return(result, e.to_string()) + unsafe { + match SERVICES.evm.core.validate_raw_tx(tx, queue_id) { + Ok(ValidateTxInfo { + signed_tx, + prepay_fee, + used_gas: _, + }) => cross_boundary_success_return( + result, + ffi::PreValidateTxCompletion { + nonce: signed_tx.nonce().as_u64(), + sender: signed_tx.sender.to_fixed_bytes(), + prepay_fee: prepay_fee.try_into().unwrap_or_default(), + }, + ), + Err(e) => { + debug!("evm_try_prevalidate_raw_tx failed with error: {e}"); + cross_boundary_error_return(result, e.to_string()) + } } } } @@ -281,7 +292,7 @@ pub fn evm_try_prevalidate_raw_tx( /// /// Returns the transaction nonce, sender address, transaction fees and gas used /// if valid. Logs and set the error reason to result object otherwise. -pub fn evm_try_validate_raw_tx( +pub fn evm_unsafe_try_validate_raw_tx_in_q( result: &mut ffi::CrossBoundaryResult, tx: &str, queue_id: u64, @@ -293,24 +304,25 @@ pub fn evm_try_validate_raw_tx( return cross_boundary_error_return(result, e.to_string()); } } - - match SERVICES.evm.core.validate_raw_tx(tx, queue_id, true) { - Ok(ValidateTxInfo { - signed_tx, - prepay_fee, - used_gas, - }) => cross_boundary_success_return( - result, - ffi::ValidateTxCompletion { - nonce: signed_tx.nonce().as_u64(), - sender: signed_tx.sender.to_fixed_bytes(), - prepay_fee: prepay_fee.try_into().unwrap_or_default(), - gas_used: used_gas, - }, - ), - Err(e) => { - debug!("evm_try_validate_raw_tx failed with error: {e}"); - cross_boundary_error_return(result, e.to_string()) + unsafe { + match SERVICES.evm.core.validate_raw_tx(tx, queue_id) { + Ok(ValidateTxInfo { + signed_tx, + prepay_fee, + used_gas, + }) => cross_boundary_success_return( + result, + ffi::ValidateTxCompletion { + nonce: signed_tx.nonce().as_u64(), + sender: signed_tx.sender.to_fixed_bytes(), + prepay_fee: prepay_fee.try_into().unwrap_or_default(), + gas_used: used_gas, + }, + ), + Err(e) => { + debug!("evm_try_validate_raw_tx failed with error: {e}"); + cross_boundary_error_return(result, e.to_string()) + } } } } @@ -320,8 +332,11 @@ pub fn evm_try_validate_raw_tx( /// # Returns /// /// Returns the EVM queue ID as a `u64`. -pub fn evm_get_queue_id() -> u64 { - SERVICES.evm.core.get_queue_id() +pub fn evm_unsafe_try_create_queue(result: &mut ffi::CrossBoundaryResult) -> u64 { + let q; + unsafe { q = SERVICES.evm.core.create_queue() } + cross_boundary_success(result); + q } /// /// Discards an EVM queue. @@ -330,8 +345,9 @@ pub fn evm_get_queue_id() -> u64 { /// /// * `queue_id` - The queue ID. /// -pub fn evm_discard_context(queue_id: u64) { - SERVICES.evm.core.remove(queue_id) +pub fn evm_unsafe_try_remove_queue(result: &mut ffi::CrossBoundaryResult, queue_id: u64) { + unsafe { SERVICES.evm.core.remove_queue(queue_id) } + cross_boundary_success(result); } /// Add an EVM transaction to a specific queue. @@ -348,7 +364,7 @@ pub fn evm_discard_context(queue_id: u64) { /// - The `raw_tx` is in invalid format /// - The queue does not exists. /// -pub fn evm_try_queue_tx( +pub fn evm_unsafe_try_push_tx_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, raw_tx: &str, @@ -356,17 +372,21 @@ pub fn evm_try_queue_tx( gas_used: u64, ) { let signed_tx: Result = raw_tx.try_into(); - match signed_tx { - Ok(signed_tx) => { - match SERVICES - .evm - .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()), + unsafe { + match signed_tx { + Ok(signed_tx) => { + match SERVICES.evm.push_tx_in_queue( + 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()), + } } + Err(e) => cross_boundary_error_return(result, e.to_string()), } - Err(e) => cross_boundary_error_return(result, e.to_string()), } } @@ -382,7 +402,7 @@ pub fn evm_try_queue_tx( /// # Returns /// /// Returns a `FinalizeBlockResult` containing the block hash, failed transactions, burnt fees and priority fees (in satoshis) on success. -pub fn evm_try_construct_block( +pub fn evm_unsafe_try_construct_block_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, difficulty: u32, @@ -391,40 +411,45 @@ pub fn evm_try_construct_block( dvm_block_number: u64, ) -> ffi::FinalizeBlockCompletion { let eth_address = H160::from(miner_address); - match SERVICES.evm.construct_block( - queue_id, - difficulty, - eth_address, - timestamp, - dvm_block_number, - ) { - Ok(FinalizedBlockInfo { - block_hash, - failed_transactions, - total_burnt_fees, - total_priority_fees, - }) => { - cross_boundary_success(result); - ffi::FinalizeBlockCompletion { + unsafe { + match SERVICES.evm.construct_block_in_queue( + queue_id, + difficulty, + eth_address, + timestamp, + dvm_block_number, + ) { + Ok(FinalizedBlockInfo { block_hash, failed_transactions, - total_burnt_fees: WeiAmount(total_burnt_fees).to_satoshi().as_u64(), - total_priority_fees: WeiAmount(total_priority_fees).to_satoshi().as_u64(), + total_burnt_fees, + total_priority_fees, + }) => { + cross_boundary_success(result); + ffi::FinalizeBlockCompletion { + block_hash, + failed_transactions, + total_burnt_fees: WeiAmount(total_burnt_fees).to_satoshi().as_u64(), + total_priority_fees: WeiAmount(total_priority_fees).to_satoshi().as_u64(), + } } + Err(e) => cross_boundary_error_return(result, e.to_string()), } - Err(e) => cross_boundary_error_return(result, e.to_string()), } } -pub fn evm_try_finalize_block(result: &mut ffi::CrossBoundaryResult, queue_id: u64) { - match SERVICES.evm.finalize_block(queue_id) { - Ok(_) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), +pub fn evm_unsafe_try_commit_queue(result: &mut ffi::CrossBoundaryResult, queue_id: u64) { + unsafe { + match SERVICES.evm.commit_queue(queue_id) { + Ok(_) => cross_boundary_success(result), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } -pub fn evm_disconnect_latest_block() { +pub fn evm_disconnect_latest_block(result: &mut ffi::CrossBoundaryResult) { SERVICES.evm.storage.disconnect_latest_block(); + cross_boundary_success(result); } /// Return the block for a given height. @@ -496,12 +521,14 @@ pub fn evm_try_create_dst20( address, })); - match SERVICES - .evm - .queue_tx(queue_id, system_tx, native_hash, U256::zero()) - { - Ok(_) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match SERVICES + .evm + .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) + { + Ok(_) => cross_boundary_success(result), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } @@ -527,11 +554,13 @@ pub fn evm_try_bridge_dst20( out, })); - match SERVICES - .evm - .queue_tx(queue_id, system_tx, native_hash, U256::zero()) - { - Ok(_) => cross_boundary_success(result), - Err(e) => cross_boundary_error_return(result, e.to_string()), + unsafe { + match SERVICES + .evm + .push_tx_in_queue(queue_id, system_tx, native_hash, U256::zero()) + { + Ok(_) => cross_boundary_success(result), + Err(e) => cross_boundary_error_return(result, e.to_string()), + } } } diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 01164cf645..07cab96882 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -68,55 +68,55 @@ pub mod ffi { // // If they are fallible, it's a TODO to changed and move later // so errors are propogated up properly. - fn evm_get_balance(address: [u8; 20]) -> u64; - fn evm_get_queue_id() -> u64; - fn evm_discard_context(queue_id: u64); - fn evm_disconnect_latest_block(); + fn evm_try_get_balance(result: &mut CrossBoundaryResult, address: [u8; 20]) -> u64; + fn evm_unsafe_try_create_queue(result: &mut CrossBoundaryResult) -> u64; + fn evm_unsafe_try_remove_queue(result: &mut CrossBoundaryResult, queue_id: u64); + fn evm_disconnect_latest_block(result: &mut CrossBoundaryResult); // Failible functions // Has to take CrossBoundaryResult as first param // Has to start with try_ / evm_try - fn evm_try_get_next_valid_nonce_in_queue( + fn evm_unsafe_try_get_next_valid_nonce_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: [u8; 20], ) -> u64; - fn evm_try_remove_txs_by_sender( + fn evm_unsafe_try_remove_txs_by_sender_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: [u8; 20], ); - fn evm_try_add_balance( + fn evm_unsafe_try_add_balance_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: &str, amount: [u8; 32], native_tx_hash: [u8; 32], ); - fn evm_try_sub_balance( + fn evm_unsafe_try_sub_balance_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: &str, amount: [u8; 32], native_tx_hash: [u8; 32], ) -> bool; - fn evm_try_prevalidate_raw_tx( + fn evm_unsafe_try_prevalidate_raw_tx( result: &mut CrossBoundaryResult, tx: &str, ) -> PreValidateTxCompletion; - fn evm_try_validate_raw_tx( + fn evm_unsafe_try_validate_raw_tx_in_q( result: &mut CrossBoundaryResult, tx: &str, queue_id: u64, ) -> ValidateTxCompletion; - fn evm_try_queue_tx( + fn evm_unsafe_try_push_tx_in_q( result: &mut CrossBoundaryResult, queue_id: u64, raw_tx: &str, hash: [u8; 32], gas_used: u64, ); - fn evm_try_construct_block( + fn evm_unsafe_try_construct_block_in_q( result: &mut CrossBoundaryResult, queue_id: u64, difficulty: u32, @@ -124,7 +124,7 @@ pub mod ffi { timestamp: u64, dvm_block_number: u64, ) -> FinalizeBlockCompletion; - fn evm_try_finalize_block(result: &mut CrossBoundaryResult, queue_id: u64); + fn evm_unsafe_try_commit_queue(result: &mut CrossBoundaryResult, queue_id: u64); fn evm_try_create_and_sign_tx( result: &mut CrossBoundaryResult, ctx: CreateTransactionContext, diff --git a/src/ffi/ffihelpers.h b/src/ffi/ffihelpers.h index 10edb2848e..7d1240aa7a 100644 --- a/src/ffi/ffihelpers.h +++ b/src/ffi/ffihelpers.h @@ -1,6 +1,7 @@ #ifndef DEFI_FFI_FFIHELPERS_H #define DEFI_FFI_FFIHELPERS_H +#include #include #define CrossBoundaryCheckedThrow(x) { \ @@ -21,5 +22,24 @@ return true; \ }(); +#define CrossBoundaryResVal(x) [&]() { \ + CrossBoundaryResult result; \ + auto res = x; \ + if (!result.ok) { \ + return ResVal(Res::Err("%s\n", result.reason.c_str())); \ + } \ + return ResVal(std::move(res), Res::Ok()); \ +}(); + +#define CrossBoundaryResValChecked(x) [&]() { \ + CrossBoundaryResult result; \ + auto res = x; \ + if (!result.ok) { \ + LogPrintf("%s\n", result.reason.c_str()); \ + return ResVal(Res::Err("%s\n", result.reason.c_str())); \ + } \ + return ResVal(std::move(res), Res::Ok()); \ +}(); + #endif // DEFI_FFI_FFIHELPERS_H diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 2561afeca0..6a6714e8dc 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -3905,7 +3906,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; if (tokenId == DCT_ID{0}) { CrossBoundaryResult result; - if (!evm_try_sub_balance(result, evmQueueId, HexStr(fromAddress.begin(), fromAddress.end()), + if (!evm_unsafe_try_sub_balance_in_q(result, evmQueueId, HexStr(fromAddress.begin(), fromAddress.end()), ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray())) { return DeFiErrors::TransferDomainNotEnoughBalance(EncodeDestination(dest)); } @@ -3940,7 +3941,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; CrossBoundaryResult result; if (tokenId == DCT_ID{0}) { - evm_try_add_balance(result, evmQueueId, HexStr(toAddress.begin(), toAddress.end()), + evm_unsafe_try_add_balance_in_q(result, evmQueueId, HexStr(toAddress.begin(), toAddress.end()), ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray()); if (!result.ok) { return Res::Err("Error bridging DFI: %s", result.reason); @@ -3975,21 +3976,21 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { CrossBoundaryResult result; if (!prevalidateEvm) { - const auto validateResults = evm_try_validate_raw_tx(result, HexStr(obj.evmTx), evmQueueId); + const auto validateResults = evm_unsafe_try_validate_raw_tx_in_q(result, HexStr(obj.evmTx), evmQueueId); // Completely remove this fork guard on mainnet upgrade to restore nonce check from EVM activation if (!result.ok) { LogPrintf("[evm_try_validate_raw_tx] failed, reason : %s\n", result.reason); return Res::Err("evm tx failed to validate %s", result.reason); } - evm_try_queue_tx(result, evmQueueId, HexStr(obj.evmTx), tx.GetHash().GetByteArray(), validateResults.gas_used); + evm_unsafe_try_push_tx_in_q(result, evmQueueId, HexStr(obj.evmTx), tx.GetHash().GetByteArray(), validateResults.gas_used); if (!result.ok) { - LogPrintf("[evm_try_queue_tx] failed, reason : %s\n", result.reason); + LogPrintf("[evm_try_push_tx_in_q] failed, reason : %s\n", result.reason); return Res::Err("evm tx failed to queue %s\n", result.reason); } } else { - evm_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); + evm_unsafe_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); if (!result.ok) { LogPrintf("[evm_try_prevalidate_raw_tx] failed, reason : %s\n", result.reason); return Res::Err("evm tx failed to validate %s", result.reason); @@ -4250,15 +4251,16 @@ Res CustomTxVisit(CCustomCSView &mnview, return Res::ErrCode(CustomTxErrCodes::Fatal, "Disabled custom transaction"); } - auto context = evmQueueId; + auto q = evmQueueId; bool prevalidateEvm = false; - if (context == 0) { + if (q == 0) { prevalidateEvm = true; - context = evm_get_queue_id(); + auto r = CrossBoundaryResVal(evm_unsafe_try_create_queue(result)); + if (r) { q = *r; } else { return r; } } try { - return std::visit(CCustomTxApplyVisitor(tx, height, coins, mnview, consensus, time, txn, context, prevalidateEvm), txMessage); + return std::visit(CCustomTxApplyVisitor(tx, height, coins, mnview, consensus, time, txn, q, prevalidateEvm), txMessage); } catch (const std::bad_variant_access &e) { return Res::Err(e.what()); } catch (...) { diff --git a/src/masternodes/rpc_accounts.cpp b/src/masternodes/rpc_accounts.cpp index b51efeb4f3..b3e1be827c 100644 --- a/src/masternodes/rpc_accounts.cpp +++ b/src/masternodes/rpc_accounts.cpp @@ -5,6 +5,7 @@ #include #include #include +#include std::string tokenAmountString(const CTokenAmount &amount, AmountFormat format = AmountFormat::Symbol) { const auto token = pcustomcsview->GetToken(amount.nTokenId); @@ -478,7 +479,9 @@ UniValue getaccount(const JSONRPCRequest& request) { const auto keyID = std::get(dest); std::array address{}; std::copy(keyID.begin(), keyID.end(), address.begin()); - if (const auto balance = evm_get_balance(address)) { + auto r = CrossBoundaryResVal(evm_try_get_balance(result, address)); + if (!r) throw JSONRPCError(RPC_MISC_ERROR, r.msg); + if (const auto balance = *r) { balances[DCT_ID{}] = balance; } } @@ -605,8 +608,13 @@ UniValue gettokenbalances(const JSONRPCRequest& request) { for (const auto keyID : pwallet->GetKeys()) { std::array address{}; std::copy(keyID.begin(), keyID.end(), address.begin()); - const auto evmAmount = evm_get_balance(address); - totalBalances.Add({{}, static_cast(evmAmount)}); + auto res = CrossBoundaryResVal(evm_try_get_balance(result, address)); + if (res) { + auto evmAmount = *res; + totalBalances.Add({{}, static_cast(evmAmount)}); + } else { + throw JSONRPCError(RPC_MISC_ERROR, res.msg); + } } } diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 026641a392..16b47d3a09 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2447,7 +2447,7 @@ static Res ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCust } CrossBoundaryResult result; - const auto blockResult = evm_try_construct_block(result, evmQueueId, block.nBits, beneficiary, block.GetBlockTime(), pindex->nHeight); + const auto blockResult = evm_unsafe_try_construct_block_in_q(result, evmQueueId, block.nBits, beneficiary, block.GetBlockTime(), pindex->nHeight); if (!result.ok) { return Res::Err(result.reason.c_str()); } diff --git a/src/miner.cpp b/src/miner.cpp index 0677a53693..60116f2953 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -272,7 +273,9 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc timeOrdering = false; } - const auto evmQueueId = evm_get_queue_id(); + auto r = CrossBoundaryResValChecked(evm_unsafe_try_create_queue(result)); + if (!r) return nullptr; + const auto evmQueueId = *r; std::map txFees; if (timeOrdering) { @@ -286,8 +289,9 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc std::array beneficiary{}; std::copy(nodePtr->ownerAuthAddress.begin(), nodePtr->ownerAuthAddress.end(), beneficiary.begin()); CrossBoundaryResult result; - auto blockResult = evm_try_construct_block(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), beneficiary, blockTime, nHeight); - evm_discard_context(evmQueueId); + auto blockResult = evm_unsafe_try_construct_block_in_q(result, evmQueueId, pos::GetNextWorkRequired(pindexPrev, pblock->nTime, consensus), beneficiary, blockTime, nHeight); + + CrossBoundaryChecked(evm_unsafe_try_remove_queue(result, evmQueueId)); const auto blockHash = std::vector(blockResult.block_hash.begin(), blockResult.block_hash.end()); @@ -658,7 +662,7 @@ bool BlockAssembler::EvmTxPreapply(const EvmTxPreApplyContext& ctx) const auto obj = std::get(txMessage); CrossBoundaryResult result; - const auto txResult = evm_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); + const auto txResult = evm_unsafe_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); if (!result.ok) { return false; } @@ -689,7 +693,7 @@ bool BlockAssembler::EvmTxPreapply(const EvmTxPreApplyContext& ctx) } } evmAddressTxsMap.erase(addrKey.address); - evm_try_remove_txs_by_sender(result, evmQueueId, addrKey.address); + evm_unsafe_try_remove_txs_by_sender_in_q(result, evmQueueId, addrKey.address); // TODO handle missing evmQueueId error if (!result.ok) { return false; @@ -699,7 +703,7 @@ bool BlockAssembler::EvmTxPreapply(const EvmTxPreApplyContext& ctx) } } - const auto nonce = evm_try_get_next_valid_nonce_in_queue(result, evmQueueId, txResult.sender); + const auto nonce = evm_unsafe_try_get_next_valid_nonce_in_q(result, evmQueueId, txResult.sender); if (!result.ok) { return false; } diff --git a/src/validation.cpp b/src/validation.cpp index 56fb1f946d..66ba6d033f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -55,7 +55,7 @@ #include #include #include - +#include #include #include @@ -918,7 +918,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool const auto obj = std::get(txMessage); CrossBoundaryResult result; - const auto txResult = evm_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); + const auto txResult = evm_unsafe_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); if (!result.ok) { return state.Invalid(ValidationInvalidReason::CONSENSUS, error("evm tx failed to validate %s", result.reason.c_str()), REJECT_INVALID, "evm-validate-failed"); } @@ -3182,7 +3182,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha mnview.GetHistoryWriters().DiscardDB(); return error("DisconnectTip(): DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); } - evm_disconnect_latest_block(); + CrossBoundaryChecked(evm_disconnect_latest_block(result)); bool flushed = view.Flush() && mnview.Flush(); assert(flushed); mnview.GetHistoryWriters().FlushDB(); @@ -3325,11 +3325,13 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp CCustomCSView mnview(*pcustomcsview, paccountHistoryDB.get(), pburnHistoryDB.get(), pvaultHistoryDB.get()); bool rewardedAnchors{}; std::array beneficiary{}; - const auto evmQueueId = evm_get_queue_id(); + uint64_t evmQueueId{}; + auto r = CrossBoundaryResValChecked(evm_unsafe_try_create_queue(result)); + if (r) { evmQueueId = *r; } bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, mnview, chainparams, rewardedAnchors, beneficiary, false, evmQueueId); GetMainSignals().BlockChecked(blockConnecting, state); if (!rv) { - evm_discard_context(evmQueueId); + CrossBoundaryChecked(evm_unsafe_try_remove_queue(result, evmQueueId)); if (state.IsInvalid()) { InvalidBlockFound(pindexNew, state); } @@ -3340,7 +3342,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp LogPrint(BCLog::BENCH, " - Connect total: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime3 - nTime2) * MILLI, nTimeConnectTotal * MICRO, nTimeConnectTotal * MILLI / nBlocksTotal); if (IsEVMEnabled(pindexNew->nHeight, mnview, chainparams.GetConsensus())) { CrossBoundaryResult result; - evm_try_finalize_block(result, evmQueueId); + CrossBoundaryChecked(evm_unsafe_try_commit_queue(result, evmQueueId)); if (!result.ok) { state.Invalid(ValidationInvalidReason::CONSENSUS, error("EVM finalization failed: %s", result.reason.c_str()),