btc.rs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. use super::bridge::{CoinClient, CoinNotification, CoinSubscribtion};
  2. use crate::serial::{serialize, Decodable, Encodable};
  3. use crate::Result;
  4. use async_trait::async_trait;
  5. use bitcoin::blockdata::script::Script;
  6. use bitcoin::hash_types::Txid;
  7. use bitcoin::network::constants::Network;
  8. use bitcoin::util::address::Address;
  9. use bitcoin::util::ecdsa::{PrivateKey, PublicKey};
  10. use electrum_client::{Client as ElectrumClient, ElectrumApi};
  11. use log::*;
  12. use rand::distributions::Alphanumeric;
  13. use rand::{thread_rng, Rng};
  14. use secp256k1::key::SecretKey;
  15. use async_std::sync::Arc;
  16. use std::str::FromStr;
  17. // Swap out these types for any future non bitcoin-rs types
  18. pub type PubAddress = Address;
  19. pub type PubKey = PublicKey;
  20. pub type PrivKey = PrivateKey;
  21. pub struct BitcoinKeys {
  22. _secret_key: SecretKey,
  23. bitcoin_private_key: PrivateKey,
  24. btc_client: Arc<ElectrumClient>,
  25. pub bitcoin_public_key: PublicKey,
  26. pub pub_address: Address,
  27. pub script: Script,
  28. pub network: Network,
  29. }
  30. impl BitcoinKeys {
  31. pub fn new(btc_client: Arc<ElectrumClient>, network: Network) -> Result<Arc<BitcoinKeys>> {
  32. let context = secp256k1::Secp256k1::new();
  33. // Probably not good enough for release
  34. let rand: String = thread_rng()
  35. .sample_iter(&Alphanumeric)
  36. .take(32)
  37. .map(char::from)
  38. .collect();
  39. let rand_hex = hex::encode(rand);
  40. // Generate simple byte array from rand
  41. let data_slice: &[u8] = rand_hex.as_bytes();
  42. let secret_key = SecretKey::from_slice(&hex::decode(data_slice).unwrap()).unwrap();
  43. // Use Testnet
  44. let bitcoin_private_key = PrivateKey::new(secret_key, network);
  45. let bitcoin_public_key = PublicKey::from_private_key(&context, &bitcoin_private_key);
  46. //let pubkey_serialized = bitcoin_public_key.to_bytes();
  47. let pub_address = Address::p2pkh(&bitcoin_public_key, network);
  48. let script = Script::new_p2pk(&bitcoin_public_key);
  49. Ok(Arc::new(BitcoinKeys {
  50. _secret_key: secret_key,
  51. bitcoin_private_key,
  52. btc_client,
  53. bitcoin_public_key,
  54. pub_address,
  55. script,
  56. network,
  57. }))
  58. }
  59. pub async fn start_subscribe(self: Arc<Self>) -> BtcResult<(Txid, u64)> {
  60. debug!(target: "BTC CLIENT", "Subscribe to scriptpubkey");
  61. let client = &self.btc_client;
  62. // Check if script is already subscribed
  63. if let Some(status_start) = client.script_subscribe(&self.script)? {
  64. loop {
  65. match client.script_pop(&self.script)? {
  66. Some(status) => {
  67. // Script has a notification update
  68. if status != status_start {
  69. let balance = client.script_get_balance(&self.script)?;
  70. if balance.confirmed > 0 {
  71. debug!(target: "BTC CLIENT", "BTC Balance: Confirmed!");
  72. let history = client.script_get_history(&self.script)?;
  73. //return tx_hash of latest tx that created balance
  74. return Ok((history[0].tx_hash, balance.confirmed));
  75. } else {
  76. debug!(target: "BTC CLIENT", "BTC Balance: Unconfirmed!");
  77. continue;
  78. }
  79. } else {
  80. debug!(target: "BTC CLIENT", "ScriptPubKey status has not changed");
  81. continue;
  82. }
  83. }
  84. None => {
  85. debug!(target: "BTC CLIENT", "Scriptpubkey does not yet exist in script notifications!");
  86. continue;
  87. }
  88. };
  89. } // Endloop
  90. } else {
  91. return Err(BtcFailed::ElectrumError(
  92. "Did not subscribe to scriptpubkey".to_string(),
  93. ));
  94. }
  95. }
  96. // This should do a db lookup to return the same obj
  97. pub fn address_from_slice(key: &[u8]) -> Result<Address> {
  98. let pub_key = PublicKey::from_slice(key).unwrap();
  99. let address = Address::p2pkh(&pub_key, Network::Testnet);
  100. Ok(address)
  101. }
  102. // This should do a db lookup to return the same obj
  103. pub fn private_key_from_slice(key: &[u8]) -> Result<PrivKey> {
  104. let key = PrivKey::from_slice(key, Network::Testnet).unwrap();
  105. Ok(key)
  106. }
  107. pub fn get_deposit_address(&self) -> Result<&Address> {
  108. Ok(&self.pub_address)
  109. }
  110. pub fn get_pubkey(&self) -> &PublicKey {
  111. &self.bitcoin_public_key
  112. }
  113. pub fn get_privkey(&self) -> &PrivateKey {
  114. &self.bitcoin_private_key
  115. }
  116. pub fn get_script(&self) -> &Script {
  117. &self.script
  118. }
  119. }
  120. pub struct BtcClient {
  121. client: Arc<ElectrumClient>,
  122. network: Network,
  123. }
  124. impl BtcClient {
  125. pub fn new(btc_endpoint: (Network, String)) -> Result<Self> {
  126. let (network, client_address) = btc_endpoint;
  127. let client = ElectrumClient::new(&client_address)
  128. .map_err(|err| crate::Error::from(super::BtcFailed::from(err)))?;
  129. Ok(Self {
  130. client: Arc::new(client),
  131. network: network,
  132. })
  133. }
  134. }
  135. #[async_trait]
  136. impl CoinClient for BtcClient {
  137. async fn subscribe(&self) -> Result<CoinSubscribtion> {
  138. //// Generate bitcoin Address
  139. let btc_keys = BitcoinKeys::new(self.client.clone(), self.network)?;
  140. let btc_pub = btc_keys.clone();
  141. let btc_pub = btc_pub.get_pubkey();
  142. let btc_priv = btc_keys.clone();
  143. let btc_priv = btc_priv.get_privkey();
  144. // start scheduler for checking balance
  145. debug!(target: "BRIDGE BITCOIN", "Subscribing for deposit");
  146. let (_txid, _balance) = btc_keys.start_subscribe().await?;
  147. //let _script = btc_keys.get_script();
  148. Ok(CoinSubscribtion {
  149. secret_key: serialize(&btc_priv.to_bytes()),
  150. public_key: serialize(&btc_pub.to_bytes()),
  151. })
  152. }
  153. async fn get_notifier(&self) -> Result<async_channel::Receiver<CoinNotification>> {
  154. // TODO this not implemented yet
  155. let (_, notifier) = async_channel::unbounded();
  156. Ok(notifier)
  157. }
  158. async fn send(&self, _address: Vec<u8>, _amount: u64) -> Result<()> {
  159. // TODO
  160. Ok(())
  161. }
  162. }
  163. impl Encodable for bitcoin::Address {
  164. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  165. let addr = self.to_string();
  166. let len = addr.encode(s)?;
  167. Ok(len)
  168. }
  169. }
  170. impl Decodable for bitcoin::Address {
  171. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  172. let addr: String = Decodable::decode(&mut d)?;
  173. let addr = bitcoin::Address::from_str(&addr)
  174. .map_err(|err| crate::Error::from(BtcFailed::from(err)))?;
  175. Ok(addr)
  176. }
  177. }
  178. impl Encodable for bitcoin::PublicKey {
  179. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  180. let key = self.to_bytes();
  181. let len = key.encode(s)?;
  182. Ok(len)
  183. }
  184. }
  185. impl Decodable for bitcoin::PublicKey {
  186. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  187. let key: Vec<u8> = Decodable::decode(&mut d)?;
  188. let key = bitcoin::PublicKey::from_slice(&key)
  189. .map_err(|err| crate::Error::from(BtcFailed::from(err)))?;
  190. Ok(key)
  191. }
  192. }
  193. impl Encodable for bitcoin::PrivateKey {
  194. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  195. let key = self.to_bytes();
  196. let len = key.encode(s)?;
  197. Ok(len)
  198. }
  199. }
  200. impl Decodable for bitcoin::PrivateKey {
  201. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  202. let key: Vec<u8> = Decodable::decode(&mut d)?;
  203. let key = bitcoin::PrivateKey::from_slice(&key, Network::Testnet)
  204. .map_err(|err| crate::Error::from(BtcFailed::from(err)))?;
  205. Ok(key)
  206. }
  207. }
  208. #[derive(Debug)]
  209. pub enum BtcFailed {
  210. NotEnoughValue(u64),
  211. BadBTCAddress(String),
  212. ElectrumError(String),
  213. BtcError(String),
  214. DecodeAndEncodeError(String),
  215. }
  216. impl std::error::Error for BtcFailed {}
  217. impl std::fmt::Display for BtcFailed {
  218. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  219. match self {
  220. BtcFailed::NotEnoughValue(i) => {
  221. write!(f, "There is no enough value {}", i)
  222. }
  223. BtcFailed::BadBTCAddress(ref err) => {
  224. write!(f, "Unable to create Electrum Client: {}", err)
  225. }
  226. BtcFailed::ElectrumError(ref err) => write!(f, "could not parse BTC address: {}", err),
  227. BtcFailed::DecodeAndEncodeError(ref err) => {
  228. write!(f, "Decode and decode keys error: {}", err)
  229. }
  230. BtcFailed::BtcError(i) => {
  231. write!(f, "BtcFailed: {}", i)
  232. }
  233. }
  234. }
  235. }
  236. impl From<crate::error::Error> for BtcFailed {
  237. fn from(err: crate::error::Error) -> BtcFailed {
  238. BtcFailed::BtcError(err.to_string())
  239. }
  240. }
  241. impl From<bitcoin::util::address::Error> for BtcFailed {
  242. fn from(err: bitcoin::util::address::Error) -> BtcFailed {
  243. BtcFailed::BadBTCAddress(err.to_string())
  244. }
  245. }
  246. impl From<electrum_client::Error> for BtcFailed {
  247. fn from(err: electrum_client::Error) -> BtcFailed {
  248. BtcFailed::ElectrumError(err.to_string())
  249. }
  250. }
  251. impl From<bitcoin::util::key::Error> for BtcFailed {
  252. fn from(err: bitcoin::util::key::Error) -> BtcFailed {
  253. BtcFailed::DecodeAndEncodeError(err.to_string())
  254. }
  255. }
  256. pub type BtcResult<T> = std::result::Result<T, BtcFailed>;
  257. #[cfg(test)]
  258. mod tests {
  259. use crate::serial::{deserialize, serialize};
  260. use std::str::FromStr;
  261. #[test]
  262. pub fn test_serialize_btc_address() -> super::BtcResult<()> {
  263. let btc_addr =
  264. bitcoin::Address::from_str(&String::from("mxVFsFW5N4mu1HPkxPttorvocvzeZ7KZyk"))?;
  265. let btc_ser = serialize(&btc_addr);
  266. let btc_dser = deserialize(&btc_ser)?;
  267. assert_eq!(btc_addr, btc_dser);
  268. Ok(())
  269. }
  270. }