2018-10-10 13:51:43 -07:00
|
|
|
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
|
|
|
|
2021-05-18 23:54:28 -07:00
|
|
|
use {
|
2021-09-17 12:40:14 -07:00
|
|
|
crate::{
|
2021-12-17 15:03:09 -08:00
|
|
|
rpc::check_is_at_least_confirmed,
|
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, SubscriptionParams,
|
|
|
|
SubscriptionToken,
|
2021-09-17 12:40:14 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
dashmap::DashMap,
|
2021-05-18 23:54:28 -07:00
|
|
|
jsonrpc_core::{Error, ErrorCode, Result},
|
|
|
|
jsonrpc_derive::rpc,
|
2021-09-17 12:40:14 -07:00
|
|
|
jsonrpc_pubsub::{typed::Subscriber, SubscriptionId as PubSubSubscriptionId},
|
|
|
|
solana_account_decoder::{UiAccount, UiAccountEncoding},
|
2022-08-24 09:47:02 -07:00
|
|
|
solana_rpc_client_api::{
|
|
|
|
config::{
|
2021-12-17 15:03:09 -08:00
|
|
|
RpcAccountInfoConfig, RpcBlockSubscribeConfig, RpcBlockSubscribeFilter,
|
|
|
|
RpcProgramAccountsConfig, RpcSignatureSubscribeConfig, RpcTransactionLogsConfig,
|
|
|
|
RpcTransactionLogsFilter,
|
2021-05-18 23:54:28 -07:00
|
|
|
},
|
2022-08-24 09:47:02 -07:00
|
|
|
response::{
|
2021-12-17 15:03:09 -08:00
|
|
|
Response as RpcResponse, RpcBlockUpdate, RpcKeyedAccount, RpcLogsResponse,
|
2022-07-07 19:55:18 -07:00
|
|
|
RpcSignatureResult, RpcVersionInfo, RpcVote, SlotInfo, SlotUpdate,
|
2021-05-18 23:54:28 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature},
|
2021-12-17 15:03:09 -08:00
|
|
|
solana_transaction_status::UiTransactionEncoding,
|
2021-09-17 12:40:14 -07:00
|
|
|
std::{str::FromStr, sync::Arc},
|
2020-04-22 11:22:09 -07:00
|
|
|
};
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
// We have to keep both of the following traits to not break backwards compatibility.
|
|
|
|
// `RpcSolPubSubInternal` is actually used by the current PubSub API implementation.
|
|
|
|
// `RpcSolPubSub` and the corresponding `gen_client` module are preserved
|
|
|
|
// so the clients reliant on `gen_client::Client` do not break after this implementation is released.
|
|
|
|
//
|
|
|
|
// There are no compile-time checks that ensure coherence between traits
|
|
|
|
// so extra attention is required when adding a new method to the API.
|
2020-12-11 17:57:40 -08:00
|
|
|
|
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"
|
|
|
|
)]
|
2021-09-17 12:40:14 -07:00
|
|
|
fn account_unsubscribe(
|
|
|
|
&self,
|
|
|
|
meta: Option<Self::Metadata>,
|
|
|
|
id: PubSubSubscriptionId,
|
|
|
|
) -> 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"
|
|
|
|
)]
|
2021-09-17 12:40:14 -07:00
|
|
|
fn program_unsubscribe(
|
|
|
|
&self,
|
|
|
|
meta: Option<Self::Metadata>,
|
|
|
|
id: PubSubSubscriptionId,
|
|
|
|
) -> 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"
|
|
|
|
)]
|
2021-09-17 12:40:14 -07:00
|
|
|
fn logs_unsubscribe(
|
|
|
|
&self,
|
|
|
|
meta: Option<Self::Metadata>,
|
|
|
|
id: PubSubSubscriptionId,
|
|
|
|
) -> Result<bool>;
|
2020-11-20 13:52:58 -08:00
|
|
|
|
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>,
|
2021-09-17 12:40:14 -07:00
|
|
|
id: PubSubSubscriptionId,
|
2020-01-15 10:52:02 -08:00
|
|
|
) -> 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"
|
|
|
|
)]
|
2021-09-17 12:40:14 -07:00
|
|
|
fn slot_unsubscribe(
|
|
|
|
&self,
|
|
|
|
meta: Option<Self::Metadata>,
|
|
|
|
id: PubSubSubscriptionId,
|
|
|
|
) -> Result<bool>;
|
2020-03-27 09:33:40 -07:00
|
|
|
|
2021-02-28 23:29:11 -08:00
|
|
|
// Get series of updates for all slots
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "slotsUpdatesNotification",
|
|
|
|
subscribe,
|
|
|
|
name = "slotsUpdatesSubscribe"
|
|
|
|
)]
|
|
|
|
fn slots_updates_subscribe(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
subscriber: Subscriber<Arc<SlotUpdate>>,
|
|
|
|
);
|
|
|
|
|
|
|
|
// Unsubscribe from slots updates notification subscription.
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "slotsUpdatesNotification",
|
|
|
|
unsubscribe,
|
|
|
|
name = "slotsUpdatesUnsubscribe"
|
|
|
|
)]
|
|
|
|
fn slots_updates_unsubscribe(
|
|
|
|
&self,
|
|
|
|
meta: Option<Self::Metadata>,
|
2021-09-17 12:40:14 -07:00
|
|
|
id: PubSubSubscriptionId,
|
2021-02-28 23:29:11 -08:00
|
|
|
) -> Result<bool>;
|
|
|
|
|
2021-12-17 15:03:09 -08:00
|
|
|
// Subscribe to block data and content
|
|
|
|
#[pubsub(subscription = "blockNotification", subscribe, name = "blockSubscribe")]
|
|
|
|
fn block_subscribe(
|
|
|
|
&self,
|
|
|
|
meta: Self::Metadata,
|
|
|
|
subscriber: Subscriber<Arc<RpcBlockUpdate>>,
|
|
|
|
filter: RpcBlockSubscribeFilter,
|
|
|
|
config: Option<RpcBlockSubscribeConfig>,
|
|
|
|
);
|
|
|
|
|
|
|
|
// Unsubscribe from block notification subscription.
|
|
|
|
#[pubsub(
|
|
|
|
subscription = "blockNotification",
|
|
|
|
unsubscribe,
|
|
|
|
name = "blockUnsubscribe"
|
|
|
|
)]
|
|
|
|
fn block_unsubscribe(
|
|
|
|
&self,
|
|
|
|
meta: Option<Self::Metadata>,
|
|
|
|
id: PubSubSubscriptionId,
|
|
|
|
) -> Result<bool>;
|
|
|
|
|
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"
|
|
|
|
)]
|
2021-09-17 12:40:14 -07:00
|
|
|
fn vote_unsubscribe(
|
|
|
|
&self,
|
|
|
|
meta: Option<Self::Metadata>,
|
|
|
|
id: PubSubSubscriptionId,
|
|
|
|
) -> Result<bool>;
|
2020-05-17 14:01:08 -07:00
|
|
|
|
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"
|
|
|
|
)]
|
2021-09-17 12:40:14 -07:00
|
|
|
fn root_unsubscribe(
|
|
|
|
&self,
|
|
|
|
meta: Option<Self::Metadata>,
|
|
|
|
id: PubSubSubscriptionId,
|
|
|
|
) -> Result<bool>;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub use internal::RpcSolPubSubInternal;
|
|
|
|
|
|
|
|
// We have to use a separate module so the code generated by different `rpc` macro invocations do not interfere with each other.
|
|
|
|
mod internal {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[rpc]
|
|
|
|
pub trait RpcSolPubSubInternal {
|
|
|
|
// Get notification every time account data is changed
|
|
|
|
// Accepts pubkey parameter as base-58 encoded string
|
|
|
|
#[rpc(name = "accountSubscribe")]
|
|
|
|
fn account_subscribe(
|
|
|
|
&self,
|
|
|
|
pubkey_str: String,
|
|
|
|
config: Option<RpcAccountInfoConfig>,
|
|
|
|
) -> Result<SubscriptionId>;
|
|
|
|
|
|
|
|
// Unsubscribe from account notification subscription.
|
|
|
|
#[rpc(name = "accountUnsubscribe")]
|
|
|
|
fn account_unsubscribe(&self, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
|
|
|
// Get notification every time account data owned by a particular program is changed
|
|
|
|
// Accepts pubkey parameter as base-58 encoded string
|
|
|
|
#[rpc(name = "programSubscribe")]
|
|
|
|
fn program_subscribe(
|
|
|
|
&self,
|
|
|
|
pubkey_str: String,
|
|
|
|
config: Option<RpcProgramAccountsConfig>,
|
|
|
|
) -> Result<SubscriptionId>;
|
|
|
|
|
|
|
|
// Unsubscribe from account notification subscription.
|
|
|
|
#[rpc(name = "programUnsubscribe")]
|
|
|
|
fn program_unsubscribe(&self, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
|
|
|
// Get logs for all transactions that reference the specified address
|
|
|
|
#[rpc(name = "logsSubscribe")]
|
|
|
|
fn logs_subscribe(
|
|
|
|
&self,
|
|
|
|
filter: RpcTransactionLogsFilter,
|
|
|
|
config: Option<RpcTransactionLogsConfig>,
|
|
|
|
) -> Result<SubscriptionId>;
|
|
|
|
|
|
|
|
// Unsubscribe from logs notification subscription.
|
|
|
|
#[rpc(name = "logsUnsubscribe")]
|
|
|
|
fn logs_unsubscribe(&self, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
|
|
|
// Get notification when signature is verified
|
|
|
|
// Accepts signature parameter as base-58 encoded string
|
|
|
|
#[rpc(name = "signatureSubscribe")]
|
|
|
|
fn signature_subscribe(
|
|
|
|
&self,
|
|
|
|
signature_str: String,
|
|
|
|
config: Option<RpcSignatureSubscribeConfig>,
|
|
|
|
) -> Result<SubscriptionId>;
|
|
|
|
|
|
|
|
// Unsubscribe from signature notification subscription.
|
|
|
|
#[rpc(name = "signatureUnsubscribe")]
|
|
|
|
fn signature_unsubscribe(&self, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
|
|
|
// Get notification when slot is encountered
|
|
|
|
#[rpc(name = "slotSubscribe")]
|
|
|
|
fn slot_subscribe(&self) -> Result<SubscriptionId>;
|
|
|
|
|
|
|
|
// Unsubscribe from slot notification subscription.
|
|
|
|
#[rpc(name = "slotUnsubscribe")]
|
|
|
|
fn slot_unsubscribe(&self, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
|
|
|
// Get series of updates for all slots
|
|
|
|
#[rpc(name = "slotsUpdatesSubscribe")]
|
|
|
|
fn slots_updates_subscribe(&self) -> Result<SubscriptionId>;
|
|
|
|
|
|
|
|
// Unsubscribe from slots updates notification subscription.
|
|
|
|
#[rpc(name = "slotsUpdatesUnsubscribe")]
|
|
|
|
fn slots_updates_unsubscribe(&self, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
2021-12-17 15:03:09 -08:00
|
|
|
// Subscribe to block data and content
|
|
|
|
#[rpc(name = "blockSubscribe")]
|
|
|
|
fn block_subscribe(
|
|
|
|
&self,
|
|
|
|
filter: RpcBlockSubscribeFilter,
|
|
|
|
config: Option<RpcBlockSubscribeConfig>,
|
|
|
|
) -> Result<SubscriptionId>;
|
|
|
|
|
|
|
|
// Unsubscribe from block notification subscription.
|
|
|
|
#[rpc(name = "blockUnsubscribe")]
|
|
|
|
fn block_unsubscribe(&self, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
// Get notification when vote is encountered
|
|
|
|
#[rpc(name = "voteSubscribe")]
|
|
|
|
fn vote_subscribe(&self) -> Result<SubscriptionId>;
|
|
|
|
|
|
|
|
// Unsubscribe from vote notification subscription.
|
|
|
|
#[rpc(name = "voteUnsubscribe")]
|
|
|
|
fn vote_unsubscribe(&self, id: SubscriptionId) -> Result<bool>;
|
|
|
|
|
|
|
|
// Get notification when a new root is set
|
|
|
|
#[rpc(name = "rootSubscribe")]
|
|
|
|
fn root_subscribe(&self) -> Result<SubscriptionId>;
|
|
|
|
|
|
|
|
// Unsubscribe from slot notification subscription.
|
|
|
|
#[rpc(name = "rootUnsubscribe")]
|
|
|
|
fn root_unsubscribe(&self, id: SubscriptionId) -> Result<bool>;
|
2022-07-07 19:55:18 -07:00
|
|
|
|
|
|
|
// Get the current solana version running on the node
|
|
|
|
#[rpc(name = "getVersion")]
|
|
|
|
fn get_version(&self) -> Result<RpcVersionInfo>;
|
2021-09-17 12:40:14 -07:00
|
|
|
}
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
|
2019-02-17 09:09:46 -08:00
|
|
|
pub struct RpcSolPubSubImpl {
|
2021-09-17 12:40:14 -07:00
|
|
|
config: PubSubConfig,
|
|
|
|
subscription_control: SubscriptionControl,
|
|
|
|
current_subscriptions: Arc<DashMap<SubscriptionId, SubscriptionToken>>,
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
2018-10-12 11:04:14 -07:00
|
|
|
|
|
|
|
impl RpcSolPubSubImpl {
|
2021-09-17 12:40:14 -07:00
|
|
|
pub fn new(
|
|
|
|
config: PubSubConfig,
|
|
|
|
subscription_control: SubscriptionControl,
|
|
|
|
current_subscriptions: Arc<DashMap<SubscriptionId, SubscriptionToken>>,
|
|
|
|
) -> Self {
|
2021-06-16 21:28:23 -07:00
|
|
|
Self {
|
2021-09-17 12:40:14 -07:00
|
|
|
config,
|
|
|
|
subscription_control,
|
|
|
|
current_subscriptions,
|
2021-06-16 21:28:23 -07:00
|
|
|
}
|
2019-02-17 12:51:12 -08:00
|
|
|
}
|
2019-02-17 12:24:36 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn subscribe(&self, params: SubscriptionParams) -> Result<SubscriptionId> {
|
|
|
|
let token = self
|
|
|
|
.subscription_control
|
|
|
|
.subscribe(params)
|
|
|
|
.map_err(|_| Error {
|
2020-12-11 17:57:40 -08:00
|
|
|
code: ErrorCode::InternalError,
|
|
|
|
message: "Internal Error: Subscription refused. Node subscription limit reached"
|
|
|
|
.into(),
|
|
|
|
data: None,
|
2021-09-17 12:40:14 -07:00
|
|
|
})?;
|
|
|
|
let id = token.id();
|
|
|
|
self.current_subscriptions.insert(id, token);
|
|
|
|
Ok(id)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
if self.current_subscriptions.remove(&id).is_some() {
|
|
|
|
Ok(true)
|
2020-12-11 17:57:40 -08:00
|
|
|
} else {
|
2021-09-17 12:40:14 -07:00
|
|
|
Err(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid subscription id.".into(),
|
|
|
|
data: None,
|
|
|
|
})
|
2020-12-11 17:57:40 -08:00
|
|
|
}
|
|
|
|
}
|
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,
|
2022-12-06 06:30:06 -08:00
|
|
|
message: format!("Invalid Request: Invalid {thing} provided"),
|
2019-05-20 22:21:13 -07:00
|
|
|
data: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
impl RpcSolPubSubInternal for RpcSolPubSubImpl {
|
2019-02-17 12:24:36 -08:00
|
|
|
fn account_subscribe(
|
2019-02-17 09:09:46 -08:00
|
|
|
&self,
|
|
|
|
pubkey_str: String,
|
2020-07-23 12:38:28 -07:00
|
|
|
config: Option<RpcAccountInfoConfig>,
|
2021-09-17 12:40:14 -07:00
|
|
|
) -> Result<SubscriptionId> {
|
2022-05-16 23:46:02 -07:00
|
|
|
let RpcAccountInfoConfig {
|
|
|
|
encoding,
|
|
|
|
data_slice,
|
|
|
|
commitment,
|
|
|
|
min_context_slot: _, // ignored
|
|
|
|
} = config.unwrap_or_default();
|
2021-09-17 12:40:14 -07:00
|
|
|
let params = AccountSubscriptionParams {
|
|
|
|
pubkey: param::<Pubkey>(&pubkey_str, "pubkey")?,
|
2022-05-16 23:46:02 -07:00
|
|
|
commitment: commitment.unwrap_or_default(),
|
|
|
|
data_slice,
|
|
|
|
encoding: encoding.unwrap_or(UiAccountEncoding::Binary),
|
2021-09-17 12:40:14 -07:00
|
|
|
};
|
|
|
|
self.subscribe(SubscriptionParams::Account(params))
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn account_unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
self.unsubscribe(id)
|
2019-02-17 12:24:36 -08:00
|
|
|
}
|
|
|
|
|
2019-03-06 14:31:58 -08:00
|
|
|
fn program_subscribe(
|
|
|
|
&self,
|
|
|
|
pubkey_str: String,
|
2020-07-23 12:38:28 -07:00
|
|
|
config: Option<RpcProgramAccountsConfig>,
|
2021-09-17 12:40:14 -07:00
|
|
|
) -> Result<SubscriptionId> {
|
|
|
|
let config = config.unwrap_or_default();
|
|
|
|
let params = ProgramSubscriptionParams {
|
|
|
|
pubkey: param::<Pubkey>(&pubkey_str, "pubkey")?,
|
|
|
|
filters: config.filters.unwrap_or_default(),
|
|
|
|
encoding: config
|
|
|
|
.account_config
|
|
|
|
.encoding
|
|
|
|
.unwrap_or(UiAccountEncoding::Binary),
|
|
|
|
data_slice: config.account_config.data_slice,
|
|
|
|
commitment: config.account_config.commitment.unwrap_or_default(),
|
|
|
|
with_context: config.with_context.unwrap_or_default(),
|
|
|
|
};
|
|
|
|
self.subscribe(SubscriptionParams::Program(params))
|
2019-03-06 14:31:58 -08:00
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn program_unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
self.unsubscribe(id)
|
2019-03-06 14:31:58 -08:00
|
|
|
}
|
|
|
|
|
2020-11-20 13:52:58 -08:00
|
|
|
fn logs_subscribe(
|
|
|
|
&self,
|
|
|
|
filter: RpcTransactionLogsFilter,
|
2020-12-07 11:00:52 -08:00
|
|
|
config: Option<RpcTransactionLogsConfig>,
|
2021-09-17 12:40:14 -07:00
|
|
|
) -> Result<SubscriptionId> {
|
|
|
|
let params = LogsSubscriptionParams {
|
|
|
|
kind: match filter {
|
|
|
|
RpcTransactionLogsFilter::All => LogsSubscriptionKind::All,
|
|
|
|
RpcTransactionLogsFilter::AllWithVotes => LogsSubscriptionKind::AllWithVotes,
|
|
|
|
RpcTransactionLogsFilter::Mentions(keys) => {
|
|
|
|
if keys.len() != 1 {
|
|
|
|
return Err(Error {
|
|
|
|
code: ErrorCode::InvalidParams,
|
|
|
|
message: "Invalid Request: Only 1 address supported".into(),
|
|
|
|
data: None,
|
|
|
|
});
|
2020-11-20 13:52:58 -08:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
LogsSubscriptionKind::Single(param::<Pubkey>(&keys[0], "mentions")?)
|
2020-11-20 13:52:58 -08:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
},
|
|
|
|
commitment: config.and_then(|c| c.commitment).unwrap_or_default(),
|
2020-11-20 13:52:58 -08:00
|
|
|
};
|
2021-09-17 12:40:14 -07:00
|
|
|
self.subscribe(SubscriptionParams::Logs(params))
|
2020-11-20 13:52:58 -08:00
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn logs_unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
self.unsubscribe(id)
|
2020-11-20 13:52:58 -08:00
|
|
|
}
|
|
|
|
|
2019-02-17 12:24:36 -08:00
|
|
|
fn signature_subscribe(
|
2018-10-10 13:51:43 -07:00
|
|
|
&self,
|
|
|
|
signature_str: String,
|
2021-09-17 12:40:14 -07:00
|
|
|
config: Option<RpcSignatureSubscribeConfig>,
|
|
|
|
) -> Result<SubscriptionId> {
|
|
|
|
let config = config.unwrap_or_default();
|
|
|
|
let params = SignatureSubscriptionParams {
|
|
|
|
signature: param::<Signature>(&signature_str, "signature")?,
|
|
|
|
commitment: config.commitment.unwrap_or_default(),
|
|
|
|
enable_received_notification: config.enable_received_notification.unwrap_or_default(),
|
|
|
|
};
|
|
|
|
self.subscribe(SubscriptionParams::Signature(params))
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn signature_unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
self.unsubscribe(id)
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
2019-11-26 00:42:54 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn slot_subscribe(&self) -> Result<SubscriptionId> {
|
|
|
|
self.subscribe(SubscriptionParams::Slot)
|
2019-11-26 00:42:54 -08:00
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn slot_unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
self.unsubscribe(id)
|
2019-11-26 00:42:54 -08:00
|
|
|
}
|
2020-03-27 09:33:40 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn slots_updates_subscribe(&self) -> Result<SubscriptionId> {
|
|
|
|
self.subscribe(SubscriptionParams::SlotsUpdates)
|
2021-02-28 23:29:11 -08:00
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn slots_updates_unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
self.unsubscribe(id)
|
2021-02-28 23:29:11 -08:00
|
|
|
}
|
|
|
|
|
2021-12-17 15:03:09 -08:00
|
|
|
fn block_subscribe(
|
|
|
|
&self,
|
|
|
|
filter: RpcBlockSubscribeFilter,
|
|
|
|
config: Option<RpcBlockSubscribeConfig>,
|
|
|
|
) -> Result<SubscriptionId> {
|
|
|
|
if !self.config.enable_block_subscription {
|
|
|
|
return Err(Error::new(jsonrpc_core::ErrorCode::MethodNotFound));
|
|
|
|
}
|
|
|
|
let config = config.unwrap_or_default();
|
|
|
|
let commitment = config.commitment.unwrap_or_default();
|
|
|
|
check_is_at_least_confirmed(commitment)?;
|
|
|
|
let params = BlockSubscriptionParams {
|
|
|
|
commitment: config.commitment.unwrap_or_default(),
|
|
|
|
encoding: config.encoding.unwrap_or(UiTransactionEncoding::Base64),
|
|
|
|
kind: match filter {
|
|
|
|
RpcBlockSubscribeFilter::All => BlockSubscriptionKind::All,
|
|
|
|
RpcBlockSubscribeFilter::MentionsAccountOrProgram(key) => {
|
|
|
|
BlockSubscriptionKind::MentionsAccountOrProgram(param::<Pubkey>(
|
|
|
|
&key,
|
|
|
|
"mentions_account_or_program",
|
|
|
|
)?)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
transaction_details: config.transaction_details.unwrap_or_default(),
|
|
|
|
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
|
|
|
};
|
|
|
|
self.subscribe(SubscriptionParams::Block(params))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn block_unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
if !self.config.enable_block_subscription {
|
|
|
|
return Err(Error::new(jsonrpc_core::ErrorCode::MethodNotFound));
|
|
|
|
}
|
|
|
|
self.unsubscribe(id)
|
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn vote_subscribe(&self) -> Result<SubscriptionId> {
|
|
|
|
if !self.config.enable_vote_subscription {
|
|
|
|
return Err(Error::new(jsonrpc_core::ErrorCode::MethodNotFound));
|
2020-12-11 17:57:40 -08:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
self.subscribe(SubscriptionParams::Vote)
|
2020-05-17 14:01:08 -07:00
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn vote_unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
if !self.config.enable_vote_subscription {
|
|
|
|
return Err(Error::new(jsonrpc_core::ErrorCode::MethodNotFound));
|
2020-05-17 14:01:08 -07:00
|
|
|
}
|
2021-09-17 12:40:14 -07:00
|
|
|
self.unsubscribe(id)
|
2020-05-17 14:01:08 -07:00
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn root_subscribe(&self) -> Result<SubscriptionId> {
|
|
|
|
self.subscribe(SubscriptionParams::Root)
|
2020-03-27 09:33:40 -07:00
|
|
|
}
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
fn root_unsubscribe(&self, id: SubscriptionId) -> Result<bool> {
|
|
|
|
self.unsubscribe(id)
|
2020-03-27 09:33:40 -07:00
|
|
|
}
|
2022-07-07 19:55:18 -07:00
|
|
|
|
|
|
|
fn get_version(&self) -> Result<RpcVersionInfo> {
|
|
|
|
let version = solana_version::Version::default();
|
|
|
|
Ok(RpcVersionInfo {
|
|
|
|
solana_core: version.to_string(),
|
|
|
|
feature_set: Some(version.feature_set),
|
|
|
|
})
|
|
|
|
}
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-05-18 23:54:28 -07:00
|
|
|
use {
|
2021-09-17 12:40:14 -07:00
|
|
|
super::{RpcSolPubSubInternal, *},
|
2021-05-18 23:54:28 -07:00
|
|
|
crate::{
|
2021-09-17 12:40:14 -07:00
|
|
|
optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank, rpc_pubsub_service,
|
|
|
|
rpc_subscriptions::RpcSubscriptions,
|
2021-05-18 23:54:28 -07:00
|
|
|
},
|
2021-09-17 12:40:14 -07:00
|
|
|
jsonrpc_core::{IoHandler, Response},
|
2021-05-18 23:54:28 -07:00
|
|
|
serial_test::serial,
|
|
|
|
solana_account_decoder::{parse_account_data::parse_account_data, UiAccountEncoding},
|
2022-08-24 09:47:02 -07:00
|
|
|
solana_rpc_client_api::response::{
|
2021-09-17 12:40:14 -07:00
|
|
|
ProcessedSignatureResult, ReceivedSignatureResult, RpcSignatureResult, SlotInfo,
|
|
|
|
},
|
2021-05-18 23:54:28 -07:00
|
|
|
solana_runtime::{
|
|
|
|
bank::Bank,
|
|
|
|
bank_forks::BankForks,
|
|
|
|
commitment::{BlockCommitmentCache, CommitmentSlots},
|
|
|
|
genesis_utils::{
|
2022-05-04 03:17:29 -07:00
|
|
|
activate_all_features, create_genesis_config,
|
|
|
|
create_genesis_config_with_vote_accounts, GenesisConfigInfo, ValidatorVoteKeypairs,
|
2021-05-18 23:54:28 -07:00
|
|
|
},
|
2022-01-19 18:39:21 -08:00
|
|
|
vote_transaction::VoteTransaction,
|
2021-05-18 23:54:28 -07:00
|
|
|
},
|
|
|
|
solana_sdk::{
|
|
|
|
account::ReadableAccount,
|
2021-09-17 12:40:14 -07:00
|
|
|
clock::Slot,
|
2021-05-18 23:54:28 -07:00
|
|
|
commitment_config::CommitmentConfig,
|
|
|
|
hash::Hash,
|
|
|
|
message::Message,
|
|
|
|
pubkey::Pubkey,
|
2022-05-04 03:17:29 -07:00
|
|
|
rent::Rent,
|
2021-05-18 23:54:28 -07:00
|
|
|
signature::{Keypair, Signer},
|
2021-06-15 09:04:00 -07:00
|
|
|
stake::{
|
|
|
|
self, instruction as stake_instruction,
|
2022-04-25 15:35:05 -07:00
|
|
|
state::{Authorized, Lockup, StakeAuthorize, StakeState},
|
2021-06-15 09:04:00 -07:00
|
|
|
},
|
2021-05-18 23:54:28 -07:00
|
|
|
system_instruction, system_program, system_transaction,
|
|
|
|
transaction::{self, Transaction},
|
|
|
|
},
|
2021-06-15 09:04:00 -07:00
|
|
|
solana_stake_program::stake_state,
|
2022-01-19 18:39:21 -08:00
|
|
|
solana_vote_program::vote_state::Vote,
|
2021-05-18 23:54:28 -07:00
|
|
|
std::{
|
2021-12-17 15:03:09 -08:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, AtomicU64},
|
|
|
|
RwLock,
|
|
|
|
},
|
2021-05-18 23:54:28 -07:00
|
|
|
thread::sleep,
|
|
|
|
time::Duration,
|
2020-06-25 21:06:58 -07:00
|
|
|
},
|
2020-03-30 16:53:25 -07:00
|
|
|
};
|
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-12-13 17:26:34 -08:00
|
|
|
let commitment_slots = CommitmentSlots {
|
|
|
|
slot: current_slot,
|
|
|
|
..CommitmentSlots::default()
|
|
|
|
};
|
2020-07-17 10:54:49 -07:00
|
|
|
subscriptions.notify_subscribers(commitment_slots);
|
2019-05-06 07:31:50 -07:00
|
|
|
Ok(())
|
2019-02-17 15:33:25 -08:00
|
|
|
}
|
|
|
|
|
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();
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&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)));
|
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 rpc_subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
|
|
|
&Arc::new(AtomicBool::new(false)),
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2021-09-17 12:40:14 -07:00
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests())),
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
|
|
|
));
|
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
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
|
2020-11-23 15:00:03 -08:00
|
|
|
rpc.signature_subscribe(
|
|
|
|
tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
2021-01-26 11:23:07 -08:00
|
|
|
commitment: Some(CommitmentConfig::finalized()),
|
2020-11-23 15:00:03 -08:00
|
|
|
..RpcSignatureSubscribeConfig::default()
|
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2021-09-17 12:40:14 -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
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
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
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
2020-09-01 22:06:06 -07:00
|
|
|
|
|
|
|
// Test "received"
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
|
2020-09-01 22:06:06 -07:00
|
|
|
rpc.signature_subscribe(
|
|
|
|
tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
2021-01-26 11:23:07 -08:00
|
|
|
commitment: Some(CommitmentConfig::finalized()),
|
2020-09-01 22:06:06 -07:00
|
|
|
enable_received_notification: Some(true),
|
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2020-09-01 22:06:06 -07:00
|
|
|
let received_slot = 1;
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc_subscriptions.notify_signatures_received((received_slot, vec![tx.signatures[0]]));
|
2021-02-24 00:59:22 -08:00
|
|
|
|
2020-09-01 22:06:06 -07:00
|
|
|
// Test signature confirmation notification
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
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,
|
|
|
|
}
|
|
|
|
});
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
2021-02-24 00:59:22 -08:00
|
|
|
|
|
|
|
// Test "received" for gossip subscription
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
|
2021-02-24 00:59:22 -08:00
|
|
|
rpc.signature_subscribe(
|
|
|
|
tx.signatures[0].to_string(),
|
|
|
|
Some(RpcSignatureSubscribeConfig {
|
|
|
|
commitment: Some(CommitmentConfig::confirmed()),
|
|
|
|
enable_received_notification: Some(true),
|
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2021-02-24 00:59:22 -08:00
|
|
|
let received_slot = 2;
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc_subscriptions.notify_signatures_received((received_slot, vec![tx.signatures[0]]));
|
2021-02-24 00:59:22 -08:00
|
|
|
|
|
|
|
// Test signature confirmation notification
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2021-02-24 00:59:22 -08:00
|
|
|
let expected_res =
|
|
|
|
RpcSignatureResult::ReceivedSignature(ReceivedSignatureResult::ReceivedSignature);
|
|
|
|
let expected = json!({
|
|
|
|
"jsonrpc": "2.0",
|
|
|
|
"method": "signatureNotification",
|
|
|
|
"params": {
|
|
|
|
"result": {
|
|
|
|
"context": { "slot": received_slot },
|
|
|
|
"value": expected_res,
|
|
|
|
},
|
|
|
|
"subscription": 2,
|
|
|
|
}
|
|
|
|
});
|
2021-09-17 12:40:14 -07:00
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
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();
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&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
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let mut io = IoHandler::<()>::default();
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
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 (rpc, _receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
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":["{}"]}}"#,
|
2021-10-22 21:25:54 -07:00
|
|
|
tx.signatures[0]
|
2018-10-10 13:51:43 -07:00
|
|
|
);
|
2021-09-17 12:40:14 -07:00
|
|
|
let _res = io.handle_request_sync(&req);
|
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]}"#;
|
2021-09-17 12:40:14 -07:00
|
|
|
let res = io.handle_request_sync(req);
|
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}"#;
|
2021-06-18 06:34:46 -07: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();
|
2022-03-04 02:20:11 -08:00
|
|
|
assert_eq!(result, expected);
|
2018-10-10 13:51:43 -07:00
|
|
|
|
|
|
|
// Test bad parameter
|
2020-05-15 09:35:43 -07:00
|
|
|
let req = r#"{"jsonrpc":"2.0","id":1,"method":"signatureUnsubscribe","params":[1]}"#;
|
2021-09-17 12:40:14 -07:00
|
|
|
let res = io.handle_request_sync(req);
|
2021-06-07 11:03:20 -07:00
|
|
|
let expected = r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid subscription id."},"id":1}"#;
|
2021-06-18 06:34:46 -07: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();
|
2022-03-04 02:20:11 -08:00
|
|
|
assert_eq!(result, expected);
|
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_subscribe() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo {
|
2022-05-04 03:17:29 -07:00
|
|
|
mut genesis_config,
|
2019-05-22 20:39:00 -07:00
|
|
|
mint_keypair: alice,
|
|
|
|
..
|
2022-04-25 15:35:05 -07:00
|
|
|
} = create_genesis_config(10_000_000_000);
|
2022-05-04 03:17:29 -07:00
|
|
|
genesis_config.rent = Rent::default();
|
|
|
|
activate_all_features(&mut genesis_config);
|
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();
|
2021-06-15 09:04:00 -07:00
|
|
|
let stake_program_id = stake::program::id();
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&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)));
|
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);
|
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 rpc_subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
|
|
|
&Arc::new(AtomicBool::new(false)),
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2021-09-17 12:40:14 -07:00
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
|
|
|
1, 1,
|
|
|
|
))),
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
|
|
|
));
|
|
|
|
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
|
2021-08-20 13:30:59 -07:00
|
|
|
let encoding = UiAccountEncoding::Base64;
|
2021-09-17 12:40:14 -07:00
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
rpc.account_subscribe(
|
2020-08-07 15:01:51 -07:00
|
|
|
stake_account.pubkey().to_string(),
|
2020-07-23 12:38:28 -07:00
|
|
|
Some(RpcAccountInfoConfig {
|
2021-01-26 11:23:07 -08:00
|
|
|
commitment: Some(CommitmentConfig::processed()),
|
2021-08-20 13:30:59 -07:00
|
|
|
encoding: Some(encoding),
|
2020-08-10 15:35:29 -07:00
|
|
|
data_slice: None,
|
2022-05-16 23:46:02 -07:00
|
|
|
min_context_slot: None,
|
2020-07-23 12:38:28 -07:00
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// Make sure the subscription is processed before continuing.
|
|
|
|
let (rpc2, mut receiver2) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
rpc2.slot_subscribe().unwrap();
|
|
|
|
rpc_subscriptions.notify_slot(1, 0, 0);
|
|
|
|
receiver2.recv();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2022-04-25 15:35:05 -07:00
|
|
|
let balance = {
|
|
|
|
let bank = bank_forks.read().unwrap().working_bank();
|
|
|
|
let rent = &bank.rent_collector().rent;
|
2022-05-04 03:17:29 -07:00
|
|
|
rent.minimum_balance(StakeState::size_of())
|
2022-04-25 15:35:05 -07:00
|
|
|
};
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2022-04-25 15:35:05 -07:00
|
|
|
let tx = system_transaction::transfer(&alice, &from.pubkey(), balance, blockhash);
|
|
|
|
process_transaction_and_notify(&bank_forks, &tx, &rpc_subscriptions, 1).unwrap();
|
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(),
|
2022-04-25 15:35:05 -07:00
|
|
|
balance,
|
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);
|
2021-09-17 12:40:14 -07:00
|
|
|
process_transaction_and_notify(&bank_forks, &tx, &rpc_subscriptions, 1).unwrap();
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2019-03-07 13:19:43 -08:00
|
|
|
// Test signature confirmation notification #1
|
2021-03-09 14:31:33 -08:00
|
|
|
let account = bank_forks
|
2019-05-06 07:31:50 -07:00
|
|
|
.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())
|
2021-03-09 14:31:33 -08:00
|
|
|
.unwrap();
|
|
|
|
let expected_data = account.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(),
|
2022-04-25 15:35:05 -07:00
|
|
|
"lamports": balance,
|
2021-08-20 13:30:59 -07:00
|
|
|
"data": [base64::encode(expected_data), encoding],
|
2020-03-23 05:34:42 -07:00
|
|
|
"executable": false,
|
2020-08-16 22:22:16 -07:00
|
|
|
"rentEpoch": 0,
|
2022-10-17 10:56:04 -07:00
|
|
|
"space": expected_data.len(),
|
2020-03-23 05:34:42 -07:00
|
|
|
},
|
2018-10-10 13:51:43 -07:00
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2022-05-04 03:17:29 -07:00
|
|
|
let balance = {
|
|
|
|
let bank = bank_forks.read().unwrap().working_bank();
|
|
|
|
let rent = &bank.rent_collector().rent;
|
|
|
|
rent.minimum_balance(0)
|
|
|
|
};
|
|
|
|
let tx =
|
|
|
|
system_transaction::transfer(&alice, &stake_authority.pubkey(), balance, blockhash);
|
2021-09-17 12:40:14 -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,
|
2021-01-26 09:44:44 -08:00
|
|
|
None,
|
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);
|
2021-09-17 12:40:14 -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!(
|
2021-06-15 09:04:00 -07:00
|
|
|
stake_state::authorized_from(&account).unwrap().staker,
|
2020-08-07 15:01:51 -07:00
|
|
|
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();
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-07-23 12:38:28 -07:00
|
|
|
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();
|
2020-07-23 12:38:28 -07:00
|
|
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
|
|
|
bank_forks.write().unwrap().insert(bank1);
|
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 rpc_subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
|
|
|
&Arc::new(AtomicBool::new(false)),
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2021-09-17 12:40:14 -07:00
|
|
|
bank_forks.clone(),
|
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::new_for_tests_with_slots(
|
|
|
|
1, 1,
|
|
|
|
))),
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
|
|
|
));
|
|
|
|
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
|
2020-07-23 12:38:28 -07:00
|
|
|
rpc.account_subscribe(
|
|
|
|
nonce_account.pubkey().to_string(),
|
|
|
|
Some(RpcAccountInfoConfig {
|
2021-01-26 11:23:07 -08:00
|
|
|
commitment: Some(CommitmentConfig::processed()),
|
2020-07-23 12:38:28 -07:00
|
|
|
encoding: Some(UiAccountEncoding::JsonParsed),
|
2020-08-10 15:35:29 -07:00
|
|
|
data_slice: None,
|
2022-05-16 23:46:02 -07:00
|
|
|
min_context_slot: None,
|
2020-07-23 12:38:28 -07:00
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// Make sure the subscription is processed before continuing.
|
|
|
|
let (rpc2, mut receiver2) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
rpc2.slot_subscribe().unwrap();
|
|
|
|
rpc_subscriptions.notify_slot(1, 0, 0);
|
|
|
|
receiver2.recv();
|
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);
|
2021-09-17 12:40:14 -07:00
|
|
|
process_transaction_and_notify(&bank_forks, &tx, &rpc_subscriptions, 1).unwrap();
|
2020-07-23 12:38:28 -07:00
|
|
|
|
|
|
|
// Test signature confirmation notification #1
|
2021-03-09 14:31:33 -08:00
|
|
|
let account = bank_forks
|
2020-07-23 12:38:28 -07:00
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(1)
|
|
|
|
.unwrap()
|
|
|
|
.get_account(&nonce_account.pubkey())
|
2021-03-09 14:31:33 -08:00
|
|
|
.unwrap();
|
|
|
|
let expected_data = account.data();
|
2020-08-09 00:50:45 -07:00
|
|
|
let expected_data = parse_account_data(
|
|
|
|
&nonce_account.pubkey(),
|
|
|
|
&system_program::id(),
|
2021-03-09 14:31:33 -08:00
|
|
|
expected_data,
|
2020-08-09 00:50:45 -07:00
|
|
|
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,
|
2022-10-17 10:56:04 -07:00
|
|
|
"space": account.data().len(),
|
2020-07-23 12:38:28 -07:00
|
|
|
},
|
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
2020-07-23 12:38:28 -07:00
|
|
|
}
|
|
|
|
|
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();
|
2021-09-17 12:40:14 -07:00
|
|
|
|
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_forks = Arc::new(RwLock::new(BankForks::new(Bank::new_for_tests(
|
|
|
|
&genesis_config,
|
|
|
|
))));
|
2018-10-10 13:51:43 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let mut io = IoHandler::<()>::default();
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
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 (rpc, _receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
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!(
|
2022-12-06 06:30:06 -08:00
|
|
|
r#"{{"jsonrpc":"2.0","id":1,"method":"accountSubscribe","params":["{bob_pubkey}"]}}"#
|
2018-10-10 13:51:43 -07:00
|
|
|
);
|
2021-09-17 12:40:14 -07:00
|
|
|
let _res = io.handle_request_sync(&req);
|
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]}"#;
|
2021-09-17 12:40:14 -07:00
|
|
|
let res = io.handle_request_sync(req);
|
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}"#;
|
2021-06-18 06:34:46 -07: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();
|
2022-03-04 02:20:11 -08:00
|
|
|
assert_eq!(result, expected);
|
2018-10-10 13:51:43 -07:00
|
|
|
|
|
|
|
// Test bad parameter
|
2020-05-15 09:35:43 -07:00
|
|
|
let req = r#"{"jsonrpc":"2.0","id":1,"method":"accountUnsubscribe","params":[1]}"#;
|
2021-09-17 12:40:14 -07:00
|
|
|
let res = io.handle_request_sync(req);
|
2021-06-07 11:03:20 -07:00
|
|
|
let expected = r#"{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid subscription id."},"id":1}"#;
|
2021-06-18 06:34:46 -07: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();
|
2022-03-04 02:20:11 -08:00
|
|
|
assert_eq!(result, expected);
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|
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);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&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-03-30 16:53:25 -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 rpc_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-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),
|
2021-09-17 12:40:14 -07:00
|
|
|
));
|
|
|
|
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
|
2020-05-06 23:23:06 -07:00
|
|
|
rpc.account_subscribe(
|
|
|
|
bob.pubkey().to_string(),
|
2020-07-23 12:38:28 -07:00
|
|
|
Some(RpcAccountInfoConfig {
|
2021-01-26 11:23:07 -08:00
|
|
|
commitment: Some(CommitmentConfig::finalized()),
|
2020-07-23 12:38:28 -07:00
|
|
|
encoding: None,
|
2020-08-10 15:35:29 -07:00
|
|
|
data_slice: None,
|
2022-05-16 23:46:02 -07:00
|
|
|
min_context_slot: None,
|
2020-07-23 12:38:28 -07:00
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
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();
|
2021-09-17 12:40:14 -07:00
|
|
|
rpc_subscriptions.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));
|
2021-09-17 12:40:14 -07:00
|
|
|
let _panic = receiver.recv();
|
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);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&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)));
|
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 bob = Keypair::new();
|
|
|
|
|
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()));
|
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-09-28 19:43:05 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_forks.clone(),
|
|
|
|
block_commitment_cache,
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks),
|
2021-09-17 12:40:14 -07:00
|
|
|
));
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
|
2020-05-06 23:23:06 -07:00
|
|
|
rpc.account_subscribe(
|
|
|
|
bob.pubkey().to_string(),
|
2020-07-23 12:38:28 -07:00
|
|
|
Some(RpcAccountInfoConfig {
|
2021-01-26 11:23:07 -08:00
|
|
|
commitment: Some(CommitmentConfig::finalized()),
|
2020-07-23 12:38:28 -07:00
|
|
|
encoding: None,
|
2020-08-10 15:35:29 -07:00
|
|
|
data_slice: None,
|
2022-05-16 23:46:02 -07:00
|
|
|
min_context_slot: None,
|
2020-07-23 12:38:28 -07:00
|
|
|
}),
|
2021-09-17 12:40:14 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
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-12-13 17:26:34 -08:00
|
|
|
let commitment_slots = CommitmentSlots {
|
|
|
|
slot: 1,
|
|
|
|
..CommitmentSlots::default()
|
|
|
|
};
|
2021-09-17 12:40:14 -07:00
|
|
|
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
|
|
|
};
|
2021-09-17 12:40:14 -07:00
|
|
|
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,
|
2022-10-17 10:56:04 -07:00
|
|
|
"space": 0,
|
2020-03-23 05:34:42 -07:00
|
|
|
},
|
2019-05-06 07:31:50 -07:00
|
|
|
},
|
|
|
|
"subscription": 0,
|
|
|
|
}
|
|
|
|
});
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
|
|
|
assert_eq!(
|
|
|
|
expected,
|
|
|
|
serde_json::from_str::<serde_json::Value>(&response).unwrap(),
|
|
|
|
);
|
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);
|
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)));
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
let rpc_subscriptions = Arc::new(RpcSubscriptions::default_with_bank_forks(
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
bank_forks,
|
|
|
|
));
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
rpc.slot_subscribe().unwrap();
|
|
|
|
|
|
|
|
rpc_subscriptions.notify_slot(0, 0, 0);
|
2019-11-26 00:42:54 -08:00
|
|
|
|
|
|
|
// Test slot confirmation notification
|
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!(
|
2022-12-06 06:30:06 -08:00
|
|
|
r#"{{"jsonrpc":"2.0","method":"slotNotification","params":{{"result":{expected_res_str},"subscription":0}}}}"#
|
2020-01-20 13:08:29 -08:00
|
|
|
);
|
|
|
|
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);
|
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)));
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
let rpc_subscriptions = Arc::new(RpcSubscriptions::default_with_bank_forks(
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
bank_forks,
|
|
|
|
));
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
let sub_id = rpc.slot_subscribe().unwrap();
|
|
|
|
|
|
|
|
rpc_subscriptions.notify_slot(0, 0, 0);
|
|
|
|
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!(
|
2022-12-06 06:30:06 -08:00
|
|
|
r#"{{"jsonrpc":"2.0","method":"slotNotification","params":{{"result":{expected_res_str},"subscription":0}}}}"#
|
2020-01-20 13:08:29 -08:00
|
|
|
);
|
|
|
|
assert_eq!(expected, response);
|
2019-11-26 00:42:54 -08:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
assert!(rpc.slot_unsubscribe(42.into()).is_err());
|
|
|
|
assert!(rpc.slot_unsubscribe(sub_id).is_ok());
|
2019-11-26 00:42:54 -08:00
|
|
|
}
|
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));
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2021-05-18 23:54:28 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2020-05-17 14:01:08 -07:00
|
|
|
|
|
|
|
// Setup Subscriptions
|
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-09-28 19:43:05 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_forks,
|
|
|
|
block_commitment_cache,
|
|
|
|
optimistically_confirmed_bank,
|
2021-05-18 23:54:28 -07:00
|
|
|
));
|
2021-09-17 12:40:14 -07:00
|
|
|
// Setup RPC
|
|
|
|
let (rpc, mut receiver) = rpc_pubsub_service::test_connection(&subscriptions);
|
|
|
|
rpc.vote_subscribe().unwrap();
|
2020-05-17 14:01:08 -07:00
|
|
|
|
2021-05-18 23:54:28 -07:00
|
|
|
let vote = Vote {
|
|
|
|
slots: vec![1, 2],
|
|
|
|
hash: Hash::default(),
|
|
|
|
timestamp: None,
|
|
|
|
};
|
2022-05-19 18:28:46 -07:00
|
|
|
subscriptions.notify_vote(
|
|
|
|
Pubkey::default(),
|
|
|
|
VoteTransaction::from(vote),
|
|
|
|
Signature::default(),
|
|
|
|
);
|
2020-05-17 14:01:08 -07:00
|
|
|
|
2021-09-17 12:40:14 -07:00
|
|
|
let response = receiver.recv();
|
2020-05-17 14:01:08 -07:00
|
|
|
assert_eq!(
|
|
|
|
response,
|
2022-05-19 18:28:46 -07:00
|
|
|
r#"{"jsonrpc":"2.0","method":"voteNotification","params":{"result":{"votePubkey":"11111111111111111111111111111111","slots":[1,2],"hash":"11111111111111111111111111111111","timestamp":null,"signature":"1111111111111111111111111111111111111111111111111111111111111111"},"subscription":0}}"#
|
2020-05-17 14:01:08 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[serial]
|
|
|
|
fn test_vote_unsubscribe() {
|
|
|
|
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)));
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
let rpc_subscriptions = Arc::new(RpcSubscriptions::default_with_bank_forks(
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
bank_forks,
|
|
|
|
));
|
2021-09-17 12:40:14 -07:00
|
|
|
let (rpc, _receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
let sub_id = rpc.vote_subscribe().unwrap();
|
|
|
|
|
|
|
|
assert!(rpc.vote_unsubscribe(42.into()).is_err());
|
|
|
|
assert!(rpc.vote_unsubscribe(sub_id).is_ok());
|
2020-05-17 14:01:08 -07:00
|
|
|
}
|
2022-07-07 19:55:18 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_version() {
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
|
|
|
let rpc_subscriptions = Arc::new(RpcSubscriptions::default_with_bank_forks(
|
|
|
|
max_complete_transaction_status_slot,
|
|
|
|
bank_forks,
|
|
|
|
));
|
|
|
|
let (rpc, _receiver) = rpc_pubsub_service::test_connection(&rpc_subscriptions);
|
|
|
|
let version = rpc.get_version().unwrap();
|
|
|
|
let expected_version = solana_version::Version::default();
|
|
|
|
assert_eq!(version.to_string(), expected_version.to_string());
|
|
|
|
assert_eq!(version.feature_set.unwrap(), expected_version.feature_set);
|
|
|
|
}
|
2018-10-10 13:51:43 -07:00
|
|
|
}
|