2018-10-10 13:51:43 -07:00
|
|
|
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
|
|
|
|
2020-09-03 17:14:45 -07:00
|
|
|
use crate::rpc_subscriptions::{RpcSubscriptions, RpcVote};
|
2019-02-04 16:41:03 -08:00
|
|
|
use jsonrpc_core::{Error, ErrorCode, Result};
|
|
|
|
use jsonrpc_derive::rpc;
|
2020-01-15 10:52:02 -08:00
|
|
|
use jsonrpc_pubsub::{typed::Subscriber, Session, SubscriptionId};
|
2020-06-30 21:55:11 -07:00
|
|
|
use solana_account_decoder::UiAccount;
|
2020-07-23 12:38:28 -07:00
|
|
|
use solana_client::{
|
2020-11-20 13:52:58 -08:00
|
|
|
rpc_config::{
|
|
|
|
RpcAccountInfoConfig, RpcProgramAccountsConfig, RpcSignatureSubscribeConfig,
|
|
|
|
RpcTransactionLogsConfig, RpcTransactionLogsFilter,
|
|
|
|
},
|
|
|
|
rpc_response::{
|
|
|
|
Response as RpcResponse, RpcKeyedAccount, RpcLogsResponse, RpcSignatureResult, SlotInfo,
|
|
|
|
},
|
2020-07-23 12:38:28 -07:00
|
|
|
};
|
2020-04-22 11:22:09 -07:00
|
|
|
#[cfg(test)]
|
2020-06-17 08:27:03 -07:00
|
|
|
use solana_runtime::bank_forks::BankForks;
|
2020-09-01 22:06:06 -07:00
|
|
|
use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature};
|
2020-05-06 23:23:06 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
use std::sync::RwLock;
|
2020-04-22 11:22:09 -07:00
|
|
|
use std::{
|
|
|
|
str::FromStr,
|
|
|
|
sync::{atomic, Arc},
|
|
|
|
};
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-12-11 17:57:40 -08:00
|
|
|
const MAX_ACTIVE_SUBSCRIPTIONS: usize = 100_000;
|
|
|
|
|
2019-11-08 15:41:36 -08:00
|
|
|
// Suppress needless_return due to
|
|
|
|
// https://github.com/paritytech/jsonrpc/blob/2d38e6424d8461cdf72e78425ce67d51af9c6586/derive/src/lib.rs#L204
|
|
|
|
// Once https://github.com/paritytech/jsonrpc/issues/418 is resolved, try to remove this clippy allow
|
|
|
|
#[allow(clippy::needless_return)]
|
2020-02-25 20:23:54 -08:00
|
|
|
#[rpc]
|
2019-02-04 16:41:03 -08:00
|
|
|
pub trait RpcSolPubSub {
|
|
|
|
type Metadata;
|
|
|
|
|
2019-03-14 09:48:27 -07:00
|
|
|
// Get notification every time account data is changed
|
2019-02-04 16:41:03 -08:00
|
|
|
// Accepts pubkey parameter as base-58 encoded string
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "accountNotification",
|
|
|
|
subscribe,
|
|
|
|
name = "accountSubscribe"
|
|
|
|
)]
|
2019-05-06 07:31:50 -07:00
|
|
|
fn account_subscribe(
|
|
|
|
&self,
|
2020-01-15 10:52:02 -08:00
|
|
|
meta: Self::Metadata,
|
2020-06-30 21:55:11 -07:00
|
|
|
subscriber: Subscriber<RpcResponse<UiAccount>>,
|
2020-01-15 10:52:02 -08:00
|
|
|
pubkey_str: String,
|
2020-07-23 12:38:28 -07:00
|
|
|
config: Option<RpcAccountInfoConfig>,
|
2019-05-06 07:31:50 -07:00
|
|
|
);
|
2019-02-04 16:41:03 -08:00
|
|
|
|
|
|
|
// Unsubscribe from account notification subscription.
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "accountNotification",
|
|
|
|
unsubscribe,
|
|
|
|
name = "accountUnsubscribe"
|
|
|
|
)]
|
2020-01-15 10:52:02 -08:00
|
|
|
fn account_unsubscribe(&self, meta: Option<Self::Metadata>, id: SubscriptionId)
|
|
|
|
-> Result<bool>;
|
2019-02-04 16:41:03 -08:00
|
|
|
|
2019-03-14 09:48:27 -07:00
|
|
|
// Get notification every time account data owned by a particular program is changed
|
2019-03-06 14:31:58 -08:00
|
|
|
// Accepts pubkey parameter as base-58 encoded string
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "programNotification",
|
|
|
|
subscribe,
|
|
|
|
name = "programSubscribe"
|
|
|
|
)]
|
2019-05-06 07:31:50 -07:00
|
|
|
fn program_subscribe(
|
|
|
|
&self,
|
2020-01-15 10:52:02 -08:00
|
|
|
meta: Self::Metadata,
|
2020-03-23 05:34:42 -07:00
|
|
|
subscriber: Subscriber<RpcResponse<RpcKeyedAccount>>,
|
2020-01-15 10:52:02 -08:00
|
|
|
pubkey_str: String,
|
2020-07-23 12:38:28 -07:00
|
|
|
config: Option<RpcProgramAccountsConfig>,
|
2019-05-06 07:31:50 -07:00
|
|
|
);
|
2019-03-06 14:31:58 -08:00
|
|
|
|
|
|
|
// Unsubscribe from account notification subscription.
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "programNotification",
|
|
|
|
unsubscribe,
|
|
|
|
name = "programUnsubscribe"
|
|
|
|
)]
|
2020-01-15 10:52:02 -08:00
|
|
|
fn program_unsubscribe(&self, meta: Option<Self::Metadata>, id: SubscriptionId)
|
|
|
|
-> Result<bool>;
|
2019-03-06 14:31:58 -08:00
|
|
|
|
2020-11-20 13:52:58 -08:00
|
|
|
// Get logs for all transactions that reference the specified address
|
|
|
|
#[pubsub(subscription = "logsNotification", subscribe, name = "logsSubscribe")]
|
|
|
|
fn logs_subscribe(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
subscriber: Subscriber<RpcResponse<RpcLogsResponse>>,
|
|
|
|
filter: RpcTransactionLogsFilter,
|
2020-12-07 11:00:52 -08:00
|
|
|
config: Option<RpcTransactionLogsConfig>,
|
2020-11-20 13:52:58 -08:00
|
|
|
);
|
|
|
|
|
|
|
|
// Unsubscribe from logs notification subscription.
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "logsNotification",
|
|
|
|
unsubscribe,
|
|
|
|
name = "logsUnsubscribe"
|
|
|
|
)]
|
|
|
|
fn logs_unsubscribe(&self, meta: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
2019-02-04 16:41:03 -08:00
|
|
|
// Get notification when signature is verified
|
|
|
|
// Accepts signature parameter as base-58 encoded string
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "signatureNotification",
|
|
|
|
subscribe,
|
|
|
|
name = "signatureSubscribe"
|
|
|
|
)]
|
2019-04-05 19:56:17 -07:00
|
|
|
fn signature_subscribe(
|
|
|
|
&self,
|
2020-01-15 10:52:02 -08:00
|
|
|
meta: Self::Metadata,
|
2020-04-04 16:13:26 -07:00
|
|
|
subscriber: Subscriber<RpcResponse<RpcSignatureResult>>,
|
2020-01-15 10:52:02 -08:00
|
|
|
signature_str: String,
|
2020-09-01 22:06:06 -07:00
|
|
|
config: Option<RpcSignatureSubscribeConfig>,
|
2019-04-05 19:56:17 -07:00
|
|
|
);
|
2019-02-04 16:41:03 -08:00
|
|
|
|
|
|
|
// Unsubscribe from signature notification subscription.
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "signatureNotification",
|
|
|
|
unsubscribe,
|
|
|
|
name = "signatureUnsubscribe"
|
|
|
|
)]
|
2020-01-15 10:52:02 -08:00
|
|
|
fn signature_unsubscribe(
|
|
|
|
&self,
|
|
|
|
meta: Option<Self::Metadata>,
|
|
|
|
id: SubscriptionId,
|
|
|
|
) -> Result<bool>;
|
2019-11-26 00:42:54 -08:00
|
|
|
|
|
|
|
// Get notification when slot is encountered
|
|
|
|
#[pubsub(subscription = "slotNotification", subscribe, name = "slotSubscribe")]
|
2020-01-15 10:52:02 -08:00
|
|
|
fn slot_subscribe(&self, meta: Self::Metadata, subscriber: Subscriber<SlotInfo>);
|
2019-11-26 00:42:54 -08:00
|
|
|
|
|
|
|
// Unsubscribe from slot notification subscription.
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "slotNotification",
|
|
|
|
unsubscribe,
|
|
|
|
name = "slotUnsubscribe"
|
|
|
|
)]
|
2020-01-15 10:52:02 -08:00
|
|
|
fn slot_unsubscribe(&self, meta: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool>;
|
2020-03-27 09:33:40 -07:00
|
|
|
|
2020-05-17 14:01:08 -07:00
|
|
|
// Get notification when vote is encountered
|
|
|
|
#[pubsub(subscription = "voteNotification", subscribe, name = "voteSubscribe")]
|
|
|
|
fn vote_subscribe(&self, meta: Self::Metadata, subscriber: Subscriber<RpcVote>);
|
|
|
|
|
|
|
|
// Unsubscribe from vote notification subscription.
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "voteNotification",
|
|
|
|
unsubscribe,
|
|
|
|
name = "voteUnsubscribe"
|
|
|
|
)]
|
|
|
|
fn vote_unsubscribe(&self, meta: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
2020-03-27 09:33:40 -07:00
|
|
|
// Get notification when a new root is set
|
|
|
|
#[pubsub(subscription = "rootNotification", subscribe, name = "rootSubscribe")]
|
|
|
|
fn root_subscribe(&self, meta: Self::Metadata, subscriber: Subscriber<Slot>);
|
|
|
|
|
|
|
|
// Unsubscribe from slot notification subscription.
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "rootNotification",
|
|
|
|
unsubscribe,
|
|
|
|
name = "rootUnsubscribe"
|
|
|
|
)]
|
|
|
|
fn root_unsubscribe(&self, meta: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool>;
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
|
2019-02-17 09:09:46 -08:00
|
|
|
pub struct RpcSolPubSubImpl {
|
2018-10-12 11:04:14 -07:00
|
|
|
uid: Arc<atomic::AtomicUsize>,
|
2019-02-17 12:51:12 -08:00
|
|
|
subscriptions: Arc<RpcSubscriptions>,
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
2018-10-12 11:04:14 -07:00
|
|
|
|
|
|
|
impl RpcSolPubSubImpl {
|
2019-02-18 16:25:17 -08:00
|
|
|
pub fn new(subscriptions: Arc<RpcSubscriptions>) -> Self {
|
2019-02-17 12:51:12 -08:00
|
|
|
let uid = Arc::new(atomic::AtomicUsize::default());
|
2019-02-18 16:25:17 -08:00
|
|
|
Self { uid, subscriptions }
|
2019-02-17 12:51:12 -08:00
|
|
|
}
|
2019-02-17 12:24:36 -08:00
|
|
|
|
2020-04-22 11:22:09 -07:00
|
|
|
#[cfg(test)]
|
2020-06-25 21:06:58 -07:00
|
|
|
fn default_with_bank_forks(bank_forks: Arc<RwLock<BankForks>>) -> Self {
|
2020-04-22 11:22:09 -07:00
|
|
|
let uid = Arc::new(atomic::AtomicUsize::default());
|
2020-06-25 21:06:58 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::default_with_bank_forks(bank_forks));
|
2020-04-22 11:22:09 -07:00
|
|
|
Self { uid, subscriptions }
|
|
|
|
}
|
2020-12-11 17:57:40 -08:00
|
|
|
|
|
|
|
fn check_subscription_count(&self) -> Result<()> {
|
|
|
|
let num_subscriptions = self.subscriptions.total();
|
|
|
|
debug!("Total existing subscriptions: {}", num_subscriptions);
|
|
|
|
if num_subscriptions >= MAX_ACTIVE_SUBSCRIPTIONS {
|
|
|
|
info!("Node subscription limit reached");
|
|
|
|
Err(Error {
|
|
|
|
code: ErrorCode::InternalError,
|
|
|
|
message: "Internal Error: Subscription refused. Node subscription limit reached"
|
|
|
|
.into(),
|
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2020-04-22 11:22:09 -07:00
|
|
|
}
|
2019-05-20 22:21:13 -07:00
|
|
|
|
|
|
|
fn param<T: FromStr>(param_str: &str, thing: &str) -> Result<T> {
|
|
|
|
param_str.parse::<T>().map_err(|_e| Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: format!("Invalid Request: Invalid {} provided", thing),
|
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-02-17 12:24:36 -08:00
|
|
|
impl RpcSolPubSub for RpcSolPubSubImpl {
|
|
|
|
type Metadata = Arc<Session>;
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-02-17 12:24:36 -08:00
|
|
|
fn account_subscribe(
|
2019-02-17 09:09:46 -08:00
|
|
|
&self,
|
2019-02-17 12:24:36 -08:00
|
|
|
_meta: Self::Metadata,
|
2020-06-30 21:55:11 -07:00
|
|
|
subscriber: Subscriber<RpcResponse<UiAccount>>,
|
2019-02-17 09:09:46 -08:00
|
|
|
pubkey_str: String,
|
2020-07-23 12:38:28 -07:00
|
|
|
config: Option<RpcAccountInfoConfig>,
|
2019-02-17 09:09:46 -08:00
|
|
|
) {
|
2020-12-11 17:57:40 -08:00
|
|
|
if let Err(err) = self.check_subscription_count() {
|
|
|
|
subscriber.reject(err).unwrap_or_default();
|
|
|
|
return;
|
|
|
|
}
|
2019-05-20 22:21:13 -07:00
|
|
|
match param::<Pubkey>(&pubkey_str, "pubkey") {
|
|
|
|
Ok(pubkey) => {
|
2019-06-06 23:53:21 -07:00
|
|
|
let id = self.uid.fetch_add(1, atomic::Ordering::Relaxed);
|
2019-05-20 22:21:13 -07:00
|
|
|
let sub_id = SubscriptionId::Number(id as u64);
|
|
|
|
info!("account_subscribe: account={:?} id={:?}", pubkey, sub_id);
|
2020-05-06 23:23:06 -07:00
|
|
|
self.subscriptions
|
2020-07-23 12:38:28 -07:00
|
|
|
.add_account_subscription(pubkey, config, sub_id, subscriber)
|
2019-05-20 22:21:13 -07:00
|
|
|
}
|
2020-12-11 17:57:40 -08:00
|
|
|
Err(e) => subscriber.reject(e).unwrap_or_default(),
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-17 12:24:36 -08:00
|
|
|
fn account_unsubscribe(
|
|
|
|
&self,
|
|
|
|
_meta: Option<Self::Metadata>,
|
|
|
|
id: SubscriptionId,
|
|
|
|
) -> Result<bool> {
|
|
|
|
info!("account_unsubscribe: id={:?}", id);
|
2019-02-17 12:51:12 -08:00
|
|
|
if self.subscriptions.remove_account_subscription(&id) {
|
2019-02-17 12:24:36 -08:00
|
|
|
Ok(true)
|
|
|
|
} else {
|
|
|
|
Err(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid Request: Subscription id does not exist".into(),
|
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-06 14:31:58 -08:00
|
|
|
fn program_subscribe(
|
|
|
|
&self,
|
|
|
|
_meta: Self::Metadata,
|
2020-03-23 05:34:42 -07:00
|
|
|
subscriber: Subscriber<RpcResponse<RpcKeyedAccount>>,
|
2019-03-06 14:31:58 -08:00
|
|
|
pubkey_str: String,
|
2020-07-23 12:38:28 -07:00
|
|
|
config: Option<RpcProgramAccountsConfig>,
|
2019-03-06 14:31:58 -08:00
|
|
|
) {
|
2020-12-11 17:57:40 -08:00
|
|
|
if let Err(err) = self.check_subscription_count() {
|
|
|
|
subscriber.reject(err).unwrap_or_default();
|
|
|
|
return;
|
|
|
|
}
|
2019-05-20 22:21:13 -07:00
|
|
|
match param::<Pubkey>(&pubkey_str, "pubkey") {
|
|
|
|
Ok(pubkey) => {
|
2019-06-06 23:53:21 -07:00
|
|
|
let id = self.uid.fetch_add(1, atomic::Ordering::Relaxed);
|
2019-05-20 22:21:13 -07:00
|
|
|
let sub_id = SubscriptionId::Number(id as u64);
|
|
|
|
info!("program_subscribe: account={:?} id={:?}", pubkey, sub_id);
|
2020-05-06 23:23:06 -07:00
|
|
|
self.subscriptions
|
2020-07-23 12:38:28 -07:00
|
|
|
.add_program_subscription(pubkey, config, sub_id, subscriber)
|
2019-05-20 22:21:13 -07:00
|
|
|
}
|
2020-12-11 17:57:40 -08:00
|
|
|
Err(e) => subscriber.reject(e).unwrap_or_default(),
|
2019-03-06 14:31:58 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn program_unsubscribe(
|
|
|
|
&self,
|
|
|
|
_meta: Option<Self::Metadata>,
|
|
|
|
id: SubscriptionId,
|
|
|
|
) -> Result<bool> {
|
2019-03-08 15:27:54 -08:00
|
|
|
info!("program_unsubscribe: id={:?}", id);
|
2019-03-06 14:31:58 -08:00
|
|
|
if self.subscriptions.remove_program_subscription(&id) {
|
|
|
|
Ok(true)
|
|
|
|
} else {
|
|
|
|
Err(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid Request: Subscription id does not exist".into(),
|
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-20 13:52:58 -08:00
|
|
|
fn logs_subscribe(
|
|
|
|
&self,
|
|
|
|
_meta: Self::Metadata,
|
|
|
|
subscriber: Subscriber<RpcResponse<RpcLogsResponse>>,
|
|
|
|
filter: RpcTransactionLogsFilter,
|
2020-12-07 11:00:52 -08:00
|
|
|
config: Option<RpcTransactionLogsConfig>,
|
2020-11-20 13:52:58 -08:00
|
|
|
) {
|
|
|
|
info!("logs_subscribe");
|
2020-12-11 17:57:40 -08:00
|
|
|
if let Err(err) = self.check_subscription_count() {
|
|
|
|
subscriber.reject(err).unwrap_or_default();
|
|
|
|
return;
|
|
|
|
}
|
2020-11-20 13:52:58 -08:00
|
|
|
|
|
|
|
let (address, include_votes) = match filter {
|
|
|
|
RpcTransactionLogsFilter::All => (None, false),
|
|
|
|
RpcTransactionLogsFilter::AllWithVotes => (None, true),
|
|
|
|
RpcTransactionLogsFilter::Mentions(addresses) => {
|
|
|
|
match addresses.len() {
|
|
|
|
1 => match param::<Pubkey>(&addresses[0], "mentions") {
|
|
|
|
Ok(address) => (Some(address), false),
|
|
|
|
Err(e) => {
|
2020-12-11 17:57:40 -08:00
|
|
|
subscriber.reject(e).unwrap_or_default();
|
2020-11-20 13:52:58 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
// Room is reserved in the API to support multiple addresses, but for now
|
|
|
|
// the implementation only supports one
|
|
|
|
subscriber
|
|
|
|
.reject(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid Request: Only 1 address supported".into(),
|
|
|
|
data: None,
|
|
|
|
})
|
2020-12-11 17:57:40 -08:00
|
|
|
.unwrap_or_default();
|
2020-11-20 13:52:58 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let id = self.uid.fetch_add(1, atomic::Ordering::Relaxed);
|
|
|
|
let sub_id = SubscriptionId::Number(id as u64);
|
|
|
|
self.subscriptions.add_logs_subscription(
|
|
|
|
address,
|
|
|
|
include_votes,
|
2020-12-07 11:00:52 -08:00
|
|
|
config.and_then(|config| config.commitment),
|
2020-11-20 13:52:58 -08:00
|
|
|
sub_id,
|
|
|
|
subscriber,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn logs_unsubscribe(&self, _meta: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool> {
|
|
|
|
info!("logs_unsubscribe: id={:?}", id);
|
|
|
|
if self.subscriptions.remove_logs_subscription(&id) {
|
|
|
|
Ok(true)
|
|
|
|
} else {
|
|
|
|
Err(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid Request: Subscription id does not exist".into(),
|
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-17 12:24:36 -08:00
|
|
|
fn signature_subscribe(
|
2018-10-10 13:51:43 -07:00
|
|
|
&self,
|
2019-02-17 12:24:36 -08:00
|
|
|
_meta: Self::Metadata,
|
2020-04-04 16:13:26 -07:00
|
|
|
subscriber: Subscriber<RpcResponse<RpcSignatureResult>>,
|
2018-10-10 13:51:43 -07:00
|
|
|
signature_str: String,
|
2020-09-01 22:06:06 -07:00
|
|
|
signature_subscribe_config: Option<RpcSignatureSubscribeConfig>,
|
2018-10-10 13:51:43 -07:00
|
|
|
) {
|
2018-10-12 11:04:14 -07:00
|
|
|
info!("signature_subscribe");
|
2020-12-11 17:57:40 -08:00
|
|
|
if let Err(err) = self.check_subscription_count() {
|
|
|
|
subscriber.reject(err).unwrap_or_default();
|
|
|
|
return;
|
|
|
|
}
|
2019-05-20 22:21:13 -07:00
|
|
|
match param::<Signature>(&signature_str, "signature") {
|
|
|
|
Ok(signature) => {
|
2019-06-06 23:53:21 -07:00
|
|
|
let id = self.uid.fetch_add(1, atomic::Ordering::Relaxed);
|
2019-05-20 22:21:13 -07:00
|
|
|
let sub_id = SubscriptionId::Number(id as u64);
|
|
|
|
info!(
|
|
|
|
"signature_subscribe: signature={:?} id={:?}",
|
|
|
|
signature, sub_id
|
|
|
|
);
|
2020-09-01 22:06:06 -07:00
|
|
|
self.subscriptions.add_signature_subscription(
|
|
|
|
signature,
|
|
|
|
signature_subscribe_config,
|
|
|
|
sub_id,
|
|
|
|
subscriber,
|
|
|
|
);
|
2019-05-20 22:21:13 -07:00
|
|
|
}
|
2020-12-11 17:57:40 -08:00
|
|
|
Err(e) => subscriber.reject(e).unwrap_or_default(),
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-04 16:41:03 -08:00
|
|
|
fn signature_unsubscribe(
|
|
|
|
&self,
|
|
|
|
_meta: Option<Self::Metadata>,
|
|
|
|
id: SubscriptionId,
|
|
|
|
) -> Result<bool> {
|
2018-10-12 11:04:14 -07:00
|
|
|
info!("signature_unsubscribe");
|
2019-02-17 12:51:12 -08:00
|
|
|
if self.subscriptions.remove_signature_subscription(&id) {
|
2018-10-10 13:51:43 -07:00
|
|
|
Ok(true)
|
|
|
|
} else {
|
|
|
|
Err(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid Request: Subscription id does not exist".into(),
|
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2019-11-26 00:42:54 -08:00
|
|
|
|
|
|
|
fn slot_subscribe(&self, _meta: Self::Metadata, subscriber: Subscriber<SlotInfo>) {
|
|
|
|
info!("slot_subscribe");
|
2020-12-11 17:57:40 -08:00
|
|
|
if let Err(err) = self.check_subscription_count() {
|
|
|
|
subscriber.reject(err).unwrap_or_default();
|
|
|
|
return;
|
|
|
|
}
|
2019-11-26 00:42:54 -08:00
|
|
|
let id = self.uid.fetch_add(1, atomic::Ordering::Relaxed);
|
|
|
|
let sub_id = SubscriptionId::Number(id as u64);
|
|
|
|
info!("slot_subscribe: id={:?}", sub_id);
|
2020-03-24 09:53:32 -07:00
|
|
|
self.subscriptions.add_slot_subscription(sub_id, subscriber);
|
2019-11-26 00:42:54 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn slot_unsubscribe(&self, _meta: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool> {
|
|
|
|
info!("slot_unsubscribe");
|
|
|
|
if self.subscriptions.remove_slot_subscription(&id) {
|
|
|
|
Ok(true)
|
|
|
|
} else {
|
|
|
|
Err(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid Request: Subscription id does not exist".into(),
|
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2020-03-27 09:33:40 -07:00
|
|
|
|
2020-05-17 14:01:08 -07:00
|
|
|
fn vote_subscribe(&self, _meta: Self::Metadata, subscriber: Subscriber<RpcVote>) {
|
|
|
|
info!("vote_subscribe");
|
2020-12-11 17:57:40 -08:00
|
|
|
if let Err(err) = self.check_subscription_count() {
|
|
|
|
subscriber.reject(err).unwrap_or_default();
|
|
|
|
return;
|
|
|
|
}
|
2020-05-17 14:01:08 -07:00
|
|
|
let id = self.uid.fetch_add(1, atomic::Ordering::Relaxed);
|
|
|
|
let sub_id = SubscriptionId::Number(id as u64);
|
|
|
|
info!("vote_subscribe: id={:?}", sub_id);
|
|
|
|
self.subscriptions.add_vote_subscription(sub_id, subscriber);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn vote_unsubscribe(&self, _meta: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool> {
|
|
|
|
info!("vote_unsubscribe");
|
|
|
|
if self.subscriptions.remove_vote_subscription(&id) {
|
|
|
|
Ok(true)
|
|
|
|
} else {
|
|
|
|
Err(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid Request: Subscription id does not exist".into(),
|
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-27 09:33:40 -07:00
|
|
|
fn root_subscribe(&self, _meta: Self::Metadata, subscriber: Subscriber<Slot>) {
|
|
|
|
info!("root_subscribe");
|
2020-12-11 17:57:40 -08:00
|
|
|
if let Err(err) = self.check_subscription_count() {
|
|
|
|
subscriber.reject(err).unwrap_or_default();
|
|
|
|
return;
|
|
|
|
}
|
2020-03-27 09:33:40 -07:00
|
|
|
let id = self.uid.fetch_add(1, atomic::Ordering::Relaxed);
|
|
|
|
let sub_id = SubscriptionId::Number(id as u64);
|
|
|
|
info!("root_subscribe: id={:?}", sub_id);
|
|
|
|
self.subscriptions.add_root_subscription(sub_id, subscriber);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn root_unsubscribe(&self, _meta: Option<Self::Metadata>, id: SubscriptionId) -> Result<bool> {
|
|
|
|
info!("root_unsubscribe");
|
|
|
|
if self.subscriptions.remove_root_subscription(&id) {
|
|
|
|
Ok(true)
|
|
|
|
} else {
|
|
|
|
Err(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid Request: Subscription id does not exist".into(),
|
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2020-03-30 16:53:25 -07:00
|
|
|
use crate::{
|
2020-05-17 14:01:08 -07:00
|
|
|
cluster_info_vote_listener::{ClusterInfoVoteListener, VoteTracker},
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank,
|
2020-07-17 08:24:51 -07:00
|
|
|
rpc_subscriptions::tests::robust_poll_or_panic,
|
2020-03-30 16:53:25 -07:00
|
|
|
};
|
2020-05-17 14:01:08 -07:00
|
|
|
use crossbeam_channel::unbounded;
|
2020-01-15 10:52:02 -08:00
|
|
|
use jsonrpc_core::{futures::sync::mpsc, Response};
|
2019-02-17 10:17:58 -08:00
|
|
|
use jsonrpc_pubsub::{PubSubHandler, Session};
|
2020-04-16 22:02:55 -07:00
|
|
|
use serial_test_derive::serial;
|
2020-07-23 12:38:28 -07:00
|
|
|
use solana_account_decoder::{parse_account_data::parse_account_data, UiAccountEncoding};
|
2020-09-03 17:14:45 -07:00
|
|
|
use solana_client::rpc_response::{ProcessedSignatureResult, ReceivedSignatureResult};
|
2020-05-17 14:01:08 -07:00
|
|
|
use solana_runtime::{
|
|
|
|
bank::Bank,
|
2020-06-17 08:27:03 -07:00
|
|
|
bank_forks::BankForks,
|
2020-07-17 10:54:49 -07:00
|
|
|
commitment::{BlockCommitmentCache, CommitmentSlots},
|
2020-06-25 21:06:58 -07:00
|
|
|
genesis_utils::{
|
|
|
|
create_genesis_config, create_genesis_config_with_vote_accounts, GenesisConfigInfo,
|
|
|
|
ValidatorVoteKeypairs,
|
|
|
|
},
|
2020-05-17 14:01:08 -07:00
|
|
|
};
|
2020-01-15 10:52:02 -08:00
|
|
|
use solana_sdk::{
|
2020-09-01 22:06:06 -07:00
|
|
|
commitment_config::CommitmentConfig,
|
2020-05-17 14:01:08 -07:00
|
|
|
hash::Hash,
|
2020-06-24 13:52:38 -07:00
|
|
|
message::Message,
|
2020-01-15 10:52:02 -08:00
|
|
|
pubkey::Pubkey,
|
2020-02-20 13:28:55 -08:00
|
|
|
signature::{Keypair, Signer},
|
2020-07-23 12:38:28 -07:00
|
|
|
system_instruction, system_program, system_transaction,
|
2020-01-15 10:52:02 -08:00
|
|
|
transaction::{self, Transaction},
|
|
|
|
};
|
2020-08-07 15:01:51 -07:00
|
|
|
use solana_stake_program::{
|
|
|
|
self, stake_instruction,
|
|
|
|
stake_state::{Authorized, Lockup, StakeAuthorize, StakeState},
|
|
|
|
};
|
2020-05-17 14:01:08 -07:00
|
|
|
use solana_vote_program::vote_transaction;
|
2020-03-30 16:53:25 -07:00
|
|
|
use std::{
|
|
|
|
sync::{atomic::AtomicBool, RwLock},
|
|
|
|
thread::sleep,
|
|
|
|
time::Duration,
|
|
|
|
};
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-02-18 14:21:23 -08:00
|
|
|
fn process_transaction_and_notify(
|
2020-06-08 17:38:14 -07:00
|
|
|
bank_forks: &RwLock<BankForks>,
|
2019-02-17 15:33:25 -08:00
|
|
|
tx: &Transaction,
|
|
|
|
subscriptions: &RpcSubscriptions,
|
2020-05-18 11:49:01 -07:00
|
|
|
current_slot: Slot,
|
2019-05-06 07:31:50 -07:00
|
|
|
) -> transaction::Result<()> {
|
|
|
|
bank_forks
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
2020-05-18 11:49:01 -07:00
|
|
|
.get(current_slot)
|
2019-05-06 07:31:50 -07:00
|
|
|
.unwrap()
|
|
|
|
.process_transaction(tx)?;
|
2020-07-17 10:54:49 -07:00
|
|
|
let mut commitment_slots = CommitmentSlots::default();
|
|
|
|
commitment_slots.slot = current_slot;
|
|
|
|
subscriptions.notify_subscribers(commitment_slots);
|
2019-05-06 07:31:50 -07:00
|
|
|
Ok(())
|
2019-02-17 15:33:25 -08:00
|
|
|
}
|
|
|
|
|
2019-02-17 12:24:36 -08:00
|
|
|
fn create_session() -> Arc<Session> {
|
|
|
|
Arc::new(Session::new(mpsc::channel(1).0))
|
|
|
|
}
|
|
|
|
|
2018-10-10 13:51:43 -07:00
|
|
|
#[test]
|
2020-04-16 22:02:55 -07:00
|
|
|
#[serial]
|
2018-10-10 13:51:43 -07:00
|
|
|
fn test_signature_subscribe() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair: alice,
|
|
|
|
..
|
2019-11-08 20:56:57 -08:00
|
|
|
} = create_genesis_config(10_000);
|
2018-10-10 13:51:43 -07:00
|
|
|
let bob = Keypair::new();
|
|
|
|
let bob_pubkey = bob.pubkey();
|
2019-11-08 20:56:57 -08:00
|
|
|
let bank = Bank::new(&genesis_config);
|
2019-05-06 07:31:50 -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)));
|
2020-03-30 16:53:25 -07:00
|
|
|
let rpc = RpcSolPubSubImpl {
|
|
|
|
subscriptions: Arc::new(RpcSubscriptions::new(
|
|
|
|
&Arc::new(AtomicBool::new(false)),
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks.clone(),
|
2020-06-25 21:06:58 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
2020-09-28 19:43:05 -07:00
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
2020-03-30 16:53:25 -07:00
|
|
|
)),
|
2020-04-22 11:22:09 -07:00
|
|
|
uid: Arc::new(atomic::AtomicUsize::default()),
|
2020-03-30 16:53:25 -07:00
|
|
|
};
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-02-17 12:51:12 -08:00
|
|
|
// Test signature subscriptions
|
2019-05-20 10:03:19 -07:00
|
|
|
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-02-17 12:24:36 -08:00
|
|
|
let session = create_session();
|
2020-01-20 13:08:29 -08:00
|
|
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("signatureNotification");
|
2020-11-23 15:00:03 -08:00
|
|
|
rpc.signature_subscribe(
|
|
|
|
session,
|
|
|
|
subscriber,
|
|
|
|
tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::single()),
|
|
|
|
..RpcSignatureSubscribeConfig::default()
|
|
|
|
}),
|
|
|
|
);
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-05-06 23:23:06 -07:00
|
|
|
process_transaction_and_notify(&bank_forks, &tx, &rpc.subscriptions, 0).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
|
|
|
// Test signature confirmation notification
|
2020-03-27 09:33:40 -07:00
|
|
|
let (response, _) = robust_poll_or_panic(receiver);
|
2020-09-01 22:06:06 -07:00
|
|
|
let expected_res =
|
2020-09-03 17:14:45 -07:00
|
|
|
RpcSignatureResult::ProcessedSignature(ProcessedSignatureResult { err: None });
|
2020-03-23 05:34:42 -07:00
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "signatureNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": 0 },
|
|
|
|
"value": expected_res,
|
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
2020-09-01 22:06:06 -07:00
|
|
|
|
|
|
|
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
|
|
|
|
|
|
|
// Test "received"
|
|
|
|
let session = create_session();
|
|
|
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("signatureNotification");
|
|
|
|
rpc.signature_subscribe(
|
|
|
|
session,
|
|
|
|
subscriber,
|
|
|
|
tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
2020-11-23 15:00:03 -08:00
|
|
|
commitment: Some(CommitmentConfig::single()),
|
2020-09-01 22:06:06 -07:00
|
|
|
enable_received_notification: Some(true),
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
let received_slot = 1;
|
|
|
|
rpc.subscriptions
|
|
|
|
.notify_signatures_received((received_slot, vec![tx.signatures[0]]));
|
|
|
|
// Test signature confirmation notification
|
|
|
|
let (response, _) = robust_poll_or_panic(receiver);
|
2020-09-03 17:14:45 -07:00
|
|
|
let expected_res =
|
|
|
|
RpcSignatureResult::ReceivedSignature(ReceivedSignatureResult::ReceivedSignature);
|
2020-09-01 22:06:06 -07:00
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "signatureNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": received_slot },
|
|
|
|
"value": expected_res,
|
|
|
|
},
|
|
|
|
"subscription": 1,
|
|
|
|
}
|
|
|
|
});
|
2020-03-23 05:34:42 -07:00
|
|
|
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-04-16 22:02:55 -07:00
|
|
|
#[serial]
|
2018-10-10 13:51:43 -07:00
|
|
|
fn test_signature_unsubscribe() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair: alice,
|
|
|
|
..
|
2019-11-08 20:56:57 -08:00
|
|
|
} = create_genesis_config(10_000);
|
2020-10-19 12:12:08 -07:00
|
|
|
let bob_pubkey = solana_sdk::pubkey::new_rand();
|
2019-11-08 20:56:57 -08:00
|
|
|
let bank = Bank::new(&genesis_config);
|
2020-05-06 23:23:06 -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)));
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-02-17 12:24:36 -08:00
|
|
|
let session = create_session();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
|
|
|
let mut io = PubSubHandler::default();
|
2020-06-25 21:06:58 -07:00
|
|
|
let rpc = RpcSolPubSubImpl::default_with_bank_forks(bank_forks);
|
2018-10-10 13:51:43 -07:00
|
|
|
io.extend_with(rpc.to_delegate());
|
|
|
|
|
2019-05-20 10:03:19 -07:00
|
|
|
let tx = system_transaction::transfer(&alice, &bob_pubkey, 20, blockhash);
|
2018-10-10 13:51:43 -07:00
|
|
|
let req = format!(
|
|
|
|
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
|
2018-10-26 14:43:34 -07:00
|
|
|
tx.signatures[0].to_string()
|
2018-10-10 13:51:43 -07:00
|
|
|
);
|
2018-10-12 11:04:14 -07:00
|
|
|
let _res = io.handle_request_sync(&req, session.clone());
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-05-15 09:35:43 -07:00
|
|
|
let req = r#"{"jsonrpc":"2.0","id":1,"method":"signatureUnsubscribe","params":[0]}"#;
|
2018-10-12 11:04:14 -07:00
|
|
|
let res = io.handle_request_sync(&req, session.clone());
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-05-15 09:35:43 -07:00
|
|
|
let expected = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
|
2019-02-17 15:33:25 -08:00
|
|
|
let expected: Response = serde_json::from_str(&expected).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-02-17 15:33:25 -08:00
|
|
|
let result: Response = serde_json::from_str(&res.unwrap()).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
assert_eq!(expected, result);
|
|
|
|
|
|
|
|
// Test bad parameter
|
2020-05-15 09:35:43 -07:00
|
|
|
let req = r#"{"jsonrpc":"2.0","id":1,"method":"signatureUnsubscribe","params":[1]}"#;
|
|
|
|
let res = io.handle_request_sync(&req, session);
|
|
|
|
let expected = r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Request: Subscription id does not exist"},"id":1}"#;
|
2019-02-17 15:33:25 -08:00
|
|
|
let expected: Response = serde_json::from_str(&expected).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-02-17 15:33:25 -08:00
|
|
|
let result: Response = serde_json::from_str(&res.unwrap()).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
assert_eq!(expected, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-04-16 22:02:55 -07:00
|
|
|
#[serial]
|
2018-10-10 13:51:43 -07:00
|
|
|
fn test_account_subscribe() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
2020-08-07 15:01:51 -07:00
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair: alice,
|
|
|
|
..
|
2019-11-08 20:56:57 -08:00
|
|
|
} = create_genesis_config(10_000);
|
2019-03-12 11:44:41 -07:00
|
|
|
|
2020-10-19 12:12:08 -07:00
|
|
|
let new_stake_authority = solana_sdk::pubkey::new_rand();
|
2020-08-07 15:01:51 -07:00
|
|
|
let stake_authority = Keypair::new();
|
|
|
|
let from = Keypair::new();
|
|
|
|
let stake_account = Keypair::new();
|
|
|
|
let stake_program_id = solana_stake_program::id();
|
2019-11-08 20:56:57 -08:00
|
|
|
let bank = Bank::new(&genesis_config);
|
2019-05-06 07:31:50 -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)));
|
2020-05-06 23:23:06 -07:00
|
|
|
let bank0 = bank_forks.read().unwrap().get(0).unwrap().clone();
|
|
|
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
|
|
bank_forks.write().unwrap().insert(bank1);
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-03-30 16:53:25 -07:00
|
|
|
let rpc = RpcSolPubSubImpl {
|
|
|
|
subscriptions: Arc::new(RpcSubscriptions::new(
|
|
|
|
&Arc::new(AtomicBool::new(false)),
|
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),
|
2020-03-30 16:53:25 -07:00
|
|
|
)),
|
2020-04-22 11:22:09 -07:00
|
|
|
uid: Arc::new(atomic::AtomicUsize::default()),
|
2020-03-30 16:53:25 -07:00
|
|
|
};
|
2019-02-17 12:24:36 -08:00
|
|
|
let session = create_session();
|
2020-01-20 13:08:29 -08:00
|
|
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
2019-05-06 07:31:50 -07:00
|
|
|
rpc.account_subscribe(
|
|
|
|
session,
|
|
|
|
subscriber,
|
2020-08-07 15:01:51 -07:00
|
|
|
stake_account.pubkey().to_string(),
|
2020-07-23 12:38:28 -07:00
|
|
|
Some(RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::recent()),
|
|
|
|
encoding: None,
|
2020-08-10 15:35:29 -07:00
|
|
|
data_slice: None,
|
2020-07-23 12:38:28 -07:00
|
|
|
}),
|
2019-05-06 07:31:50 -07:00
|
|
|
);
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-08-07 15:01:51 -07:00
|
|
|
let tx = system_transaction::transfer(&alice, &from.pubkey(), 51, blockhash);
|
2020-05-06 23:23:06 -07:00
|
|
|
process_transaction_and_notify(&bank_forks, &tx, &rpc.subscriptions, 1).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-08-07 15:01:51 -07:00
|
|
|
let authorized = Authorized::auto(&stake_authority.pubkey());
|
|
|
|
let ixs = stake_instruction::create_account(
|
|
|
|
&from.pubkey(),
|
|
|
|
&stake_account.pubkey(),
|
|
|
|
&authorized,
|
|
|
|
&Lockup::default(),
|
2019-03-07 13:19:43 -08:00
|
|
|
51,
|
2018-10-10 13:51:43 -07:00
|
|
|
);
|
2020-08-07 15:01:51 -07:00
|
|
|
let message = Message::new(&ixs, Some(&from.pubkey()));
|
|
|
|
let tx = Transaction::new(&[&from, &stake_account], message, blockhash);
|
2020-05-06 23:23:06 -07:00
|
|
|
process_transaction_and_notify(&bank_forks, &tx, &rpc.subscriptions, 1).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
sleep(Duration::from_millis(200));
|
|
|
|
|
2019-03-07 13:19:43 -08:00
|
|
|
// Test signature confirmation notification #1
|
2019-05-06 07:31:50 -07:00
|
|
|
let expected_data = bank_forks
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
2020-05-06 23:23:06 -07:00
|
|
|
.get(1)
|
2019-05-06 07:31:50 -07:00
|
|
|
.unwrap()
|
2020-08-07 15:01:51 -07:00
|
|
|
.get_account(&stake_account.pubkey())
|
2019-05-06 07:31:50 -07:00
|
|
|
.unwrap()
|
|
|
|
.data;
|
2018-10-10 13:51:43 -07:00
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "accountNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
2020-05-06 23:23:06 -07:00
|
|
|
"context": { "slot": 1 },
|
2020-03-23 05:34:42 -07:00
|
|
|
"value": {
|
2020-08-07 15:01:51 -07:00
|
|
|
"owner": stake_program_id.to_string(),
|
2020-03-23 05:34:42 -07:00
|
|
|
"lamports": 51,
|
|
|
|
"data": bs58::encode(expected_data).into_string(),
|
|
|
|
"executable": false,
|
2020-08-16 22:22:16 -07:00
|
|
|
"rentEpoch": 0,
|
2020-03-23 05:34:42 -07:00
|
|
|
},
|
2018-10-10 13:51:43 -07:00
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-03-27 09:33:40 -07:00
|
|
|
let (response, _) = robust_poll_or_panic(receiver);
|
2020-01-20 13:08:29 -08:00
|
|
|
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-08-07 15:01:51 -07:00
|
|
|
let tx = system_transaction::transfer(&alice, &stake_authority.pubkey(), 1, blockhash);
|
2020-05-06 23:23:06 -07:00
|
|
|
process_transaction_and_notify(&bank_forks, &tx, &rpc.subscriptions, 1).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
sleep(Duration::from_millis(200));
|
2020-08-07 15:01:51 -07:00
|
|
|
let ix = stake_instruction::authorize(
|
|
|
|
&stake_account.pubkey(),
|
|
|
|
&stake_authority.pubkey(),
|
|
|
|
&new_stake_authority,
|
|
|
|
StakeAuthorize::Staker,
|
2018-10-10 13:51:43 -07:00
|
|
|
);
|
2020-08-07 15:01:51 -07:00
|
|
|
let message = Message::new(&[ix], Some(&stake_authority.pubkey()));
|
|
|
|
let tx = Transaction::new(&[&stake_authority], message, blockhash);
|
2020-05-06 23:23:06 -07:00
|
|
|
process_transaction_and_notify(&bank_forks, &tx, &rpc.subscriptions, 1).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
sleep(Duration::from_millis(200));
|
|
|
|
|
2020-08-07 15:01:51 -07:00
|
|
|
let bank = bank_forks.read().unwrap()[1].clone();
|
|
|
|
let account = bank.get_account(&stake_account.pubkey()).unwrap();
|
2019-05-06 07:31:50 -07:00
|
|
|
assert_eq!(
|
2020-08-07 15:01:51 -07:00
|
|
|
StakeState::authorized_from(&account).unwrap().staker,
|
|
|
|
new_stake_authority
|
2019-05-06 07:31:50 -07:00
|
|
|
);
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
|
2020-07-23 12:38:28 -07:00
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_account_subscribe_with_encoding() {
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
|
|
|
mint_keypair: alice,
|
|
|
|
..
|
|
|
|
} = create_genesis_config(10_000);
|
|
|
|
|
|
|
|
let nonce_account = Keypair::new();
|
|
|
|
let bank = Bank::new(&genesis_config);
|
|
|
|
let blockhash = bank.last_blockhash();
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let bank0 = bank_forks.read().unwrap().get(0).unwrap().clone();
|
|
|
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
|
|
bank_forks.write().unwrap().insert(bank1);
|
|
|
|
|
|
|
|
let rpc = RpcSolPubSubImpl {
|
|
|
|
subscriptions: Arc::new(RpcSubscriptions::new(
|
|
|
|
&Arc::new(AtomicBool::new(false)),
|
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
|
|
|
1, 1,
|
|
|
|
))),
|
2020-09-28 19:43:05 -07:00
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
2020-07-23 12:38:28 -07:00
|
|
|
)),
|
|
|
|
uid: Arc::new(atomic::AtomicUsize::default()),
|
|
|
|
};
|
|
|
|
let session = create_session();
|
|
|
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
|
|
|
rpc.account_subscribe(
|
|
|
|
session,
|
|
|
|
subscriber,
|
|
|
|
nonce_account.pubkey().to_string(),
|
|
|
|
Some(RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::recent()),
|
|
|
|
encoding: Some(UiAccountEncoding::JsonParsed),
|
2020-08-10 15:35:29 -07:00
|
|
|
data_slice: None,
|
2020-07-23 12:38:28 -07:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
let ixs = system_instruction::create_nonce_account(
|
|
|
|
&alice.pubkey(),
|
|
|
|
&nonce_account.pubkey(),
|
|
|
|
&alice.pubkey(),
|
|
|
|
100,
|
|
|
|
);
|
|
|
|
let message = Message::new(&ixs, Some(&alice.pubkey()));
|
|
|
|
let tx = Transaction::new(&[&alice, &nonce_account], message, blockhash);
|
|
|
|
process_transaction_and_notify(&bank_forks, &tx, &rpc.subscriptions, 1).unwrap();
|
|
|
|
sleep(Duration::from_millis(200));
|
|
|
|
|
|
|
|
// Test signature confirmation notification #1
|
|
|
|
let expected_data = bank_forks
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(1)
|
|
|
|
.unwrap()
|
|
|
|
.get_account(&nonce_account.pubkey())
|
|
|
|
.unwrap()
|
|
|
|
.data;
|
2020-08-09 00:50:45 -07:00
|
|
|
let expected_data = parse_account_data(
|
|
|
|
&nonce_account.pubkey(),
|
|
|
|
&system_program::id(),
|
|
|
|
&expected_data,
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
.unwrap();
|
2020-07-23 12:38:28 -07:00
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "accountNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": 1 },
|
|
|
|
"value": {
|
|
|
|
"owner": system_program::id().to_string(),
|
|
|
|
"lamports": 100,
|
|
|
|
"data": expected_data,
|
|
|
|
"executable": false,
|
2020-08-16 22:22:16 -07:00
|
|
|
"rentEpoch": 0,
|
2020-07-23 12:38:28 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let (response, _) = robust_poll_or_panic(receiver);
|
|
|
|
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
|
|
|
}
|
|
|
|
|
2018-10-10 13:51:43 -07:00
|
|
|
#[test]
|
2020-04-16 22:02:55 -07:00
|
|
|
#[serial]
|
2018-10-10 13:51:43 -07:00
|
|
|
fn test_account_unsubscribe() {
|
2020-10-19 12:12:08 -07:00
|
|
|
let bob_pubkey = solana_sdk::pubkey::new_rand();
|
2019-02-17 12:24:36 -08:00
|
|
|
let session = create_session();
|
2020-05-06 23:23:06 -07:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(Bank::new(&genesis_config))));
|
2018-10-10 13:51:43 -07:00
|
|
|
|
|
|
|
let mut io = PubSubHandler::default();
|
2020-06-25 21:06:58 -07:00
|
|
|
let rpc = RpcSolPubSubImpl::default_with_bank_forks(bank_forks);
|
2018-10-12 11:04:14 -07:00
|
|
|
|
2018-10-10 13:51:43 -07:00
|
|
|
io.extend_with(rpc.to_delegate());
|
|
|
|
|
|
|
|
let req = format!(
|
|
|
|
r#"{{"jsonrpc":"2.0","id":1,"method":"accountSubscribe","params":["{}"]}}"#,
|
|
|
|
bob_pubkey.to_string()
|
|
|
|
);
|
2018-10-12 11:04:14 -07:00
|
|
|
let _res = io.handle_request_sync(&req, session.clone());
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-05-15 09:35:43 -07:00
|
|
|
let req = r#"{"jsonrpc":"2.0","id":1,"method":"accountUnsubscribe","params":[0]}"#;
|
2018-10-12 11:04:14 -07:00
|
|
|
let res = io.handle_request_sync(&req, session.clone());
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2020-05-15 09:35:43 -07:00
|
|
|
let expected = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
|
2019-02-17 15:33:25 -08:00
|
|
|
let expected: Response = serde_json::from_str(&expected).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-02-17 15:33:25 -08:00
|
|
|
let result: Response = serde_json::from_str(&res.unwrap()).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
assert_eq!(expected, result);
|
|
|
|
|
|
|
|
// Test bad parameter
|
2020-05-15 09:35:43 -07:00
|
|
|
let req = r#"{"jsonrpc":"2.0","id":1,"method":"accountUnsubscribe","params":[1]}"#;
|
|
|
|
let res = io.handle_request_sync(&req, session);
|
|
|
|
let expected = r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid Request: Subscription id does not exist"},"id":1}"#;
|
2019-02-17 15:33:25 -08:00
|
|
|
let expected: Response = serde_json::from_str(&expected).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-02-17 15:33:25 -08:00
|
|
|
let result: Response = serde_json::from_str(&res.unwrap()).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
assert_eq!(expected, result);
|
|
|
|
}
|
2019-05-06 07:31:50 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
2020-05-06 23:23:06 -07:00
|
|
|
fn test_account_commitment_not_fulfilled() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair: alice,
|
|
|
|
..
|
2019-11-08 20:56:57 -08:00
|
|
|
} = create_genesis_config(10_000);
|
|
|
|
let bank = Bank::new(&genesis_config);
|
2019-05-06 07:31:50 -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)));
|
2019-05-06 07:31:50 -07:00
|
|
|
let bob = Keypair::new();
|
|
|
|
|
2020-06-25 21:06:58 -07:00
|
|
|
let mut rpc = RpcSolPubSubImpl::default_with_bank_forks(bank_forks.clone());
|
2020-03-30 16:53:25 -07:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
|
|
|
let subscriptions = RpcSubscriptions::new(
|
|
|
|
&exit,
|
2020-05-06 23:23:06 -07:00
|
|
|
bank_forks.clone(),
|
2020-06-25 21:06:58 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
2020-09-28 19:43:05 -07:00
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
2020-03-30 16:53:25 -07:00
|
|
|
);
|
|
|
|
rpc.subscriptions = Arc::new(subscriptions);
|
2019-05-06 07:31:50 -07:00
|
|
|
let session = create_session();
|
2020-01-20 13:08:29 -08:00
|
|
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
2020-05-06 23:23:06 -07:00
|
|
|
rpc.account_subscribe(
|
|
|
|
session,
|
|
|
|
subscriber,
|
|
|
|
bob.pubkey().to_string(),
|
2020-07-23 12:38:28 -07:00
|
|
|
Some(RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::root()),
|
|
|
|
encoding: None,
|
2020-08-10 15:35:29 -07:00
|
|
|
data_slice: None,
|
2020-07-23 12:38:28 -07:00
|
|
|
}),
|
2020-05-06 23:23:06 -07:00
|
|
|
);
|
2019-05-06 07:31:50 -07:00
|
|
|
|
2019-05-20 10:03:19 -07:00
|
|
|
let tx = system_transaction::transfer(&alice, &bob.pubkey(), 100, blockhash);
|
2019-05-06 07:31:50 -07:00
|
|
|
bank_forks
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
2020-05-06 23:23:06 -07:00
|
|
|
.get(1)
|
2019-05-06 07:31:50 -07:00
|
|
|
.unwrap()
|
|
|
|
.process_transaction(&tx)
|
|
|
|
.unwrap();
|
2020-05-18 11:49:01 -07:00
|
|
|
rpc.subscriptions
|
2020-07-17 10:54:49 -07:00
|
|
|
.notify_subscribers(CommitmentSlots::default());
|
2020-01-20 13:08:29 -08:00
|
|
|
// allow 200ms for notification thread to wake
|
|
|
|
std::thread::sleep(Duration::from_millis(200));
|
|
|
|
let _panic = robust_poll_or_panic(receiver);
|
2019-05-06 07:31:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-05-06 23:23:06 -07:00
|
|
|
fn test_account_commitment() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
|
|
|
genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair: alice,
|
|
|
|
..
|
2019-11-08 20:56:57 -08:00
|
|
|
} = create_genesis_config(10_000);
|
|
|
|
let bank = Bank::new(&genesis_config);
|
2019-05-06 07:31:50 -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)));
|
2020-05-06 23:23:06 -07:00
|
|
|
let bank0 = bank_forks.read().unwrap().get(0).unwrap().clone();
|
|
|
|
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 bob = Keypair::new();
|
|
|
|
|
2020-06-25 21:06:58 -07:00
|
|
|
let mut rpc = RpcSolPubSubImpl::default_with_bank_forks(bank_forks.clone());
|
2020-03-30 16:53:25 -07:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2020-06-25 21:06:58 -07:00
|
|
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests()));
|
2020-03-30 16:53:25 -07:00
|
|
|
|
2020-09-28 19:43:05 -07:00
|
|
|
let subscriptions = RpcSubscriptions::new(
|
|
|
|
&exit,
|
|
|
|
bank_forks.clone(),
|
|
|
|
block_commitment_cache,
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
|
|
|
);
|
2020-03-30 16:53:25 -07:00
|
|
|
rpc.subscriptions = Arc::new(subscriptions);
|
2019-05-06 07:31:50 -07:00
|
|
|
let session = create_session();
|
2020-01-20 13:08:29 -08:00
|
|
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("accountNotification");
|
2020-05-06 23:23:06 -07:00
|
|
|
rpc.account_subscribe(
|
|
|
|
session,
|
|
|
|
subscriber,
|
|
|
|
bob.pubkey().to_string(),
|
2020-07-23 12:38:28 -07:00
|
|
|
Some(RpcAccountInfoConfig {
|
|
|
|
commitment: Some(CommitmentConfig::root()),
|
|
|
|
encoding: None,
|
2020-08-10 15:35:29 -07:00
|
|
|
data_slice: None,
|
2020-07-23 12:38:28 -07:00
|
|
|
}),
|
2020-05-06 23:23:06 -07:00
|
|
|
);
|
2019-05-06 07:31:50 -07:00
|
|
|
|
2019-05-20 10:03:19 -07:00
|
|
|
let tx = system_transaction::transfer(&alice, &bob.pubkey(), 100, blockhash);
|
2019-05-06 07:31:50 -07:00
|
|
|
bank_forks
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
2020-05-06 23:23:06 -07:00
|
|
|
.get(1)
|
2019-05-06 07:31:50 -07:00
|
|
|
.unwrap()
|
|
|
|
.process_transaction(&tx)
|
|
|
|
.unwrap();
|
2020-07-17 10:54:49 -07:00
|
|
|
let mut commitment_slots = CommitmentSlots::default();
|
|
|
|
commitment_slots.slot = 1;
|
|
|
|
rpc.subscriptions.notify_subscribers(commitment_slots);
|
2020-05-18 11:49:01 -07:00
|
|
|
|
2020-07-17 10:54:49 -07:00
|
|
|
let commitment_slots = CommitmentSlots {
|
2020-07-17 08:24:51 -07:00
|
|
|
slot: 2,
|
|
|
|
root: 1,
|
2020-05-18 11:49:01 -07:00
|
|
|
highest_confirmed_slot: 1,
|
2020-07-17 08:24:51 -07:00
|
|
|
highest_confirmed_root: 1,
|
2020-05-18 11:49:01 -07:00
|
|
|
};
|
2020-07-17 10:54:49 -07:00
|
|
|
rpc.subscriptions.notify_subscribers(commitment_slots);
|
2019-05-06 07:31:50 -07:00
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "accountNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
2020-05-06 23:23:06 -07:00
|
|
|
"context": { "slot": 1 },
|
2020-03-23 05:34:42 -07:00
|
|
|
"value": {
|
|
|
|
"owner": system_program::id().to_string(),
|
|
|
|
"lamports": 100,
|
|
|
|
"data": "",
|
|
|
|
"executable": false,
|
2020-08-16 22:22:16 -07:00
|
|
|
"rentEpoch": 0,
|
2020-03-23 05:34:42 -07:00
|
|
|
},
|
2019-05-06 07:31:50 -07:00
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
2020-03-27 09:33:40 -07:00
|
|
|
let (response, _) = robust_poll_or_panic(receiver);
|
2020-01-20 13:08:29 -08:00
|
|
|
assert_eq!(serde_json::to_string(&expected).unwrap(), response);
|
2019-05-06 07:31:50 -07:00
|
|
|
}
|
2019-11-26 00:42:54 -08:00
|
|
|
|
|
|
|
#[test]
|
2020-04-16 22:02:55 -07:00
|
|
|
#[serial]
|
2019-11-26 00:42:54 -08:00
|
|
|
fn test_slot_subscribe() {
|
2020-05-06 23:23:06 -07:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
|
|
|
let bank = Bank::new(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2020-06-25 21:06:58 -07:00
|
|
|
let rpc = RpcSolPubSubImpl::default_with_bank_forks(bank_forks);
|
2019-11-26 00:42:54 -08:00
|
|
|
let session = create_session();
|
2020-01-20 13:08:29 -08:00
|
|
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("slotNotification");
|
2019-11-26 00:42:54 -08:00
|
|
|
rpc.slot_subscribe(session, subscriber);
|
|
|
|
|
|
|
|
rpc.subscriptions.notify_slot(0, 0, 0);
|
|
|
|
// Test slot confirmation notification
|
2020-03-27 09:33:40 -07:00
|
|
|
let (response, _) = robust_poll_or_panic(receiver);
|
2020-01-20 13:08:29 -08:00
|
|
|
let expected_res = SlotInfo {
|
|
|
|
parent: 0,
|
|
|
|
slot: 0,
|
|
|
|
root: 0,
|
|
|
|
};
|
|
|
|
let expected_res_str =
|
|
|
|
serde_json::to_string(&serde_json::to_value(expected_res).unwrap()).unwrap();
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-04-16 22:02:55 -07:00
|
|
|
#[serial]
|
2019-11-26 00:42:54 -08:00
|
|
|
fn test_slot_unsubscribe() {
|
2020-05-06 23:23:06 -07:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
|
|
|
let bank = Bank::new(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2020-06-25 21:06:58 -07:00
|
|
|
let rpc = RpcSolPubSubImpl::default_with_bank_forks(bank_forks);
|
2019-11-26 00:42:54 -08:00
|
|
|
let session = create_session();
|
2020-01-20 13:08:29 -08:00
|
|
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("slotNotification");
|
2019-11-26 00:42:54 -08:00
|
|
|
rpc.slot_subscribe(session, subscriber);
|
|
|
|
rpc.subscriptions.notify_slot(0, 0, 0);
|
2020-03-27 09:33:40 -07:00
|
|
|
let (response, _) = robust_poll_or_panic(receiver);
|
2020-01-20 13:08:29 -08:00
|
|
|
let expected_res = SlotInfo {
|
|
|
|
parent: 0,
|
|
|
|
slot: 0,
|
|
|
|
root: 0,
|
|
|
|
};
|
|
|
|
let expected_res_str =
|
|
|
|
serde_json::to_string(&serde_json::to_value(expected_res).unwrap()).unwrap();
|
|
|
|
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
|
|
|
|
|
|
|
let session = create_session();
|
|
|
|
assert!(rpc
|
|
|
|
.slot_unsubscribe(Some(session), SubscriptionId::Number(42))
|
|
|
|
.is_err());
|
|
|
|
|
|
|
|
let session = create_session();
|
|
|
|
assert!(rpc
|
|
|
|
.slot_unsubscribe(Some(session), SubscriptionId::Number(0))
|
|
|
|
.is_ok());
|
|
|
|
}
|
2020-05-17 14:01:08 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_vote_subscribe() {
|
2020-06-25 21:06:58 -07:00
|
|
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests()));
|
2020-05-17 14:01:08 -07:00
|
|
|
|
2020-07-23 18:50:42 -07:00
|
|
|
let validator_voting_keypairs: Vec<_> =
|
|
|
|
(0..10).map(|_| ValidatorVoteKeypairs::new_rand()).collect();
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config_with_vote_accounts(
|
|
|
|
10_000,
|
|
|
|
&validator_voting_keypairs,
|
|
|
|
vec![100; validator_voting_keypairs.len()],
|
|
|
|
);
|
2020-05-17 14:01:08 -07:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
|
|
|
let bank = Bank::new(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = BankForks::new(bank);
|
2020-05-17 14:01:08 -07:00
|
|
|
let bank = bank_forks.get(0).unwrap().clone();
|
|
|
|
let bank_forks = Arc::new(RwLock::new(bank_forks));
|
|
|
|
|
|
|
|
// Setup RPC
|
2020-06-25 21:06:58 -07:00
|
|
|
let mut rpc = RpcSolPubSubImpl::default_with_bank_forks(bank_forks.clone());
|
2020-05-17 14:01:08 -07:00
|
|
|
let session = create_session();
|
|
|
|
let (subscriber, _id_receiver, receiver) = Subscriber::new_test("voteNotification");
|
|
|
|
|
|
|
|
// Setup Subscriptions
|
2020-09-28 19:43:05 -07:00
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
2020-11-14 09:29:51 -08:00
|
|
|
let subscriptions = RpcSubscriptions::new_with_vote_subscription(
|
2020-09-28 19:43:05 -07:00
|
|
|
&exit,
|
|
|
|
bank_forks,
|
|
|
|
block_commitment_cache,
|
|
|
|
optimistically_confirmed_bank,
|
2020-11-14 09:29:51 -08:00
|
|
|
true,
|
2020-09-28 19:43:05 -07:00
|
|
|
);
|
2020-05-17 14:01:08 -07:00
|
|
|
rpc.subscriptions = Arc::new(subscriptions);
|
|
|
|
rpc.vote_subscribe(session, subscriber);
|
|
|
|
|
|
|
|
// Create some voters at genesis
|
|
|
|
let vote_tracker = VoteTracker::new(&bank);
|
|
|
|
let (votes_sender, votes_receiver) = unbounded();
|
|
|
|
let (vote_tracker, validator_voting_keypairs) =
|
|
|
|
(Arc::new(vote_tracker), validator_voting_keypairs);
|
|
|
|
|
|
|
|
let vote_slots = vec![1, 2];
|
|
|
|
validator_voting_keypairs.iter().for_each(|keypairs| {
|
|
|
|
let node_keypair = &keypairs.node_keypair;
|
|
|
|
let vote_keypair = &keypairs.vote_keypair;
|
|
|
|
let vote_tx = vote_transaction::new_vote_transaction(
|
|
|
|
vote_slots.clone(),
|
|
|
|
Hash::default(),
|
|
|
|
Hash::default(),
|
|
|
|
node_keypair,
|
|
|
|
vote_keypair,
|
|
|
|
vote_keypair,
|
2020-07-28 02:33:27 -07:00
|
|
|
None,
|
2020-05-17 14:01:08 -07:00
|
|
|
);
|
|
|
|
votes_sender.send(vec![vote_tx]).unwrap();
|
|
|
|
});
|
|
|
|
|
|
|
|
// Process votes and check they were notified.
|
2020-07-09 22:52:54 -07:00
|
|
|
let (s, _r) = unbounded();
|
2020-07-20 17:29:07 -07:00
|
|
|
let (_replay_votes_sender, replay_votes_receiver) = unbounded();
|
2020-05-17 14:01:08 -07:00
|
|
|
ClusterInfoVoteListener::get_and_process_votes_for_tests(
|
|
|
|
&votes_receiver,
|
|
|
|
&vote_tracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
&bank,
|
2020-06-08 17:38:14 -07:00
|
|
|
&rpc.subscriptions,
|
2020-07-09 22:52:54 -07:00
|
|
|
&s,
|
2020-07-20 17:29:07 -07:00
|
|
|
&replay_votes_receiver,
|
2020-05-17 14:01:08 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let (response, _) = robust_poll_or_panic(receiver);
|
|
|
|
assert_eq!(
|
|
|
|
response,
|
|
|
|
r#"{"jsonrpc":"2.0","method":"voteNotification","params":{"result":{"hash":"11111111111111111111111111111111","slots":[1,2],"timestamp":null},"subscription":0}}"#
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_vote_unsubscribe() {
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
|
|
|
let bank = Bank::new(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2020-06-25 21:06:58 -07:00
|
|
|
let rpc = RpcSolPubSubImpl::default_with_bank_forks(bank_forks);
|
2020-05-17 14:01:08 -07:00
|
|
|
let session = create_session();
|
|
|
|
let (subscriber, _id_receiver, _) = Subscriber::new_test("voteNotification");
|
|
|
|
rpc.vote_subscribe(session, subscriber);
|
|
|
|
|
|
|
|
let session = create_session();
|
|
|
|
assert!(rpc
|
|
|
|
.vote_unsubscribe(Some(session), SubscriptionId::Number(42))
|
|
|
|
.is_err());
|
|
|
|
|
|
|
|
let session = create_session();
|
|
|
|
assert!(rpc
|
|
|
|
.vote_unsubscribe(Some(session), SubscriptionId::Number(0))
|
|
|
|
.is_ok());
|
|
|
|
}
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|