Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

requestAirdrop RPC API is now optional #3152

Merged
merged 4 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 1 addition & 18 deletions core/src/fullnode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,25 +125,11 @@ impl Fullnode {
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 rpc_service = JsonRpcService::new(
&cluster_info,
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), node.info.rpc.port()),
drone_addr,
storage_state.clone(),
config.rpc_config.clone(),
&exit,
Expand Down Expand Up @@ -237,10 +223,7 @@ impl Fullnode {
}
let bank = bank_forks_.read().unwrap().working_bank();
trace!("rpc working bank {} {}", bank.slot(), bank.last_blockhash());
rpc_service_rp
.write()
.unwrap()
.set_bank(&bank_forks_.read().unwrap().working_bank());
rpc_service_rp.write().unwrap().set_bank(&bank);
let timer = Duration::from_millis(100);
sleep(timer);
});
Expand Down
3 changes: 1 addition & 2 deletions core/src/local_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,6 @@ impl Drop for LocalCluster {
#[cfg(test)]
mod test {
use super::*;
use crate::rpc::JsonRpcConfig;

#[test]
fn test_local_cluster_start_and_exit() {
Expand All @@ -224,7 +223,7 @@ mod test {
fn test_local_cluster_start_and_exit_with_config() {
solana_logger::setup();
let mut fullnode_exit = FullnodeConfig::default();
fullnode_exit.rpc_config = JsonRpcConfig::TestOnlyAllowRpcFullnodeExit;
fullnode_exit.rpc_config.enable_fullnode_exit = true;
let cluster = LocalCluster::new_with_config(1, 100, 3, &fullnode_exit);
drop(cluster)
}
Expand Down
84 changes: 35 additions & 49 deletions core/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@ use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::{Duration, Instant};

#[derive(Clone)]
pub enum JsonRpcConfig {
DefaultConfig,
TestOnlyAllowRpcFullnodeExit,
#[derive(Debug, Clone)]
pub struct JsonRpcConfig {
pub enable_fullnode_exit: bool, // Enable the 'fullnodeExit' command
pub drone_addr: Option<SocketAddr>,
}

impl Default for JsonRpcConfig {
fn default() -> Self {
JsonRpcConfig::DefaultConfig
Self {
enable_fullnode_exit: false,
drone_addr: None,
}
}
}

Expand Down Expand Up @@ -110,16 +113,13 @@ impl JsonRpcRequestProcessor {
}

pub fn fullnode_exit(&self) -> Result<bool> {
match self.config {
JsonRpcConfig::DefaultConfig => {
debug!("default config, fullnode_exit ignored");
Ok(false)
}
JsonRpcConfig::TestOnlyAllowRpcFullnodeExit => {
warn!("TEST_ONLY JsonRPC fullnode_exit request...");
self.fullnode_exit.store(true, Ordering::Relaxed);
Ok(true)
}
if self.config.enable_fullnode_exit {
warn!("fullnode_exit request...");
self.fullnode_exit.store(true, Ordering::Relaxed);
Ok(true)
} else {
debug!("fullnode_exit ignored");
Ok(false)
}
}
}
Expand Down Expand Up @@ -172,8 +172,6 @@ fn verify_signature(input: &str) -> Result<Signature> {
pub struct Meta {
pub request_processor: Arc<RwLock<JsonRpcRequestProcessor>>,
pub cluster_info: Arc<RwLock<ClusterInfo>>,
pub rpc_addr: SocketAddr,
pub drone_addr: SocketAddr,
}
impl Metadata for Meta {}

Expand Down Expand Up @@ -294,6 +292,14 @@ impl RpcSol for RpcSolImpl {

fn request_airdrop(&self, meta: Self::Metadata, id: String, lamports: u64) -> Result<String> {
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 blockhash = meta
Expand All @@ -302,13 +308,11 @@ impl RpcSol for RpcSolImpl {
.unwrap()
.bank()?
.last_blockhash();
let transaction =
request_airdrop_transaction(&meta.drone_addr, &pubkey, lamports, blockhash).map_err(
|err| {
info!("request_airdrop_transaction failed: {:?}", err);
Error::internal_error()
},
)?;;
let transaction = request_airdrop_transaction(&drone_addr, &pubkey, lamports, blockhash)
.map_err(|err| {
info!("request_airdrop_transaction failed: {:?}", err);
Error::internal_error()
})?;;

let data = serialize(&transaction).map_err(|err| {
info!("request_airdrop: serialize error: {:?}", err);
Expand Down Expand Up @@ -415,7 +419,7 @@ mod tests {
use solana_sdk::hash::{hash, Hash};
use solana_sdk::signature::{Keypair, KeypairUtil};
use solana_sdk::system_transaction::SystemTransaction;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::net::SocketAddr;
use std::thread;

fn start_rpc_handler_with_tx(pubkey: Pubkey) -> (MetaIoHandler<Meta>, Meta, Hash, Keypair) {
Expand All @@ -438,17 +442,13 @@ mod tests {

cluster_info.write().unwrap().insert_info(leader.clone());
cluster_info.write().unwrap().set_leader(leader.id);
let rpc_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);
let drone_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0);

let mut io = MetaIoHandler::default();
let rpc = RpcSolImpl;
io.extend_with(rpc.to_delegate());
let meta = Meta {
request_processor,
cluster_info,
drone_addr,
rpc_addr,
};
(io, meta, blockhash, alice)
}
Expand Down Expand Up @@ -604,14 +604,14 @@ mod tests {
let bob_pubkey = Keypair::new().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!(
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}"#;
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"))
Expand Down Expand Up @@ -639,8 +639,6 @@ mod tests {
Arc::new(RwLock::new(request_processor))
},
cluster_info: Arc::new(RwLock::new(ClusterInfo::new(NodeInfo::default()))),
drone_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0),
rpc_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0),
};

let req =
Expand Down Expand Up @@ -714,26 +712,14 @@ mod tests {
assert_eq!(request_processor.fullnode_exit(), Ok(false));
assert_eq!(exit.load(Ordering::Relaxed), false);
}
#[test]
fn test_rpc_request_processor_default_config_fullnode_exit_fails() {
let exit = Arc::new(AtomicBool::new(false));
let request_processor = JsonRpcRequestProcessor::new(
StorageState::default(),
JsonRpcConfig::DefaultConfig,
&exit,
);
assert_eq!(request_processor.fullnode_exit(), Ok(false));
assert_eq!(exit.load(Ordering::Relaxed), false);
}

#[test]
fn test_rpc_request_processor_allow_fullnode_exit_config() {
let exit = Arc::new(AtomicBool::new(false));
let request_processor = JsonRpcRequestProcessor::new(
StorageState::default(),
JsonRpcConfig::TestOnlyAllowRpcFullnodeExit,
&exit,
);
let mut config = JsonRpcConfig::default();
config.enable_fullnode_exit = true;
let request_processor =
JsonRpcRequestProcessor::new(StorageState::default(), config, &exit);
assert_eq!(request_processor.fullnode_exit(), Ok(true));
assert_eq!(exit.load(Ordering::Relaxed), true);
}
Expand Down
9 changes: 1 addition & 8 deletions core/src/rpc_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ impl JsonRpcService {
pub fn new(
cluster_info: &Arc<RwLock<ClusterInfo>>,
rpc_addr: SocketAddr,
drone_addr: SocketAddr,
storage_state: StorageState,
config: JsonRpcConfig,
exit: &Arc<AtomicBool>,
) -> Self {
info!("rpc bound to {:?}", rpc_addr);
info!("rpc configuration: {:?}", config);
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
storage_state,
config,
Expand All @@ -51,8 +51,6 @@ impl JsonRpcService {
ServerBuilder::with_meta_extractor(io, move |_req: &hyper::Request<hyper::Body>| Meta {
request_processor: request_processor_.clone(),
cluster_info: info.clone(),
drone_addr,
rpc_addr,
}).threads(4)
.cors(DomainsValidation::AllowOnly(vec![
AccessControlAllowOrigin::Any,
Expand Down Expand Up @@ -106,14 +104,9 @@ mod tests {
IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
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(
&cluster_info,
rpc_addr,
drone_addr,
StorageState::default(),
JsonRpcConfig::default(),
&exit,
Expand Down
23 changes: 16 additions & 7 deletions fullnode/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ fn main() {
.takes_value(false)
.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::with_name("signer")
.short("s")
Expand Down Expand Up @@ -217,8 +224,11 @@ fn main() {
let use_only_bootstrap_leader = matches.is_present("no_leader_rotation");

if matches.is_present("enable_rpc_exit") {
fullnode_config.rpc_config = solana::rpc::JsonRpcConfig::TestOnlyAllowRpcFullnodeExit;
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 mut addr = solana_netutil::parse_port_or_addr(
Expand All @@ -238,9 +248,10 @@ fn main() {
} else {
fullnode_config.account_paths = None;
}
let cluster_entrypoint = matches
.value_of("network")
.map(|network| network.parse().expect("failed to parse network address"));
let cluster_entrypoint = matches.value_of("network").map(|network| {
let gossip_addr = 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") {
(
None,
Expand Down Expand Up @@ -296,9 +307,7 @@ fn main() {
&keypair,
ledger_path,
vote_signer,
cluster_entrypoint
.map(|i| NodeInfo::new_entry_point(&i))
.as_ref(),
cluster_entrypoint.as_ref(),
&fullnode_config,
);

Expand Down
2 changes: 1 addition & 1 deletion multinode-demo/bootstrap-leader.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ tune_system
trap 'kill "$pid" && wait "$pid"' INT TERM
$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 \
--identity "$SOLANA_CONFIG_DIR"/bootstrap-leader-id.json \
--ledger "$SOLANA_CONFIG_DIR"/bootstrap-leader-ledger \
--accounts "$SOLANA_CONFIG_DIR"/bootstrap-leader-accounts \
--rpc-port 8899 \
--rpc-drone-address 127.0.0.1:9900 \
"$@" \
> >($bootstrap_leader_logger) 2>&1 &
pid=$!
Expand Down
1 change: 1 addition & 0 deletions multinode-demo/fullnode.sh
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ $program \
--network "$leader_address" \
--ledger "$ledger_config_dir" \
--accounts "$accounts_config_dir" \
--rpc-drone-address "${leader_address%:*}:9900" \
"${extra_fullnode_args[@]}" \
> >($fullnode_logger) 2>&1 &
pid=$!
Expand Down
1 change: 1 addition & 0 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ args=(
--identity "$dataDir"/config/leader-keypair.json
--ledger "$dataDir"/ledger/
--rpc-port 8899
--rpc-drone-address 127.0.0.1:9900
)
if [[ -n $blockstreamSocket ]]; then
args+=(--blockstream "$blockstreamSocket")
Expand Down
19 changes: 9 additions & 10 deletions tests/local_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ extern crate solana;
use solana::cluster_tests;
use solana::fullnode::FullnodeConfig;
use solana::local_cluster::LocalCluster;
use solana::rpc::JsonRpcConfig;

#[test]
fn test_spend_and_verify_all_nodes_1() {
Expand Down Expand Up @@ -54,18 +53,18 @@ fn test_fullnode_exit_default_config_should_panic() {
fn test_fullnode_exit_2() {
solana_logger::setup();
let num_nodes = 2;
let mut fullnode_exit = FullnodeConfig::default();
fullnode_exit.rpc_config = JsonRpcConfig::TestOnlyAllowRpcFullnodeExit;
let local = LocalCluster::new_with_config(num_nodes, 10_000, 100, &fullnode_exit);
let mut fullnode_config = FullnodeConfig::default();
fullnode_config.rpc_config.enable_fullnode_exit = true;
let local = LocalCluster::new_with_config(num_nodes, 10_000, 100, &fullnode_config);
cluster_tests::fullnode_exit(&local.entry_point_info, num_nodes);
}

#[test]
fn test_leader_failure_2() {
let num_nodes = 2;
let mut fullnode_exit = FullnodeConfig::default();
fullnode_exit.rpc_config = JsonRpcConfig::TestOnlyAllowRpcFullnodeExit;
let local = LocalCluster::new_with_config(num_nodes, 10_000, 100, &fullnode_exit);
let mut fullnode_config = FullnodeConfig::default();
fullnode_config.rpc_config.enable_fullnode_exit = true;
let local = LocalCluster::new_with_config(num_nodes, 10_000, 100, &fullnode_config);
cluster_tests::kill_entry_and_spend_and_verify_rest(
&local.entry_point_info,
&local.funding_keypair,
Expand All @@ -76,9 +75,9 @@ fn test_leader_failure_2() {
#[test]
fn test_leader_failure_3() {
let num_nodes = 3;
let mut fullnode_exit = FullnodeConfig::default();
fullnode_exit.rpc_config = JsonRpcConfig::TestOnlyAllowRpcFullnodeExit;
let local = LocalCluster::new_with_config(num_nodes, 10_000, 100, &fullnode_exit);
let mut fullnode_config = FullnodeConfig::default();
fullnode_config.rpc_config.enable_fullnode_exit = true;
let local = LocalCluster::new_with_config(num_nodes, 10_000, 100, &fullnode_config);
cluster_tests::kill_entry_and_spend_and_verify_rest(
&local.entry_point_info,
&local.funding_keypair,
Expand Down