requestAirdrop RPC API is now optional
This commit is contained in:
@ -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,
|
||||||
|
@ -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 =
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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=$!
|
||||||
|
@ -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
1
run.sh
@ -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")
|
||||||
|
Reference in New Issue
Block a user