Skip to content
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
7 changes: 6 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ jobs:
needs: [check]
strategy:
matrix: # Try all combinations of features. Some times weird things appear.
features: ['', '-F electrum-discovery', '-F liquid', '-F electrum-discovery,liquid']
features: [
'',
'-F electrum-discovery',
'-F liquid',
'-F electrum-discovery,liquid',
]
steps:
- uses: actions/checkout@v3
- id: toolchain
Expand Down
56 changes: 56 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::{path::Path, process::Command};

fn main() {
// Specify re-run conditions

// 1. Rerun build script if we pass a new GIT_HASH
println!("cargo:rerun-if-env-changed=GIT_HASH");

// 2. Only do git based reruns if git directory exists
if Path::new(".git").exists() {
// If we change the branch, rerun
println!("cargo:rerun-if-changed=.git/HEAD");
if let Ok(r) = std::fs::read_to_string(".git/HEAD") {
if let Some(stripped) = r.strip_prefix("ref: ") {
// If the HEAD is detached it will be a commit hash
// so the HEAD changed directive above will pick it up,
// otherwise it will point to a ref in the refs directory
println!("cargo:rerun-if-changed=.git/{}", stripped);
}
}
}

// Getting git hash

// Don't fetch git hash if it's already in the ENV
let existing = std::env::var("GIT_HASH").unwrap_or_else(|_| String::new());
if !existing.is_empty() {
return;
}

// Get git hash from git and don't do anything if the command fails
if let Some(rev_parse) = cmd("git", &["rev-parse", "--short", "HEAD"]) {
// Add (dirty) to the GIT_HASH if the git status isn't clean
// This includes untracked files
let dirty = cmd("git", &["status", "--short"]).expect("git command works");

let git_hash = if dirty.is_empty() {
rev_parse
} else {
format!("{}(dirty)", rev_parse.trim())
};

println!("cargo:rustc-env=GIT_HASH={}", git_hash.trim());
}
}

// Helper function, Command is verbose...
fn cmd(name: &str, args: &[&str]) -> Option<String> {
Command::new(name).args(args).output().ok().and_then(|o| {
if o.status.success() {
String::from_utf8(o.stdout).ok()
} else {
None
}
})
}
31 changes: 26 additions & 5 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,19 @@ use crate::errors::*;
#[cfg(feature = "liquid")]
use bitcoin::Network as BNetwork;

const ELECTRS_VERSION: &str = env!("CARGO_PKG_VERSION");
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");

lazy_static! {
pub(crate) static ref VERSION_STRING: String = {
if let Some(hash) = GIT_HASH {
format!("{} {}-{}", APP_NAME, ELECTRS_VERSION, hash)
} else {
format!("{} {}", APP_NAME, ELECTRS_VERSION)
}
};
}

