|
@@ -1,13 +1,14 @@
|
|
|
use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion};
|
|
use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion};
|
|
|
use crate::serial::{deserialize, serialize, Decodable, Encodable};
|
|
use crate::serial::{deserialize, serialize, Decodable, Encodable};
|
|
|
use crate::{Error, Result};
|
|
use crate::{Error, Result};
|
|
|
|
|
+use crate::util::{generate_id, NetworkName};
|
|
|
use async_trait::async_trait;
|
|
use async_trait::async_trait;
|
|
|
use bitcoin::blockdata::script::Script;
|
|
use bitcoin::blockdata::script::Script;
|
|
|
-use bitcoin::hash_types::{PubkeyHash as BtcPubKeyHash, Txid};
|
|
|
|
|
|
|
+use bitcoin::hash_types::{PubkeyHash as BtcPubKeyHash};
|
|
|
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 as BtcPrivKey, PublicKey as BtcPubKey};
|
|
use bitcoin::util::ecdsa::{PrivateKey as BtcPrivKey, PublicKey as BtcPubKey};
|
|
|
-use electrum_client::{Client as ElectrumClient, ElectrumApi};
|
|
|
|
|
|
|
+use electrum_client::{Client as ElectrumClient, ElectrumApi, GetBalanceRes};
|
|
|
use log::*;
|
|
use log::*;
|
|
|
use std::convert::From;
|
|
use std::convert::From;
|
|
|
|
|
|
|
@@ -75,14 +76,14 @@ impl Default for Keypair {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pub struct BtcKeys {
|
|
pub struct BtcKeys {
|
|
|
- _keypair: Arc<Keypair>,
|
|
|
|
|
|
|
+ keypair: Arc<Keypair>,
|
|
|
btc_privkey: BtcPrivKey,
|
|
btc_privkey: BtcPrivKey,
|
|
|
pub btc_pubkey: BtcPubKey,
|
|
pub btc_pubkey: BtcPubKey,
|
|
|
pub network: Network,
|
|
pub network: Network,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl BtcKeys {
|
|
impl BtcKeys {
|
|
|
- pub fn new(keypair: Keypair, network: Network) -> Self {
|
|
|
|
|
|
|
+ pub fn new(keypair: &Keypair, network: Network) -> Self {
|
|
|
|
|
|
|
|
let (secret_key, public_key) = keypair.as_tuple();
|
|
let (secret_key, public_key) = keypair.as_tuple();
|
|
|
|
|
|
|
@@ -90,7 +91,7 @@ impl BtcKeys {
|
|
|
let btc_pubkey = BtcPubKey::new(public_key);
|
|
let btc_pubkey = BtcPubKey::new(public_key);
|
|
|
|
|
|
|
|
Self {
|
|
Self {
|
|
|
- _keypair: Arc::new(keypair),
|
|
|
|
|
|
|
+ keypair: Arc::new(*keypair),
|
|
|
btc_privkey,
|
|
btc_privkey,
|
|
|
btc_pubkey,
|
|
btc_pubkey,
|
|
|
network,
|
|
network,
|
|
@@ -99,7 +100,7 @@ impl BtcKeys {
|
|
|
pub fn priv_from_secret(keypair: &Keypair, network: Network) -> BtcPrivKey {
|
|
pub fn priv_from_secret(keypair: &Keypair, network: Network) -> BtcPrivKey {
|
|
|
BtcPrivKey::new(keypair.secret(), network)
|
|
BtcPrivKey::new(keypair.secret(), network)
|
|
|
}
|
|
}
|
|
|
- pub fn btcpub_from_pubkey(keypair: &Keypair) -> BtcPubKey {
|
|
|
|
|
|
|
+ pub fn btcpub_from_keypair(keypair: &Keypair) -> BtcPubKey {
|
|
|
BtcPubKey::new(keypair.public)
|
|
BtcPubKey::new(keypair.public)
|
|
|
}
|
|
}
|
|
|
pub fn btc_privkey(&self) -> &BtcPrivKey {
|
|
pub fn btc_privkey(&self) -> &BtcPrivKey {
|
|
@@ -120,13 +121,13 @@ impl BtcKeys {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pub struct BtcClient {
|
|
pub struct BtcClient {
|
|
|
- _main_keypair: Keypair,
|
|
|
|
|
|
|
+ main_keypair: Keypair,
|
|
|
notify_channel: (
|
|
notify_channel: (
|
|
|
async_channel::Sender<TokenNotification>,
|
|
async_channel::Sender<TokenNotification>,
|
|
|
async_channel::Receiver<TokenNotification>,
|
|
async_channel::Receiver<TokenNotification>,
|
|
|
),
|
|
),
|
|
|
client: Arc<ElectrumClient>,
|
|
client: Arc<ElectrumClient>,
|
|
|
- _network: Network,
|
|
|
|
|
|
|
+ network: Network,
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -146,17 +147,18 @@ impl BtcClient {
|
|
|
.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 {
|
|
|
- _main_keypair: main_keypair,
|
|
|
|
|
|
|
+ main_keypair,
|
|
|
notify_channel,
|
|
notify_channel,
|
|
|
client: Arc::new(electrum_client),
|
|
client: Arc::new(electrum_client),
|
|
|
- _network: network,
|
|
|
|
|
|
|
+ network,
|
|
|
}))
|
|
}))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async fn _handle_subscribe_request(
|
|
|
|
|
|
|
+ async fn handle_subscribe_request(
|
|
|
self: Arc<Self>,
|
|
self: Arc<Self>,
|
|
|
keypair: BtcKeys,
|
|
keypair: BtcKeys,
|
|
|
- ) -> BtcResult<(Txid, u64)> {
|
|
|
|
|
|
|
+ drk_pub_key: jubjub::SubgroupPoint,
|
|
|
|
|
+ ) -> BtcResult<()> {
|
|
|
debug!(
|
|
debug!(
|
|
|
target: "BTC BRIDGE",
|
|
target: "BTC BRIDGE",
|
|
|
"Handle subscribe request"
|
|
"Handle subscribe request"
|
|
@@ -165,43 +167,60 @@ impl BtcClient {
|
|
|
|
|
|
|
|
// p2pkh script
|
|
// p2pkh script
|
|
|
let script = BtcKeys::derive_script(keypair.btc_pubkey_hash());
|
|
let script = BtcKeys::derive_script(keypair.btc_pubkey_hash());
|
|
|
|
|
+ //Subscribe to script, returns Error::AlreadySubscribed otherwise
|
|
|
|
|
+ let status = client.script_subscribe(&script)?;
|
|
|
|
|
+
|
|
|
|
|
+ //Fetch any current balance
|
|
|
|
|
+ let prev_balance = client.script_get_balance(&script)?;
|
|
|
|
|
+
|
|
|
|
|
+ let cur_balance: GetBalanceRes;
|
|
|
|
|
+
|
|
|
|
|
+ loop {
|
|
|
|
|
+ let current_status = client.script_pop(&script)?;
|
|
|
|
|
+ if current_status != status {
|
|
|
|
|
+ debug!(target: "BTC CLIENT", "ScriptPubKey status has not changed");
|
|
|
|
|
+ continue
|
|
|
|
|
+ }
|
|
|
|
|
+ match current_status {
|
|
|
|
|
+ // Script has a notification update
|
|
|
|
|
+ Some(_status_update) => {
|
|
|
|
|
+ cur_balance = client.script_get_balance(&script)?;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ // No items in the queue
|
|
|
|
|
+ None => {
|
|
|
|
|
+ debug!(target: "BTC CLIENT",
|
|
|
|
|
+ "Scriptpubkey does not yet exist in script notifications!");
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ let send_notification = self.notify_channel.0.clone();
|
|
|
|
|
|
|
|
- if let Some(status_start) = client.script_subscribe(&script)? {
|
|
|
|
|
- loop {
|
|
|
|
|
- match client.script_pop(&script)? {
|
|
|
|
|
- Some(status) => {
|
|
|
|
|
- // Script has a notification update
|
|
|
|
|
- if status != status_start {
|
|
|
|
|
- let balance = client.script_get_balance(&script)?;
|
|
|
|
|
- if balance.confirmed > 0 {
|
|
|
|
|
- debug!(target: "BTC CLIENT", "BTC Balance: Confirmed!");
|
|
|
|
|
- let history = client.script_get_history(&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(),
|
|
|
|
|
|
|
+ if cur_balance.confirmed < prev_balance.confirmed {
|
|
|
|
|
+ return Err(BtcFailed::Notification(
|
|
|
|
|
+ "New balance is less than previous balance".into(),
|
|
|
));
|
|
));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //let keypair = serialize(&keypair);
|
|
|
|
|
|
|
+ let amnt = cur_balance.confirmed - prev_balance.confirmed;
|
|
|
|
|
+ let ui_amnt = amnt;
|
|
|
|
|
|
|
|
- //Ok(())
|
|
|
|
|
|
|
+ send_notification
|
|
|
|
|
+ .send(TokenNotification {
|
|
|
|
|
+ network: NetworkName::Bitcoin,
|
|
|
|
|
+ // is btc an acceptable token name?
|
|
|
|
|
+ token_id: generate_id("btc", &NetworkName::Bitcoin)?,
|
|
|
|
|
+ drk_pub_key,
|
|
|
|
|
+ received_balance: amnt,
|
|
|
|
|
+ })
|
|
|
|
|
+ .await
|
|
|
|
|
+ .map_err(Error::from)?;
|
|
|
|
|
+
|
|
|
|
|
+ debug!(target: "BTC BRIDGE", "Received {} btc", ui_amnt);
|
|
|
|
|
+
|
|
|
|
|
+ Ok(())
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -209,21 +228,19 @@ impl BtcClient {
|
|
|
impl NetworkClient for BtcClient {
|
|
impl NetworkClient for BtcClient {
|
|
|
async fn subscribe(
|
|
async fn subscribe(
|
|
|
self: Arc<Self>,
|
|
self: Arc<Self>,
|
|
|
- _drk_pub_key: jubjub::SubgroupPoint,
|
|
|
|
|
|
|
+ drk_pub_key: jubjub::SubgroupPoint,
|
|
|
_mint: Option<String>,
|
|
_mint: Option<String>,
|
|
|
) -> Result<TokenSubscribtion> {
|
|
) -> Result<TokenSubscribtion> {
|
|
|
// Generate bitcoin keys
|
|
// Generate bitcoin keys
|
|
|
let keypair = Keypair::new();
|
|
let keypair = Keypair::new();
|
|
|
-
|
|
|
|
|
|
|
+ let btc_keys = BtcKeys::new(&keypair, self.network);
|
|
|
let secret_key = serialize(&keypair);
|
|
let secret_key = serialize(&keypair);
|
|
|
- let public_key = BtcKeys::btcpub_from_pubkey(&keypair).to_string();
|
|
|
|
|
|
|
+ let public_key = BtcKeys::btcpub_from_keypair(&keypair).to_string();
|
|
|
|
|
|
|
|
// 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?;
|
|
|
|
|
-
|
|
|
|
|
- //smol::spawn(self.handle_subscribe_request(btc_keys)).detach();
|
|
|
|
|
|
|
+ smol::spawn(self.handle_subscribe_request(btc_keys, drk_pub_key)).detach();
|
|
|
|
|
|
|
|
Ok(TokenSubscribtion {
|
|
Ok(TokenSubscribtion {
|
|
|
secret_key,
|
|
secret_key,
|
|
@@ -344,6 +361,7 @@ pub enum BtcFailed {
|
|
|
BtcError(String),
|
|
BtcError(String),
|
|
|
DecodeAndEncodeError(String),
|
|
DecodeAndEncodeError(String),
|
|
|
KeypairError(String),
|
|
KeypairError(String),
|
|
|
|
|
+ Notification(String),
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl std::error::Error for BtcFailed {}
|
|
impl std::error::Error for BtcFailed {}
|
|
@@ -364,6 +382,9 @@ impl std::fmt::Display for BtcFailed {
|
|
|
BtcFailed::KeypairError(ref err) => {
|
|
BtcFailed::KeypairError(ref err) => {
|
|
|
write!(f, "Keypair error from Secp256k1: {}", err)
|
|
write!(f, "Keypair error from Secp256k1: {}", err)
|
|
|
}
|
|
}
|
|
|
|
|
+ BtcFailed::Notification(i) => {
|
|
|
|
|
+ write!(f, "Received Notification Error: {}", i)
|
|
|
|
|
+ }
|
|
|
BtcFailed::BtcError(i) => {
|
|
BtcFailed::BtcError(i) => {
|
|
|
write!(f, "BtcFailed: {}", i)
|
|
write!(f, "BtcFailed: {}", i)
|
|
|
}
|
|
}
|