diff --git a/zilliqa/src/api/zilliqa.rs b/zilliqa/src/api/zilliqa.rs index 5d0cc44b4..f8c3025f6 100644 --- a/zilliqa/src/api/zilliqa.rs +++ b/zilliqa/src/api/zilliqa.rs @@ -395,33 +395,33 @@ fn get_transaction(params: Params, node: &Arc>) -> Result node.get_finalized_height()? { + return Err(ErrorObject::owned( + RPCErrorCode::RpcDatabaseError as i32, + "Block not finalized".to_string(), + jsonrpc_error_data, + ) + .into()); + } GetTxResponse::new(tx, receipt, block.number()) } @@ -506,27 +506,24 @@ fn get_blockchain_info(_: Params, node: &Arc>) -> Result block.transactions.len(), None => 0, @@ -552,7 +549,7 @@ fn get_blockchain_info(_: Params, node: &Arc>) -> Result>) -> Result { let node = node.lock().unwrap(); - Ok(node.get_chain_tip().to_string()) + Ok(node.get_latest_finalized_block_number()?.to_string()) } // GetSmartContractState @@ -721,6 +718,9 @@ fn get_tx_block(params: Params, node: &Arc>) -> Result node.get_finalized_height()? { + return Err(anyhow!("Block not finalized")); + } let txn_fees = get_txn_fees_for_block(&node, block.hash())?; let block: zil::TxBlock = zil::TxBlock::new(&block, txn_fees); @@ -752,6 +752,9 @@ fn get_tx_block_verbose( let Some(block) = node.get_block(block_number)? else { return Ok(None); }; + if block.number() > node.get_finalized_height()? { + return Err(anyhow!("Block not finalized")); + } let proposer = node .get_proposer_reward_address(block.header)? .expect("No proposer"); @@ -769,7 +772,7 @@ fn get_smart_contracts(params: Params, node: &Arc>) -> Result>) -> Result< pub fn get_latest_ds_block(_params: Params, node: &Arc>) -> Result { // Dummy implementation let node = node.lock().unwrap(); - let num_tx_blocks = node.get_chain_tip(); + let num_tx_blocks = node.get_latest_finalized_block_number()?; let num_ds_blocks = (num_tx_blocks / TX_BLOCKS_PER_DS_BLOCK) + 1; Ok(get_example_ds_block(num_ds_blocks, num_tx_blocks)) } @@ -890,7 +893,7 @@ pub fn get_current_ds_comm( ) -> Result { // Dummy implementation let node = node.lock().unwrap(); - let num_tx_blocks = node.get_chain_tip(); + let num_tx_blocks = node.get_latest_finalized_block_number()?; let num_ds_blocks = (num_tx_blocks / TX_BLOCKS_PER_DS_BLOCK) + 1; Ok(GetCurrentDSCommResult { current_dsepoch: num_ds_blocks.to_string(), @@ -904,7 +907,7 @@ pub fn get_current_ds_comm( pub fn get_current_ds_epoch(_params: Params, node: &Arc>) -> Result { // Dummy implementation let node = node.lock().unwrap(); - let num_tx_blocks = node.get_chain_tip(); + let num_tx_blocks = node.get_latest_finalized_block_number()?; let num_ds_blocks = (num_tx_blocks / TX_BLOCKS_PER_DS_BLOCK) + 1; Ok(num_ds_blocks.to_string()) } @@ -913,7 +916,7 @@ pub fn get_current_ds_epoch(_params: Params, node: &Arc>) -> Result< pub fn ds_block_listing(params: Params, node: &Arc>) -> Result { // Dummy implementation let node = node.lock().unwrap(); - let num_tx_blocks = node.get_chain_tip(); + let num_tx_blocks = node.get_latest_finalized_block_number()?; let num_ds_blocks = (num_tx_blocks / TX_BLOCKS_PER_DS_BLOCK) + 1; let max_pages = num_ds_blocks / 10; let page_requested: u64 = params.one()?; @@ -938,14 +941,13 @@ pub fn ds_block_listing(params: Params, node: &Arc>) -> Result>) -> Result { let node = node.lock().unwrap(); let max_measurement_blocks = 5; - let height = node.get_chain_tip(); + let height = node.get_latest_finalized_block_number()?; if height == 0 { return Ok(0.0); } let measurement_blocks = height.min(max_measurement_blocks); let start_measure_block = node - .consensus - .get_canonical_block_by_number(height - measurement_blocks + 1)? + .get_block(height - measurement_blocks + 1)? .ok_or(anyhow!("Unable to get block"))?; let start_measure_time = start_measure_block.header.timestamp; let end_measure_time = SystemTime::now(); @@ -976,7 +978,7 @@ fn tx_block_listing(params: Params, node: &Arc>) -> Result>) -> Result { // Calculates transaction rate over the most recent block fn get_tx_rate(_params: Params, node: &Arc>) -> Result { let node = node.lock().unwrap(); - let head_block_num = node.get_chain_tip(); + let head_block_num = node.get_latest_finalized_block_number()?; if head_block_num <= 1 { return Ok(0.0); } @@ -1023,12 +1025,12 @@ fn get_tx_rate(_params: Params, node: &Arc>) -> Result { let prev_block = node .get_block(prev_block_num)? .ok_or(anyhow!("Unable to get block"))?; - let transactions_between = head_block.transactions.len() as f64; + let transactions_both = prev_block.transactions.len() + head_block.transactions.len(); let time_between = head_block .header .timestamp .duration_since(prev_block.header.timestamp)?; - let transaction_rate = transactions_between / time_between.as_secs_f64(); + let transaction_rate = transactions_both as f64 / time_between.as_secs_f64(); Ok(transaction_rate) } @@ -1047,6 +1049,9 @@ fn get_transactions_for_tx_block_ex( let block = node .get_block(block_number)? .ok_or_else(|| anyhow!("Block not found"))?; + if block.number() > node.get_finalized_height()? { + return Err(anyhow!("Block not finalized")); + } let total_transactions = block.transactions.len(); let num_pages = (total_transactions / TRANSACTIONS_PER_PAGE) @@ -1177,6 +1182,10 @@ fn get_txn_bodies_for_tx_block( .get_block(block_number)? .ok_or_else(|| anyhow!("Block not found"))?; + if block.number() > node.get_finalized_height()? { + return Err(anyhow!("Block not finalized")); + } + extract_transaction_bodies(&block, &node) } @@ -1194,6 +1203,10 @@ fn get_txn_bodies_for_tx_block_ex( .get_block(block_number)? .ok_or_else(|| anyhow!("Block not found"))?; + if block.number() > node.get_finalized_height()? { + return Err(anyhow!("Block not finalized")); + } + let total_transactions = block.transactions.len(); let num_pages = (total_transactions / TRANSACTIONS_PER_PAGE) + (if total_transactions % TRANSACTIONS_PER_PAGE != 0 { @@ -1230,7 +1243,7 @@ fn get_txn_bodies_for_tx_block_ex( // GetNumDSBlocks fn get_num_ds_blocks(_params: Params, node: &Arc>) -> Result { let node = node.lock().unwrap(); - let num_tx_blocks = node.get_chain_tip(); + let num_tx_blocks = node.get_latest_finalized_block_number()?; let num_ds_blocks = (num_tx_blocks / TX_BLOCKS_PER_DS_BLOCK) + 1; Ok(num_ds_blocks.to_string()) } @@ -1241,11 +1254,11 @@ fn get_recent_transactions( node: &Arc>, ) -> Result { let node = node.lock().unwrap(); - let mut block_number = node.get_chain_tip(); + let mut block_number = node.get_latest_finalized_block_number()?; let mut txns = Vec::new(); let mut blocks_searched = 0; while block_number > 0 && txns.len() < 100 && blocks_searched < 100 { - let block = match node.consensus.get_canonical_block_by_number(block_number)? { + let block = match node.get_block(block_number)? { Some(block) => block, None => continue, }; @@ -1275,9 +1288,7 @@ fn get_num_transactions(_params: Params, node: &Arc>) -> Result>) -> Result { let node = node.lock().unwrap(); - let latest_block = node - .consensus - .get_canonical_block_by_number(node.get_chain_tip())?; + let latest_block = node.get_latest_finalized_block()?; let num_transactions = match latest_block { Some(block) => block.transactions.len(), None => 0, @@ -1289,13 +1300,12 @@ fn get_num_txns_tx_epoch(_params: Params, node: &Arc>) -> Result>) -> Result { let node = node.lock().unwrap(); let ds_epoch_size = TX_BLOCKS_PER_DS_BLOCK; - let current_epoch = node.get_chain_tip() / ds_epoch_size; + let current_epoch = node.get_latest_finalized_block_number()? / ds_epoch_size; let current_epoch_first = current_epoch * ds_epoch_size; let mut num_txns_epoch = 0; - for i in current_epoch_first..node.get_chain_tip() { + for i in current_epoch_first..node.get_latest_finalized_block_number()? { let block = node - .consensus - .get_canonical_block_by_number(i)? + .get_block(i)? .ok_or_else(|| anyhow!("Block not found"))?; num_txns_epoch += block.transactions.len(); } @@ -1370,7 +1380,7 @@ fn get_smart_contract_sub_state(params: Params, node: &Arc>) -> Resu // First get the account and check that its a scilla account let block = node - .get_block(BlockId::latest())? + .get_latest_finalized_block()? .ok_or_else(|| anyhow!("Unable to get latest block!"))?; let state = node.get_state(&block)?; diff --git a/zilliqa/src/node.rs b/zilliqa/src/node.rs index f02d7fa46..120c91e53 100644 --- a/zilliqa/src/node.rs +++ b/zilliqa/src/node.rs @@ -463,6 +463,17 @@ impl Node { } } + pub fn get_latest_finalized_block(&self) -> Result> { + self.resolve_block_number(BlockNumberOrTag::Finalized) + } + + pub fn get_latest_finalized_block_number(&self) -> Result { + match self.resolve_block_number(BlockNumberOrTag::Finalized)? { + Some(block) => Ok(block.number()), + None => Ok(0), + } + } + pub fn get_block(&self, block_id: impl Into) -> Result> { match block_id.into() { BlockId::Hash(RpcBlockHash { diff --git a/zilliqa/tests/it/main.rs b/zilliqa/tests/it/main.rs index 110a275d8..51c20ccbf 100644 --- a/zilliqa/tests/it/main.rs +++ b/zilliqa/tests/it/main.rs @@ -1150,6 +1150,31 @@ impl Network { .unwrap(); } + pub async fn run_until_block_finalized( + &mut self, + target_block: u64, + mut timeout: usize, + ) -> Result<()> { + let initial_timeout = timeout; + let db = self.get_node(0).db.clone(); + loop { + if let Some(view) = db.get_finalized_view()? { + if let Some(block) = db.get_block_by_view(view)? { + if block.number() >= target_block { + return Ok(()); + } + } + } + if timeout == 0 { + return Err(anyhow!( + "condition was still false after {initial_timeout} ticks" + )); + } + self.tick().await; + timeout -= 1; + } + } + pub fn disconnect_node(&mut self, index: usize) { self.disconnected.insert(index); } diff --git a/zilliqa/tests/it/zil.rs b/zilliqa/tests/it/zil.rs index c1b14558e..dfe3bfa61 100644 --- a/zilliqa/tests/it/zil.rs +++ b/zilliqa/tests/it/zil.rs @@ -16,6 +16,7 @@ use serde::Deserialize; use serde_json::{json, Value}; use sha2::{Digest, Sha256}; use zilliqa::{ + api::types::zil::GetTxResponse, schnorr, zq1_proto::{Code, Data, Nonce, ProtoTransactionCoreInfo}, }; @@ -200,13 +201,13 @@ async fn send_transaction( network .run_until_async( || async { - wallet - .get_transaction_receipt(txn_hash) - .await - .unwrap() - .is_some() + let response: Result = wallet + .provider() + .request("GetTransaction", [txn_hash]) + .await; + response.is_ok() }, - 50, + 100, ) .await .unwrap(); @@ -295,13 +296,13 @@ async fn send_transaction_for_status( network .run_until_async( || async { - wallet - .get_transaction_receipt(txn_hash) - .await - .unwrap() - .is_some() + let response: Result = wallet + .provider() + .request("GetTransaction", [txn_hash]) + .await; + response.is_ok() }, - 50, + 100, ) .await .unwrap(); @@ -776,7 +777,7 @@ async fn get_transaction(mut network: Network) { .expect("Failed to get ID from response"); // Wait for the transaction to be mined - network.run_until_block(&wallet, 1.into(), 50).await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); // Use the GetTransaction API to retrieve the transaction details let response: Value = wallet @@ -1404,7 +1405,7 @@ async fn get_tx_block(mut network: Network) { let wallet = network.genesis_wallet().await; // Ensure there is at least one block in the chain - network.run_until_block(&wallet, 1.into(), 50).await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); // Request the first block let block_number = "1"; @@ -1496,7 +1497,7 @@ async fn get_tx_block_verbose(mut network: Network) { let wallet = network.genesis_wallet().await; // Ensure there is at least one block in the chain - network.run_until_block(&wallet, 1.into(), 50).await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); // Request the first block let block_number = "1"; @@ -1809,6 +1810,8 @@ async fn get_tx_block_rate_1(mut network: Network) { ) .await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); + let response: Value = wallet .provider() .request("GetTxBlockRate", [""]) @@ -1824,7 +1827,7 @@ async fn get_tx_block_rate_1(mut network: Network) { async fn tx_block_listing(mut network: Network) { let wallet = network.genesis_wallet().await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 100).await.unwrap(); let response: Value = wallet .provider() @@ -1835,7 +1838,6 @@ async fn tx_block_listing(mut network: Network) { let tx_block_listing: zilliqa::api::types::zil::TxBlockListingResult = serde_json::from_value(response).expect("Failed to deserialize response"); - assert_eq!(wallet.get_block_number().await.unwrap(), 2.into()); assert_eq!( tx_block_listing.data.len(), 2, @@ -1884,6 +1886,8 @@ async fn get_num_peers(mut network: Network) { async fn get_tx_rate_0(mut network: Network) { let wallet = network.genesis_wallet().await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); + let response: Value = wallet .provider() .request("GetTransactionRate", [""]) @@ -1894,7 +1898,7 @@ async fn get_tx_rate_0(mut network: Network) { assert!(tx_rate >= 0.0, "Transaction rate should be non-negative"); - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let response: Value = wallet .provider() @@ -1913,6 +1917,8 @@ async fn get_tx_rate_1(mut network: Network) { let (secret_key, _address) = zilliqa_account(&mut network).await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); + let to_addr: H160 = "0x00000000000000000000000000000000deadbeef" .parse() .unwrap(); @@ -1928,17 +1934,7 @@ async fn get_tx_rate_1(mut network: Network) { ) .await; - let response: Value = wallet - .provider() - .request("GetTransactionRate", [""]) - .await - .expect("Failed to call GetTxRate API"); - - let tx_rate: f64 = serde_json::from_value(response).expect("Failed to deserialize response"); - - assert!(tx_rate > 0.0, "Transaction block rate should be positive"); - - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let response: Value = wallet .provider() @@ -1948,13 +1944,13 @@ async fn get_tx_rate_1(mut network: Network) { let tx_rate: f64 = serde_json::from_value(response).expect("Failed to deserialize response"); - assert!(tx_rate > 0.0, "Transaction rate should be non-negative"); + assert!(tx_rate > 0.0, "Transaction block rate should be positive"); } #[zilliqa_macros::test] async fn get_txns_for_tx_block_ex_0(mut network: Network) { let wallet = network.genesis_wallet().await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); let block_number = "1"; let page_number = "1"; @@ -2046,7 +2042,7 @@ async fn get_txns_for_tx_block_ex_1(mut network: Network) { ) .await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let block_number = "1"; let page_number = "0"; @@ -2092,7 +2088,7 @@ async fn get_txns_for_tx_block_0(mut network: Network) { ) .await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let block_number = "1"; @@ -2147,7 +2143,7 @@ async fn get_txn_bodies_for_tx_block_0(mut network: Network) { ) .await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let block_number = "1"; @@ -2187,7 +2183,7 @@ async fn get_txn_bodies_for_tx_block_1(mut network: Network) { ) .await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let block_number = "1"; @@ -2231,7 +2227,7 @@ async fn get_txn_bodies_for_tx_block_ex_0(mut network: Network) { ) .await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let block_number = "1"; let page_number = "2"; @@ -2277,7 +2273,7 @@ async fn get_txn_bodies_for_tx_block_ex_1(mut network: Network) { ) .await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let block_number = "1"; let page_number = "0"; @@ -2380,7 +2376,7 @@ async fn get_recent_transactions_1(mut network: Network) { ) .await; - network.run_until_block(&wallet, 1.into(), 50).await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); let (secret_key, _address) = zilliqa_account(&mut network).await; @@ -2399,7 +2395,7 @@ async fn get_recent_transactions_1(mut network: Network) { ) .await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let response: Value = wallet .provider() @@ -2462,7 +2458,7 @@ async fn get_recent_transactions_1(mut network: Network) { // ) // .await; -// network.run_until_block(&wallet, 1.into(), 50).await; +// network.run_until_block_finalized(1u64, 50).await.unwrap(); // let (secret_key, _address) = zilliqa_account(&mut network).await; @@ -2481,7 +2477,7 @@ async fn get_recent_transactions_1(mut network: Network) { // ) // .await; -// network.run_until_block(&wallet, 2.into(), 50).await; +// network.run_until_block_finalized(2u64, 50).await.unwrap(); // let response: Value = wallet // .provider() @@ -2542,7 +2538,7 @@ async fn get_num_txns_ds_epoch_1(mut network: Network) { ) .await; - network.run_until_block(&wallet, 1.into(), 50).await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); let (secret_key, _address) = zilliqa_account(&mut network).await; @@ -2561,7 +2557,7 @@ async fn get_num_txns_ds_epoch_1(mut network: Network) { ) .await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let response: Value = wallet .provider() @@ -2622,7 +2618,7 @@ async fn get_num_txns_tx_epoch_1(mut network: Network) { ) .await; - network.run_until_block(&wallet, 1.into(), 50).await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); let (secret_key, _address) = zilliqa_account(&mut network).await; @@ -2641,7 +2637,7 @@ async fn get_num_txns_tx_epoch_1(mut network: Network) { ) .await; - network.run_until_block(&wallet, 2.into(), 50).await; + network.run_until_block_finalized(2u64, 50).await.unwrap(); let response: Value = wallet .provider() @@ -2917,6 +2913,8 @@ async fn get_smart_contract_sub_state(mut network: Network) { assert_eq!(event["params"][0]["value"], "foobar"); } + network.run_until_block_finalized(2u64, 50).await.unwrap(); + let state: serde_json::Value = network .random_wallet() .await @@ -3111,7 +3109,7 @@ async fn get_transaction_status(mut network: Network) { .as_str() .expect("Failed to get ID from response"); - network.run_until_block(&wallet, 1.into(), 50).await; + network.run_until_block_finalized(1u64, 50).await.unwrap(); let (secret_key, _address) = zilliqa_account(&mut network).await; @@ -3134,7 +3132,7 @@ async fn get_transaction_status(mut network: Network) { .as_str() .expect("Failed to get ID from response"); - // network.run_until_block(&wallet, 2.into(), 50).await; + // network.run_until_block_finalized(2u64, 50).await.unwrap(); let response_1: Value = wallet .provider()