2019-02-17 08:38:36 -08:00
|
|
|
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
2022-05-11 21:17:21 -07:00
|
|
|
|
2021-05-18 23:54:28 -07:00
|
|
|
use {
|
|
|
|
crate::{
|
|
|
|
optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank,
|
|
|
|
parsed_token_accounts::{get_parsed_token_account, get_parsed_token_accounts},
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc_pubsub_service::PubSubConfig,
|
|
|
|
rpc_subscription_tracker::{
|
2021-12-17 15:03:09 -08:00
|
|
|
AccountSubscriptionParams, BlockSubscriptionKind, BlockSubscriptionParams,
|
|
|
|
LogsSubscriptionKind, LogsSubscriptionParams, ProgramSubscriptionParams,
|
|
|
|
SignatureSubscriptionParams, SubscriptionControl, SubscriptionId, SubscriptionInfo,
|
|
|
|
SubscriptionParams, SubscriptionsTracker,
|
2021-09-17 12:40:14 -07:00
|
|
|
},
|
2020-09-01 22:06:06 -07:00
|
|
|
},
|
2021-09-17 12:40:14 -07:00
|
|
|
crossbeam_channel::{Receiver, RecvTimeoutError, SendError, Sender},
|
2021-10-31 23:17:24 -07:00
|
|
|
rayon::prelude::*,
|
2021-05-18 23:54:28 -07:00
|
|
|
serde::Serialize,
|
2022-01-25 20:32:21 -08:00
|
|
|
solana_account_decoder::{parse_token::is_known_spl_token_id, UiAccount, UiAccountEncoding},
|
2022-04-20 18:18:12 -07:00
|
|
|
solana_client::rpc_response::{
|
2022-05-11 21:17:21 -07:00
|
|
|
ProcessedSignatureResult, ReceivedSignatureResult, Response as RpcResponse, RpcBlockUpdate,
|
2022-04-20 18:18:12 -07:00
|
|
|
RpcBlockUpdateError, RpcKeyedAccount, RpcLogsResponse, RpcResponseContext,
|
|
|
|
RpcSignatureResult, RpcVote, SlotInfo, SlotUpdate,
|
2021-05-18 23:54:28 -07:00
|
|
|
},
|
2021-12-17 15:03:09 -08:00
|
|
|
solana_ledger::{blockstore::Blockstore, get_tmp_ledger_path},
|
2021-05-18 23:54:28 -07:00
|
|
|
solana_measure::measure::Measure,
|
2021-10-31 23:17:24 -07:00
|
|
|
solana_rayon_threadlimit::get_thread_count,
|
2021-05-18 23:54:28 -07:00
|
|
|
solana_runtime::{
|
2021-09-17 12:40:14 -07:00
|
|
|
bank::{Bank, TransactionLogInfo},
|
2021-05-18 23:54:28 -07:00
|
|
|
bank_forks::BankForks,
|
|
|
|
commitment::{BlockCommitmentCache, CommitmentSlots},
|
2022-01-19 18:39:21 -08:00
|
|
|
vote_transaction::VoteTransaction,
|
2021-05-18 23:54:28 -07:00
|
|
|
},
|
|
|
|
solana_sdk::{
|
|
|
|
account::{AccountSharedData, ReadableAccount},
|
2021-10-29 10:11:20 -07:00
|
|
|
clock::Slot,
|
2021-05-18 23:54:28 -07:00
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::Signature,
|
|
|
|
timing::timestamp,
|
|
|
|
transaction,
|
|
|
|
},
|
2022-03-07 23:20:34 -08:00
|
|
|
solana_transaction_status::{
|
|
|
|
BlockEncodingOptions, ConfirmedBlock, EncodeError, VersionedConfirmedBlock,
|
|
|
|
},
|
2021-05-18 23:54:28 -07:00
|
|
|
std::{
|
2021-10-31 23:17:24 -07:00
|
|
|
cell::RefCell,
|
2021-09-17 12:40:14 -07:00
|
|
|
collections::{HashMap, VecDeque},
|
|
|
|
io::Cursor,
|
|
|
|
iter, str,
|
2021-05-18 23:54:28 -07:00
|
|
|
sync::{
|
2021-12-17 15:03:09 -08:00
|
|
|
atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering},
|
2021-10-31 23:17:24 -07:00
|
|
|
Arc, Mutex, RwLock, Weak,
|
2021-05-18 23:54:28 -07:00
|
|
|
},
|
|
|
|
thread::{Builder, JoinHandle},
|
2021-12-03 09:00:31 -08:00
|
|
|
time::{Duration, Instant},
|
2020-11-20 13:52:58 -08:00
|
|
|
},
|
2021-09-17 12:40:14 -07:00
|
|
|
tokio::sync::broadcast,
|
2020-01-15 10:52:02 -08:00
|
|
|
};
|
2020-07-23 08:35:23 -07:00
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
const RECEIVE_DELAY_MILLIS: u64 = 100;
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn get_transaction_logs(
|
|
|
|
bank: &Bank,
|
|
|
|
params: &LogsSubscriptionParams,
|
|
|
|
) -> Option<Vec<TransactionLogInfo>> {
|
|
|
|
let pubkey = match ¶ms.kind {
|
|
|
|
LogsSubscriptionKind::All | LogsSubscriptionKind::AllWithVotes => None,
|
|
|
|
LogsSubscriptionKind::Single(pubkey) => Some(pubkey),
|
|
|
|
};
|
|
|
|
let mut logs = bank.get_transaction_logs(pubkey);
|
|
|
|
if matches!(params.kind, LogsSubscriptionKind::All) {
|
|
|
|
// Filter out votes if the subscriber doesn't want them
|
|
|
|
if let Some(logs) = &mut logs {
|
|
|
|
logs.retain(|log| !log.is_vote);
|
2020-11-20 13:52:58 -08:00
|
|
|
}
|
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
logs
|
2020-11-20 13:52:58 -08:00
|
|
|
}
|
2021-10-31 23:17:24 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct TimestampedNotificationEntry {
|
|
|
|
pub entry: NotificationEntry,
|
|
|
|
pub queued_at: Instant,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<NotificationEntry> for TimestampedNotificationEntry {
|
|
|
|
fn from(entry: NotificationEntry) -> Self {
|
|
|
|
TimestampedNotificationEntry {
|
|
|
|
entry,
|
|
|
|
queued_at: Instant::now(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
pub enum NotificationEntry {
|
2020-01-20 13:08:29 -08:00
|
|
|
Slot(SlotInfo),
|
2021-02-28 23:29:11 -08:00
|
|
|
SlotUpdate(SlotUpdate),
|
2022-01-26 22:03:03 -08:00
|
|
|
Vote((Pubkey, VoteTransaction)),
|
2020-03-27 09:33:40 -07:00
|
|
|
Root(Slot),
|
2020-07-17 10:54:49 -07:00
|
|
|
Bank(CommitmentSlots),
|
2020-05-22 12:55:17 -07:00
|
|
|
Gossip(Slot),
|
2020-09-01 22:06:06 -07:00
|
|
|
SignaturesReceived((Slot, Vec<Signature>)),
|
2021-09-17 12:40:14 -07:00
|
|
|
Subscribed(SubscriptionParams, SubscriptionId),
|
|
|
|
Unsubscribed(SubscriptionParams, SubscriptionId),
|
2020-01-20 13:08:29 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Debug for NotificationEntry {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
match self {
|
2020-03-27 09:33:40 -07:00
|
|
|
NotificationEntry::Root(root) => write!(f, "Root({})", root),
|
2020-05-17 14:01:08 -07:00
|
|
|
NotificationEntry::Vote(vote) => write!(f, "Vote({:?})", vote),
|
2020-01-20 13:08:29 -08:00
|
|
|
NotificationEntry::Slot(slot_info) => write!(f, "Slot({:?})", slot_info),
|
2021-02-28 23:29:11 -08:00
|
|
|
NotificationEntry::SlotUpdate(slot_update) => {
|
|
|
|
write!(f, "SlotUpdate({:?})", slot_update)
|
|
|
|
}
|
2020-07-17 10:54:49 -07:00
|
|
|
NotificationEntry::Bank(commitment_slots) => {
|
|
|
|
write!(f, "Bank({{slot: {:?}}})", commitment_slots.slot)
|
2020-07-17 08:24:51 -07:00
|
|
|
}
|
2020-09-01 22:06:06 -07:00
|
|
|
NotificationEntry::SignaturesReceived(slot_signatures) => {
|
|
|
|
write!(f, "SignaturesReceived({:?})", slot_signatures)
|
|
|
|
}
|
2020-05-22 12:55:17 -07:00
|
|
|
NotificationEntry::Gossip(slot) => write!(f, "Gossip({:?})", slot),
|
2021-09-17 12:40:14 -07:00
|
|
|
NotificationEntry::Subscribed(params, id) => {
|
|
|
|
write!(f, "Subscribed({:?}, {:?})", params, id)
|
|
|
|
}
|
|
|
|
NotificationEntry::Unsubscribed(params, id) => {
|
|
|
|
write!(f, "Unsubscribed({:?}, {:?})", params, id)
|
|
|
|
}
|
2020-01-20 13:08:29 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-23 05:34:42 -07:00
|
|
|
#[allow(clippy::type_complexity)]
|
2021-09-17 12:40:14 -07:00
|
|
|
fn check_commitment_and_notify<P, S, B, F, X>(
|
|
|
|
params: &P,
|
|
|
|
subscription: &SubscriptionInfo,
|
2019-05-06 07:31:50 -07:00
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
2021-12-17 15:03:09 -08:00
|
|
|
slot: Slot,
|
2020-02-25 20:23:54 -08:00
|
|
|
bank_method: B,
|
|
|
|
filter_results: F,
|
2021-10-31 23:17:24 -07:00
|
|
|
notifier: &RpcNotifier,
|
2021-09-17 12:40:14 -07:00
|
|
|
is_final: bool,
|
|
|
|
) -> bool
|
2020-02-13 09:00:50 -08:00
|
|
|
where
|
2019-05-06 07:31:50 -07:00
|
|
|
S: Clone + Serialize,
|
2021-09-17 12:40:14 -07:00
|
|
|
B: Fn(&Bank, &P) -> X,
|
|
|
|
F: Fn(X, &P, Slot, Arc<Bank>) -> (Box<dyn Iterator<Item = S>>, Slot),
|
2020-11-20 13:52:58 -08:00
|
|
|
X: Clone + Default,
|
2019-05-06 07:31:50 -07:00
|
|
|
{
|
2021-09-17 12:40:14 -07:00
|
|
|
let mut notified = false;
|
2022-04-29 01:32:46 -07:00
|
|
|
let bank = bank_forks.read().unwrap().get(slot);
|
|
|
|
if let Some(bank) = bank {
|
2021-09-17 12:40:14 -07:00
|
|
|
let results = bank_method(&bank, params);
|
|
|
|
let mut w_last_notified_slot = subscription.last_notified_slot.write().unwrap();
|
|
|
|
let (filter_results, result_slot) =
|
|
|
|
filter_results(results, params, *w_last_notified_slot, bank);
|
|
|
|
for result in filter_results {
|
|
|
|
notifier.notify(
|
2022-05-11 21:17:21 -07:00
|
|
|
RpcResponse::from(RpcNotificationResponse {
|
|
|
|
context: RpcNotificationContext { slot },
|
2021-09-17 12:40:14 -07:00
|
|
|
value: result,
|
2022-05-11 21:17:21 -07:00
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
subscription,
|
|
|
|
is_final,
|
|
|
|
);
|
|
|
|
*w_last_notified_slot = result_slot;
|
|
|
|
notified = true;
|
|
|
|
}
|
|
|
|
}
|
2021-12-17 15:03:09 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
notified
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct RpcNotification {
|
|
|
|
pub subscription_id: SubscriptionId,
|
|
|
|
pub is_final: bool,
|
|
|
|
pub json: Weak<String>,
|
2021-10-31 23:17:24 -07:00
|
|
|
pub created_at: Instant,
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
|
2022-05-11 21:17:21 -07:00
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
struct RpcNotificationResponse<T> {
|
|
|
|
context: RpcNotificationContext,
|
|
|
|
value: T,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> From<RpcNotificationResponse<T>> for RpcResponse<T> {
|
|
|
|
fn from(notification: RpcNotificationResponse<T>) -> Self {
|
|
|
|
let RpcNotificationResponse {
|
|
|
|
context: RpcNotificationContext { slot },
|
|
|
|
value,
|
|
|
|
} = notification;
|
|
|
|
Self {
|
|
|
|
context: RpcResponseContext {
|
|
|
|
slot,
|
|
|
|
api_version: None,
|
|
|
|
},
|
|
|
|
value,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
struct RpcNotificationContext {
|
|
|
|
slot: Slot,
|
|
|
|
}
|
|
|
|
|
2022-04-13 23:29:45 -07:00
|
|
|
const RPC_NOTIFICATIONS_METRICS_SUBMISSION_INTERVAL_MS: Duration = Duration::from_millis(2_000);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
struct RecentItems {
|
|
|
|
queue: VecDeque<Arc<String>>,
|
|
|
|
total_bytes: usize,
|
|
|
|
max_len: usize,
|
|
|
|
max_total_bytes: usize,
|
2022-04-13 23:29:45 -07:00
|
|
|
last_metrics_submission: Instant,
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RecentItems {
|
|
|
|
fn new(max_len: usize, max_total_bytes: usize) -> Self {
|
|
|
|
Self {
|
|
|
|
queue: VecDeque::new(),
|
|
|
|
total_bytes: 0,
|
|
|
|
max_len,
|
|
|
|
max_total_bytes,
|
2022-04-13 23:29:45 -07:00
|
|
|
last_metrics_submission: Instant::now(),
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push(&mut self, item: Arc<String>) {
|
|
|
|
self.total_bytes = self
|
|
|
|
.total_bytes
|
|
|
|
.checked_add(item.len())
|
|
|
|
.expect("total bytes overflow");
|
|
|
|
self.queue.push_back(item);
|
|
|
|
|
|
|
|
while self.total_bytes > self.max_total_bytes || self.queue.len() > self.max_len {
|
|
|
|
let item = self.queue.pop_front().expect("can't be empty");
|
|
|
|
self.total_bytes = self
|
|
|
|
.total_bytes
|
|
|
|
.checked_sub(item.len())
|
|
|
|
.expect("total bytes underflow");
|
2019-05-06 07:31:50 -07:00
|
|
|
}
|
2021-10-06 15:16:56 -07:00
|
|
|
|
2022-04-13 23:29:45 -07:00
|
|
|
let now = Instant::now();
|
|
|
|
let last_metrics_ago = now.duration_since(self.last_metrics_submission);
|
|
|
|
if last_metrics_ago > RPC_NOTIFICATIONS_METRICS_SUBMISSION_INTERVAL_MS {
|
|
|
|
datapoint_info!(
|
|
|
|
"rpc_subscriptions_recent_items",
|
|
|
|
("num", self.queue.len(), i64),
|
|
|
|
("total_bytes", self.total_bytes, i64),
|
|
|
|
);
|
|
|
|
self.last_metrics_submission = now;
|
|
|
|
} else {
|
|
|
|
trace!(
|
|
|
|
"rpc_subscriptions_recent_items num={} total_bytes={}",
|
|
|
|
self.queue.len(),
|
|
|
|
self.total_bytes,
|
|
|
|
);
|
|
|
|
}
|
2019-05-06 07:31:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
struct RpcNotifier {
|
|
|
|
sender: broadcast::Sender<RpcNotification>,
|
2021-10-31 23:17:24 -07:00
|
|
|
recent_items: Mutex<RecentItems>,
|
|
|
|
}
|
|
|
|
|
|
|
|
thread_local! {
|
|
|
|
static RPC_NOTIFIER_BUF: RefCell<Vec<u8>> = RefCell::new(Vec::new());
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
struct NotificationParams<T> {
|
|
|
|
result: T,
|
|
|
|
subscription: SubscriptionId,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
struct Notification<T> {
|
|
|
|
jsonrpc: Option<jsonrpc_core::Version>,
|
|
|
|
method: &'static str,
|
|
|
|
params: NotificationParams<T>,
|
|
|
|
}
|
2020-02-25 20:23:54 -08:00
|
|
|
|
|
|
|
impl RpcNotifier {
|
2021-10-31 23:17:24 -07:00
|
|
|
fn notify<T>(&self, value: T, subscription: &SubscriptionInfo, is_final: bool)
|
2020-02-25 20:23:54 -08:00
|
|
|
where
|
|
|
|
T: serde::Serialize,
|
|
|
|
{
|
2021-10-31 23:17:24 -07:00
|
|
|
let buf_arc = RPC_NOTIFIER_BUF.with(|buf| {
|
|
|
|
let mut buf = buf.borrow_mut();
|
|
|
|
buf.clear();
|
|
|
|
let notification = Notification {
|
|
|
|
jsonrpc: Some(jsonrpc_core::Version::V2),
|
|
|
|
method: subscription.method(),
|
|
|
|
params: NotificationParams {
|
|
|
|
result: value,
|
|
|
|
subscription: subscription.id(),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
serde_json::to_writer(Cursor::new(&mut *buf), ¬ification)
|
|
|
|
.expect("serialization never fails");
|
|
|
|
let buf_str = str::from_utf8(&buf).expect("json is always utf-8");
|
|
|
|
Arc::new(String::from(buf_str))
|
|
|
|
});
|
2021-09-17 12:40:14 -07:00
|
|
|
|
|
|
|
let notification = RpcNotification {
|
|
|
|
subscription_id: subscription.id(),
|
|
|
|
json: Arc::downgrade(&buf_arc),
|
|
|
|
is_final,
|
2021-10-31 23:17:24 -07:00
|
|
|
created_at: Instant::now(),
|
2021-09-17 12:40:14 -07:00
|
|
|
};
|
|
|
|
// There is an unlikely case where this can fail: if the last subscription is closed
|
|
|
|
// just as the notifier generates a notification for it.
|
|
|
|
let _ = self.sender.send(notification);
|
|
|
|
|
|
|
|
inc_new_counter_info!("rpc-pubsub-messages", 1);
|
|
|
|
inc_new_counter_info!("rpc-pubsub-bytes", buf_arc.len());
|
|
|
|
|
2021-10-31 23:17:24 -07:00
|
|
|
self.recent_items.lock().unwrap().push(buf_arc);
|
2020-02-25 20:23:54 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-17 15:03:09 -08:00
|
|
|
fn filter_block_result_txs(
|
2022-03-07 23:20:34 -08:00
|
|
|
mut block: VersionedConfirmedBlock,
|
2021-12-17 15:03:09 -08:00
|
|
|
last_modified_slot: Slot,
|
|
|
|
params: &BlockSubscriptionParams,
|
2022-03-07 23:20:34 -08:00
|
|
|
) -> Result<Option<RpcBlockUpdate>, RpcBlockUpdateError> {
|
2022-02-09 21:28:18 -08:00
|
|
|
block.transactions = match params.kind {
|
2021-12-17 15:03:09 -08:00
|
|
|
BlockSubscriptionKind::All => block.transactions,
|
|
|
|
BlockSubscriptionKind::MentionsAccountOrProgram(pk) => block
|
|
|
|
.transactions
|
|
|
|
.into_iter()
|
2022-03-07 23:20:34 -08:00
|
|
|
.filter(|tx| tx.account_keys().iter().any(|key| key == &pk))
|
2021-12-17 15:03:09 -08:00
|
|
|
.collect(),
|
|
|
|
};
|
|
|
|
|
2022-02-09 21:28:18 -08:00
|
|
|
if block.transactions.is_empty() {
|
2021-12-17 15:03:09 -08:00
|
|
|
if let BlockSubscriptionKind::MentionsAccountOrProgram(_) = params.kind {
|
2022-03-07 23:20:34 -08:00
|
|
|
return Ok(None);
|
2021-12-17 15:03:09 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-07 23:20:34 -08:00
|
|
|
let block = ConfirmedBlock::from(block)
|
|
|
|
.encode_with_options(
|
|
|
|
params.encoding,
|
|
|
|
BlockEncodingOptions {
|
|
|
|
transaction_details: params.transaction_details,
|
|
|
|
show_rewards: params.show_rewards,
|
|
|
|
max_supported_transaction_version: params.max_supported_transaction_version,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.map_err(|err| match err {
|
|
|
|
EncodeError::UnsupportedTransactionVersion(version) => {
|
|
|
|
RpcBlockUpdateError::UnsupportedTransactionVersion(version)
|
|
|
|
}
|
|
|
|
})?;
|
2021-12-17 15:03:09 -08:00
|
|
|
|
|
|
|
// If last_modified_slot < last_notified_slot, then the last notif was for a fork.
|
|
|
|
// That's the risk clients take when subscribing to non-finalized commitments.
|
|
|
|
// This code lets the logic for dealing with forks live on the client side.
|
2022-03-07 23:20:34 -08:00
|
|
|
Ok(Some(RpcBlockUpdate {
|
2021-12-17 15:03:09 -08:00
|
|
|
slot: last_modified_slot,
|
|
|
|
block: Some(block),
|
|
|
|
err: None,
|
2022-03-07 23:20:34 -08:00
|
|
|
}))
|
2021-12-17 15:03:09 -08:00
|
|
|
}
|
|
|
|
|
2020-02-25 20:23:54 -08:00
|
|
|
fn filter_account_result(
|
2021-03-09 13:06:07 -08:00
|
|
|
result: Option<(AccountSharedData, Slot)>,
|
2021-09-17 12:40:14 -07:00
|
|
|
params: &AccountSubscriptionParams,
|
2020-05-06 23:23:06 -07:00
|
|
|
last_notified_slot: Slot,
|
2020-11-10 03:48:42 -08:00
|
|
|
bank: Arc<Bank>,
|
2020-06-30 21:55:11 -07:00
|
|
|
) -> (Box<dyn Iterator<Item = UiAccount>>, Slot) {
|
2020-11-10 03:48:42 -08:00
|
|
|
// If the account is not found, `last_modified_slot` will default to zero and
|
|
|
|
// we will notify clients that the account no longer exists if we haven't already
|
|
|
|
let (account, last_modified_slot) = result.unwrap_or_default();
|
|
|
|
|
|
|
|
// If last_modified_slot < last_notified_slot this means that we last notified for a fork
|
|
|
|
// and should notify that the account state has been reverted.
|
|
|
|
let results: Box<dyn Iterator<Item = UiAccount>> = if last_modified_slot != last_notified_slot {
|
2022-01-25 20:32:21 -08:00
|
|
|
if is_known_spl_token_id(account.owner())
|
|
|
|
&& params.encoding == UiAccountEncoding::JsonParsed
|
|
|
|
{
|
2021-09-17 12:40:14 -07:00
|
|
|
Box::new(iter::once(get_parsed_token_account(
|
|
|
|
bank,
|
|
|
|
¶ms.pubkey,
|
|
|
|
account,
|
|
|
|
)))
|
2020-11-10 03:48:42 -08:00
|
|
|
} else {
|
|
|
|
Box::new(iter::once(UiAccount::encode(
|
2021-09-17 12:40:14 -07:00
|
|
|
¶ms.pubkey,
|
|
|
|
&account,
|
|
|
|
params.encoding,
|
|
|
|
None,
|
|
|
|
None,
|
2020-11-10 03:48:42 -08:00
|
|
|
)))
|
2019-05-06 07:31:50 -07:00
|
|
|
}
|
2020-11-10 03:48:42 -08:00
|
|
|
} else {
|
|
|
|
Box::new(iter::empty())
|
|
|
|
};
|
|
|
|
|
|
|
|
(results, last_modified_slot)
|
2019-05-06 07:31:50 -07:00
|
|
|
}
|
|
|
|
|
2020-04-04 16:13:26 -07:00
|
|
|
fn filter_signature_result(
|
|
|
|
result: Option<transaction::Result<()>>,
|
2021-09-17 12:40:14 -07:00
|
|
|
_params: &SignatureSubscriptionParams,
|
2020-05-06 23:23:06 -07:00
|
|
|
last_notified_slot: Slot,
|
2020-11-10 03:48:42 -08:00
|
|
|
_bank: Arc<Bank>,
|
2020-05-06 23:23:06 -07:00
|
|
|
) -> (Box<dyn Iterator<Item = RpcSignatureResult>>, Slot) {
|
|
|
|
(
|
2020-09-01 22:06:06 -07:00
|
|
|
Box::new(result.into_iter().map(|result| {
|
2020-09-03 17:14:45 -07:00
|
|
|
RpcSignatureResult::ProcessedSignature(ProcessedSignatureResult { err: result.err() })
|
2020-09-01 22:06:06 -07:00
|
|
|
})),
|
2020-05-06 23:23:06 -07:00
|
|
|
last_notified_slot,
|
2020-04-04 16:13:26 -07:00
|
|
|
)
|
2019-05-06 07:31:50 -07:00
|
|
|
}
|
|
|
|
|
2020-02-25 20:23:54 -08:00
|
|
|
fn filter_program_results(
|
2021-03-09 13:06:07 -08:00
|
|
|
accounts: Vec<(Pubkey, AccountSharedData)>,
|
2021-09-17 12:40:14 -07:00
|
|
|
params: &ProgramSubscriptionParams,
|
2020-05-06 23:23:06 -07:00
|
|
|
last_notified_slot: Slot,
|
2020-11-10 03:48:42 -08:00
|
|
|
bank: Arc<Bank>,
|
2020-05-06 23:23:06 -07:00
|
|
|
) -> (Box<dyn Iterator<Item = RpcKeyedAccount>>, Slot) {
|
2020-09-09 14:07:29 -07:00
|
|
|
let accounts_is_empty = accounts.is_empty();
|
2021-09-17 12:40:14 -07:00
|
|
|
let encoding = params.encoding;
|
|
|
|
let filters = params.filters.clone();
|
2020-08-07 10:37:39 -07:00
|
|
|
let keyed_accounts = accounts.into_iter().filter(move |(_, account)| {
|
2022-04-20 18:18:12 -07:00
|
|
|
filters
|
|
|
|
.iter()
|
|
|
|
.all(|filter_type| filter_type.allows(account))
|
2020-08-07 10:37:39 -07:00
|
|
|
});
|
2022-01-25 20:32:21 -08:00
|
|
|
let accounts: Box<dyn Iterator<Item = RpcKeyedAccount>> =
|
|
|
|
if is_known_spl_token_id(¶ms.pubkey)
|
|
|
|
&& params.encoding == UiAccountEncoding::JsonParsed
|
|
|
|
&& !accounts_is_empty
|
|
|
|
{
|
|
|
|
Box::new(get_parsed_token_accounts(bank, keyed_accounts))
|
|
|
|
} else {
|
|
|
|
Box::new(
|
|
|
|
keyed_accounts.map(move |(pubkey, account)| RpcKeyedAccount {
|
|
|
|
pubkey: pubkey.to_string(),
|
|
|
|
account: UiAccount::encode(&pubkey, &account, encoding, None, None),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
};
|
2020-08-07 10:37:39 -07:00
|
|
|
(accounts, last_notified_slot)
|
2019-05-06 07:31:50 -07:00
|
|
|
}
|
|
|
|
|
2020-11-20 13:52:58 -08:00
|
|
|
fn filter_logs_results(
|
|
|
|
logs: Option<Vec<TransactionLogInfo>>,
|
2021-09-17 12:40:14 -07:00
|
|
|
_params: &LogsSubscriptionParams,
|
2020-11-20 13:52:58 -08:00
|
|
|
last_notified_slot: Slot,
|
|
|
|
_bank: Arc<Bank>,
|
|
|
|
) -> (Box<dyn Iterator<Item = RpcLogsResponse>>, Slot) {
|
|
|
|
match logs {
|
|
|
|
None => (Box::new(iter::empty()), last_notified_slot),
|
|
|
|
Some(logs) => (
|
|
|
|
Box::new(logs.into_iter().map(|log| RpcLogsResponse {
|
|
|
|
signature: log.signature.to_string(),
|
|
|
|
err: log.result.err(),
|
|
|
|
logs: log.log_messages,
|
|
|
|
})),
|
|
|
|
last_notified_slot,
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn initial_last_notified_slot(
|
|
|
|
params: &SubscriptionParams,
|
|
|
|
bank_forks: &RwLock<BankForks>,
|
|
|
|
block_commitment_cache: &RwLock<BlockCommitmentCache>,
|
|
|
|
optimistically_confirmed_bank: &RwLock<OptimisticallyConfirmedBank>,
|
2022-04-29 01:32:46 -07:00
|
|
|
) -> Option<Slot> {
|
2021-09-17 12:40:14 -07:00
|
|
|
match params {
|
|
|
|
SubscriptionParams::Account(params) => {
|
|
|
|
let slot = if params.commitment.is_finalized() {
|
|
|
|
block_commitment_cache
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.highest_confirmed_root()
|
|
|
|
} else if params.commitment.is_confirmed() {
|
|
|
|
optimistically_confirmed_bank.read().unwrap().bank.slot()
|
|
|
|
} else {
|
|
|
|
block_commitment_cache.read().unwrap().slot()
|
|
|
|
};
|
2020-05-06 23:23:06 -07:00
|
|
|
|
2022-04-29 01:32:46 -07:00
|
|
|
let bank = bank_forks.read().unwrap().get(slot)?;
|
|
|
|
Some(bank.get_account_modified_slot(¶ms.pubkey)?.1)
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
2022-04-29 01:32:46 -07:00
|
|
|
_ => None,
|
2020-12-11 17:57:40 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-05 19:59:54 -07:00
|
|
|
#[derive(Default)]
|
|
|
|
struct PubsubNotificationStats {
|
|
|
|
since: Option<Instant>,
|
|
|
|
notification_entry_processing_count: u64,
|
|
|
|
notification_entry_processing_time_us: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PubsubNotificationStats {
|
|
|
|
fn maybe_submit(&mut self) {
|
2022-04-13 23:29:45 -07:00
|
|
|
const SUBMIT_CADENCE: Duration = RPC_NOTIFICATIONS_METRICS_SUBMISSION_INTERVAL_MS;
|
2021-11-05 19:59:54 -07:00
|
|
|
let elapsed = self.since.as_ref().map(Instant::elapsed);
|
|
|
|
if elapsed.unwrap_or(Duration::MAX) < SUBMIT_CADENCE {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
datapoint_info!(
|
|
|
|
"pubsub_notification_entries",
|
|
|
|
(
|
|
|
|
"notification_entry_processing_count",
|
|
|
|
self.notification_entry_processing_count,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"notification_entry_processing_time_us",
|
|
|
|
self.notification_entry_processing_time_us,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
);
|
|
|
|
*self = Self {
|
|
|
|
since: Some(Instant::now()),
|
|
|
|
..Self::default()
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-06 23:23:06 -07:00
|
|
|
pub struct RpcSubscriptions {
|
2021-10-31 23:17:24 -07:00
|
|
|
notification_sender: Sender<TimestampedNotificationEntry>,
|
2020-01-20 13:08:29 -08:00
|
|
|
t_cleanup: Option<JoinHandle<()>>,
|
2021-09-17 12:40:14 -07:00
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
exit: Arc<AtomicBool>,
|
2021-09-17 12:40:14 -07:00
|
|
|
control: SubscriptionControl,
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
impl Drop for RpcSubscriptions {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.shutdown().unwrap_or_else(|err| {
|
|
|
|
warn!("RPC Notification - shutdown error: {:?}", err);
|
|
|
|
});
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RpcSubscriptions {
|
2020-03-30 16:53:25 -07:00
|
|
|
pub fn new(
|
|
|
|
exit: &Arc<AtomicBool>,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot: Arc<AtomicU64>,
|
|
|
|
blockstore: Arc<Blockstore>,
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
2020-03-30 16:53:25 -07:00
|
|
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank: Arc<RwLock<OptimisticallyConfirmedBank>>,
|
2020-11-14 09:29:51 -08:00
|
|
|
) -> Self {
|
2021-09-17 12:40:14 -07:00
|
|
|
Self::new_with_config(
|
|
|
|
exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
blockstore,
|
2021-09-17 12:40:14 -07:00
|
|
|
bank_forks,
|
|
|
|
block_commitment_cache,
|
|
|
|
optimistically_confirmed_bank,
|
|
|
|
&PubSubConfig::default(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_for_tests(
|
|
|
|
exit: &Arc<AtomicBool>,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot: Arc<AtomicU64>,
|
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
|
|
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
|
|
|
optimistically_confirmed_bank: Arc<RwLock<OptimisticallyConfirmedBank>>,
|
|
|
|
) -> Self {
|
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
|
|
|
let blockstore = Arc::new(blockstore);
|
|
|
|
|
|
|
|
Self::new_with_config(
|
|
|
|
exit,
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
blockstore,
|
|
|
|
bank_forks,
|
|
|
|
block_commitment_cache,
|
|
|
|
optimistically_confirmed_bank,
|
|
|
|
&PubSubConfig::default_for_tests(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_for_tests_with_blockstore(
|
|
|
|
exit: &Arc<AtomicBool>,
|
|
|
|
max_complete_transaction_status_slot: Arc<AtomicU64>,
|
|
|
|
blockstore: Arc<Blockstore>,
|
2021-09-17 12:40:14 -07:00
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
|
|
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
|
|
|
optimistically_confirmed_bank: Arc<RwLock<OptimisticallyConfirmedBank>>,
|
|
|
|
) -> Self {
|
|
|
|
Self::new_with_config(
|
2020-11-14 09:29:51 -08:00
|
|
|
exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
blockstore,
|
2020-11-14 09:29:51 -08:00
|
|
|
bank_forks,
|
|
|
|
block_commitment_cache,
|
|
|
|
optimistically_confirmed_bank,
|
2021-09-17 12:40:14 -07:00
|
|
|
&PubSubConfig::default_for_tests(),
|
2020-11-14 09:29:51 -08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
pub fn new_with_config(
|
2020-11-14 09:29:51 -08:00
|
|
|
exit: &Arc<AtomicBool>,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot: Arc<AtomicU64>,
|
|
|
|
blockstore: Arc<Blockstore>,
|
2020-11-14 09:29:51 -08:00
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
|
|
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
|
|
|
optimistically_confirmed_bank: Arc<RwLock<OptimisticallyConfirmedBank>>,
|
2021-09-17 12:40:14 -07:00
|
|
|
config: &PubSubConfig,
|
2020-03-30 16:53:25 -07:00
|
|
|
) -> Self {
|
2021-09-17 12:40:14 -07:00
|
|
|
let (notification_sender, notification_receiver) = crossbeam_channel::unbounded();
|
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
let exit_clone = exit.clone();
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = SubscriptionsTracker::new(bank_forks.clone());
|
|
|
|
|
|
|
|
let (broadcast_sender, _) = broadcast::channel(config.queue_capacity_items);
|
2020-01-20 13:08:29 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let notifier = RpcNotifier {
|
|
|
|
sender: broadcast_sender.clone(),
|
2021-10-31 23:17:24 -07:00
|
|
|
recent_items: Mutex::new(RecentItems::new(
|
2021-09-17 12:40:14 -07:00
|
|
|
config.queue_capacity_items,
|
|
|
|
config.queue_capacity_bytes,
|
2021-10-31 23:17:24 -07:00
|
|
|
)),
|
2021-09-17 12:40:14 -07:00
|
|
|
};
|
2021-10-31 23:17:24 -07:00
|
|
|
let notification_threads = config.notification_threads;
|
2020-01-20 13:08:29 -08:00
|
|
|
let t_cleanup = Builder::new()
|
|
|
|
.name("solana-rpc-notifications".to_string())
|
|
|
|
.spawn(move || {
|
2021-10-31 23:17:24 -07:00
|
|
|
let pool = rayon::ThreadPoolBuilder::new()
|
|
|
|
.num_threads(notification_threads.unwrap_or_else(get_thread_count))
|
|
|
|
.thread_name(|i| format!("sol-sub-notif-{}", i))
|
|
|
|
.build()
|
|
|
|
.unwrap();
|
|
|
|
pool.install(|| {
|
|
|
|
Self::process_notifications(
|
|
|
|
exit_clone,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
blockstore,
|
2021-10-31 23:17:24 -07:00
|
|
|
notifier,
|
|
|
|
notification_receiver,
|
|
|
|
subscriptions,
|
|
|
|
bank_forks,
|
|
|
|
block_commitment_cache,
|
|
|
|
optimistically_confirmed_bank,
|
|
|
|
)
|
|
|
|
});
|
2020-01-20 13:08:29 -08:00
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let control = SubscriptionControl::new(
|
2021-10-23 00:04:15 -07:00
|
|
|
config.max_active_subscriptions,
|
2021-09-17 12:40:14 -07:00
|
|
|
notification_sender.clone(),
|
|
|
|
broadcast_sender,
|
|
|
|
);
|
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
Self {
|
|
|
|
notification_sender,
|
|
|
|
t_cleanup: Some(t_cleanup),
|
2021-09-17 12:40:14 -07:00
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
exit: exit.clone(),
|
2021-09-17 12:40:14 -07:00
|
|
|
control,
|
2020-01-20 13:08:29 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-14 09:29:51 -08:00
|
|
|
// For tests only...
|
2021-12-17 15:03:09 -08:00
|
|
|
pub fn default_with_bank_forks(
|
|
|
|
max_complete_transaction_status_slot: Arc<AtomicU64>,
|
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
|
|
|
) -> Self {
|
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
|
|
|
let blockstore = Arc::new(blockstore);
|
2020-09-28 19:43:05 -07:00
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
2021-09-17 12:40:14 -07:00
|
|
|
Self::new(
|
2020-04-22 11:22:09 -07:00
|
|
|
&Arc::new(AtomicBool::new(false)),
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
blockstore,
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks,
|
2020-06-25 21:06:58 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::default())),
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank,
|
2020-11-20 13:52:58 -08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
pub fn control(&self) -> &SubscriptionControl {
|
|
|
|
&self.control
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
2019-02-18 14:21:23 -08:00
|
|
|
|
|
|
|
/// Notify subscribers of changes to any accounts or new signatures since
|
|
|
|
/// the bank's last checkpoint.
|
2020-07-17 10:54:49 -07:00
|
|
|
pub fn notify_subscribers(&self, commitment_slots: CommitmentSlots) {
|
|
|
|
self.enqueue_notification(NotificationEntry::Bank(commitment_slots));
|
2019-02-18 14:21:23 -08:00
|
|
|
}
|
2019-11-26 00:42:54 -08:00
|
|
|
|
2021-01-26 11:23:07 -08:00
|
|
|
/// Notify Confirmed commitment-level subscribers of changes to any accounts or new
|
2020-05-22 12:55:17 -07:00
|
|
|
/// signatures.
|
|
|
|
pub fn notify_gossip_subscribers(&self, slot: Slot) {
|
|
|
|
self.enqueue_notification(NotificationEntry::Gossip(slot));
|
|
|
|
}
|
|
|
|
|
2021-02-28 23:29:11 -08:00
|
|
|
pub fn notify_slot_update(&self, slot_update: SlotUpdate) {
|
|
|
|
self.enqueue_notification(NotificationEntry::SlotUpdate(slot_update));
|
|
|
|
}
|
|
|
|
|
2019-11-26 00:42:54 -08:00
|
|
|
pub fn notify_slot(&self, slot: Slot, parent: Slot, root: Slot) {
|
2020-01-20 13:08:29 -08:00
|
|
|
self.enqueue_notification(NotificationEntry::Slot(SlotInfo { slot, parent, root }));
|
2021-03-12 05:44:06 -08:00
|
|
|
self.enqueue_notification(NotificationEntry::SlotUpdate(SlotUpdate::CreatedBank {
|
|
|
|
slot,
|
|
|
|
parent,
|
|
|
|
timestamp: timestamp(),
|
|
|
|
}));
|
2020-01-20 13:08:29 -08:00
|
|
|
}
|
|
|
|
|
2020-09-01 22:06:06 -07:00
|
|
|
pub fn notify_signatures_received(&self, slot_signatures: (Slot, Vec<Signature>)) {
|
|
|
|
self.enqueue_notification(NotificationEntry::SignaturesReceived(slot_signatures));
|
|
|
|
}
|
|
|
|
|
2022-01-26 22:03:03 -08:00
|
|
|
pub fn notify_vote(&self, vote_pubkey: Pubkey, vote: VoteTransaction) {
|
|
|
|
self.enqueue_notification(NotificationEntry::Vote((vote_pubkey, vote)));
|
2020-05-17 14:01:08 -07:00
|
|
|
}
|
|
|
|
|
2020-03-27 09:33:40 -07:00
|
|
|
pub fn notify_roots(&self, mut rooted_slots: Vec<Slot>) {
|
2020-12-13 17:26:34 -08:00
|
|
|
rooted_slots.sort_unstable();
|
2020-03-27 09:33:40 -07:00
|
|
|
rooted_slots.into_iter().for_each(|root| {
|
2021-02-28 23:29:11 -08:00
|
|
|
self.enqueue_notification(NotificationEntry::SlotUpdate(SlotUpdate::Root {
|
|
|
|
slot: root,
|
|
|
|
timestamp: timestamp(),
|
|
|
|
}));
|
2020-03-27 09:33:40 -07:00
|
|
|
self.enqueue_notification(NotificationEntry::Root(root));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
fn enqueue_notification(&self, notification_entry: NotificationEntry) {
|
2021-10-31 23:17:24 -07:00
|
|
|
match self.notification_sender.send(notification_entry.into()) {
|
2020-01-20 13:08:29 -08:00
|
|
|
Ok(()) => (),
|
|
|
|
Err(SendError(notification)) => {
|
|
|
|
warn!(
|
|
|
|
"Dropped RPC Notification - receiver disconnected : {:?}",
|
|
|
|
notification
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_notifications(
|
|
|
|
exit: Arc<AtomicBool>,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot: Arc<AtomicU64>,
|
|
|
|
blockstore: Arc<Blockstore>,
|
2021-10-31 23:17:24 -07:00
|
|
|
notifier: RpcNotifier,
|
|
|
|
notification_receiver: Receiver<TimestampedNotificationEntry>,
|
2021-09-17 12:40:14 -07:00
|
|
|
mut subscriptions: SubscriptionsTracker,
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
2021-09-17 12:40:14 -07:00
|
|
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
|
|
|
optimistically_confirmed_bank: Arc<RwLock<OptimisticallyConfirmedBank>>,
|
2020-01-20 13:08:29 -08:00
|
|
|
) {
|
2021-11-05 19:59:54 -07:00
|
|
|
let mut stats = PubsubNotificationStats::default();
|
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
loop {
|
|
|
|
if exit.load(Ordering::Relaxed) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
match notification_receiver.recv_timeout(Duration::from_millis(RECEIVE_DELAY_MILLIS)) {
|
2021-09-17 12:40:14 -07:00
|
|
|
Ok(notification_entry) => {
|
2021-10-31 23:17:24 -07:00
|
|
|
let TimestampedNotificationEntry { entry, queued_at } = notification_entry;
|
|
|
|
match entry {
|
2021-09-17 12:40:14 -07:00
|
|
|
NotificationEntry::Subscribed(params, id) => {
|
|
|
|
subscriptions.subscribe(params.clone(), id, || {
|
|
|
|
initial_last_notified_slot(
|
|
|
|
¶ms,
|
|
|
|
&bank_forks,
|
|
|
|
&block_commitment_cache,
|
|
|
|
&optimistically_confirmed_bank,
|
|
|
|
)
|
2022-04-29 01:32:46 -07:00
|
|
|
.unwrap_or(0)
|
2021-09-17 12:40:14 -07:00
|
|
|
});
|
2020-11-16 22:37:38 -08:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
NotificationEntry::Unsubscribed(params, id) => {
|
|
|
|
subscriptions.unsubscribe(params, id);
|
2020-02-20 16:03:46 -08:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
NotificationEntry::Slot(slot_info) => {
|
|
|
|
if let Some(sub) = subscriptions
|
|
|
|
.node_progress_watchers()
|
|
|
|
.get(&SubscriptionParams::Slot)
|
|
|
|
{
|
|
|
|
debug!("slot notify: {:?}", slot_info);
|
|
|
|
inc_new_counter_info!("rpc-subscription-notify-slot", 1);
|
|
|
|
notifier.notify(&slot_info, sub, false);
|
|
|
|
}
|
2021-02-28 23:29:11 -08:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
NotificationEntry::SlotUpdate(slot_update) => {
|
|
|
|
if let Some(sub) = subscriptions
|
|
|
|
.node_progress_watchers()
|
|
|
|
.get(&SubscriptionParams::SlotsUpdates)
|
|
|
|
{
|
|
|
|
inc_new_counter_info!("rpc-subscription-notify-slots-updates", 1);
|
|
|
|
notifier.notify(&slot_update, sub, false);
|
|
|
|
}
|
2020-11-16 22:37:38 -08:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
// These notifications are only triggered by votes observed on gossip,
|
|
|
|
// unlike `NotificationEntry::Gossip`, which also accounts for slots seen
|
|
|
|
// in VoteState's from bank states built in ReplayStage.
|
2022-01-26 22:03:03 -08:00
|
|
|
NotificationEntry::Vote((vote_pubkey, ref vote_info)) => {
|
2021-09-17 12:40:14 -07:00
|
|
|
let rpc_vote = RpcVote {
|
2022-01-26 22:03:03 -08:00
|
|
|
vote_pubkey: vote_pubkey.to_string(),
|
2021-12-07 16:47:26 -08:00
|
|
|
slots: vote_info.slots(),
|
|
|
|
hash: bs58::encode(vote_info.hash()).into_string(),
|
|
|
|
timestamp: vote_info.timestamp(),
|
2021-09-17 12:40:14 -07:00
|
|
|
};
|
|
|
|
if let Some(sub) = subscriptions
|
|
|
|
.node_progress_watchers()
|
|
|
|
.get(&SubscriptionParams::Vote)
|
|
|
|
{
|
|
|
|
debug!("vote notify: {:?}", vote_info);
|
|
|
|
inc_new_counter_info!("rpc-subscription-notify-vote", 1);
|
|
|
|
notifier.notify(&rpc_vote, sub, false);
|
|
|
|
}
|
2020-05-17 14:01:08 -07:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
NotificationEntry::Root(root) => {
|
|
|
|
if let Some(sub) = subscriptions
|
|
|
|
.node_progress_watchers()
|
|
|
|
.get(&SubscriptionParams::Root)
|
|
|
|
{
|
|
|
|
debug!("root notify: {:?}", root);
|
|
|
|
inc_new_counter_info!("rpc-subscription-notify-root", 1);
|
|
|
|
notifier.notify(&root, sub, false);
|
|
|
|
}
|
2020-11-16 22:37:38 -08:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
NotificationEntry::Bank(commitment_slots) => {
|
2021-12-17 15:03:09 -08:00
|
|
|
const SOURCE: &str = "bank";
|
|
|
|
RpcSubscriptions::notify_watchers(
|
|
|
|
max_complete_transaction_status_slot.clone(),
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions.commitment_watchers(),
|
|
|
|
&bank_forks,
|
2021-12-17 15:03:09 -08:00
|
|
|
&blockstore,
|
2021-09-17 12:40:14 -07:00
|
|
|
&commitment_slots,
|
2021-10-31 23:17:24 -07:00
|
|
|
¬ifier,
|
2021-12-17 15:03:09 -08:00
|
|
|
SOURCE,
|
|
|
|
);
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
NotificationEntry::Gossip(slot) => {
|
|
|
|
let commitment_slots = CommitmentSlots {
|
|
|
|
highest_confirmed_slot: slot,
|
|
|
|
..CommitmentSlots::default()
|
|
|
|
};
|
2021-12-17 15:03:09 -08:00
|
|
|
const SOURCE: &str = "gossip";
|
|
|
|
RpcSubscriptions::notify_watchers(
|
|
|
|
max_complete_transaction_status_slot.clone(),
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions.gossip_watchers(),
|
|
|
|
&bank_forks,
|
2021-12-17 15:03:09 -08:00
|
|
|
&blockstore,
|
2021-09-17 12:40:14 -07:00
|
|
|
&commitment_slots,
|
2021-10-31 23:17:24 -07:00
|
|
|
¬ifier,
|
2021-12-17 15:03:09 -08:00
|
|
|
SOURCE,
|
|
|
|
);
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
NotificationEntry::SignaturesReceived((slot, slot_signatures)) => {
|
|
|
|
for slot_signature in &slot_signatures {
|
|
|
|
if let Some(subs) = subscriptions.by_signature().get(slot_signature)
|
|
|
|
{
|
|
|
|
for subscription in subs.values() {
|
|
|
|
if let SubscriptionParams::Signature(params) =
|
|
|
|
subscription.params()
|
|
|
|
{
|
|
|
|
if params.enable_received_notification {
|
|
|
|
notifier.notify(
|
2022-05-11 21:17:21 -07:00
|
|
|
RpcResponse::from(RpcNotificationResponse {
|
|
|
|
context: RpcNotificationContext { slot },
|
2021-09-17 12:40:14 -07:00
|
|
|
value: RpcSignatureResult::ReceivedSignature(
|
|
|
|
ReceivedSignatureResult::ReceivedSignature,
|
|
|
|
),
|
2022-05-11 21:17:21 -07:00
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
subscription,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error!("invalid params type in visit_by_signature");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-27 09:33:40 -07:00
|
|
|
}
|
|
|
|
}
|
2021-11-05 19:59:54 -07:00
|
|
|
stats.notification_entry_processing_time_us +=
|
|
|
|
queued_at.elapsed().as_micros() as u64;
|
|
|
|
stats.notification_entry_processing_count += 1;
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
2020-01-20 13:08:29 -08:00
|
|
|
Err(RecvTimeoutError::Timeout) => {
|
|
|
|
// not a problem - try reading again
|
|
|
|
}
|
|
|
|
Err(RecvTimeoutError::Disconnected) => {
|
|
|
|
warn!("RPC Notification thread - sender disconnected");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-11-05 19:59:54 -07:00
|
|
|
stats.maybe_submit();
|
2020-01-20 13:08:29 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-17 15:03:09 -08:00
|
|
|
fn notify_watchers(
|
|
|
|
max_complete_transaction_status_slot: Arc<AtomicU64>,
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions: &HashMap<SubscriptionId, Arc<SubscriptionInfo>>,
|
2020-05-22 12:55:17 -07:00
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
2021-12-17 15:03:09 -08:00
|
|
|
blockstore: &Blockstore,
|
2020-07-17 10:54:49 -07:00
|
|
|
commitment_slots: &CommitmentSlots,
|
2021-10-31 23:17:24 -07:00
|
|
|
notifier: &RpcNotifier,
|
2020-09-23 18:46:42 -07:00
|
|
|
source: &'static str,
|
2020-05-22 12:55:17 -07:00
|
|
|
) {
|
2021-12-17 15:03:09 -08:00
|
|
|
let mut total_time = Measure::start("notify_watchers");
|
|
|
|
|
2021-10-31 23:17:24 -07:00
|
|
|
let num_accounts_found = AtomicUsize::new(0);
|
|
|
|
let num_accounts_notified = AtomicUsize::new(0);
|
2020-05-22 12:55:17 -07:00
|
|
|
|
2021-12-17 15:03:09 -08:00
|
|
|
let num_blocks_found = AtomicUsize::new(0);
|
|
|
|
let num_blocks_notified = AtomicUsize::new(0);
|
|
|
|
|
2021-10-31 23:17:24 -07:00
|
|
|
let num_logs_found = AtomicUsize::new(0);
|
|
|
|
let num_logs_notified = AtomicUsize::new(0);
|
2020-11-20 13:52:58 -08:00
|
|
|
|
2021-10-31 23:17:24 -07:00
|
|
|
let num_programs_found = AtomicUsize::new(0);
|
|
|
|
let num_programs_notified = AtomicUsize::new(0);
|
2020-05-22 12:55:17 -07:00
|
|
|
|
2021-12-17 15:03:09 -08:00
|
|
|
let num_signatures_found = AtomicUsize::new(0);
|
|
|
|
let num_signatures_notified = AtomicUsize::new(0);
|
|
|
|
|
2021-10-31 23:17:24 -07:00
|
|
|
let subscriptions = subscriptions.into_par_iter();
|
|
|
|
subscriptions.for_each(|(_id, subscription)| {
|
2021-12-17 15:03:09 -08:00
|
|
|
let slot = if let Some(commitment) = subscription.commitment() {
|
|
|
|
if commitment.is_finalized() {
|
|
|
|
Some(commitment_slots.highest_confirmed_root)
|
|
|
|
} else if commitment.is_confirmed() {
|
|
|
|
Some(commitment_slots.highest_confirmed_slot)
|
|
|
|
} else {
|
|
|
|
Some(commitment_slots.slot)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error!("missing commitment in notify_watchers");
|
|
|
|
None
|
|
|
|
};
|
2021-09-17 12:40:14 -07:00
|
|
|
match subscription.params() {
|
|
|
|
SubscriptionParams::Account(params) => {
|
2021-10-31 23:17:24 -07:00
|
|
|
num_accounts_found.fetch_add(1, Ordering::Relaxed);
|
2021-12-17 15:03:09 -08:00
|
|
|
if let Some(slot) = slot {
|
|
|
|
let notified = check_commitment_and_notify(
|
|
|
|
params,
|
|
|
|
subscription,
|
|
|
|
bank_forks,
|
|
|
|
slot,
|
|
|
|
|bank, params| bank.get_account_modified_slot(¶ms.pubkey),
|
|
|
|
filter_account_result,
|
|
|
|
notifier,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
|
|
|
|
if notified {
|
|
|
|
num_accounts_notified.fetch_add(1, Ordering::Relaxed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SubscriptionParams::Block(params) => {
|
|
|
|
num_blocks_found.fetch_add(1, Ordering::Relaxed);
|
|
|
|
if let Some(slot) = slot {
|
2022-04-29 01:32:46 -07:00
|
|
|
let bank = bank_forks.read().unwrap().get(slot);
|
|
|
|
if let Some(bank) = bank {
|
2021-12-17 15:03:09 -08:00
|
|
|
// We're calling it unnotified in this context
|
|
|
|
// because, logically, it gets set to `last_notified_slot + 1`
|
|
|
|
// on the final iteration of the loop down below.
|
|
|
|
// This is used to notify blocks for slots that were
|
|
|
|
// potentially missed due to upstream transient errors
|
|
|
|
// that led to this notification not being triggered for
|
|
|
|
// a slot.
|
|
|
|
//
|
|
|
|
// e.g.
|
|
|
|
// notify_watchers is triggered for Slot 1
|
|
|
|
// some time passes
|
|
|
|
// notify_watchers is triggered for Slot 4
|
|
|
|
// this will try to fetch blocks for slots 2, 3, and 4
|
|
|
|
// as long as they are ancestors of `slot`
|
|
|
|
let mut w_last_unnotified_slot =
|
|
|
|
subscription.last_notified_slot.write().unwrap();
|
|
|
|
// would mean it's the first notification for this subscription connection
|
|
|
|
if *w_last_unnotified_slot == 0 {
|
|
|
|
*w_last_unnotified_slot = slot;
|
|
|
|
}
|
|
|
|
let mut slots_to_notify: Vec<_> =
|
|
|
|
(*w_last_unnotified_slot..slot).collect();
|
|
|
|
let ancestors = bank.proper_ancestors_set();
|
|
|
|
slots_to_notify = slots_to_notify
|
|
|
|
.into_iter()
|
|
|
|
.filter(|slot| ancestors.contains(slot))
|
|
|
|
.collect();
|
|
|
|
slots_to_notify.push(slot);
|
|
|
|
for s in slots_to_notify {
|
|
|
|
// To avoid skipping a slot that fails this condition,
|
|
|
|
// caused by non-deterministic concurrency accesses, we
|
|
|
|
// break out of the loop. Besides if the current `s` is
|
|
|
|
// greater, then any `s + K` is also greater.
|
|
|
|
if s > max_complete_transaction_status_slot.load(Ordering::SeqCst) {
|
|
|
|
break;
|
|
|
|
}
|
2022-01-13 23:24:41 -08:00
|
|
|
|
2022-02-09 21:28:18 -08:00
|
|
|
let block_update_result = blockstore
|
2022-01-13 23:24:41 -08:00
|
|
|
.get_complete_block(s, false)
|
|
|
|
.map_err(|e| {
|
|
|
|
error!("get_complete_block error: {}", e);
|
|
|
|
RpcBlockUpdateError::BlockStoreError
|
|
|
|
})
|
2022-03-07 23:20:34 -08:00
|
|
|
.and_then(|block| filter_block_result_txs(block, s, params));
|
2022-01-13 23:24:41 -08:00
|
|
|
|
2022-02-09 21:28:18 -08:00
|
|
|
match block_update_result {
|
|
|
|
Ok(block_update) => {
|
2022-03-07 23:20:34 -08:00
|
|
|
if let Some(block_update) = block_update {
|
2021-12-17 15:03:09 -08:00
|
|
|
notifier.notify(
|
2022-05-11 21:17:21 -07:00
|
|
|
RpcResponse::from(RpcNotificationResponse {
|
|
|
|
context: RpcNotificationContext { slot: s },
|
2022-02-09 21:28:18 -08:00
|
|
|
value: block_update,
|
2022-05-11 21:17:21 -07:00
|
|
|
}),
|
2021-12-17 15:03:09 -08:00
|
|
|
subscription,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
num_blocks_notified.fetch_add(1, Ordering::Relaxed);
|
|
|
|
// the next time this subscription is notified it will
|
|
|
|
// try to fetch all slots between (s + 1) to `slot`, inclusively
|
|
|
|
*w_last_unnotified_slot = s + 1;
|
|
|
|
}
|
|
|
|
}
|
2022-01-13 23:24:41 -08:00
|
|
|
Err(err) => {
|
2021-12-17 15:03:09 -08:00
|
|
|
// we don't advance `w_last_unnotified_slot` so that
|
|
|
|
// it'll retry on the next notification trigger
|
|
|
|
notifier.notify(
|
2022-05-11 21:17:21 -07:00
|
|
|
RpcResponse::from(RpcNotificationResponse {
|
|
|
|
context: RpcNotificationContext { slot: s },
|
2021-12-17 15:03:09 -08:00
|
|
|
value: RpcBlockUpdate {
|
|
|
|
slot,
|
|
|
|
block: None,
|
2022-01-13 23:24:41 -08:00
|
|
|
err: Some(err),
|
2021-12-17 15:03:09 -08:00
|
|
|
},
|
2022-05-11 21:17:21 -07:00
|
|
|
}),
|
2021-12-17 15:03:09 -08:00
|
|
|
subscription,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
SubscriptionParams::Logs(params) => {
|
2021-10-31 23:17:24 -07:00
|
|
|
num_logs_found.fetch_add(1, Ordering::Relaxed);
|
2021-12-17 15:03:09 -08:00
|
|
|
if let Some(slot) = slot {
|
|
|
|
let notified = check_commitment_and_notify(
|
|
|
|
params,
|
|
|
|
subscription,
|
|
|
|
bank_forks,
|
|
|
|
slot,
|
|
|
|
get_transaction_logs,
|
|
|
|
filter_logs_results,
|
|
|
|
notifier,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
|
|
|
|
if notified {
|
|
|
|
num_logs_notified.fetch_add(1, Ordering::Relaxed);
|
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
SubscriptionParams::Program(params) => {
|
2021-10-31 23:17:24 -07:00
|
|
|
num_programs_found.fetch_add(1, Ordering::Relaxed);
|
2021-12-17 15:03:09 -08:00
|
|
|
if let Some(slot) = slot {
|
|
|
|
let notified = check_commitment_and_notify(
|
|
|
|
params,
|
|
|
|
subscription,
|
|
|
|
bank_forks,
|
|
|
|
slot,
|
|
|
|
|bank, params| {
|
|
|
|
bank.get_program_accounts_modified_since_parent(¶ms.pubkey)
|
|
|
|
},
|
|
|
|
filter_program_results,
|
|
|
|
notifier,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
|
|
|
|
if notified {
|
|
|
|
num_programs_notified.fetch_add(1, Ordering::Relaxed);
|
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
SubscriptionParams::Signature(params) => {
|
2021-10-31 23:17:24 -07:00
|
|
|
num_signatures_found.fetch_add(1, Ordering::Relaxed);
|
2021-12-17 15:03:09 -08:00
|
|
|
if let Some(slot) = slot {
|
|
|
|
let notified = check_commitment_and_notify(
|
|
|
|
params,
|
|
|
|
subscription,
|
|
|
|
bank_forks,
|
|
|
|
slot,
|
|
|
|
|bank, params| {
|
|
|
|
bank.get_signature_status_processed_since_parent(¶ms.signature)
|
|
|
|
},
|
|
|
|
filter_signature_result,
|
|
|
|
notifier,
|
|
|
|
true, // Unsubscribe.
|
|
|
|
);
|
|
|
|
|
|
|
|
if notified {
|
|
|
|
num_signatures_notified.fetch_add(1, Ordering::Relaxed);
|
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => error!("wrong subscription type in alps map"),
|
|
|
|
}
|
2021-10-31 23:17:24 -07:00
|
|
|
});
|
2021-09-17 12:40:14 -07:00
|
|
|
|
|
|
|
total_time.stop();
|
|
|
|
|
2021-10-31 23:17:24 -07:00
|
|
|
let total_notified = num_accounts_notified.load(Ordering::Relaxed)
|
|
|
|
+ num_logs_notified.load(Ordering::Relaxed)
|
|
|
|
+ num_programs_notified.load(Ordering::Relaxed)
|
|
|
|
+ num_signatures_notified.load(Ordering::Relaxed);
|
2021-09-17 12:40:14 -07:00
|
|
|
let total_ms = total_time.as_ms();
|
2020-09-23 18:46:42 -07:00
|
|
|
if total_notified > 0 || total_ms > 10 {
|
|
|
|
debug!(
|
2021-09-17 12:40:14 -07:00
|
|
|
"notified({}): accounts: {} / {} logs: {} / {} programs: {} / {} signatures: {} / {}",
|
2020-09-23 18:46:42 -07:00
|
|
|
source,
|
2021-10-31 23:17:24 -07:00
|
|
|
num_accounts_found.load(Ordering::Relaxed),
|
|
|
|
num_accounts_notified.load(Ordering::Relaxed),
|
|
|
|
num_logs_found.load(Ordering::Relaxed),
|
|
|
|
num_logs_notified.load(Ordering::Relaxed),
|
|
|
|
num_programs_found.load(Ordering::Relaxed),
|
|
|
|
num_programs_notified.load(Ordering::Relaxed),
|
|
|
|
num_signatures_found.load(Ordering::Relaxed),
|
|
|
|
num_signatures_notified.load(Ordering::Relaxed),
|
2020-05-22 12:55:17 -07:00
|
|
|
);
|
2020-11-14 11:40:24 -08:00
|
|
|
inc_new_counter_info!("rpc-subscription-notify-bank-or-gossip", total_notified);
|
2020-11-13 11:31:23 -08:00
|
|
|
datapoint_info!(
|
|
|
|
"rpc_subscriptions",
|
2022-01-21 16:01:22 -08:00
|
|
|
("source", source, String),
|
2021-10-31 23:17:24 -07:00
|
|
|
(
|
|
|
|
"num_account_subscriptions",
|
|
|
|
num_accounts_found.load(Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"num_account_pubkeys_notified",
|
|
|
|
num_accounts_notified.load(Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"num_logs_subscriptions",
|
|
|
|
num_logs_found.load(Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"num_logs_notified",
|
|
|
|
num_logs_notified.load(Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"num_program_subscriptions",
|
|
|
|
num_programs_found.load(Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"num_programs_notified",
|
|
|
|
num_programs_notified.load(Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"num_signature_subscriptions",
|
|
|
|
num_signatures_found.load(Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"num_signatures_notified",
|
|
|
|
num_signatures_notified.load(Ordering::Relaxed),
|
|
|
|
i64
|
|
|
|
),
|
2021-09-17 12:40:14 -07:00
|
|
|
("notifications_time", total_time.as_us() as i64, i64),
|
|
|
|
);
|
|
|
|
inc_new_counter_info!(
|
|
|
|
"rpc-subscription-counter-num_accounts_notified",
|
2021-10-31 23:17:24 -07:00
|
|
|
num_accounts_notified.load(Ordering::Relaxed)
|
2021-09-17 12:40:14 -07:00
|
|
|
);
|
|
|
|
inc_new_counter_info!(
|
|
|
|
"rpc-subscription-counter-num_logs_notified",
|
2021-10-31 23:17:24 -07:00
|
|
|
num_logs_notified.load(Ordering::Relaxed)
|
2021-09-17 12:40:14 -07:00
|
|
|
);
|
|
|
|
inc_new_counter_info!(
|
|
|
|
"rpc-subscription-counter-num_programs_notified",
|
2021-10-31 23:17:24 -07:00
|
|
|
num_programs_notified.load(Ordering::Relaxed)
|
2021-09-17 12:40:14 -07:00
|
|
|
);
|
|
|
|
inc_new_counter_info!(
|
|
|
|
"rpc-subscription-counter-num_signatures_notified",
|
2021-10-31 23:17:24 -07:00
|
|
|
num_signatures_notified.load(Ordering::Relaxed)
|
2020-11-13 11:31:23 -08:00
|
|
|
);
|
2020-09-01 22:06:06 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
fn shutdown(&mut self) -> std::thread::Result<()> {
|
|
|
|
if self.t_cleanup.is_some() {
|
|
|
|
info!("RPC Notification thread - shutting down");
|
|
|
|
self.exit.store(true, Ordering::Relaxed);
|
|
|
|
let x = self.t_cleanup.take().unwrap().join();
|
|
|
|
info!("RPC Notification thread - shut down.");
|
|
|
|
x
|
|
|
|
} else {
|
|
|
|
warn!("RPC Notification thread - already shut down.");
|
|
|
|
Ok(())
|
2019-11-26 00:42:54 -08:00
|
|
|
}
|
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
fn total(&self) -> usize {
|
|
|
|
self.control.total()
|
|
|
|
}
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2020-01-20 13:08:29 -08:00
|
|
|
pub(crate) mod tests {
|
2021-05-18 23:54:28 -07:00
|
|
|
use {
|
|
|
|
super::*,
|
2021-09-17 12:40:14 -07:00
|
|
|
crate::{
|
|
|
|
optimistically_confirmed_bank_tracker::{
|
|
|
|
BankNotification, OptimisticallyConfirmedBank, OptimisticallyConfirmedBankTracker,
|
|
|
|
},
|
2022-03-07 23:20:34 -08:00
|
|
|
rpc::{create_test_transaction_entries, populate_blockstore_for_tests},
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc_pubsub::RpcSolPubSubInternal,
|
|
|
|
rpc_pubsub_service,
|
2021-05-18 23:54:28 -07:00
|
|
|
},
|
|
|
|
serial_test::serial,
|
2021-09-17 12:40:14 -07:00
|
|
|
solana_client::rpc_config::{
|
2022-02-18 21:32:29 -08:00
|
|
|
RpcAccountInfoConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter,
|
2022-04-26 10:31:11 -07:00
|
|
|
RpcProgramAccountsConfig, RpcSignatureSubscribeConfig, RpcTransactionLogsConfig,
|
|
|
|
RpcTransactionLogsFilter,
|
2021-09-17 12:40:14 -07:00
|
|
|
},
|
2021-05-18 23:54:28 -07:00
|
|
|
solana_runtime::{
|
|
|
|
commitment::BlockCommitment,
|
|
|
|
genesis_utils::{create_genesis_config, GenesisConfigInfo},
|
|
|
|
},
|
|
|
|
solana_sdk::{
|
2021-09-17 12:40:14 -07:00
|
|
|
commitment_config::CommitmentConfig,
|
2021-05-18 23:54:28 -07:00
|
|
|
message::Message,
|
|
|
|
signature::{Keypair, Signer},
|
2021-06-15 09:04:00 -07:00
|
|
|
stake, system_instruction, system_program, system_transaction,
|
2021-05-18 23:54:28 -07:00
|
|
|
transaction::Transaction,
|
2021-09-17 12:40:14 -07:00
|
|
|
},
|
2021-12-17 15:03:09 -08:00
|
|
|
solana_transaction_status::{TransactionDetails, UiTransactionEncoding},
|
|
|
|
std::{
|
|
|
|
collections::HashSet,
|
|
|
|
sync::atomic::{AtomicU64, Ordering::Relaxed},
|
|
|
|
},
|
2021-09-17 12:40:14 -07:00
|
|
|
};
|
2020-01-20 13:08:29 -08:00
|
|
|
|
2021-08-20 13:30:59 -07:00
|
|
|
fn make_account_result(lamports: u64, subscription: u64, data: &str) -> serde_json::Value {
|
|
|
|
json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "accountNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": 1 },
|
|
|
|
"value": {
|
|
|
|
"data": data,
|
|
|
|
"executable": false,
|
|
|
|
"lamports": lamports,
|
|
|
|
"owner": "11111111111111111111111111111111",
|
|
|
|
"rentEpoch": 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"subscription": subscription,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-02-17 08:38:36 -08:00
|
|
|
#[test]
|
2020-04-17 10:48:39 -07:00
|
|
|
#[serial]
|
2019-02-17 08:38:36 -08:00
|
|
|
fn test_check_account_subscribe() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2019-11-08 20:56:57 -08:00
|
|
|
} = create_genesis_config(100);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2019-03-02 10:25:16 -08:00
|
|
|
let blockhash = bank.last_blockhash();
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank0 = bank_forks.read().unwrap().get(0).unwrap();
|
2020-05-06 23:23:06 -07:00
|
|
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
|
|
bank_forks.write().unwrap().insert(bank1);
|
2019-05-06 07:31:50 -07:00
|
|
|
let alice = Keypair::new();
|
2019-02-17 08:38:36 -08:00
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2020-03-30 16:53:25 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks.clone(),
|
2020-07-08 17:50:13 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
|
|
|
1, 1,
|
2020-06-25 21:06:58 -07:00
|
|
|
))),
|
2020-09-28 19:43:05 -07:00
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
2021-09-17 12:40:14 -07:00
|
|
|
));
|
2019-02-17 08:38:36 -08:00
|
|
|
|
2021-08-20 13:30:59 -07:00
|
|
|
let tx0 = system_transaction::create_account(
|
2020-05-06 23:23:06 -07:00
|
|
|
&mint_keypair,
|
|
|
|
&alice,
|
|
|
|
blockhash,
|
|
|
|
1,
|
2020-11-10 03:48:42 -08:00
|
|
|
0,
|
|
|
|
&system_program::id(),
|
2020-05-06 23:23:06 -07:00
|
|
|
);
|
2021-08-20 13:30:59 -07:00
|
|
|
let expected0 = make_account_result(1, 0, "");
|
2020-11-10 03:48:42 -08:00
|
|
|
|
2021-08-20 13:30:59 -07:00
|
|
|
let tx1 = {
|
2020-11-10 03:48:42 -08:00
|
|
|
let instruction =
|
|
|
|
system_instruction::transfer(&alice.pubkey(), &mint_keypair.pubkey(), 1);
|
|
|
|
let message = Message::new(&[instruction], Some(&mint_keypair.pubkey()));
|
|
|
|
Transaction::new(&[&alice, &mint_keypair], message, blockhash)
|
|
|
|
};
|
2021-08-20 13:30:59 -07:00
|
|
|
let expected1 = make_account_result(0, 1, "");
|
2020-11-10 03:48:42 -08:00
|
|
|
|
2021-08-20 13:30:59 -07:00
|
|
|
let tx2 = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&alice,
|
|
|
|
blockhash,
|
|
|
|
1,
|
|
|
|
1024,
|
|
|
|
&system_program::id(),
|
|
|
|
);
|
|
|
|
let expected2 = make_account_result(1, 2, "error: data too large for bs58 encoding");
|
|
|
|
|
|
|
|
let subscribe_cases = vec![
|
|
|
|
(alice.pubkey(), tx0, expected0),
|
|
|
|
(alice.pubkey(), tx1, expected1),
|
|
|
|
(alice.pubkey(), tx2, expected2),
|
|
|
|
];
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
for (pubkey, tx, expected) in subscribe_cases {
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
|
|
|
|
let sub_id = rpc
|
|
|
|
.account_subscribe(
|
|
|
|
pubkey.to_string(),
|
|
|
|
Some(RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::processed()),
|
|
|
|
encoding: None,
|
|
|
|
data_slice: None,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2019-02-17 08:38:36 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Account(AccountSubscriptionParams {
|
|
|
|
pubkey,
|
|
|
|
commitment: CommitmentConfig::processed(),
|
|
|
|
data_slice: None,
|
|
|
|
encoding: UiAccountEncoding::Binary,
|
|
|
|
}));
|
2021-08-20 13:30:59 -07:00
|
|
|
|
|
|
|
bank_forks
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(1)
|
|
|
|
.unwrap()
|
2021-09-17 12:40:14 -07:00
|
|
|
.process_transaction(&tx)
|
2021-08-20 13:30:59 -07:00
|
|
|
.unwrap();
|
|
|
|
let commitment_slots = CommitmentSlots {
|
|
|
|
slot: 1,
|
|
|
|
..CommitmentSlots::default()
|
|
|
|
};
|
|
|
|
subscriptions.notify_subscribers(commitment_slots);
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2021-08-20 13:30:59 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
|
|
|
rpc.account_unsubscribe(sub_id).unwrap();
|
2021-08-20 13:30:59 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_unsubscribed(&SubscriptionParams::Account(AccountSubscriptionParams {
|
|
|
|
pubkey,
|
|
|
|
commitment: CommitmentConfig::processed(),
|
|
|
|
data_slice: None,
|
|
|
|
encoding: UiAccountEncoding::Binary,
|
|
|
|
}));
|
2021-08-20 13:30:59 -07:00
|
|
|
}
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
2019-03-06 14:31:58 -08:00
|
|
|
|
2021-12-17 15:03:09 -08:00
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_check_confirmed_block_subscribe() {
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2022-02-09 21:28:18 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_genesis_config(10_000);
|
2021-12-17 15:03:09 -08:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2022-02-09 21:28:18 -08:00
|
|
|
let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
|
2021-12-17 15:03:09 -08:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
|
|
|
let blockstore = Arc::new(blockstore);
|
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests_with_blockstore(
|
|
|
|
&exit,
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
blockstore.clone(),
|
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
|
|
|
optimistically_confirmed_bank,
|
|
|
|
));
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let filter = RpcBlockSubscribeFilter::All;
|
|
|
|
let config = RpcBlockSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::confirmed()),
|
|
|
|
encoding: Some(UiTransactionEncoding::Json),
|
|
|
|
transaction_details: Some(TransactionDetails::Signatures),
|
|
|
|
show_rewards: None,
|
2022-03-07 23:20:34 -08:00
|
|
|
max_supported_transaction_version: None,
|
2021-12-17 15:03:09 -08:00
|
|
|
};
|
|
|
|
let params = BlockSubscriptionParams {
|
|
|
|
kind: BlockSubscriptionKind::All,
|
|
|
|
commitment: config.commitment.unwrap(),
|
|
|
|
encoding: config.encoding.unwrap(),
|
|
|
|
transaction_details: config.transaction_details.unwrap(),
|
|
|
|
show_rewards: config.show_rewards.unwrap_or_default(),
|
2022-03-07 23:20:34 -08:00
|
|
|
max_supported_transaction_version: config.max_supported_transaction_version,
|
2021-12-17 15:03:09 -08:00
|
|
|
};
|
|
|
|
let sub_id = rpc.block_subscribe(filter, Some(config)).unwrap();
|
|
|
|
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Block(params.clone()));
|
|
|
|
|
|
|
|
let bank = bank_forks.read().unwrap().working_bank();
|
|
|
|
let keypair1 = Keypair::new();
|
|
|
|
let keypair2 = Keypair::new();
|
|
|
|
let keypair3 = Keypair::new();
|
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
|
2022-02-09 21:28:18 -08:00
|
|
|
bank.transfer(rent_exempt_amount, &mint_keypair, &keypair2.pubkey())
|
|
|
|
.unwrap();
|
2022-03-07 23:20:34 -08:00
|
|
|
populate_blockstore_for_tests(
|
|
|
|
create_test_transaction_entries(
|
|
|
|
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
|
|
|
|
bank.clone(),
|
|
|
|
)
|
|
|
|
.0,
|
2021-12-17 15:03:09 -08:00
|
|
|
bank,
|
|
|
|
blockstore.clone(),
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
);
|
|
|
|
|
|
|
|
let slot = 0;
|
|
|
|
subscriptions.notify_gossip_subscribers(slot);
|
|
|
|
let actual_resp = receiver.recv();
|
|
|
|
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
|
|
|
|
|
2022-02-09 21:28:18 -08:00
|
|
|
let confirmed_block =
|
|
|
|
ConfirmedBlock::from(blockstore.get_complete_block(slot, false).unwrap());
|
2022-03-07 23:20:34 -08:00
|
|
|
let block = confirmed_block
|
|
|
|
.encode_with_options(
|
|
|
|
params.encoding,
|
|
|
|
BlockEncodingOptions {
|
|
|
|
transaction_details: params.transaction_details,
|
|
|
|
show_rewards: false,
|
|
|
|
max_supported_transaction_version: None,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
2021-12-17 15:03:09 -08:00
|
|
|
let expected_resp = RpcBlockUpdate {
|
|
|
|
slot,
|
|
|
|
block: Some(block),
|
|
|
|
err: None,
|
|
|
|
};
|
|
|
|
let expected_resp = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "blockNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": slot },
|
|
|
|
"value": expected_resp,
|
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
assert_eq!(expected_resp, actual_resp);
|
|
|
|
|
|
|
|
// should not trigger since commitment NOT set to finalized
|
|
|
|
subscriptions.notify_subscribers(CommitmentSlots {
|
|
|
|
slot,
|
|
|
|
root: slot,
|
|
|
|
highest_confirmed_slot: slot,
|
|
|
|
highest_confirmed_root: slot,
|
|
|
|
});
|
|
|
|
let should_err = receiver.recv_timeout(Duration::from_millis(300));
|
|
|
|
assert!(should_err.is_err());
|
|
|
|
|
|
|
|
rpc.slot_unsubscribe(sub_id).unwrap();
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_unsubscribed(&SubscriptionParams::Block(params));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_check_confirmed_block_subscribe_with_mentions() {
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2022-02-09 21:28:18 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_genesis_config(10_000);
|
2021-12-17 15:03:09 -08:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2022-02-09 21:28:18 -08:00
|
|
|
let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
|
2021-12-17 15:03:09 -08:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
|
|
|
let blockstore = Arc::new(blockstore);
|
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests_with_blockstore(
|
|
|
|
&exit,
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
blockstore.clone(),
|
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
|
|
|
optimistically_confirmed_bank,
|
|
|
|
));
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let keypair1 = Keypair::new();
|
|
|
|
let filter =
|
|
|
|
RpcBlockSubscribeFilter::MentionsAccountOrProgram(keypair1.pubkey().to_string());
|
|
|
|
let config = RpcBlockSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::confirmed()),
|
|
|
|
encoding: Some(UiTransactionEncoding::Json),
|
|
|
|
transaction_details: Some(TransactionDetails::Signatures),
|
|
|
|
show_rewards: None,
|
2022-03-07 23:20:34 -08:00
|
|
|
max_supported_transaction_version: None,
|
2021-12-17 15:03:09 -08:00
|
|
|
};
|
|
|
|
let params = BlockSubscriptionParams {
|
|
|
|
kind: BlockSubscriptionKind::MentionsAccountOrProgram(keypair1.pubkey()),
|
|
|
|
commitment: config.commitment.unwrap(),
|
|
|
|
encoding: config.encoding.unwrap(),
|
|
|
|
transaction_details: config.transaction_details.unwrap(),
|
|
|
|
show_rewards: config.show_rewards.unwrap_or_default(),
|
2022-03-07 23:20:34 -08:00
|
|
|
max_supported_transaction_version: config.max_supported_transaction_version,
|
2021-12-17 15:03:09 -08:00
|
|
|
};
|
|
|
|
let sub_id = rpc.block_subscribe(filter, Some(config)).unwrap();
|
|
|
|
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Block(params.clone()));
|
|
|
|
|
|
|
|
let bank = bank_forks.read().unwrap().working_bank();
|
|
|
|
let keypair2 = Keypair::new();
|
|
|
|
let keypair3 = Keypair::new();
|
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
|
2022-02-09 21:28:18 -08:00
|
|
|
bank.transfer(rent_exempt_amount, &mint_keypair, &keypair2.pubkey())
|
|
|
|
.unwrap();
|
2022-03-07 23:20:34 -08:00
|
|
|
populate_blockstore_for_tests(
|
|
|
|
create_test_transaction_entries(
|
|
|
|
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
|
|
|
|
bank.clone(),
|
|
|
|
)
|
|
|
|
.0,
|
2021-12-17 15:03:09 -08:00
|
|
|
bank,
|
|
|
|
blockstore.clone(),
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
);
|
|
|
|
|
|
|
|
let slot = 0;
|
|
|
|
subscriptions.notify_gossip_subscribers(slot);
|
|
|
|
let actual_resp = receiver.recv();
|
|
|
|
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
|
|
|
|
|
|
|
|
// make sure it filtered out the other keypairs
|
2022-03-07 23:20:34 -08:00
|
|
|
let mut confirmed_block =
|
2022-02-09 21:28:18 -08:00
|
|
|
ConfirmedBlock::from(blockstore.get_complete_block(slot, false).unwrap());
|
2022-03-07 23:20:34 -08:00
|
|
|
confirmed_block.transactions.retain(|tx_with_meta| {
|
2022-01-13 23:24:41 -08:00
|
|
|
tx_with_meta
|
2022-03-07 23:20:34 -08:00
|
|
|
.account_keys()
|
|
|
|
.iter()
|
|
|
|
.any(|key| key == &keypair1.pubkey())
|
2021-12-17 15:03:09 -08:00
|
|
|
});
|
2022-03-07 23:20:34 -08:00
|
|
|
let block = confirmed_block
|
|
|
|
.encode_with_options(
|
|
|
|
params.encoding,
|
|
|
|
BlockEncodingOptions {
|
|
|
|
transaction_details: params.transaction_details,
|
|
|
|
show_rewards: false,
|
|
|
|
max_supported_transaction_version: None,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
2021-12-17 15:03:09 -08:00
|
|
|
let expected_resp = RpcBlockUpdate {
|
|
|
|
slot,
|
|
|
|
block: Some(block),
|
|
|
|
err: None,
|
|
|
|
};
|
|
|
|
let expected_resp = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "blockNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": slot },
|
|
|
|
"value": expected_resp,
|
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
assert_eq!(expected_resp, actual_resp);
|
|
|
|
|
|
|
|
rpc.slot_unsubscribe(sub_id).unwrap();
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_unsubscribed(&SubscriptionParams::Block(params));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_check_finalized_block_subscribe() {
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2022-02-09 21:28:18 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_genesis_config(10_000);
|
2021-12-17 15:03:09 -08:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2022-02-09 21:28:18 -08:00
|
|
|
let rent_exempt_amount = bank.get_minimum_balance_for_rent_exemption(0);
|
2021-12-17 15:03:09 -08:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
let blockstore = Blockstore::open(&ledger_path).unwrap();
|
|
|
|
let blockstore = Arc::new(blockstore);
|
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests_with_blockstore(
|
|
|
|
&exit,
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
blockstore.clone(),
|
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
|
|
|
optimistically_confirmed_bank,
|
|
|
|
));
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let filter = RpcBlockSubscribeFilter::All;
|
|
|
|
let config = RpcBlockSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::finalized()),
|
|
|
|
encoding: Some(UiTransactionEncoding::Json),
|
|
|
|
transaction_details: Some(TransactionDetails::Signatures),
|
|
|
|
show_rewards: None,
|
2022-03-07 23:20:34 -08:00
|
|
|
max_supported_transaction_version: None,
|
2021-12-17 15:03:09 -08:00
|
|
|
};
|
|
|
|
let params = BlockSubscriptionParams {
|
|
|
|
kind: BlockSubscriptionKind::All,
|
|
|
|
commitment: config.commitment.unwrap(),
|
|
|
|
encoding: config.encoding.unwrap(),
|
|
|
|
transaction_details: config.transaction_details.unwrap(),
|
|
|
|
show_rewards: config.show_rewards.unwrap_or_default(),
|
2022-03-07 23:20:34 -08:00
|
|
|
max_supported_transaction_version: config.max_supported_transaction_version,
|
2021-12-17 15:03:09 -08:00
|
|
|
};
|
|
|
|
let sub_id = rpc.block_subscribe(filter, Some(config)).unwrap();
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Block(params.clone()));
|
|
|
|
|
|
|
|
let bank = bank_forks.read().unwrap().working_bank();
|
|
|
|
let keypair1 = Keypair::new();
|
|
|
|
let keypair2 = Keypair::new();
|
|
|
|
let keypair3 = Keypair::new();
|
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::new(blockstore.max_root()));
|
2022-02-09 21:28:18 -08:00
|
|
|
bank.transfer(rent_exempt_amount, &mint_keypair, &keypair2.pubkey())
|
|
|
|
.unwrap();
|
2022-03-07 23:20:34 -08:00
|
|
|
populate_blockstore_for_tests(
|
|
|
|
create_test_transaction_entries(
|
|
|
|
vec![&mint_keypair, &keypair1, &keypair2, &keypair3],
|
|
|
|
bank.clone(),
|
|
|
|
)
|
|
|
|
.0,
|
2021-12-17 15:03:09 -08:00
|
|
|
bank,
|
|
|
|
blockstore.clone(),
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
);
|
|
|
|
|
|
|
|
let slot = 0;
|
|
|
|
subscriptions.notify_subscribers(CommitmentSlots {
|
|
|
|
slot,
|
|
|
|
root: slot,
|
|
|
|
highest_confirmed_slot: slot,
|
|
|
|
highest_confirmed_root: slot,
|
|
|
|
});
|
|
|
|
let actual_resp = receiver.recv();
|
|
|
|
let actual_resp = serde_json::from_str::<serde_json::Value>(&actual_resp).unwrap();
|
|
|
|
|
2022-02-09 21:28:18 -08:00
|
|
|
let confirmed_block =
|
|
|
|
ConfirmedBlock::from(blockstore.get_complete_block(slot, false).unwrap());
|
2022-03-07 23:20:34 -08:00
|
|
|
let block = confirmed_block
|
|
|
|
.encode_with_options(
|
|
|
|
params.encoding,
|
|
|
|
BlockEncodingOptions {
|
|
|
|
transaction_details: params.transaction_details,
|
|
|
|
show_rewards: false,
|
|
|
|
max_supported_transaction_version: None,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.unwrap();
|
2021-12-17 15:03:09 -08:00
|
|
|
let expected_resp = RpcBlockUpdate {
|
|
|
|
slot,
|
|
|
|
block: Some(block),
|
|
|
|
err: None,
|
|
|
|
};
|
|
|
|
let expected_resp = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "blockNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": slot },
|
|
|
|
"value": expected_resp,
|
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
assert_eq!(expected_resp, actual_resp);
|
|
|
|
|
|
|
|
// should not trigger since commitment set to finalized
|
|
|
|
subscriptions.notify_gossip_subscribers(slot);
|
|
|
|
let should_err = receiver.recv_timeout(Duration::from_millis(300));
|
|
|
|
assert!(should_err.is_err());
|
|
|
|
|
|
|
|
rpc.slot_unsubscribe(sub_id).unwrap();
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_unsubscribed(&SubscriptionParams::Block(params));
|
|
|
|
}
|
|
|
|
|
2019-03-06 14:31:58 -08:00
|
|
|
#[test]
|
2020-04-17 10:48:39 -07:00
|
|
|
#[serial]
|
2019-03-06 14:31:58 -08:00
|
|
|
fn test_check_program_subscribe() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2019-11-08 20:56:57 -08:00
|
|
|
} = create_genesis_config(100);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2019-03-06 14:31:58 -08:00
|
|
|
let blockhash = bank.last_blockhash();
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2019-05-06 07:31:50 -07:00
|
|
|
let alice = Keypair::new();
|
2019-04-03 08:45:57 -07:00
|
|
|
let tx = system_transaction::create_account(
|
2019-03-06 14:31:58 -08:00
|
|
|
&mint_keypair,
|
2019-11-08 02:27:35 -08:00
|
|
|
&alice,
|
2019-03-06 14:31:58 -08:00
|
|
|
blockhash,
|
|
|
|
1,
|
|
|
|
16,
|
2021-06-15 09:04:00 -07:00
|
|
|
&stake::program::id(),
|
2019-03-06 14:31:58 -08:00
|
|
|
);
|
2019-05-06 07:31:50 -07:00
|
|
|
bank_forks
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.get(0)
|
|
|
|
.unwrap()
|
|
|
|
.process_transaction(&tx)
|
|
|
|
.unwrap();
|
2019-03-06 14:31:58 -08:00
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2020-09-28 19:43:05 -07:00
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2020-03-30 16:53:25 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks,
|
2020-06-25 21:06:58 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank,
|
2021-09-17 12:40:14 -07:00
|
|
|
));
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id = rpc
|
|
|
|
.program_subscribe(
|
|
|
|
stake::program::id().to_string(),
|
|
|
|
Some(RpcProgramAccountsConfig {
|
|
|
|
account_config: RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::processed()),
|
|
|
|
..RpcAccountInfoConfig::default()
|
|
|
|
},
|
|
|
|
..RpcProgramAccountsConfig::default()
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2019-03-06 14:31:58 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Program(ProgramSubscriptionParams {
|
|
|
|
pubkey: stake::program::id(),
|
|
|
|
filters: Vec::new(),
|
|
|
|
commitment: CommitmentConfig::processed(),
|
|
|
|
data_slice: None,
|
|
|
|
encoding: UiAccountEncoding::Binary,
|
|
|
|
with_context: false,
|
|
|
|
}));
|
2019-03-06 14:31:58 -08:00
|
|
|
|
2020-07-17 10:54:49 -07:00
|
|
|
subscriptions.notify_subscribers(CommitmentSlots::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2020-03-23 05:34:42 -07:00
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "programNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": 0 },
|
|
|
|
"value": {
|
|
|
|
"account": {
|
|
|
|
"data": "1111111111111111",
|
|
|
|
"executable": false,
|
|
|
|
"lamports": 1,
|
2020-08-07 15:01:51 -07:00
|
|
|
"owner": "Stake11111111111111111111111111111111111111",
|
2020-08-16 22:22:16 -07:00
|
|
|
"rentEpoch": 0,
|
2020-03-23 05:34:42 -07:00
|
|
|
},
|
|
|
|
"pubkey": alice.pubkey().to_string(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
2019-03-06 14:31:58 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc.program_unsubscribe(sub_id).unwrap();
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_unsubscribed(&SubscriptionParams::Program(ProgramSubscriptionParams {
|
|
|
|
pubkey: stake::program::id(),
|
|
|
|
filters: Vec::new(),
|
|
|
|
commitment: CommitmentConfig::processed(),
|
|
|
|
data_slice: None,
|
|
|
|
encoding: UiAccountEncoding::Binary,
|
|
|
|
with_context: false,
|
|
|
|
}));
|
2019-03-06 14:31:58 -08:00
|
|
|
}
|
2020-02-11 17:09:40 -08:00
|
|
|
|
2021-08-10 16:44:45 -07:00
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_check_program_subscribe_for_missing_optimistically_confirmed_slot() {
|
|
|
|
// Testing if we can get the pubsub notification if a slot does not
|
|
|
|
// receive OptimisticallyConfirmed but its descendant slot get the confirmed
|
|
|
|
// notification.
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_genesis_config(100);
|
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
|
|
|
bank.lazy_rent_collection.store(true, Relaxed);
|
|
|
|
|
|
|
|
let blockhash = bank.last_blockhash();
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank0 = bank_forks.read().unwrap().get(0).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
|
|
bank_forks.write().unwrap().insert(bank1);
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank1 = bank_forks.read().unwrap().get(1).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
// add account for alice and process the transaction at bank1
|
|
|
|
let alice = Keypair::new();
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&alice,
|
|
|
|
blockhash,
|
|
|
|
1,
|
|
|
|
16,
|
|
|
|
&stake::program::id(),
|
|
|
|
);
|
|
|
|
|
|
|
|
bank1.process_transaction(&tx).unwrap();
|
|
|
|
|
|
|
|
let bank2 = Bank::new_from_parent(&bank1, &Pubkey::default(), 2);
|
|
|
|
bank_forks.write().unwrap().insert(bank2);
|
|
|
|
|
|
|
|
// add account for bob and process the transaction at bank2
|
|
|
|
let bob = Keypair::new();
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&bob,
|
|
|
|
blockhash,
|
|
|
|
2,
|
|
|
|
16,
|
|
|
|
&stake::program::id(),
|
|
|
|
);
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank2 = bank_forks.read().unwrap().get(2).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
bank2.process_transaction(&tx).unwrap();
|
|
|
|
|
|
|
|
let bank3 = Bank::new_from_parent(&bank2, &Pubkey::default(), 3);
|
|
|
|
bank_forks.write().unwrap().insert(bank3);
|
|
|
|
|
|
|
|
// add account for joe and process the transaction at bank3
|
|
|
|
let joe = Keypair::new();
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&joe,
|
|
|
|
blockhash,
|
|
|
|
3,
|
|
|
|
16,
|
|
|
|
&stake::program::id(),
|
|
|
|
);
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank3 = bank_forks.read().unwrap().get(3).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
bank3.process_transaction(&tx).unwrap();
|
|
|
|
|
|
|
|
// now add programSubscribe at the "confirmed" commitment level
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
|
|
|
let mut pending_optimistically_confirmed_banks = HashSet::new();
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2021-08-10 16:44:45 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2021-08-10 16:44:45 -07:00
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
|
|
|
1, 1,
|
|
|
|
))),
|
|
|
|
optimistically_confirmed_bank.clone(),
|
|
|
|
));
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
|
|
|
|
let sub_id = rpc
|
|
|
|
.program_subscribe(
|
|
|
|
stake::program::id().to_string(),
|
|
|
|
Some(RpcProgramAccountsConfig {
|
|
|
|
account_config: RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::confirmed()),
|
|
|
|
..RpcAccountInfoConfig::default()
|
|
|
|
},
|
|
|
|
..RpcProgramAccountsConfig::default()
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Program(ProgramSubscriptionParams {
|
|
|
|
pubkey: stake::program::id(),
|
|
|
|
filters: Vec::new(),
|
|
|
|
encoding: UiAccountEncoding::Binary,
|
|
|
|
data_slice: None,
|
|
|
|
commitment: CommitmentConfig::confirmed(),
|
|
|
|
with_context: false,
|
|
|
|
}));
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
let mut highest_confirmed_slot: Slot = 0;
|
|
|
|
let mut last_notified_confirmed_slot: Slot = 0;
|
|
|
|
// Optimistically notifying slot 3 without notifying slot 1 and 2, bank3 is unfrozen, we expect
|
|
|
|
// to see transaction for alice and bob to be notified in order.
|
|
|
|
OptimisticallyConfirmedBankTracker::process_notification(
|
|
|
|
BankNotification::OptimisticallyConfirmed(3),
|
|
|
|
&bank_forks,
|
|
|
|
&optimistically_confirmed_bank,
|
|
|
|
&subscriptions,
|
|
|
|
&mut pending_optimistically_confirmed_banks,
|
|
|
|
&mut last_notified_confirmed_slot,
|
|
|
|
&mut highest_confirmed_slot,
|
2021-09-01 14:10:16 -07:00
|
|
|
&None,
|
2021-08-10 16:44:45 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
// a closure to reduce code duplications in building expected responses:
|
|
|
|
let build_expected_resp = |slot: Slot, lamports: u64, pubkey: &str, subscription: i32| {
|
|
|
|
json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "programNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": slot },
|
|
|
|
"value": {
|
|
|
|
"account": {
|
|
|
|
"data": "1111111111111111",
|
|
|
|
"executable": false,
|
|
|
|
"lamports": lamports,
|
|
|
|
"owner": "Stake11111111111111111111111111111111111111",
|
|
|
|
"rentEpoch": 0,
|
|
|
|
},
|
|
|
|
"pubkey": pubkey,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"subscription": subscription,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
};
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2021-08-10 16:44:45 -07:00
|
|
|
let expected = build_expected_resp(1, 1, &alice.pubkey().to_string(), 0);
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
2021-08-10 16:44:45 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2021-08-10 16:44:45 -07:00
|
|
|
let expected = build_expected_resp(2, 2, &bob.pubkey().to_string(), 0);
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
bank3.freeze();
|
|
|
|
OptimisticallyConfirmedBankTracker::process_notification(
|
|
|
|
BankNotification::Frozen(bank3),
|
|
|
|
&bank_forks,
|
|
|
|
&optimistically_confirmed_bank,
|
|
|
|
&subscriptions,
|
|
|
|
&mut pending_optimistically_confirmed_banks,
|
|
|
|
&mut last_notified_confirmed_slot,
|
|
|
|
&mut highest_confirmed_slot,
|
2021-09-01 14:10:16 -07:00
|
|
|
&None,
|
2021-08-10 16:44:45 -07:00
|
|
|
);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2021-08-10 16:44:45 -07:00
|
|
|
let expected = build_expected_resp(3, 3, &joe.pubkey().to_string(), 0);
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
|
|
|
rpc.program_unsubscribe(sub_id).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
#[should_panic]
|
|
|
|
fn test_check_program_subscribe_for_missing_optimistically_confirmed_slot_with_no_banks_no_notifications(
|
|
|
|
) {
|
|
|
|
// Testing if we can get the pubsub notification if a slot does not
|
|
|
|
// receive OptimisticallyConfirmed but its descendant slot get the confirmed
|
|
|
|
// notification with a bank in the BankForks. We are not expecting to receive any notifications -- should panic.
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_genesis_config(100);
|
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
|
|
|
bank.lazy_rent_collection.store(true, Relaxed);
|
|
|
|
|
|
|
|
let blockhash = bank.last_blockhash();
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank0 = bank_forks.read().unwrap().get(0).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
|
|
bank_forks.write().unwrap().insert(bank1);
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank1 = bank_forks.read().unwrap().get(1).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
// add account for alice and process the transaction at bank1
|
|
|
|
let alice = Keypair::new();
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&alice,
|
|
|
|
blockhash,
|
|
|
|
1,
|
|
|
|
16,
|
|
|
|
&stake::program::id(),
|
|
|
|
);
|
|
|
|
|
|
|
|
bank1.process_transaction(&tx).unwrap();
|
|
|
|
|
|
|
|
let bank2 = Bank::new_from_parent(&bank1, &Pubkey::default(), 2);
|
|
|
|
bank_forks.write().unwrap().insert(bank2);
|
|
|
|
|
|
|
|
// add account for bob and process the transaction at bank2
|
|
|
|
let bob = Keypair::new();
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&bob,
|
|
|
|
blockhash,
|
|
|
|
2,
|
|
|
|
16,
|
|
|
|
&stake::program::id(),
|
|
|
|
);
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank2 = bank_forks.read().unwrap().get(2).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
bank2.process_transaction(&tx).unwrap();
|
|
|
|
|
|
|
|
// now add programSubscribe at the "confirmed" commitment level
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
|
|
|
let mut pending_optimistically_confirmed_banks = HashSet::new();
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2021-08-10 16:44:45 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2021-08-10 16:44:45 -07:00
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
|
|
|
1, 1,
|
|
|
|
))),
|
|
|
|
optimistically_confirmed_bank.clone(),
|
|
|
|
));
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
rpc.program_subscribe(
|
|
|
|
stake::program::id().to_string(),
|
2021-08-10 16:44:45 -07:00
|
|
|
Some(RpcProgramAccountsConfig {
|
|
|
|
account_config: RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::confirmed()),
|
|
|
|
..RpcAccountInfoConfig::default()
|
|
|
|
},
|
|
|
|
..RpcProgramAccountsConfig::default()
|
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Program(ProgramSubscriptionParams {
|
|
|
|
pubkey: stake::program::id(),
|
|
|
|
filters: Vec::new(),
|
|
|
|
encoding: UiAccountEncoding::Binary,
|
|
|
|
data_slice: None,
|
|
|
|
commitment: CommitmentConfig::confirmed(),
|
|
|
|
with_context: false,
|
|
|
|
}));
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
let mut highest_confirmed_slot: Slot = 0;
|
|
|
|
let mut last_notified_confirmed_slot: Slot = 0;
|
|
|
|
// Optimistically notifying slot 3 without notifying slot 1 and 2, bank3 is not in the bankforks, we do not
|
|
|
|
// expect to see any RPC notifications.
|
|
|
|
OptimisticallyConfirmedBankTracker::process_notification(
|
|
|
|
BankNotification::OptimisticallyConfirmed(3),
|
|
|
|
&bank_forks,
|
|
|
|
&optimistically_confirmed_bank,
|
|
|
|
&subscriptions,
|
|
|
|
&mut pending_optimistically_confirmed_banks,
|
|
|
|
&mut last_notified_confirmed_slot,
|
|
|
|
&mut highest_confirmed_slot,
|
2021-09-01 14:10:16 -07:00
|
|
|
&None,
|
2021-08-10 16:44:45 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
// The following should panic
|
2021-09-17 12:40:14 -07:00
|
|
|
let _response = receiver.recv();
|
2021-08-10 16:44:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_check_program_subscribe_for_missing_optimistically_confirmed_slot_with_no_banks() {
|
|
|
|
// Testing if we can get the pubsub notification if a slot does not
|
|
|
|
// receive OptimisticallyConfirmed but its descendant slot get the confirmed
|
|
|
|
// notification. It differs from the test_check_program_subscribe_for_missing_optimistically_confirmed_slot
|
|
|
|
// test in that when the descendant get confirmed, the descendant does not have a bank yet.
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_genesis_config(100);
|
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
|
|
|
bank.lazy_rent_collection.store(true, Relaxed);
|
|
|
|
|
|
|
|
let blockhash = bank.last_blockhash();
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank0 = bank_forks.read().unwrap().get(0).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
|
|
bank_forks.write().unwrap().insert(bank1);
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank1 = bank_forks.read().unwrap().get(1).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
// add account for alice and process the transaction at bank1
|
|
|
|
let alice = Keypair::new();
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&alice,
|
|
|
|
blockhash,
|
|
|
|
1,
|
|
|
|
16,
|
|
|
|
&stake::program::id(),
|
|
|
|
);
|
|
|
|
|
|
|
|
bank1.process_transaction(&tx).unwrap();
|
|
|
|
|
|
|
|
let bank2 = Bank::new_from_parent(&bank1, &Pubkey::default(), 2);
|
|
|
|
bank_forks.write().unwrap().insert(bank2);
|
|
|
|
|
|
|
|
// add account for bob and process the transaction at bank2
|
|
|
|
let bob = Keypair::new();
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&bob,
|
|
|
|
blockhash,
|
|
|
|
2,
|
|
|
|
16,
|
|
|
|
&stake::program::id(),
|
|
|
|
);
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank2 = bank_forks.read().unwrap().get(2).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
bank2.process_transaction(&tx).unwrap();
|
|
|
|
|
|
|
|
// now add programSubscribe at the "confirmed" commitment level
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
|
|
|
let mut pending_optimistically_confirmed_banks = HashSet::new();
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2021-08-10 16:44:45 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2021-08-10 16:44:45 -07:00
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
|
|
|
1, 1,
|
|
|
|
))),
|
|
|
|
optimistically_confirmed_bank.clone(),
|
|
|
|
));
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id = rpc
|
|
|
|
.program_subscribe(
|
|
|
|
stake::program::id().to_string(),
|
|
|
|
Some(RpcProgramAccountsConfig {
|
|
|
|
account_config: RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::confirmed()),
|
|
|
|
..RpcAccountInfoConfig::default()
|
|
|
|
},
|
|
|
|
..RpcProgramAccountsConfig::default()
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Program(ProgramSubscriptionParams {
|
|
|
|
pubkey: stake::program::id(),
|
|
|
|
filters: Vec::new(),
|
|
|
|
encoding: UiAccountEncoding::Binary,
|
|
|
|
data_slice: None,
|
|
|
|
commitment: CommitmentConfig::confirmed(),
|
|
|
|
with_context: false,
|
|
|
|
}));
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
let mut highest_confirmed_slot: Slot = 0;
|
|
|
|
let mut last_notified_confirmed_slot: Slot = 0;
|
|
|
|
// Optimistically notifying slot 3 without notifying slot 1 and 2, bank3 is not in the bankforks, we expect
|
|
|
|
// to see transaction for alice and bob to be notified only when bank3 is added to the fork and
|
|
|
|
// frozen. The notifications should be in the increasing order of the slot.
|
|
|
|
OptimisticallyConfirmedBankTracker::process_notification(
|
|
|
|
BankNotification::OptimisticallyConfirmed(3),
|
|
|
|
&bank_forks,
|
|
|
|
&optimistically_confirmed_bank,
|
|
|
|
&subscriptions,
|
|
|
|
&mut pending_optimistically_confirmed_banks,
|
|
|
|
&mut last_notified_confirmed_slot,
|
|
|
|
&mut highest_confirmed_slot,
|
2021-09-01 14:10:16 -07:00
|
|
|
&None,
|
2021-08-10 16:44:45 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
// a closure to reduce code duplications in building expected responses:
|
|
|
|
let build_expected_resp = |slot: Slot, lamports: u64, pubkey: &str, subscription: i32| {
|
|
|
|
json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "programNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": slot },
|
|
|
|
"value": {
|
|
|
|
"account": {
|
|
|
|
"data": "1111111111111111",
|
|
|
|
"executable": false,
|
|
|
|
"lamports": lamports,
|
|
|
|
"owner": "Stake11111111111111111111111111111111111111",
|
|
|
|
"rentEpoch": 0,
|
|
|
|
},
|
|
|
|
"pubkey": pubkey,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"subscription": subscription,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
};
|
|
|
|
|
|
|
|
let bank3 = Bank::new_from_parent(&bank2, &Pubkey::default(), 3);
|
|
|
|
bank_forks.write().unwrap().insert(bank3);
|
|
|
|
|
|
|
|
// add account for joe and process the transaction at bank3
|
|
|
|
let joe = Keypair::new();
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&joe,
|
|
|
|
blockhash,
|
|
|
|
3,
|
|
|
|
16,
|
|
|
|
&stake::program::id(),
|
|
|
|
);
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank3 = bank_forks.read().unwrap().get(3).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
|
|
|
|
bank3.process_transaction(&tx).unwrap();
|
|
|
|
bank3.freeze();
|
|
|
|
OptimisticallyConfirmedBankTracker::process_notification(
|
|
|
|
BankNotification::Frozen(bank3),
|
|
|
|
&bank_forks,
|
|
|
|
&optimistically_confirmed_bank,
|
|
|
|
&subscriptions,
|
|
|
|
&mut pending_optimistically_confirmed_banks,
|
|
|
|
&mut last_notified_confirmed_slot,
|
|
|
|
&mut highest_confirmed_slot,
|
2021-09-01 14:10:16 -07:00
|
|
|
&None,
|
2021-08-10 16:44:45 -07:00
|
|
|
);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2021-08-10 16:44:45 -07:00
|
|
|
let expected = build_expected_resp(1, 1, &alice.pubkey().to_string(), 0);
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
2021-08-10 16:44:45 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2021-08-10 16:44:45 -07:00
|
|
|
let expected = build_expected_resp(2, 2, &bob.pubkey().to_string(), 0);
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
2021-08-10 16:44:45 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2021-08-10 16:44:45 -07:00
|
|
|
let expected = build_expected_resp(3, 3, &joe.pubkey().to_string(), 0);
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
|
|
|
rpc.program_unsubscribe(sub_id).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
}
|
|
|
|
|
2019-02-17 08:38:36 -08:00
|
|
|
#[test]
|
2020-04-17 10:48:39 -07:00
|
|
|
#[serial]
|
2019-02-17 08:38:36 -08:00
|
|
|
fn test_check_signature_subscribe() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair,
|
|
|
|
..
|
2019-11-08 20:56:57 -08:00
|
|
|
} = create_genesis_config(100);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2019-03-02 10:25:16 -08:00
|
|
|
let blockhash = bank.last_blockhash();
|
2020-06-12 10:04:17 -07:00
|
|
|
let mut bank_forks = BankForks::new(bank);
|
2019-05-06 07:31:50 -07:00
|
|
|
let alice = Keypair::new();
|
2020-03-23 17:00:34 -07:00
|
|
|
|
|
|
|
let past_bank_tx =
|
|
|
|
system_transaction::transfer(&mint_keypair, &alice.pubkey(), 1, blockhash);
|
2020-02-13 09:00:50 -08:00
|
|
|
let unprocessed_tx =
|
2020-03-23 17:00:34 -07:00
|
|
|
system_transaction::transfer(&mint_keypair, &alice.pubkey(), 2, blockhash);
|
|
|
|
let processed_tx =
|
|
|
|
system_transaction::transfer(&mint_keypair, &alice.pubkey(), 3, blockhash);
|
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
bank_forks
|
|
|
|
.get(0)
|
|
|
|
.unwrap()
|
2020-03-23 17:00:34 -07:00
|
|
|
.process_transaction(&past_bank_tx)
|
|
|
|
.unwrap();
|
|
|
|
|
2020-10-19 12:23:14 -07:00
|
|
|
let next_bank = Bank::new_from_parent(
|
2022-04-28 11:51:00 -07:00
|
|
|
&bank_forks.get(0).unwrap(),
|
2020-10-19 12:23:14 -07:00
|
|
|
&solana_sdk::pubkey::new_rand(),
|
|
|
|
1,
|
|
|
|
);
|
2020-03-23 17:00:34 -07:00
|
|
|
bank_forks.insert(next_bank);
|
|
|
|
|
|
|
|
bank_forks
|
|
|
|
.get(1)
|
|
|
|
.unwrap()
|
|
|
|
.process_transaction(&processed_tx)
|
2019-05-06 07:31:50 -07:00
|
|
|
.unwrap();
|
2020-03-30 16:53:25 -07:00
|
|
|
let bank1 = bank_forks[1].clone();
|
2019-02-17 08:38:36 -08:00
|
|
|
|
2020-03-23 17:00:34 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(bank_forks));
|
|
|
|
|
2020-03-30 16:53:25 -07:00
|
|
|
let mut cache0 = BlockCommitment::default();
|
|
|
|
cache0.increase_confirmation_stake(1, 10);
|
|
|
|
let cache1 = BlockCommitment::default();
|
|
|
|
|
|
|
|
let mut block_commitment = HashMap::new();
|
2020-05-15 09:35:43 -07:00
|
|
|
block_commitment.entry(0).or_insert(cache0);
|
|
|
|
block_commitment.entry(1).or_insert(cache1);
|
2020-07-17 08:24:51 -07:00
|
|
|
let block_commitment_cache = BlockCommitmentCache::new(
|
|
|
|
block_commitment,
|
|
|
|
10,
|
2020-07-17 10:54:49 -07:00
|
|
|
CommitmentSlots {
|
2020-07-17 08:24:51 -07:00
|
|
|
slot: bank1.slot(),
|
2020-08-12 20:51:15 -07:00
|
|
|
..CommitmentSlots::default()
|
2020-07-17 08:24:51 -07:00
|
|
|
},
|
|
|
|
);
|
2020-03-30 16:53:25 -07:00
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2020-09-28 19:43:05 -07:00
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2020-05-06 23:23:06 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks,
|
|
|
|
Arc::new(RwLock::new(block_commitment_cache)),
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank,
|
2021-09-17 12:40:14 -07:00
|
|
|
));
|
|
|
|
|
|
|
|
let (past_bank_rpc1, mut past_bank_receiver1) =
|
|
|
|
rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let (past_bank_rpc2, mut past_bank_receiver2) =
|
|
|
|
rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let (processed_rpc, mut processed_receiver) =
|
|
|
|
rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let (another_rpc, _another_receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let (processed_rpc3, mut processed_receiver3) =
|
|
|
|
rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
|
|
|
|
let past_bank_sub_id1 = past_bank_rpc1
|
|
|
|
.signature_subscribe(
|
|
|
|
past_bank_tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::processed()),
|
|
|
|
enable_received_notification: Some(false),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let past_bank_sub_id2 = past_bank_rpc2
|
|
|
|
.signature_subscribe(
|
|
|
|
past_bank_tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::finalized()),
|
|
|
|
enable_received_notification: Some(false),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let processed_sub_id = processed_rpc
|
|
|
|
.signature_subscribe(
|
|
|
|
processed_tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::processed()),
|
|
|
|
enable_received_notification: Some(false),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
another_rpc
|
|
|
|
.signature_subscribe(
|
|
|
|
unprocessed_tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::processed()),
|
|
|
|
enable_received_notification: Some(false),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-03-24 09:53:32 -07:00
|
|
|
|
2020-09-01 22:06:06 -07:00
|
|
|
// Add a subscription that gets `received` notifications
|
2021-09-17 12:40:14 -07:00
|
|
|
let processed_sub_id3 = processed_rpc3
|
|
|
|
.signature_subscribe(
|
|
|
|
unprocessed_tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::processed()),
|
|
|
|
enable_received_notification: Some(true),
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
assert!(subscriptions
|
|
|
|
.control
|
|
|
|
.signature_subscribed(&unprocessed_tx.signatures[0]));
|
|
|
|
assert!(subscriptions
|
|
|
|
.control
|
|
|
|
.signature_subscribed(&processed_tx.signatures[0]));
|
2019-02-17 08:38:36 -08:00
|
|
|
|
2020-07-17 10:54:49 -07:00
|
|
|
let mut commitment_slots = CommitmentSlots::default();
|
2020-09-01 22:06:06 -07:00
|
|
|
let received_slot = 1;
|
|
|
|
commitment_slots.slot = received_slot;
|
|
|
|
subscriptions
|
|
|
|
.notify_signatures_received((received_slot, vec![unprocessed_tx.signatures[0]]));
|
2020-07-17 10:54:49 -07:00
|
|
|
subscriptions.notify_subscribers(commitment_slots);
|
2020-09-01 22:06:06 -07:00
|
|
|
let expected_res =
|
2020-09-03 17:14:45 -07:00
|
|
|
RpcSignatureResult::ProcessedSignature(ProcessedSignatureResult { err: None });
|
|
|
|
let received_expected_res =
|
|
|
|
RpcSignatureResult::ReceivedSignature(ReceivedSignatureResult::ReceivedSignature);
|
2020-03-30 16:53:25 -07:00
|
|
|
struct Notification {
|
|
|
|
slot: Slot,
|
|
|
|
id: u64,
|
|
|
|
}
|
2020-03-24 09:53:32 -07:00
|
|
|
|
2020-09-01 22:06:06 -07:00
|
|
|
let expected_notification =
|
|
|
|
|exp: Notification, expected_res: &RpcSignatureResult| -> String {
|
|
|
|
let json = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "signatureNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": exp.slot },
|
|
|
|
"value": expected_res,
|
|
|
|
},
|
|
|
|
"subscription": exp.id,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
serde_json::to_string(&json).unwrap()
|
|
|
|
};
|
2019-02-17 08:38:36 -08:00
|
|
|
|
2020-03-30 16:53:25 -07:00
|
|
|
// Expect to receive a notification from bank 1 because this subscription is
|
|
|
|
// looking for 0 confirmations and so checks the current bank
|
2021-09-17 12:40:14 -07:00
|
|
|
let expected = expected_notification(
|
|
|
|
Notification {
|
|
|
|
slot: 1,
|
|
|
|
id: past_bank_sub_id1.into(),
|
|
|
|
},
|
|
|
|
&expected_res,
|
|
|
|
);
|
|
|
|
let response = past_bank_receiver1.recv();
|
2020-03-30 16:53:25 -07:00
|
|
|
assert_eq!(expected, response);
|
|
|
|
|
|
|
|
// Expect to receive a notification from bank 0 because this subscription is
|
|
|
|
// looking for 1 confirmation and so checks the past bank
|
2021-09-17 12:40:14 -07:00
|
|
|
let expected = expected_notification(
|
|
|
|
Notification {
|
|
|
|
slot: 0,
|
|
|
|
id: past_bank_sub_id2.into(),
|
|
|
|
},
|
|
|
|
&expected_res,
|
|
|
|
);
|
|
|
|
let response = past_bank_receiver2.recv();
|
2020-03-30 16:53:25 -07:00
|
|
|
assert_eq!(expected, response);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let expected = expected_notification(
|
|
|
|
Notification {
|
|
|
|
slot: 1,
|
|
|
|
id: processed_sub_id.into(),
|
|
|
|
},
|
|
|
|
&expected_res,
|
|
|
|
);
|
|
|
|
let response = processed_receiver.recv();
|
2020-03-30 16:53:25 -07:00
|
|
|
assert_eq!(expected, response);
|
2020-03-23 17:00:34 -07:00
|
|
|
|
2020-09-01 22:06:06 -07:00
|
|
|
// Expect a "received" notification
|
|
|
|
let expected = expected_notification(
|
|
|
|
Notification {
|
|
|
|
slot: received_slot,
|
2021-09-17 12:40:14 -07:00
|
|
|
id: processed_sub_id3.into(),
|
2020-09-01 22:06:06 -07:00
|
|
|
},
|
|
|
|
&received_expected_res,
|
|
|
|
);
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = processed_receiver3.recv();
|
2020-09-01 22:06:06 -07:00
|
|
|
assert_eq!(expected, response);
|
|
|
|
|
2020-02-13 09:00:50 -08:00
|
|
|
// Subscription should be automatically removed after notification
|
2021-09-17 12:40:14 -07:00
|
|
|
|
|
|
|
assert!(!subscriptions
|
|
|
|
.control
|
|
|
|
.signature_subscribed(&processed_tx.signatures[0]));
|
|
|
|
assert!(!subscriptions
|
|
|
|
.control
|
|
|
|
.signature_subscribed(&past_bank_tx.signatures[0]));
|
2020-02-13 09:00:50 -08:00
|
|
|
|
|
|
|
// Unprocessed signature subscription should not be removed
|
2021-09-17 12:40:14 -07:00
|
|
|
assert!(subscriptions
|
|
|
|
.control
|
|
|
|
.signature_subscribed(&unprocessed_tx.signatures[0]));
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
2020-02-11 17:09:40 -08:00
|
|
|
|
2019-11-26 00:42:54 -08:00
|
|
|
#[test]
|
2020-04-17 10:48:39 -07:00
|
|
|
#[serial]
|
2019-11-26 00:42:54 -08:00
|
|
|
fn test_check_slot_subscribe() {
|
2020-01-20 13:08:29 -08:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2020-05-06 23:23:06 -07:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2020-09-28 19:43:05 -07:00
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2020-03-30 16:53:25 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks,
|
2020-06-25 21:06:58 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank,
|
2021-09-17 12:40:14 -07:00
|
|
|
));
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id = rpc.slot_subscribe().unwrap();
|
2019-11-26 00:42:54 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Slot);
|
2019-11-26 00:42:54 -08:00
|
|
|
|
|
|
|
subscriptions.notify_slot(0, 0, 0);
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
let expected_res = SlotInfo {
|
|
|
|
parent: 0,
|
|
|
|
slot: 0,
|
|
|
|
root: 0,
|
|
|
|
};
|
2021-09-17 12:40:14 -07:00
|
|
|
let expected_res_str = serde_json::to_string(&expected_res).unwrap();
|
|
|
|
|
2020-01-20 13:08:29 -08:00
|
|
|
let expected = format!(
|
|
|
|
r#"{{"jsonrpc":"2.0","method":"slotNotification","params":{{"result":{},"subscription":0}}}}"#,
|
|
|
|
expected_res_str
|
|
|
|
);
|
|
|
|
assert_eq!(expected, response);
|
2019-11-26 00:42:54 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc.slot_unsubscribe(sub_id).unwrap();
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_unsubscribed(&SubscriptionParams::Slot);
|
2019-11-26 00:42:54 -08:00
|
|
|
}
|
2020-02-11 17:09:40 -08:00
|
|
|
|
2020-03-27 09:33:40 -07:00
|
|
|
#[test]
|
2020-04-17 10:48:39 -07:00
|
|
|
#[serial]
|
2020-03-27 09:33:40 -07:00
|
|
|
fn test_check_root_subscribe() {
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2020-05-06 23:23:06 -07:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2020-09-28 19:43:05 -07:00
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2020-03-30 16:53:25 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks,
|
2020-06-25 21:06:58 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank,
|
2021-09-17 12:40:14 -07:00
|
|
|
));
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id = rpc.root_subscribe().unwrap();
|
2020-03-27 09:33:40 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_subscribed(&SubscriptionParams::Root);
|
2020-03-27 09:33:40 -07:00
|
|
|
|
|
|
|
subscriptions.notify_roots(vec![2, 1, 3]);
|
|
|
|
|
|
|
|
for expected_root in 1..=3 {
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
|
|
|
|
2020-03-27 09:33:40 -07:00
|
|
|
let expected_res_str =
|
|
|
|
serde_json::to_string(&serde_json::to_value(expected_root).unwrap()).unwrap();
|
|
|
|
let expected = format!(
|
|
|
|
r#"{{"jsonrpc":"2.0","method":"rootNotification","params":{{"result":{},"subscription":0}}}}"#,
|
|
|
|
expected_res_str
|
|
|
|
);
|
|
|
|
assert_eq!(expected, response);
|
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc.root_unsubscribe(sub_id).unwrap();
|
|
|
|
subscriptions
|
|
|
|
.control
|
|
|
|
.assert_unsubscribed(&SubscriptionParams::Root);
|
2020-02-11 17:09:40 -08:00
|
|
|
}
|
2020-05-22 12:55:17 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_gossip_separate_account_notifications() {
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_genesis_config(100);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-05-22 12:55:17 -07:00
|
|
|
let blockhash = bank.last_blockhash();
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank0 = bank_forks.read().unwrap().get(0).unwrap();
|
2020-05-22 12:55:17 -07:00
|
|
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
|
|
bank_forks.write().unwrap().insert(bank1);
|
2020-06-17 09:44:51 -07:00
|
|
|
let bank2 = Bank::new_from_parent(&bank0, &Pubkey::default(), 2);
|
|
|
|
bank_forks.write().unwrap().insert(bank2);
|
2020-05-22 12:55:17 -07:00
|
|
|
let alice = Keypair::new();
|
|
|
|
|
2020-09-28 19:43:05 -07:00
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
|
|
|
let mut pending_optimistically_confirmed_banks = HashSet::new();
|
|
|
|
|
2020-05-22 12:55:17 -07:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2020-05-22 12:55:17 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-05-22 12:55:17 -07:00
|
|
|
bank_forks.clone(),
|
2020-07-08 17:50:13 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
|
|
|
1, 1,
|
2020-06-25 21:06:58 -07:00
|
|
|
))),
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank.clone(),
|
|
|
|
));
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc0, mut receiver0) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let (rpc1, mut receiver1) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id0 = rpc0
|
|
|
|
.account_subscribe(
|
|
|
|
alice.pubkey().to_string(),
|
|
|
|
Some(RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::confirmed()),
|
|
|
|
encoding: None,
|
|
|
|
data_slice: None,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-05-22 12:55:17 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
assert!(subscriptions.control.account_subscribed(&alice.pubkey()));
|
2020-05-22 12:55:17 -07:00
|
|
|
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&alice,
|
|
|
|
blockhash,
|
|
|
|
1,
|
|
|
|
16,
|
2021-06-15 09:04:00 -07:00
|
|
|
&stake::program::id(),
|
2020-05-22 12:55:17 -07:00
|
|
|
);
|
2020-06-17 09:44:51 -07:00
|
|
|
|
|
|
|
// Add the transaction to the 1st bank and then freeze the bank
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank1 = bank_forks.write().unwrap().get(1).unwrap();
|
2020-06-17 09:44:51 -07:00
|
|
|
bank1.process_transaction(&tx).unwrap();
|
|
|
|
bank1.freeze();
|
|
|
|
|
|
|
|
// Add the same transaction to the unfrozen 2nd bank
|
2020-05-22 12:55:17 -07:00
|
|
|
bank_forks
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
2020-06-17 09:44:51 -07:00
|
|
|
.get(2)
|
2020-05-22 12:55:17 -07:00
|
|
|
.unwrap()
|
|
|
|
.process_transaction(&tx)
|
|
|
|
.unwrap();
|
2020-06-17 09:44:51 -07:00
|
|
|
|
|
|
|
// First, notify the unfrozen bank first to queue pending notification
|
2021-08-10 16:44:45 -07:00
|
|
|
let mut highest_confirmed_slot: Slot = 0;
|
|
|
|
let mut last_notified_confirmed_slot: Slot = 0;
|
2020-09-28 19:43:05 -07:00
|
|
|
OptimisticallyConfirmedBankTracker::process_notification(
|
|
|
|
BankNotification::OptimisticallyConfirmed(2),
|
|
|
|
&bank_forks,
|
|
|
|
&optimistically_confirmed_bank,
|
|
|
|
&subscriptions,
|
|
|
|
&mut pending_optimistically_confirmed_banks,
|
2021-08-10 16:44:45 -07:00
|
|
|
&mut last_notified_confirmed_slot,
|
|
|
|
&mut highest_confirmed_slot,
|
2021-09-01 14:10:16 -07:00
|
|
|
&None,
|
2020-09-28 19:43:05 -07:00
|
|
|
);
|
2020-06-17 09:44:51 -07:00
|
|
|
|
|
|
|
// Now, notify the frozen bank and ensure its notifications are processed
|
2021-08-10 16:44:45 -07:00
|
|
|
highest_confirmed_slot = 0;
|
2020-09-28 19:43:05 -07:00
|
|
|
OptimisticallyConfirmedBankTracker::process_notification(
|
|
|
|
BankNotification::OptimisticallyConfirmed(1),
|
|
|
|
&bank_forks,
|
|
|
|
&optimistically_confirmed_bank,
|
|
|
|
&subscriptions,
|
|
|
|
&mut pending_optimistically_confirmed_banks,
|
2021-08-10 16:44:45 -07:00
|
|
|
&mut last_notified_confirmed_slot,
|
|
|
|
&mut highest_confirmed_slot,
|
2021-09-01 14:10:16 -07:00
|
|
|
&None,
|
2020-09-28 19:43:05 -07:00
|
|
|
);
|
2020-06-17 09:44:51 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver0.recv();
|
2020-05-22 12:55:17 -07:00
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "accountNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": 1 },
|
|
|
|
"value": {
|
|
|
|
"data": "1111111111111111",
|
|
|
|
"executable": false,
|
|
|
|
"lamports": 1,
|
2020-08-07 15:01:51 -07:00
|
|
|
"owner": "Stake11111111111111111111111111111111111111",
|
2020-08-16 22:22:16 -07:00
|
|
|
"rentEpoch": 0,
|
2020-05-22 12:55:17 -07:00
|
|
|
},
|
|
|
|
},
|
2020-06-17 09:44:51 -07:00
|
|
|
"subscription": 0,
|
2020-05-22 12:55:17 -07:00
|
|
|
}
|
|
|
|
});
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
2020-06-17 09:44:51 -07:00
|
|
|
);
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc0.account_unsubscribe(sub_id0).unwrap();
|
|
|
|
|
|
|
|
let sub_id1 = rpc1
|
|
|
|
.account_subscribe(
|
|
|
|
alice.pubkey().to_string(),
|
|
|
|
Some(RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::confirmed()),
|
|
|
|
encoding: None,
|
|
|
|
data_slice: None,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-06-17 09:44:51 -07:00
|
|
|
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank2 = bank_forks.read().unwrap().get(2).unwrap();
|
2021-08-10 16:44:45 -07:00
|
|
|
bank2.freeze();
|
|
|
|
highest_confirmed_slot = 0;
|
2020-09-28 19:43:05 -07:00
|
|
|
OptimisticallyConfirmedBankTracker::process_notification(
|
|
|
|
BankNotification::Frozen(bank2),
|
|
|
|
&bank_forks,
|
|
|
|
&optimistically_confirmed_bank,
|
|
|
|
&subscriptions,
|
|
|
|
&mut pending_optimistically_confirmed_banks,
|
2021-08-10 16:44:45 -07:00
|
|
|
&mut last_notified_confirmed_slot,
|
|
|
|
&mut highest_confirmed_slot,
|
2021-09-01 14:10:16 -07:00
|
|
|
&None,
|
2020-09-28 19:43:05 -07:00
|
|
|
);
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver1.recv();
|
2020-05-22 12:55:17 -07:00
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "accountNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
2020-06-17 09:44:51 -07:00
|
|
|
"context": { "slot": 2 },
|
2020-05-22 12:55:17 -07:00
|
|
|
"value": {
|
|
|
|
"data": "1111111111111111",
|
|
|
|
"executable": false,
|
|
|
|
"lamports": 1,
|
2020-08-07 15:01:51 -07:00
|
|
|
"owner": "Stake11111111111111111111111111111111111111",
|
2020-08-16 22:22:16 -07:00
|
|
|
"rentEpoch": 0,
|
2020-05-22 12:55:17 -07:00
|
|
|
},
|
|
|
|
},
|
2020-06-17 09:44:51 -07:00
|
|
|
"subscription": 1,
|
2020-05-22 12:55:17 -07:00
|
|
|
}
|
|
|
|
});
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
|
|
|
rpc1.account_unsubscribe(sub_id1).unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
assert!(!subscriptions.control.account_subscribed(&alice.pubkey()));
|
2020-12-11 17:57:40 -08:00
|
|
|
}
|
|
|
|
|
2022-04-26 10:31:11 -07:00
|
|
|
fn make_logs_result(signature: &str, subscription_id: u64) -> serde_json::Value {
|
|
|
|
json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "logsNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": {
|
|
|
|
"slot": 0
|
|
|
|
},
|
|
|
|
"value": {
|
|
|
|
"signature": signature,
|
|
|
|
"err": null,
|
|
|
|
"logs": [
|
|
|
|
"Program 11111111111111111111111111111111 invoke [1]",
|
|
|
|
"Program 11111111111111111111111111111111 success"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"subscription": subscription_id
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_logs_subscribe() {
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair,
|
|
|
|
..
|
|
|
|
} = create_genesis_config(100);
|
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
|
|
|
let blockhash = bank.last_blockhash();
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
|
|
|
|
let alice = Keypair::new();
|
|
|
|
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
|
|
|
&exit,
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
|
|
|
optimistically_confirmed_bank,
|
|
|
|
));
|
|
|
|
|
|
|
|
let sub_config = RpcTransactionLogsConfig {
|
|
|
|
commitment: Some(CommitmentConfig::processed()),
|
|
|
|
};
|
|
|
|
|
|
|
|
let (rpc_all, mut receiver_all) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id_for_all = rpc_all
|
|
|
|
.logs_subscribe(RpcTransactionLogsFilter::All, Some(sub_config.clone()))
|
|
|
|
.unwrap();
|
|
|
|
assert!(subscriptions.control.logs_subscribed(None));
|
|
|
|
|
|
|
|
let (rpc_alice, mut receiver_alice) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id_for_alice = rpc_alice
|
|
|
|
.logs_subscribe(
|
|
|
|
RpcTransactionLogsFilter::Mentions(vec![alice.pubkey().to_string()]),
|
|
|
|
Some(sub_config),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
assert!(subscriptions.control.logs_subscribed(Some(&alice.pubkey())));
|
|
|
|
|
|
|
|
let tx = system_transaction::create_account(
|
|
|
|
&mint_keypair,
|
|
|
|
&alice,
|
|
|
|
blockhash,
|
|
|
|
1,
|
|
|
|
0,
|
|
|
|
&system_program::id(),
|
|
|
|
);
|
|
|
|
|
|
|
|
bank_forks
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(0)
|
|
|
|
.unwrap()
|
|
|
|
.process_transaction_with_logs(&tx)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
subscriptions.notify_subscribers(CommitmentSlots::new_from_slot(0));
|
|
|
|
|
|
|
|
let expected_response_all =
|
|
|
|
make_logs_result(&tx.signatures[0].to_string(), u64::from(sub_id_for_all));
|
|
|
|
let response_all = receiver_all.recv();
|
|
|
|
assert_eq!(
|
|
|
|
expected_response_all,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response_all).unwrap(),
|
|
|
|
);
|
|
|
|
let expected_response_alice =
|
|
|
|
make_logs_result(&tx.signatures[0].to_string(), u64::from(sub_id_for_alice));
|
|
|
|
let response_alice = receiver_alice.recv();
|
|
|
|
assert_eq!(
|
|
|
|
expected_response_alice,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response_alice).unwrap(),
|
|
|
|
);
|
|
|
|
|
|
|
|
rpc_all.logs_unsubscribe(sub_id_for_all).unwrap();
|
|
|
|
assert!(!subscriptions.control.logs_subscribed(None));
|
|
|
|
rpc_alice.logs_unsubscribe(sub_id_for_alice).unwrap();
|
|
|
|
assert!(!subscriptions.control.logs_subscribed(Some(&alice.pubkey())));
|
|
|
|
}
|
|
|
|
|
2020-12-11 17:57:40 -08:00
|
|
|
#[test]
|
|
|
|
fn test_total_subscriptions() {
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(100);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2020-12-11 17:57:40 -08:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2021-12-17 15:03:09 -08:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::default_with_bank_forks(
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
bank_forks,
|
|
|
|
));
|
2021-09-17 12:40:14 -07:00
|
|
|
|
|
|
|
let (rpc1, _receiver1) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id1 = rpc1
|
|
|
|
.account_subscribe(Pubkey::default().to_string(), None)
|
|
|
|
.unwrap();
|
|
|
|
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 1);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc2, _receiver2) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id2 = rpc2
|
|
|
|
.program_subscribe(Pubkey::default().to_string(), None)
|
|
|
|
.unwrap();
|
|
|
|
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 2);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc3, _receiver3) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id3 = rpc3
|
|
|
|
.logs_subscribe(RpcTransactionLogsFilter::All, None)
|
|
|
|
.unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 3);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc4, _receiver4) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id4 = rpc4
|
|
|
|
.signature_subscribe(Signature::default().to_string(), None)
|
|
|
|
.unwrap();
|
|
|
|
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 4);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc5, _receiver5) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id5 = rpc5.slot_subscribe().unwrap();
|
|
|
|
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 5);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc6, _receiver6) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id6 = rpc6.vote_subscribe().unwrap();
|
|
|
|
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 6);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc7, _receiver7) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id7 = rpc7.root_subscribe().unwrap();
|
|
|
|
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 7);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
// Add duplicate account subscription, but it shouldn't increment the count.
|
|
|
|
let (rpc8, _receiver8) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
let sub_id8 = rpc8
|
|
|
|
.account_subscribe(Pubkey::default().to_string(), None)
|
|
|
|
.unwrap();
|
|
|
|
assert_eq!(subscriptions.total(), 7);
|
2020-12-11 17:57:40 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc1.account_unsubscribe(sub_id1).unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 7);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc8.account_unsubscribe(sub_id8).unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 6);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc2.program_unsubscribe(sub_id2).unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 5);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc3.logs_unsubscribe(sub_id3).unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 4);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc4.signature_unsubscribe(sub_id4).unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 3);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc5.slot_unsubscribe(sub_id5).unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 2);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc6.vote_unsubscribe(sub_id6).unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 1);
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc7.root_unsubscribe(sub_id7).unwrap();
|
2020-12-11 17:57:40 -08:00
|
|
|
assert_eq!(subscriptions.total(), 0);
|
|
|
|
}
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|