diff --git a/lib/ain-cpp-imports/src/bridge.rs b/lib/ain-cpp-imports/src/bridge.rs index 00446242aa..b0d0c92a8f 100644 --- a/lib/ain-cpp-imports/src/bridge.rs +++ b/lib/ain-cpp-imports/src/bridge.rs @@ -30,7 +30,7 @@ pub mod ffi { fn getPoolTransactions() -> Vec; fn getNativeTxSize(data: Vec) -> u64; fn getMinRelayTxFee() -> u64; - fn getEthPrivKey(key_id: [u8; 20]) -> [u8; 32]; + fn getEthPrivKey(key: String) -> [u8; 32]; fn getStateInputJSON() -> String; fn getHighestBlock() -> i32; fn getCurrentHeight() -> i32; diff --git a/lib/ain-cpp-imports/src/lib.rs b/lib/ain-cpp-imports/src/lib.rs index 0c068c2138..ee5001904e 100644 --- a/lib/ain-cpp-imports/src/lib.rs +++ b/lib/ain-cpp-imports/src/lib.rs @@ -55,7 +55,7 @@ mod ffi { pub fn getMinRelayTxFee() -> u64 { unimplemented!("{}", UNIMPL_MSG) } - pub fn getEthPrivKey(_key_id: [u8; 20]) -> [u8; 32] { + pub fn getEthPrivKey(_key: String) -> [u8; 32] { unimplemented!("{}", UNIMPL_MSG) } pub fn getStateInputJSON() -> String { @@ -136,8 +136,8 @@ pub fn get_min_relay_tx_fee() -> Result> { Ok(tx_fee) } -pub fn get_eth_priv_key(key_id: [u8; 20]) -> Result<[u8; 32], Box> { - let eth_key = ffi::getEthPrivKey(key_id); +pub fn get_eth_priv_key(key: String) -> Result<[u8; 32], Box> { + let eth_key = ffi::getEthPrivKey(key); Ok(eth_key) } diff --git a/lib/ain-evm/src/core.rs b/lib/ain-evm/src/core.rs index 823068245d..58439dcbdc 100644 --- a/lib/ain-evm/src/core.rs +++ b/lib/ain-evm/src/core.rs @@ -27,7 +27,7 @@ use crate::{ Result, }; -pub type NativeTxHash = [u8; 32]; +pub type XHash = String; pub struct EVMCoreService { pub tx_queues: Arc, @@ -349,7 +349,7 @@ impl EVMCoreService { queue_id: u64, address: H160, amount: U256, - hash: NativeTxHash, + hash: XHash, ) -> Result<()> { let queue_tx = QueueTx::SystemTx(SystemTx::EvmIn(BalanceUpdate { address, amount })); self.tx_queues @@ -368,7 +368,7 @@ impl EVMCoreService { queue_id: u64, address: H160, amount: U256, - hash: NativeTxHash, + hash: XHash, ) -> Result<()> { let block_number = self .storage diff --git a/lib/ain-evm/src/ecrecover.rs b/lib/ain-evm/src/ecrecover.rs index 5f9b54013c..4e18be207d 100644 --- a/lib/ain-evm/src/ecrecover.rs +++ b/lib/ain-evm/src/ecrecover.rs @@ -31,7 +31,7 @@ pub fn public_key_to_address(pubkey: &PublicKey) -> H160 { #[cfg(test)] mod tests { use hex_literal::hex; - use primitive_types::H256; + use primitive_types::*; use super::{public_key_to_address, recover_public_key}; @@ -56,4 +56,98 @@ mod tests { "89790061e1efe88bda902193c8ab3b061aa4ef2c".parse().unwrap() ); } + + #[test] + fn test_recover_test2() { + // Tx hex: f86c808504e3b29200825208946c34cbb9219d8caa428835d2073e8ec88ba0a110880de0b6b3a76400008025a037f41c543402c9b02b35b45ef43ac31a63dcbeba0c622249810ecdec00aee376a05eb2be77eb0c7a1875a53ba15fc6afe246fbffe869157edbde64270e41ba045e + + // Decoded: + // { + // "nonce": 0, + // "gasPrice": 21000000000, + // "gasLimit": 21000, + // "to": "0x6c34cbb9219d8caa428835d2073e8ec88ba0a110", + // "value": 1000000000000000000, + // "data": "", + // "from": "0x9b8a4af42140d8a4c153a822f02571a1dd037e89", + // "r": "37f41c543402c9b02b35b45ef43ac31a63dcbeba0c622249810ecdec00aee376", + // "v": "25", + // "s": "5eb2be77eb0c7a1875a53ba15fc6afe246fbffe869157edbde64270e41ba045e" + // } + + let from = "0x9b8a4af42140d8a4c153a822f02571a1dd037e89"; + let r = "37f41c543402c9b02b35b45ef43ac31a63dcbeba0c622249810ecdec00aee376"; + let s = "5eb2be77eb0c7a1875a53ba15fc6afe246fbffe869157edbde64270e41ba045e"; + let hash = ""; + + // let recovery_id = 0; + + // let pubkey = recover_public_key(&hash, &r, &s, recovery_id); + // assert!(pubkey.is_ok()); + // let address = public_key_to_address(&pubkey.unwrap()); + // assert_eq!( + // address, + // from + // ); + } + + #[test] + fn test_recover_test3() { + // Tx: https://etherscan.io/getRawTx?tx=0x89221691a67b15427c97f1fd0cd65966ff617728cd897be27d88a04ee0bc1e2d + // + // Hex: + // 0xf901ed828c848503d77a05008301754a94d9f61a4a96f66afe09c6f55b72aeaf1590ac849580b9018439125215000000000000000000000000260f38dbc414a9d588ca2dedddb7588da25736a60000000000000000000000000000000000000000000000000205061e42dd640000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005dd767960000000000000000000000000000000000000000000000000000000000000c4a000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004187e330045ecad46221a46b1be365a45d293988e2162b94ef939d837d49be6cbb0425cfcfa16bed80a8a8fdb0984c24d081781603473e9077db8ff92618c310bd1c000000000000000000000000000000000000000000000000000000000000001ca02fa2191f585d3f704d073dd19fd2dddc745612dacdd60fc27d4df53d2717a057a069bb520bc99dfa007ce23ba52b4eed758d53eb7cc4c66bf7e045c2c13e62675f + + // Decoded with https://flightwallet.github.io/decode-eth-tx/ + // { + // "nonce": 35972, + // "gasPrice": 16500000000, + // "gasLimit": 95562, + // "to": "0xd9f61a4a96f66afe09c6f55b72aeaf1590ac8495", + // "value": 0, + // "data": "39125215000000000000000000000000260f38dbc414a9d588ca2dedddb7588da25736a60000000000000000000000000000000000000000000000000205061e42dd640000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000005dd767960000000000000000000000000000000000000000000000000000000000000c4a000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004187e330045ecad46221a46b1be365a45d293988e2162b94ef939d837d49be6cbb0425cfcfa16bed80a8a8fdb0984c24d081781603473e9077db8ff92618c310bd1c00000000000000000000000000000000000000000000000000000000000000", + // "from": "0x3f1e01f65cac6cdb60ef5f7fc8f988f042949a2c", + // "r": "2fa2191f585d3f704d073dd19fd2dddc745612dacdd60fc27d4df53d2717a057", + // "v": "1c", + // "s": "69bb520bc99dfa007ce23ba52b4eed758d53eb7cc4c66bf7e045c2c13e62675f" + // } + + // let to_str = "0xd9f61a4A96f66Afe09c6F55B72AeaF1590AC8495"; + // let txhash_str = "0x89221691a67b15427c97f1fd0cd65966ff617728cd897be27d88a04ee0bc1e2d"; + // let from_str = "0x3f1e01F65Cac6CDB60Ef5F7fC8F988f042949a2C"; + // let s_str = "69bb520bc99dfa007ce23ba52b4eed758d53eb7cc4c66bf7e045c2c13e62675f"; + // let r_str = "2fa2191f585d3f704d073dd19fd2dddc745612dacdd60fc27d4df53d2717a057"; + + // let h_vals = &[txhash_str, s_str, r_str].iter().map(|x| H256::).collect::>(); + // let [hash, r, s ] = h_vals[..]; + + let from = H160::from_slice(&hex!("3f1e01F65Cac6CDB60Ef5F7fC8F988f042949a2C")); + let to = H160::from_slice(&hex!("d9f61a4A96f66Afe09c6F55B72AeaF1590AC8495")); + + let hash = H256::from_slice(&hex!( + "89221691a67b15427c97f1fd0cd65966ff617728cd897be27d88a04ee0bc1e2d" + )); + let r = H256::from_slice(&hex!( + "2fa2191f585d3f704d073dd19fd2dddc745612dacdd60fc27d4df53d2717a057" + )); + let s = H256::from_slice(&hex!( + "69bb520bc99dfa007ce23ba52b4eed758d53eb7cc4c66bf7e045c2c13e62675f" + )); + + for x in 0..=4 { + let rx = x; + let pubkey = recover_public_key(&hash, &r, &s, rx); + if let Ok(pubkey) = pubkey { + let address = public_key_to_address(&pubkey); + println!("address: {:x}", address); + println!("from: {:x}", from); + if address == from { + println!("found: {}", rx); + break; + } + } else { + println!("{:?}", pubkey.err().unwrap()); + } + } + } } diff --git a/lib/ain-evm/src/evm.rs b/lib/ain-evm/src/evm.rs index 1553ce6cdd..c170c740df 100644 --- a/lib/ain-evm/src/evm.rs +++ b/lib/ain-evm/src/evm.rs @@ -14,7 +14,7 @@ use primitive_types::H256; use crate::backend::{EVMBackend, Vicinity}; use crate::block::BlockService; use crate::bytes::Bytes; -use crate::core::{EVMCoreService, NativeTxHash}; +use crate::core::{EVMCoreService, XHash}; use crate::executor::{AinExecutor, TxResponse}; use crate::fee::{calculate_gas_fee, calculate_prepay_gas_fee}; use crate::filters::FilterService; @@ -40,8 +40,8 @@ pub struct EVMServices { } pub struct FinalizedBlockInfo { - pub block_hash: [u8; 32], - pub failed_transactions: Vec, + pub block_hash: XHash, + pub failed_transactions: Vec, pub total_burnt_fees: U256, pub total_priority_fees: U256, pub block_number: U256, @@ -227,7 +227,7 @@ impl EVMServices { signed_tx.transaction.hash() ); if !exit_reason.is_succeed() { - failed_transactions.push(hex::encode(queue_item.tx_hash)); + failed_transactions.push(queue_item.tx_hash); } let gas_fee = calculate_gas_fee(&signed_tx, U256::from(used_gas), base_fee)?; @@ -245,7 +245,7 @@ impl EVMServices { ); if let Err(e) = executor.add_balance(address, amount) { debug!("[construct_block] EvmIn failed with {e}"); - failed_transactions.push(hex::encode(queue_item.tx_hash)); + failed_transactions.push(queue_item.tx_hash); } } QueueTx::SystemTx(SystemTx::EvmOut(BalanceUpdate { address, amount })) => { @@ -256,7 +256,7 @@ impl EVMServices { if let Err(e) = executor.sub_balance(address, amount) { debug!("[construct_block] EvmOut failed with {e}"); - failed_transactions.push(hex::encode(queue_item.tx_hash)); + failed_transactions.push(queue_item.tx_hash); } } QueueTx::SystemTx(SystemTx::DeployContract(DeployContractData { @@ -304,12 +304,12 @@ impl EVMServices { Ok(DST20BridgeInfo { address, storage }) => { if let Err(e) = executor.update_storage(address, storage) { debug!("[construct_block] EvmOut failed with {e}"); - failed_transactions.push(hex::encode(queue_item.tx_hash)); + failed_transactions.push(queue_item.tx_hash); } } Err(e) => { debug!("[construct_block] EvmOut failed with {e}"); - failed_transactions.push(hex::encode(queue_item.tx_hash)); + failed_transactions.push(queue_item.tx_hash); } } } @@ -358,8 +358,7 @@ impl EVMServices { .collect(), Vec::new(), ); - - let block_hash = *block.header.hash().as_fixed_bytes(); + let block_hash = format!("{:?}", block.header.hash()); let receipts = self.receipt.generate_receipts( &all_transactions, receipts_v3, @@ -436,7 +435,7 @@ impl EVMServices { &self, queue_id: u64, tx: QueueTx, - hash: NativeTxHash, + hash: XHash, gas_used: U256, ) -> Result<()> { let parent_data = self.block.get_latest_block_hash_and_number()?; diff --git a/lib/ain-evm/src/transaction/mod.rs b/lib/ain-evm/src/transaction/mod.rs index 152bf5dd90..74b8807501 100644 --- a/lib/ain-evm/src/transaction/mod.rs +++ b/lib/ain-evm/src/transaction/mod.rs @@ -4,6 +4,7 @@ use ethereum::{ AccessList, EnvelopedDecoderError, LegacyTransaction, TransactionAction, TransactionSignature, TransactionV2, }; +use libsecp256k1::PublicKey; use primitive_types::{H160, H256, U256}; use rlp::RlpStream; use sha3::Digest; @@ -49,18 +50,18 @@ impl LegacyUnsignedTransaction { H256::from(output) } - pub fn sign(&self, key: &H256, chain_id: u64) -> Result { + pub fn sign(&self, key: &[u8], chain_id: u64) -> Result { self.sign_with_chain_id(key, chain_id) } pub fn sign_with_chain_id( &self, - key: &H256, + key: &[u8], chain_id: u64, ) -> Result { let hash = self.signing_hash(chain_id); let msg = libsecp256k1::Message::parse(hash.as_fixed_bytes()); - let s = libsecp256k1::sign(&msg, &libsecp256k1::SecretKey::parse_slice(&key[..])?); + let s = libsecp256k1::sign(&msg, &libsecp256k1::SecretKey::parse_slice(key)?); let sig = s.0.serialize(); let sig = TransactionSignature::new( @@ -100,6 +101,7 @@ impl From<&LegacyTransaction> for LegacyUnsignedTransaction { pub struct SignedTx { pub transaction: TransactionV2, pub sender: H160, + pub pubkey: PublicKey, } impl TryFrom for SignedTx { @@ -161,6 +163,7 @@ impl TryFrom for SignedTx { Ok(SignedTx { transaction: src, sender: public_key_to_address(&pubkey), + pubkey, }) } } @@ -356,6 +359,7 @@ mod tests { // Legacy let signed_tx = crate::transaction::SignedTx::try_from("f86b8085689451eee18252089434c1ca09a2dc717d89baef2f30ff6a6b2975e17e872386f26fc10000802da0ae5c76f8073460cbc7a911d3cc1b367072db64848a9532343559ce6917c51a46a01d2e4928450c59acca3de8340eb15b7446b37936265a51ab35e63f749a048002").unwrap(); + assert_eq!(hex::encode(signed_tx.pubkey.serialize()), "044c6412f7cd3ac0e2538c3c9843d27d1e03b422eaf655c6a699da22b57a89802989318dbaeea62f5fc751fa8cd1404e687d67b8ab8513fe0d37bafbf407aa6cf7"); assert_eq!( hex::encode(signed_tx.sender.as_fixed_bytes()), "f829754bae400b679febefdcfc9944c323e1f94e" diff --git a/lib/ain-evm/src/txqueue.rs b/lib/ain-evm/src/txqueue.rs index a92b1ea01d..572c5a4e23 100644 --- a/lib/ain-evm/src/txqueue.rs +++ b/lib/ain-evm/src/txqueue.rs @@ -7,7 +7,7 @@ use ethereum::{Block, TransactionV2}; use ethereum_types::{H160, U256}; use rand::Rng; -use crate::core::NativeTxHash; +use crate::core::XHash; use crate::fee::calculate_gas_fee; use crate::receipt::Receipt; use crate::transaction::{system::SystemTx, SignedTx}; @@ -119,7 +119,7 @@ impl TransactionQueueMap { &self, queue_id: u64, tx: QueueTx, - hash: NativeTxHash, + hash: XHash, gas_used: U256, base_fee: U256, ) -> Result<()> { @@ -219,7 +219,7 @@ pub enum QueueTx { #[derive(Debug, Clone, PartialEq, Eq)] pub struct QueueTxItem { pub tx: QueueTx, - pub tx_hash: NativeTxHash, + pub tx_hash: XHash, pub tx_fee: U256, pub gas_used: U256, } @@ -277,7 +277,7 @@ impl TransactionQueue { pub fn queue_tx( &self, tx: QueueTx, - tx_hash: NativeTxHash, + tx_hash: XHash, gas_used: U256, base_fee: U256, ) -> Result<()> { diff --git a/lib/ain-grpc/src/rpc/eth.rs b/lib/ain-grpc/src/rpc/eth.rs index 7e621bef70..66ae03f952 100644 --- a/lib/ain-grpc/src/rpc/eth.rs +++ b/lib/ain-grpc/src/rpc/eth.rs @@ -1059,8 +1059,8 @@ fn sign( message: TransactionMessage, ) -> Result> { debug!("sign address {:#x}", address); - let key_id = address.as_fixed_bytes().to_owned(); - let priv_key = get_eth_priv_key(key_id).unwrap(); + let key = format!("{:?}", address); + let priv_key = get_eth_priv_key(key).unwrap(); let secret_key = SecretKey::parse(&priv_key).unwrap(); match message { diff --git a/lib/ain-rs-exports/src/evm.rs b/lib/ain-rs-exports/src/evm.rs index 2656987b9b..549e609b4a 100644 --- a/lib/ain-rs-exports/src/evm.rs +++ b/lib/ain-rs-exports/src/evm.rs @@ -2,17 +2,17 @@ use ain_evm::storage::traits::BlockStorage; use ain_evm::transaction::system::{DST20Data, DeployContractData, SystemTx}; use ain_evm::txqueue::QueueTx; use ain_evm::{ - core::ValidateTxInfo, + core::{ValidateTxInfo, XHash}, evm::FinalizedBlockInfo, services::SERVICES, storage::traits::Rollback, storage::traits::TransactionStorage, transaction::{self, SignedTx}, - weiamount::WeiAmount, + weiamount::{try_from_gwei, try_from_satoshi, WeiAmount}, }; use ethereum::{EnvelopedEncodable, TransactionAction, TransactionSignature, TransactionV2}; use log::debug; -use primitive_types::{H160, H256, U256}; +use primitive_types::U256; use transaction::{LegacyUnsignedTransaction, TransactionError, LOWER_H256}; use crate::ffi; @@ -38,29 +38,36 @@ pub fn evm_try_create_and_sign_tx( let to_action = if ctx.to.is_empty() { TransactionAction::Create } else { - TransactionAction::Call(H160::from_slice(&ctx.to)) + let Ok(to_address) = ctx.to.parse() else { + return cross_boundary_error_return(result, "Invalid address"); + }; + TransactionAction::Call(to_address) + }; + let nonce = U256::from(ctx.nonce); + let gas_price = match try_from_gwei(U256::from(ctx.gas_price)) { + Ok(price) => price, + Err(e) => return cross_boundary_error_return(result, e.to_string()), + }; + let gas_limit = U256::from(ctx.gas_limit); + let value = match try_from_satoshi(U256::from(ctx.value)) { + Ok(wei_value) => wei_value, + Err(e) => return cross_boundary_error_return(result, e.to_string()), }; - - let nonce_u256 = U256::from(ctx.nonce); - let gas_price_u256 = U256::from(ctx.gas_price); - let gas_limit_u256 = U256::from(ctx.gas_limit); - let value_u256 = U256::from(ctx.value); // Create let t = LegacyUnsignedTransaction { - nonce: nonce_u256, - gas_price: gas_price_u256, - gas_limit: gas_limit_u256, + nonce, + gas_price: gas_price.0, + gas_limit, action: to_action, - value: value_u256, + value: value.0, input: ctx.input, // Dummy sig for now. Needs 27, 28 or > 36 for valid v. sig: TransactionSignature::new(27, LOWER_H256, LOWER_H256).unwrap(), }; - // Sign - let priv_key_h256 = H256::from(ctx.priv_key); - match t.sign(&priv_key_h256, ctx.chain_id) { + // Sign with a big endian byte array + match t.sign(&ctx.priv_key, ctx.chain_id) { Ok(signed) => cross_boundary_success_return(result, signed.encode().into()), Err(e) => cross_boundary_error_return(result, e.to_string()), } @@ -79,14 +86,16 @@ pub fn evm_try_create_and_sign_tx( /// # Returns /// /// Returns the balance of the account as a `u64` on success. -pub fn evm_try_get_balance(result: &mut ffi::CrossBoundaryResult, address: [u8; 20]) -> u64 { - let account = H160::from(address); +pub fn evm_try_get_balance(result: &mut ffi::CrossBoundaryResult, address: &str) -> u64 { + let Ok(address) = address.parse() else { + return cross_boundary_error_return(result, "Invalid address"); + }; let (_, latest_block_number) = match SERVICES.evm.block.get_latest_block_hash_and_number() { Err(e) => return cross_boundary_error_return(result, e.to_string()), Ok(data) => data.unwrap_or_default(), }; - match SERVICES.evm.core.get_balance(account, latest_block_number) { + match SERVICES.evm.core.get_balance(address, latest_block_number) { Err(e) => cross_boundary_error_return(result, e.to_string()), Ok(balance) => { let amount = WeiAmount(balance).to_satoshi().try_into(); @@ -109,9 +118,12 @@ pub fn evm_try_get_balance(result: &mut ffi::CrossBoundaryResult, address: [u8; pub fn evm_unsafe_try_get_next_valid_nonce_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, - address: [u8; 20], + address: &str, ) -> u64 { - let address = H160::from(address); + let Ok(address) = address.parse() else { + return cross_boundary_error_return(result, "Invalid address"); + }; + unsafe { match SERVICES .evm @@ -139,9 +151,12 @@ pub fn evm_unsafe_try_get_next_valid_nonce_in_q( pub fn evm_unsafe_try_remove_txs_by_sender_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, - address: [u8; 20], + address: &str, ) { - let address = H160::from(address); + let Ok(address) = address.parse() else { + return cross_boundary_error_return(result, "Invalid address"); + }; + unsafe { match SERVICES.evm.core.remove_txs_by_sender_in(queue_id, address) { Ok(_) => cross_boundary_success_return(result, ()), @@ -163,18 +178,23 @@ pub fn evm_unsafe_try_add_balance_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: &str, - amount: [u8; 32], - hash: [u8; 32], + amount: u64, + native_hash: &str, ) { let Ok(address) = address.parse() else { return cross_boundary_error_return(result, "Invalid address"); }; + let amount = match try_from_satoshi(U256::from(amount)) { + Ok(wei_amount) => wei_amount, + Err(e) => return cross_boundary_error_return(result, e.to_string()), + }; + let native_hash = XHash::from(native_hash); unsafe { match SERVICES .evm .core - .add_balance(queue_id, address, amount.into(), hash) + .add_balance(queue_id, address, amount.0, native_hash) { Ok(_) => cross_boundary_success_return(result, ()), Err(e) => cross_boundary_error_return(result, e.to_string()), @@ -205,18 +225,23 @@ pub fn evm_unsafe_try_sub_balance_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: &str, - amount: [u8; 32], - hash: [u8; 32], + amount: u64, + native_hash: &str, ) -> bool { let Ok(address) = address.parse() else { return cross_boundary_error_return(result, "Invalid address"); }; + let amount = match try_from_satoshi(U256::from(amount)) { + Ok(wei_amount) => wei_amount, + Err(e) => return cross_boundary_error_return(result, e.to_string()), + }; + let native_hash = XHash::from(native_hash); unsafe { match SERVICES .evm .core - .sub_balance(queue_id, address, amount.into(), hash) + .sub_balance(queue_id, address, amount.0, native_hash) { Ok(_) => cross_boundary_success_return(result, true), Err(e) => cross_boundary_error_return(result, e.to_string()), @@ -249,14 +274,15 @@ pub fn evm_unsafe_try_sub_balance_in_q( pub fn evm_unsafe_try_prevalidate_raw_tx( result: &mut ffi::CrossBoundaryResult, tx: &str, -) -> ffi::PreValidateTxCompletion { +) -> ffi::ValidateTxCompletion { let queue_id = 0; + unsafe { match SERVICES.evm.core.validate_raw_tx(tx, queue_id) { Ok(ValidateTxInfo { signed_tx, prepay_fee, - used_gas: _, + used_gas, }) => { let Ok(nonce) = u64::try_from(signed_tx.nonce()) else { return cross_boundary_error_return(result, "nonce value overflow"); @@ -268,10 +294,12 @@ pub fn evm_unsafe_try_prevalidate_raw_tx( cross_boundary_success_return( result, - ffi::PreValidateTxCompletion { + ffi::ValidateTxCompletion { nonce, - sender: signed_tx.sender.to_fixed_bytes(), + sender: format!("{:?}", signed_tx.sender), + tx_hash: format!("{:?}", signed_tx.hash()), prepay_fee, + gas_used: used_gas, }, ) } @@ -338,8 +366,8 @@ pub fn evm_unsafe_try_validate_raw_tx_in_q( result, ffi::ValidateTxCompletion { nonce, - sender: signed_tx.sender.to_fixed_bytes(), - tx_hash: signed_tx.hash().to_fixed_bytes(), + sender: format!("{:?}", signed_tx.sender), + tx_hash: format!("{:?}", signed_tx.hash()), prepay_fee, gas_used: used_gas, }, @@ -396,17 +424,19 @@ pub fn evm_unsafe_try_push_tx_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, raw_tx: &str, - hash: [u8; 32], + native_hash: &str, gas_used: u64, ) { + let native_hash = native_hash.to_string(); let signed_tx: Result = raw_tx.try_into(); + unsafe { match signed_tx { Ok(signed_tx) => { match SERVICES.evm.push_tx_in_queue( queue_id, signed_tx.into(), - hash, + native_hash, U256::from(gas_used), ) { Ok(_) => cross_boundary_success(result), @@ -434,12 +464,15 @@ pub fn evm_unsafe_try_construct_block_in_q( result: &mut ffi::CrossBoundaryResult, queue_id: u64, difficulty: u32, - miner_address: [u8; 20], + miner_address: &str, timestamp: u64, dvm_block_number: u64, mnview_ptr: usize, ) -> ffi::FinalizeBlockCompletion { - let eth_address = H160::from(miner_address); + let Ok(eth_address) = miner_address.parse() else { + return cross_boundary_error_return(result, "Invalid address"); + }; + unsafe { match SERVICES.evm.construct_block_in_queue( queue_id, @@ -519,14 +552,14 @@ pub fn evm_try_set_attribute( pub fn evm_try_get_block_hash_by_number( result: &mut ffi::CrossBoundaryResult, height: u64, -) -> [u8; 32] { +) -> XHash { match SERVICES .evm .storage .get_block_by_number(&U256::from(height)) { Ok(Some(block)) => { - cross_boundary_success_return(result, block.header.hash().to_fixed_bytes()) + cross_boundary_success_return(result, format!("{:?}", block.header.hash())) } Ok(None) => cross_boundary_error_return(result, "Invalid block number"), Err(e) => cross_boundary_error_return(result, e.to_string()), @@ -542,13 +575,11 @@ pub fn evm_try_get_block_hash_by_number( /// # Returns /// /// Returns the block number associated with the given blockhash. -pub fn evm_try_get_block_number_by_hash( - result: &mut ffi::CrossBoundaryResult, - hash: [u8; 32], -) -> u64 { - let Ok(hash) = H256::try_from(hash) else { +pub fn evm_try_get_block_number_by_hash(result: &mut ffi::CrossBoundaryResult, hash: &str) -> u64 { + let Ok(hash) = hash.parse() else { return cross_boundary_error_return(result, "Invalid block hash"); }; + match SERVICES.evm.storage.get_block_by_hash(&hash) { Ok(Some(block)) => { let Ok(block_number) = u64::try_from(block.header.number) else { @@ -563,9 +594,9 @@ pub fn evm_try_get_block_number_by_hash( pub fn evm_try_get_block_header_by_hash( result: &mut ffi::CrossBoundaryResult, - hash: [u8; 32], + hash: &str, ) -> ffi::EVMBlockHeader { - let Ok(hash) = H256::try_from(hash) else { + let Ok(hash) = hash.parse() else { return cross_boundary_error_return(result, "Invalid block hash"); }; @@ -585,17 +616,17 @@ pub fn evm_try_get_block_header_by_hash( }; let out = ffi::EVMBlockHeader { - parent_hash: block.header.parent_hash.to_fixed_bytes(), - beneficiary: block.header.beneficiary.to_fixed_bytes(), - state_root: block.header.state_root.to_fixed_bytes(), - receipts_root: block.header.receipts_root.to_fixed_bytes(), + parent_hash: format!("{:?}", block.header.parent_hash), + beneficiary: format!("{:?}", block.header.beneficiary), + state_root: format!("{:?}", block.header.state_root), + receipts_root: format!("{:?}", block.header.receipts_root), number, gas_limit, gas_used, timestamp: block.header.timestamp, extra_data: block.header.extra_data.clone(), - mix_hash: block.header.mix_hash.to_fixed_bytes(), - nonce: block.header.nonce.to_low_u64_ne(), + mix_hash: format!("{:?}", block.header.mix_hash), + nonce: block.header.nonce.to_low_u64_be(), base_fee, }; cross_boundary_success_return(result, out) @@ -638,13 +669,13 @@ pub fn evm_try_is_dst20_deployed_or_queued( pub fn evm_try_get_tx_by_hash( result: &mut ffi::CrossBoundaryResult, - tx_hash: [u8; 32], + tx_hash: &str, ) -> ffi::EVMTransaction { - match SERVICES - .evm - .storage - .get_transaction_by_hash(&H256::from(tx_hash)) - { + let Ok(tx_hash) = tx_hash.parse() else { + return cross_boundary_error_return(result, "Invalid tx hash"); + }; + + match SERVICES.evm.storage.get_transaction_by_hash(&tx_hash) { Ok(Some(tx)) => { let Ok(tx) = SignedTx::try_from(tx) else { return cross_boundary_error_return(result, "failed to convert tx to SignedTx"); @@ -707,8 +738,8 @@ pub fn evm_try_get_tx_by_hash( let out = ffi::EVMTransaction { tx_type, - hash: tx.hash().to_fixed_bytes(), - sender: tx.sender.to_fixed_bytes(), + hash: format!("{:?}", tx.hash()), + sender: format!("{:?}", tx.sender), nonce, gas_price, gas_limit, @@ -719,8 +750,8 @@ pub fn evm_try_get_tx_by_hash( TransactionAction::Create => true, }, to: match tx.to() { - Some(to) => to.to_fixed_bytes(), - None => H160::zero().to_fixed_bytes(), + Some(to) => format!("{:?}", to), + None => XHash::new(), }, value, data: tx.data().to_vec(), @@ -735,11 +766,12 @@ pub fn evm_try_get_tx_by_hash( pub fn evm_try_create_dst20( result: &mut ffi::CrossBoundaryResult, queue_id: u64, - native_hash: [u8; 32], + native_hash: &str, name: &str, symbol: &str, token_id: u64, ) { + let native_hash = XHash::from(native_hash); let address = match ain_contracts::dst20_address_from_token_id(token_id) { Ok(address) => address, Err(e) => cross_boundary_error_return(result, e.to_string()), @@ -768,21 +800,26 @@ pub fn evm_try_bridge_dst20( result: &mut ffi::CrossBoundaryResult, queue_id: u64, address: &str, - amount: [u8; 32], - native_hash: [u8; 32], + amount: u64, + native_hash: &str, token_id: u64, out: bool, ) { let Ok(address) = address.parse() else { return cross_boundary_error_return(result, "Invalid address"); }; + let amount = match try_from_satoshi(U256::from(amount)) { + Ok(wei_amount) => wei_amount, + Err(e) => return cross_boundary_error_return(result, e.to_string()), + }; + let native_hash = XHash::from(native_hash); let contract = ain_contracts::dst20_address_from_token_id(token_id) .unwrap_or_else(|e| cross_boundary_error_return(result, e.to_string())); let system_tx = QueueTx::SystemTx(SystemTx::DST20Bridge(DST20Data { to: address, contract, - amount: amount.into(), + amount: amount.0, out, })); @@ -817,3 +854,27 @@ pub fn evm_unsafe_try_get_target_block_in_q( } } } + +#[cfg(test)] +mod tests { + #[test] + fn test_hash_type_string() { + use primitive_types::H160; + let num = 0b11010111_11010111_11010111_11010111_11010111_11010111_11010111_11010111; + let num_h160 = H160::from_low_u64_be(num); + let num_h160_string = format!("{:?}", num_h160); + println!("{}", num_h160_string); + + let num_h160_test: H160 = num_h160_string.parse().unwrap(); + assert_eq!(num_h160_test, num_h160); + + use primitive_types::H256; + let num_h256: H256 = "0x3186715414c5fbd73586662d26b83b66b5754036379d56e896a560a90e409351" + .parse() + .unwrap(); + let num_h256_string = format!("{:?}", num_h256); + println!("{}", num_h256_string); + let num_h256_test: H256 = num_h256_string.parse().unwrap(); + assert_eq!(num_h256_test, num_h256); + } +} diff --git a/lib/ain-rs-exports/src/lib.rs b/lib/ain-rs-exports/src/lib.rs index 53739eb4c0..ea71cee313 100644 --- a/lib/ain-rs-exports/src/lib.rs +++ b/lib/ain-rs-exports/src/lib.rs @@ -10,16 +10,16 @@ pub mod ffi { // ========== Block ========== #[derive(Default)] pub struct EVMBlockHeader { - pub parent_hash: [u8; 32], - pub beneficiary: [u8; 20], - pub state_root: [u8; 32], - pub receipts_root: [u8; 32], + pub parent_hash: String, + pub beneficiary: String, + pub state_root: String, + pub receipts_root: String, pub number: u64, pub gas_limit: u64, pub gas_used: u64, pub timestamp: u64, pub extra_data: Vec, - pub mix_hash: [u8; 32], + pub mix_hash: String, pub nonce: u64, pub base_fee: u64, } @@ -29,15 +29,15 @@ pub mod ffi { pub struct EVMTransaction { // EIP-2718 transaction type: legacy - 0x0, EIP2930 - 0x1, EIP1559 - 0x2 pub tx_type: u8, - pub hash: [u8; 32], - pub sender: [u8; 20], + pub hash: String, + pub sender: String, pub nonce: u64, pub gas_price: u64, pub gas_limit: u64, pub max_fee_per_gas: u64, pub max_priority_fee_per_gas: u64, pub create_tx: bool, - pub to: [u8; 20], + pub to: String, pub value: u64, pub data: Vec, } @@ -64,38 +64,31 @@ pub mod ffi { // ========== EVM ========== - pub struct CreateTransactionContext { + pub struct CreateTransactionContext<'a> { pub chain_id: u64, - pub nonce: [u8; 32], - pub gas_price: [u8; 32], - pub gas_limit: [u8; 32], - pub to: [u8; 20], - pub value: [u8; 32], + pub nonce: u64, + pub gas_price: u64, + pub gas_limit: u64, + pub to: &'a str, + pub value: u64, pub input: Vec, pub priv_key: [u8; 32], } #[derive(Default)] pub struct FinalizeBlockCompletion { - pub block_hash: [u8; 32], + pub block_hash: String, pub failed_transactions: Vec, pub total_burnt_fees: u64, pub total_priority_fees: u64, pub block_number: u64, } - #[derive(Default)] - pub struct PreValidateTxCompletion { - pub nonce: u64, - pub sender: [u8; 20], - pub prepay_fee: u64, - } - #[derive(Default)] pub struct ValidateTxCompletion { pub nonce: u64, - pub sender: [u8; 20], - pub tx_hash: [u8; 32], + pub sender: String, + pub tx_hash: String, pub prepay_fee: u64, pub gas_used: u64, } @@ -105,7 +98,7 @@ pub mod ffi { // // If they are fallible, it's a TODO to changed and move later // so errors are propogated up properly. - fn evm_try_get_balance(result: &mut CrossBoundaryResult, address: [u8; 20]) -> u64; + fn evm_try_get_balance(result: &mut CrossBoundaryResult, address: &str) -> 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_try_disconnect_latest_block(result: &mut CrossBoundaryResult); @@ -116,31 +109,31 @@ pub mod ffi { fn evm_unsafe_try_get_next_valid_nonce_in_q( result: &mut CrossBoundaryResult, queue_id: u64, - address: [u8; 20], + address: &str, ) -> u64; fn evm_unsafe_try_remove_txs_by_sender_in_q( result: &mut CrossBoundaryResult, queue_id: u64, - address: [u8; 20], + address: &str, ); fn evm_unsafe_try_add_balance_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: &str, - amount: [u8; 32], - native_tx_hash: [u8; 32], + amount: u64, + native_hash: &str, ); fn evm_unsafe_try_sub_balance_in_q( result: &mut CrossBoundaryResult, queue_id: u64, address: &str, - amount: [u8; 32], - native_tx_hash: [u8; 32], + amount: u64, + native_hash: &str, ) -> bool; fn evm_unsafe_try_prevalidate_raw_tx( result: &mut CrossBoundaryResult, tx: &str, - ) -> PreValidateTxCompletion; + ) -> ValidateTxCompletion; fn evm_unsafe_try_validate_raw_tx_in_q( result: &mut CrossBoundaryResult, tx: &str, @@ -150,14 +143,14 @@ pub mod ffi { result: &mut CrossBoundaryResult, queue_id: u64, raw_tx: &str, - hash: [u8; 32], + native_hash: &str, gas_used: u64, ); fn evm_unsafe_try_construct_block_in_q( result: &mut CrossBoundaryResult, queue_id: u64, difficulty: u32, - miner_address: [u8; 20], + miner_address: &str, timestamp: u64, dvm_block_number: u64, mnview_ptr: usize, @@ -176,25 +169,22 @@ pub mod ffi { fn evm_try_get_block_hash_by_number( result: &mut CrossBoundaryResult, height: u64, - ) -> [u8; 32]; - fn evm_try_get_block_number_by_hash( - result: &mut CrossBoundaryResult, - hash: [u8; 32], - ) -> u64; + ) -> String; + fn evm_try_get_block_number_by_hash(result: &mut CrossBoundaryResult, hash: &str) -> u64; fn evm_try_get_block_header_by_hash( result: &mut CrossBoundaryResult, - hash: [u8; 32], + hash: &str, ) -> EVMBlockHeader; fn evm_try_get_block_count(result: &mut CrossBoundaryResult) -> u64; fn evm_try_get_tx_by_hash( result: &mut CrossBoundaryResult, - tx_hash: [u8; 32], + tx_hash: &str, ) -> EVMTransaction; fn evm_try_create_dst20( result: &mut CrossBoundaryResult, context: u64, - native_hash: [u8; 32], + native_hash: &str, name: &str, symbol: &str, token_id: u64, @@ -203,8 +193,8 @@ pub mod ffi { result: &mut CrossBoundaryResult, context: u64, address: &str, - amount: [u8; 32], - native_hash: [u8; 32], + amount: u64, + native_hash: &str, token_id: u64, out: bool, ); diff --git a/src/ffi/ffiexports.cpp b/src/ffi/ffiexports.cpp index d250f02540..9c1af972bd 100644 --- a/src/ffi/ffiexports.cpp +++ b/src/ffi/ffiexports.cpp @@ -194,9 +194,15 @@ uint64_t getMinRelayTxFee() { return ::minRelayTxFee.GetFeePerK() * 10000000; } -std::array getEthPrivKey(EvmAddressData keyID) { +std::array getEthPrivKey(rust::string key) { + const auto dest = DecodeDestination(std::string(key.begin(), key.length())); + if (dest.index() != WitV16KeyEthHashType) { + return {}; + } + const auto keyID = std::get(dest); + const CKeyID ethKeyID{keyID}; + CKey ethPrivKey; - const auto ethKeyID = CKeyID{uint160{std::vector(keyID.begin(), keyID.end())}}; for (const auto &wallet: GetWallets()) { if (wallet->GetKey(ethKeyID, ethPrivKey)) { std::array privKeyArray{}; diff --git a/src/ffi/ffiexports.h b/src/ffi/ffiexports.h index a19cfbf19d..348f2b55f9 100644 --- a/src/ffi/ffiexports.h +++ b/src/ffi/ffiexports.h @@ -40,7 +40,7 @@ std::array getChainWork(std::array blockHash); rust::vec getPoolTransactions(); uint64_t getNativeTxSize(rust::Vec rawTransaction); uint64_t getMinRelayTxFee(); -std::array getEthPrivKey(EvmAddressData keyID); +std::array getEthPrivKey(rust::string key); rust::string getStateInputJSON(); int getHighestBlock(); int getCurrentHeight(); diff --git a/src/key.h b/src/key.h index 26699ab05e..0857fa6639 100644 --- a/src/key.h +++ b/src/key.h @@ -15,7 +15,8 @@ #include #include -typedef std::array EvmAddressData; +// typedef std::array EvmAddressData; +typedef std::string EvmAddressData; /** * secure_allocator is defined in allocators.h diff --git a/src/key_io.cpp b/src/key_io.cpp index 60890cb473..3a08819283 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -63,8 +63,6 @@ class DestinationEncoder { // Raw addr = ETH_ADDR_PREFIX + HexStr(id); // Produce ERC55 checksum address: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md - // TODO: This should ideally be id.ToString() - // HexStr now is hashing the reversed form. const auto address = HexStr(id); std::vector input(address.begin(), address.end()); std::vector output; diff --git a/src/masternodes/evm.cpp b/src/masternodes/evm.cpp index 4eb30284b0..8486c9ffef 100644 --- a/src/masternodes/evm.cpp +++ b/src/masternodes/evm.cpp @@ -3,45 +3,45 @@ #include #include -Res CVMDomainGraphView::SetVMDomainBlockEdge(VMDomainEdge type, uint256 blockHashKey, uint256 blockHash) +Res CVMDomainGraphView::SetVMDomainBlockEdge(VMDomainEdge type, std::string blockHashKey, std::string blockHash) { return WriteBy(std::pair(static_cast(type), blockHashKey), blockHash) - ? Res::Ok() : DeFiErrors::DatabaseRWFailure(blockHashKey.GetHex()); + ? Res::Ok() : DeFiErrors::DatabaseRWFailure(blockHashKey); } -ResVal CVMDomainGraphView::GetVMDomainBlockEdge(VMDomainEdge type, uint256 blockHashKey) const +ResVal CVMDomainGraphView::GetVMDomainBlockEdge(VMDomainEdge type, std::string blockHashKey) const { - uint256 blockHash; + std::string blockHash; if (ReadBy(std::pair(static_cast(type), blockHashKey), blockHash)) - return ResVal(blockHash, Res::Ok()); - return DeFiErrors::DatabaseKeyNotFound(blockHashKey.GetHex()); + return ResVal(blockHash, Res::Ok()); + return DeFiErrors::DatabaseKeyNotFound(blockHashKey); } -Res CVMDomainGraphView::SetVMDomainTxEdge(VMDomainEdge type, uint256 txHashKey, uint256 txHash) +Res CVMDomainGraphView::SetVMDomainTxEdge(VMDomainEdge type, std::string txHashKey, std::string txHash) { return WriteBy(std::pair(static_cast(type), txHashKey), txHash) - ? Res::Ok() : DeFiErrors::DatabaseRWFailure(txHashKey.GetHex()); + ? Res::Ok() : DeFiErrors::DatabaseRWFailure(txHashKey); } -ResVal CVMDomainGraphView::GetVMDomainTxEdge(VMDomainEdge type, uint256 txHashKey) const +ResVal CVMDomainGraphView::GetVMDomainTxEdge(VMDomainEdge type, std::string txHashKey) const { - uint256 txHash; + std::string txHash; if (ReadBy(std::pair(static_cast(type), txHashKey), txHash)) - return ResVal(txHash, Res::Ok()); - return DeFiErrors::DatabaseKeyNotFound(txHashKey.GetHex()); + return ResVal(txHash, Res::Ok()); + return DeFiErrors::DatabaseKeyNotFound(txHashKey); } -void CVMDomainGraphView::ForEachVMDomainBlockEdges(std::function &, const uint256 &)> callback, const std::pair &start) { - ForEach, uint256>( - [&callback](const std::pair &key, uint256 val) { +void CVMDomainGraphView::ForEachVMDomainBlockEdges(std::function &, const std::string &)> callback, const std::pair &start) { + ForEach, std::string>( + [&callback](const std::pair &key, std::string val) { auto k = std::make_pair(static_cast(key.first), key.second); return callback(k, val); }, std::make_pair(static_cast(start.first), start.second)); } -void CVMDomainGraphView::ForEachVMDomainTxEdges(std::function &, const uint256 &)> callback, const std::pair &start) { - ForEach, uint256>( - [&callback](const std::pair &key, uint256 val) { +void CVMDomainGraphView::ForEachVMDomainTxEdges(std::function &, const std::string &)> callback, const std::pair &start) { + ForEach, std::string>( + [&callback](const std::pair &key, std::string val) { auto k = std::make_pair(static_cast(key.first), key.second); return callback(k, val); }, std::make_pair(static_cast(start.first), start.second)); diff --git a/src/masternodes/evm.h b/src/masternodes/evm.h index cc4973cb6f..8724dc580e 100644 --- a/src/masternodes/evm.h +++ b/src/masternodes/evm.h @@ -35,13 +35,13 @@ struct CEvmTxMessage { class CVMDomainGraphView : public virtual CStorageView { public: - Res SetVMDomainBlockEdge(VMDomainEdge type, uint256 blockHashKey, uint256 blockHash); - ResVal GetVMDomainBlockEdge(VMDomainEdge type, uint256 blockHashKey) const; - void ForEachVMDomainBlockEdges(std::function &, const uint256 &)> callback, const std::pair &start = {}); + Res SetVMDomainBlockEdge(VMDomainEdge type, std::string blockHashKey, std::string blockHash); + ResVal GetVMDomainBlockEdge(VMDomainEdge type, std::string blockHashKey) const; + void ForEachVMDomainBlockEdges(std::function &, const std::string &)> callback, const std::pair &start = {}); - Res SetVMDomainTxEdge(VMDomainEdge type, uint256 txHashKey, uint256 txHash); - ResVal GetVMDomainTxEdge(VMDomainEdge type, uint256 txHashKey) const; - void ForEachVMDomainTxEdges(std::function &, const uint256 &)> callback, const std::pair &start = {}); + Res SetVMDomainTxEdge(VMDomainEdge type, std::string txHashKey, std::string txHash); + ResVal GetVMDomainTxEdge(VMDomainEdge type, std::string txHashKey) const; + void ForEachVMDomainTxEdges(std::function &, const std::string &)> callback, const std::pair &start = {}); struct VMDomainBlockEdge { static constexpr uint8_t prefix() { return 'N'; } diff --git a/src/masternodes/govvariables/attributes.cpp b/src/masternodes/govvariables/attributes.cpp index 2dabf6b273..89be581691 100644 --- a/src/masternodes/govvariables/attributes.cpp +++ b/src/masternodes/govvariables/attributes.cpp @@ -1820,7 +1820,7 @@ Res ATTRIBUTES::Validate(const CCustomCSView &view) const { evmQueueId && !evm_try_is_dst20_deployed_or_queued(result, evmQueueId, token->name, token->symbol, tokenID.v)) { - evm_try_create_dst20(result, evmQueueId, token->creationTx.GetByteArray(), + evm_try_create_dst20(result, evmQueueId, token->creationTx.GetHex(), token->name, token->symbol, tokenID.v); diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index 967c0630b7..ae65635b44 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -769,7 +769,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { uint64_t time; uint32_t txn; uint64_t evmQueueId; - bool prevalidateEvm; + bool evmSanityCheckOnly; bool isEvmEnabledForBlock; public: @@ -781,14 +781,14 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { uint64_t time, uint32_t txn, const uint64_t evmQueueId, - const bool prevalidateEvm, + const bool evmSanityCheckOnly, const bool isEvmEnabledForBlock) : CCustomTxVisitor(tx, height, coins, mnview, consensus), time(time), txn(txn), evmQueueId(evmQueueId), - prevalidateEvm(prevalidateEvm), + evmSanityCheckOnly(evmSanityCheckOnly), isEvmEnabledForBlock(isEvmEnabledForBlock) {} Res operator()(const CCreateMasterNodeMessage &obj) const { @@ -1073,7 +1073,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { if (tokenId && token.IsDAT() && isEvmEnabledForBlock) { CrossBoundaryResult result; - evm_try_create_dst20(result, evmQueueId, tx.GetHash().GetByteArray(), + evm_try_create_dst20(result, evmQueueId, tx.GetHash().GetHex(), rust::string(tokenName.c_str()), rust::string(tokenSymbol.c_str()), tokenId->v); @@ -3911,22 +3911,20 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { CTxDestination dest; ExtractDestination(dst.address, dest); const auto toAddress = std::get(dest); - arith_uint256 balanceIn = dst.amount.nValue; + + // Safety: Safe since validate checks for < 0 + const auto balanceIn = static_cast(dst.amount.nValue); auto tokenId = dst.amount.nTokenId; - balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; CrossBoundaryResult result; if (tokenId == DCT_ID{0}) { - evm_unsafe_try_add_balance_in_q(result, evmQueueId, HexStr(toAddress.begin(), toAddress.end()), - ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray()); + evm_unsafe_try_add_balance_in_q(result, evmQueueId, toAddress.ToHexString(), balanceIn, tx.GetHash().GetHex()); if (!result.ok) { return Res::Err("Error bridging DFI: %s", result.reason); } } else { CrossBoundaryResult result; - evm_try_bridge_dst20(result, evmQueueId, HexStr(toAddress.begin(), toAddress.end()), - ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray(), tokenId.v, false); - + evm_try_bridge_dst20(result, evmQueueId, toAddress.ToHexString(), balanceIn, tx.GetHash().GetHex(), tokenId.v, false); if (!result.ok) { return Res::Err("Error bridging DST20: %s", result.reason); } @@ -3939,13 +3937,13 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { CTxDestination dest; ExtractDestination(src.address, dest); const auto fromAddress = std::get(dest); - arith_uint256 balanceIn = src.amount.nValue; + + // Safety: Safe since validate checks for < 0 + const auto balanceIn = static_cast(src.amount.nValue); auto tokenId = dst.amount.nTokenId; - balanceIn *= CAMOUNT_TO_GWEI * WEI_IN_GWEI; if (tokenId == DCT_ID{0}) { CrossBoundaryResult result; - if (!evm_unsafe_try_sub_balance_in_q(result, evmQueueId, HexStr(fromAddress.begin(), fromAddress.end()), - ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray())) { + if (!evm_unsafe_try_sub_balance_in_q(result, evmQueueId, fromAddress.ToHexString(), balanceIn, tx.GetHash().GetHex())) { return DeFiErrors::TransferDomainNotEnoughBalance(EncodeDestination(dest)); } if (!result.ok) { @@ -3954,9 +3952,7 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { } else { CrossBoundaryResult result; - evm_try_bridge_dst20(result, evmQueueId, HexStr(fromAddress.begin(), fromAddress.end()), - ArithToUint256(balanceIn).GetByteArray(), tx.GetHash().GetByteArray(), tokenId.v, true); - + evm_try_bridge_dst20(result, evmQueueId, fromAddress.ToHexString(), balanceIn, tx.GetHash().GetHex(), tokenId.v, true); if (!result.ok) { return Res::Err("Error bridging DST20: %s", result.reason); } @@ -3996,38 +3992,38 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor { CrossBoundaryResult result; ValidateTxCompletion validateResults; - if (!prevalidateEvm) { - 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_unsafe_try_push_tx_in_q(result, evmQueueId, HexStr(obj.evmTx), tx.GetHash().GetByteArray(), validateResults.gas_used); - if (!result.ok) { - 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_unsafe_try_prevalidate_raw_tx(result, HexStr(obj.evmTx)); + if (evmSanityCheckOnly) { + validateResults = 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); } + return Res::Ok(); } - auto txHash = tx.GetHash(); - auto evmTxHashBytes = std::vector(validateResults.tx_hash.begin(), validateResults.tx_hash.end()); - auto evmTxHash = uint256S(HexStr(evmTxHashBytes)); + validateResults = evm_unsafe_try_validate_raw_tx_in_q(result, HexStr(obj.evmTx), evmQueueId); + 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_unsafe_try_push_tx_in_q(result, evmQueueId, HexStr(obj.evmTx), tx.GetHash().GetHex(), validateResults.gas_used); + if (!result.ok) { + 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); + } + + + auto txHash = tx.GetHash().GetHex(); + auto evmTxHash = std::string(validateResults.tx_hash.data(), validateResults.tx_hash.length()).substr(2); auto res = mnview.SetVMDomainTxEdge(VMDomainEdge::DVMToEVM, txHash, evmTxHash); if (!res) { - LogPrintf("Failed to store DVMtoEVM TX hash for DFI TX %s\n", txHash.ToString()); + LogPrintf("Failed to store DVMtoEVM TX hash for DFI TX %s\n", txHash); } res = mnview.SetVMDomainTxEdge(VMDomainEdge::EVMToDVM, evmTxHash, txHash); if (!res) { - LogPrintf("Failed to store EVMToDVM TX hash for DFI TX %s\n", txHash.ToString()); + LogPrintf("Failed to store EVMToDVM TX hash for DFI TX %s\n", txHash); } return Res::Ok(); } @@ -4133,6 +4129,11 @@ Res ValidateTransferDomainEdge(const CTransaction &tx, if (src.amount.nTokenId != dst.amount.nTokenId) return DeFiErrors::TransferDomainDifferentTokens(); + // We allow 0 here, just if we need to touch something + // on either sides or special case later. + if (src.amount.nValue < 0) + return DeFiErrors::TransferDomainInvalid(); + auto tokenId = src.amount.nTokenId; if (tokenId != DCT_ID{0}) { @@ -4281,16 +4282,16 @@ Res CustomTxVisit(CCustomCSView &mnview, } auto q = evmQueueId; - bool prevalidateEvm = false; + bool evmSanityCheckOnly = false; if (q == 0) { - prevalidateEvm = true; + evmSanityCheckOnly = true; auto r = XResultValue(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, q, prevalidateEvm, isEvmEnabledForBlock), + CCustomTxApplyVisitor(tx, height, coins, mnview, consensus, time, txn, q, evmSanityCheckOnly, isEvmEnabledForBlock), txMessage); } catch (const std::bad_variant_access &e) { return Res::Err(e.what()); @@ -5271,10 +5272,10 @@ bool IsTransferDomainEnabled(const int height, const CCustomCSView &view, const UniValue EVM::ToUniValue() const { UniValue obj(UniValue::VOBJ); obj.pushKV("version", static_cast(version)); - obj.pushKV("blockHash", "0x" + blockHash.GetHex()); + obj.pushKV("blockHash", "0x" + blockHash); obj.pushKV("burntFee", burntFee); obj.pushKV("priorityFee", priorityFee); - obj.pushKV("beneficiary", "0x" + HexStr(beneficiary)); + obj.pushKV("beneficiary", "0x" + beneficiary); return obj; } diff --git a/src/masternodes/mn_checks.h b/src/masternodes/mn_checks.h index 1f73d83529..e88a824e95 100644 --- a/src/masternodes/mn_checks.h +++ b/src/masternodes/mn_checks.h @@ -23,7 +23,7 @@ class CCustomCSView; struct EVM { uint32_t version; - uint256 blockHash; + std::string blockHash; uint64_t burntFee; uint64_t priorityFee; EvmAddressData beneficiary; diff --git a/src/masternodes/rpc_accounts.cpp b/src/masternodes/rpc_accounts.cpp index 238d0a4867..e13299554f 100644 --- a/src/masternodes/rpc_accounts.cpp +++ b/src/masternodes/rpc_accounts.cpp @@ -477,9 +477,7 @@ UniValue getaccount(const JSONRPCRequest& request) { CTxDestination dest; if (ExtractDestination(reqOwner, dest) && dest.index() == WitV16KeyEthHashType) { const auto keyID = std::get(dest); - EvmAddressData address{}; - std::copy(keyID.begin(), keyID.end(), address.begin()); - auto r = XResultValue(evm_try_get_balance(result, address)); + auto r = XResultValue(evm_try_get_balance(result, keyID.ToHexString())); if (!r) throw JSONRPCError(RPC_MISC_ERROR, r.msg); if (const auto balance = *r) { balances[DCT_ID{}] = balance; @@ -606,9 +604,8 @@ UniValue gettokenbalances(const JSONRPCRequest& request) { if (evm_dfi_lookup) { for (const auto keyID : pwallet->GetKeys()) { - EvmAddressData address{}; - std::copy(keyID.begin(), keyID.end(), address.begin()); - auto res = XResultValue(evm_try_get_balance(result, address)); + // TODO: Use GetHex when eth key is fixed to be stored in LE + auto res = XResultValue(evm_try_get_balance(result, HexStr(keyID))); if (res) { auto evmAmount = *res; totalBalances.Add({{}, static_cast(evmAmount)}); diff --git a/src/masternodes/rpc_customtx.cpp b/src/masternodes/rpc_customtx.cpp index b97b70df33..3cac50fa13 100644 --- a/src/masternodes/rpc_customtx.cpp +++ b/src/masternodes/rpc_customtx.cpp @@ -576,10 +576,10 @@ class CCustomTxRpcVisitor { } void operator()(const CEvmTxMessage &obj) const { - auto txHash = tx.GetHash(); + auto txHash = tx.GetHash().GetHex(); if (auto evmTxHash = mnview.GetVMDomainTxEdge(VMDomainEdge::DVMToEVM, txHash)) { CrossBoundaryResult result; - auto txInfo = evm_try_get_tx_by_hash(result, evmTxHash->GetByteArray()); + auto txInfo = evm_try_get_tx_by_hash(result, *evmTxHash); if (result.ok) { std::string tx_type; switch (txInfo.tx_type) { @@ -600,18 +600,15 @@ class CCustomTxRpcVisitor { } } rpcInfo.pushKV("type", tx_type); - rpcInfo.pushKV("hash", evmTxHash->ToString()); - rpcInfo.pushKV("sender", EncodeDestination(CTxDestination(WitnessV16EthHash(uint160::FromByteArray(txInfo.sender))))); + rpcInfo.pushKV("hash", *evmTxHash); + rpcInfo.pushKV("sender", std::string(txInfo.sender.data(), txInfo.sender.length())); rpcInfo.pushKV("nonce", txInfo.nonce); rpcInfo.pushKV("gasPrice", txInfo.gas_price); rpcInfo.pushKV("gasLimit", txInfo.gas_limit); rpcInfo.pushKV("maxFeePerGas", txInfo.max_fee_per_gas); rpcInfo.pushKV("maxPriorityFeePerGas", txInfo.max_priority_fee_per_gas); rpcInfo.pushKV("createTx", txInfo.create_tx); - std::string to = ""; - if (!txInfo.create_tx) - to = EncodeDestination(CTxDestination(WitnessV16EthHash(uint160::FromByteArray(txInfo.to)))); - rpcInfo.pushKV("to", to); + rpcInfo.pushKV("to", std::string(txInfo.to.data(), txInfo.to.length())); rpcInfo.pushKV("value", txInfo.value); } } diff --git a/src/masternodes/rpc_evm.cpp b/src/masternodes/rpc_evm.cpp index 7a82f34022..2f5eff52aa 100644 --- a/src/masternodes/rpc_evm.cpp +++ b/src/masternodes/rpc_evm.cpp @@ -54,7 +54,7 @@ UniValue evmtx(const JSONRPCRequest &request) { {"gasPrice", RPCArg::Type::NUM, RPCArg::Optional::NO, "Gas Price in Gwei"}, {"gasLimit", RPCArg::Type::NUM, RPCArg::Optional::NO, "Gas limit"}, {"to", RPCArg::Type::STR, RPCArg::Optional::NO, "To address. Can be empty"}, - {"value", RPCArg::Type::NUM, RPCArg::Optional::NO, "Amount to send"}, + {"value", RPCArg::Type::NUM, RPCArg::Optional::NO, "Amount to send in DFI"}, {"data", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Hex encoded data. Can be blank."}, }, RPCResult{"\"hash\" (string) The hex-encoded hash of broadcasted transaction\n"}, @@ -90,18 +90,16 @@ UniValue evmtx(const JSONRPCRequest &request) { // TODO Get chain ID from Params when defined const uint64_t chainID{1}; - const arith_uint256 nonceParam = request.params[1].get_int64(); - const auto nonce = ArithToUint256(nonceParam); - - arith_uint256 gasPriceArith = request.params[2].get_int64(); // Price as GWei - gasPriceArith *= WEI_IN_GWEI; // Convert to Wei - const uint256 gasPrice = ArithToUint256(gasPriceArith); - - arith_uint256 gasLimitArith = request.params[3].get_int64(); - const uint256 gasLimit = ArithToUint256(gasLimitArith); + if (request.params[1].get_int64() < 0 || request.params[2].get_int64() < 0 || request.params[3].get_int64() < 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Input params cannot be negative"); + } + const auto nonce = static_cast(request.params[1].get_int64()); + const auto gasPrice = static_cast(request.params[2].get_int64()); // Price as GWei + const auto gasLimit = static_cast(request.params[3].get_int64()); + const uint64_t value = AmountFromValue(request.params[5]); // Amount in CAmount const auto toStr = request.params[4].get_str(); - EvmAddressData to{}; + std::string to = ""; if (!toStr.empty()) { const auto toDest = DecodeDestination(toStr); if (toDest.index() != WitV16KeyEthHashType) { @@ -109,12 +107,9 @@ UniValue evmtx(const JSONRPCRequest &request) { } const auto toEth = std::get(toDest); - std::copy(toEth.begin(), toEth.end(), to.begin()); + to = toEth.ToHexString(); } - const arith_uint256 valueParam = AmountFromValue(request.params[5]); - const auto value = ArithToUint256(valueParam * CAMOUNT_TO_GWEI * WEI_IN_GWEI); - rust::Vec input{}; if (!request.params[6].isNull()) { const auto inputStr = request.params[6].get_str(); @@ -133,11 +128,11 @@ UniValue evmtx(const JSONRPCRequest &request) { CrossBoundaryResult result; const auto signedTx = evm_try_create_and_sign_tx(result, CreateTransactionContext{chainID, - nonce.GetByteArray(), - gasPrice.GetByteArray(), - gasLimit.GetByteArray(), + nonce, + gasPrice, + gasLimit, to, - value.GetByteArray(), + value, input, privKey}); if (!result.ok) { @@ -205,14 +200,22 @@ UniValue vmmap(const JSONRPCRequest &request) { return str; }; - const std::string input = request.params[0].get_str(); + auto ensureEVMHashStripped = [](const std::string &str) { + if (str.length() > 2 && str.substr(0, 2) == "0x") { + return str.substr(2); + } + return str; + }; + + const auto inputStr = request.params[0].get_str(); + const auto input = ensureEVMHashStripped(inputStr); int typeInt = request.params[1].get_int(); if (typeInt < 0 || typeInt >= VMDomainRPCMapTypeCount) { throwInvalidParam(); } - auto tryResolveMapBlockOrTxResult = [](ResVal &res, const uint256 input) { + auto tryResolveMapBlockOrTxResult = [](ResVal &res, const std::string input) { res = pcustomcsview->GetVMDomainTxEdge(VMDomainEdge::DVMToEVM, input); if (res) return VMDomainRPCMapType::TxHashDVMToEVM; @@ -263,7 +266,7 @@ UniValue vmmap(const JSONRPCRequest &request) { }; */ auto type = static_cast(typeInt); - ResVal res = ResVal(uint256{}, Res::Ok()); + ResVal res = ResVal(std::string{}, Res::Ok()); auto handleAutoInfer = [&]() -> std::tuple { // auto mapType = tryResolveBlockNumberType(input); @@ -272,7 +275,7 @@ UniValue vmmap(const JSONRPCRequest &request) { auto inLength = input.length(); if (inLength == 64 || inLength == 66) { - auto mapType = tryResolveMapBlockOrTxResult(res, uint256S(input)); + auto mapType = tryResolveMapBlockOrTxResult(res, input); // We don't pass this type back on purpose if (mapType != VMDomainRPCMapType::Unknown) { return {mapType, true}; @@ -282,14 +285,14 @@ UniValue vmmap(const JSONRPCRequest &request) { return {VMDomainRPCMapType::Unknown, false}; }; - auto finalizeResult = [&](ResVal &res, const VMDomainRPCMapType type, const std::string input) { + auto finalizeResult = [&](ResVal &res, const VMDomainRPCMapType type, const std::string input) { if (!res) { throw JSONRPCError(RPC_INVALID_REQUEST, res.msg); } else { UniValue ret(UniValue::VOBJ); - ret.pushKV("input", input); + ret.pushKV("input", inputStr); ret.pushKV("type", GetVMDomainRPCMapType(type)); - ret.pushKV("output", ensureEVMHashPrefixed(res.val->ToString(), type)); + ret.pushKV("output", ensureEVMHashPrefixed(*res.val, type)); return ret; } }; @@ -312,10 +315,9 @@ UniValue vmmap(const JSONRPCRequest &request) { } CrossBoundaryResult result; auto evmHash = evm_try_get_block_hash_by_number(result, height); + auto evmBlockHash = std::string(evmHash.data(), evmHash.length()); crossBoundaryOkOrThrow(result); - auto evmBlockHash = std::vector(evmHash.begin(), evmHash.end()); - std::reverse(evmBlockHash.begin(), evmBlockHash.end()); - ResVal dvm_block = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, uint256(evmBlockHash)); + ResVal dvm_block = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash); if (!dvm_block) { throwInvalidParam(dvm_block.msg); } @@ -335,12 +337,12 @@ UniValue vmmap(const JSONRPCRequest &request) { } CBlockIndex *pindex = ::ChainActive()[height]; auto evmBlockHash = - pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::DVMToEVM, uint256S(pindex->GetBlockHash().GetHex())); + pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::DVMToEVM, pindex->GetBlockHash().GetHex()); if (!evmBlockHash.val.has_value()) { throwInvalidParam(evmBlockHash.msg); } CrossBoundaryResult result; - uint64_t blockNumber = evm_try_get_block_number_by_hash(result, evmBlockHash.val.value().GetByteArray()); + uint64_t blockNumber = evm_try_get_block_number_by_hash(result, *evmBlockHash.val); crossBoundaryOkOrThrow(result); return finalizeBlockNumberResult(blockNumber, VMDomainRPCMapType::BlockNumberDVMToEVM, height); }; @@ -357,19 +359,19 @@ UniValue vmmap(const JSONRPCRequest &request) { switch (type) { case VMDomainRPCMapType::TxHashDVMToEVM: { - res = pcustomcsview->GetVMDomainTxEdge(VMDomainEdge::DVMToEVM, uint256S(input)); + res = pcustomcsview->GetVMDomainTxEdge(VMDomainEdge::DVMToEVM, input); break; } case VMDomainRPCMapType::TxHashEVMToDVM: { - res = pcustomcsview->GetVMDomainTxEdge(VMDomainEdge::EVMToDVM, uint256S(input)); + res = pcustomcsview->GetVMDomainTxEdge(VMDomainEdge::EVMToDVM, input); break; } case VMDomainRPCMapType::BlockHashDVMToEVM: { - res = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::DVMToEVM, uint256S(input)); + res = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::DVMToEVM, input); break; } case VMDomainRPCMapType::BlockHashEVMToDVM: { - res = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, uint256S(input)); + res = pcustomcsview->GetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, input); break; } // TODO(canonbrother): disable for release, more investigation needed @@ -417,50 +419,50 @@ UniValue logvmmaps(const JSONRPCRequest &request) { switch (type) { case VMDomainIndexType::BlockHashDVMToEVM: { pcustomcsview->ForEachVMDomainBlockEdges( - [&](const std::pair &index, const uint256 &blockHash) { + [&](const std::pair &index, const std::string &blockHash) { if (index.first == VMDomainEdge::DVMToEVM) { - indexesJson.pushKV(index.second.GetHex(), blockHash.GetHex()); + indexesJson.pushKV(index.second, blockHash); ++count; } return true; }, - std::make_pair(VMDomainEdge::DVMToEVM, uint256{})); + std::make_pair(VMDomainEdge::DVMToEVM, std::string{})); break; } case VMDomainIndexType::BlockHashEVMToDVM: { pcustomcsview->ForEachVMDomainBlockEdges( - [&](const std::pair &index, const uint256 &blockHash) { + [&](const std::pair &index, const std::string &blockHash) { if (index.first == VMDomainEdge::EVMToDVM) { - indexesJson.pushKV(index.second.GetHex(), blockHash.GetHex()); + indexesJson.pushKV(index.second, blockHash); ++count; } return true; }, - std::make_pair(VMDomainEdge::EVMToDVM, uint256{})); + std::make_pair(VMDomainEdge::EVMToDVM, std::string{})); break; } case VMDomainIndexType::TxHashDVMToEVM: { pcustomcsview->ForEachVMDomainTxEdges( - [&](const std::pair &index, const uint256 &txHash) { + [&](const std::pair &index, const std::string &txHash) { if (index.first == VMDomainEdge::DVMToEVM) { - indexesJson.pushKV(index.second.GetHex(), txHash.GetHex()); + indexesJson.pushKV(index.second, txHash); ++count; } return true; }, - std::make_pair(VMDomainEdge::DVMToEVM, uint256{})); + std::make_pair(VMDomainEdge::DVMToEVM, std::string{})); break; } case VMDomainIndexType::TxHashEVMToDVM: { pcustomcsview->ForEachVMDomainTxEdges( - [&](const std::pair &index, const uint256 &txHash) { + [&](const std::pair &index, const std::string &txHash) { if (index.first == VMDomainEdge::EVMToDVM) { - indexesJson.pushKV(index.second.GetHex(), txHash.GetHex()); + indexesJson.pushKV(index.second, txHash); ++count; } return true; }, - std::make_pair(VMDomainEdge::EVMToDVM, uint256{})); + std::make_pair(VMDomainEdge::EVMToDVM, std::string{})); break; } default: diff --git a/src/masternodes/validation.cpp b/src/masternodes/validation.cpp index 6cfe400005..82b23cf907 100644 --- a/src/masternodes/validation.cpp +++ b/src/masternodes/validation.cpp @@ -2382,8 +2382,8 @@ static void RevertFailedTransferDomainTxs(const std::vector &failed } static Res ValidateCoinbaseXVMOutput(const XVM &xvm, const FinalizeBlockCompletion &blockResult) { - const auto blockResultBlockHash = uint256::FromByteArray(blockResult.block_hash); - + const auto blockResultBlockHash = std::string(blockResult.block_hash.data(), blockResult.block_hash.length()).substr(2); + if (xvm.evm.blockHash != blockResultBlockHash) { return Res::Err("Incorrect EVM block hash in coinbase output"); } @@ -2444,9 +2444,6 @@ static Res ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCust if (!result.ok) { return Res::Err(result.reason.c_str()); } - auto evmBlockHashData = std::vector(blockResult.block_hash.rbegin(), blockResult.block_hash.rend()); - auto evmBlockHash = uint256(evmBlockHashData); - if (block.vtx[0]->vout.size() < 2) { return Res::Err("Not enough outputs in coinbase TX"); } @@ -2454,10 +2451,11 @@ static Res ProcessEVMQueue(const CBlock &block, const CBlockIndex *pindex, CCust auto res = ValidateCoinbaseXVMOutput(*xvmRes, blockResult); if (!res) return res; - res = cache.SetVMDomainBlockEdge(VMDomainEdge::DVMToEVM, block.GetHash(), evmBlockHash); + auto evmBlockHash = std::string(blockResult.block_hash.data(), blockResult.block_hash.length()).substr(2); + res = cache.SetVMDomainBlockEdge(VMDomainEdge::DVMToEVM, block.GetHash().GetHex(), evmBlockHash); if (!res) return res; - res = cache.SetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash, block.GetHash()); + res = cache.SetVMDomainBlockEdge(VMDomainEdge::EVMToDVM, evmBlockHash, block.GetHash().GetHex()); if (!res) return res; if (!blockResult.failed_transactions.empty()) { diff --git a/src/miner.cpp b/src/miner.cpp index da8841969f..af76061515 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -293,7 +293,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc auto r = XResultStatusLogged(evm_unsafe_try_remove_queue(result, evmQueueId)); if (!r) { return nullptr; } - xvm = XVM{0, {0, uint256::FromByteArray(blockResult.block_hash), blockResult.total_burnt_fees, blockResult.total_priority_fees, evmBeneficiary}}; + xvm = XVM{0, {0, std::string(blockResult.block_hash.data(), blockResult.block_hash.length()).substr(2), blockResult.total_burnt_fees, blockResult.total_priority_fees, evmBeneficiary}}; // LogPrintf("DEBUG:: CreateNewBlock:: xvm-init:: %s\n", xvm.ToUniValue().write()); std::set failedTransactions; @@ -393,7 +393,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc } if (isEvmEnabledForBlock) { - if (xvm.evm.blockHash.IsNull()) { + if (xvm.evm.blockHash.empty()) { LogPrint(BCLog::STAKING, "%s: EVM block hash is null\n", __func__); return nullptr; } @@ -666,7 +666,8 @@ bool BlockAssembler::EvmTxPreapply(const EvmTxPreApplyContext& ctx) auto& evmFeeMap = pkgCtx.feeMap; auto& evmAddressTxsMap = pkgCtx.addressTxsMap; - const auto addrKey = EvmAddressWithNonce{txResult.sender, txResult.nonce}; + const auto txResultSender = std::string(txResult.sender.data(), txResult.sender.length()); + const auto addrKey = EvmAddressWithNonce{txResultSender, txResult.nonce}; if (auto feeEntry = evmFeeMap.find(addrKey); feeEntry != evmFeeMap.end()) { // Key already exists. We check to see if we need to prioritize higher fee tx const auto& lastFee = feeEntry->second; @@ -699,7 +700,7 @@ bool BlockAssembler::EvmTxPreapply(const EvmTxPreApplyContext& ctx) } } - const auto nonce = evm_unsafe_try_get_next_valid_nonce_in_q(result, evmQueueId, txResult.sender); + const auto nonce = evm_unsafe_try_get_next_valid_nonce_in_q(result, evmQueueId, txResultSender); if (!result.ok) { return false; } @@ -711,9 +712,9 @@ bool BlockAssembler::EvmTxPreapply(const EvmTxPreApplyContext& ctx) return false; } - auto addrNonce = EvmAddressWithNonce{txResult.sender, txResult.nonce}; + auto addrNonce = EvmAddressWithNonce{txResultSender, txResult.nonce}; evmFeeMap.insert({addrNonce, txResult.prepay_fee}); - evmAddressTxsMap[txResult.sender].emplace(txResult.nonce, txIter); + evmAddressTxsMap[txResultSender].emplace(txResult.nonce, txIter); return true; } @@ -1138,7 +1139,8 @@ Staker::Status Staker::stake(const CChainParams& chainparams, const ThreadStaker if (pubKey.IsCompressed()) { pubKey.Decompress(); } - const auto evmBeneficiary = pubKey.GetEthID().GetByteArray(); + // TODO: Use GetHex when eth key is fixed to be stored in LE + const auto evmBeneficiary = HexStr(pubKey.GetEthID()); auto pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey, blockTime, evmBeneficiary); if (!pblocktemplate) { LogPrintf("Error: WalletStaker: Keypool ran out, keypoolrefill and restart required\n"); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index de2b3ed484..9eabe391ca 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -270,10 +270,10 @@ struct RewardInfo { std::optional VmInfoUniv(const CTransaction& tx) { auto evmBlockHeaderToUniValue = [](const EVMBlockHeader& header) { UniValue r(UniValue::VOBJ); - r.pushKV("parenthash", uint256::FromByteArray(header.parent_hash).ToString()); - r.pushKV("beneficiary", uint160::FromByteArray(header.beneficiary).ToString()); - r.pushKV("stateRoot", uint256::FromByteArray(header.state_root).ToString()); - r.pushKV("receiptRoot", uint256::FromByteArray(header.receipts_root).ToString()); + r.pushKV("parenthash", std::string(header.parent_hash.data(), header.parent_hash.length())); + r.pushKV("beneficiary", std::string(header.beneficiary.data(), header.beneficiary.length())); + r.pushKV("stateRoot", std::string(header.state_root.data(), header.state_root.length())); + r.pushKV("receiptRoot", std::string(header.receipts_root.data(), header.receipts_root.length())); r.pushKV("number", header.number); r.pushKV("gasLimit", header.gas_limit); r.pushKV("gasUsed", header.gas_used); @@ -283,40 +283,40 @@ std::optional VmInfoUniv(const CTransaction& tx) { return r; }; - CustomTxType guess; - UniValue txResults(UniValue::VOBJ); - if (tx.IsCoinBase()) { - if (tx.vout.size() < 2) { - // TODO: Decode vout 0 to dvm + CustomTxType guess; + UniValue txResults(UniValue::VOBJ); + if (tx.IsCoinBase()) { + if (tx.vout.size() < 2) { + // TODO: Decode vout 0 to dvm + return {}; + } + auto tx1ScriptPubKey = tx.vout[1].scriptPubKey; + if (tx1ScriptPubKey.size() == 0) return {}; + auto xvm = XVM::TryFrom(tx1ScriptPubKey); + if (!xvm) return {}; + UniValue result(UniValue::VOBJ); + result.pushKV("vmtype", "coinbase"); + result.pushKV("txtype", "coinbase"); + result.pushKV("msg", xvm->ToUniValue()); + CrossBoundaryResult res; + auto evmBlockHeader = evm_try_get_block_header_by_hash(res, xvm->evm.blockHash); + if (!res.ok) return {}; + result.pushKV("xvmHeader", evmBlockHeaderToUniValue(evmBlockHeader)); + return result; + } + auto res = RpcInfo(tx, std::numeric_limits::max(), guess, txResults); + if (guess == CustomTxType::None) { return {}; } - auto tx1ScriptPubKey = tx.vout[1].scriptPubKey; - if (tx1ScriptPubKey.size() == 0) return {}; - auto xvm = XVM::TryFrom(tx1ScriptPubKey); - if (!xvm) return {}; UniValue result(UniValue::VOBJ); - result.pushKV("vmtype", "coinbase"); - result.pushKV("txtype", "coinbase"); - result.pushKV("msg", xvm->ToUniValue()); - CrossBoundaryResult res; - auto evmBlockHeader = evm_try_get_block_header_by_hash(res, xvm->evm.blockHash.GetByteArray()); - if (!res.ok) return {}; - result.pushKV("xvmHeader", evmBlockHeaderToUniValue(evmBlockHeader)); + result.pushKV("vmtype", guess == CustomTxType::EvmTx ? "evm" : "dvm"); + result.pushKV("txtype", ToString(guess)); + if (!res.ok) { + result.pushKV("error", res.msg); + } else { + result.pushKV("msg", txResults); + } return result; - } - auto res = RpcInfo(tx, std::numeric_limits::max(), guess, txResults); - if (guess == CustomTxType::None) { - return {}; - } - UniValue result(UniValue::VOBJ); - result.pushKV("vmtype", guess == CustomTxType::EvmTx ? "evm" : "dvm"); - result.pushKV("txtype", ToString(guess)); - if (!res.ok) { - result.pushKV("error", res.msg); - } else { - result.pushKV("msg", txResults); - } - return result; } UniValue ExtendedTxToUniv(const CTransaction& tx, bool include_hex, int serialize_flags, int version, bool txDetails) { diff --git a/src/script/standard.cpp b/src/script/standard.cpp index cb20c0b181..5b2a108f94 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -29,6 +29,11 @@ WitnessV0KeyHash::WitnessV0KeyHash(const CPubKey& pubkey) : uint160(pubkey.GetID WitnessV16EthHash::WitnessV16EthHash(const CPubKey& pubkey) : uint160(pubkey.GetEthID()) {} +// TO DO: Remove this temporary fix to return hex string, once EthHash is switched from big endian to little endian. +std::string WitnessV16EthHash::ToHexString() const { + return HexStr(data, data + sizeof(data)); +} + const char* GetTxnOutputType(txnouttype t) { switch (t) diff --git a/src/script/standard.h b/src/script/standard.h index 42442b0882..140688fe37 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -114,6 +114,7 @@ struct WitnessV16EthHash : public uint160 { WitnessV16EthHash() : uint160() {} explicit WitnessV16EthHash(const uint160& hash) : uint160(hash) {} explicit WitnessV16EthHash(const CPubKey& pubkey); + std::string ToHexString() const; using uint160::uint160; }; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index d6efa71811..840689656f 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -775,34 +775,24 @@ BOOST_AUTO_TEST_CASE(test_CreateEthTx) { // Address 0xf829754bae400b679febefdcfc9944c323e1f94e const uint64_t chainID{5}; // Goerli testnetwork - - // Check address on explorer to calc nonce - const std::vector nonceVec{ParseHex("0000000000000000000000000000000000000000000000000000000000000000")}; - std::array nonce{}; - std::copy(nonceVec.begin(), nonceVec.end(), nonce.begin()); // Not need with nonce 0 but useful later - - const uint256 gasPrice{uint256S("689451EEE1")}; // 449.164996321 Gwei - const uint256 gasLimit{uint256S("5208")}; // 21,000 - - std::vector toVec{ParseHex("34c1ca09a2dc717d89baef2f30ff6a6b2975e17e")}; - EvmAddressData to{}; - std::copy(toVec.begin(), toVec.end(), to.begin()); - - std::array value{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,ParseHex("23")[0],ParseHex("86")[0],ParseHex("F2")[0],ParseHex("6F")[0],ParseHex("C1")[0],0,0}; // 0.01 Eth + uint64_t nonce = 0; + const uint64_t gasPrice = 449; // 449 GWei + const uint64_t gasLimit = 21000; // 21_000 + std::string to = "34c1ca09a2dc717d89baef2f30ff6a6b2975e17e"; + uint64_t value = 1000000; // 0.01 DFI const std::vector privKeyVec{ParseHex("1a8ec29c671461a375ee1fb193ab3b64ab5449837e060362daadd4b299ae5571")}; std::array privKey{}; std::copy(privKeyVec.begin(), privKeyVec.end(), privKey.begin()); - rust::Vec input{}; CrossBoundaryResult result; - const auto reply = evm_try_create_and_sign_tx(result, CreateTransactionContext{chainID, nonce, gasPrice.GetByteArray(), gasLimit.GetByteArray(), to, value, input, privKey}); + const auto reply = evm_try_create_and_sign_tx(result, CreateTransactionContext{chainID, nonce, gasPrice, gasLimit, to, value, input, privKey}); std::vector replyVector(reply.size()); std::copy(reply.begin(), reply.end(), replyVector.begin()); std::string transaction(HexStr(replyVector.begin(), replyVector.end())); const auto rawBytes = ParseHex(transaction); - BOOST_CHECK_EQUAL(transaction, "f86b8085689451eee18252089434c1ca09a2dc717d89baef2f30ff6a6b2975e17e872386f26fc10000802da0ae5c76f8073460cbc7a911d3cc1b367072db64848a9532343559ce6917c51a46a01d2e4928450c59acca3de8340eb15b7446b37936265a51ab35e63f749a048002"); + BOOST_CHECK_EQUAL(transaction, "f86b8085688a7c4a008252089434c1ca09a2dc717d89baef2f30ff6a6b2975e17e872386f26fc10000802ea0faaabaa535de3859c7ee5f924545fcaa071a3516ce7ef1e6dc91faceef9b7c7fa053d23409fc611d228c818111aa75d04e3701ea7944f8e2d7fd8cd695c21399f5"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/xvm_tests.cpp b/src/test/xvm_tests.cpp index 117517204d..c00939bad0 100644 --- a/src/test/xvm_tests.cpp +++ b/src/test/xvm_tests.cpp @@ -17,38 +17,28 @@ BOOST_AUTO_TEST_CASE(xvm_test_case_1) auto oneVecReversed = std::vector(oneArr.begin(), oneArr.end()); std::reverse(oneVecReversed.begin(), oneVecReversed.end()); - auto twoArr20 = EvmAddressData{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2}; - auto toString = [](EvmAddressData arr) { - std::ostringstream os; - for (int i: arr) { - os << i; - } - return os.str(); - }; - XVM xvm; - xvm.evm.blockHash = one; - xvm.evm.beneficiary = twoArr20; + xvm.evm.blockHash = one.GetHex(); + xvm.evm.beneficiary = "00000000000000000002"; auto s = xvm.ToScript(); auto xvm2 = XVM::TryFrom(s); XVM xvm3; - xvm3.evm.blockHash = uint256(oneVec); + xvm3.evm.blockHash = uint256(oneVec).GetHex(); XVM xvm4; - xvm4.evm.blockHash = uint256(oneVecReversed); + xvm4.evm.blockHash = uint256(oneVecReversed).GetHex(); for (const auto& [result, expected]: std::vector> { { zero.GetHex(), "0000000000000000000000000000000000000000000000000000000000000000" }, { one.GetHex(), "0000000000000000000000000000000000000000000000000000000000000001" }, - { xvm.evm.blockHash.GetHex(), "0000000000000000000000000000000000000000000000000000000000000001" }, - { xvm2->evm.blockHash.GetHex(), "0000000000000000000000000000000000000000000000000000000000000001" }, - { xvm3.evm.blockHash.GetHex(), "0100000000000000000000000000000000000000000000000000000000000000" }, - { xvm4.evm.blockHash.GetHex(), "0000000000000000000000000000000000000000000000000000000000000001" }, - { toString(twoArr20), "00000000000000000002" }, - { toString(xvm.evm.beneficiary), "00000000000000000002" }, - { toString(xvm2->evm.beneficiary), "00000000000000000002" }, + { xvm.evm.blockHash, "0000000000000000000000000000000000000000000000000000000000000001" }, + { xvm2->evm.blockHash, "0000000000000000000000000000000000000000000000000000000000000001" }, + { xvm3.evm.blockHash, "0100000000000000000000000000000000000000000000000000000000000000" }, + { xvm4.evm.blockHash, "0000000000000000000000000000000000000000000000000000000000000001" }, + { xvm.evm.beneficiary, "00000000000000000002" }, + { xvm2->evm.beneficiary, "00000000000000000002" }, }) { // BOOST_TEST_MESSAGE("expected: " + expected + ", result: " + result); BOOST_CHECK(result == expected); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index e8dbb440c0..82094808e5 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -353,7 +353,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n) nTransactionsUpdated += n; } -void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate, const std::optional> ethSender) +void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate, const std::optional ethSender) { NotifyEntryAdded(entry.GetSharedTx()); // Add to memory pool without checking anything. diff --git a/src/txmempool.h b/src/txmempool.h index 01256a2418..5d07f7a291 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -581,7 +581,7 @@ class CTxMemPool // and any other callers may break wallet's in-mempool tracking (due to // lack of CValidationInterface::TransactionAddedToMempool callbacks). void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); - void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true, const std::optional> ethSender = std::nullopt) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); + void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true, const std::optional ethSender = std::nullopt) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs); void removeForReorg(const CCoinsViewCache* pcoins, unsigned int nMemPoolHeight, int flags) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main); diff --git a/src/uint256.h b/src/uint256.h index 7350aad13e..84a16e521c 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -68,9 +68,9 @@ class base_blob [[nodiscard]] std::array GetByteArray() const { - // We store bytes in the reverse order. So any expectations of + // We store bytes in little endian. So any expectations of // an array of bytes should be in same order as the hex string. - // The protected data array is an internal implementation detail. + // The protected data array is an internal implementation detail. std::array reversedArray; std::copy(std::reverse_iterator(data + sizeof(data)), std::reverse_iterator(data), reversedArray.begin()); return reversedArray; @@ -123,10 +123,6 @@ class uint160 : public base_blob<160> { public: uint160() {} explicit uint160(const std::vector& vch) : base_blob<160>(vch) {} - - static uint160 FromByteArray(const std::array& data) { - return uint160(std::vector(data.rbegin(), data.rend())); - } }; /** 256-bit opaque blob. @@ -138,10 +134,6 @@ class uint256 : public base_blob<256> { public: uint256() {} explicit uint256(const std::vector& vch) : base_blob<256>(vch) {} - - static uint256 FromByteArray(const std::array& data) { - return uint256(std::vector(data.rbegin(), data.rend())); - } }; /* uint256 from const char *. diff --git a/src/validation.cpp b/src/validation.cpp index 016070a669..1b9f642ec8 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -912,7 +912,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool __func__, hash.ToString(), FormatStateMessage(state)); } - std::optional> ethSender; + std::optional ethSender{}; if (isEvmTx) { auto txMessage = customTypeToMessage(txType); @@ -927,11 +927,12 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool if (!result.ok) { return state.Invalid(ValidationInvalidReason::CONSENSUS, error("evm tx failed to validate %s", result.reason.c_str()), REJECT_INVALID, "evm-validate-failed"); } - const auto sender = pool.ethTxsBySender.find(txResult.sender); + const auto txResultSender = std::string(txResult.sender.data(), txResult.sender.length()); + const auto sender = pool.ethTxsBySender.find(txResultSender); if (sender != pool.ethTxsBySender.end() && sender->second.size() >= MEMPOOL_MAX_ETH_TXS) { return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, error("Too many Eth trransaction from the same sender in mempool. Limit %d.", MEMPOOL_MAX_ETH_TXS), REJECT_INVALID, "too-many-eth-txs-by-sender"); } else { - ethSender = txResult.sender; + ethSender = txResultSender; } } diff --git a/test/functional/feature_evm_contract_env_vars.py b/test/functional/feature_evm_contract_env_vars.py index c02dcbdbc1..3641a8c974 100755 --- a/test/functional/feature_evm_contract_env_vars.py +++ b/test/functional/feature_evm_contract_env_vars.py @@ -117,13 +117,15 @@ def test_block_chainid(self): def test_coinbase(self): block = self.nodes[0].getblock( - self.nodes[0].getblockhash(self.nodes[0].getblockcount()) + self.nodes[0].getblockhash(self.nodes[0].getblockcount()), 3 ) - raw_tx = self.nodes[0].getrawtransaction(block["tx"][0], 1) - opreturn_miner_keyid = raw_tx["vout"][1]["scriptPubKey"]["hex"][120:] + coinbase_xvm = block["tx"][0]["vm"] + assert_equal(coinbase_xvm["vmtype"], "coinbase") + assert_equal(coinbase_xvm["txtype"], "coinbase") + opreturn_miner_keyid = coinbase_xvm["msg"]["evm"]["beneficiary"] coinbase = self.contract.functions.coinbase().call() assert_equal( - coinbase, self.nodes[0].w3.to_checksum_address(f"0x{opreturn_miner_keyid}") + coinbase, self.nodes[0].w3.to_checksum_address(opreturn_miner_keyid) ) def test_difficulty(self): diff --git a/test/functional/feature_evm_vmmap_rpc.py b/test/functional/feature_evm_vmmap_rpc.py index 8b5fb0845d..f8dfbd4384 100755 --- a/test/functional/feature_evm_vmmap_rpc.py +++ b/test/functional/feature_evm_vmmap_rpc.py @@ -23,44 +23,25 @@ class VMMapTests(DefiTestFramework): def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True - self.extra_args = [ - [ - "-dummypos=0", - "-txnotokens=0", - "-amkheight=50", - "-bayfrontheight=51", - "-eunosheight=80", - "-fortcanningheight=82", - "-fortcanninghillheight=84", - "-fortcanningroadheight=86", - "-fortcanningcrunchheight=88", - "-fortcanningspringheight=90", - "-fortcanninggreatworldheight=94", - "-fortcanningepilogueheight=96", - "-grandcentralheight=101", - "-nextnetworkupgradeheight=105", - "-subsidytest=1", - "-txindex=1", - ], - [ - "-dummypos=0", - "-txnotokens=0", - "-amkheight=50", - "-bayfrontheight=51", - "-eunosheight=80", - "-fortcanningheight=82", - "-fortcanninghillheight=84", - "-fortcanningroadheight=86", - "-fortcanningcrunchheight=88", - "-fortcanningspringheight=90", - "-fortcanninggreatworldheight=94", - "-fortcanningepilogueheight=96", - "-grandcentralheight=101", - "-nextnetworkupgradeheight=105", - "-subsidytest=1", - "-txindex=1", - ], + extra_args = [ + "-dummypos=0", + "-txnotokens=0", + "-amkheight=50", + "-bayfrontheight=51", + "-eunosheight=80", + "-fortcanningheight=82", + "-fortcanninghillheight=84", + "-fortcanningroadheight=86", + "-fortcanningcrunchheight=88", + "-fortcanningspringheight=90", + "-fortcanninggreatworldheight=94", + "-fortcanningepilogueheight=96", + "-grandcentralheight=101", + "-nextnetworkupgradeheight=105", + "-subsidytest=1", + "-txindex=1", ] + self.extra_args = [extra_args, extra_args] def setup(self): self.address = self.nodes[0].get_genesis_keys().ownerAuthAddress diff --git a/test/functional/test_framework/evm_key_pair.py b/test/functional/test_framework/evm_key_pair.py index 17af559662..f369299b43 100644 --- a/test/functional/test_framework/evm_key_pair.py +++ b/test/functional/test_framework/evm_key_pair.py @@ -1,24 +1,9 @@ from eth_account import Account -def validate_key(privkey, address): - account = Account.from_key(privkey) - - if account.address != address: - raise RuntimeError( - f""" - Private key does not correspond to provided address. - Address provided: {address} - Address computed: {account.address} - """ - ) - else: - return privkey, address - - class EvmKeyPair: def __init__(self, privkey: str = None, address: str = None): - self.privkey, self.address = validate_key(privkey, address) + self.privkey, self.address = EvmKeyPair.validate_key(privkey, address) @staticmethod def from_node(node): @@ -27,3 +12,18 @@ def from_node(node): privkey = node.dumpprivkey(address) return EvmKeyPair(privkey, address) + + @staticmethod + def validate_key(privkey, address): + account = Account.from_key(privkey) + + if account.address != address: + raise RuntimeError( + f""" + Private key does not correspond to provided address. + Address provided: {address} + Address computed: {account.address} + """ + ) + else: + return privkey, address diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index de0230a2e1..682771513b 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -249,6 +249,8 @@ def main(self): [os.path.join(config["environment"]["BUILDDIR"], "src"), os.environ["PATH"]] ) + os.environ["RUST_LOG"] = "debug" + # Set up temp directory and start logging if self.options.tmpdir: self.options.tmpdir = os.path.abspath(self.options.tmpdir) @@ -449,6 +451,7 @@ def _rollback_to(self, block, node): if current_height == block: return blockhash = node.getblockhash(block + 1) + node.clearmempool() node.invalidateblock(blockhash) node.clearmempool() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 2cfa8f7828..d464e888fb 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -295,20 +295,21 @@ "feature_loan_priceupdate.py", "feature_loan_vaultstate.py", "feature_loan.py", + "feature_dst20.py", "feature_evm_contracts.py", - "feature_evm_logs.py", "feature_evm_contract_env_vars.py", + "feature_evm_dfi_intrinsics.py", + "feature_evm_logs.py", "feature_evm_fee.py", "feature_evm_genesis.py", "feature_evm_rollback.py", "feature_evm_rpc_transaction.py", "feature_evm_rpc.py", - "feature_evm_vmmap_rpc.py", "feature_evm_smart_contract.py", + "feature_evm_transaction_replacement.py", "feature_evm_transferdomain.py", + "feature_evm_vmmap_rpc.py", "feature_evm.py", - "feature_dst20.py", - "feature_evm_dfi_intrinsics.py", "feature_loan_low_interest.py", "feature_loan_estimatecollateral.py", "feature_vault_pct_check_factor.py", @@ -340,7 +341,6 @@ "feature_negative_interest.py", "rpc_getstoredinterest.py", "feature_dusd_loans.py", - "feature_evm_transaction_replacement.py", # Don't append tests at the end to avoid merge conflicts # Put them in a random line within the section that fits their approximate run-time ]