parent
686aa3a150
commit
0f66e5e49b
|
@ -22,7 +22,7 @@ pub struct Response<T> {
|
||||||
pub value: T,
|
pub value: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Serialize)]
|
#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcConfirmedBlock {
|
pub struct RpcConfirmedBlock {
|
||||||
pub previous_blockhash: Hash,
|
pub previous_blockhash: Hash,
|
||||||
|
|
|
@ -1124,7 +1124,7 @@ impl ReplayStage {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
pub(crate) mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
commitment::BlockCommitment,
|
commitment::BlockCommitment,
|
||||||
|
@ -1149,7 +1149,7 @@ mod test {
|
||||||
hash::{hash, Hash},
|
hash::{hash, Hash},
|
||||||
instruction::InstructionError,
|
instruction::InstructionError,
|
||||||
packet::PACKET_DATA_SIZE,
|
packet::PACKET_DATA_SIZE,
|
||||||
signature::{Keypair, KeypairUtil},
|
signature::{Keypair, KeypairUtil, Signature},
|
||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::TransactionError,
|
transaction::TransactionError,
|
||||||
};
|
};
|
||||||
|
@ -1561,6 +1561,61 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_test_transactions_and_populate_blocktree(
|
||||||
|
keypairs: Vec<&Keypair>,
|
||||||
|
previous_slot: Slot,
|
||||||
|
bank: Arc<Bank>,
|
||||||
|
blocktree: Arc<Blocktree>,
|
||||||
|
) -> Vec<Signature> {
|
||||||
|
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]
|
#[test]
|
||||||
fn test_write_persist_transaction_status() {
|
fn test_write_persist_transaction_status() {
|
||||||
let GenesisConfigInfo {
|
let GenesisConfigInfo {
|
||||||
|
@ -1568,7 +1623,7 @@ mod test {
|
||||||
mint_keypair,
|
mint_keypair,
|
||||||
..
|
..
|
||||||
} = create_genesis_config(1000);
|
} = 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)
|
let blocktree = Blocktree::open(&ledger_path)
|
||||||
.expect("Expected to successfully open database ledger");
|
.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 bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1));
|
||||||
let slot = bank1.slot();
|
let slot = bank1.slot();
|
||||||
|
|
||||||
// Generate transactions for processing
|
let signatures = create_test_transactions_and_populate_blocktree(
|
||||||
// Successful transaction
|
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
|
||||||
let success_tx =
|
bank0.slot(),
|
||||||
system_transaction::transfer(&mint_keypair, &keypair1.pubkey(), 2, blockhash);
|
bank1,
|
||||||
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,
|
|
||||||
blocktree.clone(),
|
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();
|
let confirmed_block = blocktree.get_confirmed_block(slot).unwrap();
|
||||||
assert_eq!(confirmed_block.transactions.len(), 3);
|
assert_eq!(confirmed_block.transactions.len(), 3);
|
||||||
|
|
||||||
for (transaction, result) in confirmed_block.transactions.into_iter() {
|
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(()));
|
assert_eq!(result.unwrap().status, Ok(()));
|
||||||
} else if transaction.signatures[0] == ix_error_signature {
|
} else if transaction.signatures[0] == signatures[1] {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap().status,
|
result.unwrap().status,
|
||||||
Err(TransactionError::InstructionError(
|
Err(TransactionError::InstructionError(
|
||||||
|
|
|
@ -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<RpcTransactionStatus> is always None.
|
|
||||||
pub fn get_confirmed_block(&self, slot: Slot) -> Result<Option<RpcConfirmedBlock>> {
|
pub fn get_confirmed_block(&self, slot: Slot) -> Result<Option<RpcConfirmedBlock>> {
|
||||||
Ok(self.blocktree.get_confirmed_block(slot).ok())
|
Ok(self.blocktree.get_confirmed_block(slot).ok())
|
||||||
}
|
}
|
||||||
|
@ -980,6 +975,7 @@ pub mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
contact_info::ContactInfo,
|
contact_info::ContactInfo,
|
||||||
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
||||||
|
replay_stage::tests::create_test_transactions_and_populate_blocktree,
|
||||||
};
|
};
|
||||||
use jsonrpc_core::{MetaIoHandler, Output, Response, Value};
|
use jsonrpc_core::{MetaIoHandler, Output, Response, Value};
|
||||||
use solana_ledger::get_tmp_ledger_path;
|
use solana_ledger::get_tmp_ledger_path;
|
||||||
|
@ -1007,6 +1003,7 @@ pub mod tests {
|
||||||
alice: Keypair,
|
alice: Keypair,
|
||||||
leader_pubkey: Pubkey,
|
leader_pubkey: Pubkey,
|
||||||
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
||||||
|
confirmed_block_signatures: Vec<Signature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_rpc_handler_with_tx(pubkey: &Pubkey) -> RpcHandler {
|
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)));
|
Arc::new(RwLock::new(BlockCommitmentCache::new(block_commitment, 42)));
|
||||||
let ledger_path = get_tmp_ledger_path!();
|
let ledger_path = get_tmp_ledger_path!();
|
||||||
let blocktree = Blocktree::open(&ledger_path).unwrap();
|
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 leader_pubkey = *bank.collector_id();
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
|
@ -1042,7 +1051,7 @@ pub mod tests {
|
||||||
JsonRpcConfig::default(),
|
JsonRpcConfig::default(),
|
||||||
bank_forks,
|
bank_forks,
|
||||||
block_commitment_cache.clone(),
|
block_commitment_cache.clone(),
|
||||||
Arc::new(blocktree),
|
blocktree,
|
||||||
StorageState::default(),
|
StorageState::default(),
|
||||||
&validator_exit,
|
&validator_exit,
|
||||||
)));
|
)));
|
||||||
|
@ -1074,6 +1083,7 @@ pub mod tests {
|
||||||
alice,
|
alice,
|
||||||
leader_pubkey,
|
leader_pubkey,
|
||||||
block_commitment_cache,
|
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 req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}}"#);
|
||||||
let res = io.handle_request_sync(&req, meta);
|
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 =
|
let expected: Response =
|
||||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
serde_json::from_str(&expected).expect("expected response deserialization");
|
||||||
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
let result: Response = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
@ -1769,4 +1779,43 @@ pub mod tests {
|
||||||
assert_eq!(commitment, None);
|
assert_eq!(commitment, None);
|
||||||
assert_eq!(total_staked, 42);
|
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<RpcConfirmedBlock> =
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue