Janus 4 жил өмнө
parent
commit
780d9ccb3a
2 өөрчлөгдсөн 125 нэмэгдсэн , 131 устгасан
  1. 13 12
      src/bin/cashierd.rs
  2. 112 119
      src/service/btc.rs

+ 13 - 12
src/bin/cashierd.rs

@@ -403,18 +403,19 @@ impl Cashierd {
                 #[cfg(feature = "btc")]
                 #[cfg(feature = "btc")]
                 "btc" | "bitcoin" => {
                 "btc" | "bitcoin" => {
                     debug!(target: "CASHIER DAEMON", "Add btc network");
                     debug!(target: "CASHIER DAEMON", "Add btc network");
-                    let btc_endpoint: (bitcoin::network::constants::Network, String) = (
-                        bitcoin::network::constants::Network::Bitcoin,
-                        String::from("ssl://blockstream.info:993"),
-                    );
-                    use drk::service::btc::BtcClient;
-                    let _btc_client = BtcClient::new(btc_endpoint)?;
-                    // NOTE bitcoin is not implemented yet
-                    //
-                    // TODO check if there is main_keypair inside
-                    // cashierdb before generating new one
-                    //
-                    //bridge2.add_clients("btc".into(), btc_client).await?;
+                    use drk::service::btc::{BtcClient, BitcoinKeys};
+                    let _main_keypair: BitcoinKeys;
+
+                    let _main_keypairs = self.cashier_wallet.get_main_keys(&"btc".into())?;
+                    // if main_keypairs.is_empty() {
+                    //     //main_keypair = BitcoinKeys::new(bitcoin::network::constants::Network::Testnet)?;
+                    // } else {
+                    //     //main_keypair = deserialize(&main_keypairs[0].0)?;
+                    // }
+
+                    // let btc_client = BtcClient::new(main_keypair)?;
+
+                    // bridge2.add_clients("btc".into(), btc_client).await?;
                 }
                 }
 
 
                 _ => {
                 _ => {

+ 112 - 119
src/service/btc.rs

@@ -4,176 +4,169 @@ use crate::Result;
 
 
 use async_trait::async_trait;
 use async_trait::async_trait;
 use bitcoin::blockdata::script::Script;
 use bitcoin::blockdata::script::Script;
-use bitcoin::hash_types::Txid;
+use bitcoin::hash_types::{PubkeyHash as BtcPubKeyHash, Txid};
 use bitcoin::network::constants::Network;
 use bitcoin::network::constants::Network;
 use bitcoin::util::address::Address;
 use bitcoin::util::address::Address;
-use bitcoin::util::ecdsa::{PrivateKey, PublicKey};
+use bitcoin::util::ecdsa::{PrivateKey as BtcPrivKey, PublicKey as BtcPubKey};
 use electrum_client::{Client as ElectrumClient, ElectrumApi};
 use electrum_client::{Client as ElectrumClient, ElectrumApi};
 use log::*;
 use log::*;
-use rand::distributions::Alphanumeric;
-use rand::{thread_rng, Rng};
-use secp256k1::key::SecretKey;
+
+use secp256k1::key::{PublicKey, SecretKey};
+use secp256k1::{rand::rngs::OsRng, Secp256k1};
 
 
 use async_std::sync::Arc;
 use async_std::sync::Arc;
 use std::str::FromStr;
 use std::str::FromStr;
 
 
 // Swap out these types for any future non bitcoin-rs types
 // Swap out these types for any future non bitcoin-rs types
 pub type PubAddress = Address;
 pub type PubAddress = Address;
-pub type PubKey = PublicKey;
-pub type PrivKey = PrivateKey;
+pub type PubKey = BtcPubKey;
+pub type PrivKey = BtcPrivKey;
+
+const ELECTRUM_SERVER: &str = "ssl://blockstream.info:993";
 
 
 pub struct BitcoinKeys {
 pub struct BitcoinKeys {
-    _secret_key: SecretKey,
-    bitcoin_private_key: PrivateKey,
-    btc_client: Arc<ElectrumClient>,
-    pub bitcoin_public_key: PublicKey,
-    pub pub_address: Address,
-    pub script: Script,
+    secret_key: SecretKey,
+    public_key: PublicKey,
+    _context: Secp256k1<secp256k1::All>,
+    btc_privkey: BtcPrivKey,
+    pub btc_pubkey: BtcPubKey,
     pub network: Network,
     pub network: Network,
 }
 }
 
 
 impl BitcoinKeys {
 impl BitcoinKeys {
-    pub fn new(btc_client: Arc<ElectrumClient>, network: Network) -> Result<Arc<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();
+    pub fn new(network: Network) -> Result<Arc<BitcoinKeys>> {
+        let secp = Secp256k1::new();
+        let mut rng = OsRng::new().expect("OsRng");
 
 
-        // Use Testnet
-        let bitcoin_private_key = PrivateKey::new(secret_key, network);
+        let (secret_key, public_key) = secp.generate_keypair(&mut rng);
 
 
-        let bitcoin_public_key = PublicKey::from_private_key(&context, &bitcoin_private_key);
-        //let pubkey_serialized = bitcoin_public_key.to_bytes();
-
-        let pub_address = Address::p2pkh(&bitcoin_public_key, network);
-
-        let script = Script::new_p2pk(&bitcoin_public_key);
+        let btc_privkey = BtcPrivKey::new(secret_key, network);
+        let btc_pubkey = btc_privkey.public_key(&secp);
 
 
         Ok(Arc::new(BitcoinKeys {
         Ok(Arc::new(BitcoinKeys {
-            _secret_key: secret_key,
-            bitcoin_private_key,
-            btc_client,
-            bitcoin_public_key,
-            pub_address,
-            script,
+            secret_key,
+            public_key,
+            _context: secp,
+            btc_privkey,
+            btc_pubkey,
             network,
             network,
         }))
         }))
     }
     }
 
 
-    pub async fn start_subscribe(self: Arc<Self>) -> BtcResult<(Txid, u64)> {
-        debug!(target: "BTC CLIENT", "Subscribe to scriptpubkey");
-        let client = &self.btc_client;
-        // Check if script is already subscribed
-        if let Some(status_start) = client.script_subscribe(&self.script)? {
-            loop {
-                match client.script_pop(&self.script)? {
-                    Some(status) => {
-                        // Script has a notification update
-                        if status != status_start {
-                            let balance = client.script_get_balance(&self.script)?;
-                            if balance.confirmed > 0 {
-                                debug!(target: "BTC CLIENT", "BTC Balance: Confirmed!");
-                                let history = client.script_get_history(&self.script)?;
-                                //return tx_hash of latest tx that created balance
-                                return Ok((history[0].tx_hash, balance.confirmed));
-                            } else {
-                                debug!(target: "BTC CLIENT", "BTC Balance: Unconfirmed!");
-                                continue;
-                            }
-                        } else {
-                            debug!(target: "BTC CLIENT", "ScriptPubKey status has not changed");
-                            continue;
-                        }
-                    }
-                    None => {
-                        debug!(target: "BTC CLIENT", "Scriptpubkey does not yet exist in script notifications!");
-                        continue;
-                    }
-                };
-            } // Endloop
-        } else {
-            return Err(BtcFailed::ElectrumError(
-                "Did not subscribe to scriptpubkey".to_string(),
-            ));
-        }
-    }
-
-    // This should do a db lookup to return the same obj
-    pub fn address_from_slice(key: &[u8]) -> Result<Address> {
-        let pub_key = PublicKey::from_slice(key).unwrap();
-        let address = Address::p2pkh(&pub_key, Network::Testnet);
-
-        Ok(address)
+    pub fn pubkey(&self) -> &PublicKey {
+        &self.public_key
     }
     }
-
-    // This should do a db lookup to return the same obj
-    pub fn private_key_from_slice(key: &[u8]) -> Result<PrivKey> {
-        let key = PrivKey::from_slice(key, Network::Testnet).unwrap();
-        Ok(key)
+    pub fn btc_privkey(&self) -> &BtcPrivKey {
+        &self.btc_privkey
     }
     }
-
-    pub fn get_deposit_address(&self) -> Result<&Address> {
-        Ok(&self.pub_address)
+    pub fn btc_pubkey(&self) -> &BtcPubKey {
+        &self.btc_pubkey
     }
     }
-    pub fn get_pubkey(&self) -> &PublicKey {
-        &self.bitcoin_public_key
+    pub fn btc_pubkey_hash(&self) -> BtcPubKeyHash {
+        self.btc_pubkey.pubkey_hash()
     }
     }
-    pub fn get_privkey(&self) -> &PrivateKey {
-        &self.bitcoin_private_key
+    pub fn derive_btc_address(btc_pubkey: BtcPubKey, network: Network) -> Address {
+        Address::p2pkh(&btc_pubkey, network)
     }
     }
-    pub fn get_script(&self) -> &Script {
-        &self.script
+    pub fn derive_script(btc_pubkey_hash: BtcPubKeyHash) -> Script {
+        Script::new_p2pkh(&btc_pubkey_hash)
     }
     }
 }
 }
 
 
 pub struct BtcClient {
 pub struct BtcClient {
-    client: Arc<ElectrumClient>,
-    network: Network,
+    _client: Arc<ElectrumClient>,
+    _network: Network,
+    _keypair: BitcoinKeys,
 }
 }
 
 
 impl BtcClient {
 impl BtcClient {
-    pub fn new(btc_endpoint: (Network, String)) -> Result<Arc<Self>> {
-        let (network, client_address) = btc_endpoint;
-        let client = ElectrumClient::new(&client_address)
+    pub fn new(keypair: BitcoinKeys) -> Result<Arc<Self>> {
+        let network = bitcoin::network::constants::Network::Testnet;
+        let client = ElectrumClient::new(ELECTRUM_SERVER)
             .map_err(|err| crate::Error::from(super::BtcFailed::from(err)))?;
             .map_err(|err| crate::Error::from(super::BtcFailed::from(err)))?;
         Ok(Arc::new(Self {
         Ok(Arc::new(Self {
-            client: Arc::new(client),
-            network,
+            _client: Arc::new(client),
+            _network: network,
+            _keypair: keypair,
         }))
         }))
     }
     }
+
+    // pub async fn start_subscribe(self: Arc<Self>) -> BtcResult<(Txid, u64)> {
+    //     debug!(target: "BTC CLIENT", "Subscribe to scriptpubkey");
+    //     let client = &self.btc_client;
+    //     // Check if script is already subscribed
+    //     if let Some(status_start) = client.script_subscribe(&self.script)? {
+    //         loop {
+    //             match client.script_pop(&self.script)? {
+    //                 Some(status) => {
+    //                     // Script has a notification update
+    //                     if status != status_start {
+    //                         let balance = client.script_get_balance(&self.script)?;
+    //                         if balance.confirmed > 0 {
+    //                             debug!(target: "BTC CLIENT", "BTC Balance: Confirmed!");
+    //                             let history = client.script_get_history(&self.script)?;
+    //                             //return tx_hash of latest tx that created balance
+    //                             return Ok((history[0].tx_hash, balance.confirmed));
+    //                         } else {
+    //                             debug!(target: "BTC CLIENT", "BTC Balance: Unconfirmed!");
+    //                             continue;
+    //                         }
+    //                     } else {
+    //                         debug!(target: "BTC CLIENT", "ScriptPubKey status has not changed");
+    //                         continue;
+    //                     }
+    //                 }
+    //                 None => {
+    //                     debug!(target: "BTC CLIENT", "Scriptpubkey does not yet exist in script notifications!");
+    //                     continue;
+    //                 }
+    //             };
+    //         } // Endloop
+    //     } else {
+    //         return Err(BtcFailed::ElectrumError(
+    //             "Did not subscribe to scriptpubkey".to_string(),
+    //         ));
+    //     }
+    // }
+
+    async fn handle_subscribe_request(self: Arc<Self>, keypair: Arc<BitcoinKeys>) -> Result<()> {
+        debug!(
+            target: "BTC BRIDGE",
+            "Handle subscribe request"
+        );
+
+        // p2pkh script
+        let _script = BitcoinKeys::derive_script(keypair.btc_pubkey_hash());
+
+        //if self.client.script_subscribe(&script)?
+
+        //let keypair = serialize(&keypair);
+
+        Ok(())
+    }
 }
 }
 
 
 #[async_trait]
 #[async_trait]
 impl NetworkClient for BtcClient {
 impl NetworkClient for BtcClient {
     async fn subscribe(self: Arc<Self>) -> Result<TokenSubscribtion> {
     async fn subscribe(self: Arc<Self>) -> Result<TokenSubscribtion> {
-        //// Generate bitcoin Address
-        let btc_keys = BitcoinKeys::new(self.client.clone(), self.network)?;
-
-        let btc_pub = btc_keys.clone();
-        let btc_pub = btc_pub.get_pubkey();
-        let btc_priv = btc_keys.clone();
-        let btc_priv = btc_priv.get_privkey();
+        // Generate bitcoin keys
+        let btc_keys = BitcoinKeys::new(Network::Testnet)?;
+        let btc_privkey = btc_keys.clone();
+        let btc_privkey = btc_privkey.btc_privkey();
+        let btc_pubkey = btc_keys.clone();
+        let btc_pubkey = btc_pubkey.btc_pubkey();
 
 
         // start scheduler for checking balance
         // start scheduler for checking balance
         debug!(target: "BRIDGE BITCOIN", "Subscribing for deposit");
         debug!(target: "BRIDGE BITCOIN", "Subscribing for deposit");
 
 
-        let (_txid, _balance) = btc_keys.start_subscribe().await?;
-        //let _script = btc_keys.get_script();
+        //let (_txid, _balance) = btc_keys.start_subscribe().await?;
+
+        let self2 = self.clone();
+        smol::spawn(self2.handle_subscribe_request(btc_keys)).detach();
 
 
         Ok(TokenSubscribtion {
         Ok(TokenSubscribtion {
-            secret_key: serialize(&btc_priv.to_bytes()),
-            public_key: btc_pub.to_string(),
+            secret_key: serialize(&btc_privkey.to_bytes()),
+            public_key: btc_pubkey.to_string(),
         })
         })
     }
     }