2019-02-17 08:38:36 -08:00
|
|
|
//! The `pubsub` module implements a threaded subscription service on client RPC request
|
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
use crate::bank_forks::BankForks;
|
2019-03-06 14:31:58 -08:00
|
|
|
use bs58;
|
2019-03-06 14:31:16 -08:00
|
|
|
use core::hash::Hash;
|
2019-02-17 08:38:36 -08:00
|
|
|
use jsonrpc_core::futures::Future;
|
2019-02-17 10:01:21 -08:00
|
|
|
use jsonrpc_pubsub::typed::Sink;
|
2019-02-17 08:38:36 -08:00
|
|
|
use jsonrpc_pubsub::SubscriptionId;
|
2019-05-06 07:31:50 -07:00
|
|
|
use serde::Serialize;
|
2019-04-05 09:42:54 -07:00
|
|
|
use solana_runtime::bank::Bank;
|
2019-02-17 08:38:36 -08:00
|
|
|
use solana_sdk::account::Account;
|
|
|
|
use solana_sdk::pubkey::Pubkey;
|
|
|
|
use solana_sdk::signature::Signature;
|
2019-04-05 19:56:17 -07:00
|
|
|
use solana_sdk::transaction;
|
2019-05-06 07:31:50 -07:00
|
|
|
use solana_vote_api::vote_state::MAX_LOCKOUT_HISTORY;
|
2019-02-17 08:38:36 -08:00
|
|
|
use std::collections::HashMap;
|
2019-05-06 07:31:50 -07:00
|
|
|
use std::sync::{Arc, RwLock};
|
2019-02-17 08:38:36 -08:00
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
pub type Confirmations = usize;
|
|
|
|
|
|
|
|
type RpcAccountSubscriptions =
|
|
|
|
RwLock<HashMap<Pubkey, HashMap<SubscriptionId, (Sink<Account>, Confirmations)>>>;
|
2019-03-06 14:31:58 -08:00
|
|
|
type RpcProgramSubscriptions =
|
2019-05-06 07:31:50 -07:00
|
|
|
RwLock<HashMap<Pubkey, HashMap<SubscriptionId, (Sink<(String, Account)>, Confirmations)>>>;
|
|
|
|
type RpcSignatureSubscriptions = RwLock<
|
|
|
|
HashMap<Signature, HashMap<SubscriptionId, (Sink<transaction::Result<()>>, Confirmations)>>,
|
|
|
|
>;
|
2019-03-06 14:31:16 -08:00
|
|
|
|
|
|
|
fn add_subscription<K, S>(
|
2019-05-06 07:31:50 -07:00
|
|
|
subscriptions: &mut HashMap<K, HashMap<SubscriptionId, (Sink<S>, Confirmations)>>,
|
2019-03-06 14:31:16 -08:00
|
|
|
hashmap_key: &K,
|
2019-05-06 07:31:50 -07:00
|
|
|
confirmations: Option<Confirmations>,
|
2019-03-06 14:31:16 -08:00
|
|
|
sub_id: &SubscriptionId,
|
|
|
|
sink: &Sink<S>,
|
|
|
|
) where
|
|
|
|
K: Eq + Hash + Clone + Copy,
|
|
|
|
S: Clone,
|
|
|
|
{
|
2019-05-06 07:31:50 -07:00
|
|
|
let confirmations = confirmations.unwrap_or(0);
|
|
|
|
let confirmations = if confirmations > MAX_LOCKOUT_HISTORY {
|
|
|
|
MAX_LOCKOUT_HISTORY
|
|
|
|
} else {
|
|
|
|
confirmations
|
|
|
|
};
|
2019-03-06 14:31:16 -08:00
|
|
|
if let Some(current_hashmap) = subscriptions.get_mut(hashmap_key) {
|
2019-05-06 07:31:50 -07:00
|
|
|
current_hashmap.insert(sub_id.clone(), (sink.clone(), confirmations));
|
2019-03-06 14:31:16 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
let mut hashmap = HashMap::new();
|
2019-05-06 07:31:50 -07:00
|
|
|
hashmap.insert(sub_id.clone(), (sink.clone(), confirmations));
|
2019-03-06 14:31:16 -08:00
|
|
|
subscriptions.insert(*hashmap_key, hashmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn remove_subscription<K, S>(
|
2019-05-06 07:31:50 -07:00
|
|
|
subscriptions: &mut HashMap<K, HashMap<SubscriptionId, (Sink<S>, Confirmations)>>,
|
2019-03-06 14:31:16 -08:00
|
|
|
sub_id: &SubscriptionId,
|
|
|
|
) -> bool
|
|
|
|
where
|
|
|
|
K: Eq + Hash + Clone + Copy,
|
|
|
|
S: Clone,
|
|
|
|
{
|
|
|
|
let mut found = false;
|
|
|
|
subscriptions.retain(|_, v| {
|
|
|
|
v.retain(|k, _| {
|
|
|
|
if *k == *sub_id {
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
!found
|
|
|
|
});
|
|
|
|
!v.is_empty()
|
|
|
|
});
|
|
|
|
found
|
|
|
|
}
|
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
fn check_confirmations_and_notify<K, S, F, N, X>(
|
|
|
|
subscriptions: &HashMap<K, HashMap<SubscriptionId, (Sink<S>, Confirmations)>>,
|
|
|
|
hashmap_key: &K,
|
|
|
|
current_slot: u64,
|
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
|
|
|
bank_method: F,
|
|
|
|
notify: N,
|
|
|
|
) where
|
|
|
|
K: Eq + Hash + Clone + Copy,
|
|
|
|
S: Clone + Serialize,
|
|
|
|
F: Fn(&Bank, &K) -> X,
|
|
|
|
N: Fn(X, &Sink<S>, u64),
|
|
|
|
X: Clone + Serialize,
|
|
|
|
{
|
|
|
|
let current_ancestors = bank_forks
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(current_slot)
|
|
|
|
.unwrap()
|
|
|
|
.ancestors
|
|
|
|
.clone();
|
|
|
|
if let Some(hashmap) = subscriptions.get(hashmap_key) {
|
|
|
|
for (_bank_sub_id, (sink, confirmations)) in hashmap.iter() {
|
|
|
|
let desired_slot: Vec<u64> = current_ancestors
|
|
|
|
.iter()
|
|
|
|
.filter(|(_, &v)| v == *confirmations)
|
|
|
|
.map(|(k, _)| k)
|
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
let root: Vec<u64> = current_ancestors
|
|
|
|
.iter()
|
|
|
|
.filter(|(_, &v)| v == 32)
|
|
|
|
.map(|(k, _)| k)
|
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
let root = if root.len() == 1 { root[0] } else { 0 };
|
|
|
|
if desired_slot.len() == 1 {
|
|
|
|
let desired_bank = bank_forks
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get(desired_slot[0])
|
|
|
|
.unwrap()
|
|
|
|
.clone();
|
|
|
|
let result = bank_method(&desired_bank, hashmap_key);
|
|
|
|
notify(result, &sink, root);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn notify_account<S>(result: Option<(S, u64)>, sink: &Sink<S>, root: u64)
|
|
|
|
where
|
|
|
|
S: Clone + Serialize,
|
|
|
|
{
|
|
|
|
if let Some((account, fork)) = result {
|
|
|
|
if fork >= root {
|
|
|
|
sink.notify(Ok(account)).wait().unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn notify_signature<S>(result: Option<S>, sink: &Sink<S>, _root: u64)
|
|
|
|
where
|
|
|
|
S: Clone + Serialize,
|
|
|
|
{
|
|
|
|
if let Some(result) = result {
|
|
|
|
sink.notify(Ok(result)).wait().unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn notify_program(accounts: Vec<(Pubkey, Account)>, sink: &Sink<(String, Account)>, _root: u64) {
|
|
|
|
for (pubkey, account) in accounts.iter() {
|
|
|
|
sink.notify(Ok((bs58::encode(pubkey).into_string(), account.clone())))
|
|
|
|
.wait()
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-17 08:38:36 -08:00
|
|
|
pub struct RpcSubscriptions {
|
|
|
|
account_subscriptions: RpcAccountSubscriptions,
|
2019-03-06 14:31:58 -08:00
|
|
|
program_subscriptions: RpcProgramSubscriptions,
|
2019-02-17 08:38:36 -08:00
|
|
|
signature_subscriptions: RpcSignatureSubscriptions,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for RpcSubscriptions {
|
|
|
|
fn default() -> Self {
|
|
|
|
RpcSubscriptions {
|
|
|
|
account_subscriptions: RpcAccountSubscriptions::default(),
|
2019-03-06 14:31:58 -08:00
|
|
|
program_subscriptions: RpcProgramSubscriptions::default(),
|
2019-02-17 08:38:36 -08:00
|
|
|
signature_subscriptions: RpcSignatureSubscriptions::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RpcSubscriptions {
|
2019-05-06 07:31:50 -07:00
|
|
|
pub fn check_account(
|
|
|
|
&self,
|
|
|
|
pubkey: &Pubkey,
|
|
|
|
current_slot: u64,
|
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
|
|
|
) {
|
2019-02-17 08:38:36 -08:00
|
|
|
let subscriptions = self.account_subscriptions.read().unwrap();
|
2019-05-06 07:31:50 -07:00
|
|
|
check_confirmations_and_notify(
|
|
|
|
&subscriptions,
|
|
|
|
pubkey,
|
|
|
|
current_slot,
|
|
|
|
bank_forks,
|
|
|
|
Bank::get_account_modified_since_parent,
|
|
|
|
notify_account,
|
|
|
|
);
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
pub fn check_program(
|
|
|
|
&self,
|
|
|
|
program_id: &Pubkey,
|
|
|
|
current_slot: u64,
|
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
|
|
|
) {
|
2019-03-06 14:31:58 -08:00
|
|
|
let subscriptions = self.program_subscriptions.write().unwrap();
|
2019-05-06 07:31:50 -07:00
|
|
|
check_confirmations_and_notify(
|
|
|
|
&subscriptions,
|
|
|
|
program_id,
|
|
|
|
current_slot,
|
|
|
|
bank_forks,
|
|
|
|
Bank::get_program_accounts_modified_since_parent,
|
|
|
|
notify_program,
|
|
|
|
);
|
2019-03-06 14:31:58 -08:00
|
|
|
}
|
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
pub fn check_signature(
|
|
|
|
&self,
|
|
|
|
signature: &Signature,
|
|
|
|
current_slot: u64,
|
|
|
|
bank_forks: &Arc<RwLock<BankForks>>,
|
|
|
|
) {
|
2019-02-17 08:38:36 -08:00
|
|
|
let mut subscriptions = self.signature_subscriptions.write().unwrap();
|
2019-05-06 07:31:50 -07:00
|
|
|
check_confirmations_and_notify(
|
|
|
|
&subscriptions,
|
|
|
|
signature,
|
|
|
|
current_slot,
|
|
|
|
bank_forks,
|
|
|
|
Bank::get_signature_status,
|
|
|
|
notify_signature,
|
|
|
|
);
|
2019-02-17 08:38:36 -08:00
|
|
|
subscriptions.remove(&signature);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_account_subscription(
|
|
|
|
&self,
|
|
|
|
pubkey: &Pubkey,
|
2019-05-06 07:31:50 -07:00
|
|
|
confirmations: Option<Confirmations>,
|
2019-02-17 08:38:36 -08:00
|
|
|
sub_id: &SubscriptionId,
|
|
|
|
sink: &Sink<Account>,
|
|
|
|
) {
|
|
|
|
let mut subscriptions = self.account_subscriptions.write().unwrap();
|
2019-05-06 07:31:50 -07:00
|
|
|
add_subscription(&mut subscriptions, pubkey, confirmations, sub_id, sink);
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove_account_subscription(&self, id: &SubscriptionId) -> bool {
|
|
|
|
let mut subscriptions = self.account_subscriptions.write().unwrap();
|
2019-03-06 14:31:16 -08:00
|
|
|
remove_subscription(&mut subscriptions, id)
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
|
|
|
|
2019-03-06 14:31:58 -08:00
|
|
|
pub fn add_program_subscription(
|
|
|
|
&self,
|
|
|
|
program_id: &Pubkey,
|
2019-05-06 07:31:50 -07:00
|
|
|
confirmations: Option<Confirmations>,
|
2019-03-06 14:31:58 -08:00
|
|
|
sub_id: &SubscriptionId,
|
|
|
|
sink: &Sink<(String, Account)>,
|
|
|
|
) {
|
|
|
|
let mut subscriptions = self.program_subscriptions.write().unwrap();
|
2019-05-06 07:31:50 -07:00
|
|
|
add_subscription(&mut subscriptions, program_id, confirmations, sub_id, sink);
|
2019-03-06 14:31:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove_program_subscription(&self, id: &SubscriptionId) -> bool {
|
|
|
|
let mut subscriptions = self.program_subscriptions.write().unwrap();
|
|
|
|
remove_subscription(&mut subscriptions, id)
|
|
|
|
}
|
|
|
|
|
2019-02-17 08:38:36 -08:00
|
|
|
pub fn add_signature_subscription(
|
|
|
|
&self,
|
|
|
|
signature: &Signature,
|
2019-05-06 07:31:50 -07:00
|
|
|
confirmations: Option<Confirmations>,
|
2019-02-17 08:38:36 -08:00
|
|
|
sub_id: &SubscriptionId,
|
2019-05-06 07:31:50 -07:00
|
|
|
sink: &Sink<transaction::Result<()>>,
|
2019-02-17 08:38:36 -08:00
|
|
|
) {
|
|
|
|
let mut subscriptions = self.signature_subscriptions.write().unwrap();
|
2019-05-06 07:31:50 -07:00
|
|
|
add_subscription(&mut subscriptions, signature, confirmations, sub_id, sink);
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn remove_signature_subscription(&self, id: &SubscriptionId) -> bool {
|
|
|
|
let mut subscriptions = self.signature_subscriptions.write().unwrap();
|
2019-03-06 14:31:16 -08:00
|
|
|
remove_subscription(&mut subscriptions, id)
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
2019-02-18 14:21:23 -08:00
|
|
|
|
|
|
|
/// Notify subscribers of changes to any accounts or new signatures since
|
|
|
|
/// the bank's last checkpoint.
|
2019-05-06 07:31:50 -07:00
|
|
|
pub fn notify_subscribers(&self, current_slot: u64, bank_forks: &Arc<RwLock<BankForks>>) {
|
2019-02-18 14:21:23 -08:00
|
|
|
let pubkeys: Vec<_> = {
|
|
|
|
let subs = self.account_subscriptions.read().unwrap();
|
|
|
|
subs.keys().cloned().collect()
|
|
|
|
};
|
|
|
|
for pubkey in &pubkeys {
|
2019-05-06 07:31:50 -07:00
|
|
|
self.check_account(pubkey, current_slot, bank_forks);
|
2019-02-18 14:21:23 -08:00
|
|
|
}
|
|
|
|
|
2019-03-06 14:31:58 -08:00
|
|
|
let programs: Vec<_> = {
|
|
|
|
let subs = self.program_subscriptions.read().unwrap();
|
|
|
|
subs.keys().cloned().collect()
|
|
|
|
};
|
|
|
|
for program_id in &programs {
|
2019-05-06 07:31:50 -07:00
|
|
|
self.check_program(program_id, current_slot, bank_forks);
|
2019-03-06 14:31:58 -08:00
|
|
|
}
|
|
|
|
|
2019-02-18 14:21:23 -08:00
|
|
|
let signatures: Vec<_> = {
|
|
|
|
let subs = self.signature_subscriptions.read().unwrap();
|
|
|
|
subs.keys().cloned().collect()
|
|
|
|
};
|
|
|
|
for signature in &signatures {
|
2019-05-06 07:31:50 -07:00
|
|
|
self.check_signature(signature, current_slot, bank_forks);
|
2019-02-18 14:21:23 -08:00
|
|
|
}
|
|
|
|
}
|
2019-02-17 08:38:36 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2019-05-07 11:16:22 -07:00
|
|
|
use crate::genesis_utils::create_genesis_block;
|
2019-02-17 10:17:58 -08:00
|
|
|
use jsonrpc_pubsub::typed::Subscriber;
|
2019-03-02 13:23:22 -08:00
|
|
|
use solana_budget_api;
|
2019-02-17 08:38:36 -08:00
|
|
|
use solana_sdk::signature::{Keypair, KeypairUtil};
|
2019-04-03 08:45:57 -07:00
|
|
|
use solana_sdk::system_transaction;
|
2019-02-17 08:38:36 -08:00
|
|
|
use tokio::prelude::{Async, Stream};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_check_account_subscribe() {
|
2019-05-07 11:16:22 -07:00
|
|
|
let (genesis_block, mint_keypair) = create_genesis_block(100);
|
2019-02-17 08:38:36 -08:00
|
|
|
let bank = Bank::new(&genesis_block);
|
2019-03-02 10:25:16 -08:00
|
|
|
let blockhash = bank.last_blockhash();
|
2019-05-06 07:31:50 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
|
|
|
let alice = Keypair::new();
|
2019-04-03 08:45:57 -07:00
|
|
|
let tx = system_transaction::create_account(
|
2019-02-17 08:38:36 -08:00
|
|
|
&mint_keypair,
|
2019-03-09 19:28:43 -08:00
|
|
|
&alice.pubkey(),
|
2019-03-02 10:25:16 -08:00
|
|
|
blockhash,
|
2019-02-17 08:38:36 -08:00
|
|
|
1,
|
|
|
|
16,
|
2019-03-09 19:28:43 -08:00
|
|
|
&solana_budget_api::id(),
|
2019-02-17 08:38:36 -08:00
|
|
|
0,
|
|
|
|
);
|
2019-05-06 07:31:50 -07:00
|
|
|
bank_forks
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.get(0)
|
|
|
|
.unwrap()
|
|
|
|
.process_transaction(&tx)
|
|
|
|
.unwrap();
|
2019-02-17 08:38:36 -08:00
|
|
|
|
|
|
|
let (subscriber, _id_receiver, mut transport_receiver) =
|
|
|
|
Subscriber::new_test("accountNotification");
|
|
|
|
let sub_id = SubscriptionId::Number(0 as u64);
|
|
|
|
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
|
|
|
let subscriptions = RpcSubscriptions::default();
|
2019-05-06 07:31:50 -07:00
|
|
|
subscriptions.add_account_subscription(&alice.pubkey(), None, &sub_id, &sink);
|
2019-02-17 08:38:36 -08:00
|
|
|
|
|
|
|
assert!(subscriptions
|
|
|
|
.account_subscriptions
|
2019-02-18 14:21:23 -08:00
|
|
|
.read()
|
2019-02-17 08:38:36 -08:00
|
|
|
.unwrap()
|
|
|
|
.contains_key(&alice.pubkey()));
|
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
subscriptions.check_account(&alice.pubkey(), 0, &bank_forks);
|
2019-02-17 08:38:36 -08:00
|
|
|
let string = transport_receiver.poll();
|
|
|
|
if let Async::Ready(Some(response)) = string.unwrap() {
|
2019-04-25 17:58:49 -07:00
|
|
|
let expected = format!(r#"{{"jsonrpc":"2.0","method":"accountNotification","params":{{"result":{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0]}},"subscription":0}}}}"#);
|
2019-02-17 08:38:36 -08:00
|
|
|
assert_eq!(expected, response);
|
|
|
|
}
|
|
|
|
|
|
|
|
subscriptions.remove_account_subscription(&sub_id);
|
|
|
|
assert!(!subscriptions
|
|
|
|
.account_subscriptions
|
2019-02-18 14:21:23 -08:00
|
|
|
.read()
|
2019-02-17 08:38:36 -08:00
|
|
|
.unwrap()
|
|
|
|
.contains_key(&alice.pubkey()));
|
|
|
|
}
|
2019-03-06 14:31:58 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_check_program_subscribe() {
|
2019-05-07 11:16:22 -07:00
|
|
|
let (genesis_block, mint_keypair) = create_genesis_block(100);
|
2019-03-06 14:31:58 -08:00
|
|
|
let bank = Bank::new(&genesis_block);
|
|
|
|
let blockhash = bank.last_blockhash();
|
2019-05-06 07:31:50 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
|
|
|
let alice = Keypair::new();
|
2019-04-03 08:45:57 -07:00
|
|
|
let tx = system_transaction::create_account(
|
2019-03-06 14:31:58 -08:00
|
|
|
&mint_keypair,
|
2019-03-09 19:28:43 -08:00
|
|
|
&alice.pubkey(),
|
2019-03-06 14:31:58 -08:00
|
|
|
blockhash,
|
|
|
|
1,
|
|
|
|
16,
|
2019-03-09 19:28:43 -08:00
|
|
|
&solana_budget_api::id(),
|
2019-03-06 14:31:58 -08:00
|
|
|
0,
|
|
|
|
);
|
2019-05-06 07:31:50 -07:00
|
|
|
bank_forks
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.get(0)
|
|
|
|
.unwrap()
|
|
|
|
.process_transaction(&tx)
|
|
|
|
.unwrap();
|
2019-03-06 14:31:58 -08:00
|
|
|
|
|
|
|
let (subscriber, _id_receiver, mut transport_receiver) =
|
|
|
|
Subscriber::new_test("programNotification");
|
|
|
|
let sub_id = SubscriptionId::Number(0 as u64);
|
|
|
|
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
|
|
|
let subscriptions = RpcSubscriptions::default();
|
2019-05-06 07:31:50 -07:00
|
|
|
subscriptions.add_program_subscription(&solana_budget_api::id(), None, &sub_id, &sink);
|
2019-03-06 14:31:58 -08:00
|
|
|
|
|
|
|
assert!(subscriptions
|
|
|
|
.program_subscriptions
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.contains_key(&solana_budget_api::id()));
|
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
subscriptions.check_program(&solana_budget_api::id(), 0, &bank_forks);
|
2019-03-06 14:31:58 -08:00
|
|
|
let string = transport_receiver.poll();
|
|
|
|
if let Async::Ready(Some(response)) = string.unwrap() {
|
2019-04-25 17:58:49 -07:00
|
|
|
let expected = format!(r#"{{"jsonrpc":"2.0","method":"programNotification","params":{{"result":["{:?}",{{"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"executable":false,"lamports":1,"owner":[2,203,81,223,225,24,34,35,203,214,138,130,144,208,35,77,63,16,87,51,47,198,115,123,98,188,19,160,0,0,0,0]}}],"subscription":0}}}}"#, alice.pubkey());
|
2019-03-06 14:31:58 -08:00
|
|
|
assert_eq!(expected, response);
|
|
|
|
}
|
|
|
|
|
|
|
|
subscriptions.remove_program_subscription(&sub_id);
|
|
|
|
assert!(!subscriptions
|
|
|
|
.program_subscriptions
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.contains_key(&solana_budget_api::id()));
|
|
|
|
}
|
2019-02-17 08:38:36 -08:00
|
|
|
#[test]
|
|
|
|
fn test_check_signature_subscribe() {
|
2019-05-07 11:16:22 -07:00
|
|
|
let (genesis_block, mint_keypair) = create_genesis_block(100);
|
2019-02-17 08:38:36 -08:00
|
|
|
let bank = Bank::new(&genesis_block);
|
2019-03-02 10:25:16 -08:00
|
|
|
let blockhash = bank.last_blockhash();
|
2019-05-06 07:31:50 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(0, bank)));
|
|
|
|
let alice = Keypair::new();
|
2019-04-03 08:45:57 -07:00
|
|
|
let tx = system_transaction::transfer(&mint_keypair, &alice.pubkey(), 20, blockhash, 0);
|
2019-02-17 08:38:36 -08:00
|
|
|
let signature = tx.signatures[0];
|
2019-05-06 07:31:50 -07:00
|
|
|
bank_forks
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.get(0)
|
|
|
|
.unwrap()
|
|
|
|
.process_transaction(&tx)
|
|
|
|
.unwrap();
|
2019-02-17 08:38:36 -08:00
|
|
|
|
|
|
|
let (subscriber, _id_receiver, mut transport_receiver) =
|
|
|
|
Subscriber::new_test("signatureNotification");
|
|
|
|
let sub_id = SubscriptionId::Number(0 as u64);
|
|
|
|
let sink = subscriber.assign_id(sub_id.clone()).unwrap();
|
|
|
|
let subscriptions = RpcSubscriptions::default();
|
2019-05-06 07:31:50 -07:00
|
|
|
subscriptions.add_signature_subscription(&signature, None, &sub_id, &sink);
|
2019-02-17 08:38:36 -08:00
|
|
|
|
|
|
|
assert!(subscriptions
|
|
|
|
.signature_subscriptions
|
2019-02-18 14:21:23 -08:00
|
|
|
.read()
|
2019-02-17 08:38:36 -08:00
|
|
|
.unwrap()
|
|
|
|
.contains_key(&signature));
|
|
|
|
|
2019-05-06 07:31:50 -07:00
|
|
|
subscriptions.check_signature(&signature, 0, &bank_forks);
|
2019-02-17 08:38:36 -08:00
|
|
|
let string = transport_receiver.poll();
|
|
|
|
if let Async::Ready(Some(response)) = string.unwrap() {
|
2019-04-05 19:56:17 -07:00
|
|
|
let expected_res: Option<transaction::Result<()>> = Some(Ok(()));
|
|
|
|
let expected_res_str =
|
|
|
|
serde_json::to_string(&serde_json::to_value(expected_res).unwrap()).unwrap();
|
|
|
|
let expected = format!(r#"{{"jsonrpc":"2.0","method":"signatureNotification","params":{{"result":{},"subscription":0}}}}"#, expected_res_str);
|
2019-02-17 08:38:36 -08:00
|
|
|
assert_eq!(expected, response);
|
|
|
|
}
|
|
|
|
|
|
|
|
subscriptions.remove_signature_subscription(&sub_id);
|
|
|
|
assert!(!subscriptions
|
|
|
|
.signature_subscriptions
|
2019-02-18 14:21:23 -08:00
|
|
|
.read()
|
2019-02-17 08:38:36 -08:00
|
|
|
.unwrap()
|
|
|
|
.contains_key(&signature));
|
|
|
|
}
|
|
|
|
}
|