Преглед изворни кода

bin/cashierd2.rs: basic skeleton of cashierd rewrite w deposit

lunar-mining пре 4 година
родитељ
комит
f13312824e
1 измењених фајлова са 236 додато и 0 уклоњено
  1. 236 0
      src/bin/cashierd2.rs

+ 236 - 0
src/bin/cashierd2.rs

@@ -0,0 +1,236 @@
+use async_std::sync::Arc;
+use log::*;
+use std::path::PathBuf;
+
+use clap::clap_app;
+use serde::{Deserialize, Serialize};
+use serde_json::{json, Value};
+use simplelog::{
+    CombinedLogger, Config as SimLogConfig, ConfigBuilder, LevelFilter, TermLogger, TerminalMode,
+    WriteLogger,
+};
+use tokio::io::{AsyncReadExt, AsyncWriteExt};
+use tokio::net::TcpListener;
+
+use drk::{
+    cli::Config,
+    rpc::{
+        jsonrpc::{error as jsonerr, response as jsonresp},
+        jsonrpc::{ErrorCode::*, JsonRequest, JsonResult},
+    },
+    serial::{deserialize, serialize},
+    service::bridge,
+    util::join_config_path,
+    wallet::CashierDb,
+    Result,
+};
+
+#[derive(Clone, Serialize, Deserialize, Debug)]
+struct CashierdConfig {
+    #[serde(rename = "accept_url")]
+    pub accept_url: String,
+
+    #[serde(rename = "rpc_url")]
+    pub rpc_url: String,
+
+    #[serde(rename = "gateway_url")]
+    pub gateway_url: String,
+
+    #[serde(rename = "log_path")]
+    pub log_path: String,
+
+    #[serde(rename = "cashierdb_path")]
+    pub cashierdb_path: String,
+
+    #[serde(rename = "password")]
+    pub password: String,
+
+    #[serde(rename = "client_password")]
+    pub client_password: String,
+}
+
+#[derive(Clone)]
+struct Cashierd {
+    verbose: bool,
+    config: CashierdConfig,
+    wallet: Arc<CashierDb>,
+    bridge: Arc<bridge::Bridge>,
+    // clientdb:
+    // mint_params:
+    // spend_params:
+}
+
+impl Cashierd {
+    fn new(verbose: bool, config_path: PathBuf) -> Result<Self> {
+        let config: CashierdConfig = Config::<CashierdConfig>::load(config_path)?;
+        let wallet = CashierDb::new(
+            &PathBuf::from(config.cashierdb_path.clone()),
+            config.password.clone(),
+        )?;
+        let bridge = bridge::Bridge::new();
+
+        Ok(Self {
+            verbose,
+            config,
+            wallet,
+            bridge,
+        })
+    }
+
+    //async fn bridge_subscribe() -> Result<()> {
+    //    Ok(())
+    //}
+
+    async fn handle_request(self, req: JsonRequest) -> JsonResult {
+        if req.params.as_array().is_none() {
+            return JsonResult::Err(jsonerr(InvalidParams, None, req.id));
+        }
+
+        debug!(target: "RPC", "--> {:#?}", serde_json::to_string(&req).unwrap());
+
+        match req.method.as_str() {
+            //Some("say_hello") => return self.say_hello(req.id, req.params).await,
+            //Some("create_wallet") => return self.create_wallet(req.id, req.params).await,
+            //Some("key_gen") => return self.key_gen(req.id, req.params).await,
+            //Some("get_key") => return self.get_key(req.id, req.params).await,
+            Some("deposit") => return self.deposit(req.id, req.params).await,
+            //Some("withdraw") => return self.withdraw(req.id, req.params).await,
+            //Some("transfer") => return self.transfer(req.id, req.params).await,
+            Some(_) => {}
+            None => {}
+        };
+
+        return JsonResult::Err(jsonerr(MethodNotFound, None, req.id));
+    }
+
+    async fn deposit(self, id: Value, params: Value) -> JsonResult {
+        debug!(target: "CASHIER", "Received deposit request");
+        let args = params.as_array().unwrap();
+        if args.len() != 2 {
+            return JsonResult::Err(jsonerr(InvalidParams, None, id));
+        }
+
+        let _network = &args[0];
+        let _token: jubjub::Fr = deserialize(&args[1].as_str().unwrap().as_bytes()).unwrap();
+        let pubkey: jubjub::SubgroupPoint =
+            deserialize(&args[2].as_str().unwrap().as_bytes()).unwrap();
+
+        // TODO: Sanity check.
+        let _check = self
+            .wallet
+            .get_deposit_coin_keys_by_dkey_public(&pubkey, &serialize(&1));
+
+        // TODO: implement bridge communication
+        //let bridge_subscription = bridge.subscribe(ex.clone()).await;
+        //bridge_subscribtion
+        //    .sender
+        //    .send(bridge::BridgeRequests {
+        //        token,
+        //        payload: bridge::BridgeRequestsPayload::WatchRequest,
+        //    })
+        //    .await
+        //    .unwrap();
+
+        //    let bridge_res = bridge_subscribtion.receiver.recv().await?;
+
+        //    match bridge_res.payload {
+        //        bridge::BridgeResponsePayload::WatchResponse(coin_priv, coin_pub) => {
+        //            // add pairings to db
+        //            let _result = cashier_wallet.put_exchange_keys(
+        //                &dpub,
+        //                &coin_priv,
+        //                &coin_pub,
+        //                &serialize(&asset_id),
+        //            );
+
+        // TODO: read pubkey from wallet. This is just a stand-in
+        let pubkey = bs58::encode(serialize(&pubkey)).into_string();
+
+        JsonResult::Resp(jsonresp(json!(pubkey), json!(id)))
+    }
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+    let args = clap_app!(cashierd =>
+        (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
+        (@arg verbose: -v --verbose "Increase verbosity")
+    )
+    .get_matches();
+
+    let config_path: PathBuf;
+
+    if args.is_present("CONFIG") {
+        config_path = PathBuf::from(args.value_of("CONFIG").unwrap());
+    } else {
+        config_path = join_config_path(&PathBuf::from("cashierd.toml"))?;
+    }
+
+    let cashierd = Cashierd::new(args.clone().is_present("verbose"), config_path)?;
+    // TODO: TLS
+    let listener = TcpListener::bind(cashierd.clone().config.rpc_url).await?;
+    debug!(target: "RPC SERVER", "Listening on {}", cashierd.clone().config.rpc_url);
+
+    let logger_config = ConfigBuilder::new().set_time_format_str("%T%.6f").build();
+    let debug_level = if args.is_present("verbose") {
+        LevelFilter::Debug
+    } else {
+        LevelFilter::Off
+    };
+
+    let log_path = cashierd.clone().config.log_path;
+    CombinedLogger::init(vec![
+        TermLogger::new(debug_level, logger_config, TerminalMode::Mixed).unwrap(),
+        WriteLogger::new(
+            LevelFilter::Debug,
+            SimLogConfig::default(),
+            std::fs::File::create(log_path).unwrap(),
+        ),
+    ])
+    .unwrap();
+    loop {
+        debug!(target: "RPC SERVER", "waiting for client");
+
+        let (mut socket, _) = listener.accept().await?;
+        let cashierd = cashierd.clone();
+
+        debug!(target: "RPC SERVER", "accepted client");
+
+        tokio::spawn(async move {
+            let mut buf = [0; 2048];
+
+            loop {
+                let n = match socket.read(&mut buf).await {
+                    Ok(n) if n == 0 => {
+                        debug!(target: "RPC SERVER", "closed connection");
+                        return;
+                    }
+                    Ok(n) => n,
+                    Err(e) => {
+                        debug!(target: "RPC SERVER", "failed to read from socket; err = {:?}", e);
+                        return;
+                    }
+                };
+
+                let r: JsonRequest = match serde_json::from_slice(&buf[0..n]) {
+                    Ok(r) => r,
+                    Err(e) => {
+                        debug!(target: "RPC SERVER", "received invalid json; err = {:?}", e);
+                        return;
+                    }
+                };
+
+                let reply = cashierd.clone().handle_request(r).await;
+                let j = serde_json::to_string(&reply).unwrap();
+
+                debug!(target: "RPC", "<-- {:#?}", j);
+
+                // Write the data back
+                if let Err(e) = socket.write_all(j.as_bytes()).await {
+                    debug!(target: "RPC SERVER", "failed to write to socket; err = {:?}", e);
+                    return;
+                }
+            }
+        });
+    }
+}