requestAirdrop RPC API is now optional

This commit is contained in:
Michael Vines
2019-03-06 09:26:12 -08:00
parent 516aa44aad
commit 0a4f909566
7 changed files with 38 additions and 43 deletions

View File

@ -125,25 +125,11 @@ impl Fullnode {
keypair.clone(), keypair.clone(),
))); )));
// TODO: The RPC service assumes that there is a drone running on the cluster
// entrypoint, which is a bad assumption.
// See https://github.com/solana-labs/solana/issues/1830 for the removal of drone
// from the RPC API
let drone_addr = {
let mut entrypoint_drone_addr = match entrypoint_info_option {
Some(entrypoint_info_info) => entrypoint_info_info.rpc,
None => node.info.rpc,
};
entrypoint_drone_addr.set_port(solana_drone::drone::DRONE_PORT);
entrypoint_drone_addr
};
let storage_state = StorageState::new(); let storage_state = StorageState::new();
let rpc_service = JsonRpcService::new( let rpc_service = JsonRpcService::new(
&cluster_info, &cluster_info,
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), node.info.rpc.port()), SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), node.info.rpc.port()),
drone_addr,
storage_state.clone(), storage_state.clone(),
config.rpc_config.clone(), config.rpc_config.clone(),
&exit, &exit,

View File

