1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use crate::client::{Client, ClientType, CryptoClient};
use crate::types::{Amount, ClientOptions, Currency, Symbol, SyncItem, SyncStats, WalletBalance};
use crate::Result;
use async_std::sync::Arc;
use async_trait::async_trait;
use num_bigint::BigInt;
use rpc_json_client::{ClientBuilder, RpcClient};

#[derive(Clone)]
pub struct RavencoinRpcClient {
    client: Arc<RpcClient>,
}

pub fn get_client(client_type: ClientType, options: ClientOptions) -> crate::Result<Box<Client>> {
    match client_type {
        //@todo need url to come as well.
        ClientType::RPC => Ok(Box::new(RavencoinRpcClient::new(options))),
        _ => Err(crate::error::ClientError::UnsupportedType(client_type)),
    }
}

impl RavencoinRpcClient {
    pub fn new(options: ClientOptions) -> Self {
        let client = ClientBuilder::new(&options.url).with_retry().build();

        RavencoinRpcClient {
            client: Arc::new(client),
        }
    }
}

#[async_trait]
impl CryptoClient for RavencoinRpcClient {
    async fn sync_stats(&self) -> SyncStats {
        let result: serde_json::Value = match self.client.execute("getblockchaininfo", &[]).await {
            Ok(r) => r,
            Err(_e) => {
                //@todo completely revamp this section should probably return a error like I say
                //below, but we want to make sure that the monitor understands to re-try.
                // info!("Node appeared to not be ready yet. Sleeping for 60 seconds");
                async_std::task::sleep(std::time::Duration::from_secs(60)).await;
                //We should return an error here... but oh well
                return SyncStats {
                    current_block: 0,
                    syncing: true,
                    sync_item: SyncItem::VerificationProgress,
                    estimated_sync_item_remaining: 0.0,
                };
            }
        };

        let blocks = result.as_object().unwrap().get("blocks").unwrap();
        //Should be match instead.
        let current_block = blocks.as_u64().unwrap();

        //@todo save the as_object up above and then just reuse that everytime instead of
        //re-unwrapping it everytime.
        //Should be match instead.
        let progress = result
            .as_object()
            .unwrap()
            .get("verificationprogress")
            .unwrap()
            .as_f64()
            .unwrap();

        let estimated_sync_item_remaining = 1.0 - progress;

        //Triple 9s
        let (syncing, estimated_sync_item_remaining) = if estimated_sync_item_remaining < 0.001 {
            (false, 0.0)
        } else {
            (true, estimated_sync_item_remaining)
        };

        SyncStats {
            current_block,
            syncing,
            sync_item: SyncItem::VerificationProgress,
            estimated_sync_item_remaining,
        }
    }

    async fn wallet_balance(&self, _identifier: &str) -> Result<WalletBalance> {
        let result: serde_json::Value = self.client.execute("getwalletinfo", &[]).await?;

        let confirmed_balance = result["balance"].as_f64().unwrap_or(0.0);
        let unconfirmed_balance = result["unconfirmed_balance"].as_f64().unwrap_or(0.0);

        let confirmed_balance = BigInt::from((confirmed_balance * 100_000_000.0).floor() as u64);
        let unconfirmed_balance =
            BigInt::from((unconfirmed_balance * 100_000_000.0).floor() as u64);

        Ok(WalletBalance {
            //We need bigints here actually.
            confirmed_balance: Amount {
                value: confirmed_balance,
                currency: Currency {
                    symbol: Symbol::RVN,
                    decimals: 8,
                },
            },
            unconfirmed_balance: Amount {
                value: unconfirmed_balance,
                currency: Currency {
                    symbol: Symbol::RVN,
                    decimals: 8,
                },
            },
        })
    }

    fn client_type(&self) -> ClientType {
        ClientType::RPC
    }
}