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-20 13:20:37 -07:00
use bank ::{ Account , Bank } ;
2018-08-22 11:53:24 -06:00
use bincode ::deserialize ;
2018-08-10 17:05:23 -06:00
use bs58 ;
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-08-14 18:03:48 -06:00
use signature ::{ Pubkey , Signature } ;
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-10 22:41:44 -07:00
use std ::sync ::atomic ::{ AtomicBool , Ordering } ;
2018-08-14 18:03:48 -06:00
use std ::sync ::Arc ;
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-08-22 11:53:24 -06:00
transactions_addr : SocketAddr ,
2018-08-22 11:54:37 -06:00
drone_addr : SocketAddr ,
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-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 =
ServerBuilder ::with_meta_extractor ( io , move | _req : & hyper ::Request | Meta {
request_processor : request_processor . clone ( ) ,
transactions_addr ,
drone_addr ,
} ) . 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 ;
}
loop {
if exit . load ( Ordering ::Relaxed ) {
server . unwrap ( ) . close ( ) ;
break ;
}
sleep ( Duration ::from_millis ( 100 ) ) ;
}
( )
} )
. 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-08-22 11:53:24 -06:00
pub transactions_addr : SocketAddr ,
2018-08-22 11:54:37 -06:00
pub drone_addr : SocketAddr ,
2018-08-10 17:05:23 -06:00
}
impl Metadata for Meta { }
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-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-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-09-20 13:20:37 -07:00
#[ rpc(meta, name = " getAccount " ) ]
fn get_account ( & self , Self ::Metadata , String ) -> Result < Account > ;
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-08-20 14:20:20 -07:00
let signature_vec = bs58 ::decode ( id )
. into_vec ( )
. map_err ( | _ | Error ::invalid_request ( ) ) ? ;
2018-08-10 17:05:23 -06:00
if signature_vec . len ( ) ! = mem ::size_of ::< Signature > ( ) {
2018-08-15 11:44:00 -06:00
return Err ( Error ::invalid_request ( ) ) ;
}
let signature = Signature ::new ( & signature_vec ) ;
2018-08-15 12:41:39 -06:00
meta . request_processor . get_signature_status ( signature )
2018-08-10 17:05:23 -06:00
}
2018-08-20 14:20:20 -07:00
fn get_balance ( & self , meta : Self ::Metadata , id : String ) -> Result < i64 > {
let pubkey_vec = bs58 ::decode ( id )
. into_vec ( )
. map_err ( | _ | Error ::invalid_request ( ) ) ? ;
2018-08-10 17:05:23 -06:00
if pubkey_vec . len ( ) ! = mem ::size_of ::< Pubkey > ( ) {
2018-08-15 11:44:00 -06:00
return Err ( Error ::invalid_request ( ) ) ;
}
let pubkey = Pubkey ::new ( & pubkey_vec ) ;
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-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-09-20 13:20:37 -07:00
fn get_account ( & self , meta : Self ::Metadata , id : String ) -> Result < Account > {
let pubkey_vec = bs58 ::decode ( id )
. into_vec ( )
. map_err ( | _ | Error ::invalid_request ( ) ) ? ;
if pubkey_vec . len ( ) ! = mem ::size_of ::< Pubkey > ( ) {
return Err ( Error ::invalid_request ( ) ) ;
}
let pubkey = Pubkey ::new ( & pubkey_vec ) ;
meta . request_processor . get_account ( pubkey )
}
2018-08-26 22:32:51 -06:00
fn request_airdrop ( & self , meta : Self ::Metadata , id : String , tokens : u64 ) -> Result < String > {
2018-08-22 11:54:37 -06:00
let pubkey_vec = bs58 ::decode ( id )
. into_vec ( )
. map_err ( | _ | Error ::invalid_request ( ) ) ? ;
if pubkey_vec . len ( ) ! = mem ::size_of ::< Pubkey > ( ) {
return Err ( Error ::invalid_request ( ) ) ;
}
let pubkey = Pubkey ::new ( & pubkey_vec ) ;
2018-08-26 22:32:51 -06:00
let signature = request_airdrop ( & meta . drone_addr , & pubkey , tokens )
2018-08-22 11:54:37 -06:00
. map_err ( | _ | Error ::internal_error ( ) ) ? ;
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-08-26 22:32:51 -06:00
signature_status = meta
2018-08-22 12:25:21 -06:00
. request_processor
2018-08-26 22:32:51 -06:00
. get_signature_status ( signature )
2018-08-22 12:25:21 -06:00
. map_err ( | _ | Error ::internal_error ( ) ) ? ;
2018-08-26 22:32:51 -06:00
if signature_status {
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 ( ) ;
transactions_socket
. send_to ( & data , & meta . transactions_addr )
2018-09-18 11:31:21 -07:00
. map_err ( | err | {
debug! ( " send_transaction: send_to error: {:?} " , err ) ;
Error ::internal_error ( )
} ) ? ;
2018-08-22 11:53:24 -06:00
Ok ( bs58 ::encode ( tx . signature ) . into_string ( ) )
}
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-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 ( ) )
}
fn get_signature_status ( & self , signature : Signature ) -> Result < bool > {
Ok ( self . bank . has_signature ( & signature ) )
}
fn get_transaction_count ( & self ) -> Result < u64 > {
Ok ( self . bank . transaction_count ( ) as u64 )
2018-08-10 17:05:23 -06:00
}
2018-09-20 13:20:37 -07:00
fn get_account ( & self , pubkey : Pubkey ) -> Result < Account > {
self . bank
. get_account ( & pubkey )
. ok_or ( Error ::invalid_request ( ) )
}
2018-08-10 17:05:23 -06:00
}
2018-08-13 11:24:39 -06:00
#[ cfg(test) ]
mod tests {
use super ::* ;
use bank ::Bank ;
2018-08-13 13:59:04 -06:00
use jsonrpc_core ::Response ;
2018-08-13 11:24:39 -06:00
use mint ::Mint ;
use signature ::{ Keypair , KeypairUtil } ;
2018-08-22 11:54:37 -06:00
use std ::net ::{ IpAddr , Ipv4Addr , SocketAddr } ;
2018-08-13 11:24:39 -06:00
use std ::sync ::Arc ;
2018-08-14 18:03:48 -06:00
use transaction ::Transaction ;
2018-08-13 11:24:39 -06:00
#[ test ]
fn test_rpc_request ( ) {
let alice = Mint ::new ( 10_000 ) ;
let bob_pubkey = Keypair ::new ( ) . pubkey ( ) ;
2018-08-14 18:03:48 -06:00
let bank = Bank ::new ( & alice ) ;
let last_id = bank . last_id ( ) ;
2018-09-17 13:36:31 -07:00
let tx = Transaction ::system_move ( & alice . keypair ( ) , bob_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-08-22 11:53:24 -06:00
let transactions_addr = SocketAddr ::new ( IpAddr ::V4 ( Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 0 ) ;
2018-08-22 11:54:37 -06:00
let drone_addr = SocketAddr ::new ( IpAddr ::V4 ( Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 0 ) ;
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 ,
transactions_addr ,
drone_addr ,
} ;
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
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
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-08-15 12:41:39 -06:00
let req = format! ( r # "{{"jsonrpc":"2.0","id":1,"method":"getTransactionCount"}}"# ) ;
2018-08-14 18:03:48 -06:00
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = format! ( r # "{{"jsonrpc":"2.0","result":1,"id":1}}"# ) ;
let expected : Response =
serde_json ::from_str ( & expected ) . expect ( " expected response deserialization " ) ;
2018-08-13 11:24:39 -06:00
2018-08-14 18:03:48 -06:00
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-09-20 13:20:37 -07:00
let req = format! (
r # "{{"jsonrpc":"2.0","id":1,"method":"getAccount","params":["{}"]}}"# ,
bob_pubkey
) ;
let res = io . handle_request_sync ( & req , meta . clone ( ) ) ;
let expected = r #" {
" jsonrpc " :" 2.0 " ,
" result " :{
" contract_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 ] ,
" tokens " : 20 ,
" userdata " : [ ]
} ,
" 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
}
#[ test ]
fn test_rpc_request_bad_parameter_type ( ) {
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 ( ) ) ;
2018-08-15 12:41:39 -06:00
let req = r # "{"jsonrpc":"2.0","id":1,"method":"confirmTransaction","params":[1234567890]}"# ;
2018-08-13 11:24:39 -06:00
let meta = Meta {
2018-08-15 10:37:02 -06:00
request_processor : JsonRpcRequestProcessor ::new ( Arc ::new ( bank ) ) ,
2018-08-22 11:53:24 -06:00
transactions_addr : SocketAddr ::new ( IpAddr ::V4 ( Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 0 ) ,
2018-08-22 11:54:37 -06:00
drone_addr : SocketAddr ::new ( IpAddr ::V4 ( Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 0 ) ,
2018-08-13 11:24:39 -06:00
} ;
let res = io . handle_request_sync ( req , meta ) ;
let expected = r # "{"jsonrpc":"2.0","error":{"code":-32602,"message":"Invalid params: invalid type: integer `1234567890`, expected a string."},"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 ]
2018-08-14 18:03:48 -06:00
fn test_rpc_request_bad_signature ( ) {
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 req =
2018-08-15 12:41:39 -06:00
r # "{"jsonrpc":"2.0","id":1,"method":"confirmTransaction","params":["a1b2c3d4e5"]}"# ;
2018-08-13 11:24:39 -06:00
let meta = Meta {
2018-08-15 10:37:02 -06:00
request_processor : JsonRpcRequestProcessor ::new ( Arc ::new ( bank ) ) ,
2018-08-22 11:53:24 -06:00
transactions_addr : SocketAddr ::new ( IpAddr ::V4 ( Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 0 ) ,
2018-08-22 11:54:37 -06:00
drone_addr : SocketAddr ::new ( IpAddr ::V4 ( Ipv4Addr ::new ( 0 , 0 , 0 , 0 ) ) , 0 ) ,
2018-08-13 11:24:39 -06:00
} ;
let res = io . handle_request_sync ( req , meta ) ;
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 ) ;
}
}