zcash-sync/src/main/rpc.rs

276 lines
7.4 KiB
Rust
Raw Normal View History

2022-06-09 10:05:58 -07:00
#[macro_use]
extern crate rocket;
2022-06-10 03:41:03 -07:00
use anyhow::anyhow;
2022-06-10 02:16:00 -07:00
use rocket::fairing::AdHoc;
2022-06-10 11:41:05 -07:00
use rocket::http::Status;
2022-06-10 03:41:03 -07:00
use rocket::response::Responder;
2022-06-10 03:09:37 -07:00
use rocket::serde::{json::Json, Deserialize, Serialize};
2022-06-10 11:41:05 -07:00
use rocket::{response, Request, Response, State};
use std::collections::HashMap;
use thiserror::Error;
2022-06-10 02:16:00 -07:00
use warp_api_ffi::api::payment::{Recipient, RecipientMemo};
2022-06-10 11:41:05 -07:00
use warp_api_ffi::api::payment_uri::PaymentURI;
2022-06-10 03:41:03 -07:00
use warp_api_ffi::{AccountRec, CoinConfig, TxRec};
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
Other(#[from] anyhow::Error),
}
impl<'r> Responder<'r, 'static> for Error {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
let error = self.to_string();
Response::build_from(error.respond_to(req)?)
.status(Status::InternalServerError)
.ok()
}
}
2022-06-09 10:05:58 -07:00
2022-06-10 04:14:21 -07:00
fn init(coin: u8, config: HashMap<String, String>) -> anyhow::Result<()> {
2022-06-10 03:09:37 -07:00
warp_api_ffi::init_coin(
2022-06-10 04:14:21 -07:00
coin,
2022-06-10 11:41:05 -07:00
config
.get("db_path")
.ok_or(anyhow!("Missing configuration value"))?,
2022-06-10 03:09:37 -07:00
)?;
warp_api_ffi::set_coin_lwd_url(
2022-06-10 04:14:21 -07:00
coin,
2022-06-10 11:41:05 -07:00
config
.get("lwd_url")
.ok_or(anyhow!("Missing configuration value"))?,
2022-06-10 03:09:37 -07:00
);
2022-06-10 04:14:21 -07:00
Ok(())
}
#[rocket::main]
async fn main() -> anyhow::Result<()> {
2022-06-10 06:01:07 -07:00
env_logger::init();
2022-06-10 04:14:21 -07:00
let _ = dotenv::dotenv();
let rocket = rocket::build();
let figment = rocket.figment();
let zec: HashMap<String, String> = figment.extract_inner("zec")?;
init(0, zec)?;
let yec: HashMap<String, String> = figment.extract_inner("yec")?;
init(1, yec)?;
2022-06-09 10:05:58 -07:00
2022-06-10 11:41:05 -07:00
let _ = rocket
.mount(
2022-06-09 10:05:58 -07:00
"/",
routes![
set_lwd,
2022-06-10 02:16:00 -07:00
set_active,
2022-06-09 10:05:58 -07:00
new_account,
2022-06-10 03:41:03 -07:00
list_accounts,
2022-06-09 10:05:58 -07:00
sync,
2022-06-10 02:16:00 -07:00
rewind,
get_latest_height,
get_backup,
get_balance,
get_address,
get_tx_history,
pay,
2022-06-10 11:41:05 -07:00
mark_synced,
broadcast_tx,
new_diversified_address,
make_payment_uri,
parse_payment_uri,
2022-06-09 10:05:58 -07:00
],
)
2022-06-10 02:16:00 -07:00
.attach(AdHoc::config::<Config>())
2022-06-09 10:05:58 -07:00
.launch()
.await?;
Ok(())
}
#[post("/set_lwd?<coin>&<lwd_url>")]
pub fn set_lwd(coin: u8, lwd_url: String) {
warp_api_ffi::set_coin_lwd_url(coin, &lwd_url);
}
2022-06-10 02:16:00 -07:00
#[post("/set_active?<coin>&<id_account>")]
pub fn set_active(coin: u8, id_account: u32) {
warp_api_ffi::set_active_account(coin, id_account);
}
2022-06-10 03:09:37 -07:00
#[post("/new_account", format = "application/json", data = "<seed>")]
2022-06-10 03:41:03 -07:00
pub fn new_account(seed: Json<AccountSeed>) -> Result<String, Error> {
2022-06-10 03:09:37 -07:00
let id_account = warp_api_ffi::api::account::new_account(
seed.coin,
&seed.name,
seed.key.clone(),
seed.index,
2022-06-10 03:41:03 -07:00
)?;
2022-06-10 02:16:00 -07:00
warp_api_ffi::set_active_account(seed.coin, id_account);
2022-06-10 03:41:03 -07:00
Ok(id_account.to_string())
}
#[get("/accounts")]
pub fn list_accounts() -> Result<Json<Vec<AccountRec>>, Error> {
let c = CoinConfig::get_active();
let db = c.db()?;
let accounts = db.get_accounts()?;
Ok(Json(accounts))
2022-06-09 10:05:58 -07:00
}
#[post("/sync?<offset>")]
2022-06-10 03:41:03 -07:00
pub async fn sync(offset: Option<u32>) -> Result<(), Error> {
let c = CoinConfig::get_active();
warp_api_ffi::api::sync::coin_sync(c.coin, true, offset.unwrap_or(0), |_| {}).await?;
Ok(())
2022-06-09 10:05:58 -07:00
}
2022-06-10 02:16:00 -07:00
#[post("/rewind?<height>")]
2022-06-10 03:41:03 -07:00
pub async fn rewind(height: u32) -> Result<(), Error> {
warp_api_ffi::api::sync::rewind_to_height(height).await?;
Ok(())
2022-06-10 02:16:00 -07:00
}
2022-06-10 11:41:05 -07:00
#[post("/mark_synced")]
pub async fn mark_synced() -> Result<(), Error> {
let c = CoinConfig::get_active();
warp_api_ffi::api::sync::skip_to_last_height(c.coin).await?;
Ok(())
}
2022-06-10 02:16:00 -07:00
#[get("/latest_height")]
2022-06-10 03:41:03 -07:00
pub async fn get_latest_height() -> Result<Json<Heights>, Error> {
let latest = warp_api_ffi::api::sync::get_latest_height().await?;
let synced = warp_api_ffi::api::sync::get_synced_height()?;
Ok(Json(Heights { latest, synced }))
2022-06-10 02:16:00 -07:00
}
#[get("/address")]
2022-06-10 03:41:03 -07:00
pub fn get_address() -> Result<String, Error> {
2022-06-10 02:16:00 -07:00
let c = CoinConfig::get_active();
2022-06-10 03:41:03 -07:00
let db = c.db()?;
let address = db.get_address(c.id_account)?;
Ok(address)
2022-06-10 02:16:00 -07:00
}
#[get("/backup")]
2022-06-10 03:41:03 -07:00
pub fn get_backup(config: &State<Config>) -> Result<Json<Backup>, Error> {
2022-06-10 02:16:00 -07:00
if !config.allow_backup {
2022-06-10 03:41:03 -07:00
Err(anyhow!("Backup API not enabled").into())
2022-06-10 03:09:37 -07:00
} else {
2022-06-10 02:16:00 -07:00
let c = CoinConfig::get_active();
2022-06-10 03:41:03 -07:00
let db = c.db()?;
let (seed, sk, fvk) = db.get_backup(c.id_account)?;
2022-06-10 03:09:37 -07:00
Ok(Json(Backup { seed, sk, fvk }))
2022-06-10 02:16:00 -07:00
}
}
#[get("/tx_history")]
2022-06-10 03:41:03 -07:00
pub fn get_tx_history() -> Result<Json<Vec<TxRec>>, Error> {
2022-06-10 02:16:00 -07:00
let c = CoinConfig::get_active();
2022-06-10 03:41:03 -07:00
let db = c.db()?;
let txs = db.get_txs(c.id_account)?;
Ok(Json(txs))
2022-06-10 02:16:00 -07:00
}
#[get("/balance")]
2022-06-10 03:41:03 -07:00
pub fn get_balance() -> Result<String, Error> {
2022-06-10 02:16:00 -07:00
let c = CoinConfig::get_active();
2022-06-10 03:41:03 -07:00
let db = c.db()?;
let balance = db.get_balance(c.id_account)?;
Ok(balance.to_string())
2022-06-10 02:16:00 -07:00
}
2022-06-10 03:09:37 -07:00
#[post("/pay", data = "<payment>")]
2022-06-10 03:41:03 -07:00
pub async fn pay(payment: Json<Payment>, config: &State<Config>) -> Result<String, Error> {
2022-06-10 02:16:00 -07:00
if !config.allow_send {
2022-06-10 03:41:03 -07:00
Err(anyhow!("Payment API not enabled").into())
2022-06-10 03:09:37 -07:00
} else {
2022-06-10 02:16:00 -07:00
let c = CoinConfig::get_active();
2022-06-10 03:41:03 -07:00
let latest = warp_api_ffi::api::sync::get_latest_height().await?;
2022-06-10 02:16:00 -07:00
let from = {
2022-06-10 03:41:03 -07:00
let db = c.db()?;
db.get_address(c.id_account)?
2022-06-10 02:16:00 -07:00
};
2022-06-10 03:09:37 -07:00
let recipients: Vec<_> = payment
.recipients
.iter()
.map(|p| RecipientMemo::from_recipient(&from, p))
.collect();
2022-06-10 02:16:00 -07:00
let txid = warp_api_ffi::api::payment::build_sign_send_multi_payment(
latest,
&recipients,
false,
payment.confirmations,
2022-06-10 03:09:37 -07:00
Box::new(|_| {}),
)
2022-06-10 03:41:03 -07:00
.await?;
2022-06-10 02:16:00 -07:00
Ok(txid)
}
}
2022-06-10 11:41:05 -07:00
#[post("/broadcast_tx?<tx_hex>")]
pub async fn broadcast_tx(tx_hex: String) -> Result<String, Error> {
let tx = hex::decode(tx_hex.trim_end()).map_err(|e| anyhow!(e.to_string()))?;
let tx_id = warp_api_ffi::api::payment::broadcast_tx(&tx).await?;
Ok(tx_id)
}
#[get("/new_diversified_address")]
pub fn new_diversified_address() -> Result<String, Error> {
let address = warp_api_ffi::api::account::new_diversified_address()?;
Ok(address)
}
#[get("/make_payment_uri", data = "<payment>")]
pub fn make_payment_uri(payment: Json<PaymentURI>) -> Result<String, Error> {
let uri = warp_api_ffi::api::payment_uri::make_payment_uri(
&payment.address,
payment.amount,
&payment.memo,
)?;
Ok(uri)
}
#[get("/parse_payment_uri?<uri>")]
pub fn parse_payment_uri(uri: String) -> Result<Json<PaymentURI>, Error> {
let payment = warp_api_ffi::api::payment_uri::parse_payment_uri(&uri)?;
Ok(Json(payment))
}
2022-06-10 02:16:00 -07:00
#[derive(Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct Config {
allow_backup: bool,
allow_send: bool,
}
#[derive(Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct AccountSeed {
coin: u8,
name: String,
key: Option<String>,
index: Option<u32>,
}
#[derive(Serialize)]
#[serde(crate = "rocket::serde")]
pub struct Heights {
latest: u32,
synced: u32,
}
2022-06-09 10:05:58 -07:00
2022-06-10 02:16:00 -07:00
#[derive(Serialize)]
#[serde(crate = "rocket::serde")]
pub struct Backup {
seed: Option<String>,
sk: Option<String>,
fvk: String,
}
2022-06-09 10:05:58 -07:00
2022-06-10 02:16:00 -07:00
#[derive(Deserialize)]
#[serde(crate = "rocket::serde")]
pub struct Payment {
recipients: Vec<Recipient>,
confirmations: u32,
2022-06-09 10:05:58 -07:00
}