common: adding the storage information
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
This commit is contained in:
parent
40c1d0f94c
commit
e96d1878d7
|
@ -171,13 +171,11 @@ impl RPCCommand<State> for OnFundingChannelTx {
|
|||
let tx = plugin
|
||||
.state
|
||||
.manager()
|
||||
.handle_onfunding_tx(tx, txid, body.channel_id)
|
||||
.handle_onfunding_tx(tx, txid, &mut psbt, body.channel_id)
|
||||
.unwrap();
|
||||
let updated_psbt = PartiallySignedTransaction::from_unsigned_tx(tx.clone())
|
||||
.map_err(|err| error!("{err}"))?;
|
||||
let result = OnFundingChannelTxResponse {
|
||||
tx: serialize_hex(&tx),
|
||||
psbt: updated_psbt.serialize_hex(),
|
||||
psbt: psbt.serialize_hex(),
|
||||
};
|
||||
Ok(json::json!({ "result": json::to_value(&result)? }))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
mod comm;
|
||||
mod proxy;
|
||||
mod rgb_manager;
|
||||
mod rgb_storage;
|
||||
mod types;
|
||||
|
||||
use lightning as ldk;
|
||||
use reqwest::blocking::Client as BlockingClient;
|
||||
|
|
|
@ -1,22 +1,40 @@
|
|||
//! RGB Manager
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::MutexGuard;
|
||||
|
||||
use bitcoin::bip32::ChildNumber;
|
||||
use bitcoin::bip32::{ExtendedPrivKey, ExtendedPubKey};
|
||||
use bitcoin::secp256k1;
|
||||
use bitcoin::secp256k1::Secp256k1;
|
||||
use bitcoin::Network;
|
||||
use rgb_lib::wallet::Online;
|
||||
use rgb_lib::wallet::Recipient;
|
||||
use rgb_lib::wallet::RecipientData;
|
||||
use rgb_lib::ScriptBuf;
|
||||
use rgbwallet::bitcoin;
|
||||
use rgbwallet::bitcoin::psbt::PartiallySignedTransaction;
|
||||
|
||||
use crate::lib::wallet::{DatabaseType, Wallet, WalletData};
|
||||
use crate::lib::BitcoinNetwork;
|
||||
use crate::proxy;
|
||||
use crate::rgb_storage as store;
|
||||
use crate::types;
|
||||
use store::RGBStorage;
|
||||
|
||||
/// Static blinding costant (will be removed in the future)
|
||||
/// See https://github.com/RGB-Tools/rust-lightning/blob/80497c4086beea490b56e5b8413b7f6d86f2c042/lightning/src/rgb_utils/mod.rs#L53
|
||||
pub const STATIC_BLINDING: u64 = 777;
|
||||
|
||||
pub struct RGBManager {
|
||||
proxy_client: Arc<proxy::Client>,
|
||||
esplora: Arc<proxy::Client>,
|
||||
wallet: Arc<Mutex<Wallet>>,
|
||||
online_wallet: Option<Online>,
|
||||
storage: Box<dyn store::RGBStorage>,
|
||||
path: String,
|
||||
proxy_endpoint: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for RGBManager {
|
||||
|
@ -25,26 +43,6 @@ impl std::fmt::Debug for RGBManager {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_coin_type(bitcoin_network: BitcoinNetwork) -> u32 {
|
||||
u32::from(bitcoin_network != BitcoinNetwork::Mainnet)
|
||||
}
|
||||
|
||||
fn derive_account_xprv_from_mnemonic(
|
||||
bitcoin_network: BitcoinNetwork,
|
||||
master_xprv: &ExtendedPrivKey,
|
||||
) -> anyhow::Result<ExtendedPrivKey> {
|
||||
const PURPOSE: u8 = 84;
|
||||
const ACCOUNT: u8 = 0;
|
||||
|
||||
let coin_type = get_coin_type(bitcoin_network);
|
||||
let account_derivation_path = vec![
|
||||
ChildNumber::from_hardened_idx(PURPOSE as u32).unwrap(),
|
||||
ChildNumber::from_hardened_idx(coin_type).unwrap(),
|
||||
ChildNumber::from_hardened_idx(ACCOUNT as u32).unwrap(),
|
||||
];
|
||||
Ok(master_xprv.derive_priv(&Secp256k1::new(), &account_derivation_path)?)
|
||||
}
|
||||
|
||||
impl RGBManager {
|
||||
pub fn init(
|
||||
root_dir: &str,
|
||||
|
@ -55,7 +53,8 @@ impl RGBManager {
|
|||
|
||||
let bitcoin_network = BitcoinNetwork::from_str(network)?;
|
||||
// with rgb library tere is a new function for calculate the account key
|
||||
let account_privkey = derive_account_xprv_from_mnemonic(bitcoin_network, master_xprv)?;
|
||||
let account_privkey =
|
||||
Self::derive_account_xprv_from_mnemonic(bitcoin_network, master_xprv)?;
|
||||
let account_xpub = ExtendedPubKey::from_priv(&Secp256k1::new(), &account_privkey);
|
||||
let mut wallet = Wallet::new(WalletData {
|
||||
data_dir: root_dir.to_owned(),
|
||||
|
@ -74,30 +73,47 @@ impl RGBManager {
|
|||
Network::Regtest => "",
|
||||
_ => anyhow::bail!("Network `{network}` not supported"),
|
||||
};
|
||||
let mut online_info = None;
|
||||
if !url.is_empty() {
|
||||
let _ = wallet.go_online(false, url.to_owned())?;
|
||||
online_info = Some(wallet.go_online(false, url.to_owned())?);
|
||||
}
|
||||
// FIXME: setting up the correct proxy client URL
|
||||
Ok(Self {
|
||||
proxy_client: Arc::new(client),
|
||||
esplora: Arc::new(client),
|
||||
wallet: Arc::new(Mutex::new(wallet)),
|
||||
online_wallet: online_info,
|
||||
path: root_dir.to_owned(),
|
||||
storage: Box::new(store::InMemoryStorage::new()?),
|
||||
proxy_endpoint: String::from("TODO add the proxy endpoint"),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn wallet(&self) -> Arc<Mutex<Wallet>> {
|
||||
self.wallet.clone()
|
||||
pub fn wallet(&self) -> MutexGuard<'_, Wallet> {
|
||||
self.wallet.lock().unwrap()
|
||||
}
|
||||
|
||||
pub fn proxy_client(&self) -> Arc<proxy::Client> {
|
||||
self.proxy_client.clone()
|
||||
self.esplora.clone()
|
||||
}
|
||||
|
||||
/// Check if the channel with `channel_id` is a colored channel
|
||||
/// if yes return true, otherwise false.
|
||||
///
|
||||
/// Return an error if the channel do not exist inside the db.
|
||||
pub fn is_colored_channel(&self, _channel_id: &String) -> anyhow::Result<bool> {
|
||||
Ok(true)
|
||||
fn get_coin_type(bitcoin_network: BitcoinNetwork) -> u32 {
|
||||
u32::from(bitcoin_network != BitcoinNetwork::Mainnet)
|
||||
}
|
||||
|
||||
fn derive_account_xprv_from_mnemonic(
|
||||
bitcoin_network: BitcoinNetwork,
|
||||
master_xprv: &ExtendedPrivKey,
|
||||
) -> anyhow::Result<ExtendedPrivKey> {
|
||||
const PURPOSE: u8 = 84;
|
||||
const ACCOUNT: u8 = 0;
|
||||
|
||||
let coin_type = Self::get_coin_type(bitcoin_network);
|
||||
let account_derivation_path = vec![
|
||||
ChildNumber::from_hardened_idx(PURPOSE as u32).unwrap(),
|
||||
ChildNumber::from_hardened_idx(coin_type).unwrap(),
|
||||
ChildNumber::from_hardened_idx(ACCOUNT as u32).unwrap(),
|
||||
];
|
||||
Ok(master_xprv.derive_priv(&Secp256k1::new(), &account_derivation_path)?)
|
||||
}
|
||||
|
||||
/// Modify the funding transaction before sign it with the node signer.
|
||||
|
@ -105,14 +121,47 @@ impl RGBManager {
|
|||
&self,
|
||||
tx: bitcoin::Transaction,
|
||||
txid: bitcoin::Txid,
|
||||
psbt: &mut PartiallySignedTransaction,
|
||||
channel_id: String,
|
||||
) -> anyhow::Result<bitcoin::Transaction> {
|
||||
if self.is_colored_channel(&channel_id)? {
|
||||
debug_assert!(tx.txid() == txid);
|
||||
debug_assert!(psbt.clone().extract_tx().txid() == txid);
|
||||
// allow looup by channel and returnt the rgb info
|
||||
if self.storage.is_channel_rgb(&channel_id, false)? {
|
||||
// Step 1: get the rgb info https://github.com/RGB-Tools/rgb-lightning-node/blob/master/src/ldk.rs#L328
|
||||
// Step 2: avoid to sign the PSBT because is CLN that does it
|
||||
// Step 3: Make the cosignemtn and post it somewhere
|
||||
let info = self.storage.get_rgb_channel_info_pending(&channel_id)?;
|
||||
// Step 2: Modify the psbt and start sending with the rgb wallet
|
||||
self.prepare_rgb_tx(&info, &tx, psbt)?;
|
||||
// TODO: Step 3: Make the cosignemtn and post it somewhere
|
||||
return Ok(tx);
|
||||
}
|
||||
Ok(tx)
|
||||
}
|
||||
|
||||
// Missing parameters: amount_sat of the funding tx and
|
||||
// the script one
|
||||
//
|
||||
// Maybe it is possible extract from the tx if we know the information from
|
||||
// the tx, but not sure if this is a good usage of cln hooks?
|
||||
fn prepare_rgb_tx(
|
||||
&self,
|
||||
info: &types::RgbInfo,
|
||||
tx: &bitcoin::Transaction,
|
||||
psb: &mut PartiallySignedTransaction,
|
||||
) -> anyhow::Result<()> {
|
||||
let recipient_map = amplify::map! {
|
||||
info.contract_id.to_string() => vec![Recipient {
|
||||
recipient_data: RecipientData::WitnessData {
|
||||
script_buf: ScriptBuf::new(), // TODO: get this from the transaction
|
||||
amount_sat: 0, // TODO get this from the transaction
|
||||
blinding: Some(STATIC_BLINDING),
|
||||
},
|
||||
amount: info.local_rgb_amount,
|
||||
transport_endpoints: vec![self.proxy_endpoint.clone()]
|
||||
}]
|
||||
};
|
||||
let wallet = self.wallet();
|
||||
// FIXME: modify the psbt with the RGB information
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
//! RGB Storage interface
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::types::RgbInfo;
|
||||
|
||||
/// A common interface for an RGB Storage
|
||||
pub trait RGBStorage {
|
||||
fn new() -> anyhow::Result<Self>
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
fn get_rgb_channel_info(&self, channel_id: &str) -> anyhow::Result<RgbInfo>;
|
||||
|
||||
fn get_rgb_channel_info_pending(&self, channel_id: &str) -> anyhow::Result<RgbInfo>;
|
||||
|
||||
fn is_channel_rgb(&self, channel_id: &str, is_pending: bool) -> anyhow::Result<bool>;
|
||||
}
|
||||
|
||||
pub struct InMemoryStorage {
|
||||
inner: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl InMemoryStorage {
|
||||
fn derive_channel_db_key(&self, channel_id: &str, is_pending: bool) -> anyhow::Result<String> {
|
||||
return if is_pending {
|
||||
Ok(format!("rgb/pending/channel/{channel_id}"))
|
||||
} else {
|
||||
Ok(format!("rgb/channel/{channel_id}"))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl RGBStorage for InMemoryStorage {
|
||||
fn new() -> anyhow::Result<Self> {
|
||||
Ok(Self {
|
||||
inner: HashMap::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_rgb_channel_info(&self, channel_id: &str) -> anyhow::Result<RgbInfo> {
|
||||
let key = self.derive_channel_db_key(channel_id, false)?;
|
||||
let value = self
|
||||
.inner
|
||||
.get(&key)
|
||||
.ok_or(anyhow::anyhow!("rgb channel with key `{key}` is not found"))?;
|
||||
let info: RgbInfo = serde_json::from_str(&value)?;
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
fn get_rgb_channel_info_pending(&self, channel_id: &str) -> anyhow::Result<RgbInfo> {
|
||||
let key = self.derive_channel_db_key(channel_id, true)?;
|
||||
let value = self
|
||||
.inner
|
||||
.get(&key)
|
||||
.ok_or(anyhow::anyhow!("rgb channel with key `{key}` is not found"))?;
|
||||
let info: RgbInfo = serde_json::from_str(&value)?;
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
fn is_channel_rgb(&self, channel_id: &str, is_pending: bool) -> anyhow::Result<bool> {
|
||||
let key = self.derive_channel_db_key(channel_id, is_pending)?;
|
||||
Ok(self.inner.contains_key(&key))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
//! RGB types
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use commit_verify::mpc::MerkleBlock;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::core::{Anchor, TransitionBundle};
|
||||
use crate::std::contract::ContractId;
|
||||
|
||||
/// 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,
|
||||
/// Whether the RGB amount in route should be overridden
|
||||
pub override_route_amount: bool,
|
||||
}
|
||||
|
||||
/// RGB transfer info
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct TransferInfo {
|
||||
/// Transfer anchor
|
||||
pub anchor: Anchor<MerkleBlock>,
|
||||
/// Transfer bundles
|
||||
pub bundles: BTreeMap<ContractId, TransitionBundle>,
|
||||
/// Transfer contract ID
|
||||
pub contract_id: ContractId,
|
||||
/// Transfer RGB amount
|
||||
pub rgb_amount: u64,
|
||||
}
|
Loading…
Reference in New Issue