Refactor RPC subscriptions account handling (#9888)

* Switch subscriptions to use commitment instead of confirmations

* Add bank method to return account and last-modified slot

* Add last_modified_slot to subscription data and use to filter account subscriptions

* Update tests to non-zero last_notified_slot

* Add accounts subscriptions to test; fails at higher tx load

* Pass BankForks to RpcSubscriptions

* Use BankForks on add_account_subscription to properly initialize last_notified_slot

* Bundle subscriptions

* Check for non-equality

* Use commitment to initialize last_notified_slot; revert context.slot chage
This commit is contained in:
Tyera Eulberg
2020-05-07 00:23:06 -06:00
committed by GitHub
parent f6e26f6c8c
commit 754c65c066
10 changed files with 464 additions and 277 deletions

View File

@ -6,7 +6,13 @@ use solana_core::{
commitment::BlockCommitmentCache, rpc_pubsub_service::PubSubService,
rpc_subscriptions::RpcSubscriptions, validator::TestValidator,
};
use solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path};
use solana_ledger::{
bank_forks::BankForks,
blockstore::Blockstore,
genesis_utils::{create_genesis_config, GenesisConfigInfo},
get_tmp_ledger_path,
};
use solana_runtime::bank::Bank;
use solana_sdk::{
commitment_config::CommitmentConfig, pubkey::Pubkey, rpc_port, signature::Signer,
system_transaction,
@ -88,8 +94,12 @@ fn test_slot_subscription() {
let exit = Arc::new(AtomicBool::new(false));
let ledger_path = get_tmp_ledger_path!();
let blockstore = Arc::new(Blockstore::open(&ledger_path).unwrap());
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
let bank = Bank::new(&genesis_config);
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
let subscriptions = Arc::new(RpcSubscriptions::new(
&exit,
bank_forks,
Arc::new(RwLock::new(BlockCommitmentCache::default_with_blockstore(
blockstore,
))),

View File

@ -9,7 +9,7 @@ use reqwest::{self, header::CONTENT_TYPE};
use serde_json::{json, Value};
use solana_client::{
rpc_client::{get_rpc_request_str, RpcClient},
rpc_response::{Response, RpcSignatureResult},
rpc_response::{Response, RpcAccount, RpcSignatureResult},
};
use solana_core::contact_info::ContactInfo;
use solana_core::{rpc_pubsub::gen_client::Client as PubsubClient, validator::TestValidator};
@ -164,9 +164,15 @@ fn test_rpc_subscriptions() {
.iter()
.map(|tx| tx.signatures[0].to_string())
.collect();
let account_set: HashSet<String> = transactions
.iter()
.map(|tx| tx.message.account_keys[1].to_string())
.collect();
// Track when subscriptions are ready
let (ready_sender, ready_receiver) = channel::<()>();
// Track account notifications are received
let (account_sender, account_receiver) = channel::<Response<RpcAccount>>();
// Track when status notifications are received
let (status_sender, status_receiver) = channel::<(String, Response<RpcSignatureResult>)>();
@ -209,6 +215,22 @@ fn test_rpc_subscriptions() {
eprintln!("slot sub err: {:#?}", err);
}),
);
for pubkey in account_set {
let account_sender = account_sender.clone();
tokio::spawn(
client
.account_subscribe(pubkey, None)
.and_then(move |account_stream| {
account_stream.for_each(move |result| {
account_sender.send(result).unwrap();
future::ok(())
})
})
.map_err(|err| {
eprintln!("acct sub err: {:#?}", err);
}),
);
}
future::ok(())
})
.map_err(|_| ())
@ -262,6 +284,26 @@ fn test_rpc_subscriptions() {
}
}
let deadline = Instant::now() + Duration::from_secs(5);
let mut account_notifications = transactions.len();
while account_notifications > 0 {
let timeout = deadline.saturating_duration_since(Instant::now());
match account_receiver.recv_timeout(timeout) {
Ok(result) => {
assert_eq!(result.value.lamports, 1);
account_notifications -= 1;
}
Err(_err) => {
assert!(
false,
"recv_timeout, {}/{} accounts remaining",
account_notifications,
transactions.len()
);
}
}
}
rt.shutdown_now().wait().unwrap();
server.close().unwrap();
remove_dir_all(ledger_path).unwrap();