common: adds basic function for rgb

Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
This commit is contained in:
Vincenzo Palazzo 2024-02-20 11:56:30 +01:00
parent 7598ba2aee
commit 9548429b62
Signed by: vincenzopalazzo
GPG Key ID: 8B6DC2B870B80D5F
9 changed files with 263 additions and 0 deletions

View File

@ -38,6 +38,7 @@
libcap
gcc
pkg-config
openssl
git
gnumake

View File

@ -11,3 +11,4 @@ log = "0.4.20"
anyhow = "1.0.79"
serde = "1.0.159"
serde_json = "1.0.95"
rgb-common = { path = "../rgb-common" }

View File

@ -1,3 +1,5 @@
use rgb_common::anyhow;
mod plugin;
fn main() -> anyhow::Result<()> {

View File

@ -6,6 +6,8 @@ use serde_json as json;
use clightningrpc_plugin::{commands::RPCCommand, plugin::Plugin};
use clightningrpc_plugin_macros::plugin;
use rgb_common::anyhow;
#[derive(Clone, Debug)]
pub(crate) struct State;

View File

@ -4,3 +4,27 @@ version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.71"
bitcoin = { version = "0.29.0", default-features = false, features = ["secp-recovery"] }
lightning = "0.0.118"
amplify = "=4.5.0"
base64 = "0.13.0"
bp-core = "=0.10.11"
commit_verify = "=0.10.6"
futures = "0.3"
hex = "0.4"
reqwest = { version = "0.11", default-features = false, features = ["json", "blocking"] }
rgb-contracts = { version = "=0.10.2", features = ["electrum"] }
rgb_core = { package = "rgb-core", version = "=0.10.8" }
rgb-lib = { git = "https://github.com/RGB-Tools/rgb-lib", branch = "rln_v0.10" }
rgb-std = "=0.10.9"
rgb-wallet = "=0.10.9"
serde = { version = "^1.0", features = ["derive"] }
serde_json = "^1.0"
strict_encoding = "=2.6.1"
tokio = { version = "1.36", features = ["macros", "rt-multi-thread"] }
# Fixing dependencies resolution :/
amplify_num = "=0.5.1"

104
rgb-common/src/comm.rs Normal file
View File

@ -0,0 +1,104 @@
//! A module to provide RGB functionality
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;
use bitcoin::OutPoint as BtcOutPoint;
use serde::{Deserialize, Serialize};
use bp::seals::txout::CloseMethod;
use rgb_core::ContractId;
use crate::ldk;
use crate::proxy;
use crate::std::persistence::ConsignerError::Reveal;
use ldk::ln::PaymentHash;
/// RGB channel info
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RgbInfo {
/// Channel contract ID
pub contract_id: ContractId,
/// Channel RGB local amount
pub local_rgb_amount: u64,
/// Channel RGB remote amount
pub remote_rgb_amount: u64,
}
/// RGB payment info
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RgbPaymentInfo {
/// RGB contract ID
pub contract_id: ContractId,
/// RGB payment amount
pub amount: u64,
/// RGB local amount
pub local_rgb_amount: u64,
/// RGB remote amount
pub remote_rgb_amount: u64,
}
/// Get RgbPaymentInfo file
pub fn get_rgb_payment_info(payment_hash: &PaymentHash, ldk_data_dir: &PathBuf) -> RgbPaymentInfo {
let rgb_payment_info_path = ldk_data_dir.join(hex::encode(payment_hash.0));
parse_rgb_payment_info(&rgb_payment_info_path)
}
/// Parse RgbPaymentInfo
pub fn parse_rgb_payment_info(rgb_payment_info_path: &PathBuf) -> RgbPaymentInfo {
let serialized_info =
fs::read_to_string(&rgb_payment_info_path).expect("valid rgb payment info");
serde_json::from_str(&serialized_info).expect("valid rgb info file")
}
/// Get RgbInfo file
pub fn get_rgb_channel_info(
channel_id: &[u8; 32],
ldk_data_dir: &PathBuf,
) -> anyhow::Result<(RgbInfo, PathBuf)> {
let info_file_path = ldk_data_dir.join(hex::encode(channel_id));
let serialized_info = fs::read_to_string(&info_file_path)?;
let info: RgbInfo = serde_json::from_str(&serialized_info)?;
Ok((info, info_file_path))
}
/// Write RgbInfo file
pub fn write_rgb_channel_info(path: &PathBuf, rgb_info: &RgbInfo) {
let serialized_info = serde_json::to_string(&rgb_info).expect("valid rgb info");
fs::write(path, serialized_info).expect("able to write")
}
/// Rename RgbInfo file to channel_id
pub(crate) fn rename_rgbinfo_file(
channel_id: &[u8; 32],
temporary_channel_id: &[u8; 32],
ldk_data_dir: &PathBuf,
) {
let temporary_channel_id_path = ldk_data_dir.join(hex::encode(temporary_channel_id));
let channel_id_path = ldk_data_dir.join(hex::encode(channel_id));
fs::rename(temporary_channel_id_path, channel_id_path).expect("rename ok");
}
/// Update RGB channel amount
pub(crate) fn update_rgb_channel_amount(
channel_id: &[u8; 32],
rgb_offered_htlc: u64,
rgb_received_htlc: u64,
ldk_data_dir: &PathBuf,
) -> anyhow::Result<()> {
let (mut rgb_info, info_file_path) = get_rgb_channel_info(channel_id, ldk_data_dir)?;
if rgb_offered_htlc > rgb_received_htlc {
let spent = rgb_offered_htlc - rgb_received_htlc;
rgb_info.local_rgb_amount -= spent;
rgb_info.remote_rgb_amount += spent;
} else {
let received = rgb_received_htlc - rgb_offered_htlc;
rgb_info.local_rgb_amount += received;
rgb_info.remote_rgb_amount -= received;
}
write_rgb_channel_info(&info_file_path, &rgb_info);
Ok(())
}

View File

@ -1 +1,16 @@
mod comm;
mod proxy;
mod rgb_manager;
use lightning as ldk;
use reqwest::blocking::Client as BlockingClient;
pub use anyhow;
// Re-exporting RGB dependencies under a single module.
pub use rgb;
pub use rgb::interface::rgb20 as asset20;
pub use rgb_core as core;
pub use rgb_lib as lib;
pub use rgb_manager::RGBManager;
pub use rgbstd as std;
pub use rgbwallet as wallet;

72
rgb-common/src/proxy.rs Normal file
View File

@ -0,0 +1,72 @@
//! A module for operating an RGB HTTP JSON-RPC proxy
use amplify::s;
use reqwest::header::CONTENT_TYPE;
use serde::{Deserialize, Serialize};
use tokio::task;
use core::time::Duration;
use crate::BlockingClient;
const JSON: &str = "application/json";
const PROXY_TIMEOUT: u8 = 90;
/// JSON-RPC Error
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct JsonRpcError {
pub(crate) code: i64,
message: String,
}
/// JSON-RPC request
#[derive(Debug, Deserialize, Serialize)]
pub struct JsonRpcRequest<P> {
method: String,
jsonrpc: String,
id: Option<String>,
params: Option<P>,
}
/// JSON-RPC response
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct JsonRpcResponse<R> {
id: Option<String>,
pub(crate) result: Option<R>,
pub(crate) error: Option<JsonRpcError>,
}
/// Blinded UTXO parameter
#[derive(Debug, Deserialize, Serialize)]
pub struct BlindedUtxoParam {
blinded_utxo: String,
}
pub(crate) fn get_blocking_client() -> BlockingClient {
BlockingClient::builder()
.timeout(Duration::from_secs(PROXY_TIMEOUT as u64))
.build()
.expect("valid proxy")
}
pub(crate) fn get_consignment(
url: &str,
consignment_id: String,
) -> Result<JsonRpcResponse<String>, reqwest::Error> {
task::block_in_place(|| {
let body = JsonRpcRequest {
method: s!("consignment.get"),
jsonrpc: s!("2.0"),
id: None,
params: Some(BlindedUtxoParam {
blinded_utxo: consignment_id,
}),
};
get_blocking_client()
.post(url)
.header(CONTENT_TYPE, JSON)
.json(&body)
.send()?
.json::<JsonRpcResponse<String>>()
})
}

View File

@ -0,0 +1,42 @@
//! RGB Manager
use std::str::FromStr;
use std::sync::Arc;
use std::sync::Mutex;
use crate::lib::wallet::{DatabaseType, Wallet, WalletData};
use crate::lib::BitcoinNetwork;
use crate::proxy;
pub struct RGBManager {
proxy_client: Arc<crate::BlockingClient>,
wallet: Arc<Mutex<Wallet>>,
}
impl RGBManager {
pub fn init(root_dir: &str, pubkey: &str, network: &str) -> anyhow::Result<Self> {
let client = proxy::get_blocking_client();
let wallet = Wallet::new(WalletData {
data_dir: root_dir.to_owned(),
bitcoin_network: BitcoinNetwork::from_str(network)?,
database_type: DatabaseType::Sqlite,
max_allocations_per_utxo: 11,
pubkey: pubkey.to_owned(),
mnemonic: None,
vanilla_keychain: None,
})?;
// FIXME: go online
// FIXME: setting up the correct proxy client URL
Ok(Self {
proxy_client: Arc::new(client),
wallet: Arc::new(Mutex::new(wallet)),
})
}
pub fn wallet(&self) -> Arc<Mutex<Wallet>> {
self.wallet.clone()
}
pub fn proxy_client(&self) -> Arc<crate::BlockingClient> {
self.proxy_client.clone()
}
}