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

Add secp256k1 keypair type for btc

Janus пре 4 година
родитељ
комит
7fcfffd171
2 измењених фајлова са 112 додато и 25 уклоњено
  1. 21 18
      src/bin/cashierd.rs
  2. 91 7
      src/service/btc.rs

+ 21 - 18
src/bin/cashierd.rs

@@ -415,24 +415,27 @@ impl Cashierd {
                 #[cfg(feature = "btc")]
                 NetworkName::Bitcoin => {
                     debug!(target: "CASHIER DAEMON", "Add btc network");
-                    //use drk::service::btc::{BtcClient, BitcoinKeys};
-
-                    //let _btc_client = BtcClient::new("testnet")?;
-                    // NOTE bitcoin is not implemented yet
-                    //let _main_keypair: BitcoinKeys;
-
-                    let _main_keypairs =
-                        self.cashier_wallet.get_main_keys(&NetworkName::Bitcoin)?;
-                    // if main_keypairs.is_empty() {
-                    //     //main_keypair = BitcoinKeys::new(bitcoin::network::constants::Network::Testnet)?;
-                    // } else {
-                    //     //main_keypair = deserialize(&main_keypairs[0].0)?;
-                    // }
-                    //
-                    // 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, Keypair};
+
+                    let main_keypair: Keypair;
+
+                    let main_keypairs = self.cashier_wallet.get_main_keys(&NetworkName::Bitcoin)?;
+
+                    if main_keypairs.is_empty() {
+                        main_keypair = Keypair::new();
+                        self.cashier_wallet.put_main_keys(
+                            &serialize(&main_keypair),
+                            &serialize(&main_keypair.pubkey()),
+                            &NetworkName::Bitcoin,
+                        )?;
+
+                    } else {
+                        main_keypair = deserialize(&main_keypairs[0].0)?;
+                    }
+
+                    let btc_client = BtcClient::new(serialize(&main_keypair), &chain).await?;
+
+                    bridge2.add_clients(NetworkName::Bitcoin, btc_client).await?;
                 }
             }
         }

+ 91 - 7
src/service/btc.rs

@@ -1,7 +1,7 @@
 use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion};
-use crate::serial::{serialize, Decodable, Encodable};
+use crate::serial::{serialize, deserialize, Decodable, Encodable};
 use crate::{Error, Result};
-
+use std::convert::From;
 use async_trait::async_trait;
 use bitcoin::blockdata::script::Script;
 use bitcoin::hash_types::{PubkeyHash as BtcPubKeyHash, Txid};
@@ -12,6 +12,7 @@ use electrum_client::{Client as ElectrumClient, ElectrumApi};
 use log::*;
 
 use secp256k1::key::{PublicKey, SecretKey};
+use secp256k1::constants::{SECRET_KEY_SIZE, PUBLIC_KEY_SIZE};
 use secp256k1::{rand::rngs::OsRng, Secp256k1};
 
 use async_std::sync::Arc;
@@ -22,8 +23,47 @@ pub type PubAddress = Address;
 pub type PubKey = BtcPubKey;
 pub type PrivKey = BtcPrivKey;
 
