mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
Merge pull request #3 from darkrenaissance/bitcoin
Cashier with bitcoin
This commit is contained in:
43
Cargo.lock
generated
43
Cargo.lock
generated
@@ -401,6 +401,12 @@ version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bech32"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1"
|
||||
|
||||
[[package]]
|
||||
name = "bellman"
|
||||
version = "0.8.1"
|
||||
@@ -446,6 +452,23 @@ dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6742ec672d3f12506f4ac5c0d853926ff1f94e675f60ffd3224039972bf663f1"
|
||||
dependencies = [
|
||||
"bech32",
|
||||
"bitcoin_hashes",
|
||||
"secp256k1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcoin_hashes"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ce18265ec2324ad075345d5814fbeed4f41f0a660055dc78840b74d19b874b1"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
@@ -961,6 +984,7 @@ dependencies = [
|
||||
"async-trait",
|
||||
"bellman",
|
||||
"bimap",
|
||||
"bitcoin",
|
||||
"bitvec",
|
||||
"blake2b_simd",
|
||||
"blake2s_simd",
|
||||
@@ -992,6 +1016,7 @@ dependencies = [
|
||||
"regex",
|
||||
"rocksdb",
|
||||
"rusqlite",
|
||||
"secp256k1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
@@ -2426,6 +2451,24 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97d03ceae636d0fed5bae6a7f4f664354c5f4fcedf6eef053fef17e49f837d0a"
|
||||
dependencies = [
|
||||
"secp256k1-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "827cb7cce42533829c792fc51b82fbf18b125b45a702ef2c8be77fce65463a7b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.3.1"
|
||||
|
||||
11
Cargo.toml
11
Cargo.toml
@@ -15,7 +15,7 @@ bls12_381 = "0.3.1"
|
||||
jubjub = "0.5.1"
|
||||
|
||||
zcash_primitives = "0.5.0"
|
||||
zcash_proofs = "0.5.0"
|
||||
zcash_proofs = "0.5.0"
|
||||
# zcash_primitives = { git = "https://github.com/zcash/librustzcash" }
|
||||
#zcash_proofs = { git = "https://github.com/zcash/librustzcash" }
|
||||
#zcash_proofs = { git = "https://github.com/narodnik/librustzcash" }
|
||||
@@ -77,6 +77,9 @@ bytes = "1.0.1"
|
||||
rocksdb = "0.16.0"
|
||||
dirs = "3.0.2"
|
||||
|
||||
bitcoin = "0.26.2"
|
||||
secp256k1 = "0.20.3"
|
||||
|
||||
[dependencies.rusqlite]
|
||||
version = "0.25.1"
|
||||
features = ["bundled", "sqlcipher"]
|
||||
@@ -109,13 +112,17 @@ path = "src/bin/tx.rs"
|
||||
name = "gatewayd"
|
||||
path = "src/bin/gatewayd.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "cashierd"
|
||||
path = "src/bin/cashierd.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "darkfid"
|
||||
path = "src/bin/darkfid.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "drk"
|
||||
path = "src/bin/drk.rs"
|
||||
|
||||
[profile.release]
|
||||
debug = 1
|
||||
|
||||
|
||||
101
src/bin/cashierd.rs
Normal file
101
src/bin/cashierd.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use std::net::SocketAddr;
|
||||
use std::str;
|
||||
use std::sync::Arc;
|
||||
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Read;
|
||||
use std::{fs, path::Path, path::PathBuf};
|
||||
use toml;
|
||||
|
||||
use drk::blockchain::{rocks::columns, Rocks, RocksColumn};
|
||||
use drk::cli::{CashierdCli, CashierdConfig};
|
||||
use drk::wallet::{WalletDb, WalletPtr};
|
||||
use drk::service::CashierService;
|
||||
|
||||
use drk::util::join_config_path;
|
||||
use drk::Result;
|
||||
|
||||
use async_executor::Executor;
|
||||
use easy_parallel::Parallel;
|
||||
|
||||
fn setup_addr(address: Option<SocketAddr>, default: SocketAddr) -> SocketAddr {
|
||||
match address {
|
||||
Some(addr) => addr,
|
||||
None => default,
|
||||
}
|
||||
}
|
||||
|
||||
async fn start(executor: Arc<Executor<'_>>, config: Arc<&CashierdConfig>) -> Result<()> {
|
||||
let accept_addr: SocketAddr = config.accept_url.parse()?;
|
||||
|
||||
let database_path = config.database_path.clone();
|
||||
|
||||
let database_path = join_config_path(&PathBuf::from(database_path))?;
|
||||
|
||||
let rocks = Rocks::new(&database_path)?;
|
||||
|
||||
let rocks_cashierstore_column = RocksColumn::<columns::CashierKeys>::new(rocks);
|
||||
// Use pw: PASSWORD for now
|
||||
//let cashier_wallet = Arc::new(WalletDB::new("cashier.db", "PASSWORD")?);
|
||||
let wallet = Arc::new(WalletDb::new("cashier.db", config.password.clone())?);
|
||||
|
||||
let cashier = CashierService::new(accept_addr, rocks_cashierstore_column, wallet)?;
|
||||
|
||||
cashier.start(executor.clone()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
use simplelog::*;
|
||||
|
||||
let ex = Arc::new(Executor::new());
|
||||
let (signal, shutdown) = async_channel::unbounded::<()>();
|
||||
|
||||
let path = join_config_path(&PathBuf::from("cashierd.toml")).unwrap();
|
||||
|
||||
let config: CashierdConfig = if Path::new(&path).exists() {
|
||||
CashierdConfig::load(path)?
|
||||
} else {
|
||||
CashierdConfig::load_default(path)?
|
||||
};
|
||||
|
||||
let config_ptr = Arc::new(&config);
|
||||
|
||||
let options = CashierdCli::load()?;
|
||||
|
||||
let logger_config = ConfigBuilder::new().set_time_format_str("%T%.6f").build();
|
||||
|
||||
let debug_level = if options.verbose {
|
||||
LevelFilter::Debug
|
||||
} else {
|
||||
LevelFilter::Off
|
||||
};
|
||||
|
||||
let log_path = config.log_path.clone();
|
||||
CombinedLogger::init(vec![
|
||||
TermLogger::new(debug_level, logger_config, TerminalMode::Mixed).unwrap(),
|
||||
WriteLogger::new(
|
||||
LevelFilter::Debug,
|
||||
Config::default(),
|
||||
std::fs::File::create(log_path).unwrap(),
|
||||
),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
|
||||
let ex2 = ex.clone();
|
||||
|
||||
let (_, result) = Parallel::new()
|
||||
// Run four executor threads.
|
||||
.each(0..3, |_| smol::future::block_on(ex.run(shutdown.recv())))
|
||||
// Run the main future on the current thread.
|
||||
.finish(|| {
|
||||
smol::future::block_on(async move {
|
||||
start(ex2, config_ptr).await?;
|
||||
drop(signal);
|
||||
Ok::<(), drk::Error>(())
|
||||
})
|
||||
});
|
||||
|
||||
result
|
||||
}
|
||||
44
src/blockchain/cashier_keypair.rs
Normal file
44
src/blockchain/cashier_keypair.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use crate::serial::{Decodable, Encodable};
|
||||
use crate::Result;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CashierKeypair {
|
||||
zk_public: jubjub::SubgroupPoint,
|
||||
payload: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CashierKeypair {
|
||||
pub fn new(zk_public: jubjub::SubgroupPoint, payload: Vec<u8>) -> Self {
|
||||
CashierKeypair { zk_public, payload }
|
||||
}
|
||||
|
||||
pub fn set_index(&mut self, index: jubjub::SubgroupPoint) {
|
||||
self.zk_public = index;
|
||||
}
|
||||
|
||||
pub fn get_index(&self) -> jubjub::SubgroupPoint {
|
||||
self.zk_public
|
||||
}
|
||||
|
||||
pub fn get_payload(&self) -> Vec<u8> {
|
||||
self.payload.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for CashierKeypair {
|
||||
fn encode<S: std::io::Write>(&self, mut s: S) -> Result<usize> {
|
||||
let mut len = 0;
|
||||
len += self.zk_public.encode(&mut s)?;
|
||||
len += self.payload.encode(&mut s)?;
|
||||
Ok(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for CashierKeypair {
|
||||
fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
|
||||
Ok(Self {
|
||||
zk_public: Decodable::decode(&mut d)?,
|
||||
payload: Decodable::decode(&mut d)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
55
src/blockchain/cashierstore.rs
Normal file
55
src/blockchain/cashierstore.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::serial::{deserialize, serialize};
|
||||
use crate::Result;
|
||||
|
||||
use super::rocks::{columns, IteratorMode, RocksColumn};
|
||||
use super::cashier_keypair::CashierKeypair;
|
||||
|
||||
pub struct CashierStore {
|
||||
rocks: RocksColumn<columns::CashierKeys>,
|
||||
}
|
||||
|
||||
impl CashierStore {
|
||||
pub fn new(rocks: RocksColumn<columns::CashierKeys>) -> Result<Arc<Self>> {
|
||||
Ok(Arc::new(CashierStore { rocks }))
|
||||
}
|
||||
|
||||
pub fn get(&self, key: jubjub::SubgroupPoint) -> Result<Option<Vec<u8>>> {
|
||||
let value = self.rocks.get(key)?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub fn put(&self, keypair: CashierKeypair) -> Result<Option<jubjub::SubgroupPoint>> {
|
||||
|
||||
let index = keypair.get_index();
|
||||
let check = self.get(index);
|
||||
match self.get(index) {
|
||||
Ok(_v) => Ok(None),
|
||||
Err(_e) => {
|
||||
self.rocks.put(index.clone(), keypair)?;
|
||||
Ok(Some(index))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value_deserialized(&self, key: Vec<u8>) -> Result<Option<CashierKeypair>> {
|
||||
self.rocks.get_value_deserialized::<CashierKeypair>(key)
|
||||
}
|
||||
// Fix this
|
||||
// pub fn get_last_index(&self) -> Result<jubjub::SubgroupPoint> {
|
||||
// let last_index = self.rocks.iterator(IteratorMode::End)?.next();
|
||||
// match last_index {
|
||||
// Some((index, _)) => Ok(deserialize(&index)?),
|
||||
// None => Ok()
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn get_last_index_as_bytes(&self) -> Result<Vec<u8>> {
|
||||
let last_index = self.rocks.iterator(IteratorMode::End)?.next();
|
||||
match last_index {
|
||||
Some((index, _)) => Ok(index.to_vec()),
|
||||
None => Ok(serialize::<u64>(&0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
pub mod rocks;
|
||||
pub mod slab;
|
||||
pub mod slabstore;
|
||||
pub mod cashier_keypair;
|
||||
pub mod cashierstore;
|
||||
|
||||
pub use rocks::{Rocks, RocksColumn};
|
||||
pub use slab::Slab;
|
||||
pub use slabstore::SlabStore;
|
||||
pub use cashier_keypair::CashierKeypair;
|
||||
pub use cashierstore::CashierStore;
|
||||
|
||||
@@ -20,6 +20,7 @@ pub mod columns {
|
||||
pub struct Slabs;
|
||||
pub struct Nullifiers;
|
||||
pub struct MerkleRoots;
|
||||
pub struct CashierKeys;
|
||||
}
|
||||
|
||||
impl Column for columns::Slabs {
|
||||
@@ -33,7 +34,9 @@ impl Column for columns::Nullifiers {
|
||||
impl Column for columns::MerkleRoots {
|
||||
const NAME: &'static str = "merkleroots";
|
||||
}
|
||||
|
||||
impl Column for columns::CashierKeys {
|
||||
const NAME: &'static str = "cashierkeys";
|
||||
}
|
||||
pub struct Rocks {
|
||||
db: DB,
|
||||
}
|
||||
@@ -51,10 +54,12 @@ impl Rocks {
|
||||
// nullifiers column family
|
||||
let nullifiers_cf = ColumnFamilyDescriptor::new(columns::Nullifiers::NAME, cf_opts.clone());
|
||||
// merkleroots column family
|
||||
let merkleroots_cf = ColumnFamilyDescriptor::new(columns::MerkleRoots::NAME, cf_opts);
|
||||
let merkleroots_cf = ColumnFamilyDescriptor::new(columns::MerkleRoots::NAME, cf_opts.clone());
|
||||
// cashierkeypair column family
|
||||
let cashierkeys_cf = ColumnFamilyDescriptor::new(columns::CashierKeys::NAME, cf_opts);
|
||||
|
||||
// column families
|
||||
let cfs = vec![default_cf, slab_cf, nullifiers_cf, merkleroots_cf];
|
||||
let cfs = vec![default_cf, slab_cf, nullifiers_cf, merkleroots_cf, cashierkeys_cf];
|
||||
|
||||
// database options
|
||||
let mut opt = Options::default();
|
||||
|
||||
23
src/cli/cashierd_cli.rs
Normal file
23
src/cli/cashierd_cli.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use crate::Result;
|
||||
|
||||
pub struct CashierdCli {
|
||||
pub verbose: bool,
|
||||
}
|
||||
|
||||
impl CashierdCli {
|
||||
pub fn load() -> Result<Self> {
|
||||
let app = clap_app!(dfi =>
|
||||
(version: "0.1.0")
|
||||
(author: "Amir Taaki <amir@dyne.org>")
|
||||
(about: "run service daemon")
|
||||
(@arg VERBOSE: -v --verbose "Increase verbosity")
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let verbose = app.is_present("VERBOSE");
|
||||
|
||||
Ok(Self {
|
||||
verbose,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -160,3 +160,48 @@ impl Default for GatewaydConfig {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CashierdConfig {
|
||||
#[serde(default)]
|
||||
#[serde(rename = "connect_url")]
|
||||
pub accept_url: String,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(rename = "database_path")]
|
||||
pub database_path: String,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(rename = "log_path")]
|
||||
pub log_path: String,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(rename = "password")]
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
impl CashierdConfig {
|
||||
pub fn load(path: PathBuf) -> Result<Self> {
|
||||
let toml = fs::read(&path)?;
|
||||
let str_buff = str::from_utf8(&toml)?;
|
||||
let config: Self = toml::from_str(str_buff)?;
|
||||
Ok(config)
|
||||
}
|
||||
pub fn load_default(path: PathBuf) -> Result<Self> {
|
||||
let toml = Self::default();
|
||||
let config_file = toml::to_string(&toml)?;
|
||||
fs::write(&path, &config_file)?;
|
||||
let config = Self::load(path)?;
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CashierdConfig {
|
||||
fn default() -> Self {
|
||||
let accept_url = String::from("127.0.0.1:7777");
|
||||
let database_path = String::from("cashierd.db");
|
||||
let log_path = String::from("/tmp/cashierd.log");
|
||||
let password = String::new();
|
||||
Self { accept_url, database_path, log_path, password }
|
||||
}
|
||||
}
|
||||
|
||||
146
src/cli/client_cli/cli_config.rs
Normal file
146
src/cli/client_cli/cli_config.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
//use crate::serial::{deserialize, serialize, Decodable, Encodable};
|
||||
//use toml::{map::Map, Value};
|
||||
use crate::util::join_config_path;
|
||||
//use crate::Result;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
//use log::*;
|
||||
|
||||
use std::{fs::OpenOptions, io::prelude::*, path::PathBuf};
|
||||
|
||||
//pub trait ClientConfig: Default + Deserialize {
|
||||
// fn load(path: PathBuf) -> Result<Self> {
|
||||
// let path = join_config_path(&path)?;
|
||||
// let mut file = OpenOptions::new()
|
||||
// .read(true)
|
||||
// .write(true)
|
||||
// .create(true)
|
||||
// .open(path)?;
|
||||
//
|
||||
// //let mut toml_map = Map::new();
|
||||
// let mut buffer = String::new();
|
||||
// file.read_to_string(&mut buffer)?;
|
||||
// //let buffer: &'static str = buffer;
|
||||
//
|
||||
// //let tomlstring = toml::to_string(&file).expect("Could not encode TTOML value");
|
||||
// if !buffer.is_empty() {
|
||||
// let config: Self = toml::from_str(&buffer)?;
|
||||
// //let config = toml::to_string(&buffer).unwrap();
|
||||
// //let config: Self = deserialize(&buffer)?;
|
||||
// //Ok(config)
|
||||
// Ok(config)
|
||||
// } else {
|
||||
// Ok(Self::default())
|
||||
// }
|
||||
// }
|
||||
// fn save(&self, path: PathBuf) -> Result<()> {
|
||||
// //let path = join_config_path(&path)?;
|
||||
// //let mut file = OpenOptions::new().write(true).create(true).open(&path)?;
|
||||
// //let serialized = serialize(self);
|
||||
// //file.write_all(&serialized)?;
|
||||
// Ok(())
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//impl ClientConfig for DrkConfig {}
|
||||
//impl ClientConfig for DarkfidConfig {}
|
||||
|
||||
#[derive(Serialize, Default, Deserialize, Debug)]
|
||||
pub struct DrkConfig {
|
||||
#[serde(rename = "rpc_url")]
|
||||
pub rpc_url: String,
|
||||
|
||||
#[serde(rename = "log_path")]
|
||||
pub log_path: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Default, Deserialize, Debug)]
|
||||
pub struct DarkfidConfig {
|
||||
#[serde(rename = "connect_url")]
|
||||
pub connect_url: String,
|
||||
|
||||
#[serde(rename = "subscriber_url")]
|
||||
pub subscriber_url: String,
|
||||
|
||||
#[serde(rename = "rpc_url")]
|
||||
pub rpc_url: String,
|
||||
|
||||
#[serde(rename = "database_path")]
|
||||
pub database_path: String,
|
||||
|
||||
#[serde(rename = "log_path")]
|
||||
pub log_path: String,
|
||||
|
||||
#[serde(rename = "password")]
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Default, Deserialize, Debug)]
|
||||
pub struct GatewaydConfig {
|
||||
#[serde(rename = "connect_url")]
|
||||
pub accept_url: String,
|
||||
|
||||
#[serde(rename = "subscriber_url")]
|
||||
pub publisher_url: String,
|
||||
|
||||
#[serde(rename = "database_path")]
|
||||
pub database_path: String,
|
||||
|
||||
#[serde(rename = "log_path")]
|
||||
pub log_path: String,
|
||||
}
|
||||
#[derive(Serialize, Default, Deserialize, Debug)]
|
||||
pub struct CashierdConfig {
|
||||
#[serde(rename = "connect_url")]
|
||||
pub accept_url: String,
|
||||
|
||||
#[serde(rename = "database_path")]
|
||||
pub database_path: String,
|
||||
|
||||
#[serde(rename = "log_path")]
|
||||
pub log_path: String,
|
||||
}
|
||||
//impl Default for DrkCliConfig {
|
||||
// // default toml file
|
||||
// fn default() -> Self {
|
||||
// let rpc_url = String::from("http://127.0.0.1:8000");
|
||||
// let log_path = String::from("/tmp/drk_cli.log");
|
||||
// Self {
|
||||
// rpc_url,
|
||||
// log_path,
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//impl Default for DarkfidCliConfig {
|
||||
// // create default config file
|
||||
// fn default() -> Self {
|
||||
// //toml::toml! {
|
||||
// // connect-url = "127.0.0.1:3333"
|
||||
// //};
|
||||
// let connect_url = String::from("127.0.0.1:3333");
|
||||
// let subscriber_url = String::from("127.0.0.1:4444");
|
||||
// let rpc_url = String::from("127.0.0.1:8000");
|
||||
//
|
||||
// let database_path = String::from("database_client.db");
|
||||
// let database_path = join_config_path(&PathBuf::from(database_path))
|
||||
// .expect("error during join database_path to config path");
|
||||
// let database_path = String::from(
|
||||
// database_path
|
||||
// .to_str()
|
||||
// .expect("error convert Path to String"),
|
||||
// );
|
||||
// let log_path = String::from("/tmp/darkfid_service_daemon.log");
|
||||
//
|
||||
// let password = String::new();
|
||||
// Self {
|
||||
// connect_url,
|
||||
// subscriber_url,
|
||||
// rpc_url,
|
||||
// database_path,
|
||||
// log_path,
|
||||
// password,
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -2,9 +2,11 @@ pub mod cli_config;
|
||||
pub mod darkfid_cli;
|
||||
pub mod drk_cli;
|
||||
pub mod gatewayd_cli;
|
||||
pub mod cashierd_cli;
|
||||
|
||||
pub use cli_config::{DarkfidConfig, DrkConfig, GatewaydConfig};
|
||||
pub use cli_config::{DarkfidConfig, DrkConfig, CashierdConfig, GatewaydConfig};
|
||||
pub use darkfid_cli::DarkfidCli;
|
||||
pub use drk_cli::DrkCli;
|
||||
pub use drk_cli::Transfer;
|
||||
pub use gatewayd_cli::GatewaydCli;
|
||||
pub use cashierd_cli::CashierdCli;
|
||||
|
||||
@@ -39,7 +39,7 @@ impl RpcAdapter {
|
||||
|
||||
pub fn cash_key_gen(&self) -> Result<()> {
|
||||
debug!(target: "adapter", "key_gen() [START]");
|
||||
let (public, private) = self.wallet.key_gen();
|
||||
let (public, private) = self.wallet.cash_key_gen();
|
||||
self.wallet.put_keypair(public, private)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
254
src/service/bitcoin_bridge.rs
Normal file
254
src/service/bitcoin_bridge.rs
Normal file
@@ -0,0 +1,254 @@
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::distributions::Alphanumeric;
|
||||
use secp256k1::key::{SecretKey, PublicKey};
|
||||
use bitcoin::util::ecdsa::{PrivateKey, PublicKey as BitcoinPubKey};
|
||||
use bitcoin::util::{address::Payload, address::Address};
|
||||
// Use p2pkh for 1st iteration
|
||||
use bitcoin::hash_types::PubkeyHash;
|
||||
use bitcoin::network::constants::Network;
|
||||
use super::reqrep::{PeerId, RepProtocol, Reply, ReqProtocol, Request};
|
||||
use crate::blockchain::{rocks::columns, RocksColumn, CashierKeypair, CashierStore};
|
||||
use crate::{serial::deserialize, serial::serialize, Error, Result};
|
||||
use crate::wallet::{WalletDb, WalletPtr};
|
||||
use std::net::SocketAddr;
|
||||
use async_std::sync::Arc;
|
||||
use async_executor::Executor;
|
||||
use log::*;
|
||||
|
||||
#[repr(u8)]
|
||||
enum CashierError {
|
||||
NoError,
|
||||
UpdateIndex,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
enum CashierCommand {
|
||||
GetDBTC,
|
||||
GetBTC,
|
||||
}
|
||||
|
||||
pub struct BitcoinKeys {
|
||||
secret_key: SecretKey,
|
||||
bitcoin_private_key: PrivateKey,
|
||||
pub bitcoin_public_key: BitcoinPubKey,
|
||||
pub pub_address: Address,
|
||||
}
|
||||
impl BitcoinKeys {
|
||||
pub fn new(
|
||||
|
||||
) -> Result<BitcoinKeys> {
|
||||
|
||||
let context = secp256k1::Secp256k1::new();
|
||||
|
||||
// Probably not good enough for release
|
||||
let rand: String = thread_rng()
|
||||
.sample_iter(&Alphanumeric)
|
||||
.take(32)
|
||||
.map(char::from)
|
||||
.collect();
|
||||
|
||||
let rand_hex = hex::encode(rand);
|
||||
|
||||
// Generate simple byte array from rand
|
||||
let data_slice: &[u8] = rand_hex.as_bytes();
|
||||
|
||||
let secret_key = SecretKey::from_slice(&hex::decode(data_slice).unwrap()).unwrap();
|
||||
|
||||
//let public_key = PublicKey::from_secret_key(&context, &secret_key);
|
||||
|
||||
// Use Testnet
|
||||
let bitcoin_private_key = PrivateKey::new(secret_key, Network::Testnet);
|
||||
|
||||
let bitcoin_public_key = BitcoinPubKey::from_private_key(&context, &bitcoin_private_key);
|
||||
|
||||
let pub_address = Address::p2pkh(&bitcoin_public_key, Network::Testnet);
|
||||
|
||||
Ok(Self {
|
||||
secret_key,
|
||||
bitcoin_private_key,
|
||||
bitcoin_public_key,
|
||||
pub_address,
|
||||
})
|
||||
}
|
||||
pub fn get_deposit_address(&self) -> &Address {
|
||||
&self.pub_address
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CashierService {
|
||||
addr: SocketAddr,
|
||||
cashierstore: Arc<CashierStore>,
|
||||
wallet: Arc<WalletDb>,
|
||||
}
|
||||
|
||||
impl CashierService {
|
||||
pub fn new(
|
||||
addr: SocketAddr,
|
||||
rocks: RocksColumn<columns::CashierKeys>,
|
||||
wallet: Arc<WalletDb>,
|
||||
)-> Result<Arc<CashierService>> {
|
||||
let cashierstore = CashierStore::new(rocks)?;
|
||||
|
||||
Ok(Arc::new(CashierService {
|
||||
cashierstore,
|
||||
addr,
|
||||
wallet,
|
||||
}))
|
||||
}
|
||||
pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
|
||||
let service_name = String::from("CASHIER DAEMON");
|
||||
|
||||
let mut protocol = RepProtocol::new(self.addr.clone(), service_name.clone());
|
||||
|
||||
let (send, recv) = protocol.start().await?;
|
||||
|
||||
let handle_request_task = executor.spawn(self.handle_request_loop(
|
||||
send.clone(),
|
||||
recv.clone(),
|
||||
executor.clone(),
|
||||
));
|
||||
|
||||
protocol.run(executor.clone()).await?;
|
||||
|
||||
let _ = handle_request_task.cancel().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_request_loop(
|
||||
self: Arc<Self>,
|
||||
send_queue: async_channel::Sender<(PeerId, Reply)>,
|
||||
recv_queue: async_channel::Receiver<(PeerId, Request)>,
|
||||
executor: Arc<Executor<'_>>,
|
||||
) -> Result<()> {
|
||||
loop {
|
||||
match recv_queue.recv().await {
|
||||
Ok(msg) => {
|
||||
let cashierstore = self.cashierstore.clone();
|
||||
let _ = executor
|
||||
.spawn(Self::handle_request(
|
||||
msg,
|
||||
cashierstore,
|
||||
send_queue.clone(),
|
||||
))
|
||||
.detach();
|
||||
}
|
||||
Err(_) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn handle_request(
|
||||
msg: (PeerId, Request),
|
||||
cashierstore: Arc<CashierStore>,
|
||||
send_queue: async_channel::Sender<(PeerId, Reply)>,
|
||||
) -> Result<()> {
|
||||
let request = msg.1;
|
||||
let peer = msg.0;
|
||||
match request.get_command() {
|
||||
0 => {
|
||||
// Exchange zk_pubkey for bitcoin address
|
||||
let zkpub = request.get_payload();
|
||||
|
||||
// Generate bitcoin Address
|
||||
let btc_keys = BitcoinKeys::new().unwrap();
|
||||
let deposit_address = btc_keys.get_deposit_address();
|
||||
|
||||
let mut reply = Reply::from(&request, CashierError::NoError as u32, vec![]);
|
||||
// if let None = error {
|
||||
// reply.set_error(CashierError::UpdateIndex as u32);
|
||||
// }
|
||||
// send reply
|
||||
send_queue.send((peer, reply)).await?;
|
||||
|
||||
}
|
||||
1 => {
|
||||
// Withdraw
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::ServicesError("received wrong command"));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CashierClient {
|
||||
protocol: ReqProtocol,
|
||||
cashierstore: Arc<CashierStore>,
|
||||
}
|
||||
|
||||
impl CashierClient {
|
||||
pub fn new(addr: SocketAddr, rocks: RocksColumn<columns::CashierKeys>) -> Result<Self> {
|
||||
let protocol = ReqProtocol::new(addr, String::from("CASHIER CLIENT"));
|
||||
|
||||
let cashierstore = CashierStore::new(rocks)?;
|
||||
|
||||
Ok(CashierClient {
|
||||
protocol,
|
||||
cashierstore,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn start(&mut self) -> Result<()> {
|
||||
self.protocol.start().await?;
|
||||
//self.sync().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_keys(&mut self, index: jubjub::SubgroupPoint) -> Result<Option<CashierKeypair>> {
|
||||
let rep = self
|
||||
.protocol
|
||||
.request(
|
||||
CashierCommand::GetDBTC as u8,
|
||||
serialize(&index),
|
||||
&handle_error,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(keys) = rep {
|
||||
let keys: CashierKeypair = deserialize(&keys)?;
|
||||
//self.gateway_slabs_sub_s.send(slab.clone()).await?;
|
||||
self.cashierstore.put(keys.clone())?;
|
||||
return Ok(Some(keys));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
// pub async fn put_keys(&mut self, mut keys: CashierKeys) -> Result<()> {
|
||||
// loop {
|
||||
// let last_index = self.sync().await?;
|
||||
// //keys.set_index(last_index + 1);
|
||||
// let keys = serialize(&keys);
|
||||
|
||||
// let rep = self
|
||||
// .protocol
|
||||
// .request(CashierCommand::PutSlab as u8, slab.clone(), &handle_error)
|
||||
// .await?;
|
||||
|
||||
// if let Some(_) = rep {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
pub fn get_cashierstore(&self) -> Arc<CashierStore> {
|
||||
self.cashierstore.clone()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn handle_error(status_code: u32) {
|
||||
match status_code {
|
||||
1 => {
|
||||
warn!("Reply has an Error: Index is not updated");
|
||||
}
|
||||
2 => {
|
||||
warn!("Reply has an Error: Index Not Exist");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
pub mod gateway;
|
||||
pub mod reqrep;
|
||||
pub mod bitcoin_bridge;
|
||||
|
||||
pub use gateway::{GatewayClient, GatewayService, GatewaySlabsSubscriber};
|
||||
|
||||
pub use bitcoin_bridge::{BitcoinKeys, CashierService, CashierClient};
|
||||
|
||||
@@ -68,7 +68,7 @@ impl WalletDb {
|
||||
|
||||
pub fn init_cashier_db(&self) -> Result<()> {
|
||||
let conn = Connection::open(&self.path)?;
|
||||
debug!(target: "walletdb", "OPENED CONNECTION AT PATH {:?}", self.path);
|
||||
debug!(target: "cashierdb", "OPENED CONNECTION AT PATH {:?}", self.path);
|
||||
let contents = include_str!("../../res/schema.sql");
|
||||
conn.execute_batch(&contents)?;
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user