btc.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. use super::bridge::{NetworkClient, TokenNotification, TokenSubscribtion};
  2. use crate::rpc::{jsonrpc, websockets::WsStream};
  3. use crate::serial::{deserialize, serialize, Decodable, Encodable};
  4. use crate::util::{generate_id, NetworkName};
  5. use crate::{Error, Result};
  6. use async_trait::async_trait;
  7. use bitcoin::blockdata::{
  8. script::{Builder, Script},
  9. transaction::{OutPoint, SigHashType, Transaction, TxIn, TxOut},
  10. };
  11. use bitcoin::hash_types::PubkeyHash as BtcPubKeyHash;
  12. use bitcoin::network::constants::Network;
  13. use bitcoin::util::address::Address;
  14. use bitcoin::util::ecdsa::{PrivateKey as BtcPrivKey, PublicKey as BtcPubKey};
  15. use electrum_client::{Client as ElectrumClient, ElectrumApi, GetBalanceRes};
  16. use futures::{SinkExt, StreamExt};
  17. use log::*;
  18. use secp256k1::{
  19. constants::{PUBLIC_KEY_SIZE, SECRET_KEY_SIZE},
  20. key::{PublicKey, SecretKey},
  21. {rand::rngs::OsRng, Secp256k1},
  22. {All, Message as BtcMessage, /*Secp256k1,*/},
  23. };
  24. use serde_json::json;
  25. use std::convert::From;
  26. use tungstenite::Message;
  27. use async_std::sync::Arc;
  28. use std::str::FromStr;
  29. // Swap out these types for any future non bitcoin-rs types
  30. pub type PubAddress = Address;
  31. pub type PubKey = BtcPubKey;
  32. pub type PrivKey = BtcPrivKey;
  33. const KEYPAIR_LENGTH: usize = SECRET_KEY_SIZE + PUBLIC_KEY_SIZE;
  34. #[derive(Clone)]
  35. pub struct Keypair {
  36. secret: SecretKey,
  37. public: PublicKey,
  38. context: Secp256k1<All>,
  39. }
  40. impl Keypair {
  41. pub fn new() -> Self {
  42. let secp = Secp256k1::new();
  43. let mut rng = OsRng::new().expect("OsRng");
  44. let (secret, public) = secp.generate_keypair(&mut rng);
  45. Self {
  46. secret,
  47. public,
  48. context: secp,
  49. }
  50. }
  51. pub fn to_bytes(&self) -> [u8; KEYPAIR_LENGTH] {
  52. let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH];
  53. bytes[..SECRET_KEY_SIZE].copy_from_slice(self.secret.as_ref());
  54. bytes[SECRET_KEY_SIZE..].copy_from_slice(&self.public.serialize());
  55. bytes
  56. }
  57. pub fn from_bytes(bytes: &[u8]) -> Result<Keypair> {
  58. if bytes.len() != KEYPAIR_LENGTH {
  59. return Err(Error::BtcFailed("Not right size".to_string()));
  60. }
  61. let secp = Secp256k1::new();
  62. //TODO: Map to errors properly, use context for public gen
  63. let secret = SecretKey::from_slice(&bytes[..SECRET_KEY_SIZE]).unwrap();
  64. let public = PublicKey::from_slice(&bytes[SECRET_KEY_SIZE..]).unwrap();
  65. Ok(Keypair {
  66. secret,
  67. public,
  68. context: secp,
  69. })
  70. }
  71. fn secret(&self) -> SecretKey {
  72. self.secret
  73. }
  74. pub fn pubkey(&self) -> PublicKey {
  75. self.public
  76. }
  77. pub fn as_tuple(&self) -> (SecretKey, PublicKey) {
  78. (self.secret, self.public)
  79. }
  80. }
  81. impl Default for Keypair {
  82. fn default() -> Self {
  83. Self::new()
  84. }
  85. }
  86. #[derive(Clone)]
  87. pub struct BtcKeys {
  88. keypair: Arc<Keypair>,
  89. btc_privkey: BtcPrivKey,
  90. pub btc_pubkey: BtcPubKey,
  91. pub script_pubkey: Script,
  92. pub network: Network,
  93. }
  94. impl BtcKeys {
  95. pub fn new(keypair: &Keypair, network: Network) -> Self {
  96. let (secret_key, public_key) = keypair.as_tuple();
  97. let btc_privkey = BtcPrivKey::new(secret_key, network);
  98. let btc_pubkey = BtcPubKey::new(public_key);
  99. let script_pubkey = BtcKeys::derive_btc_script_pubkey(public_key, network);
  100. Self {
  101. keypair: Arc::new(keypair.clone()),
  102. btc_privkey,
  103. btc_pubkey,
  104. script_pubkey,
  105. network,
  106. }
  107. }
  108. pub fn priv_from_secret(keypair: &Keypair, network: Network) -> BtcPrivKey {
  109. BtcPrivKey::new(keypair.secret(), network)
  110. }
  111. pub fn btcpub_from_keypair(keypair: &Keypair) -> BtcPubKey {
  112. BtcPubKey::new(keypair.public)
  113. }
  114. pub fn btc_privkey(&self) -> &BtcPrivKey {
  115. &self.btc_privkey
  116. }
  117. pub fn btc_pubkey(&self) -> &BtcPubKey {
  118. &self.btc_pubkey
  119. }
  120. pub fn btc_pubkey_hash(&self) -> BtcPubKeyHash {
  121. self.btc_pubkey.pubkey_hash()
  122. }
  123. pub fn derive_btc_script_pubkey(pubkey: PublicKey, network: Network) -> Script {
  124. let btc_pubkey = BtcPubKey::new(pubkey);
  125. let address = Address::p2pkh(&btc_pubkey, network);
  126. address.script_pubkey()
  127. }
  128. pub fn derive_btc_pubkey(pubkey: PublicKey) -> BtcPubKey {
  129. BtcPubKey::new(pubkey)
  130. }
  131. pub fn derive_btc_address(btc_pubkey: BtcPubKey, network: Network) -> Address {
  132. Address::p2pkh(&btc_pubkey, network)
  133. }
  134. pub fn derive_script(btc_pubkey_hash: BtcPubKeyHash) -> Script {
  135. Script::new_p2pkh(&btc_pubkey_hash)
  136. }
  137. }
  138. pub struct BtcClient {
  139. main_account: BtcKeys,
  140. notify_channel: (
  141. async_channel::Sender<TokenNotification>,
  142. async_channel::Receiver<TokenNotification>,
  143. ),
  144. client: Arc<ElectrumClient>,
  145. network: Network,
  146. }
  147. impl BtcClient {
  148. pub async fn new(main_keypair: Vec<u8>, network: &str) -> Result<Arc<Self>> {
  149. let main_keypair: Keypair = deserialize(&main_keypair)?;
  150. let notify_channel = async_channel::unbounded();
  151. let (network, url) = match network {
  152. "mainnet" => (Network::Bitcoin, "ssl://electrum.blockstream.info:50002"),
  153. "testnet" => (Network::Testnet, "ssl://electrum.blockstream.info:60002"),
  154. _ => return Err(Error::NotSupportedNetwork),
  155. };
  156. let main_account = BtcKeys::new(&main_keypair, network);
  157. let electrum_client = ElectrumClient::new(&url)
  158. .map_err(|err| crate::Error::from(super::BtcFailed::from(err)))?;
  159. Ok(Arc::new(Self {
  160. main_account,
  161. notify_channel,
  162. client: Arc::new(electrum_client),
  163. network,
  164. }))
  165. }
  166. async fn handle_subscribe_request(
  167. self: Arc<Self>,
  168. btc_keys: BtcKeys,
  169. drk_pub_key: jubjub::SubgroupPoint,
  170. ) -> BtcResult<()> {
  171. debug!(
  172. target: "BTC BRIDGE",
  173. "Handle subscribe request"
  174. );
  175. let client = &self.client;
  176. let keys_clone = btc_keys.clone();
  177. // p2pkh script
  178. let script = keys_clone.script_pubkey;
  179. //Subscribe to script, returns Error::AlreadySubscribed otherwise
  180. let status = client.script_subscribe(&script)?;
  181. //Fetch any current balance
  182. let prev_balance = client.script_get_balance(&script)?;
  183. let cur_balance: GetBalanceRes;
  184. loop {
  185. let current_status = client.script_pop(&script)?;
  186. if current_status != status {
  187. debug!(target: "BTC CLIENT", "ScriptPubKey status has not changed");
  188. continue;
  189. }
  190. match current_status {
  191. // Script has a notification update
  192. Some(_status_update) => {
  193. cur_balance = client.script_get_balance(&script)?;
  194. break;
  195. }
  196. // No items in the queue
  197. None => {
  198. debug!(target: "BTC CLIENT",
  199. "Scriptpubkey does not yet exist in script notifications!");
  200. continue;
  201. }
  202. }
  203. }
  204. let send_notification = self.notify_channel.0.clone();
  205. if cur_balance.confirmed < prev_balance.confirmed {
  206. return Err(BtcFailed::Notification(
  207. "New balance is less than previous balance".into(),
  208. ));
  209. }
  210. let amnt = cur_balance.confirmed - prev_balance.confirmed;
  211. let ui_amnt = amnt;
  212. send_notification
  213. .send(TokenNotification {
  214. network: NetworkName::Bitcoin,
  215. // is btc an acceptable token name?
  216. token_id: generate_id("btc", &NetworkName::Bitcoin)?,
  217. drk_pub_key,
  218. received_balance: amnt,
  219. })
  220. .await
  221. .map_err(Error::from)?;
  222. debug!(target: "BTC BRIDGE", "Received {} btc", ui_amnt);
  223. let _ = self.send_btc_to_main_wallet(amnt, btc_keys)?;
  224. Ok(())
  225. }
  226. async fn unsubscribe(
  227. self: Arc<Self>,
  228. write: &mut futures::stream::SplitSink<WsStream, tungstenite::Message>,
  229. pubkey: &PublicKey,
  230. sub_id: &i64,
  231. ) -> Result<()> {
  232. {
  233. let client = &self.client;
  234. let script_pubkey = BtcKeys::derive_btc_script_pubkey(*pubkey, self.network);
  235. let _ = client.script_unsubscribe(&script_pubkey).unwrap();
  236. }
  237. let unsubscription = jsonrpc::request(json!("accountUnsubscribe"), json!([sub_id]));
  238. write
  239. .send(Message::text(serde_json::to_string(&unsubscription)?))
  240. .await?;
  241. Ok(())
  242. }
  243. fn send_btc_to_main_wallet(self: Arc<Self>, amount: u64, btc_keys: BtcKeys) -> BtcResult<()> {
  244. debug!(target: "BTC BRIDGE", "Sending {} BTC to main wallet", amount);
  245. let client = &self.client;
  246. let keys_clone = btc_keys.clone();
  247. let script = keys_clone.script_pubkey;
  248. let utxo = client.script_list_unspent(&script)?;
  249. let mut inputs = Vec::new();
  250. let mut amounts: u64 = 0;
  251. for tx in utxo {
  252. let tx_in = TxIn {
  253. previous_output: OutPoint {
  254. txid: tx.tx_hash,
  255. vout: tx.tx_pos as u32,
  256. },
  257. sequence: 0xffffffff,
  258. witness: Vec::new(),
  259. script_sig: Script::new(),
  260. };
  261. inputs.push(tx_in);
  262. amounts += tx.value;
  263. }
  264. let main_script_pubkey = self.main_account.script_pubkey.clone();
  265. //Estimate fee for getting in 2 blocks ahead
  266. let estimated_fee = client.estimate_fee(2)?;
  267. //TODO: Better handling of fees, don't cast to u64
  268. let value = amounts - estimated_fee as u64;
  269. let transaction = Transaction {
  270. input: inputs,
  271. output: vec![TxOut {
  272. script_pubkey: main_script_pubkey,
  273. value: value,
  274. }],
  275. lock_time: 0,
  276. version: 2,
  277. };
  278. let _signed_tx = sign_transaction(
  279. transaction,
  280. script,
  281. btc_keys.keypair.secret,
  282. btc_keys.btc_pubkey,
  283. &btc_keys.keypair.context,
  284. );
  285. //TODO: Serialize and send tx
  286. //let txid = client.transaction_broadcast_raw(serialize(&signed_tx))?;
  287. debug!(target: "BTC BRIDGE", "Sent {} BTC to main wallet:", amount, /*txid*/);
  288. Ok(())
  289. }
  290. }
  291. #[async_trait]
  292. impl NetworkClient for BtcClient {
  293. async fn subscribe(
  294. self: Arc<Self>,
  295. drk_pub_key: jubjub::SubgroupPoint,
  296. _mint: Option<String>,
  297. ) -> Result<TokenSubscribtion> {
  298. // Generate bitcoin keys
  299. let keypair = Keypair::new();
  300. let btc_keys = BtcKeys::new(&keypair, self.network);
  301. let secret_key = serialize(&keypair);
  302. let public_key = BtcKeys::btcpub_from_keypair(&keypair).to_string();
  303. // start scheduler for checking balance
  304. debug!(target: "BRIDGE BITCOIN", "Subscribing for deposit");
  305. smol::spawn(async move {
  306. let result = self.handle_subscribe_request(btc_keys, drk_pub_key).await;
  307. if let Err(e) = result {
  308. error!(target: "BTC BRIDGE SUBSCRIPTION","{}", e.to_string());
  309. }
  310. })
  311. .detach();
  312. Ok(TokenSubscribtion {
  313. secret_key,
  314. public_key,
  315. })
  316. }
  317. async fn subscribe_with_keypair(
  318. self: Arc<Self>,
  319. private_key: Vec<u8>,
  320. _public_key: Vec<u8>,
  321. drk_pub_key: jubjub::SubgroupPoint,
  322. _mint: Option<String>,
  323. ) -> Result<String> {
  324. let keypair: Keypair = deserialize(&private_key)?;
  325. let btc_keys = BtcKeys::new(&keypair, self.network);
  326. let public_key = keypair.pubkey().to_string();
  327. smol::spawn(async move {
  328. let result = self.handle_subscribe_request(btc_keys, drk_pub_key).await;
  329. if let Err(e) = result {
  330. error!(target: "BTC BRIDGE SUBSCRIPTION","{}", e.to_string());
  331. }
  332. })
  333. .detach();
  334. Ok(public_key)
  335. }
  336. async fn get_notifier(self: Arc<Self>) -> Result<async_channel::Receiver<TokenNotification>> {
  337. Ok(self.notify_channel.1.clone())
  338. }
  339. async fn send(self: Arc<Self>, address: Vec<u8>, amount: u64) -> Result<()> {
  340. // address is not a btc address, so derive the btc address
  341. let client = &self.client;
  342. let public_key = deserialize(&address)?;
  343. let script_pubkey = BtcKeys::derive_btc_script_pubkey(public_key, self.network);
  344. let main_script_pubkey = &self.main_account.script_pubkey;
  345. //TODO: Map to errors properly
  346. let main_utxo = client.script_list_unspent(&main_script_pubkey).unwrap();
  347. let transaction = Transaction {
  348. input: vec![TxIn {
  349. previous_output: OutPoint {
  350. txid: main_utxo[0].tx_hash,
  351. vout: main_utxo[0].tx_pos as u32,
  352. },
  353. sequence: 0xffffffff,
  354. witness: Vec::new(),
  355. script_sig: Script::new(),
  356. }],
  357. output: vec![TxOut {
  358. script_pubkey: script_pubkey.clone(),
  359. value: amount,
  360. }],
  361. lock_time: 0,
  362. version: 2,
  363. };
  364. let _signed_tx = sign_transaction(
  365. transaction,
  366. script_pubkey,
  367. self.main_account.keypair.secret,
  368. self.main_account.btc_pubkey,
  369. &self.main_account.keypair.context,
  370. );
  371. //TODO: Serialize and send tx
  372. //let txid = client.transaction_broadcast_raw(serialize(&signed_tx))?;
  373. Ok(())
  374. }
  375. }
  376. pub fn sign_transaction(
  377. tx: Transaction,
  378. script_pubkey: Script,
  379. priv_key: SecretKey,
  380. pub_key: BtcPubKey,
  381. curve: &Secp256k1<All>,
  382. ) -> Transaction {
  383. let mut signed_inputs: Vec<TxIn> = Vec::new();
  384. for (i, unsigned_input) in tx.input.iter().enumerate() {
  385. let sighash = tx.signature_hash(i, &script_pubkey, SigHashType::All as u32);
  386. //TODO: replace unwrap
  387. let msg = BtcMessage::from_slice(&sighash.as_ref()).unwrap();
  388. let signature = curve.sign(&msg, &priv_key);
  389. let byte_signature = &signature.serialize_der();
  390. let mut with_hashtype = byte_signature.to_vec();
  391. with_hashtype.push(SigHashType::All as u8);
  392. let redeem_script = Builder::new()
  393. .push_slice(with_hashtype.as_slice())
  394. .push_key(&pub_key)
  395. .into_script();
  396. signed_inputs.push(TxIn {
  397. previous_output: unsigned_input.previous_output,
  398. script_sig: redeem_script,
  399. sequence: unsigned_input.sequence,
  400. witness: unsigned_input.witness.clone(),
  401. });
  402. }
  403. Transaction {
  404. version: tx.version,
  405. lock_time: tx.lock_time,
  406. input: signed_inputs,
  407. output: tx.output,
  408. }
  409. }
  410. impl Encodable for bitcoin::Address {
  411. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  412. let addr = self.to_string();
  413. let len = addr.encode(s)?;
  414. Ok(len)
  415. }
  416. }
  417. impl Decodable for bitcoin::Address {
  418. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  419. let addr: String = Decodable::decode(&mut d)?;
  420. let addr = bitcoin::Address::from_str(&addr)
  421. .map_err(|err| crate::Error::from(BtcFailed::from(err)))?;
  422. Ok(addr)
  423. }
  424. }
  425. impl Encodable for bitcoin::PublicKey {
  426. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  427. let key = self.to_bytes();
  428. let len = key.encode(s)?;
  429. Ok(len)
  430. }
  431. }
  432. impl Decodable for bitcoin::PublicKey {
  433. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  434. let key: Vec<u8> = Decodable::decode(&mut d)?;
  435. let key = bitcoin::PublicKey::from_slice(&key)
  436. .map_err(|err| crate::Error::from(BtcFailed::from(err)))?;
  437. Ok(key)
  438. }
  439. }
  440. impl Encodable for bitcoin::PrivateKey {
  441. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  442. let key: String = self.to_string();
  443. let len = key.encode(s)?;
  444. Ok(len)
  445. }
  446. }
  447. impl Decodable for bitcoin::PrivateKey {
  448. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  449. let key: String = Decodable::decode(&mut d)?;
  450. let key = bitcoin::PrivateKey::from_str(&key)
  451. .map_err(|err| crate::Error::from(BtcFailed::from(err)))?;
  452. Ok(key)
  453. }
  454. }
  455. impl Encodable for secp256k1::key::PublicKey {
  456. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  457. let key: Vec<u8> = self.serialize().to_vec();
  458. let len = key.encode(s)?;
  459. Ok(len)
  460. }
  461. }
  462. impl Decodable for secp256k1::key::PublicKey {
  463. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  464. let key: Vec<u8> = Decodable::decode(&mut d)?;
  465. let key = secp256k1::key::PublicKey::from_slice(&key)
  466. .map_err(|err| crate::Error::from(BtcFailed::from(err)))?;
  467. Ok(key)
  468. }
  469. }
  470. // TODO: add secret + public keys together for Encodable
  471. impl Encodable for Keypair {
  472. fn encode<S: std::io::Write>(&self, s: S) -> Result<usize> {
  473. let key: Vec<u8> = self.to_bytes().to_vec();
  474. let len = key.encode(s)?;
  475. Ok(len)
  476. }
  477. }
  478. impl Decodable for Keypair {
  479. fn decode<D: std::io::Read>(mut d: D) -> Result<Self> {
  480. let key: Vec<u8> = Decodable::decode(&mut d)?;
  481. let key = Keypair::from_bytes(key.as_slice()).map_err(|_| {
  482. crate::Error::from(BtcFailed::DecodeAndEncodeError(
  483. "load keypair from slice".into(),
  484. ))
  485. })?;
  486. Ok(key)
  487. }
  488. }
  489. #[derive(Debug)]
  490. pub enum BtcFailed {
  491. NotEnoughValue(u64),
  492. BadBtcAddress(String),
  493. ElectrumError(String),
  494. BtcError(String),
  495. DecodeAndEncodeError(String),
  496. KeypairError(String),
  497. Notification(String),
  498. }
  499. impl std::error::Error for BtcFailed {}
  500. impl std::fmt::Display for BtcFailed {
  501. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  502. match self {
  503. BtcFailed::NotEnoughValue(i) => {
  504. write!(f, "There is no enough value {}", i)
  505. }
  506. BtcFailed::BadBtcAddress(ref err) => {
  507. write!(f, "Unable to create Electrum Client: {}", err)
  508. }
  509. BtcFailed::ElectrumError(ref err) => write!(f, "could not parse BTC address: {}", err),
  510. BtcFailed::DecodeAndEncodeError(ref err) => {
  511. write!(f, "Decode and decode keys error: {}", err)
  512. }
  513. BtcFailed::KeypairError(ref err) => {
  514. write!(f, "Keypair error from Secp256k1: {}", err)
  515. }
  516. BtcFailed::Notification(i) => {
  517. write!(f, "Received Notification Error: {}", i)
  518. }
  519. BtcFailed::BtcError(i) => {
  520. write!(f, "BtcFailed: {}", i)
  521. }
  522. }
  523. }
  524. }
  525. impl From<crate::error::Error> for BtcFailed {
  526. fn from(err: crate::error::Error) -> BtcFailed {
  527. BtcFailed::BtcError(err.to_string())
  528. }
  529. }
  530. impl From<secp256k1::Error> for BtcFailed {
  531. fn from(err: secp256k1::Error) -> BtcFailed {
  532. BtcFailed::KeypairError(err.to_string())
  533. }
  534. }
  535. impl From<bitcoin::util::address::Error> for BtcFailed {
  536. fn from(err: bitcoin::util::address::Error) -> BtcFailed {
  537. BtcFailed::BadBtcAddress(err.to_string())
  538. }
  539. }
  540. impl From<electrum_client::Error> for BtcFailed {
  541. fn from(err: electrum_client::Error) -> BtcFailed {
  542. BtcFailed::ElectrumError(err.to_string())
  543. }
  544. }
  545. impl From<bitcoin::util::key::Error> for BtcFailed {
  546. fn from(err: bitcoin::util::key::Error) -> BtcFailed {
  547. BtcFailed::DecodeAndEncodeError(err.to_string())
  548. }
  549. }
  550. pub type BtcResult<T> = std::result::Result<T, BtcFailed>;
  551. #[cfg(test)]
  552. mod tests {
  553. use crate::serial::{deserialize, serialize};
  554. use std::str::FromStr;
  555. #[test]
  556. pub fn test_serialize_btc_address() -> super::BtcResult<()> {
  557. let btc_addr =
  558. bitcoin::Address::from_str(&String::from("mxVFsFW5N4mu1HPkxPttorvocvzeZ7KZyk"))?;
  559. let btc_ser = serialize(&btc_addr);
  560. let btc_dser = deserialize(&btc_ser)?;
  561. assert_eq!(btc_addr, btc_dser);
  562. Ok(())
  563. }
  564. }