@ -21,15 +21,17 @@ use std::sync::{Arc, RwLock};
use std::thread::sleep; use std::thread::sleep;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
#[derive(Clone)] #[derive(Debug, Clone)]
pub struct JsonRpcConfig { pub struct JsonRpcConfig {
pub enable_fullnode_exit: bool, // Enable the 'fullnodeExit' command pub enable_fullnode_exit: bool, // Enable the 'fullnodeExit' command
pub drone_addr: Option<SocketAddr>,
} }
impl Default for JsonRpcConfig { impl Default for JsonRpcConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
enable_fullnode_exit: false, enable_fullnode_exit: false,
drone_addr: None,
} }
} }
} }
@ -170,7 +172,6 @@ fn verify_signature(input: &str) -> Result<Signature> {
pub struct Meta { pub struct Meta {
pub request_processor: Arc<RwLock<JsonRpcRequestProcessor>>, pub request_processor: Arc<RwLock<JsonRpcRequestProcessor>>,
pub cluster_info: Arc<RwLock<ClusterInfo>>, pub cluster_info: Arc<RwLock<ClusterInfo>>,
pub drone_addr: SocketAddr,
} }
impl Metadata for Meta {} impl Metadata for Meta {}
@ -291,6 +292,14 @@ impl RpcSol for RpcSolImpl {
fn request_airdrop(&self, meta: Self::Metadata, id: String, lamports: u64) -> Result<String> { fn request_airdrop(&self, meta: Self::Metadata, id: String, lamports: u64) -> Result<String> {
trace!("request_airdrop id={} lamports={}", id, lamports); trace!("request_airdrop id={} lamports={}", id, lamports);
let drone_addr = meta
.request_processor
.read()
.unwrap()
.config
.drone_addr
.ok_or_else(Error::invalid_request)?;
let pubkey = verify_pubkey(id)?; let pubkey = verify_pubkey(id)?;
let blockhash = meta let blockhash = meta
@ -299,13 +308,11 @@ impl RpcSol for RpcSolImpl {
.unwrap() .unwrap()
.bank()? .bank()?
.last_blockhash(); .last_blockhash();
let transaction = let transaction = request_airdrop_transaction(&drone_addr, &pubkey, lamports, blockhash)
request_airdrop_transaction(&meta.drone_addr, &pubkey, lamports, blockhash).map_err( .map_err(|err| {
|err| {
info!("request_airdrop_transaction failed: {:?}", err); info!("request_airdrop_transaction failed: {:?}", err);
Error::internal_error() Error::internal_error()
}, })?;;
)?;;
let data = serialize(&transaction).map_err(|err| { let data = serialize(&transaction).map_err(|err| {
info!("request_airdrop: serialize error: {:?}", err); info!("request_airdrop: serialize error: {:?}", err);
@ -412,7 +419,7 @@ mod tests {
use solana_sdk::hash::{hash, Hash}; use solana_sdk::hash::{hash, Hash};
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction::SystemTransaction; use solana_sdk::system_transaction::SystemTransaction;
use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::net::SocketAddr;
use std::thread; use std::thread;
fn start_rpc_handler_with_tx(pubkey: Pubkey) -> (MetaIoHandler<Meta>, Meta, Hash, Keypair) { fn start_rpc_handler_with_tx(pubkey: Pubkey) -> (MetaIoHandler<Meta>, Meta, Hash, Keypair) {
@ -435,7 +442,6 @@ mod tests {
cluster_info.write().unwrap().insert_info(leader.clone()); cluster_info.write().unwrap().insert_info(leader.clone());
cluster_info.write().unwrap().set_leader(leader.id); cluster_info.write().unwrap().set_leader(leader.id);
let drone_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
let mut io = MetaIoHandler::default(); let mut io = MetaIoHandler::default();
let rpc = RpcSolImpl; let rpc = RpcSolImpl;
@ -443,7 +449,6 @@ mod tests {
let meta = Meta { let meta = Meta {
request_processor, request_processor,
cluster_info, cluster_info,
drone_addr,
}; };
(io, meta, blockhash, alice) (io, meta, blockhash, alice)
} }
@ -599,14 +604,14 @@ mod tests {
let bob_pubkey = Keypair::new().pubkey(); let bob_pubkey = Keypair::new().pubkey();
let (io, meta, _blockhash, _alice) = start_rpc_handler_with_tx(bob_pubkey); let (io, meta, _blockhash, _alice) = start_rpc_handler_with_tx(bob_pubkey);
// Expect internal error because no leader is running // Expect internal error because no drone is available
let req = format!( let req = format!(
r#"{{"jsonrpc":"2.0","id":1,"method":"requestAirdrop","params":["{}", 50]}}"#, r#"{{"jsonrpc":"2.0","id":1,"method":"requestAirdrop","params":["{}", 50]}}"#,
bob_pubkey bob_pubkey
); );
let res = io.handle_request_sync(&req, meta); let res = io.handle_request_sync(&req, meta);
let expected = let expected =
r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"Internal error"},"id":1}"#; r#"{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":1}"#;
let expected: Response = let expected: Response =
serde_json::from_str(expected).expect("expected response deserialization"); serde_json::from_str(expected).expect("expected response deserialization");
let result: Response = serde_json::from_str(&res.expect("actual response")) let result: Response = serde_json::from_str(&res.expect("actual response"))
@ -634,7 +639,6 @@ mod tests {
Arc::new(RwLock::new(request_processor)) Arc::new(RwLock::new(request_processor))
}, },
cluster_info: Arc::new(RwLock::new(ClusterInfo::new(NodeInfo::default()))), cluster_info: Arc::new(RwLock::new(ClusterInfo::new(NodeInfo::default()))),
drone_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0),
}; };
let req = let req =

View File

@ -24,12 +24,12 @@ impl JsonRpcService {
pub fn new( pub fn new(
cluster_info: &Arc<RwLock<ClusterInfo>>, cluster_info: &Arc<RwLock<ClusterInfo>>,
rpc_addr: SocketAddr, rpc_addr: SocketAddr,
drone_addr: SocketAddr,
storage_state: StorageState, storage_state: StorageState,
config: JsonRpcConfig, config: JsonRpcConfig,
exit: &Arc<AtomicBool>, exit: &Arc<AtomicBool>,
) -> Self { ) -> Self {
info!("rpc bound to {:?}", rpc_addr); info!("rpc bound to {:?}", rpc_addr);
info!("rpc configuration: {:?}", config);
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new( let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
storage_state, storage_state,
config, config,
@ -51,7 +51,6 @@ impl JsonRpcService {
ServerBuilder::with_meta_extractor(io, move |_req: &hyper::Request<hyper::Body>| Meta { ServerBuilder::with_meta_extractor(io, move |_req: &hyper::Request<hyper::Body>| Meta {
request_processor: request_processor_.clone(), request_processor: request_processor_.clone(),
cluster_info: info.clone(), cluster_info: info.clone(),
drone_addr,
}).threads(4) }).threads(4)
.cors(DomainsValidation::AllowOnly(vec![ .cors(DomainsValidation::AllowOnly(vec![
AccessControlAllowOrigin::Any, AccessControlAllowOrigin::Any,
@ -105,14 +104,9 @@ mod tests {
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
solana_netutil::find_available_port_in_range((10000, 65535)).unwrap(), solana_netutil::find_available_port_in_range((10000, 65535)).unwrap(),
); );
let drone_addr = SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
solana_netutil::find_available_port_in_range((10000, 65535)).unwrap(),
);
let mut rpc_service = JsonRpcService::new( let mut rpc_service = JsonRpcService::new(
&cluster_info, &cluster_info,
rpc_addr, rpc_addr,
drone_addr,
StorageState::default(), StorageState::default(),
JsonRpcConfig::default(), JsonRpcConfig::default(),
&exit, &exit,

View File

@ -169,6 +169,13 @@ fn main() {
.takes_value(false) .takes_value(false)
.help("Enable the JSON RPC 'fullnodeExit' API. Only enable in a debug environment"), .help("Enable the JSON RPC 'fullnodeExit' API. Only enable in a debug environment"),
) )
.arg(
Arg::with_name("rpc_drone_address")
.long("rpc-drone-address")
.value_name("HOST:PORT")
.takes_value(true)
.help("Enable the JSON RPC 'requestAirdrop' API with this drone address."),
)
.arg( .arg(
Arg::with_name("signer") Arg::with_name("signer")
.short("s") .short("s")
@ -219,6 +226,9 @@ fn main() {
if matches.is_present("enable_rpc_exit") { if matches.is_present("enable_rpc_exit") {
fullnode_config.rpc_config.enable_fullnode_exit = true; fullnode_config.rpc_config.enable_fullnode_exit = true;
} }
fullnode_config.rpc_config.drone_addr = matches
.value_of("rpc_drone_address")
.map(|address| address.parse().expect("failed to parse drone address"));
let gossip_addr = { let gossip_addr = {
let mut addr = solana_netutil::parse_port_or_addr( let mut addr = solana_netutil::parse_port_or_addr(
@ -238,9 +248,10 @@ fn main() {
} else { } else {
fullnode_config.account_paths = None; fullnode_config.account_paths = None;
} }
let cluster_entrypoint = matches let cluster_entrypoint = matches.value_of("network").map(|network| {
.value_of("network") let gossip_addr = network.parse().expect("failed to parse network address");
.map(|network| network.parse().expect("failed to parse network address")); NodeInfo::new_entry_point(&gossip_addr)
});
let (_signer_service, signer_addr) = if let Some(signer_addr) = matches.value_of("signer") { let (_signer_service, signer_addr) = if let Some(signer_addr) = matches.value_of("signer") {
( (
None, None,
@ -296,9 +307,7 @@ fn main() {
&keypair, &keypair,
ledger_path, ledger_path,
vote_signer, vote_signer,
cluster_entrypoint cluster_entrypoint.as_ref(),
.map(|i| NodeInfo::new_entry_point(&i))
.as_ref(),
&fullnode_config, &fullnode_config,
); );

View File

@ -28,12 +28,12 @@ tune_system
trap 'kill "$pid" && wait "$pid"' INT TERM trap 'kill "$pid" && wait "$pid"' INT TERM
$solana_ledger_tool --ledger "$SOLANA_CONFIG_DIR"/bootstrap-leader-ledger verify $solana_ledger_tool --ledger "$SOLANA_CONFIG_DIR"/bootstrap-leader-ledger verify
# shellcheck disable=SC2086 # Don't want to double quote maybe_blockstream or maybe_init_complete_file
$program \ $program \
--identity "$SOLANA_CONFIG_DIR"/bootstrap-leader-id.json \ --identity "$SOLANA_CONFIG_DIR"/bootstrap-leader-id.json \
--ledger "$SOLANA_CONFIG_DIR"/bootstrap-leader-ledger \ --ledger "$SOLANA_CONFIG_DIR"/bootstrap-leader-ledger \
--accounts "$SOLANA_CONFIG_DIR"/bootstrap-leader-accounts \ --accounts "$SOLANA_CONFIG_DIR"/bootstrap-leader-accounts \
--rpc-port 8899 \ --rpc-port 8899 \
--rpc-drone-address 127.0.0.1:9900 \
"$@" \ "$@" \
> >($bootstrap_leader_logger) 2>&1 & > >($bootstrap_leader_logger) 2>&1 &
pid=$! pid=$!

View File

@ -222,6 +222,7 @@ $program \
--network "$leader_address" \ --network "$leader_address" \
--ledger "$ledger_config_dir" \ --ledger "$ledger_config_dir" \
--accounts "$accounts_config_dir" \ --accounts "$accounts_config_dir" \
--rpc-drone-address "${leader_address%:*}:9900" \
"${extra_fullnode_args[@]}" \ "${extra_fullnode_args[@]}" \
> >($fullnode_logger) 2>&1 & > >($fullnode_logger) 2>&1 &
pid=$! pid=$!

1
run.sh
View File

@ -55,6 +55,7 @@ args=(
--identity "$dataDir"/config/leader-keypair.json --identity "$dataDir"/config/leader-keypair.json
--ledger "$dataDir"/ledger/ --ledger "$dataDir"/ledger/
--rpc-port 8899 --rpc-port 8899
--rpc-drone-address 127.0.0.1:9900
) )
if [[ -n $blockstreamSocket ]]; then if [[ -n $blockstreamSocket ]]; then
args+=(--blockstream "$blockstreamSocket") args+=(--blockstream "$blockstreamSocket")