-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(rpc): add an rpc server to Zebra (#3589)
* feature(rpc): add an rpc component * feat(rpc): add a stub for getblockchaininfo This is the first RPC used by lightwalletd, so we need it for testing. * fix(rpc): remove non-standard "jsonrpc: 1.0" from lightwalletd * fix(rpc): re-enable default RPC security checks * deps(rpc): remove not needed dependency * fix(rpc): check if RPC task has stopped * fix(rpc): reduce config by using Option * fix(rpc): use tokio executor * security(rpc): turn off rpc by default * docs(rpc): update a TODO comment Co-authored-by: teor <[email protected]> * fix(rpc): blocking tasks Co-authored-by: teor <[email protected]> * rename(rpc): rpc.rs to methods.rs * refactor(rpc): move the server to the zebra-rpc crate * fix(rpc): clippy derive Default for RPC Config * fix(dependencies): remove unused dependency features in zebra-rpc We expect to use all the listed tokio features to implement and test RPC methods. * doc(rpc): fix testnet port, add security note * fix(rpc): change Rust function names and update method doc TODOs * fix(rpc): add "TODO" to fake RPC responses * doc(rpc): update module docs * fix(rpc): simplify server struct derives * fix(rpc): simplify server code * doc(rpc): explain how request fixes securely handle user-supplied data * refactor(rpc): move the compatibility fix to a separate module * fix(rpc): move the open log inside the spawn, and instrument it * doc(rpc): fix toml format and provide a config example Co-authored-by: teor <[email protected]>
- Loading branch information
1 parent
7e585b0
commit 8e36686
Showing
10 changed files
with
401 additions
and
1 deletion.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
//! User-configurable RPC settings. | ||
use std::net::SocketAddr; | ||
|
||
use serde::{Deserialize, Serialize}; | ||
|
||
/// RPC configuration section. | ||
#[derive(Clone, Debug, Default, Deserialize, Serialize)] | ||
#[serde(deny_unknown_fields, default)] | ||
pub struct Config { | ||
/// IP address and port for the RPC server. | ||
/// | ||
/// Note: The RPC server is disabled by default. | ||
/// To enable the RPC server, set a listen address in the config: | ||
/// ```toml | ||
/// [rpc] | ||
/// listen_addr = '127.0.0.1:8232' | ||
/// ``` | ||
/// | ||
/// The recommended ports for the RPC server are: | ||
/// - Mainnet: 127.0.0.1:8232 | ||
/// - Testnet: 127.0.0.1:18232 | ||
/// | ||
/// # Security | ||
/// | ||
/// If you bind Zebra's RPC port to a public IP address, | ||
/// anyone on the internet can send transactions via your node. | ||
/// They can also query your node's state. | ||
pub listen_addr: Option<SocketAddr>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
//! A Zebra remote procedure call interface | ||
//! A Zebra Remote Procedure Call (RPC) interface | ||
#![doc(html_favicon_url = "https://www.zfnd.org/images/zebra-favicon-128.png")] | ||
#![doc(html_logo_url = "https://www.zfnd.org/images/zebra-icon.png")] | ||
#![doc(html_root_url = "https://doc.zebra.zfnd.org/zebra_rpc")] | ||
|
||
pub mod config; | ||
pub mod methods; | ||
pub mod server; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
//! Zebra supported RPC methods. | ||
//! | ||
//! Based on the [`zcashd` RPC methods](https://zcash.github.io/rpc/) | ||
//! as used by `lightwalletd.` | ||
//! | ||
//! Some parts of the `zcashd` RPC documentation are outdated. | ||
//! So this implementation follows the `lightwalletd` client implementation. | ||
use jsonrpc_core::{self, Result}; | ||
use jsonrpc_derive::rpc; | ||
|
||
#[rpc(server)] | ||
/// RPC method signatures. | ||
pub trait Rpc { | ||
/// getinfo | ||
/// | ||
/// TODO: explain what the method does | ||
/// link to the zcashd RPC reference | ||
/// list the arguments and fields that lightwalletd uses | ||
/// note any other lightwalletd changes | ||
#[rpc(name = "getinfo")] | ||
fn get_info(&self) -> Result<GetInfo>; | ||
|
||
/// getblockchaininfo | ||
/// | ||
/// TODO: explain what the method does | ||
/// link to the zcashd RPC reference | ||
/// list the arguments and fields that lightwalletd uses | ||
/// note any other lightwalletd changes | ||
#[rpc(name = "getblockchaininfo")] | ||
fn get_blockchain_info(&self) -> Result<GetBlockChainInfo>; | ||
} | ||
|
||
/// RPC method implementations. | ||
pub struct RpcImpl; | ||
impl Rpc for RpcImpl { | ||
fn get_info(&self) -> Result<GetInfo> { | ||
// TODO: dummy output data, fix in the context of #3142 | ||
let response = GetInfo { | ||
build: "TODO: Zebra v1.0.0 ...".into(), | ||
subversion: "TODO: /Zebra:1.0.0-beta.../".into(), | ||
}; | ||
|
||
Ok(response) | ||
} | ||
|
||
fn get_blockchain_info(&self) -> Result<GetBlockChainInfo> { | ||
// TODO: dummy output data, fix in the context of #3143 | ||
let response = GetBlockChainInfo { | ||
chain: "TODO: main".to_string(), | ||
}; | ||
|
||
Ok(response) | ||
} | ||
} | ||
|
||
#[derive(serde::Serialize, serde::Deserialize)] | ||
/// Response to a `getinfo` RPC request. | ||
pub struct GetInfo { | ||
build: String, | ||
subversion: String, | ||
} | ||
|
||
#[derive(serde::Serialize, serde::Deserialize)] | ||
/// Response to a `getblockchaininfo` RPC request. | ||
pub struct GetBlockChainInfo { | ||
chain: String, | ||
// TODO: add other fields used by lightwalletd (#3143) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
//! A JSON-RPC 1.0 & 2.0 endpoint for Zebra. | ||
//! | ||
//! This endpoint is compatible with clients that incorrectly send | ||
//! `"jsonrpc" = 1.0` fields in JSON-RPC 1.0 requests, | ||
//! such as `lightwalletd`. | ||
use tracing::*; | ||
use tracing_futures::Instrument; | ||
|
||
use jsonrpc_core; | ||
use jsonrpc_http_server::ServerBuilder; | ||
|
||
use crate::{ | ||
config::Config, | ||
methods::{Rpc, RpcImpl}, | ||
server::compatibility::FixHttpRequestMiddleware, | ||
}; | ||
|
||
pub mod compatibility; | ||
|
||
/// Zebra RPC Server | ||
#[derive(Clone, Debug)] | ||
pub struct RpcServer; | ||
|
||
impl RpcServer { | ||
/// Start a new RPC server endpoint | ||
pub fn spawn(config: Config) -> tokio::task::JoinHandle<()> { | ||
if let Some(listen_addr) = config.listen_addr { | ||
info!("Trying to open RPC endpoint at {}...", listen_addr,); | ||
|
||
// Create handler compatible with V1 and V2 RPC protocols | ||
let mut io = | ||
jsonrpc_core::IoHandler::with_compatibility(jsonrpc_core::Compatibility::Both); | ||
io.extend_with(RpcImpl.to_delegate()); | ||
|
||
let server = ServerBuilder::new(io) | ||
// use the same tokio executor as the rest of Zebra | ||
.event_loop_executor(tokio::runtime::Handle::current()) | ||
.threads(1) | ||
// TODO: disable this security check if we see errors from lightwalletd. | ||
//.allowed_hosts(DomainsValidation::Disabled) | ||
.request_middleware(FixHttpRequestMiddleware) | ||
.start_http(&listen_addr) | ||
.expect("Unable to start RPC server"); | ||
|
||
// The server is a blocking task, so we need to spawn it on a blocking thread. | ||
let span = Span::current(); | ||
let server = move || { | ||
span.in_scope(|| { | ||
info!("Opened RPC endpoint at {}", server.address()); | ||
|
||
server.wait(); | ||
|
||
info!("Stopping RPC endpoint"); | ||
}) | ||
}; | ||
tokio::task::spawn_blocking(server) | ||
} else { | ||
// There is no RPC port, so the RPC task does nothing. | ||
tokio::task::spawn(futures::future::pending().in_current_span()) | ||
} | ||
} | ||
} |
Oops, something went wrong.