Prechádzať zdrojové kódy

Merge branch 'master' of github.com:darkrenaissance/darkfi

ghassmo 4 rokov pred
rodič
commit
5935d81782

+ 17 - 36
Cargo.lock

@@ -314,6 +314,19 @@ dependencies = [
  "syn 1.0.76",
 ]
 
+[[package]]
+name = "async-tungstenite"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "742cc7dcb20b2f84a42f4691aa999070ec7e78f8e7e7438bf14be7017b44907e"
+dependencies = [
+ "futures-io",
+ "futures-util",
+ "log",
+ "pin-project-lite",
+ "tungstenite 0.15.0",
+]
+
 [[package]]
 name = "asynchronous-codec"
 version = "0.6.0"
@@ -1170,6 +1183,7 @@ dependencies = [
  "async-native-tls",
  "async-std",
  "async-trait",
+ "async-tungstenite",
  "bellman",
  "bimap",
  "bitcoin",
@@ -1206,8 +1220,8 @@ dependencies = [
  "solana-client",
  "solana-sdk",
  "spl-token",
- "tokio-tungstenite",
  "toml",
+ "tungstenite 0.15.0",
  "url",
  "zcash_primitives",
  "zcash_proofs",
@@ -2724,26 +2738,6 @@ dependencies = [
  "ucd-trie",
 ]
 
-[[package]]
-name = "pin-project"
-version = "1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08"
-dependencies = [
- "pin-project-internal",
-]
-
-[[package]]
-name = "pin-project-internal"
-version = "1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389"
-dependencies = [
- "proc-macro2 1.0.29",
- "quote 1.0.9",
- "syn 1.0.76",
-]
-
 [[package]]
 name = "pin-project-lite"
 version = "0.2.7"
@@ -4317,19 +4311,6 @@ dependencies = [
  "webpki",
 ]
 
-[[package]]
-name = "tokio-tungstenite"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8"
-dependencies = [
- "futures-util",
- "log",
- "pin-project",
- "tokio",
- "tungstenite 0.14.0",
-]
-
 [[package]]
 name = "tokio-util"
 version = "0.6.8"
@@ -4407,9 +4388,9 @@ dependencies = [
 
 [[package]]
 name = "tungstenite"
-version = "0.14.0"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5"
+checksum = "983d40747bce878d2fb67d910dcb8bd3eca2b2358540c3cc1b98c027407a3ae3"
 dependencies = [
  "base64 0.13.0",
  "byteorder",

+ 4 - 2
Cargo.toml

@@ -44,6 +44,9 @@ async-native-tls = "0.3.3"
 native-tls = "0.2.8"
 easy-parallel = "3.1.0"
 
+tungstenite = "0.15.0"
+async-tungstenite = "0.15.0"
+
 simple_logger = "1.13.0"
 log = "0.4.14"
 clap = "2.33.3"
@@ -62,7 +65,6 @@ rocksdb = {version = "0.16.0", default-features = false, features = ["lz4"]}
 spl-token = {version = "3.2.0", optional = true}
 solana-sdk = {version = "1.7.11", optional = true}
 solana-client = {version = "1.7.11", optional = true}
-tokio-tungstenite = {version = "0.15.0", optional = true} 
 
 ## Cashier Bitcoin Dependencies
 bitcoin = {version = "0.27.0", optional = true }
@@ -80,4 +82,4 @@ features = ["async-std-runtime", "all-transport"]
 
 [features]
 btc = ["bitcoin", "secp256k1", "electrum-client"]
-sol = ["solana-sdk", "solana-client", "spl-token", "tokio-tungstenite"]
+sol = ["solana-sdk", "solana-client", "spl-token"]

+ 2 - 2
script/research/halo/halo2.sage

@@ -274,7 +274,7 @@ for a in range(5):
         current = last_y_value
 
         # i iterates over the columns in our partition
-        for i in range(a * m, (a + 1)):
+        for i in range(a * m, (a + 1) * m):
             current *= v[i][j] + beta * delta^i * omega^j + gamma
             current /= v[i][j] + beta * s[i][j] + gamma
 
@@ -308,7 +308,7 @@ gate_3 = f_4_X * (a_1_X * a_2_X * a_3_X - a_4_X)
 c = gate_0 + y * gate_1 + y^2 * gate_2 + y^3 * gate_3
 t = X^n - 1
 for i in range(n):
-    assert h(omega^i) == 0
+    assert c(omega^i) == 0
 # Normally we do:
 #h = c / t
 # But for some reason sage is producing fractional coefficients

+ 1 - 1
src/bin/cashierd.rs

@@ -112,7 +112,7 @@ impl Cashierd {
     }
 
     async fn start(&self, executor: Arc<Executor<'static>>) -> Result<()> {
-        self.cashier_wallet.init_db()?;
+        self.cashier_wallet.init_db().await?;
 
 
         for (feature_name, _) in self.features.iter() {

+ 7 - 3
src/bin/darkfid.rs

@@ -77,7 +77,7 @@ impl Darkfid {
     // --> {"method": "create_wallet", "params": []}
     // <-- {"result": true}
     async fn create_wallet(&self, id: Value, _params: Value) -> JsonResult {
-        match self.wallet.init_db() {
+        match self.wallet.init_db().await {
             Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
             Err(e) => {
                 return JsonResult::Err(jsonerr(ServerError(-32001), Some(e.to_string()), id))
@@ -89,7 +89,12 @@ impl Darkfid {
     // <-- {"result": true}
     async fn key_gen(&self, id: Value, _params: Value) -> JsonResult {
         match self.wallet.key_gen() {
-            Ok((_, _)) => return JsonResult::Resp(jsonresp(json!(true), id)),
+            Ok((public, private)) => match self.wallet.put_keypair(public, private) {
+                Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
+                Err(e) => {
+                    return JsonResult::Err(jsonerr(ServerError(-32002), Some(e.to_string()), id))
+                }
+            },
             Err(e) => {
                 return JsonResult::Err(jsonerr(ServerError(-32002), Some(e.to_string()), id))
             }
@@ -157,7 +162,6 @@ impl Darkfid {
     // --> {""method": "features", "params": []}
     // <-- {"result": { "network": ["btc", "sol"] } }
     async fn features(&self, id: Value, _params: Value) -> JsonResult {
-        // TODO: return a dictionary of features
         let req = jsonreq(json!("features"), json!([]));
         let rep: JsonResult;
         match send_request(&self.config.cashier_rpc_url, json!(req)).await {

+ 2 - 0
src/client/mod.rs

@@ -14,6 +14,7 @@ pub enum ClientFailed {
     DoNotHaveCashierPublicKey,
     DoNotHaveKeypair,
     EmptyPassword,
+    WalletInitialized,
     ClientError(String),
 }
 
@@ -38,6 +39,7 @@ impl fmt::Display for ClientFailed {
             ClientFailed::DoNotHaveCashierPublicKey => f.write_str("Don't have cashier public key"),
             ClientFailed::DoNotHaveKeypair => f.write_str("Don't have keypair"),
             ClientFailed::EmptyPassword => f.write_str("Password is empty. Cannot create database"),
+            ClientFailed::WalletInitialized => f.write_str("Wallet already initalized"),
             ClientFailed::ClientError(i) => {
                 write!(f, "ClientError: {}", i)
             }

+ 8 - 0
src/error.rs

@@ -64,6 +64,7 @@ pub enum Error {
     ConfigNotFound,
     SetLoggerError,
     TokenParseError,
+    TungsteniteError,
 }
 
 impl std::error::Error for Error {}
@@ -129,6 +130,7 @@ impl fmt::Display for Error {
             }
             Error::SetLoggerError => f.write_str("SetLoggerError"),
             Error::TokenParseError => f.write_str("Could not parse token list"),
+            Error::TungsteniteError => f.write_str("TungsteniteError"),
         }
     }
 }
@@ -284,3 +286,9 @@ impl From<log::SetLoggerError> for Error {
         Error::SetLoggerError
     }
 }
+
+impl From<tungstenite::Error> for Error {
+    fn from(_err: tungstenite::Error) -> Error {
+        Error::TungsteniteError
+    }
+}

+ 1 - 1
src/rpc/mod.rs

@@ -1,3 +1,3 @@
-// pub mod adapter;
 pub mod jsonrpc;
 pub mod rpcserver;
+pub mod websockets;

+ 95 - 0
src/rpc/websockets.rs

@@ -0,0 +1,95 @@
+use async_native_tls::{TlsConnector, TlsStream};
+use async_tungstenite::WebSocketStream;
+use futures::sink::Sink;
+use smol::{prelude::*, Async};
+use std::net::{TcpStream, ToSocketAddrs};
+use std::pin::Pin;
+use std::task::{Context, Poll};
+use tungstenite::handshake::client::Response;
+use tungstenite::Message;
+use url::Url;
+
+use crate::{Error, Result as DrkResult};
+
+pub enum WsStream {
+    Tcp(WebSocketStream<Async<TcpStream>>),
+    Tls(WebSocketStream<TlsStream<Async<TcpStream>>>),
+}
+
+impl Sink<Message> for WsStream {
+    type Error = tungstenite::Error;
+
+    fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        match &mut *self {
+            WsStream::Tcp(s) => Pin::new(s).poll_ready(cx),
+            WsStream::Tls(s) => Pin::new(s).poll_ready(cx),
+        }
+    }
+
+    fn start_send(mut self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
+        match &mut *self {
+            WsStream::Tcp(s) => Pin::new(s).start_send(item),
+            WsStream::Tls(s) => Pin::new(s).start_send(item),
+        }
+    }
+
+    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        match &mut *self {
+            WsStream::Tcp(s) => Pin::new(s).poll_flush(cx),
+            WsStream::Tls(s) => Pin::new(s).poll_flush(cx),
+        }
+    }
+
+    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+        match &mut *self {
+            WsStream::Tcp(s) => Pin::new(s).poll_close(cx),
+            WsStream::Tls(s) => Pin::new(s).poll_close(cx),
+        }
+    }
+}
+
+impl Stream for WsStream {
+    type Item = tungstenite::Result<Message>;
+
+    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        match &mut *self {
+            WsStream::Tcp(s) => Pin::new(s).poll_next(cx),
+            WsStream::Tls(s) => Pin::new(s).poll_next(cx),
+        }
+    }
+}
+
+/// Connects to a WebSocket address (optionally secured by TLS).
+pub async fn connect(addr: &str, tls: TlsConnector) -> DrkResult<(WsStream, Response)> {
+    let url = Url::parse(addr)?;
+    let host = url
+        .host_str()
+        .ok_or_else(|| Error::UrlParseError)?
+        .to_string();
+    let port = url
+        .port_or_known_default()
+        .ok_or_else(|| Error::UrlParseError)?;
+
+    let socket_addr = {
+        let host = host.clone();
+        smol::unblock(move || (host.as_str(), port).to_socket_addrs())
+            .await?
+            .next()
+            .ok_or_else(|| Error::UrlParseError)?
+    };
+
+    match url.scheme() {
+        "ws" => {
+            let stream = Async::<TcpStream>::connect(socket_addr).await?;
+            let (stream, resp) = async_tungstenite::client_async(addr, stream).await?;
+            Ok((WsStream::Tcp(stream), resp))
+        }
+        "wss" => {
+            let stream = Async::<TcpStream>::connect(socket_addr).await?;
+            let stream = tls.connect(host, stream).await?;
+            let (stream, resp) = async_tungstenite::client_async(addr, stream).await?;
+            Ok((WsStream::Tls(stream), resp))
+        }
+        _scheme => Err(Error::UrlParseError),
+    }
+}

+ 11 - 11
src/service/sol.rs

@@ -1,12 +1,13 @@
-use crate::rpc::{jsonrpc, jsonrpc::JsonResult};
+use crate::rpc::{jsonrpc, jsonrpc::JsonResult, websockets::connect};
 use crate::serial::{deserialize, serialize, Decodable, Encodable};
 use crate::{Error, Result};
 
 use super::bridge::{TokenClient, TokenNotification, TokenSubscribtion};
 
-use async_trait::async_trait;
-
 use async_executor::Executor;
+use async_native_tls::TlsConnector;
+use async_std::sync::{Arc, Mutex};
+use async_trait::async_trait;
 use futures::{SinkExt, StreamExt};
 use log::*;
 use rand::rngs::OsRng;
@@ -17,12 +18,10 @@ use solana_sdk::{
     pubkey::Pubkey, signature::Signer, signer::keypair::Keypair, system_instruction,
     transaction::Transaction,
 };
-use tokio_tungstenite::{connect_async, tungstenite, tungstenite::protocol::Message};
-
-use async_std::sync::{Arc, Mutex};
 use std::collections::HashMap;
 use std::convert::TryFrom;
 use std::str::FromStr;
+use tungstenite::Message;
 
 //const RPC_SERVER: &str = "https://api.mainnet-beta.solana.com";
 //const WSS_SERVER: &str = "wss://api.mainnet-beta.solana.com";
@@ -71,9 +70,10 @@ impl SolClient {
 
     pub async fn run(self: Arc<Self>, executor: Arc<Executor<'_>>) -> SolResult<()> {
         // WebSocket handshake/connect
-        let (ws_stream, _) = connect_async(WSS_SERVER).await?;
-
-        let (mut write, read) = ws_stream.split();
+        let builder = native_tls::TlsConnector::builder();
+        let tls = TlsConnector::from(builder);
+        let (stream, _) = connect(WSS_SERVER, tls).await?;
+        let (mut write, read) = stream.split();
 
         let self2 = self.clone();
         let _: async_executor::Task<Result<()>> = executor.spawn(async move {
@@ -83,13 +83,13 @@ impl SolClient {
 
                 // write the request to websocket
                 write
-                    .send(Message::Text(serde_json::to_string(&sub_msg)?))
+                    .send(Message::text(serde_json::to_string(&sub_msg)?))
                     .await
                     .map_err(|err| SolFailed::from(err))?;
             }
         });
 
-        read.for_each(|message| async {
+        futures::StreamExt::for_each(read, |message| async {
             // read ws msg
             self.clone()
                 .read_ws_msg(message)

+ 18 - 10
src/wallet/cashierdb.rs

@@ -2,7 +2,7 @@ use super::{Keypair, WalletApi};
 use crate::client::ClientFailed;
 use crate::{Error, Result};
 
-use async_std::sync::Arc;
+use async_std::sync::{Arc, Mutex};
 use log::*;
 use rusqlite::{named_params, params, Connection};
 
@@ -13,6 +13,7 @@ pub type CashierDbPtr = Arc<CashierDb>;
 pub struct CashierDb {
     pub path: PathBuf,
     pub password: String,
+    pub initialized: Mutex<bool>,
 }
 
 impl WalletApi for CashierDb {
@@ -30,19 +31,26 @@ impl CashierDb {
         Ok(Arc::new(Self {
             path: path.to_owned(),
             password,
+            initialized: Mutex::new(false),
         }))
     }
 
-    pub fn init_db(&self) -> Result<()> {
-        if !self.password.trim().is_empty() {
-            let contents = include_str!("../../sql/cashier.sql");
-            let conn = Connection::open(&self.path)?;
-            debug!(target: "CASHIERDB", "Opened connection at path {:?}", self.path);
-            conn.pragma_update(None, "key", &self.password)?;
-            conn.execute_batch(&contents)?;
+    pub async fn init_db(&self) -> Result<()> {
+        if *self.initialized.lock().await == false {
+            if !self.password.trim().is_empty() {
+                let contents = include_str!("../../sql/cashier.sql");
+                let conn = Connection::open(&self.path)?;
+                debug!(target: "CASHIERDB", "Opened connection at path {:?}", self.path);
+                conn.pragma_update(None, "key", &self.password)?;
+                conn.execute_batch(&contents)?;
+                *self.initialized.lock().await = true;
+            } else {
+                debug!(target: "CASHIERDB", "Password is empty. You must set a password to use the wallet.");
+                return Err(Error::from(ClientFailed::EmptyPassword));
+            }
         } else {
-            debug!(target: "CASHIERDB", "Password is empty. You must set a password to use the wallet.");
-            return Err(Error::from(ClientFailed::EmptyPassword));
+            debug!(target: "WALLETDB", "Wallet already initialized.");
+            return Err(Error::from(ClientFailed::WalletInitialized));
         }
         Ok(())
     }

+ 19 - 11
src/wallet/walletdb.rs

@@ -6,7 +6,7 @@ use crate::crypto::{
 use crate::serial;
 use crate::{Error, Result};
 
-use async_std::sync::Arc;
+use async_std::sync::{Arc, Mutex};
 use ff::Field;
 use log::*;
 use rand::rngs::OsRng;
@@ -22,10 +22,11 @@ pub struct Keypair {
     pub private: jubjub::Fr,
 }
 
-#[derive(Clone)]
+//#[derive(Clone)]
 pub struct WalletDb {
     pub path: PathBuf,
     pub password: String,
+    pub initialized: Mutex<bool>,
 }
 
 impl WalletApi for WalletDb {
@@ -43,19 +44,26 @@ impl WalletDb {
         Ok(Arc::new(Self {
             path: path.to_owned(),
             password,
+            initialized: Mutex::new(false),
         }))
     }
 
-    pub fn init_db(&self) -> Result<()> {
-        if !self.password.trim().is_empty() {
-            let contents = include_str!("../../sql/schema.sql");
-            let conn = Connection::open(&self.path)?;
-            debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", self.path);
-            conn.pragma_update(None, "key", &self.password)?;
-            conn.execute_batch(&contents)?;
+    pub async fn init_db(&self) -> Result<()> {
+        if *self.initialized.lock().await == false {
+            if !self.password.trim().is_empty() {
+                let contents = include_str!("../../sql/schema.sql");
+                let conn = Connection::open(&self.path)?;
+                debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", self.path);
+                conn.pragma_update(None, "key", &self.password)?;
+                conn.execute_batch(&contents)?;
+                *self.initialized.lock().await = true;
+            } else {
+                debug!(target: "WALLETDB", "Password is empty. You must set a password to use the wallet.");
+                return Err(Error::from(ClientFailed::EmptyPassword));
+            }
         } else {
-            debug!(target: "WALLETDB", "Password is empty. You must set a password to use the wallet.");
-            return Err(Error::from(ClientFailed::EmptyPassword));
+            debug!(target: "WALLETDB", "Wallet already initialized.");
+            return Err(Error::from(ClientFailed::WalletInitialized));
         }
         Ok(())
     }

+ 2 - 2
todo.md

@@ -10,11 +10,11 @@
 - [ ] change assetID variable to network and add switch statement in cashier::start()
 - [ ] Optional Cargo "features" for cashierd/darkfid, to {en,dis}able different chains
 - [ ] cashierd config has explicit mainnet and testnet configurations, simplify this and have a single endpoint
-- [ ] drk -wk reports success on subsequent calls, it should rather tell that things are already initialized
+- [X] drk -wk reports success on subsequent calls, it should rather tell that things are already initialized
 - [ ] use f64 (and only positive/absolute) for amounts only on the client-facing side. internally, use u64 and num of decimals
 - [ ] drk2: retrieve cashier features and error if don't support the network
 - [ ] darkfid: match 'bitcoin' to 'btc'
-- [ ] standardize error handling in drk2, cashierd, darkfid
+- [X] standardize error handling in drk2, cashierd, darkfid
 
 ## deposit