Browse Source

Merge pull request #53 from comit-network/provide-cli

no-contract-setup-message
Thomas Eizinger 3 years ago
committed by GitHub
parent
commit
9cde56123f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .github/workflows/ci.yml
  2. 139
      Cargo.lock
  3. 3
      daemon/Cargo.toml
  4. 67
      daemon/src/maker.rs
  5. 73
      daemon/src/seed.rs
  6. 70
      daemon/src/taker.rs

4
.github/workflows/ci.yml

@ -66,8 +66,8 @@ jobs:
- run: cargo test --workspace
- name: Smoke test ${{ matrix.target }} binary
run: |
target/debug/maker &
target/debug/maker --data-dir=/tmp/maker --generate-seed &
sleep 5s # Wait for maker to start
target/debug/taker &
target/debug/taker --data-dir=/tmp/taker --generate-seed &
sleep 5s # Wait for taker to start
curl --fail http://localhost:8000/alive

139
Cargo.lock

@ -269,6 +269,37 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "3.0.0-beta.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim",
"termcolor",
"textwrap",
"vec_map",
]
[[package]]
name = "clap_derive"
version = "3.0.0-beta.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
@ -365,6 +396,16 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "crypto-mac"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [
"generic-array",
"subtle",
]
[[package]]
name = "daemon"
version = "0.1.0"
@ -372,7 +413,9 @@ dependencies = [
"anyhow",
"bdk",
"cfd_protocol",
"clap",
"futures",
"hkdf",
"rand 0.6.5",
"rocket",
"rocket_db_pools",
@ -381,6 +424,7 @@ dependencies = [
"serde",
"serde_json",
"serde_with",
"sha2",
"sqlx",
"tempfile",
"tokio",
@ -779,6 +823,26 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hkdf"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b"
dependencies = [
"digest",
"hmac",
]
[[package]]
name = "hmac"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
dependencies = [
"crypto-mac",
"digest",
]
[[package]]
name = "http"
version = "0.2.4"
@ -1099,6 +1163,12 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "os_str_bytes"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d"
[[package]]
name = "parking_lot"
version = "0.11.2"
@ -1177,6 +1247,30 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
@ -1984,6 +2078,12 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.76"
@ -2009,6 +2109,24 @@ dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
dependencies = [
"unicode-width",
]
[[package]]
name = "thiserror"
version = "1.0.29"
@ -2230,6 +2348,12 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.2"
@ -2276,6 +2400,12 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.3"
@ -2434,6 +2564,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"

3
daemon/Cargo.toml

@ -7,7 +7,9 @@ edition = "2018"
anyhow = "1"
bdk = { git = "https://github.com/bitcoindevkit/bdk/" }
cfd_protocol = { path = "../cfd_protocol" }
clap = "3.0.0-beta.4"
futures = { version = "0.3", default-features = false }
hkdf = "0.11"
rand = "0.6"
rocket = { git = "https://github.com/SergioBenitez/Rocket", features = ["json"] }
rocket_db_pools = { git = "https://github.com/SergioBenitez/Rocket", features = ["sqlx_sqlite"] }
@ -16,6 +18,7 @@ rust_decimal_macros = "1.15"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_with = { version = "1", features = ["macros"] }
sha2 = "0.9"
sqlx = { version = "0.5", features = ["offline"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "sync", "net"] }
tokio-util = { version = "0.6", features = ["codec"] }

67
daemon/src/maker.rs

@ -1,12 +1,14 @@
use crate::seed::Seed;
use anyhow::Result;
use bdk::bitcoin::secp256k1::{schnorrsig, SECP256K1};
use bdk::bitcoin::{self, Amount};
use bdk::bitcoin::{Amount, Network};
use bdk::blockchain::{ElectrumBlockchain, NoopProgress};
use bdk::KeychainKind;
use clap::Clap;
use model::cfd::{Cfd, Order};
use rocket::fairing::AdHoc;
use rocket::figment::util::map;
use rocket::figment::value::{Map, Value};
use rocket_db_pools::Database;
use std::path::PathBuf;
use tokio::sync::{mpsc, watch};
mod db;
@ -15,6 +17,7 @@ mod maker_cfd_actor;
mod maker_inc_connections_actor;
mod model;
mod routes_maker;
mod seed;
mod send_wire_message_actor;
mod to_sse_event;
mod wire;
@ -23,19 +26,55 @@ mod wire;
#[database("maker")]
pub struct Db(sqlx::SqlitePool);
#[derive(Clap)]
struct Opts {
/// The port to listen on for p2p connections.
#[clap(long, default_value = "9999")]
p2p_port: u16,
/// The port to listen on for the HTTP API.
#[clap(long, default_value = "8001")]
http_port: u16,
/// URL to the electrum backend to use for the wallet.
#[clap(long, default_value = "ssl://electrum.blockstream.info:60002")]
electrum: String,
/// Where to permanently store data, defaults to the current working directory.
#[clap(long)]
data_dir: Option<PathBuf>,
/// Generate a seed file within the data directory.
#[clap(long)]
generate_seed: bool,
}
#[rocket::main]
async fn main() -> Result<()> {
let client =
bdk::electrum_client::Client::new("ssl://electrum.blockstream.info:60002").unwrap();
let opts = Opts::parse();
let data_dir = opts
.data_dir
.unwrap_or_else(|| std::env::current_dir().expect("unable to get cwd"));
if !data_dir.exists() {
tokio::fs::create_dir_all(&data_dir).await?;
}
let seed = Seed::initialize(&data_dir.join("maker_seed"), opts.generate_seed).await?;
let client = bdk::electrum_client::Client::new(&opts.electrum).unwrap();
// TODO: Replace with sqlite once https://github.com/bitcoindevkit/bdk/pull/376 is merged.
let db = bdk::sled::open("/tmp/maker.db")?;
let db = bdk::sled::open(data_dir.join("maker_wallet_db"))?;
let wallet_db = db.open_tree("wallet")?;
let ext_priv_key = seed.derive_extended_priv_key(Network::Testnet)?;
let wallet = bdk::Wallet::new(
"wpkh(tprv8ZgxMBicQKsPd95j7aKDzWZw9Z2SiLxpz5J5iFUdqFf1unqtoonSTteF1ZSrrB831BY1eufyHehediNH76DvcDSS2JDDyDXCQKJbyd7ozVf/*)#3vkm30lf",
None,
bitcoin::Network::Testnet,
bdk::template::Bip84(ext_priv_key, KeychainKind::External),
Some(bdk::template::Bip84(ext_priv_key, KeychainKind::Internal)),
ext_priv_key.network,
wallet_db,
ElectrumBlockchain::from(client),
)
@ -48,15 +87,11 @@ async fn main() -> Result<()> {
let (order_feed_sender, order_feed_receiver) = watch::channel::<Option<Order>>(None);
let (_balance_feed_sender, balance_feed_receiver) = watch::channel::<Amount>(Amount::ZERO);
let db: Map<_, Value> = map! {
"url" => "./maker.sqlite".into(),
};
let figment = rocket::Config::figment()
.merge(("databases", map!["maker" => db]))
.merge(("port", 8001));
.merge(("databases.maker.url", data_dir.join("maker.sqlite")))
.merge(("port", opts.http_port));
let listener = tokio::net::TcpListener::bind("0.0.0.0:9999").await?;
let listener = tokio::net::TcpListener::bind(&format!("0.0.0.0:{}", opts.p2p_port)).await?;
let local_addr = listener.local_addr().unwrap();
println!("Listening on {}", local_addr);

73
daemon/src/seed.rs

@ -0,0 +1,73 @@
use anyhow::{anyhow, bail, Result};
use bdk::bitcoin::util::bip32::ExtendedPrivKey;
use bdk::bitcoin::Network;
use hkdf::Hkdf;
use rand::Rng;
use sha2::Sha256;
use std::convert::TryInto;
use std::path::Path;
pub struct Seed([u8; 256]);
impl Seed {
/// Initialize a [`Seed`] from a path.
///
/// Fails if the file does not exist or it exists but would be overwritten.
pub async fn initialize(seed_file: &Path, generate: bool) -> Result<Seed> {
let exists = seed_file.exists();
let seed = match (exists, generate) {
(true, false) => Seed::read_from(seed_file).await?,
(false, true) => {
let seed = Seed::default();
seed.write_to(seed_file).await?;
seed
}
(true, true) => bail!("Refusing to overwrite seed at {}", seed_file.display()),
(false, false) => bail!("Seed file at {} does not exist", seed_file.display()),
};
Ok(seed)
}
pub async fn read_from(path: &Path) -> Result<Self> {
let bytes = tokio::fs::read(path).await?;
let bytes = bytes
.try_into()
.map_err(|_| anyhow!("Bytes from seed file don't fit into array"))?;
Ok(Seed(bytes))
}
pub async fn write_to(&self, path: &Path) -> Result<()> {
if path.exists() {
anyhow::bail!("Refusing to overwrite file at {}", path.display())
}
tokio::fs::write(path, &self.0).await?;
Ok(())
}
pub fn derive_extended_priv_key(&self, network: Network) -> Result<ExtendedPrivKey> {
let h = Hkdf::<Sha256>::new(None, &self.0);
let mut okm = [0u8; 64];
h.expand(b"BITCOIN_WALLET_SEED", &mut okm)
.expect("okm array is of correct length");
let ext_priv_key = ExtendedPrivKey::new_master(network, &okm)?;
Ok(ext_priv_key)
}
}
impl Default for Seed {
fn default() -> Self {
let mut seed = [0u8; 256];
rand::thread_rng().fill(&mut seed);
Self(seed)
}
}

70
daemon/src/taker.rs

@ -1,18 +1,22 @@
use anyhow::Result;
use bdk::bitcoin::secp256k1::{schnorrsig, SECP256K1};
use bdk::bitcoin::{self, Amount};
use bdk::bitcoin::{Amount, Network};
use bdk::blockchain::{ElectrumBlockchain, NoopProgress};
use bdk::KeychainKind;
use clap::Clap;
use model::cfd::{Cfd, Order};
use rocket::fairing::AdHoc;
use rocket::figment::util::map;
use rocket::figment::value::{Map, Value};
use rocket_db_pools::Database;
use seed::Seed;
use std::net::SocketAddr;
use std::path::PathBuf;
use tokio::sync::watch;
mod db;
mod keypair;
mod model;
mod routes_taker;
mod seed;
mod send_wire_message_actor;
mod taker_cfd_actor;
mod taker_inc_message_actor;
@ -23,19 +27,55 @@ mod wire;
#[database("taker")]
pub struct Db(sqlx::SqlitePool);
#[derive(Clap)]
struct Opts {
/// The IP address of the taker to connect to.
#[clap(long, default_value = "127.0.0.1:9999")]
taker: SocketAddr,
/// The port to listen on for the HTTP API.
#[clap(long, default_value = "8000")]
http_port: u16,
/// URL to the electrum backend to use for the wallet.
#[clap(long, default_value = "ssl://electrum.blockstream.info:60002")]
electrum: String,
/// Where to permanently store data, defaults to the current working directory.
#[clap(long)]
data_dir: Option<PathBuf>,
/// Generate a seed file within the data directory.
#[clap(long)]
generate_seed: bool,
}
#[rocket::main]
async fn main() -> Result<()> {
let client =
bdk::electrum_client::Client::new("ssl://electrum.blockstream.info:60002").unwrap();
let opts = Opts::parse();
let data_dir = opts
.data_dir
.unwrap_or_else(|| std::env::current_dir().expect("unable to get cwd"));
if !data_dir.exists() {
tokio::fs::create_dir_all(&data_dir).await?;
}
let seed = Seed::initialize(&data_dir.join("taker_seed"), opts.generate_seed).await?;
let client = bdk::electrum_client::Client::new(&opts.electrum).unwrap();
// TODO: Replace with sqlite once https://github.com/bitcoindevkit/bdk/pull/376 is merged.
let db = bdk::sled::open("/tmp/taker.db")?;
let db = bdk::sled::open(data_dir.join("taker_wallet_db"))?;
let wallet_db = db.open_tree("wallet")?;
let ext_priv_key = seed.derive_extended_priv_key(Network::Testnet)?;
let wallet = bdk::Wallet::new(
"wpkh(tprv8ZgxMBicQKsPfL3BRRo2gK3rMQwsy49vhEHCsaRJSM3gNrwnDwpdzLVQzbsDo738VHyrMK3FJAaxsBkpu8gk77SUQ197RNyF46brV2EVKRZ/*)#29cd5ajg",
None,
bitcoin::Network::Testnet,
bdk::template::Bip84(ext_priv_key, KeychainKind::External),
Some(bdk::template::Bip84(ext_priv_key, KeychainKind::Internal)),
ext_priv_key.network,
wallet_db,
ElectrumBlockchain::from(client),
)
@ -48,19 +88,17 @@ async fn main() -> Result<()> {
let (order_feed_sender, order_feed_receiver) = watch::channel::<Option<Order>>(None);
let (_balance_feed_sender, balance_feed_receiver) = watch::channel::<Amount>(Amount::ZERO);
let socket = tokio::net::TcpSocket::new_v4().unwrap();
let socket = tokio::net::TcpSocket::new_v4()?;
let connection = socket
.connect("127.0.0.1:9999".parse().unwrap())
.connect(opts.taker)
.await
.expect("Maker should be online first");
let (read, write) = connection.into_split();
let db: Map<_, Value> = map! {
"url" => "./taker.sqlite".into(),
};
let figment = rocket::Config::figment().merge(("databases", map!["taker" => db]));
let figment = rocket::Config::figment()
.merge(("databases.taker.url", data_dir.join("taker.sqlite")))
.merge(("port", opts.http_port));
rocket::custom(figment)
.manage(cfd_feed_receiver)

Loading…
Cancel
Save