RPC PubSub now uses a well-known socket
This commit is contained in:
parent
32fc0cd7e9
commit
537436bd5e
|
@ -5,12 +5,19 @@ Solana nodes accept HTTP requests using the [JSON-RPC 2.0](https://www.jsonrpc.o
|
|||
|
||||
To interact with a Solana node inside a JavaScript application, use the [solana-web3.js](https://github.com/solana-labs/solana-web3.js) library, which gives a convenient interface for the RPC methods.
|
||||
|
||||
RPC Endpoint
|
||||
RPC HTTP Endpoint
|
||||
---
|
||||
|
||||
**Default port:** 8899
|
||||
eg. http://localhost:8899, http://192.168.1.88:8899
|
||||
|
||||
RPC PubSub WebSocket Endpoint
|
||||
---
|
||||
|
||||
**Default port:** 8900
|
||||
eg. ws://localhost:8900, http://192.168.1.88:8900
|
||||
|
||||
|
||||
Methods
|
||||
---
|
||||
|
||||
|
@ -234,33 +241,10 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
|
|||
|
||||
---
|
||||
|
||||
### startSubscriptionChannel
|
||||
Open a socket on the node for JSON-RPC subscription requests
|
||||
|
||||
##### Parameters:
|
||||
None
|
||||
|
||||
##### Results:
|
||||
* `string` - "port", open websocket port
|
||||
* `string` - "path", unique key to use as websocket path
|
||||
|
||||
##### Example:
|
||||
```bash
|
||||
// Request
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc": "2.0","id":1,"method":"startSubscriptionChannel"}' http://localhost:8899
|
||||
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":{"port":9876,"path":"BRbmMXn71cKfzXjFsmrTsWsXuQwbjXbwKdoRwVw1FRA3"},"id":1}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Subscription Websocket
|
||||
After opening a subscription socket with the `subscriptionChannel` JSON-RPC request method, submit subscription requests via websocket protocol
|
||||
Connect to the websocket at `ws://<ADDRESS>/<PATH>` returned from the request
|
||||
After connect to the RPC PubSub websocket at `ws://<ADDRESS>/`:
|
||||
- Submit subscription requests to the websocket using the methods below
|
||||
- Multiple subscriptions may be active at once
|
||||
- The subscription-channel socket will close when client closes websocket. To create new subscriptions, send a new `subscriptionChannel` JSON-RPC request.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ use leader_scheduler::LeaderScheduler;
|
|||
use ledger::read_ledger;
|
||||
use ncp::Ncp;
|
||||
use rpc::{JsonRpcService, RPC_PORT};
|
||||
use rpc_pubsub::PubSubService;
|
||||
use rpu::Rpu;
|
||||
use service::Service;
|
||||
use signature::{Keypair, KeypairUtil};
|
||||
|
@ -88,6 +89,7 @@ pub struct Fullnode {
|
|||
exit: Arc<AtomicBool>,
|
||||
rpu: Option<Rpu>,
|
||||
rpc_service: JsonRpcService,
|
||||
rpc_pubsub_service: PubSubService,
|
||||
ncp: Ncp,
|
||||
bank: Arc<Bank>,
|
||||
cluster_info: Arc<RwLock<ClusterInfo>>,
|
||||
|
@ -278,6 +280,12 @@ impl Fullnode {
|
|||
// Drone location/id will need to be handled a different way as soon as leader rotation begins
|
||||
let rpc_service = JsonRpcService::new(&bank, &cluster_info, rpc_addr, exit.clone());
|
||||
|
||||
let rpc_pubsub_addr = SocketAddr::new(
|
||||
IpAddr::V4(Ipv4Addr::from(0)),
|
||||
rpc_port.unwrap_or(RPC_PORT) + 1,
|
||||
);
|
||||
let rpc_pubsub_service = PubSubService::new(&bank, rpc_pubsub_addr, exit.clone());
|
||||
|
||||
let ncp = Ncp::new(
|
||||
&cluster_info,
|
||||
shared_window.clone(),
|
||||
|
@ -373,6 +381,7 @@ impl Fullnode {
|
|||
rpu,
|
||||
ncp,
|
||||
rpc_service,
|
||||
rpc_pubsub_service,
|
||||
node_role,
|
||||
ledger_path: ledger_path.to_owned(),
|
||||
exit,
|
||||
|
@ -567,6 +576,7 @@ impl Service for Fullnode {
|
|||
}
|
||||
self.ncp.join()?;
|
||||
self.rpc_service.join()?;
|
||||
self.rpc_pubsub_service.join()?;
|
||||
|
||||
match self.node_role {
|
||||
Some(NodeRole::Validator(validator_service)) => {
|
||||
|
|
58
src/rpc.rs
58
src/rpc.rs
|
@ -3,15 +3,12 @@
|
|||
use bank::{Bank, BankError};
|
||||
use bincode::deserialize;
|
||||
use bs58;
|
||||
use cluster_info::{ClusterInfo, FULLNODE_PORT_RANGE};
|
||||
use cluster_info::ClusterInfo;
|
||||
use drone::DRONE_PORT;
|
||||
use jsonrpc_core::*;
|
||||
use jsonrpc_http_server::*;
|
||||
use jsonrpc_macros::pubsub::Sink;
|
||||
use netutil::find_available_port_in_range;
|
||||
use rpc_pubsub::{PubSubService, SubscriptionResponse};
|
||||
use service::Service;
|
||||
use signature::{Keypair, KeypairUtil, Signature};
|
||||
use signature::Signature;
|
||||
use solana_program_interface::account::Account;
|
||||
use solana_program_interface::pubkey::Pubkey;
|
||||
use std::mem;
|
||||
|
@ -63,13 +60,10 @@ impl JsonRpcService {
|
|||
warn!("JSON RPC service unavailable: unable to bind to RPC port {}. \nMake sure this port is not already in use by another application", rpc_addr.port());
|
||||
return;
|
||||
}
|
||||
loop {
|
||||
if exit.load(Ordering::Relaxed) {
|
||||
server.unwrap().close();
|
||||
break;
|
||||
}
|
||||
while !exit.load(Ordering::Relaxed) {
|
||||
sleep(Duration::from_millis(100));
|
||||
}
|
||||
server.unwrap().close();
|
||||
()
|
||||
})
|
||||
.unwrap();
|
||||
|
@ -132,9 +126,6 @@ build_rpc_trait! {
|
|||
|
||||
#[rpc(meta, name = "sendTransaction")]
|
||||
fn send_transaction(&self, Self::Metadata, Vec<u8>) -> Result<String>;
|
||||
|
||||
#[rpc(meta, name = "startSubscriptionChannel")]
|
||||
fn start_subscription_channel(&self, Self::Metadata) -> Result<SubscriptionResponse>;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,22 +205,6 @@ impl RpcSol for RpcSolImpl {
|
|||
})?;
|
||||
Ok(bs58::encode(tx.signature).into_string())
|
||||
}
|
||||
fn start_subscription_channel(&self, meta: Self::Metadata) -> Result<SubscriptionResponse> {
|
||||
let port: u16 = find_available_port_in_range(FULLNODE_PORT_RANGE).map_err(|_| Error {
|
||||
code: ErrorCode::InternalError,
|
||||
message: "No available port in range".into(),
|
||||
data: None,
|
||||
})?;
|
||||
let mut pubsub_addr = meta.rpc_addr;
|
||||
pubsub_addr.set_port(port);
|
||||
let pubkey = Keypair::new().pubkey();
|
||||
let _pubsub_service =
|
||||
PubSubService::new(&meta.request_processor.bank, pubsub_addr, pubkey, meta.exit);
|
||||
Ok(SubscriptionResponse {
|
||||
port,
|
||||
path: pubkey.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct JsonRpcRequestProcessor {
|
||||
|
@ -264,31 +239,6 @@ impl JsonRpcRequestProcessor {
|
|||
fn get_transaction_count(&self) -> Result<u64> {
|
||||
Ok(self.bank.transaction_count() as u64)
|
||||
}
|
||||
pub fn add_account_subscription(
|
||||
&self,
|
||||
bank_sub_id: Pubkey,
|
||||
pubkey: Pubkey,
|
||||
sink: Sink<Account>,
|
||||
) {
|
||||
self.bank
|
||||
.add_account_subscription(bank_sub_id, pubkey, sink);
|
||||
}
|
||||
pub fn remove_account_subscription(&self, bank_sub_id: &Pubkey, pubkey: &Pubkey) {
|
||||
self.bank.remove_account_subscription(bank_sub_id, pubkey);
|
||||
}
|
||||
pub fn add_signature_subscription(
|
||||
&self,
|
||||
bank_sub_id: Pubkey,
|
||||
signature: Signature,
|
||||
sink: Sink<RpcSignatureStatus>,
|
||||
) {
|
||||
self.bank
|
||||
.add_signature_subscription(bank_sub_id, signature, sink);
|
||||
}
|
||||
pub fn remove_signature_subscription(&self, bank_sub_id: &Pubkey, signature: &Signature) {
|
||||
self.bank
|
||||
.remove_signature_subscription(bank_sub_id, signature);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_leader_addr(cluster_info: &Arc<RwLock<ClusterInfo>>) -> Result<SocketAddr> {
|
||||
|
|
|
@ -5,10 +5,10 @@ use bs58;
|
|||
use jsonrpc_core::futures::Future;
|
||||
use jsonrpc_core::*;
|
||||
use jsonrpc_macros::pubsub;
|
||||
use jsonrpc_pubsub::{PubSubHandler, PubSubMetadata, Session, SubscriptionId};
|
||||
use jsonrpc_ws_server::ws;
|
||||
use jsonrpc_pubsub::{PubSubHandler, Session, SubscriptionId};
|
||||
use jsonrpc_ws_server::{RequestContext, Sender, ServerBuilder};
|
||||
use rpc::{JsonRpcRequestProcessor, RpcSignatureStatus};
|
||||
use service::Service;
|
||||
use signature::{Keypair, KeypairUtil, Signature};
|
||||
use solana_program_interface::account::Account;
|
||||
use solana_program_interface::pubkey::Pubkey;
|
||||
|
@ -16,8 +16,8 @@ use std::collections::HashMap;
|
|||
use std::mem;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{atomic, Arc, Mutex, RwLock};
|
||||
use std::thread::{sleep, Builder, JoinHandle};
|
||||
use std::sync::{atomic, Arc, RwLock};
|
||||
use std::thread::{self, sleep, Builder, JoinHandle};
|
||||
use std::time::Duration;
|
||||
|
||||
pub enum ClientState {
|
||||
|
@ -25,87 +25,59 @@ pub enum ClientState {
|
|||
Init(Sender),
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct SubscriptionResponse {
|
||||
pub port: u16,
|
||||
pub path: String,
|
||||
pub struct PubSubService {
|
||||
thread_hdl: JoinHandle<()>,
|
||||
}
|
||||
|
||||
pub struct PubSubService {
|
||||
_thread_hdl: JoinHandle<()>,
|
||||
impl Service for PubSubService {
|
||||
type JoinReturnType = ();
|
||||
|
||||
fn join(self) -> thread::Result<()> {
|
||||
self.thread_hdl.join()
|
||||
}
|
||||
}
|
||||
|
||||
impl PubSubService {
|
||||
pub fn new(
|
||||
bank: &Arc<Bank>,
|
||||
pubsub_addr: SocketAddr,
|
||||
path: Pubkey,
|
||||
exit: Arc<AtomicBool>,
|
||||
) -> Self {
|
||||
let request_processor = JsonRpcRequestProcessor::new(bank.clone());
|
||||
let status = Arc::new(Mutex::new(ClientState::Uninitialized));
|
||||
let client_status = status.clone();
|
||||
let server_bank = bank.clone();
|
||||
let _thread_hdl = Builder::new()
|
||||
pub fn new(bank: &Arc<Bank>, pubsub_addr: SocketAddr, exit: Arc<AtomicBool>) -> Self {
|
||||
let rpc = RpcSolPubSubImpl::new(JsonRpcRequestProcessor::new(bank.clone()), bank.clone());
|
||||
let thread_hdl = Builder::new()
|
||||
.name("solana-pubsub".to_string())
|
||||
.spawn(move || {
|
||||
let mut io = PubSubHandler::default();
|
||||
let rpc = RpcSolPubSubImpl::default();
|
||||
let account_subs = rpc.account_subscriptions.clone();
|
||||
let signature_subs = rpc.signature_subscriptions.clone();
|
||||
io.extend_with(rpc.to_delegate());
|
||||
|
||||
let server = ServerBuilder::with_meta_extractor(io, move |context: &RequestContext|
|
||||
{
|
||||
*client_status.lock().unwrap() = ClientState::Init(context.out.clone());
|
||||
Meta {
|
||||
request_processor: request_processor.clone(),
|
||||
session: Arc::new(Session::new(context.sender().clone())),
|
||||
}
|
||||
})
|
||||
.request_middleware(move |req: &ws::Request|
|
||||
if req.resource() != format!("/{}", path.to_string()) {
|
||||
Some(ws::Response::new(403, "Client path incorrect or not provided"))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.start(&pubsub_addr);
|
||||
let server = ServerBuilder::with_meta_extractor(io, |context: &RequestContext| {
|
||||
info!("New pubsub connection");
|
||||
let session = Arc::new(Session::new(context.sender().clone()));
|
||||
session.on_drop(Box::new(|| {
|
||||
info!("Pubsub connection dropped");
|
||||
// Following should not be required as jsonrpc_pubsub will
|
||||
// unsubscribe automatically once the websocket is dropped ...
|
||||
/*
|
||||
for (_, (bank_sub_id, pubkey)) in self.account_subscriptions.read().unwrap().iter() {
|
||||
server_bank.remove_account_subscription(bank_sub_id, pubkey);
|
||||
}
|
||||
for (_, (bank_sub_id, signature)) in self.signature_subscriptions.read().unwrap().iter() {
|
||||
server_bank.remove_signature_subscription(bank_sub_id, signature);
|
||||
}
|
||||
*/
|
||||
}));
|
||||
session
|
||||
})
|
||||
.start(&pubsub_addr);
|
||||
|
||||
if server.is_err() {
|
||||
warn!("Pubsub service unavailable: unable to bind to port {}. \nMake sure this port is not already in use by another application", pubsub_addr.port());
|
||||
return;
|
||||
}
|
||||
while !exit.load(Ordering::Relaxed) {
|
||||
if let ClientState::Init(ref mut sender) = *status.lock().unwrap() {
|
||||
if sender.check_active().is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
sleep(Duration::from_millis(100));
|
||||
}
|
||||
for (_, (bank_sub_id, pubkey)) in account_subs.read().unwrap().iter() {
|
||||
server_bank.remove_account_subscription(bank_sub_id, pubkey);
|
||||
}
|
||||
for (_, (bank_sub_id, signature)) in signature_subs.read().unwrap().iter() {
|
||||
server_bank.remove_signature_subscription(bank_sub_id, signature);
|
||||
}
|
||||
server.unwrap().close();
|
||||
()
|
||||
})
|
||||
.unwrap();
|
||||
PubSubService { _thread_hdl }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Meta {
|
||||
pub request_processor: JsonRpcRequestProcessor,
|
||||
pub session: Arc<Session>,
|
||||
}
|
||||
impl Metadata for Meta {}
|
||||
impl PubSubMetadata for Meta {
|
||||
fn session(&self) -> Option<Arc<Session>> {
|
||||
Some(self.session.clone())
|
||||
PubSubService { thread_hdl }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,21 +108,36 @@ build_rpc_trait! {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct RpcSolPubSubImpl {
|
||||
uid: atomic::AtomicUsize,
|
||||
uid: Arc<atomic::AtomicUsize>,
|
||||
request_processor: JsonRpcRequestProcessor,
|
||||
bank: Arc<Bank>,
|
||||
account_subscriptions: Arc<RwLock<HashMap<SubscriptionId, (Pubkey, Pubkey)>>>,
|
||||
signature_subscriptions: Arc<RwLock<HashMap<SubscriptionId, (Pubkey, Signature)>>>,
|
||||
}
|
||||
|
||||
impl RpcSolPubSubImpl {
|
||||
fn new(request_processor: JsonRpcRequestProcessor, bank: Arc<Bank>) -> Self {
|
||||
RpcSolPubSubImpl {
|
||||
uid: Default::default(),
|
||||
request_processor,
|
||||
bank,
|
||||
account_subscriptions: Default::default(),
|
||||
signature_subscriptions: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RpcSolPubSub for RpcSolPubSubImpl {
|
||||
type Metadata = Meta;
|
||||
type Metadata = Arc<Session>;
|
||||
|
||||
fn account_subscribe(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
_meta: Self::Metadata,
|
||||
subscriber: pubsub::Subscriber<Account>,
|
||||
pubkey_str: String,
|
||||
) {
|
||||
info!("account_subscribe");
|
||||
let pubkey_vec = bs58::decode(pubkey_str).into_vec().unwrap();
|
||||
if pubkey_vec.len() != mem::size_of::<Pubkey>() {
|
||||
subscriber
|
||||
|
@ -172,15 +159,15 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
|||
.unwrap()
|
||||
.insert(sub_id.clone(), (bank_sub_id, pubkey));
|
||||
|
||||
meta.request_processor
|
||||
self.bank
|
||||
.add_account_subscription(bank_sub_id, pubkey, sink);
|
||||
}
|
||||
|
||||
fn account_unsubscribe(&self, meta: Self::Metadata, id: SubscriptionId) -> Result<bool> {
|
||||
fn account_unsubscribe(&self, _meta: Self::Metadata, id: SubscriptionId) -> Result<bool> {
|
||||
info!("account_unsubscribe");
|
||||
if let Some((bank_sub_id, pubkey)) = self.account_subscriptions.write().unwrap().remove(&id)
|
||||
{
|
||||
meta.request_processor
|
||||
.remove_account_subscription(&bank_sub_id, &pubkey);
|
||||
self.bank.remove_account_subscription(&bank_sub_id, &pubkey);
|
||||
Ok(true)
|
||||
} else {
|
||||
Err(Error {
|
||||
|
@ -193,10 +180,11 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
|||
|
||||
fn signature_subscribe(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
_meta: Self::Metadata,
|
||||
subscriber: pubsub::Subscriber<RpcSignatureStatus>,
|
||||
signature_str: String,
|
||||
) {
|
||||
info!("signature_subscribe");
|
||||
let signature_vec = bs58::decode(signature_str).into_vec().unwrap();
|
||||
if signature_vec.len() != mem::size_of::<Signature>() {
|
||||
subscriber
|
||||
|
@ -218,7 +206,7 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
|||
.unwrap()
|
||||
.insert(sub_id.clone(), (bank_sub_id, signature));
|
||||
|
||||
match meta.request_processor.get_signature_status(signature) {
|
||||
match self.request_processor.get_signature_status(signature) {
|
||||
Ok(_) => {
|
||||
sink.notify(Ok(RpcSignatureStatus::Confirmed))
|
||||
.wait()
|
||||
|
@ -229,17 +217,18 @@ impl RpcSolPubSub for RpcSolPubSubImpl {
|
|||
.remove(&sub_id);
|
||||
}
|
||||
Err(_) => {
|
||||
meta.request_processor
|
||||
self.bank
|
||||
.add_signature_subscription(bank_sub_id, signature, sink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn signature_unsubscribe(&self, meta: Self::Metadata, id: SubscriptionId) -> Result<bool> {
|
||||
fn signature_unsubscribe(&self, _meta: Self::Metadata, id: SubscriptionId) -> Result<bool> {
|
||||
info!("signature_unsubscribe");
|
||||
if let Some((bank_sub_id, signature)) =
|
||||
self.signature_subscriptions.write().unwrap().remove(&id)
|
||||
{
|
||||
meta.request_processor
|
||||
self.bank
|
||||
.remove_signature_subscription(&bank_sub_id, &signature);
|
||||
Ok(true)
|
||||
} else {
|
||||
|
@ -270,10 +259,9 @@ mod tests {
|
|||
let alice = Mint::new(10_000);
|
||||
let bank = Bank::new(&alice);
|
||||
let pubsub_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
|
||||
let pubkey = Keypair::new().pubkey();
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
let pubsub_service = PubSubService::new(&Arc::new(bank), pubsub_addr, pubkey, exit);
|
||||
let thread = pubsub_service._thread_hdl.thread();
|
||||
let pubsub_service = PubSubService::new(&Arc::new(bank), pubsub_addr, exit);
|
||||
let thread = pubsub_service.thread_hdl.thread();
|
||||
assert_eq!(thread.name().unwrap(), "solana-pubsub");
|
||||
}
|
||||
|
||||
|
@ -286,17 +274,15 @@ mod tests {
|
|||
let arc_bank = Arc::new(bank);
|
||||
let last_id = arc_bank.last_id();
|
||||
|
||||
let request_processor = JsonRpcRequestProcessor::new(arc_bank.clone());
|
||||
let (sender, mut receiver) = mpsc::channel(1);
|
||||
let session = Arc::new(Session::new(sender));
|
||||
|
||||
let mut io = PubSubHandler::default();
|
||||
let rpc = RpcSolPubSubImpl::default();
|
||||
let rpc = RpcSolPubSubImpl::new(
|
||||
JsonRpcRequestProcessor::new(arc_bank.clone()),
|
||||
arc_bank.clone(),
|
||||
);
|
||||
io.extend_with(rpc.to_delegate());
|
||||
let meta = Meta {
|
||||
request_processor,
|
||||
session,
|
||||
};
|
||||
|
||||
// Test signature subscription
|
||||
let tx = Transaction::system_move(&alice.keypair(), bob_pubkey, 20, last_id, 0);
|
||||
|
@ -305,7 +291,7 @@ mod tests {
|
|||
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
|
||||
tx.signature.to_string()
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let res = io.handle_request_sync(&req, session.clone());
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":0,"id":1}}"#);
|
||||
let expected: Response =
|
||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
||||
|
@ -318,7 +304,7 @@ mod tests {
|
|||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["a1b2c3"]}}"#
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let res = io.handle_request_sync(&req, session.clone());
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","error":{{"code":-32602,"message":"Invalid Request: Invalid signature provided"}},"id":1}}"#);
|
||||
let expected: Response =
|
||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
||||
|
@ -346,7 +332,7 @@ mod tests {
|
|||
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
|
||||
tx.signature.to_string()
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let res = io.handle_request_sync(&req, session.clone());
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":1,"id":1}}"#);
|
||||
let expected: Response =
|
||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
||||
|
@ -364,28 +350,26 @@ mod tests {
|
|||
let arc_bank = Arc::new(bank);
|
||||
let last_id = arc_bank.last_id();
|
||||
|
||||
let request_processor = JsonRpcRequestProcessor::new(arc_bank);
|
||||
let (sender, _receiver) = mpsc::channel(1);
|
||||
let session = Arc::new(Session::new(sender));
|
||||
|
||||
let mut io = PubSubHandler::default();
|
||||
let rpc = RpcSolPubSubImpl::default();
|
||||
let rpc = RpcSolPubSubImpl::new(
|
||||
JsonRpcRequestProcessor::new(arc_bank.clone()),
|
||||
arc_bank.clone(),
|
||||
);
|
||||
io.extend_with(rpc.to_delegate());
|
||||
let meta = Meta {
|
||||
request_processor,
|
||||
session: session.clone(),
|
||||
};
|
||||
|
||||
let tx = Transaction::system_move(&alice.keypair(), bob_pubkey, 20, last_id, 0);
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"signatureSubscribe","params":["{}"]}}"#,
|
||||
tx.signature.to_string()
|
||||
);
|
||||
let _res = io.handle_request_sync(&req, meta.clone());
|
||||
let _res = io.handle_request_sync(&req, session.clone());
|
||||
|
||||
let req =
|
||||
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"signatureUnsubscribe","params":[0]}}"#);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let res = io.handle_request_sync(&req, session.clone());
|
||||
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":true,"id":1}}"#);
|
||||
let expected: Response =
|
||||
|
@ -398,7 +382,7 @@ mod tests {
|
|||
// Test bad parameter
|
||||
let req =
|
||||
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"signatureUnsubscribe","params":[1]}}"#);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let res = io.handle_request_sync(&req, session.clone());
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","error":{{"code":-32602,"message":"Invalid Request: Subscription id does not exist"}},"id":1}}"#);
|
||||
let expected: Response =
|
||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
||||
|
@ -420,24 +404,22 @@ mod tests {
|
|||
let arc_bank = Arc::new(bank);
|
||||
let last_id = arc_bank.last_id();
|
||||
|
||||
let request_processor = JsonRpcRequestProcessor::new(arc_bank.clone());
|
||||
let (sender, mut receiver) = mpsc::channel(1);
|
||||
let session = Arc::new(Session::new(sender));
|
||||
|
||||
let mut io = PubSubHandler::default();
|
||||
let rpc = RpcSolPubSubImpl::default();
|
||||
let rpc = RpcSolPubSubImpl::new(
|
||||
JsonRpcRequestProcessor::new(arc_bank.clone()),
|
||||
arc_bank.clone(),
|
||||
);
|
||||
io.extend_with(rpc.to_delegate());
|
||||
let meta = Meta {
|
||||
request_processor,
|
||||
session,
|
||||
};
|
||||
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"accountSubscribe","params":["{}"]}}"#,
|
||||
contract_state.pubkey().to_string()
|
||||
);
|
||||
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let res = io.handle_request_sync(&req, session.clone());
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":0,"id":1}}"#);
|
||||
let expected: Response =
|
||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
||||
|
@ -450,7 +432,7 @@ mod tests {
|
|||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"accountSubscribe","params":["a1b2c3"]}}"#
|
||||
);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let res = io.handle_request_sync(&req, session.clone());
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","error":{{"code":-32602,"message":"Invalid Request: Invalid pubkey provided"}},"id":1}}"#);
|
||||
let expected: Response =
|
||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
||||
|
@ -481,6 +463,7 @@ mod tests {
|
|||
budget_program_id,
|
||||
0,
|
||||
);
|
||||
|
||||
arc_bank
|
||||
.process_transaction(&tx)
|
||||
.expect("process transaction");
|
||||
|
@ -488,10 +471,12 @@ mod tests {
|
|||
// Test signature confirmation notification #1
|
||||
let string = receiver.poll();
|
||||
assert!(string.is_ok());
|
||||
|
||||
let expected_userdata = arc_bank
|
||||
.get_account(&contract_state.pubkey())
|
||||
.unwrap()
|
||||
.userdata;
|
||||
|
||||
let expected = json!({
|
||||
"jsonrpc": "2.0",
|
||||
"method": "accountNotification",
|
||||
|
@ -593,27 +578,26 @@ mod tests {
|
|||
let bank = Bank::new(&alice);
|
||||
let arc_bank = Arc::new(bank);
|
||||
|
||||
let request_processor = JsonRpcRequestProcessor::new(arc_bank);
|
||||
let (sender, _receiver) = mpsc::channel(1);
|
||||
let session = Arc::new(Session::new(sender));
|
||||
|
||||
let mut io = PubSubHandler::default();
|
||||
let rpc = RpcSolPubSubImpl::default();
|
||||
let rpc = RpcSolPubSubImpl::new(
|
||||
JsonRpcRequestProcessor::new(arc_bank.clone()),
|
||||
arc_bank.clone(),
|
||||
);
|
||||
|
||||
io.extend_with(rpc.to_delegate());
|
||||
let meta = Meta {
|
||||
request_processor,
|
||||
session: session.clone(),
|
||||
};
|
||||
|
||||
let req = format!(
|
||||
r#"{{"jsonrpc":"2.0","id":1,"method":"accountSubscribe","params":["{}"]}}"#,
|
||||
bob_pubkey.to_string()
|
||||
);
|
||||
let _res = io.handle_request_sync(&req, meta.clone());
|
||||
let _res = io.handle_request_sync(&req, session.clone());
|
||||
|
||||
let req =
|
||||
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"accountUnsubscribe","params":[0]}}"#);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let res = io.handle_request_sync(&req, session.clone());
|
||||
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","result":true,"id":1}}"#);
|
||||
let expected: Response =
|
||||
|
@ -626,7 +610,7 @@ mod tests {
|
|||
// Test bad parameter
|
||||
let req =
|
||||
format!(r#"{{"jsonrpc":"2.0","id":1,"method":"accountUnsubscribe","params":[1]}}"#);
|
||||
let res = io.handle_request_sync(&req, meta.clone());
|
||||
let res = io.handle_request_sync(&req, session.clone());
|
||||
let expected = format!(r#"{{"jsonrpc":"2.0","error":{{"code":-32602,"message":"Invalid Request: Subscription id does not exist"}},"id":1}}"#);
|
||||
let expected: Response =
|
||||
serde_json::from_str(&expected).expect("expected response deserialization");
|
||||
|
|
Loading…
Reference in New Issue