+const KEYPAIR_LENGTH: usize = SECRET_KEY_SIZE + PUBLIC_KEY_SIZE;
+
+pub struct Keypair {
+    secret: SecretKey,
+    public: PublicKey,
+}
+impl Keypair {
+    pub fn new() -> Self {
+        let secp = Secp256k1::new();
+        let mut rng = OsRng::new().expect("OsRng");
+
+        let (secret, public) = secp.generate_keypair(&mut rng);
+        Self {
+            secret,
+            public,
+        }
+    }
+    pub fn to_bytes(&self) -> [u8; KEYPAIR_LENGTH] {
+        let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH];
+
+        bytes[..SECRET_KEY_SIZE].copy_from_slice(self.secret.as_ref());
+        bytes[SECRET_KEY_SIZE..].copy_from_slice(&self.public.serialize());
+        bytes
+
+    }
+    pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result<Keypair> {
+        if bytes.len() != KEYPAIR_LENGTH {
+            return Err(Error::BtcFailed("Not right size".to_string()));
+        }
+        //TODO: Map to errors properly
+        let secret = SecretKey::from_slice(&bytes[..SECRET_KEY_SIZE]).unwrap();
+        let public = PublicKey::from_slice(&bytes[SECRET_KEY_SIZE..]).unwrap();
+
+        Ok(Keypair{ secret: secret, public: public })
+    }
+    pub fn pubkey(&self) -> PublicKey {
+        self.public
+    }
+}
 pub struct BitcoinKeys {
-    secret_key: SecretKey,
+    _secret_key: SecretKey,
     public_key: PublicKey,
     _context: Secp256k1<secp256k1::All>,
     btc_privkey: BtcPrivKey,
@@ -42,7 +82,7 @@ impl BitcoinKeys {
         let btc_pubkey = btc_privkey.public_key(&secp);
 
         Ok(Arc::new(BitcoinKeys {
-            secret_key,
+            _secret_key: secret_key,
             public_key,
             _context: secp,
             btc_privkey,
@@ -74,11 +114,13 @@ impl BitcoinKeys {
 pub struct BtcClient {
     client: Arc<ElectrumClient>,
     network: Network,
-    keypair: BitcoinKeys,
+    keypair: Keypair,
 }
 
 impl BtcClient {
-    pub fn new(network: &str, keypair: BitcoinKeys) -> Result<Arc<Self>> {
+    pub async fn new(keypair: Vec<u8>, network: &str) -> Result<Arc<Self>> {
+        let keypair: Keypair = deserialize(&keypair)?;
+
         let (network, url) = match network {
             "mainnet" => (Network::Bitcoin, "ssl://electrum.blockstream.info:50002"),
             "testnet" => (Network::Testnet, "ssl://electrum.blockstream.info:60002"),
@@ -246,6 +288,40 @@ impl Decodable for bitcoin::PrivateKey {
         Ok(key)
     }
 }
+impl Encodable for secp256k1::key::PublicKey {
+    fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
+        let key: Vec<u8> = self.serialize().to_vec();
+        let len = key.encode(s)?;
+        Ok(len)
+    }
+}
+impl Decodable for secp256k1::key::PublicKey {
+    fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
+        let key: Vec<u8> = Decodable::decode(&mut d)?;
+        let key = secp256k1::key::PublicKey::from_slice(&key)
+            .map_err(|err| crate::Error::from(BtcFailed::from(err)))?;
+        Ok(key)
+    }
+}
+impl Encodable for Keypair {
+    fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
+        let key: Vec<u8> = self.to_bytes().to_vec();
+        let len = key.encode(s)?;
+        Ok(len)
+    }
+}
+
+impl Decodable for Keypair {
+    fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
+        let key: Vec<u8> = Decodable::decode(&mut d)?;
+        let key = Keypair::from_bytes(key.as_slice()).map_err(|_| {
+            crate::Error::from(BtcFailed::DecodeAndEncodeError(
+                "load keypair from slice".into(),
+            ))
+        })?;
+        Ok(key)
+    }
+}
 
 #[derive(Debug)]
 pub enum BtcFailed {
@@ -254,6 +330,7 @@ pub enum BtcFailed {
     ElectrumError(String),
     BtcError(String),
     DecodeAndEncodeError(String),
+    KeypairError(String)
 }
 
 impl std::error::Error for BtcFailed {}
@@ -271,6 +348,9 @@ impl std::fmt::Display for BtcFailed {
             BtcFailed::DecodeAndEncodeError(ref err) => {
                 write!(f, "Decode and decode keys error: {}", err)
             }
+            BtcFailed::KeypairError(ref err) => {
+                write!(f, "Keypair error from Secp256k1: {}", err)
+            }
             BtcFailed::BtcError(i) => {
                 write!(f, "BtcFailed: {}", i)
             }
@@ -283,7 +363,11 @@ impl From<crate::error::Error> for BtcFailed {
         BtcFailed::BtcError(err.to_string())
     }
 }
-
+impl From<secp256k1::Error> for BtcFailed {
+    fn from(err: secp256k1::Error) -> BtcFailed {
+        BtcFailed::KeypairError(err.to_string())
+    }
+}
 impl From<bitcoin::util::address::Error> for BtcFailed {
     fn from(err: bitcoin::util::address::Error) -> BtcFailed {
         BtcFailed::BadBtcAddress(err.to_string())