From 0f66e5e49bb1d7b36331d18283622739c5a78229 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 25 Nov 2019 12:08:03 -0700 Subject: [PATCH] Add getConfirmedBlock test to rpc (#7120) automerge --- client/src/rpc_request.rs | 2 +- core/src/replay_stage.rs | 105 +++++++++++++++++++++++--------------- core/src/rpc.rs | 63 ++++++++++++++++++++--- 3 files changed, 121 insertions(+), 49 deletions(-) diff --git a/client/src/rpc_request.rs b/client/src/rpc_request.rs index 497fcabde..f9a14785b 100644 --- a/client/src/rpc_request.rs +++ b/client/src/rpc_request.rs @@ -22,7 +22,7 @@ pub struct Response { pub value: T, } -#[derive(Debug, Default, PartialEq, Serialize)] +#[derive(Debug, Default, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RpcConfirmedBlock { pub previous_blockhash: Hash, diff --git a/core/src/replay_stage.rs b/core/src/replay_stage.rs index d5a552619..5b3727720 100644 --- a/core/src/replay_stage.rs +++ b/core/src/replay_stage.rs @@ -1124,7 +1124,7 @@ impl ReplayStage { } #[cfg(test)] -mod test { +pub(crate) mod tests { use super::*; use crate::{ commitment::BlockCommitment, @@ -1149,7 +1149,7 @@ mod test { hash::{hash, Hash}, instruction::InstructionError, packet::PACKET_DATA_SIZE, - signature::{Keypair, KeypairUtil}, + signature::{Keypair, KeypairUtil, Signature}, system_transaction, transaction::TransactionError, }; @@ -1561,6 +1561,61 @@ mod test { ); } + pub fn create_test_transactions_and_populate_blocktree( + keypairs: Vec<&Keypair>, + previous_slot: Slot, + bank: Arc, + blocktree: Arc, + ) -> Vec { + let mint_keypair = keypairs[0]; + let keypair1 = keypairs[1]; + let keypair2 = keypairs[2]; + let keypair3 = keypairs[3]; + let slot = bank.slot(); + let blockhash = bank.confirmed_last_blockhash().0; + + // Generate transactions for processing + // Successful transaction + let success_tx = + system_transaction::transfer(&mint_keypair, &keypair1.pubkey(), 2, blockhash); + let success_signature = success_tx.signatures[0]; + let entry_1 = next_entry(&blockhash, 1, vec![success_tx]); + // Failed transaction, InstructionError + let ix_error_tx = + system_transaction::transfer(&keypair2, &keypair3.pubkey(), 10, blockhash); + let ix_error_signature = ix_error_tx.signatures[0]; + let entry_2 = next_entry(&entry_1.hash, 1, vec![ix_error_tx]); + // Failed transaction + let fail_tx = + system_transaction::transfer(&mint_keypair, &keypair2.pubkey(), 2, Hash::default()); + let entry_3 = next_entry(&entry_2.hash, 1, vec![fail_tx]); + let entries = vec![entry_1, entry_2, entry_3]; + + let shreds = entries_to_test_shreds(entries.clone(), slot, previous_slot, true, 0); + blocktree.insert_shreds(shreds, None, false).unwrap(); + blocktree.set_roots(&[slot]).unwrap(); + + let (transaction_status_sender, transaction_status_receiver) = unbounded(); + let transaction_status_service = TransactionStatusService::new( + transaction_status_receiver, + blocktree.clone(), + &Arc::new(AtomicBool::new(false)), + ); + + // Check that process_entries successfully writes can_commit transactions statuses, and + // that they are matched properly by get_confirmed_block + let _result = blocktree_processor::process_entries( + &bank, + &entries, + true, + Some(transaction_status_sender), + ); + + transaction_status_service.join().unwrap(); + + vec![success_signature, ix_error_signature] + } + #[test] fn test_write_persist_transaction_status() { let GenesisConfigInfo { @@ -1568,7 +1623,7 @@ mod test { mint_keypair, .. } = create_genesis_config(1000); - let (ledger_path, blockhash) = create_new_tmp_ledger!(&genesis_config); + let (ledger_path, _) = create_new_tmp_ledger!(&genesis_config); { let blocktree = Blocktree::open(&ledger_path) .expect("Expected to successfully open database ledger"); @@ -1586,52 +1641,20 @@ mod test { let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1)); let slot = bank1.slot(); - // Generate transactions for processing - // Successful transaction - let success_tx = - system_transaction::transfer(&mint_keypair, &keypair1.pubkey(), 2, blockhash); - let success_signature = success_tx.signatures[0]; - let entry_1 = next_entry(&blockhash, 1, vec![success_tx]); - // Failed transaction, InstructionError - let ix_error_tx = - system_transaction::transfer(&keypair2, &keypair3.pubkey(), 10, blockhash); - let ix_error_signature = ix_error_tx.signatures[0]; - let entry_2 = next_entry(&entry_1.hash, 1, vec![ix_error_tx]); - // Failed transaction - let fail_tx = - system_transaction::transfer(&mint_keypair, &keypair2.pubkey(), 2, Hash::default()); - let entry_3 = next_entry(&entry_2.hash, 1, vec![fail_tx]); - let entries = vec![entry_1, entry_2, entry_3]; - - let shreds = entries_to_test_shreds(entries.clone(), slot, bank0.slot(), true, 0); - blocktree.insert_shreds(shreds, None, false).unwrap(); - blocktree.set_roots(&[slot]).unwrap(); - - let (transaction_status_sender, transaction_status_receiver) = unbounded(); - let transaction_status_service = TransactionStatusService::new( - transaction_status_receiver, + let signatures = create_test_transactions_and_populate_blocktree( + vec![&mint_keypair, &keypair1, &keypair2, &keypair3], + bank0.slot(), + bank1, blocktree.clone(), - &Arc::new(AtomicBool::new(false)), ); - // Check that process_entries successfully writes can_commit transactions statuses, and - // that they are matched properly by get_confirmed_block - let _result = blocktree_processor::process_entries( - &bank1, - &entries, - true, - Some(transaction_status_sender), - ); - - transaction_status_service.join().unwrap(); - let confirmed_block = blocktree.get_confirmed_block(slot).unwrap(); assert_eq!(confirmed_block.transactions.len(), 3); for (transaction, result) in confirmed_block.transactions.into_iter() { - if transaction.signatures[0] == success_signature { + if transaction.signatures[0] == signatures[0] { assert_eq!(result.unwrap().status, Ok(())); - } else if transaction.signatures[0] == ix_error_signature { + } else if transaction.signatures[0] == signatures[1] { assert_eq!( result.unwrap().status, Err(TransactionError::InstructionError( diff --git a/core/src/rpc.rs b/core/src/rpc.rs index 881005dc0..6ba102b42 100644 --- a/core/src/rpc.rs +++ b/core/src/rpc.rs @@ -301,11 +301,6 @@ impl JsonRpcRequestProcessor { } } - // The `get_confirmed_block` method is not fully implemented. It currenlty returns a partially - // complete RpcConfirmedBlock. The `blockhash` and `previous_blockhash` fields are legitimate - // data, while the `transactions` field contains transaction tuples (Transaction, - // transaction::Result), where the Transaction is a legitimate transaction, but the - // Option is always None. pub fn get_confirmed_block(&self, slot: Slot) -> Result> { Ok(self.blocktree.get_confirmed_block(slot).ok()) } @@ -980,6 +975,7 @@ pub mod tests { use crate::{ contact_info::ContactInfo, genesis_utils::{create_genesis_config, GenesisConfigInfo}, + replay_stage::tests::create_test_transactions_and_populate_blocktree, }; use jsonrpc_core::{MetaIoHandler, Output, Response, Value}; use solana_ledger::get_tmp_ledger_path; @@ -1007,6 +1003,7 @@ pub mod tests { alice: Keypair, leader_pubkey: Pubkey, block_commitment_cache: Arc>, + confirmed_block_signatures: Vec, } fn start_rpc_handler_with_tx(pubkey: &Pubkey) -> RpcHandler { @@ -1026,6 +1023,18 @@ pub mod tests { Arc::new(RwLock::new(BlockCommitmentCache::new(block_commitment, 42))); let ledger_path = get_tmp_ledger_path!(); let blocktree = Blocktree::open(&ledger_path).unwrap(); + let blocktree = Arc::new(blocktree); + + let keypair1 = Keypair::new(); + let keypair2 = Keypair::new(); + let keypair3 = Keypair::new(); + bank.transfer(4, &alice, &keypair2.pubkey()).unwrap(); + let confirmed_block_signatures = create_test_transactions_and_populate_blocktree( + vec![&alice, &keypair1, &keypair2, &keypair3], + 0, + bank.clone(), + blocktree.clone(), + ); let leader_pubkey = *bank.collector_id(); let exit = Arc::new(AtomicBool::new(false)); @@ -1042,7 +1051,7 @@ pub mod tests { JsonRpcConfig::default(), bank_forks, block_commitment_cache.clone(), - Arc::new(blocktree), + blocktree, StorageState::default(), &validator_exit, ))); @@ -1074,6 +1083,7 @@ pub mod tests { alice, leader_pubkey, block_commitment_cache, + confirmed_block_signatures, } } @@ -1180,7 +1190,7 @@ pub mod tests { let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}}"#); let res = io.handle_request_sync(&req, meta); - let expected = format!(r#"{{"jsonrpc":"2.0","result":1,"id":1}}"#); + let expected = format!(r#"{{"jsonrpc":"2.0","result":3,"id":1}}"#); let expected: Response = serde_json::from_str(&expected).expect("expected response deserialization"); let result: Response = serde_json::from_str(&res.expect("actual response")) @@ -1769,4 +1779,43 @@ pub mod tests { assert_eq!(commitment, None); assert_eq!(total_staked, 42); } + + #[test] + fn test_get_confirmed_block() { + let bob_pubkey = Pubkey::new_rand(); + let RpcHandler { + io, + meta, + confirmed_block_signatures, + blockhash, + .. + } = start_rpc_handler_with_tx(&bob_pubkey); + + let req = + format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getConfirmedBlock","params":[0]}}"#); + let res = io.handle_request_sync(&req, meta); + let result: Value = serde_json::from_str(&res.expect("actual response")) + .expect("actual response deserialization"); + let confirmed_block: Option = + serde_json::from_value(result["result"].clone()).unwrap(); + let confirmed_block = confirmed_block.unwrap(); + assert_eq!(confirmed_block.transactions.len(), 3); + + for (transaction, result) in confirmed_block.transactions.into_iter() { + if transaction.signatures[0] == confirmed_block_signatures[0] { + assert_eq!(transaction.message.recent_blockhash, blockhash); + assert_eq!(result.unwrap().status, Ok(())); + } else if transaction.signatures[0] == confirmed_block_signatures[1] { + assert_eq!( + result.unwrap().status, + Err(TransactionError::InstructionError( + 0, + InstructionError::CustomError(1) + )) + ); + } else { + assert_eq!(result, None); + } + } + } }