Skip to content

Commit

Permalink
Deploy on staging
Browse files Browse the repository at this point in the history
  • Loading branch information
NCrashed committed May 18, 2022
1 parent a9dd516 commit 6c29bba
Show file tree
Hide file tree
Showing 12 changed files with 402 additions and 9 deletions.
3 changes: 3 additions & 0 deletions hexstody-btc-test/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ async fn setup_api(rpc_port: u16) -> u16 {
let state = state.clone();
let polling_duration = Duration::from_secs(1);
let client = make_client();
// 64 0es encoded to base64
let secret_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
async move {
serve_public_api(
client,
Expand All @@ -106,6 +108,7 @@ async fn setup_api(rpc_port: u16) -> u16 {
state,
state_notify,
polling_duration,
secret_key,
)
.await
.expect("start api");
Expand Down
2 changes: 2 additions & 0 deletions hexstody-btc/src/api/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,14 @@ pub async fn serve_public_api(
state: Arc<Mutex<ScanState>>,
state_notify: Arc<Notify>,
polling_duration: Duration,
secret_key: &str,
) -> Result<(), rocket::Error> {
let figment = Figment::from(Config {
address,
port,
..Config::default()
})
.merge(("secret_key", secret_key))
.merge(Env::prefixed("HEXSTODY_BTC_").global());

let on_ready = AdHoc::on_liftoff("API Start!", |_| {
Expand Down
8 changes: 8 additions & 0 deletions hexstody-btc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ enum SubCommand {
node_password: String,
#[clap(long, default_value = "bitcoin", env = "HEXSTODY_BTC_NODE_NETWORK")]
network: Network,
#[clap(
long,
env = "HEXSTODY_BTC_SECRET_KEY",
hide_env_values = true,
)]
secret_key: String,
},
}

Expand All @@ -76,6 +82,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
node_user,
node_password,
network,
secret_key,
} => loop {
let (abort_handle, abort_reg) = AbortHandle::new_pair();
ctrlc::set_handler(move || {
Expand Down Expand Up @@ -116,6 +123,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
state.clone(),
state_notify.clone(),
polling_duration,
&secret_key,
)
.await;
res.map_err(|err| LogicError::from(err))
Expand Down
8 changes: 6 additions & 2 deletions hexstody-hot/src/api/operator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,14 @@ pub async fn serve_operator_api(
_start_notify: Arc<Notify>,
port: u16,
update_sender: mpsc::Sender<StateUpdate>,
secret_key: String,
static_path: String,
) -> Result<(), rocket::Error> {
let figment = rocket::Config::figment().merge(("port", port));
let figment = rocket::Config::figment()
.merge(("secret_key", secret_key))
.merge(("port", port));
rocket::custom(figment)
.mount("/", FileServer::from(relative!("static/")))
.mount("/", FileServer::from(static_path))
.mount("/", routes![index])
.mount("/", openapi_get_routes![list, create])
.mount(
Expand Down
15 changes: 12 additions & 3 deletions hexstody-hot/src/api/public/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use hexstody_db::Pool;
use rocket::fairing::AdHoc;
use rocket::fs::{relative, FileServer};
use rocket::response::{content, Redirect};
use rocket::uri;
use rocket::serde::json::Json;
use rocket::uri;
use rocket::{get, routes};
use rocket_dyn_templates::Template;
use rocket_okapi::{openapi, openapi_get_routes, swagger_ui::*};
Expand Down Expand Up @@ -96,16 +96,20 @@ pub async fn serve_public_api(
port: u16,
update_sender: mpsc::Sender<StateUpdate>,
btc_client: BtcClient,
secret_key: String,
static_path: String,
) -> Result<(), rocket::Error> {
let figment = rocket::Config::figment().merge(("port", port));
let figment = rocket::Config::figment()
.merge(("secret_key", secret_key))
.merge(("port", port));
let on_ready = AdHoc::on_liftoff("API Start!", |_| {
Box::pin(async move {
start_notify.notify_one();
})
});

rocket::custom(figment)
.mount("/", FileServer::from(relative!("static/")))
.mount("/", FileServer::from(static_path))
.mount(
"/",
openapi_get_routes![
Expand Down Expand Up @@ -166,6 +170,9 @@ mod tests {
let state = state_mx.clone();
let state_notify = state_notify.clone();
let start_notify = start_notify.clone();
// 64 0es encoded to base64
let secret_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==".to_owned();
let static_path = relative!("static/");
async move {
let serve_task = serve_public_api(
pool,
Expand All @@ -175,6 +182,8 @@ mod tests {
SERVICE_TEST_PORT,
update_sender,
btc_client,
secret_key,
static_path.to_owned(),
);
futures::pin_mut!(serve_task);
futures::future::select(serve_task, receiver.map_err(drop)).await;
Expand Down
17 changes: 17 additions & 0 deletions hexstody-hot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ struct Args {
network: Network,
#[clap(long, env = "HEXSTODY_START_REGTEST")]
start_regtest: bool,
#[clap(
long,
env = "HEXSTODY_SECRET_KEY",
hide_env_values = true,
)]
secret_key: String,
/// Path to HTML static files to serve
#[clap(
long,
env = "HEXSTODY_STATIC_PATH",
)]
static_path: Option<String>,
#[clap(subcommand)]
subcmd: SubCommand,
}
Expand Down Expand Up @@ -84,13 +96,18 @@ async fn run(btc_client: BtcClient, args: &Args) {
api_abort_handle.abort();
})
.expect("Error setting Ctrl-C handler");
let relative = rocket::fs::relative!("static/").to_owned();
let static_path = args.static_path.as_ref().unwrap_or(&relative);

match run_hot_wallet(
args.network,
api_config,
&args.dbconnect,
start_notify,
btc_client.clone(),
api_abort_reg,
&args.secret_key,
static_path,
)
.await
{
Expand Down
20 changes: 18 additions & 2 deletions hexstody-hot/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ impl ApiConfig {
pub fn parse_figment() -> Self {
let figment = rocket::Config::figment();
let public_api_enabled = figment.extract_inner("public_api_enabled").unwrap_or(true);
let public_api_port = figment.extract_inner("public_api_port").unwrap_or(8000);
let public_api_port = figment.extract_inner("public_api_port").unwrap_or(9800);
let operator_api_enabled = figment
.extract_inner("operator_api_enabled")
.unwrap_or(true);
let operator_api_port = figment.extract_inner("operator_api_port").unwrap_or(8001);
let operator_api_port = figment.extract_inner("operator_api_port").unwrap_or(9801);
ApiConfig {
public_api_enabled,
public_api_port,
Expand Down Expand Up @@ -93,6 +93,8 @@ async fn serve_api(
abort_reg: AbortRegistration,
update_sender: mpsc::Sender<StateUpdate>,
btc_client: BtcClient,
secret_key: String,
static_path: String,
) -> () {
if !api_enabled {
info!("{api_type} API disabled");
Expand All @@ -110,6 +112,8 @@ async fn serve_api(
port,
update_sender.clone(),
btc_client,
secret_key,
static_path,
)
})
.await;
Expand All @@ -123,6 +127,8 @@ async fn serve_api(
start_notify.clone(),
port,
update_sender.clone(),
secret_key,
static_path,
)
})
.await;
Expand All @@ -139,6 +145,8 @@ pub async fn serve_apis(
api_abort: AbortRegistration,
update_sender: mpsc::Sender<StateUpdate>,
btc_client: BtcClient,
secret_key: &str,
static_path: &str,
) -> Result<(), Aborted> {
let (public_handle, public_abort) = AbortHandle::new_pair();
let public_api_fut = serve_api(
Expand All @@ -152,6 +160,8 @@ pub async fn serve_apis(
public_abort,
update_sender.clone(),
btc_client.clone(),
secret_key.to_owned(),
static_path.to_owned(),
);
let (operator_handle, operator_abort) = AbortHandle::new_pair();
let operator_api_fut = serve_api(
Expand All @@ -165,6 +175,8 @@ pub async fn serve_apis(
operator_abort,
update_sender.clone(),
btc_client,
secret_key.to_owned(),
static_path.to_owned(),
);

let abortable_apis =
Expand Down Expand Up @@ -196,6 +208,8 @@ pub async fn run_hot_wallet(
start_notify: Arc<Notify>,
btc_client: BtcClient,
api_abort_reg: AbortRegistration,
secret_key: &str,
static_path: &str,
) -> Result<(), Error> {
info!("Connecting to database");
let pool = create_db_pool(db_connect).await?;
Expand Down Expand Up @@ -231,6 +245,8 @@ pub async fn run_hot_wallet(
api_abort_reg,
update_sender,
btc_client,
secret_key,
static_path,
)
.await
{
Expand Down
6 changes: 5 additions & 1 deletion hexstody-hot/src/tests/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ where
let mut api_config = ApiConfig::parse_figment();
api_config.public_api_port = public_api_port;
api_config.operator_api_port = operator_api_port;

// 64 0es encoded to base64
let secret_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==";
let static_path = rocket::fs::relative!("static/");
let (_, abort_reg) = AbortHandle::new_pair();
match run_hot_wallet(
Network::Regtest,
Expand All @@ -53,6 +55,8 @@ where
start_notify,
btc_adapter,
abort_reg,
secret_key,
static_path,
)
.await
{
Expand Down
119 changes: 119 additions & 0 deletions nix/hexstody-btc.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
{ config, pkgs, lib, ... }:
with lib; # use the functions from lib, such as mkIf
let
# the values of the options set for the service by the user of the service
cfg = config.services.hexstody-btc;
in {
##### interface. here we define the options that users of our service can specify
options = {
# the options for our service will be located under services.hexstody-btc
services.hexstody-btc = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable hexstody BTC adapter service by default.
'';
};
package = mkOption {
type = types.package;
default = pkgs.hexstody;
description = ''
Which package to use with the service.
'';
};
port = mkOption {
type = types.int;
default = 8180;
description = ''
Which port the BTC adapter listen to serve API.
'';
};
host = mkOption {
type = types.str;
default = "0.0.0.0";
description = ''
Which hostname is binded to the node.
'';
};

btcNode = mkOption {
type = types.str;
default = "127.0.0.1:8332/wallet/hexstody";
description = ''
Host and port where BTC RPC node is located.
'';
};
rpcUser = mkOption {
type = types.str;
default = "bitcoin";
description = ''
Which name of bitcoin RPC user to use.
'';
};
passwordFile = mkOption {
type = types.str;
default = "/run/keys/hexstodybtcrpc";
description = ''
Location of file with password for RPC.
'';
};
passwordFileService = mkOption {
type = types.str;
default = "hexstodybtcrpc-key.service";
description = ''
Service that indicates that passwordFile is ready.
'';
};
secretKey = mkOption {
type = types.str;
default = "/run/keys/hexstodybtccookieskey";
description = ''
Location of file with cookies secret key.
'';
};
secretKeyService = mkOption {
type = types.str;
default = "hexstodybtccookies-key.service";
description = ''
Service that indicates that secretKey is ready.
'';
};
};
};

##### implementation
config = mkIf cfg.enable { # only apply the following settings if enabled
# User to run the node
users.users.hexstody-btc = {
name = "hexstody-btc";
group = "hexstody-btc";
description = "hexstody-btc daemon user";
isSystemUser = true;
};
users.groups.hexstody-btc = {};
# Create systemd service
systemd.services.hexstody-btc = {
enable = true;
description = "Hexstody BTC adapter";
after = ["network.target" cfg.passwordFileService cfg.secretKeyService];
wants = ["network.target" cfg.passwordFileService cfg.secretKeyService];
script = ''
export HEXSTODY_BTC_NODE_PASSWORD=$(cat ${cfg.passwordFile} | xargs echo -n)
export HEXSTODY_BTC_SECRET_KEY=$(cat ${cfg.secretKey} | xargs echo -n)
${cfg.package}/bin/hexstody-btc serve \
--address ${cfg.host} \
--node-url ${cfg.btcNode} \
--node-user ${cfg.rpcUser} \
--port ${builtins.toString cfg.port}
'';
serviceConfig = {
Restart = "always";
RestartSec = 30;
User = "hexstody-btc";
LimitNOFILE = 65536;
};
wantedBy = ["multi-user.target"];
};
};
}
Loading

0 comments on commit 6c29bba

Please sign in to comment.