refactor(app): De-duplicate and fix version handling code (#6996)
* De-duplicate app_version and user_agent code, rename to build_version * Make RPC testnet flag forward-compatible with additional testnets * Fix RPC tests with new argument * Use "modified" rather than "dirty" for uncommitted changes in build metadata * Split the vergen version into its own function
This commit is contained in:
parent
fba9440af0
commit
c3f0f53256
|
@ -59,7 +59,7 @@ pub enum Network {
|
||||||
#[default]
|
#[default]
|
||||||
Mainnet,
|
Mainnet,
|
||||||
|
|
||||||
/// The testnet.
|
/// The oldest public test network.
|
||||||
Testnet,
|
Testnet,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +124,11 @@ impl Network {
|
||||||
pub fn lowercase_name(&self) -> String {
|
pub fn lowercase_name(&self) -> String {
|
||||||
self.to_string().to_ascii_lowercase()
|
self.to_string().to_ascii_lowercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if this network is a testing network.
|
||||||
|
pub fn is_a_test_network(&self) -> bool {
|
||||||
|
*self != Network::Mainnet
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Network {
|
impl FromStr for Network {
|
||||||
|
|
|
@ -251,8 +251,11 @@ where
|
||||||
{
|
{
|
||||||
// Configuration
|
// Configuration
|
||||||
//
|
//
|
||||||
/// Zebra's application version.
|
/// Zebra's application version, with build metadata.
|
||||||
app_version: String,
|
build_version: String,
|
||||||
|
|
||||||
|
/// Zebra's RPC user agent.
|
||||||
|
user_agent: String,
|
||||||
|
|
||||||
/// The configured network for this RPC service.
|
/// The configured network for this RPC service.
|
||||||
network: Network,
|
network: Network,
|
||||||
|
@ -300,8 +303,13 @@ where
|
||||||
Tip: ChainTip + Clone + Send + Sync + 'static,
|
Tip: ChainTip + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
/// Create a new instance of the RPC handler.
|
/// Create a new instance of the RPC handler.
|
||||||
pub fn new<Version>(
|
//
|
||||||
app_version: Version,
|
// TODO:
|
||||||
|
// - put some of the configs or services in their own struct?
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn new<VersionString, UserAgentString>(
|
||||||
|
build_version: VersionString,
|
||||||
|
user_agent: UserAgentString,
|
||||||
network: Network,
|
network: Network,
|
||||||
debug_force_finished_sync: bool,
|
debug_force_finished_sync: bool,
|
||||||
debug_like_zcashd: bool,
|
debug_like_zcashd: bool,
|
||||||
|
@ -310,21 +318,24 @@ where
|
||||||
latest_chain_tip: Tip,
|
latest_chain_tip: Tip,
|
||||||
) -> (Self, JoinHandle<()>)
|
) -> (Self, JoinHandle<()>)
|
||||||
where
|
where
|
||||||
Version: ToString,
|
VersionString: ToString + Clone + Send + 'static,
|
||||||
|
UserAgentString: ToString + Clone + Send + 'static,
|
||||||
<Mempool as Service<mempool::Request>>::Future: Send,
|
<Mempool as Service<mempool::Request>>::Future: Send,
|
||||||
<State as Service<zebra_state::ReadRequest>>::Future: Send,
|
<State as Service<zebra_state::ReadRequest>>::Future: Send,
|
||||||
{
|
{
|
||||||
let (runner, queue_sender) = Queue::start();
|
let (runner, queue_sender) = Queue::start();
|
||||||
|
|
||||||
let mut app_version = app_version.to_string();
|
let mut build_version = build_version.to_string();
|
||||||
|
let user_agent = user_agent.to_string();
|
||||||
|
|
||||||
// Match zcashd's version format, if the version string has anything in it
|
// Match zcashd's version format, if the version string has anything in it
|
||||||
if !app_version.is_empty() && !app_version.starts_with('v') {
|
if !build_version.is_empty() && !build_version.starts_with('v') {
|
||||||
app_version.insert(0, 'v');
|
build_version.insert(0, 'v');
|
||||||
}
|
}
|
||||||
|
|
||||||
let rpc_impl = RpcImpl {
|
let rpc_impl = RpcImpl {
|
||||||
app_version,
|
build_version,
|
||||||
|
user_agent,
|
||||||
network,
|
network,
|
||||||
debug_force_finished_sync,
|
debug_force_finished_sync,
|
||||||
debug_like_zcashd,
|
debug_like_zcashd,
|
||||||
|
@ -364,25 +375,10 @@ where
|
||||||
State::Future: Send,
|
State::Future: Send,
|
||||||
Tip: ChainTip + Clone + Send + Sync + 'static,
|
Tip: ChainTip + Clone + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
#[allow(clippy::unwrap_in_result)]
|
|
||||||
fn get_info(&self) -> Result<GetInfo> {
|
fn get_info(&self) -> Result<GetInfo> {
|
||||||
// Build a [BIP 14] valid user agent with release info.
|
|
||||||
//
|
|
||||||
// [BIP 14]: https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki
|
|
||||||
let release_version = self
|
|
||||||
.app_version
|
|
||||||
// remove everything after the `+` character if any
|
|
||||||
.split('+')
|
|
||||||
.next()
|
|
||||||
.expect("always at least 1 slice");
|
|
||||||
// Remove the previously added `v` character at the start since it's not a part of the user agent.
|
|
||||||
let release_version = release_version.strip_prefix('v').unwrap_or(release_version);
|
|
||||||
|
|
||||||
let user_agent = format!("/Zebra:{release_version}/");
|
|
||||||
|
|
||||||
let response = GetInfo {
|
let response = GetInfo {
|
||||||
build: self.app_version.clone(),
|
build: self.build_version.clone(),
|
||||||
subversion: user_agent,
|
subversion: self.user_agent.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl Response {
|
||||||
networksolps,
|
networksolps,
|
||||||
networkhashps: networksolps,
|
networkhashps: networksolps,
|
||||||
chain: network.bip70_network_name(),
|
chain: network.bip70_network_name(),
|
||||||
testnet: network == Network::Testnet,
|
testnet: network.is_a_test_network(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ proptest! {
|
||||||
let mut mempool = MockService::build().for_prop_tests();
|
let mut mempool = MockService::build().for_prop_tests();
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -94,6 +95,7 @@ proptest! {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -153,6 +155,7 @@ proptest! {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -220,6 +223,7 @@ proptest! {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -276,6 +280,7 @@ proptest! {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -330,6 +335,7 @@ proptest! {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -430,6 +436,7 @@ proptest! {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -488,6 +495,7 @@ proptest! {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -535,6 +543,7 @@ proptest! {
|
||||||
|
|
||||||
// look for an error with a `NoChainTip`
|
// look for an error with a `NoChainTip`
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
network,
|
network,
|
||||||
false,
|
false,
|
||||||
|
@ -585,6 +594,7 @@ proptest! {
|
||||||
|
|
||||||
// Start RPC with the mocked `ChainTip`
|
// Start RPC with the mocked `ChainTip`
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
network,
|
network,
|
||||||
false,
|
false,
|
||||||
|
@ -671,6 +681,7 @@ proptest! {
|
||||||
// Start RPC with the mocked `ChainTip`
|
// Start RPC with the mocked `ChainTip`
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let (rpc, _rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, _rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
network,
|
network,
|
||||||
false,
|
false,
|
||||||
|
@ -734,6 +745,7 @@ proptest! {
|
||||||
// Start RPC with the mocked `ChainTip`
|
// Start RPC with the mocked `ChainTip`
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
let (rpc, _rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, _rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
network,
|
network,
|
||||||
false,
|
false,
|
||||||
|
@ -785,6 +797,7 @@ proptest! {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -874,6 +887,7 @@ proptest! {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_prop_tests();
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -72,6 +72,7 @@ async fn test_rpc_response_data_for_network(network: Network) {
|
||||||
// Init RPC
|
// Init RPC
|
||||||
let (rpc, _rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, _rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
"RPC test",
|
"RPC test",
|
||||||
|
"/Zebra:RPC test/",
|
||||||
network,
|
network,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -29,6 +29,7 @@ async fn rpc_getinfo() {
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
"RPC test",
|
"RPC test",
|
||||||
|
"/Zebra:RPC test/",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
@ -72,6 +73,7 @@ async fn rpc_getblock() {
|
||||||
|
|
||||||
// Init RPC
|
// Init RPC
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -223,6 +225,7 @@ async fn rpc_getblock_parse_error() {
|
||||||
|
|
||||||
// Init RPC
|
// Init RPC
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -265,6 +268,7 @@ async fn rpc_getblock_missing_error() {
|
||||||
|
|
||||||
// Init RPC
|
// Init RPC
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -333,6 +337,7 @@ async fn rpc_getbestblockhash() {
|
||||||
|
|
||||||
// Init RPC
|
// Init RPC
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -378,6 +383,7 @@ async fn rpc_getrawtransaction() {
|
||||||
|
|
||||||
// Init RPC
|
// Init RPC
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -539,6 +545,7 @@ async fn rpc_getaddresstxids_invalid_arguments() {
|
||||||
zebra_state::populated_state(blocks.clone(), Mainnet).await;
|
zebra_state::populated_state(blocks.clone(), Mainnet).await;
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -682,6 +689,7 @@ async fn rpc_getaddresstxids_response_with(
|
||||||
zebra_state::populated_state(blocks.to_owned(), network).await;
|
zebra_state::populated_state(blocks.to_owned(), network).await;
|
||||||
|
|
||||||
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
network,
|
network,
|
||||||
false,
|
false,
|
||||||
|
@ -733,6 +741,7 @@ async fn rpc_getaddressutxos_invalid_arguments() {
|
||||||
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
let mut state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
|
||||||
|
|
||||||
let rpc = RpcImpl::new(
|
let rpc = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
@ -781,6 +790,7 @@ async fn rpc_getaddressutxos_response() {
|
||||||
zebra_state::populated_state(blocks.clone(), Mainnet).await;
|
zebra_state::populated_state(blocks.clone(), Mainnet).await;
|
||||||
|
|
||||||
let rpc = RpcImpl::new(
|
let rpc = RpcImpl::new(
|
||||||
|
"RPC test",
|
||||||
"RPC test",
|
"RPC test",
|
||||||
Mainnet,
|
Mainnet,
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -43,9 +43,16 @@ mod tests;
|
||||||
/// Zebra RPC Server
|
/// Zebra RPC Server
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RpcServer {
|
pub struct RpcServer {
|
||||||
|
/// The RPC config.
|
||||||
config: Config,
|
config: Config,
|
||||||
|
|
||||||
|
/// The configured network.
|
||||||
network: Network,
|
network: Network,
|
||||||
app_version: String,
|
|
||||||
|
/// Zebra's application version, with build metadata.
|
||||||
|
build_version: String,
|
||||||
|
|
||||||
|
/// A handle that shuts down the RPC server.
|
||||||
close_handle: CloseHandle,
|
close_handle: CloseHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +61,7 @@ impl fmt::Debug for RpcServer {
|
||||||
f.debug_struct("RpcServer")
|
f.debug_struct("RpcServer")
|
||||||
.field("config", &self.config)
|
.field("config", &self.config)
|
||||||
.field("network", &self.network)
|
.field("network", &self.network)
|
||||||
.field("app_version", &self.app_version)
|
.field("build_version", &self.build_version)
|
||||||
.field(
|
.field(
|
||||||
"close_handle",
|
"close_handle",
|
||||||
// TODO: when it stabilises, use std::any::type_name_of_val(&self.close_handle)
|
// TODO: when it stabilises, use std::any::type_name_of_val(&self.close_handle)
|
||||||
|
@ -66,21 +73,35 @@ impl fmt::Debug for RpcServer {
|
||||||
|
|
||||||
impl RpcServer {
|
impl RpcServer {
|
||||||
/// Start a new RPC server endpoint using the supplied configs and services.
|
/// Start a new RPC server endpoint using the supplied configs and services.
|
||||||
/// `app_version` is a version string for the application, which is used in RPC responses.
|
///
|
||||||
|
/// `build_version` and `user_agent` are version strings for the application,
|
||||||
|
/// which are used in RPC responses.
|
||||||
///
|
///
|
||||||
/// Returns [`JoinHandle`]s for the RPC server and `sendrawtransaction` queue tasks,
|
/// Returns [`JoinHandle`]s for the RPC server and `sendrawtransaction` queue tasks,
|
||||||
/// and a [`RpcServer`] handle, which can be used to shut down the RPC server task.
|
/// and a [`RpcServer`] handle, which can be used to shut down the RPC server task.
|
||||||
//
|
//
|
||||||
// TODO: put some of the configs or services in their own struct?
|
// TODO:
|
||||||
|
// - put some of the configs or services in their own struct?
|
||||||
|
// - replace VersionString with semver::Version, and update the tests to provide valid versions
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn spawn<Version, Mempool, State, Tip, BlockVerifierRouter, SyncStatus, AddressBook>(
|
pub fn spawn<
|
||||||
|
VersionString,
|
||||||
|
UserAgentString,
|
||||||
|
Mempool,
|
||||||
|
State,
|
||||||
|
Tip,
|
||||||
|
BlockVerifierRouter,
|
||||||
|
SyncStatus,
|
||||||
|
AddressBook,
|
||||||
|
>(
|
||||||
config: Config,
|
config: Config,
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
mining_config: get_block_template_rpcs::config::Config,
|
mining_config: get_block_template_rpcs::config::Config,
|
||||||
#[cfg(not(feature = "getblocktemplate-rpcs"))]
|
#[cfg(not(feature = "getblocktemplate-rpcs"))]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
mining_config: (),
|
mining_config: (),
|
||||||
app_version: Version,
|
build_version: VersionString,
|
||||||
|
user_agent: UserAgentString,
|
||||||
mempool: Buffer<Mempool, mempool::Request>,
|
mempool: Buffer<Mempool, mempool::Request>,
|
||||||
state: State,
|
state: State,
|
||||||
#[cfg_attr(not(feature = "getblocktemplate-rpcs"), allow(unused_variables))]
|
#[cfg_attr(not(feature = "getblocktemplate-rpcs"), allow(unused_variables))]
|
||||||
|
@ -93,7 +114,8 @@ impl RpcServer {
|
||||||
network: Network,
|
network: Network,
|
||||||
) -> (JoinHandle<()>, JoinHandle<()>, Option<Self>)
|
) -> (JoinHandle<()>, JoinHandle<()>, Option<Self>)
|
||||||
where
|
where
|
||||||
Version: ToString + Clone + Send + 'static,
|
VersionString: ToString + Clone + Send + 'static,
|
||||||
|
UserAgentString: ToString + Clone + Send + 'static,
|
||||||
Mempool: tower::Service<
|
Mempool: tower::Service<
|
||||||
mempool::Request,
|
mempool::Request,
|
||||||
Response = mempool::Response,
|
Response = mempool::Response,
|
||||||
|
@ -159,7 +181,8 @@ impl RpcServer {
|
||||||
|
|
||||||
// Initialize the rpc methods with the zebra version
|
// Initialize the rpc methods with the zebra version
|
||||||
let (rpc_impl, rpc_tx_queue_task_handle) = RpcImpl::new(
|
let (rpc_impl, rpc_tx_queue_task_handle) = RpcImpl::new(
|
||||||
app_version.clone(),
|
build_version.clone(),
|
||||||
|
user_agent,
|
||||||
network,
|
network,
|
||||||
config.debug_force_finished_sync,
|
config.debug_force_finished_sync,
|
||||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||||
|
@ -202,7 +225,7 @@ impl RpcServer {
|
||||||
let rpc_server_handle = RpcServer {
|
let rpc_server_handle = RpcServer {
|
||||||
config,
|
config,
|
||||||
network,
|
network,
|
||||||
app_version: app_version.to_string(),
|
build_version: build_version.to_string(),
|
||||||
close_handle,
|
close_handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ fn rpc_server_spawn(parallel_cpu_threads: bool) {
|
||||||
config,
|
config,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
"RPC server test",
|
"RPC server test",
|
||||||
|
"RPC server test",
|
||||||
Buffer::new(mempool.clone(), 1),
|
Buffer::new(mempool.clone(), 1),
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(router_verifier.clone(), 1),
|
Buffer::new(router_verifier.clone(), 1),
|
||||||
|
@ -147,6 +148,7 @@ fn rpc_server_spawn_unallocated_port(parallel_cpu_threads: bool, do_shutdown: bo
|
||||||
config,
|
config,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
"RPC server test",
|
"RPC server test",
|
||||||
|
"RPC server test",
|
||||||
Buffer::new(mempool.clone(), 1),
|
Buffer::new(mempool.clone(), 1),
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(router_verifier.clone(), 1),
|
Buffer::new(router_verifier.clone(), 1),
|
||||||
|
@ -227,6 +229,7 @@ fn rpc_server_spawn_port_conflict() {
|
||||||
config.clone(),
|
config.clone(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
"RPC server 1 test",
|
"RPC server 1 test",
|
||||||
|
"RPC server 1 test",
|
||||||
Buffer::new(mempool.clone(), 1),
|
Buffer::new(mempool.clone(), 1),
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(router_verifier.clone(), 1),
|
Buffer::new(router_verifier.clone(), 1),
|
||||||
|
@ -244,6 +247,7 @@ fn rpc_server_spawn_port_conflict() {
|
||||||
config,
|
config,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
"RPC server 2 conflict test",
|
"RPC server 2 conflict test",
|
||||||
|
"RPC server 2 conflict test",
|
||||||
Buffer::new(mempool.clone(), 1),
|
Buffer::new(mempool.clone(), 1),
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(router_verifier.clone(), 1),
|
Buffer::new(router_verifier.clone(), 1),
|
||||||
|
@ -335,6 +339,7 @@ fn rpc_server_spawn_port_conflict_parallel_auto() {
|
||||||
config.clone(),
|
config.clone(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
"RPC server 1 test",
|
"RPC server 1 test",
|
||||||
|
"RPC server 1 test",
|
||||||
Buffer::new(mempool.clone(), 1),
|
Buffer::new(mempool.clone(), 1),
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(router_verifier.clone(), 1),
|
Buffer::new(router_verifier.clone(), 1),
|
||||||
|
@ -352,6 +357,7 @@ fn rpc_server_spawn_port_conflict_parallel_auto() {
|
||||||
config,
|
config,
|
||||||
Default::default(),
|
Default::default(),
|
||||||
"RPC server 2 conflict test",
|
"RPC server 2 conflict test",
|
||||||
|
"RPC server 2 conflict test",
|
||||||
Buffer::new(mempool.clone(), 1),
|
Buffer::new(mempool.clone(), 1),
|
||||||
Buffer::new(state.clone(), 1),
|
Buffer::new(state.clone(), 1),
|
||||||
Buffer::new(router_verifier.clone(), 1),
|
Buffer::new(router_verifier.clone(), 1),
|
||||||
|
|
|
@ -132,6 +132,7 @@ chrono = { version = "0.4.26", default-features = false, features = ["clock", "s
|
||||||
humantime-serde = "1.1.1"
|
humantime-serde = "1.1.1"
|
||||||
indexmap = "1.9.3"
|
indexmap = "1.9.3"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
semver = "1.0.17"
|
||||||
serde = { version = "1.0.164", features = ["serde_derive"] }
|
serde = { version = "1.0.164", features = ["serde_derive"] }
|
||||||
toml = "0.7.4"
|
toml = "0.7.4"
|
||||||
|
|
||||||
|
@ -207,7 +208,6 @@ hex = "0.4.3"
|
||||||
jsonrpc-core = "18.0.0"
|
jsonrpc-core = "18.0.0"
|
||||||
once_cell = "1.18.0"
|
once_cell = "1.18.0"
|
||||||
regex = "1.8.4"
|
regex = "1.8.4"
|
||||||
semver = "1.0.17"
|
|
||||||
|
|
||||||
# zebra-rpc needs the preserve_order feature, it also makes test results more stable
|
# zebra-rpc needs the preserve_order feature, it also makes test results more stable
|
||||||
serde_json = { version = "1.0.97", features = ["preserve_order"] }
|
serde_json = { version = "1.0.97", features = ["preserve_order"] }
|
||||||
|
|
|
@ -7,8 +7,9 @@ use abscissa_core::{
|
||||||
config::CfgCell,
|
config::CfgCell,
|
||||||
status_err,
|
status_err,
|
||||||
terminal::{component::Terminal, stderr, stdout, ColorChoice},
|
terminal::{component::Terminal, stderr, stdout, ColorChoice},
|
||||||
Application, Component, Configurable, FrameworkError, Shutdown, StandardPaths, Version,
|
Application, Component, Configurable, FrameworkError, Shutdown, StandardPaths,
|
||||||
};
|
};
|
||||||
|
use semver::{BuildMetadata, Version};
|
||||||
|
|
||||||
use zebra_network::constants::PORT_IN_USE_ERROR;
|
use zebra_network::constants::PORT_IN_USE_ERROR;
|
||||||
use zebra_state::constants::{DATABASE_FORMAT_VERSION, LOCK_FILE_ERROR};
|
use zebra_state::constants::{DATABASE_FORMAT_VERSION, LOCK_FILE_ERROR};
|
||||||
|
@ -29,25 +30,17 @@ fn fatal_error(app_name: String, err: &dyn std::error::Error) -> ! {
|
||||||
/// Application state
|
/// Application state
|
||||||
pub static APPLICATION: AppCell<ZebradApp> = AppCell::new();
|
pub static APPLICATION: AppCell<ZebradApp> = AppCell::new();
|
||||||
|
|
||||||
/// Returns the zebrad version for this build, in SemVer 2.0 format.
|
/// Returns the `zebrad` version for this build, in SemVer 2.0 format.
|
||||||
///
|
///
|
||||||
/// Includes the git commit and the number of commits since the last version
|
/// Includes `git describe` build metatata if available:
|
||||||
/// tag, if available.
|
/// - the number of commits since the last version tag, and
|
||||||
|
/// - the git commit.
|
||||||
///
|
///
|
||||||
/// For details, see <https://semver.org/>
|
/// For details, see <https://semver.org/>
|
||||||
pub fn app_version() -> Version {
|
pub fn build_version() -> Version {
|
||||||
// CARGO_PKG_VERSION is always a valid SemVer 2.0 version.
|
// CARGO_PKG_VERSION is always a valid SemVer 2.0 version.
|
||||||
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
// VERGEN_GIT_DESCRIBE should be in the format:
|
|
||||||
// - v1.0.0-rc.9-6-g319b01bb84
|
|
||||||
// - v1.0.0-6-g319b01bb84
|
|
||||||
// but sometimes it is just a short commit hash. See #6879 for details.
|
|
||||||
//
|
|
||||||
// Currently it is the output of `git describe --tags --dirty --match='v*.*.*'`,
|
|
||||||
// or whatever is specified in zebrad/build.rs.
|
|
||||||
const VERGEN_GIT_DESCRIBE: Option<&str> = option_env!("VERGEN_GIT_DESCRIBE");
|
|
||||||
|
|
||||||
// We're using the same library as cargo uses internally, so this is guaranteed.
|
// We're using the same library as cargo uses internally, so this is guaranteed.
|
||||||
let fallback_version = CARGO_PKG_VERSION.parse().unwrap_or_else(|error| {
|
let fallback_version = CARGO_PKG_VERSION.parse().unwrap_or_else(|error| {
|
||||||
panic!(
|
panic!(
|
||||||
|
@ -56,6 +49,20 @@ pub fn app_version() -> Version {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
vergen_build_version().unwrap_or(fallback_version)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the `zebrad` version from this build, if available from `vergen`.
|
||||||
|
fn vergen_build_version() -> Option<Version> {
|
||||||
|
// VERGEN_GIT_DESCRIBE should be in the format:
|
||||||
|
// - v1.0.0-rc.9-6-g319b01bb84
|
||||||
|
// - v1.0.0-6-g319b01bb84
|
||||||
|
// but sometimes it is just a short commit hash. See #6879 for details.
|
||||||
|
//
|
||||||
|
// Currently it is the output of `git describe --tags --dirty --match='v*.*.*'`,
|
||||||
|
// or whatever is specified in zebrad/build.rs.
|
||||||
|
const VERGEN_GIT_DESCRIBE: Option<&str> = option_env!("VERGEN_GIT_DESCRIBE");
|
||||||
|
|
||||||
// The SemVer 2.0 format is:
|
// The SemVer 2.0 format is:
|
||||||
// - 1.0.0-rc.9+6.g319b01bb84
|
// - 1.0.0-rc.9+6.g319b01bb84
|
||||||
// - 1.0.0+6.g319b01bb84
|
// - 1.0.0+6.g319b01bb84
|
||||||
|
@ -66,16 +73,20 @@ pub fn app_version() -> Version {
|
||||||
// - optional build: `+`tag[`.`tag ...]
|
// - optional build: `+`tag[`.`tag ...]
|
||||||
// change the git describe format to the semver 2.0 format
|
// change the git describe format to the semver 2.0 format
|
||||||
let Some(vergen_git_describe) = VERGEN_GIT_DESCRIBE else {
|
let Some(vergen_git_describe) = VERGEN_GIT_DESCRIBE else {
|
||||||
return fallback_version;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// `git describe` uses "dirty" for uncommitted changes,
|
||||||
|
// but users won't understand what that means.
|
||||||
|
let vergen_git_describe = vergen_git_describe.replace("dirty", "modified");
|
||||||
|
|
||||||
// Split using "git describe" separators.
|
// Split using "git describe" separators.
|
||||||
let mut vergen_git_describe = vergen_git_describe.split('-').peekable();
|
let mut vergen_git_describe = vergen_git_describe.split('-').peekable();
|
||||||
|
|
||||||
// Check the "version core" part.
|
// Check the "version core" part.
|
||||||
let version = vergen_git_describe.next();
|
let version = vergen_git_describe.next();
|
||||||
let Some(mut version) = version else {
|
let Some(mut version) = version else {
|
||||||
return fallback_version;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
// strip the leading "v", if present.
|
// strip the leading "v", if present.
|
||||||
|
@ -83,7 +94,7 @@ pub fn app_version() -> Version {
|
||||||
|
|
||||||
// If the initial version is empty, just a commit hash, or otherwise invalid.
|
// If the initial version is empty, just a commit hash, or otherwise invalid.
|
||||||
if Version::parse(version).is_err() {
|
if Version::parse(version).is_err() {
|
||||||
return fallback_version;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut semver = version.to_string();
|
let mut semver = version.to_string();
|
||||||
|
@ -92,7 +103,7 @@ pub fn app_version() -> Version {
|
||||||
// but only consume it if it is a pre-release tag.
|
// but only consume it if it is a pre-release tag.
|
||||||
let Some(part) = vergen_git_describe.peek() else {
|
let Some(part) = vergen_git_describe.peek() else {
|
||||||
// No pre-release or build.
|
// No pre-release or build.
|
||||||
return semver.parse().expect("just checked semver is valid");
|
return semver.parse().ok();
|
||||||
};
|
};
|
||||||
|
|
||||||
if part.starts_with(char::is_alphabetic) {
|
if part.starts_with(char::is_alphabetic) {
|
||||||
|
@ -107,12 +118,12 @@ pub fn app_version() -> Version {
|
||||||
// Check if the next part is a build part.
|
// Check if the next part is a build part.
|
||||||
let Some(build) = vergen_git_describe.peek() else {
|
let Some(build) = vergen_git_describe.peek() else {
|
||||||
// No build tags.
|
// No build tags.
|
||||||
return semver.parse().unwrap_or(fallback_version);
|
return semver.parse().ok();
|
||||||
};
|
};
|
||||||
|
|
||||||
if !build.starts_with(char::is_numeric) {
|
if !build.starts_with(char::is_numeric) {
|
||||||
// It's not a valid "commit count" build tag from "git describe".
|
// It's not a valid "commit count" build tag from "git describe".
|
||||||
return fallback_version;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append the rest of the build parts with the correct `+` and `.` separators.
|
// Append the rest of the build parts with the correct `+` and `.` separators.
|
||||||
|
@ -122,19 +133,16 @@ pub fn app_version() -> Version {
|
||||||
semver.push('+');
|
semver.push('+');
|
||||||
semver.push_str(&build_parts);
|
semver.push_str(&build_parts);
|
||||||
|
|
||||||
semver.parse().unwrap_or(fallback_version)
|
semver.parse().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Zebra current release version.
|
/// The Zebra current release version, without any build metadata.
|
||||||
//
|
pub fn release_version() -> Version {
|
||||||
// TODO: deduplicate this code with release_version in zebra_rpc::get_info()
|
let mut release_version = build_version();
|
||||||
pub fn release_version() -> String {
|
|
||||||
app_version()
|
release_version.build = BuildMetadata::EMPTY;
|
||||||
.to_string()
|
|
||||||
.split('+')
|
release_version
|
||||||
.next()
|
|
||||||
.expect("always at least 1 slice")
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The User-Agent string provided by the node.
|
/// The User-Agent string provided by the node.
|
||||||
|
@ -142,8 +150,6 @@ pub fn release_version() -> String {
|
||||||
/// This must be a valid [BIP 14] user agent.
|
/// This must be a valid [BIP 14] user agent.
|
||||||
///
|
///
|
||||||
/// [BIP 14]: https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki
|
/// [BIP 14]: https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki
|
||||||
//
|
|
||||||
// TODO: deduplicate this code with the user agent in zebra_rpc::get_info()
|
|
||||||
pub fn user_agent() -> String {
|
pub fn user_agent() -> String {
|
||||||
let release_version = release_version();
|
let release_version = release_version();
|
||||||
format!("/Zebra:{release_version}/")
|
format!("/Zebra:{release_version}/")
|
||||||
|
@ -260,7 +266,7 @@ impl Application for ZebradApp {
|
||||||
|
|
||||||
let app_metadata = vec![
|
let app_metadata = vec![
|
||||||
// cargo or git tag + short commit
|
// cargo or git tag + short commit
|
||||||
("version", app_version().to_string()),
|
("version", build_version().to_string()),
|
||||||
// config
|
// config
|
||||||
("Zcash network", config.network.network.to_string()),
|
("Zcash network", config.network.network.to_string()),
|
||||||
// constants
|
// constants
|
||||||
|
@ -368,7 +374,7 @@ impl Application for ZebradApp {
|
||||||
#[cfg(feature = "sentry")]
|
#[cfg(feature = "sentry")]
|
||||||
let guard = sentry::init(sentry::ClientOptions {
|
let guard = sentry::init(sentry::ClientOptions {
|
||||||
debug: true,
|
debug: true,
|
||||||
release: Some(app_version().to_string().into()),
|
release: Some(build_version().to_string().into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ use zebra_consensus::router::BackgroundTaskHandles;
|
||||||
use zebra_rpc::server::RpcServer;
|
use zebra_rpc::server::RpcServer;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
application::{app_version, user_agent},
|
application::{build_version, user_agent},
|
||||||
components::{
|
components::{
|
||||||
inbound::{self, InboundSetupData, MAX_INBOUND_RESPONSE_TIME},
|
inbound::{self, InboundSetupData, MAX_INBOUND_RESPONSE_TIME},
|
||||||
mempool::{self, Mempool},
|
mempool::{self, Mempool},
|
||||||
|
@ -215,7 +215,8 @@ impl StartCmd {
|
||||||
config.mining.clone(),
|
config.mining.clone(),
|
||||||
#[cfg(not(feature = "getblocktemplate-rpcs"))]
|
#[cfg(not(feature = "getblocktemplate-rpcs"))]
|
||||||
(),
|
(),
|
||||||
app_version(),
|
build_version(),
|
||||||
|
user_agent(),
|
||||||
mempool.clone(),
|
mempool.clone(),
|
||||||
read_only_state_service,
|
read_only_state_service,
|
||||||
router_verifier,
|
router_verifier,
|
||||||
|
|
|
@ -16,7 +16,7 @@ use tracing_subscriber::{
|
||||||
EnvFilter,
|
EnvFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{application::app_version, components::tracing::Config};
|
use crate::{application::build_version, components::tracing::Config};
|
||||||
|
|
||||||
#[cfg(feature = "flamegraph")]
|
#[cfg(feature = "flamegraph")]
|
||||||
use super::flame;
|
use super::flame;
|
||||||
|
@ -341,7 +341,7 @@ impl<A: abscissa_core::Application> Component<A> for Tracing {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version(&self) -> abscissa_core::Version {
|
fn version(&self) -> abscissa_core::Version {
|
||||||
app_version()
|
build_version()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn before_shutdown(&self, _kind: Shutdown) -> Result<(), FrameworkError> {
|
fn before_shutdown(&self, _kind: Shutdown) -> Result<(), FrameworkError> {
|
||||||
|
|
Loading…
Reference in New Issue