#[derive(Debug, Clone)]
pub struct Config {
Expand Down Expand Up @@ -73,6 +85,11 @@ impl Config {

let args = App::new("Electrum Rust Server")
.version(crate_version!())
.arg(
Arg::with_name("version")
.long("version")
.help("Print out the version of this app and quit immediately."),
)
.arg(
Arg::with_name("verbosity")
.short("v")
Expand Down Expand Up @@ -260,6 +277,11 @@ impl Config {

let m = args.get_matches();

if m.is_present("version") {
eprintln!("{}", *VERSION_STRING);
std::process::exit(0);
}

let network_name = m.value_of("network").unwrap_or("mainnet");
let network_type = Network::from(network_name);
let db_dir = Path::new(m.value_of("db_dir").unwrap_or("./db"));
Expand Down Expand Up @@ -399,10 +421,9 @@ impl Config {
.unwrap_or_else(|| daemon_dir.join("blocks"));
let cookie = m.value_of("cookie").map(|s| s.to_owned());

let electrum_banner = m.value_of("electrum_banner").map_or_else(
|| format!("Welcome to mempool-electrs {}", ELECTRS_VERSION),
|s| s.into(),
);
let electrum_banner = m
.value_of("electrum_banner")
.map_or_else(|| format!("Welcome to {}", *VERSION_STRING), |s| s.into());

#[cfg(feature = "electrum-discovery")]
let electrum_public_hosts = m
Expand Down
4 changes: 3 additions & 1 deletion src/electrum/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,8 @@ mod tests {
use crate::chain::Network;
use std::time;

use crate::config::VERSION_STRING;

const PROTOCOL_VERSION: ProtocolVersion = ProtocolVersion::new(1, 4);

#[test]
Expand All @@ -534,7 +536,7 @@ mod tests {

let features = ServerFeatures {
hosts: serde_json::from_str("{\"test.foobar.example\":{\"tcp_port\":60002}}").unwrap(),
server_version: format!("electrs-esplora 9"),
server_version: VERSION_STRING.clone(),
genesis_hash: genesis_hash(Network::Testnet),
protocol_min: PROTOCOL_VERSION,
protocol_max: PROTOCOL_VERSION,
Expand Down
10 changes: 3 additions & 7 deletions src/electrum/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use bitcoin::consensus::encode::serialize;
use elements::encode::serialize;

use crate::chain::Txid;
use crate::config::Config;
use crate::config::{Config, VERSION_STRING};
use crate::electrum::{get_electrum_height, ProtocolVersion};
use crate::errors::*;
use crate::metrics::{Gauge, HistogramOpts, HistogramVec, MetricOpts, Metrics};
Expand All @@ -29,7 +29,6 @@ use crate::util::{
SyncChannel,
};

const ELECTRS_VERSION: &str = env!("CARGO_PKG_VERSION");
const PROTOCOL_VERSION: ProtocolVersion = ProtocolVersion::new(1, 4);
const MAX_HEADERS: usize = 2016;

Expand Down Expand Up @@ -138,10 +137,7 @@ impl Connection {
}

fn server_version(&self) -> Result<Value> {
Ok(json!([
format!("electrs-esplora {}", ELECTRS_VERSION),
PROTOCOL_VERSION
]))
Ok(json!([VERSION_STRING.as_str(), PROTOCOL_VERSION]))
}

fn server_banner(&self) -> Result<Value> {
Expand Down Expand Up @@ -704,7 +700,7 @@ impl RPC {
use crate::chain::genesis_hash;
let features = ServerFeatures {
hosts,
server_version: format!("electrs-esplora {}", ELECTRS_VERSION),
server_version: VERSION_STRING.clone(),
genesis_hash: genesis_hash(config.network_type),
protocol_min: PROTOCOL_VERSION,
protocol_max: PROTOCOL_VERSION,
Expand Down
3 changes: 3 additions & 0 deletions src/new_index/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1440,6 +1440,7 @@ impl TxHistoryRow {
fn prefix_height(code: u8, hash: &[u8], height: u32) -> Bytes {
bincode::options()
.with_big_endian()
.with_fixint_encoding()
.serialize(&(code, full_hash(hash), height))
.unwrap()
}
Expand All @@ -1448,6 +1449,7 @@ impl TxHistoryRow {
DBRow {
key: bincode::options()
.with_big_endian()
.with_fixint_encoding()
.serialize(&self.key)
.unwrap(),
value: vec![],
Expand All @@ -1457,6 +1459,7 @@ impl TxHistoryRow {
pub fn from_row(row: DBRow) -> Self {
let key = bincode::options()
.with_big_endian()
.with_fixint_encoding()
.deserialize(&row.key)
.expect("failed to deserialize TxHistoryKey");
TxHistoryRow { key }
Expand Down
11 changes: 9 additions & 2 deletions src/rest.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::chain::{address, BlockHash, Network, OutPoint, Script, Transaction, TxIn, TxOut, Txid};
use crate::config::Config;
use crate::config::{Config, VERSION_STRING};
use crate::errors;
use crate::new_index::{compute_script_hash, Query, SpendingInput, Utxo};
use crate::util::{
Expand Down Expand Up @@ -549,6 +549,7 @@ async fn run_server(config: Arc<Config>, query: Arc<Query>, rx: oneshot::Receive
Response::builder()
.status(err.0)
.header("Content-Type", "text/plain")
.header("Server", &**VERSION_STRING)
.body(Body::from(err.1))
.unwrap()
});
Expand Down Expand Up @@ -719,6 +720,7 @@ fn handle_request(
.status(StatusCode::OK)
.header("Content-Type", "application/octet-stream")
.header("Cache-Control", format!("public, max-age={:}", TTL_LONG))
.header("Server", &**VERSION_STRING)
.body(Body::from(raw))
.unwrap())
}
Expand Down Expand Up @@ -989,6 +991,7 @@ fn handle_request(
.status(StatusCode::OK)
.header("Content-Type", content_type)
.header("Cache-Control", format!("public, max-age={:}", ttl))
.header("Server", &**VERSION_STRING)
.body(body)
.unwrap())
}
Expand Down Expand Up @@ -1114,6 +1117,7 @@ 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("Server", &**VERSION_STRING)
.header("X-Total-Results", total_num.to_string())
.body(Body::from(serde_json::to_string(&assets)?))
.unwrap())
Expand Down Expand Up @@ -1229,6 +1233,7 @@ where
.status(status)
.header("Content-Type", "text/plain")
.header("Cache-Control", format!("public, max-age={:}", ttl))
.header("Server", &**VERSION_STRING)
.body(message.into())
.unwrap())
}
Expand All @@ -1238,6 +1243,7 @@ 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("Server", &**VERSION_STRING)
.body(Body::from(value))
.unwrap())
}
Expand All @@ -1248,7 +1254,8 @@ fn json_maybe_error_response<T: Serialize>(
) -> Result<Response<Body>, HttpError> {
let response = Response::builder()
.header("Content-Type", "application/json")
.header("Cache-Control", format!("public, max-age={:}", ttl));
.header("Cache-Control", format!("public, max-age={:}", ttl))
.header("Server", &**VERSION_STRING);
Ok(match value {
Ok(v) => response
.body(Body::from(serde_json::to_string(&v)?))
Expand Down