2018-08-16 08:46:07 -06:00
//! The `rpc` module implements the Solana RPC interface.
2018-08-10 17:05:23 -06:00
2018-09-26 17:33:18 -06:00
use bank ::{ Bank , BankError } ;
2018-08-22 11:53:24 -06:00
use bincode ::deserialize ;
2018-08-10 17:05:23 -06:00
use bs58 ;
2018-10-12 11:04:14 -07:00
use cluster_info ::ClusterInfo ;
2018-10-12 14:25:56 -06:00
use drone ::DRONE_PORT ;
2018-08-13 13:59:04 -06:00
use jsonrpc_core ::* ;
2018-08-14 18:03:48 -06:00
use jsonrpc_http_server ::* ;
2018-09-10 22:41:44 -07:00
use service ::Service ;
2018-10-12 11:04:14 -07:00
use signature ::Signature ;
2018-09-27 07:49:26 -07:00
use solana_program_interface ::account ::Account ;
use solana_program_interface ::pubkey ::Pubkey ;
2018-08-10 17:05:23 -06:00
use std ::mem ;
2018-08-22 11:53:24 -06:00
use std ::net ::{ SocketAddr , UdpSocket } ;
2018-09-26 15:57:34 -06:00
use std ::result ;
2018-09-10 22:41:44 -07:00
use std ::sync ::atomic ::{ AtomicBool , Ordering } ;
2018-10-12 14:25:56 -06:00
use std ::sync ::{ Arc , RwLock } ;
2018-09-10 22:41:44 -07:00
use std ::thread ::{ self , sleep , Builder , JoinHandle } ;
2018-08-22 12:25:21 -06:00
use std ::time ::Duration ;
use std ::time ::Instant ;
2018-08-22 11:53:24 -06:00
use transaction ::Transaction ;
use wallet ::request_airdrop ;
2018-08-10 17:05:23 -06:00
pub const RPC_PORT : u16 = 8899 ;
2018-08-14 18:03:48 -06:00
pub struct JsonRpcService {
2018-09-10 22:41:44 -07:00
thread_hdl : JoinHandle < ( ) > ,
2018-08-14 18:03:48 -06:00
}
impl JsonRpcService {
2018-08-22 11:53:24 -06:00
pub fn new (
2018-08-22 16:44:26 -06:00
bank : & Arc < Bank > ,
2018-10-12 14:25:56 -06:00
cluster_info : & Arc < RwLock < ClusterInfo > > ,
2018-08-22 11:53:24 -06:00
rpc_addr : SocketAddr ,
2018-09-10 22:41:44 -07:00
exit : Arc < AtomicBool > ,
2018-08-22 11:53:24 -06:00
) -> Self {
2018-08-22 16:44:26 -06:00
let request_processor = JsonRpcRequestProcessor ::new ( bank . clone ( ) ) ;
2018-10-12 14:25:56 -06:00
let info = cluster_info . clone ( ) ;
2018-10-10 14:51:43 -06:00
let exit_pubsub = exit . clone ( ) ;
2018-09-10 22:41:44 -07:00
let thread_hdl = Builder ::new ( )
. name ( " solana-jsonrpc " . to_string ( ) )
. spawn ( move | | {
let mut io = MetaIoHandler ::default ( ) ;
let rpc = RpcSolImpl ;
io . extend_with ( rpc . to_delegate ( ) ) ;
2018-08-15 12:41:39 -06:00
2018-09-10 22:41:44 -07:00
let server =
2018-09-28 08:20:26 -06:00
ServerBuilder ::with_meta_extractor ( io , move | _req : & hyper ::Request < hyper ::Body > | Meta {
2018-09-10 22:41:44 -07:00
request_processor : request_processor . clone ( ) ,
2018-10-12 14:25:56 -06:00
cluster_info : info . clone ( ) ,
2018-10-10 14:51:43 -06:00
rpc_addr ,
exit : exit_pubsub . clone ( ) ,
2018-09-10 22:41:44 -07:00
} ) . threads ( 4 )
. cors ( DomainsValidation ::AllowOnly ( vec! [
AccessControlAllowOrigin ::Any ,
] ) )
. start_http ( & rpc_addr ) ;
if server . is_err ( ) {
warn! ( " JSON RPC service unavailable: unable to bind to RPC port {}. \n Make sure this port is not already in use by another application " , rpc_addr . port ( ) ) ;
return ;
}
2018-10-12 11:04:14 -07:00
while ! exit . load ( Ordering ::Relaxed ) {
2018-09-10 22:41:44 -07:00
sleep ( Duration ::from_millis ( 100 ) ) ;
}
2018-10-12 11:04:14 -07:00
server . unwrap ( ) . close ( ) ;
2018-09-10 22:41:44 -07:00
( )
} )
. unwrap ( ) ;
JsonRpcService { thread_hdl }
}
}
2018-08-14 18:03:48 -06:00
2018-09-10 22:41:44 -07:00
impl Service for JsonRpcService {
2018-09-13 14:00:17 -07:00
type JoinReturnType = ( ) ;
2018-08-14 18:03:48 -06:00
2018-09-10 22:41:44 -07:00
fn join ( self ) -> thread ::Result < ( ) > {
2018-09-15 23:46:16 -07:00
self . thread_hdl . join ( )
2018-08-14 18:03:48 -06:00
}
}
2018-08-10 17:05:23 -06:00
#[ derive(Clone) ]
pub struct Meta {
2018-08-15 10:37:02 -06:00
pub request_processor : JsonRpcRequestProcessor ,
2018-10-12 14:25:56 -06:00
pub cluster_info : Arc < RwLock < ClusterInfo > > ,
2018-10-10 14:51:43 -06:00
pub rpc_addr : SocketAddr ,
pub exit : Arc < AtomicBool > ,
2018-08-10 17:05:23 -06:00
}
impl Metadata for Meta { }
2018-10-10 14:51:43 -06:00
#[ derive(Copy, Clone, PartialEq, Serialize, Debug) ]
2018-09-26 17:12:40 -07:00
pub enum RpcSignatureStatus {
Confirmed ,
SignatureNotFound ,
ProgramRuntimeError ,
GenericFailure ,
}
2018-08-10 17:05:23 -06:00
build_rpc_trait! {
pub trait RpcSol {
type Metadata ;
2018-08-15 11:34:17 -06:00
#[ rpc(meta, name = " confirmTransaction " ) ]
2018-08-10 17:05:23 -06:00
fn confirm_transaction ( & self , Self ::Metadata , String ) -> Result < bool > ;
2018-09-20 23:27:06 -06:00
#[ rpc(meta, name = " getAccountInfo " ) ]
fn get_account_info ( & self , Self ::Metadata , String ) -> Result < Account > ;
2018-08-15 11:34:17 -06:00
#[ rpc(meta, name = " getBalance " ) ]
2018-08-20 14:20:20 -07:00
fn get_balance ( & self , Self ::Metadata , String ) -> Result < i64 > ;
2018-08-14 18:03:48 -06:00
2018-08-15 11:34:17 -06:00
#[ rpc(meta, name = " getFinality " ) ]
2018-08-14 18:03:48 -06:00
fn get_finality ( & self , Self ::Metadata ) -> Result < usize > ;
2018-08-10 17:05:23 -06:00
2018-08-15 11:34:17 -06:00
#[ rpc(meta, name = " getLastId " ) ]
2018-08-13 12:52:37 -06:00
fn get_last_id ( & self , Self ::Metadata ) -> Result < String > ;
2018-09-26 17:12:40 -07:00
#[ rpc(meta, name = " getSignatureStatus " ) ]
fn get_signature_status ( & self , Self ::Metadata , String ) -> Result < RpcSignatureStatus > ;
2018-08-15 11:34:17 -06:00
#[ rpc(meta, name = " getTransactionCount " ) ]
2018-08-10 17:05:23 -06:00
fn get_transaction_count ( & self , Self ::Metadata ) -> Result < u64 > ;
2018-08-22 11:54:37 -06:00
#[ rpc(meta, name= " requestAirdrop " ) ]
2018-08-26 22:32:51 -06:00
fn request_airdrop ( & self , Self ::Metadata , String , u64 ) -> Result < String > ;
2018-08-22 11:54:37 -06:00
2018-08-22 11:53:24 -06:00
#[ rpc(meta, name = " sendTransaction " ) ]
fn send_transaction ( & self , Self ::Metadata , Vec < u8 > ) -> Result < String > ;
2018-08-10 17:05:23 -06:00
}
}
pub struct RpcSolImpl ;
impl RpcSol for RpcSolImpl {
type Metadata = Meta ;
fn confirm_transaction ( & self , meta : Self ::Metadata , id : String ) -> Result < bool > {
2018-09-26 17:12:40 -07:00
self . get_signature_status ( meta , id )
. map ( | status | status = = RpcSignatureStatus ::Confirmed )
2018-08-10 17:05:23 -06:00
}
2018-09-26 17:12:40 -07:00
2018-09-20 23:27:06 -06:00
fn get_account_info ( & self , meta : Self ::Metadata , id : String ) -> Result < Account > {
2018-10-15 11:01:40 -06:00
let pubkey = verify_pubkey ( id ) ? ;
2018-09-20 23:27:06 -06:00
meta . request_processor . get_account_info ( pubkey )
}
2018-08-20 14:20:20 -07:00
fn get_balance ( & self , meta : Self ::Metadata , id : String ) -> Result < i64 > {
2018-10-15 11:01:40 -06:00
let pubkey = verify_pubkey ( id ) ? ;
2018-08-15 12:41:39 -06:00
meta . request_processor . get_balance ( pubkey )
2018-08-10 17:05:23 -06:00
}
2018-08-14 18:03:48 -06:00
fn get_finality ( & self , meta : Self ::Metadata ) -> Result < usize > {
2018-08-15 12:41:39 -06:00
meta . request_processor . get_finality ( )
2018-08-14 18:03:48 -06:00
}
2018-08-13 12:52:37 -06:00
fn get_last_id ( & self , meta : Self ::Metadata ) -> Result < String > {
2018-08-15 12:41:39 -06:00
meta . request_processor . get_last_id ( )
2018-08-13 12:52:37 -06:00
}
2018-09-26 17:12:40 -07:00
fn get_signature_status ( & self , meta : Self ::Metadata , id : String ) -> Result < RpcSignatureStatus > {
2018-10-15 11:01:40 -06:00
let signature = verify_signature ( id ) ? ;
2018-09-26 17:12:40 -07:00
Ok (
match meta . request_processor . get_signature_status ( signature ) {
Ok ( _ ) = > RpcSignatureStatus ::Confirmed ,
2018-09-28 16:16:35 -07:00
Err ( BankError ::ProgramRuntimeError ( _ ) ) = > RpcSignatureStatus ::ProgramRuntimeError ,
2018-09-26 17:12:40 -07:00
Err ( BankError ::SignatureNotFound ) = > RpcSignatureStatus ::SignatureNotFound ,
2018-09-26 19:23:27 -07:00
Err ( err ) = > {
trace! ( " mapping {:?} to GenericFailure " , err ) ;
RpcSignatureStatus ::GenericFailure
}
2018-09-26 17:12:40 -07:00
} ,
)
}
2018-08-10 17:05:23 -06:00
fn get_transaction_count ( & self , meta : Self ::Metadata ) -> Result < u64 > {
2018-08-15 12:41:39 -06:00
meta . request_processor . get_transaction_count ( )
2018-08-14 18:03:48 -06:00
}
2018-08-26 22:32:51 -06:00
fn request_airdrop ( & self , meta : Self ::Metadata , id : String , tokens : u64 ) -> Result < String > {
2018-10-15 11:01:40 -06:00
let pubkey = verify_pubkey ( id ) ? ;
2018-10-12 14:25:56 -06:00
let mut drone_addr = get_leader_addr ( & meta . cluster_info ) ? ;
drone_addr . set_port ( DRONE_PORT ) ;
let signature =
request_airdrop ( & drone_addr , & pubkey , tokens ) . map_err ( | _ | Error ::internal_error ( ) ) ? ;
2018-10-15 11:01:40 -06:00
2018-08-22 12:25:21 -06:00
let now = Instant ::now ( ) ;
2018-08-26 22:32:51 -06:00
let mut signature_status ;
2018-08-22 12:25:21 -06:00
loop {
2018-09-26 17:12:40 -07:00
signature_status = meta . request_processor . get_signature_status ( signature ) ;
2018-08-26 22:32:51 -06:00
2018-09-26 15:57:34 -06:00
if signature_status . is_ok ( ) {
2018-08-26 22:32:51 -06:00
return Ok ( bs58 ::encode ( signature ) . into_string ( ) ) ;
2018-08-22 12:25:21 -06:00
} else if now . elapsed ( ) . as_secs ( ) > 5 {
return Err ( Error ::internal_error ( ) ) ;
}
sleep ( Duration ::from_millis ( 100 ) ) ;
}
2018-08-22 11:54:37 -06:00
}
2018-08-22 11:53:24 -06:00
fn send_transaction ( & self , meta : Self ::Metadata , data : Vec < u8 > ) -> Result < String > {
2018-09-18 11:31:21 -07:00
let tx : Transaction = deserialize ( & data ) . map_err ( | err | {
debug! ( " send_transaction: deserialize error: {:?} " , err ) ;
Error ::invalid_request ( )
} ) ? ;
2018-08-22 11:53:24 -06:00
let transactions_socket = UdpSocket ::bind ( " 0.0.0.0:0 " ) . unwrap ( ) ;
2018-10-15 11:01:40 -06:00
let transactions_addr = get_leader_addr ( & meta . cluster_info ) ? ;
2018-08-22 11:53:24 -06:00
transactions_socket
2018-10-12 14:25:56 -06:00
. send_to ( & data , transactions_addr )
2018-09-18 11:31:21 -07:00
. map_err ( | err | {
debug! ( " send_transaction: send_to error: {:?} " , err ) ;
Error ::internal_error ( )
} ) ? ;
2018-09-26 11:17:45 -06:00
Ok ( bs58 ::encode ( tx . signature ) . into_string ( ) )
2018-08-22 11:53:24 -06:00
}
2018-08-14 18:03:48 -06:00
}
#[ derive(Clone) ]
pub struct JsonRpcRequestProcessor {
bank : Arc < Bank > ,
}
impl JsonRpcRequestProcessor {
/// Create a new request processor that wraps the given Bank.
pub fn new ( bank : Arc < Bank > ) -> Self {
JsonRpcRequestProcessor { bank }
2018-08-10 17:05:23 -06:00
}
2018-08-15 12:41:39 -06:00
/// Process JSON-RPC request items sent via JSON-RPC.
2018-10-10 14:51:43 -06:00
pub fn get_account_info ( & self , pubkey : Pubkey ) -> Result < Account > {
2018-09-20 23:27:06 -06:00
self . bank
. get_account ( & pubkey )
2018-09-24 13:26:47 -06:00
. ok_or_else ( Error ::invalid_request )
2018-09-20 23:27:06 -06:00
}
2018-08-20 14:20:20 -07:00
fn get_balance ( & self , pubkey : Pubkey ) -> Result < i64 > {
2018-08-15 12:41:39 -06:00
let val = self . bank . get_balance ( & pubkey ) ;
2018-08-20 14:20:20 -07:00
Ok ( val )
2018-08-15 12:41:39 -06:00
}
fn get_finality ( & self ) -> Result < usize > {
Ok ( self . bank . finality ( ) )
}
fn get_last_id ( & self ) -> Result < String > {
let id = self . bank . last_id ( ) ;
Ok ( bs58 ::encode ( id ) . into_string ( ) )
}
2018-10-10 14:51:43 -06:00
pub fn get_signature_status ( & self , signature : Signature ) -> result ::Result < ( ) , BankError > {
2018-09-26 17:12:40 -07:00
self . bank . get_signature_status ( & signature )
2018-08-15 12:41:39 -06:00
}
fn get_transaction_count ( & self ) -> Result < u64 > {
Ok ( self . bank . transaction_count ( ) as u64 )
2018-08-10 17:05:23 -06:00
}
}
2018-08-13 11:24:39 -06:00
2018-10-12 14:25:56 -06:00
fn get_leader_addr ( cluster_info : & Arc < RwLock < ClusterInfo > > ) -> Result < SocketAddr > {
if let Some ( leader_data ) = cluster_info . read ( ) . unwrap ( ) . leader_data ( ) {
Ok ( leader_data . contact_info . tpu )
} else {
Err ( Error {
code : ErrorCode ::InternalError ,
message : " No leader detected " . into ( ) ,
data : None ,
} )
}
}
2018-10-15 11:01:40 -06:00
fn verify_pubkey ( input : String ) -> Result < Pubkey > {
let pubkey_vec = bs58 ::decode ( input )
. into_vec ( )
. map_err ( | _ | Error ::invalid_request ( ) ) ? ;
if pubkey_vec . len ( ) ! = mem ::size_of ::< Pubkey > ( ) {
Err ( Error ::invalid_request ( ) )
} else {
Ok ( Pubkey ::new ( & pubkey_vec ) )
}
}
fn verify_signature ( input : String ) -> Result < Signature > {
let signature_vec = bs58 ::decode ( input )
. into_vec ( )
. map_err ( | _ | Error ::invalid_request ( ) ) ? ;
if signature_vec . len ( ) ! = mem ::size_of ::< Signature > ( ) {
Err ( Error ::invalid_request ( ) )
} else {
Ok ( Signature ::new ( & signature_vec ) )
}
}
2018-08-13 11:24:39 -06:00
#[ cfg(test) ]
mod tests {
use super ::* ;
use bank ::Bank ;
2018-10-15 11:01:40 -06:00
use bincode ::serialize ;
use cluster_info ::{ Node , NodeInfo } ;
use fullnode ::Fullnode ;
use hash ::{ hash , Hash } ;
2018-08-13 13:59:04 -06:00
use jsonrpc_core ::Response ;
2018-10-15 11:01:40 -06:00
use leader_scheduler ::LeaderScheduler ;
2018-10-17 13:42:54 -07:00
use ledger ::create_tmp_ledger_with_mint ;
2018-08-13 11:24:39 -06:00
use mint ::Mint ;
2018-10-15 11:01:40 -06:00
use reqwest ;
use reqwest ::header ::CONTENT_TYPE ;
2018-08-13 11:24:39 -06:00
use signature ::{ Keypair , KeypairUtil } ;
2018-10-15 11:01:40 -06:00
use std ::fs ::remove_dir_all ;
2018-08-22 11:54:37 -06:00
use std ::net ::{ IpAddr , Ipv4Addr , SocketAddr } ;
2018-09-26 10:07:53 -06:00
use system_transaction ::SystemTransaction ;
use transaction ::Transaction ;
2018-08-13 11:24:39 -06:00
2018-10-15 11:01:40 -06:00
fn start_rpc_handler_with_tx ( pubkey : Pubkey ) -> ( MetaIoHandler < Meta > , Meta , Hash , Keypair ) {
2018-08-13 11:24:39 -06:00
let alice = Mint ::new ( 10_000 ) ;
2018-08-14 18:03:48 -06:00
let bank = Bank ::new ( & alice ) ;
let last_id = bank . last_id ( ) ;
2018-10-15 11:01:40 -06:00
let tx = Transaction ::system_move ( & alice . keypair ( ) , pubkey , 20 , last_id , 0 ) ;
2018-08-14 18:03:48 -06:00
bank . process_transaction ( & tx ) . expect ( " process transaction " ) ;
let request_processor = JsonRpcRequestProcessor ::new ( Arc ::new ( bank ) ) ;
2018-10-12 14:25:56 -06:00
let cluster_info = Arc ::new ( RwLock ::new (
ClusterInfo ::new ( NodeInfo ::new_unspecified ( ) ) . unwrap ( ) ,
) ) ;
2018-10-15 11:01:40 -06:00
let leader = NodeInfo ::new_with_socketaddr ( & socketaddr! ( " 127.0.0.1:1234 " ) ) ;
cluster_info . write ( ) . unwrap ( ) . insert ( & leader ) ;
cluster_info . write ( ) . unwrap ( ) . set_leader ( leader . id ) ;
2018-10-10 14:51:43 -06:00
let rpc_addr = SocketAddr ::new ( IpAddr ::V4 ( Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 0 ) ;
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
2018-08-13 11:24:39 -06:00
let mut io = MetaIoHandler ::default ( ) ;
let rpc = RpcSolImpl ;
io . extend_with ( rpc . to_delegate ( ) ) ;
2018-08-22 11:54:37 -06:00
let meta = Meta {
request_processor ,
2018-10-12 14:25:56 -06:00
cluster_info ,
2018-10-10 14:51:43 -06:00
rpc_addr ,
exit ,
2018-08-22 11:54:37 -06:00
} ;
2018-10-15 11:01:40 -06:00
( io , meta , last_id , alice . keypair ( ) )
}
#[ test ]
fn test_rpc_new ( ) {
let alice = Mint ::new ( 10_000 ) ;
let bank = Bank ::new ( & alice ) ;
let cluster_info = Arc ::new ( RwLock ::new (
ClusterInfo ::new ( NodeInfo ::new_unspecified ( ) ) . unwrap ( ) ,
) ) ;
let rpc_addr = SocketAddr ::new ( IpAddr ::V4 ( Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 24680 ) ;
let exit = Arc ::new ( AtomicBool ::new ( false ) ) ;
let rpc_service = JsonRpcService ::new ( & Arc ::new ( bank ) , & cluster_info , rpc_addr , exit ) ;
let thread = rpc_service . thread_hdl . thread ( ) ;
assert_eq! ( thread . name ( ) . unwrap ( ) , " solana-jsonrpc " ) ;
let rpc_string = format! ( " http:// {} " , rpc_addr . to_string ( ) ) ;
let client = reqwest ::Client ::new ( ) ;
let request = json! ( {
" jsonrpc " : " 2.0 " ,
" id " : 1 ,
" method " : " getBalance " ,
" params " : vec ! [ alice . pubkey ( ) . to_string ( ) ] ,
} ) ;
let mut response = client
. post ( & rpc_string )
. header ( CONTENT_TYPE , " application/json " )
. body ( request . to_string ( ) )
. send ( )
. unwrap ( ) ;
let json : Value = serde_json ::from_str ( & response . text ( ) . unwrap ( ) ) . unwrap ( ) ;
assert_eq! ( 10_000 , json [ " result " ] . as_u64 ( ) . unwrap ( ) ) ;
}
#[ test ]
fn test_rpc_request_processor_new ( ) {
let alice = Mint ::new ( 10_000 ) ;
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let bank = Bank ::new ( & alice ) ;
let arc_bank = Arc ::new ( bank ) ;
let request_processor = JsonRpcRequestProcessor ::new ( arc_bank . clone ( ) ) ;
thread ::spawn ( move | | {
let last_id = arc_bank . last_id ( ) ;
let tx = Transaction ::system_move ( & alice . keypair ( ) , bob_pubkey , 20 , last_id , 0 ) ;
arc_bank
. process_transaction ( & tx )
. expect ( " process transaction " ) ;
} ) . join ( )
. unwrap ( ) ;
assert_eq! ( request_processor . get_transaction_count ( ) . unwrap ( ) , 1 ) ;
}
#[ test ]
fn test_rpc_get_balance ( ) {
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let ( io , meta , _last_id , _alice_keypair ) = start_rpc_handler_with_tx ( bob_pubkey ) ;
2018-08-14 18:03:48 -06:00
2018-08-13 11:24:39 -06:00
let req = format! (
2018-08-15 12:41:39 -06:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getBalance","params":["{}"]}}"# ,
2018-08-13 11:24:39 -06:00
bob_pubkey
) ;
2018-10-15 11:01:40 -06:00
let res = io . handle_request_sync ( & req , meta ) ;
2018-08-20 14:20:20 -07:00
let expected = format! ( r # "{{"jsonrpc":"2.0","result":20,"id":1}}"# ) ;
2018-08-13 11:24:39 -06:00
let expected : Response =
2018-08-14 18:03:48 -06:00
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
2018-08-13 11:24:39 -06:00
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
2018-10-15 11:01:40 -06:00
}
#[ test ]
fn test_rpc_get_tx_count ( ) {
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let ( io , meta , _last_id , _alice_keypair ) = start_rpc_handler_with_tx ( bob_pubkey ) ;
2018-08-13 11:24:39 -06:00
2018-08-15 12:41:39 -06:00
let req = format! ( r # "{{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}}"# ) ;
2018-10-15 11:01:40 -06:00
let res = io . handle_request_sync ( & req , meta ) ;
2018-08-14 18:03:48 -06:00
let expected = format! ( r # "{{"jsonrpc":"2.0","result":1,"id":1}}"# ) ;
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
2018-08-13 11:24:39 -06:00
. expect ( " actual response deserialization " ) ;
2018-08-14 18:03:48 -06:00
assert_eq! ( expected , result ) ;
2018-10-15 11:01:40 -06:00
}
#[ test ]
fn test_rpc_get_account_info ( ) {
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let ( io , meta , _last_id , _alice_keypair ) = start_rpc_handler_with_tx ( bob_pubkey ) ;
2018-09-20 13:20:37 -07:00
let req = format! (
2018-09-20 14:51:17 -07:00
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccountInfo","params":["{}"]}}"# ,
2018-09-20 13:20:37 -07:00
bob_pubkey
) ;
2018-10-15 11:01:40 -06:00
let res = io . handle_request_sync ( & req , meta ) ;
2018-09-20 13:20:37 -07:00
let expected = r #" {
" jsonrpc " :" 2.0 " ,
" result " :{
2018-09-20 20:17:37 -06:00
" program_id " : [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,
2018-09-20 13:20:37 -07:00
" tokens " : 20 ,
2018-10-16 09:43:49 -07:00
" userdata " : [ ] ,
" executable " : false ,
" loader_program_id " : [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ]
2018-09-20 13:20:37 -07:00
} ,
" id " :1 }
" #;
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
2018-10-15 11:01:40 -06:00
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
2018-09-20 13:20:37 -07:00
2018-10-15 11:01:40 -06:00
#[ test ]
fn test_rpc_confirm_tx ( ) {
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let ( io , meta , last_id , alice_keypair ) = start_rpc_handler_with_tx ( bob_pubkey ) ;
let tx = Transaction ::system_move ( & alice_keypair , bob_pubkey , 20 , last_id , 0 ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"confirmTransaction","params":["{}"]}}"# ,
tx . signature
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let expected = format! ( r # "{{"jsonrpc":"2.0","result":true,"id":1}}"# ) ;
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
2018-09-20 13:20:37 -07:00
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
2018-08-13 11:24:39 -06:00
}
2018-10-15 11:01:40 -06:00
2018-08-13 11:24:39 -06:00
#[ test ]
2018-10-15 11:01:40 -06:00
fn test_rpc_get_signature_status ( ) {
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let ( io , meta , last_id , alice_keypair ) = start_rpc_handler_with_tx ( bob_pubkey ) ;
let tx = Transaction ::system_move ( & alice_keypair , bob_pubkey , 20 , last_id , 0 ) ;
2018-08-15 10:37:02 -06:00
2018-10-15 11:01:40 -06:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"# ,
tx . signature
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = format! ( r # "{{"jsonrpc":"2.0","result":"Confirmed","id":1}}"# ) ;
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
2018-08-13 11:24:39 -06:00
2018-10-15 11:01:40 -06:00
// Test getSignatureStatus request on unprocessed tx
let tx = Transaction ::system_move ( & alice_keypair , bob_pubkey , 10 , last_id , 0 ) ;
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getSignatureStatus","params":["{}"]}}"# ,
tx . signature
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let expected = format! ( r # "{{"jsonrpc":"2.0","result":"SignatureNotFound","id":1}}"# ) ;
2018-08-13 11:24:39 -06:00
let expected : Response =
2018-10-15 11:01:40 -06:00
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
#[ test ]
fn test_rpc_get_finality ( ) {
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let ( io , meta , _last_id , _alice_keypair ) = start_rpc_handler_with_tx ( bob_pubkey ) ;
let req = format! ( r # "{{"jsonrpc":"2.0","id":1,"method":"getFinality"}}"# ) ;
let res = io . handle_request_sync ( & req , meta ) ;
let expected = format! ( r # "{{"jsonrpc":"2.0","result":18446744073709551615,"id":1}}"# ) ;
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
2018-08-13 11:24:39 -06:00
2018-10-15 11:01:40 -06:00
#[ test ]
fn test_rpc_get_last_id ( ) {
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let ( io , meta , last_id , _alice_keypair ) = start_rpc_handler_with_tx ( bob_pubkey ) ;
let req = format! ( r # "{{"jsonrpc":"2.0","id":1,"method":"getLastId"}}"# ) ;
let res = io . handle_request_sync ( & req , meta ) ;
let expected = format! ( r # "{{"jsonrpc":"2.0","result":"{}","id":1}}"# , last_id ) ;
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
2018-08-13 11:24:39 -06:00
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
2018-10-15 11:01:40 -06:00
2018-08-13 11:24:39 -06:00
#[ test ]
2018-10-15 11:01:40 -06:00
fn test_rpc_request_airdrop ( ) {
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let ( io , meta , _last_id , _alice_keypair ) = start_rpc_handler_with_tx ( bob_pubkey ) ;
// Expect internal error because no leader is running
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"requestAirdrop","params":["{}", 50]}}"# ,
bob_pubkey
) ;
let res = io . handle_request_sync ( & req , meta ) ;
let expected =
r # "{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error"},"id":1}"# ;
let expected : Response =
serde_json ::from_str ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
#[ test ]
fn test_rpc_send_tx ( ) {
let leader_keypair = Keypair ::new ( ) ;
let leader = Node ::new_localhost_with_pubkey ( leader_keypair . pubkey ( ) ) ;
let alice = Mint ::new ( 10_000_000 ) ;
let bank = Bank ::new ( & alice ) ;
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
let leader_data = leader . info . clone ( ) ;
2018-10-17 13:42:54 -07:00
let ledger_path = create_tmp_ledger_with_mint ( " rpc_send_tx " , & alice ) ;
2018-10-15 11:01:40 -06:00
let last_id = bank . last_id ( ) ;
let tx = Transaction ::system_move ( & alice . keypair ( ) , bob_pubkey , 20 , last_id , 0 ) ;
let serial_tx = serialize ( & tx ) . unwrap ( ) ;
let rpc_port = 22222 ; // Needs to be distinct known number to not conflict with other tests
let genesis_entries = & alice . create_entries ( ) ;
let entry_height = genesis_entries . len ( ) as u64 ;
let server = Fullnode ::new_with_bank (
leader_keypair ,
bank ,
2018-10-18 22:57:48 -07:00
0 ,
2018-10-15 11:01:40 -06:00
entry_height ,
& genesis_entries ,
leader ,
None ,
& ledger_path ,
false ,
LeaderScheduler ::from_bootstrap_leader ( leader_data . id ) ,
Some ( rpc_port ) ,
) ;
sleep ( Duration ::from_millis ( 900 ) ) ;
let client = reqwest ::Client ::new ( ) ;
let request = json! ( {
" jsonrpc " : " 2.0 " ,
" id " : 1 ,
" method " : " sendTransaction " ,
" params " : json ! ( vec! [ serial_tx ] )
} ) ;
let mut rpc_addr = leader_data . contact_info . ncp ;
rpc_addr . set_port ( 22222 ) ;
let rpc_string = format! ( " http:// {} " , rpc_addr . to_string ( ) ) ;
let mut response = client
. post ( & rpc_string )
. header ( CONTENT_TYPE , " application/json " )
. body ( request . to_string ( ) )
. send ( )
. unwrap ( ) ;
let json : Value = serde_json ::from_str ( & response . text ( ) . unwrap ( ) ) . unwrap ( ) ;
let signature = & json [ " result " ] ;
sleep ( Duration ::from_millis ( 500 ) ) ;
let client = reqwest ::Client ::new ( ) ;
let request = json! ( {
" jsonrpc " : " 2.0 " ,
" id " : 1 ,
" method " : " confirmTransaction " ,
" params " : vec ! [ signature ] ,
} ) ;
let mut response = client
. post ( & rpc_string )
. header ( CONTENT_TYPE , " application/json " )
. body ( request . to_string ( ) )
. send ( )
. unwrap ( ) ;
let json : Value = serde_json ::from_str ( & response . text ( ) . unwrap ( ) ) . unwrap ( ) ;
assert_eq! ( true , json [ " result " ] ) ;
server . close ( ) . unwrap ( ) ;
remove_dir_all ( ledger_path ) . unwrap ( ) ;
}
#[ test ]
fn test_rpc_send_bad_tx ( ) {
2018-08-15 10:37:02 -06:00
let alice = Mint ::new ( 10_000 ) ;
let bank = Bank ::new ( & alice ) ;
2018-08-13 11:24:39 -06:00
let mut io = MetaIoHandler ::default ( ) ;
let rpc = RpcSolImpl ;
io . extend_with ( rpc . to_delegate ( ) ) ;
let meta = Meta {
2018-08-15 10:37:02 -06:00
request_processor : JsonRpcRequestProcessor ::new ( Arc ::new ( bank ) ) ,
2018-10-12 14:25:56 -06:00
cluster_info : Arc ::new ( RwLock ::new (
ClusterInfo ::new ( NodeInfo ::new_unspecified ( ) ) . unwrap ( ) ,
) ) ,
2018-10-10 14:51:43 -06:00
rpc_addr : SocketAddr ::new ( IpAddr ::V4 ( Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 0 ) ,
exit : Arc ::new ( AtomicBool ::new ( false ) ) ,
2018-08-13 11:24:39 -06:00
} ;
2018-10-15 11:01:40 -06:00
let req =
r # "{"jsonrpc":"2.0","id":1,"method":"sendTransaction","params":[[0,0,0,0,0,0,0,0]]}"# ;
let res = io . handle_request_sync ( req , meta . clone ( ) ) ;
2018-08-13 11:24:39 -06:00
let expected =
r # "{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":1}"# ;
let expected : Response =
serde_json ::from_str ( expected ) . expect ( " expected response deserialization " ) ;
let result : Response = serde_json ::from_str ( & res . expect ( " actual response " ) )
. expect ( " actual response deserialization " ) ;
assert_eq! ( expected , result ) ;
}
2018-10-15 11:01:40 -06:00
2018-10-12 14:25:56 -06:00
#[ test ]
fn test_rpc_get_leader_addr ( ) {
let cluster_info = Arc ::new ( RwLock ::new (
ClusterInfo ::new ( NodeInfo ::new_unspecified ( ) ) . unwrap ( ) ,
) ) ;
assert_eq! (
get_leader_addr ( & cluster_info ) ,
Err ( Error {
code : ErrorCode ::InternalError ,
message : " No leader detected " . into ( ) ,
data : None ,
} )
) ;
let leader = NodeInfo ::new_with_socketaddr ( & socketaddr! ( " 127.0.0.1:1234 " ) ) ;
cluster_info . write ( ) . unwrap ( ) . insert ( & leader ) ;
cluster_info . write ( ) . unwrap ( ) . set_leader ( leader . id ) ;
assert_eq! (
get_leader_addr ( & cluster_info ) ,
Ok ( socketaddr! ( " 127.0.0.1:1234 " ) )
) ;
}
2018-10-15 11:01:40 -06:00
#[ test ]
fn test_rpc_verify_pubkey ( ) {
let pubkey = Keypair ::new ( ) . pubkey ( ) ;
assert_eq! ( verify_pubkey ( pubkey . to_string ( ) ) . unwrap ( ) , pubkey ) ;
let bad_pubkey = " a1b2c3d4 " ;
assert_eq! (
verify_pubkey ( bad_pubkey . to_string ( ) ) ,
Err ( Error ::invalid_request ( ) )
) ;
}
#[ test ]
fn test_rpc_verify_signature ( ) {
let tx =
Transaction ::system_move ( & Keypair ::new ( ) , Keypair ::new ( ) . pubkey ( ) , 20 , hash ( & [ 0 ] ) , 0 ) ;
assert_eq! (
verify_signature ( tx . signature . to_string ( ) ) . unwrap ( ) ,
tx . signature
) ;
let bad_signature = " a1b2c3d4 " ;
assert_eq! (
verify_signature ( bad_signature . to_string ( ) ) ,
Err ( Error ::invalid_request ( ) )
) ;
}
2018-08-13 11:24:39 -06:00
}