| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- use rand::{thread_rng, Rng};
- use rand::distributions::Alphanumeric;
- use secp256k1::key::{SecretKey, PublicKey};
- use bitcoin::util::ecdsa::{PrivateKey, PublicKey as BitcoinPubKey};
- use bitcoin::util::{address::Payload, address::Address};
- // Use p2pkh for 1st iteration
- use bitcoin::hash_types::PubkeyHash;
- use bitcoin::network::constants::Network;
- use super::reqrep::{PeerId, RepProtocol, Reply, ReqProtocol, Request};
- use crate::blockchain::{rocks::columns, RocksColumn, CashierKeypair, CashierStore};
- use crate::{serial::deserialize, serial::serialize, Error, Result};
- use crate::wallet::{WalletDb, WalletPtr};
- use std::net::SocketAddr;
- use async_std::sync::Arc;
- use async_executor::Executor;
- use log::*;
- #[repr(u8)]
- enum CashierError {
- NoError,
- UpdateIndex,
- }
- #[repr(u8)]
- enum CashierCommand {
- GetDBTC,
- GetBTC,
- }
- pub struct BitcoinKeys {
- secret_key: SecretKey,
- bitcoin_private_key: PrivateKey,
- pub bitcoin_public_key: BitcoinPubKey,
- pub pub_address: Address,
- }
- impl BitcoinKeys {
- pub fn new(
- ) -> Result<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();
- //let public_key = PublicKey::from_secret_key(&context, &secret_key);
- // Use Testnet
- let bitcoin_private_key = PrivateKey::new(secret_key, Network::Testnet);
- let bitcoin_public_key = BitcoinPubKey::from_private_key(&context, &bitcoin_private_key);
- let pub_address = Address::p2pkh(&bitcoin_public_key, Network::Testnet);
- Ok(Self {
- secret_key,
- bitcoin_private_key,
- bitcoin_public_key,
- pub_address,
- })
- }
- pub fn get_deposit_address(&self) -> &Address {
- &self.pub_address
- }
- }
- pub struct CashierService {
- addr: SocketAddr,
- cashierstore: Arc<CashierStore>,
- wallet: Arc<WalletDb>,
- }
- impl CashierService {
- pub fn new(
- addr: SocketAddr,
- rocks: RocksColumn<columns::CashierKeys>,
- wallet: Arc<WalletDb>,
- )-> Result<Arc<CashierService>> {
- let cashierstore = CashierStore::new(rocks)?;
- Ok(Arc::new(CashierService {
- cashierstore,
- addr,
- wallet,
- }))
- }
- pub async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
- let service_name = String::from("CASHIER DAEMON");
- let mut protocol = RepProtocol::new(self.addr.clone(), service_name.clone());
- let (send, recv) = protocol.start().await?;
- let handle_request_task = executor.spawn(self.handle_request_loop(
- send.clone(),
- recv.clone(),
- executor.clone(),
- ));
- protocol.run(executor.clone()).await?;
- let _ = handle_request_task.cancel().await;
- Ok(())
- }
- async fn handle_request_loop(
- self: Arc<Self>,
- send_queue: async_channel::Sender<(PeerId, Reply)>,
- recv_queue: async_channel::Receiver<(PeerId, Request)>,
- executor: Arc<Executor<'_>>,
- ) -> Result<()> {
- loop {
- match recv_queue.recv().await {
- Ok(msg) => {
- let cashierstore = self.cashierstore.clone();
- let _ = executor
- .spawn(Self::handle_request(
- msg,
- cashierstore,
- send_queue.clone(),
- ))
- .detach();
- }
- Err(_) => {
- break;
- }
- }
- }
- Ok(())
- }
- async fn handle_request(
- msg: (PeerId, Request),
- cashierstore: Arc<CashierStore>,
- send_queue: async_channel::Sender<(PeerId, Reply)>,
- ) -> Result<()> {
- let request = msg.1;
- let peer = msg.0;
- match request.get_command() {
- 0 => {
- // Exchange zk_pubkey for bitcoin address
- let zkpub = request.get_payload();
- // Generate bitcoin Address
- let btc_keys = BitcoinKeys::new().unwrap();
- let deposit_address = btc_keys.get_deposit_address();
- let mut reply = Reply::from(&request, CashierError::NoError as u32, vec![]);
- // if let None = error {
- // reply.set_error(CashierError::UpdateIndex as u32);
- // }
- // send reply
- send_queue.send((peer, reply)).await?;
- }
- 1 => {
- // Withdraw
- }
- _ => {
- return Err(Error::ServicesError("received wrong command"));
- }
- }
- Ok(())
- }
- }
- pub struct CashierClient {
- protocol: ReqProtocol,
- cashierstore: Arc<CashierStore>,
- }
- impl CashierClient {
- pub fn new(addr: SocketAddr, rocks: RocksColumn<columns::CashierKeys>) -> Result<Self> {
- let protocol = ReqProtocol::new(addr, String::from("CASHIER CLIENT"));
- let cashierstore = CashierStore::new(rocks)?;
- Ok(CashierClient {
- protocol,
- cashierstore,
- })
- }
- pub async fn start(&mut self) -> Result<()> {
- self.protocol.start().await?;
- //self.sync().await?;
- Ok(())
- }
- pub async fn get_keys(&mut self, index: jubjub::SubgroupPoint) -> Result<Option<CashierKeypair>> {
- let rep = self
- .protocol
- .request(
- CashierCommand::GetDBTC as u8,
- serialize(&index),
- &handle_error,
- )
- .await?;
- if let Some(keys) = rep {
- let keys: CashierKeypair = deserialize(&keys)?;
- //self.gateway_slabs_sub_s.send(slab.clone()).await?;
- self.cashierstore.put(keys.clone())?;
- return Ok(Some(keys));
- }
- Ok(None)
- }
- // pub async fn put_keys(&mut self, mut keys: CashierKeys) -> Result<()> {
- // loop {
- // let last_index = self.sync().await?;
- // //keys.set_index(last_index + 1);
- // let keys = serialize(&keys);
- // let rep = self
- // .protocol
- // .request(CashierCommand::PutSlab as u8, slab.clone(), &handle_error)
- // .await?;
- // if let Some(_) = rep {
- // break;
- // }
- // }
- // Ok(())
- // }
- pub fn get_cashierstore(&self) -> Arc<CashierStore> {
- self.cashierstore.clone()
- }
- }
- fn handle_error(status_code: u32) {
- match status_code {
- 1 => {
- warn!("Reply has an Error: Index is not updated");
- }
- 2 => {
- warn!("Reply has an Error: Index Not Exist");
- }
- _ => {}
- }
- }
|