Skip to content

Commit

Permalink
Add rpc test for versioned txs
Browse files Browse the repository at this point in the history
  • Loading branch information
jstarry committed Mar 4, 2022
1 parent 23b0e79 commit 62e5b49
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 59 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions client-test/tests/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use {
solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path},
solana_rpc::{
optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank,
rpc::create_test_transactions_and_populate_blockstore,
rpc::{create_test_transaction_entries, populate_blockstore_for_tests},
rpc_pubsub_service::{PubSubConfig, PubSubService},
rpc_subscriptions::RpcSubscriptions,
},
Expand Down Expand Up @@ -232,9 +232,12 @@ fn test_block_subscription() {
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
bank.transfer(rent_exempt_amount, &alice, &keypair2.pubkey())
.unwrap();
let _confirmed_block_signatures = create_test_transactions_and_populate_blockstore(
vec![&alice, &keypair1, &keypair2, &keypair3],
0,
populate_blockstore_for_tests(
create_test_transaction_entries(
vec![&alice, &keypair1, &keypair2, &keypair3],
bank.clone(),
)
.0,
bank,
blockstore.clone(),
max_complete_transaction_status_slot,
Expand Down
4 changes: 1 addition & 3 deletions core/src/banking_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3384,9 +3384,7 @@ mod tests {
account_address: Pubkey,
address_lookup_table: AddressLookupTable<'static>,
) -> AccountSharedData {
let mut data = Vec::new();
address_lookup_table.serialize_for_tests(&mut data).unwrap();

let data = address_lookup_table.serialize_for_tests().unwrap();
let mut account =
AccountSharedData::new(1, data.len(), &solana_address_lookup_table_program::id());
account.set_data(data);
Expand Down
13 changes: 8 additions & 5 deletions core/src/replay_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3129,7 +3129,7 @@ pub mod tests {
},
solana_rpc::{
optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank,
rpc::create_test_transactions_and_populate_blockstore,
rpc::{create_test_transaction_entries, populate_blockstore_for_tests},
},
solana_runtime::{
accounts_background_service::AbsRequestSender,
Expand Down Expand Up @@ -3998,15 +3998,18 @@ pub mod tests {
let bank1 = Arc::new(Bank::new_from_parent(&bank0, &Pubkey::default(), 1));
let slot = bank1.slot();

let mut test_signatures_iter = create_test_transactions_and_populate_blockstore(
let (entries, test_signatures) = create_test_transaction_entries(
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
bank0.slot(),
bank1.clone(),
);
populate_blockstore_for_tests(
entries,
bank1,
blockstore.clone(),
Arc::new(AtomicU64::default()),
)
.into_iter();
);

let mut test_signatures_iter = test_signatures.into_iter();
let confirmed_block = blockstore.get_rooted_block(slot, false).unwrap();
let actual_tx_results: Vec<_> = confirmed_block
.transactions
Expand Down
4 changes: 1 addition & 3 deletions programs/address-lookup-table-tests/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ pub async fn add_lookup_table_account(
account_address: Pubkey,
address_lookup_table: AddressLookupTable<'static>,
) -> AccountSharedData {
let mut data = Vec::new();
address_lookup_table.serialize_for_tests(&mut data).unwrap();

let data = address_lookup_table.serialize_for_tests().unwrap();
let rent = context.banks_client.get_rent().await.unwrap();
let rent_exempt_balance = rent.minimum_balance(data.len());

Expand Down
13 changes: 6 additions & 7 deletions programs/address-lookup-table/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,13 @@ impl<'a> AddressLookupTable<'a> {
}

/// Serialize an address table including its addresses
pub fn serialize_for_tests(self, data: &mut Vec<u8>) -> Result<(), InstructionError> {
data.resize(LOOKUP_TABLE_META_SIZE, 0);
Self::overwrite_meta_data(data, self.meta)?;
pub fn serialize_for_tests(self) -> Result<Vec<u8>, InstructionError> {
let mut data = vec![0; LOOKUP_TABLE_META_SIZE];
Self::overwrite_meta_data(&mut data, self.meta)?;
self.addresses.iter().for_each(|address| {
data.extend_from_slice(address.as_ref());
});
Ok(())
Ok(data)
}

/// Efficiently deserialize an address table without allocating
Expand Down Expand Up @@ -352,9 +352,8 @@ mod tests {
fn test_case(num_addresses: usize) {
let lookup_table_meta = LookupTableMeta::new_for_tests();
let address_table = AddressLookupTable::new_for_tests(lookup_table_meta, num_addresses);
let mut address_table_data = Vec::new();
AddressLookupTable::serialize_for_tests(address_table.clone(), &mut address_table_data)
.unwrap();
let address_table_data =
AddressLookupTable::serialize_for_tests(address_table.clone()).unwrap();
assert_eq!(
AddressLookupTable::deserialize(&address_table_data).unwrap(),
address_table,
Expand Down
1 change: 1 addition & 0 deletions rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ tokio-util = { version = "0.6", features = ["codec", "compat"] }

[dev-dependencies]
serial_test = "0.6.0"
solana-address-lookup-table-program = { path = "../programs/address-lookup-table", version = "=1.10.1" }
solana-net-utils = { path = "../net-utils", version = "=1.10.1" }
solana-stake-program = { path = "../programs/stake", version = "=1.10.1" }
symlink = "0.1.0"
Expand Down
149 changes: 128 additions & 21 deletions rpc/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use {
},
rpc_response::{Response as RpcResponse, *},
},
solana_entry::entry::Entry,
solana_faucet::faucet::request_airdrop_transaction,
solana_gossip::{cluster_info::ClusterInfo, contact_info::ContactInfo},
solana_ledger::{
Expand Down Expand Up @@ -4286,22 +4287,18 @@ pub(crate) fn create_validator_exit(exit: &Arc<AtomicBool>) -> Arc<RwLock<Exit>>
Arc::new(RwLock::new(validator_exit))
}

// Used for tests
pub fn create_test_transactions_and_populate_blockstore(
pub fn create_test_transaction_entries(
keypairs: Vec<&Keypair>,
previous_slot: Slot,
bank: Arc<Bank>,
blockstore: Arc<Blockstore>,
max_complete_transaction_status_slot: Arc<AtomicU64>,
) -> Vec<Signature> {
) -> (Vec<Entry>, 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();
let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);

let mut signatures = Vec::new();
// Generate transactions for processing
// Successful transaction
let success_tx = solana_sdk::system_transaction::transfer(
Expand All @@ -4310,7 +4307,7 @@ pub fn create_test_transactions_and_populate_blockstore(
rent_exempt_amount,
blockhash,
);
let success_signature = success_tx.signatures[0];
signatures.push(success_tx.signatures[0]);
let entry_1 = solana_entry::entry::next_entry(&blockhash, 1, vec![success_tx]);
// Failed transaction, InstructionError
let ix_error_tx = solana_sdk::system_transaction::transfer(
Expand All @@ -4319,12 +4316,21 @@ pub fn create_test_transactions_and_populate_blockstore(
2 * rent_exempt_amount,
blockhash,
);
let ix_error_signature = ix_error_tx.signatures[0];
signatures.push(ix_error_tx.signatures[0]);
let entry_2 = solana_entry::entry::next_entry(&entry_1.hash, 1, vec![ix_error_tx]);
let entries = vec![entry_1, entry_2];
(vec![entry_1, entry_2], signatures)
}

pub fn populate_blockstore_for_tests(
entries: Vec<Entry>,
bank: Arc<Bank>,
blockstore: Arc<Blockstore>,
max_complete_transaction_status_slot: Arc<AtomicU64>,
) {
let slot = bank.slot();
let parent_slot = bank.parent_slot();
let shreds =
solana_ledger::blockstore::entries_to_test_shreds(&entries, slot, previous_slot, true, 0);
solana_ledger::blockstore::entries_to_test_shreds(&entries, slot, parent_slot, true, 0);
blockstore.insert_shreds(shreds, None, false).unwrap();
blockstore.set_roots(std::iter::once(&slot)).unwrap();

Expand Down Expand Up @@ -4359,8 +4365,6 @@ pub fn create_test_transactions_and_populate_blockstore(
);

transaction_status_service.join().unwrap();

vec![success_signature, ix_error_signature]
}

#[cfg(test)]
Expand All @@ -4379,13 +4383,16 @@ pub mod tests {
jsonrpc_core::{futures, ErrorCode, MetaIoHandler, Output, Response, Value},
jsonrpc_core_client::transports::local,
serde::de::DeserializeOwned,
solana_address_lookup_table_program::state::{AddressLookupTable, LookupTableMeta},
solana_client::{
rpc_custom_error::{
JSON_RPC_SERVER_ERROR_BLOCK_NOT_AVAILABLE,
JSON_RPC_SERVER_ERROR_TRANSACTION_HISTORY_NOT_AVAILABLE,
JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION,
},
rpc_filter::{Memcmp, MemcmpEncodedBytes},
},
solana_entry::entry::next_versioned_entry,
solana_gossip::{contact_info::ContactInfo, socketaddr},
solana_ledger::{
blockstore_meta::PerfSample,
Expand All @@ -4402,9 +4409,10 @@ pub mod tests {
fee_calculator::DEFAULT_BURN_PERCENT,
hash::{hash, Hash},
instruction::InstructionError,
message::{v0, MessageHeader, VersionedMessage},
message::{v0, v0::MessageAddressTableLookup, MessageHeader, VersionedMessage},
nonce, rpc_port,
signature::{Keypair, Signer},
slot_hashes::SlotHashes,
system_program, system_transaction,
timing::slot_duration_from_slots_per_year,
transaction::{self, DisabledAddressLoader, Transaction, TransactionError},
Expand All @@ -4421,7 +4429,7 @@ pub mod tests {
solana_program::{program_option::COption, pubkey::Pubkey as SplTokenPubkey},
state::{AccountState as TokenAccountState, Mint},
},
std::collections::HashMap,
std::{borrow::Cow, collections::HashMap},
};

fn spl_token_id() -> Pubkey {
Expand Down Expand Up @@ -4557,22 +4565,91 @@ pub mod tests {
serde_json::from_str(response).expect("failed to deserialize response")
}

fn overwrite_working_bank_entries(&self, entries: Vec<Entry>) {
populate_blockstore_for_tests(
entries,
self.working_bank(),
self.blockstore.clone(),
self.max_complete_transaction_status_slot.clone(),
);
}

fn create_test_transactions_and_populate_blockstore(&self) -> Vec<Signature> {
let mint_keypair = &self.mint_keypair;
let keypair1 = Keypair::new();
let keypair2 = Keypair::new();
let keypair3 = Keypair::new();
let bank = self.bank_forks.read().unwrap().working_bank();
let bank = self.working_bank();
let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
bank.transfer(rent_exempt_amount, mint_keypair, &keypair2.pubkey())
.unwrap();
create_test_transactions_and_populate_blockstore(

let (entries, signatures) = create_test_transaction_entries(
vec![&self.mint_keypair, &keypair1, &keypair2, &keypair3],
0,
bank,
self.blockstore.clone(),
self.max_complete_transaction_status_slot.clone(),
)
);
self.overwrite_working_bank_entries(entries);
signatures
}

fn create_test_versioned_transactions_and_populate_blockstore(
&self,
address_table_key: Option<Pubkey>,
) -> Vec<Signature> {
let address_table_key =
address_table_key.unwrap_or_else(|| self.store_address_lookup_table());

let bank = self.working_bank();
let recent_blockhash = bank.confirmed_last_blockhash();
let message = VersionedMessage::V0(v0::Message {
header: MessageHeader {
num_required_signatures: 1,
num_readonly_signed_accounts: 0,
num_readonly_unsigned_accounts: 0,
},
recent_blockhash,
account_keys: vec![self.mint_keypair.pubkey()],
address_table_lookups: vec![MessageAddressTableLookup {
account_key: address_table_key,
writable_indexes: vec![0],
readonly_indexes: vec![],
}],
instructions: vec![],
});

let tx = VersionedTransaction::try_new(message, &[&self.mint_keypair]).unwrap();
let signature = tx.signatures[0];
let entry = next_versioned_entry(&recent_blockhash, 1, vec![tx]);
let entries = vec![entry];
self.overwrite_working_bank_entries(entries);
vec![signature]
}

fn store_address_lookup_table(&self) -> Pubkey {
let bank = self.working_bank();
let address_table_pubkey = Pubkey::new_unique();
let address_table_account = {
let address_table_state = AddressLookupTable {
meta: LookupTableMeta {
// ensure that active address length is 1 at slot 0
last_extended_slot_start_index: 1,
..LookupTableMeta::default()
},
addresses: Cow::Owned(vec![Pubkey::new_unique()]),
};
let address_table_data = address_table_state.serialize_for_tests().unwrap();
let min_balance_lamports =
bank.get_minimum_balance_for_rent_exemption(address_table_data.len());
AccountSharedData::create(
min_balance_lamports,
address_table_data,
solana_address_lookup_table_program::id(),
false,
0,
)
};
bank.store_account(&address_table_pubkey, &address_table_account);
address_table_pubkey
}

fn add_roots_to_blockstore(&self, mut roots: Vec<Slot>) {
Expand Down Expand Up @@ -6310,6 +6387,36 @@ pub mod tests {
assert_eq!(result, expected);
}

#[test]
fn test_get_block_with_versioned_tx() {
let rpc = RpcHandler::start();

let bank = rpc.working_bank();
// Slot hashes is necessary for processing versioned txs.
bank.set_sysvar_for_tests(&SlotHashes::default());
rpc.create_test_versioned_transactions_and_populate_blockstore(None);

let request = create_test_request(
"getBlock",
Some(json!([
0u64,
{"maxSupportedTransactionVersion": 0},
])),
);
let result: Option<EncodedConfirmedBlock> =
parse_success_result(rpc.handle_request_sync(request));
let confirmed_block = result.unwrap();
assert_eq!(confirmed_block.transactions.len(), 1);

let request = create_test_request("getBlock", Some(json!([0u64,])));
let response = parse_failure_response(rpc.handle_request_sync(request));
let expected = (
JSON_RPC_SERVER_ERROR_UNSUPPORTED_TRANSACTION_VERSION,
String::from("Transaction version (0) is not supported"),
);
assert_eq!(response, expected);
}

#[test]
fn test_get_block() {
let mut rpc = RpcHandler::start();
Expand Down
Loading

0 comments on commit 62e5b49

Please sign in to comment.