diff --git a/lib/ain-grpc/src/block.rs b/lib/ain-grpc/src/block.rs index 18964e22963..1f3533d468e 100644 --- a/lib/ain-grpc/src/block.rs +++ b/lib/ain-grpc/src/block.rs @@ -7,7 +7,7 @@ use serde::{ }; use std::fmt; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "camelCase")] pub struct RpcBlock { pub hash: H256, @@ -26,35 +26,58 @@ pub struct RpcBlock { pub total_difficulty: Option, pub seal_fields: Vec>, pub uncles: Vec, - pub transactions: Vec, + pub transactions: BlockTransactions, pub nonce: U256, pub sha3_uncles: String, pub logs_bloom: String, pub size: String, } -impl From for RpcBlock { - fn from(b: BlockAny) -> Self { - let header_size = b.header.rlp_bytes().len(); +impl RpcBlock { + pub fn from_block_with_tx(block: BlockAny, full_transactions: bool) -> Self { + let header_size = block.header.rlp_bytes().len(); RpcBlock { - hash: b.header.hash(), - mix_hash: b.header.hash(), - number: b.header.number, - parent_hash: b.header.parent_hash, - transactions_root: b.header.transactions_root, - state_root: b.header.state_root, - receipts_root: b.header.receipts_root, - miner: b.header.beneficiary, - difficulty: b.header.difficulty, + hash: block.header.hash(), + mix_hash: block.header.hash(), + number: block.header.number, + parent_hash: block.header.parent_hash, + transactions_root: block.header.transactions_root, + state_root: block.header.state_root, + receipts_root: block.header.receipts_root, + miner: block.header.beneficiary, + difficulty: block.header.difficulty, total_difficulty: Some(U256::zero()), seal_fields: vec![], - gas_limit: b.header.gas_limit, - gas_used: b.header.gas_used, - timestamp: b.header.timestamp.into(), - transactions: b.transactions.into_iter().map(|t| t.hash()).collect(), + gas_limit: block.header.gas_limit, + gas_used: block.header.gas_used, + timestamp: block.header.timestamp.into(), + transactions: { + if full_transactions { + // Discard failed to retrieved transactions with flat_map. + // Should not happen as the transaction should not make it in the block in the first place. + BlockTransactions::Full( + block + .transactions + .iter() + .enumerate() + .flat_map(|(index, tx)| { + EthTransactionInfo::try_from_tx_block_and_index(tx, &block, index) + }) + .collect(), + ) + } else { + BlockTransactions::Hashes( + block + .transactions + .iter() + .map(|transaction| transaction.hash()) + .collect(), + ) + } + }, uncles: vec![], nonce: U256::default(), - extra_data: b.header.extra_data, + extra_data: block.header.extra_data, sha3_uncles: String::default(), logs_bloom: String::default(), size: format!("{header_size:#x}"), @@ -232,6 +255,8 @@ impl<'a> Visitor<'a> for BlockNumberVisitor { use std::str::FromStr; +use crate::codegen::types::EthTransactionInfo; + impl FromStr for BlockNumber { type Err = serde_json::Error; @@ -281,3 +306,24 @@ mod tests { assert_eq!(match_block_number(bn_tag_pending).unwrap(), 1001); } } + +/// Block Transactions +#[derive(Debug, Deserialize, Clone, PartialEq)] +pub enum BlockTransactions { + /// Only hashes + Hashes(Vec), + /// Full transactions + Full(Vec), +} + +impl Serialize for BlockTransactions { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match *self { + BlockTransactions::Hashes(ref hashes) => hashes.serialize(serializer), + BlockTransactions::Full(ref ts) => ts.serialize(serializer), + } + } +} diff --git a/lib/ain-grpc/src/impls.rs b/lib/ain-grpc/src/impls.rs index e0efd656c42..df2c5de5b0f 100644 --- a/lib/ain-grpc/src/impls.rs +++ b/lib/ain-grpc/src/impls.rs @@ -1,43 +1,30 @@ use std::convert::From; use std::mem::size_of_val; -use ain_evm::transaction::{SignedTx, TransactionError}; -use ethereum::{BlockAny, TransactionV2}; -use primitive_types::{H160, H256, U256}; +use ethereum::BlockAny; -use crate::codegen::types::{EthBlockInfo, EthPendingTransactionInfo, EthTransactionInfo}; - -fn format_hash(hash: H256) -> String { - format!("{hash:#x}") -} - -fn format_address(hash: H160) -> String { - format!("{hash:#x}") -} - -fn format_number(number: U256) -> String { - format!("{number:#x}") -} +use crate::codegen::types::EthBlockInfo; +use crate::utils::{format_h256, format_u256}; impl From for EthBlockInfo { fn from(block: BlockAny) -> Self { EthBlockInfo { block_number: format!("{:#x}", block.header.number), - hash: format_hash(block.header.hash()), - parent_hash: format_hash(block.header.parent_hash), + hash: format_h256(block.header.hash()), + parent_hash: format_h256(block.header.parent_hash), nonce: format!("{:#x}", block.header.nonce), - sha3_uncles: format_hash(block.header.ommers_hash), + sha3_uncles: format_h256(block.header.ommers_hash), logs_bloom: format!("{:#x}", block.header.logs_bloom), - transactions_root: format_hash(block.header.transactions_root), - state_root: format_hash(block.header.state_root), - receipt_root: format_hash(block.header.receipts_root), + transactions_root: format_h256(block.header.transactions_root), + state_root: format_h256(block.header.state_root), + receipt_root: format_h256(block.header.receipts_root), miner: format!("{:#x}", block.header.beneficiary), difficulty: format!("{:#x}", block.header.difficulty), - total_difficulty: format_number(block.header.difficulty), + total_difficulty: format_u256(block.header.difficulty), extra_data: format!("{:#x?}", block.header.extra_data.to_ascii_lowercase()), size: format!("{:#x}", size_of_val(&block)), - gas_limit: format_number(block.header.gas_limit), - gas_used: format_number(block.header.gas_used), + gas_limit: format_u256(block.header.gas_limit), + gas_used: format_u256(block.header.gas_used), timestamps: format!("0x{:x}", block.header.timestamp), transactions: block .transactions @@ -52,62 +39,3 @@ impl From for EthBlockInfo { } } } - -impl TryFrom for EthTransactionInfo { - type Error = TransactionError; - - fn try_from(tx: TransactionV2) -> Result { - let signed_tx: SignedTx = tx.try_into()?; - - Ok(EthTransactionInfo { - from: format_address(signed_tx.sender), - to: signed_tx.to().map(format_address), - gas: signed_tx.gas_limit().as_u64(), - price: signed_tx.gas_price().to_string(), - value: signed_tx.value().to_string(), - data: hex::encode(signed_tx.data()), - nonce: signed_tx.nonce().to_string(), - }) - } -} - -impl TryFrom<&str> for EthPendingTransactionInfo { - type Error = TransactionError; - - fn try_from(raw_tx: &str) -> Result { - let signed_tx: SignedTx = raw_tx.try_into()?; - - let to = if let Some(signed_to) = signed_tx.to() { - format_address(signed_to) - } else { - String::from("null") - }; - - let input = if signed_tx.data().is_empty() { - String::from("0x0") - } else { - format!("0x{}", hex::encode(signed_tx.data())) - }; - - let pending_transaction = EthPendingTransactionInfo { - hash: format_hash(signed_tx.transaction.hash()), - nonce: format_number(signed_tx.nonce()), - block_hash: String::from( - "0x0000000000000000000000000000000000000000000000000000000000000000", - ), - block_number: String::from("null"), - transaction_index: String::from("0x0"), - from: format_address(signed_tx.sender), - to, - value: format_number(signed_tx.value()), - gas: format_number(signed_tx.gas_limit()), - gas_price: format_number(signed_tx.gas_price()), - input, - v: format!("0x{:x}", signed_tx.v()), - r: format_hash(signed_tx.r()), - s: format_hash(signed_tx.s()), - }; - - Ok(pending_transaction) - } -} diff --git a/lib/ain-grpc/src/lib.rs b/lib/ain-grpc/src/lib.rs index 5005983a366..5bcd8d549e4 100644 --- a/lib/ain-grpc/src/lib.rs +++ b/lib/ain-grpc/src/lib.rs @@ -8,6 +8,8 @@ pub mod codegen; mod impls; mod receipt; pub mod rpc; +mod transaction; +mod utils; use env_logger::{Builder as LogBuilder, Env, Target}; use jsonrpsee::core::server::rpc_module::Methods; diff --git a/lib/ain-grpc/src/rpc.rs b/lib/ain-grpc/src/rpc.rs index 7f9305c3f3a..13039f65063 100644 --- a/lib/ain-grpc/src/rpc.rs +++ b/lib/ain-grpc/src/rpc.rs @@ -1,9 +1,8 @@ use crate::block::{BlockNumber, RpcBlock}; use crate::call_request::CallRequest; -use crate::codegen::types::{EthPendingTransactionInfo, EthTransactionInfo}; +use crate::codegen::types::EthTransactionInfo; use crate::receipt::ReceiptResult; -// use ain_evm::evm::EVMState; use ain_evm::executor::TxResponse; use ain_evm::handler::Handlers; @@ -18,43 +17,94 @@ use std::sync::Arc; #[rpc(server, client)] pub trait MetachainRPC { + // ---------------------------------------- + // Client + // ---------------------------------------- + + /// Makes a call to the Ethereum node without creating a transaction on the blockchain. + /// Returns the output data as a hexadecimal string. #[method(name = "eth_call")] fn call(&self, input: CallRequest) -> RpcResult; + /// Retrieves the list of accounts managed by the node. + /// Returns a vector of Ethereum addresses as hexadecimal strings. #[method(name = "eth_accounts")] fn accounts(&self) -> RpcResult>; - #[method(name = "eth_getBalance")] - fn get_balance(&self, address: H160, block_number: Option) -> RpcResult; - - #[method(name = "eth_getBlockByHash")] - fn get_block_by_hash(&self, hash: H256) -> RpcResult>; - + /// Returns the current chain ID as a hexadecimal string. #[method(name = "eth_chainId")] fn chain_id(&self) -> RpcResult; - #[method(name = "eth_hashrate")] - fn hash_rate(&self) -> RpcResult; - + /// Returns the current network ID as a string. #[method(name = "net_version")] fn net_version(&self) -> RpcResult; + // ---------------------------------------- + // Block + // ---------------------------------------- + + /// Returns the current block number as U256. #[method(name = "eth_blockNumber")] fn block_number(&self) -> RpcResult; + /// Retrieves a specific block, identified by its block number. + /// Returns full transaction info or transaction hash depending on full_transactions param #[method(name = "eth_getBlockByNumber")] fn get_block_by_number( &self, block_number: BlockNumber, - full_transaction: bool, + full_transactions: bool, ) -> RpcResult>; + /// Retrieves a specific block, identified by its hash. + #[method(name = "eth_getBlockByHash")] + fn get_block_by_hash(&self, hash: H256, full_transactions: bool) + -> RpcResult>; + + /// Retrieves the transaction count for a specific block, identified by its hash. + #[method(name = "eth_getBlockTransactionCountByHash")] + fn get_block_transaction_count_by_hash(&self, hash: H256) -> RpcResult; + + /// Retrieves the transaction count for a specific block, identified by its block number. + #[method(name = "eth_getBlockTransactionCountByNumber")] + fn get_block_transaction_count_by_number(&self, number: BlockNumber) -> RpcResult; + + // ---------------------------------------- + // Mining + // ---------------------------------------- + + /// Checks if the node is currently mining. #[method(name = "eth_mining")] fn mining(&self) -> RpcResult; + /// Returns the hash of the current block, the seedHash, and the boundary condition to be met ("target"). + #[method(name = "eth_getWork")] + fn get_getwork(&self) -> RpcResult>; + + /// Submits a proof of work solution to the node. + /// Always returns false + #[method(name = "eth_submitWork")] + fn eth_submitwork(&self, nonce: String, hash: String, digest: String) -> RpcResult; + + /// Retrieves the current hash rate of the node. + /// Always returns 0x0 + #[method(name = "eth_hashrate")] + fn hash_rate(&self) -> RpcResult; + + /// Submit mining hashrate. + /// Always returns false + #[method(name = "eth_submitHashrate")] + fn eth_submithashrate(&self, hashrate: String, id: String) -> RpcResult; + + // ---------------------------------------- + // Transaction + // ---------------------------------------- + + /// Retrieves a specific transaction, identified by its hash. #[method(name = "eth_getTransactionByHash")] fn get_transaction_by_hash(&self, hash: H256) -> RpcResult>; + /// Retrieves a specific transaction, identified by the block hash and transaction index. #[method(name = "eth_getTransactionByBlockHashAndIndex")] fn get_transaction_by_block_hash_and_index( &self, @@ -62,6 +112,7 @@ pub trait MetachainRPC { index: usize, ) -> RpcResult>; + /// Retrieves a specific transaction, identified by the block number and transaction index. #[method(name = "eth_getTransactionByBlockNumberAndIndex")] fn get_transaction_by_block_number_and_index( &self, @@ -69,18 +120,36 @@ pub trait MetachainRPC { index: usize, ) -> RpcResult>; - #[method(name = "eth_getBlockTransactionCountByHash")] - fn get_block_transaction_count_by_hash(&self, hash: H256) -> RpcResult; + /// Retrieves the list of pending transactions. + #[method(name = "eth_pendingTransactions")] + fn get_pending_transaction(&self) -> RpcResult>; - #[method(name = "eth_getBlockTransactionCountByNumber")] - fn get_block_transaction_count_by_number(&self, number: BlockNumber) -> RpcResult; + /// Retrieves the receipt of a specific transaction, identified by its hash. + #[method(name = "eth_getTransactionReceipt")] + fn get_receipt(&self, hash: H256) -> RpcResult>; - #[method(name = "eth_pendingTransactions")] - fn get_pending_transaction(&self) -> RpcResult>; + /// Retrieves the number of transactions sent from a specific address. + #[method(name = "eth_getTransactionCount")] + fn get_transaction_count( + &self, + address: H160, + block_number: Option, + ) -> RpcResult; + // ---------------------------------------- + // State + // ---------------------------------------- + + /// Retrieves the balance of a specific Ethereum address at a given block number. + /// Returns the balance as U256. + #[method(name = "eth_getBalance")] + fn get_balance(&self, address: H160, block_number: Option) -> RpcResult; + + /// Retrieves the bytecode of a contract at a specific address. #[method(name = "eth_getCode")] fn get_code(&self, address: H160, block_number: Option) -> RpcResult; + /// Retrieves the storage value at a specific position in a contract. #[method(name = "eth_getStorageAt")] fn get_storage_at( &self, @@ -89,33 +158,25 @@ pub trait MetachainRPC { block_number: Option, ) -> RpcResult; + // ---------------------------------------- + // Send + // ---------------------------------------- + /// Sends a signed transaction. + /// Returns the transaction hash as a hexadecimal string. #[method(name = "eth_sendRawTransaction")] fn send_raw_transaction(&self, tx: &str) -> RpcResult; - #[method(name = "eth_getTransactionCount")] - fn get_transaction_count( - &self, - address: H160, - block_number: Option, - ) -> RpcResult; + // ---------------------------------------- + // Gas + // ---------------------------------------- + /// Estimate gas needed for execution of given contract. #[method(name = "eth_estimateGas")] - fn estimate_gas(&self, input: CallRequest) -> RpcResult; + fn estimate_gas(&self, input: CallRequest) -> RpcResult; + /// Returns current gas_price. #[method(name = "eth_gasPrice")] - fn gas_price(&self) -> RpcResult; - - #[method(name = "eth_getTransactionReceipt")] - fn get_receipt(&self, hash: H256) -> RpcResult>; - - #[method(name = "eth_getWork")] - fn get_getwork(&self) -> RpcResult>; - - #[method(name = "eth_submitWork")] - fn eth_submitwork(&self, nonce: String, hash: String, digest: String) -> RpcResult; - - #[method(name = "eth_submitHashrate")] - fn eth_submithashrate(&self, hashrate: String, id: String) -> RpcResult; + fn gas_price(&self) -> RpcResult; } pub struct MetachainRPCModule { @@ -247,13 +308,18 @@ impl MetachainRPCServer for MetachainRPCModule { Ok(H256::from_slice(&storage)) }) } - // ------ - fn get_block_by_hash(&self, hash: H256) -> RpcResult> { + fn get_block_by_hash( + &self, + hash: H256, + full_transactions: bool, + ) -> RpcResult> { self.handler .storage .get_block_by_hash(&hash) - .map_or(Ok(None), |block| Ok(Some(block.into()))) + .map_or(Ok(None), |block| { + Ok(Some(RpcBlock::from_block_with_tx(block, full_transactions))) + }) } fn chain_id(&self) -> RpcResult { @@ -289,14 +355,16 @@ impl MetachainRPCServer for MetachainRPCModule { fn get_block_by_number( &self, block_number: BlockNumber, - _full_transaction: bool, + full_transactions: bool, ) -> RpcResult> { debug!("Getting block by number : {:#?}", block_number); let block_number = self.block_number_to_u256(Some(block_number)); self.handler .storage .get_block_by_number(&block_number) - .map_or(Ok(None), |block| Ok(Some(block.into()))) + .map_or(Ok(None), |block| { + Ok(Some(RpcBlock::from_block_with_tx(block, full_transactions))) + }) } fn mining(&self) -> RpcResult { @@ -315,11 +383,12 @@ impl MetachainRPCServer for MetachainRPCModule { }) } - fn get_pending_transaction(&self) -> RpcResult> { + fn get_pending_transaction(&self) -> RpcResult> { ain_cpp_imports::get_pool_transactions() .map(|txs| { txs.into_iter() - .flat_map(|tx| EthPendingTransactionInfo::try_from(tx.as_str())) + .flat_map(|tx| EthTransactionInfo::try_from(tx.as_str())) + .map(EthTransactionInfo::into_pending_transaction_info) .collect() }) .map_err(|e| Error::Custom(e.to_string())) @@ -402,7 +471,7 @@ impl MetachainRPCServer for MetachainRPCModule { &self, address: H160, block_number: Option, - ) -> RpcResult { + ) -> RpcResult { debug!("Getting transaction count for address: {:?}", address); let block_number = self.block_number_to_u256(block_number); let nonce = self @@ -414,10 +483,10 @@ impl MetachainRPCServer for MetachainRPCModule { })?; debug!("Count: {:#?}", nonce); - Ok(format!("{nonce:#x}")) + Ok(nonce) } - fn estimate_gas(&self, input: CallRequest) -> RpcResult { + fn estimate_gas(&self, input: CallRequest) -> RpcResult { let CallRequest { from, to, @@ -442,16 +511,13 @@ impl MetachainRPCServer for MetachainRPCModule { let native_size = ain_cpp_imports::get_native_tx_size(data).unwrap_or(0); debug!("estimateGas: {:#?} + {:#?}", native_size, used_gas); - Ok(format!( - "{:#x}", - native_size + std::cmp::max(21000, used_gas) - )) + Ok(U256::from(native_size + std::cmp::max(21000, used_gas))) } - fn gas_price(&self) -> RpcResult { + fn gas_price(&self) -> RpcResult { let gas_price = ain_cpp_imports::get_min_relay_tx_fee().unwrap_or(10); debug!("gasPrice: {:#?}", gas_price); - Ok(format!("{gas_price:#x}")) + Ok(U256::from(gas_price)) } fn get_receipt(&self, hash: H256) -> RpcResult> { diff --git a/lib/ain-grpc/src/transaction.rs b/lib/ain-grpc/src/transaction.rs new file mode 100644 index 00000000000..ceef222f74a --- /dev/null +++ b/lib/ain-grpc/src/transaction.rs @@ -0,0 +1,79 @@ +use ain_evm::transaction::{SignedTx, TransactionError}; +use ethereum::{BlockAny, TransactionV2}; +use primitive_types::{H256, U256}; + +use crate::{ + codegen::types::EthTransactionInfo, + utils::{format_address, format_h256, format_u256}, +}; + +impl From for EthTransactionInfo { + fn from(signed_tx: SignedTx) -> Self { + let input = if signed_tx.data().is_empty() { + String::from("0x0") + } else { + format!("0x{}", hex::encode(signed_tx.data())) + }; + + EthTransactionInfo { + hash: format_h256(signed_tx.transaction.hash()), + from: format_address(signed_tx.sender), + to: signed_tx.to().map(format_address), + gas: format_u256(signed_tx.gas_limit()), + gas_price: format_u256(signed_tx.gas_price()), + value: format_u256(signed_tx.value()), + input, + nonce: format_u256(signed_tx.nonce()), + v: format!("0x{:x}", signed_tx.v()), + r: format_h256(signed_tx.r()), + s: format_h256(signed_tx.s()), + block_hash: None, + block_number: None, + transaction_index: None, + } + } +} + +impl TryFrom for EthTransactionInfo { + type Error = TransactionError; + + fn try_from(tx: TransactionV2) -> Result { + let signed_tx: SignedTx = tx.try_into()?; + Ok(signed_tx.into()) + } +} + +impl TryFrom<&str> for EthTransactionInfo { + type Error = TransactionError; + + fn try_from(raw_tx: &str) -> Result { + let signed_tx: SignedTx = raw_tx.try_into()?; + Ok(signed_tx.into()) + } +} + +impl EthTransactionInfo { + pub fn try_from_tx_block_and_index( + tx: &TransactionV2, + block: &BlockAny, + index: usize, + ) -> Result { + let signed_tx: SignedTx = tx.clone().try_into()?; + + Ok(EthTransactionInfo { + block_hash: Some(format_h256(block.header.hash())), + block_number: Some(format_u256(block.header.number)), + transaction_index: Some(format_u256(U256::from(index))), + ..EthTransactionInfo::from(signed_tx) + }) + } + + pub fn into_pending_transaction_info(self) -> Self { + Self { + block_hash: Some(format_h256(H256::zero())), + block_number: Some(String::from("null")), + transaction_index: Some(String::from("0x0")), + ..self + } + } +} diff --git a/lib/ain-grpc/src/utils.rs b/lib/ain-grpc/src/utils.rs new file mode 100644 index 00000000000..c89e2ca3f8d --- /dev/null +++ b/lib/ain-grpc/src/utils.rs @@ -0,0 +1,13 @@ +use primitive_types::{H160, H256, U256}; + +pub fn format_h256(hash: H256) -> String { + format!("{hash:#x}") +} + +pub fn format_address(hash: H160) -> String { + format!("{hash:#x}") +} + +pub fn format_u256(number: U256) -> String { + format!("{number:#x}") +} diff --git a/lib/proto/types/eth.proto b/lib/proto/types/eth.proto index e2edf3e5800..eeb1ca0ef1f 100644 --- a/lib/proto/types/eth.proto +++ b/lib/proto/types/eth.proto @@ -6,26 +6,16 @@ message EthAccountsResult { } message EthTransactionInfo { - string from = 1; // The address from which the transaction is sent - optional string to = 2; // The address to which the transaction is addressed - uint64 gas = 3; // The integer of gas provided for the transaction execution - string price = 4; // The integer of gas price used for each paid gas encoded as hexadecimal - string value = 5; // The integer of value sent with this transaction encoded as hexadecimal - string data = 6; // The hash of the method signature and encoded parameters. - string nonce = 7; // The integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. -} - -message EthPendingTransactionInfo { - string blockHash = 1; // Hash of the block. null when its pending block. - string blockNumber = 2; // The block number. null when its pending block. + optional string blockHash = 1; // Hash of the block. null when its pending block. + optional string blockNumber = 2; // The block number. null when its pending block. string from = 3; // The address from which the transaction is sent string gas = 4; // The integer of gas provided for the transaction execution. string gasPrice = 5; // The integer of gas price used for each paid gas encoded as hexadecimal string hash = 6; // Hash of the transaction. string input = 7; // The data sent along with the transaction. string nonce = 8; // The integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. - string to = 9; // Address of the receiver. null when its a contract creation transaction. - string transactionIndex = 10; // Integer of the transactions index position in the block. + optional string to = 9; // Address of the receiver. null when its a contract creation transaction. + optional string transactionIndex = 10; // Integer of the transactions index position in the block. string value = 11; // The integer of value sent with this transaction encoded as hexadecimal. string v = 12; // Signature v value string r = 13; // Signature r value diff --git a/test/functional/feature_evm_rpc.py b/test/functional/feature_evm_rpc.py index 1fce80dbe29..d4d6aaaee75 100755 --- a/test/functional/feature_evm_rpc.py +++ b/test/functional/feature_evm_rpc.py @@ -54,13 +54,15 @@ def set_test_params(self): def setup(self): self.address = self.nodes[0].get_genesis_keys().ownerAuthAddress - self.ethAddress = self.nodes[0].getnewaddress("","eth") - self.to_address = self.nodes[0].getnewaddress("","eth") + self.ethAddress = '0x9b8a4af42140d8a4c153a822f02571a1dd037e89' + self.toAddress = '0x6c34cbb9219d8caa428835d2073e8ec88ba0a110' + self.nodes[0].importprivkey('af990cc3ba17e776f7f57fcc59942a82846d75833fa17d2ba59ce6858d886e23') # ethAddress + self.nodes[0].importprivkey('17b8cb134958b3d8422b6c43b0732fcdb8c713b524df2d45de12f0c7e214ba35') # toAddress # Generate chain self.nodes[0].generate(101) - assert_raises_rpc_error(-32600, "called before NextNetworkUpgrade height", self.nodes[0].evmtx, self.ethAddress, 0, 21, 21000, self.to_address, 0.1) + assert_raises_rpc_error(-32600, "called before NextNetworkUpgrade height", self.nodes[0].evmtx, self.ethAddress, 0, 21, 21000, self.toAddress, 0.1) # Move to fork height self.nodes[0].generate(4) @@ -86,7 +88,7 @@ def test_node_params(self): def test_gas(self): estimate_gas = self.nodes[0].eth_estimateGas({ 'from': self.ethAddress, - 'to': self.to_address, + 'to': self.toAddress, 'gas': "0x5208", # 21_000 'value': "0x0", }) @@ -97,7 +99,7 @@ def test_gas(self): def test_accounts(self): eth_accounts = self.nodes[0].eth_accounts() - assert_equal(eth_accounts.sort(), [self.ethAddress, self.to_address].sort()) + assert_equal(eth_accounts.sort(), [self.ethAddress, self.toAddress].sort()) def test_address_state(self, address): assert_raises_rpc_error(-32602, "invalid length 7, expected a (both 0x-prefixed or not) hex string or byte array containing 20 bytes at line 1 column 9", self.nodes[0].eth_getBalance, "test123") @@ -124,6 +126,30 @@ def test_block(self): latest_block = self.nodes[0].eth_getBlockByNumber("latest", False) assert_equal(latest_block['number'], "0x3") + # Test full transaction block + tx = self.nodes[0].evmtx(self.ethAddress, 0, 21, 21000, self.toAddress, 1) + self.nodes[0].generate(1) + + latest_block = self.nodes[0].eth_getBlockByNumber("latest", False) + assert_equal(latest_block['number'], "0x4") + assert_equal(latest_block['transactions'][0], "0x8c99e9f053e033078e33c2756221f38fd529b914165090a615f27961de687497") + + latest_full_block = self.nodes[0].eth_getBlockByNumber("latest", True) + assert_equal(latest_full_block['number'], "0x4") + assert_equal(latest_full_block['transactions'][0]['blockHash'], latest_full_block["hash"]) + assert_equal(latest_full_block['transactions'][0]['blockNumber'], latest_full_block["number"]) + assert_equal(latest_full_block['transactions'][0]['from'], self.ethAddress) + assert_equal(latest_full_block['transactions'][0]['gas'], '0x5208') + assert_equal(latest_full_block['transactions'][0]['gasPrice'], '0x4e3b29200') + assert_equal(latest_full_block['transactions'][0]['hash'], '0x8c99e9f053e033078e33c2756221f38fd529b914165090a615f27961de687497') + assert_equal(latest_full_block['transactions'][0]['input'], '0x0') + assert_equal(latest_full_block['transactions'][0]['nonce'], '0x0') + assert_equal(latest_full_block['transactions'][0]['to'], self.toAddress) + assert_equal(latest_full_block['transactions'][0]['transactionIndex'], '0x0') + assert_equal(latest_full_block['transactions'][0]['value'], '0xde0b6b3a7640000') + assert_equal(latest_full_block['transactions'][0]['v'], '0x25') + assert_equal(latest_full_block['transactions'][0]['r'], '0x37f41c543402c9b02b35b45ef43ac31a63dcbeba0c622249810ecdec00aee376') + def run_test(self): self.setup()