Merge pull request #124 from mempool/junderw/add-bitcoind-subversion

Feat: Add X-Bitcoin-Version header to all responses from REST API.
This commit is contained in:
wiz 2025-10-09 06:31:37 +07:00 committed by GitHub
commit 56023979e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 19 additions and 11 deletions

View File

@ -4,7 +4,7 @@ use std::fs;
use std::net::SocketAddr;
use std::net::ToSocketAddrs;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::sync::{Arc, OnceLock};
use stderrlog;
use crate::chain::Network;
@ -17,6 +17,8 @@ use bitcoin::Network as BNetwork;
pub(crate) const APP_NAME: &str = "mempool-electrs";
pub(crate) const ELECTRS_VERSION: &str = env!("CARGO_PKG_VERSION");
pub(crate) const GIT_HASH: Option<&str> = option_env!("GIT_HASH");
// This will be set only once in the Daemon::new() constructor at startup
pub(crate) static BITCOIND_SUBVER: OnceLock<String> = OnceLock::new();
lazy_static! {
pub(crate) static ref VERSION_STRING: String = {

View File

@ -18,6 +18,7 @@ use bitcoin::consensus::encode::{deserialize, serialize};
use elements::encode::{deserialize, serialize};
use crate::chain::{Block, BlockHash, BlockHeader, Network, Transaction, Txid};
use crate::config::BITCOIND_SUBVER;
use crate::metrics::{HistogramOpts, HistogramVec, Metrics};
use crate::signal::Waiter;
use crate::util::HeaderList;
@ -363,6 +364,9 @@ impl Daemon {
network_info.subversion,
)
}
// Insert the subversion (/Satoshi xx.xx.xx(comment)/) string from bitcoind
_ = BITCOIND_SUBVER.set(network_info.subversion);
let blockchain_info = daemon.getblockchaininfo()?;
info!("{:?}", blockchain_info);
if blockchain_info.pruned {

View File

@ -1,5 +1,5 @@
use crate::chain::{address, BlockHash, Network, OutPoint, Script, Transaction, TxIn, TxOut, Txid};
use crate::config::{Config, VERSION_STRING};
use crate::config::{Config, BITCOIND_SUBVER, VERSION_STRING};
use crate::errors;
use crate::metrics::Metrics;
use crate::new_index::{compute_script_hash, Query, SpendingInput, Utxo};
@ -16,7 +16,10 @@ use bitcoin::blockdata::opcodes;
use bitcoin::hashes::hex::{FromHex, ToHex};
use bitcoin::hashes::Error as HashError;
use hex::{self, FromHexError};
use hyper::service::{make_service_fn, service_fn};
use hyper::{
header::HeaderValue,
service::{make_service_fn, service_fn},
};
use hyper::{Body, Method, Response, Server, StatusCode};
use prometheus::{HistogramOpts, HistogramVec};
use rayon::iter::ParallelIterator;
@ -625,14 +628,19 @@ async fn run_server(
Response::builder()
.status(err.0)
.header("Content-Type", "text/plain")
.header("X-Powered-By", &**VERSION_STRING)
.body(Body::from(err.1))
.unwrap()
});
resp.headers_mut()
.insert("X-Powered-By", HeaderValue::from_static(&VERSION_STRING));
if let Some(ref origins) = config.cors {
resp.headers_mut()
.insert("Access-Control-Allow-Origin", origins.parse().unwrap());
}
if let Some(subver) = BITCOIND_SUBVER.get() {
resp.headers_mut()
.insert("X-Bitcoin-Version", HeaderValue::from_static(subver));
}
timer.observe_duration();
Ok::<_, hyper::Error>(resp)
}
@ -815,7 +823,6 @@ fn handle_request(
.status(StatusCode::OK)
.header("Content-Type", "application/octet-stream")
.header("Cache-Control", format!("public, max-age={:}", TTL_LONG))
.header("X-Powered-By", &**VERSION_STRING)
.body(Body::from(raw))
.unwrap())
}
@ -1385,7 +1392,6 @@ fn handle_request(
.status(StatusCode::OK)
.header("Content-Type", content_type)
.header("Cache-Control", format!("public, max-age={:}", ttl))
.header("X-Powered-By", &**VERSION_STRING)
.body(body)
.unwrap())
}
@ -1771,7 +1777,6 @@ fn handle_request(
// Disable caching because we don't currently support caching with query string params
.header("Cache-Control", "no-store")
.header("Content-Type", "application/json")
.header("X-Powered-By", &**VERSION_STRING)
.header("X-Total-Results", total_num.to_string())
.body(Body::from(serde_json::to_string(&assets)?))
.unwrap())
@ -1915,7 +1920,6 @@ where
.status(status)
.header("Content-Type", "text/plain")
.header("Cache-Control", format!("public, max-age={:}", ttl))
.header("X-Powered-By", &**VERSION_STRING)
.body(message.into())
.unwrap())
}
@ -1925,7 +1929,6 @@ fn json_response<T: Serialize>(value: T, ttl: u32) -> Result<Response<Body>, Htt
Ok(Response::builder()
.header("Content-Type", "application/json")
.header("Cache-Control", format!("public, max-age={:}", ttl))
.header("X-Powered-By", &**VERSION_STRING)
.body(Body::from(value))
.unwrap())
}
@ -1936,8 +1939,7 @@ fn json_response<T: Serialize>(value: T, ttl: u32) -> Result<Response<Body>, Htt
// ) -> Result<Response<Body>, HttpError> {
// let response = Response::builder()
// .header("Content-Type", "application/json")
// .header("Cache-Control", format!("public, max-age={:}", ttl))
// .header("X-Powered-By", &**VERSION_STRING);
// .header("Cache-Control", format!("public, max-age={:}", ttl));
// Ok(match value {
// Ok(v) => response
// .body(Body::from(serde_json::to_string(&v)?))