From e9b30a4f1ec7ea2333ab321ca729e3636d88ef41 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Thu, 5 Nov 2020 16:33:41 +0100 Subject: [PATCH] WIP on Transfers --- contrib/demo.sh | 15 +++++++ shell/_lnp-cli | 4 +- shell/_lnp-cli.ps1 | 2 + shell/lnp-cli.bash | 10 ++++- src/channeld/runtime.rs | 93 +++++++++++++++++++++++++++++++++-------- src/cli/command.rs | 16 +++++++ src/cli/opts.rs | 8 +++- src/peerd/runtime.rs | 2 - 8 files changed, 126 insertions(+), 24 deletions(-) create mode 100755 contrib/demo.sh diff --git a/contrib/demo.sh b/contrib/demo.sh new file mode 100755 index 0000000..e8e0ebd --- /dev/null +++ b/contrib/demo.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +./target/debug/lnp-cli -d /tmp listen + +./target/debug/lnp-cli connect 0275a326e4416600cea2601696e4ae03b239e717e87a290a00dbc1ba4f6df28290@127.0.0.1 + +./target/debug/lnp-cli propose 0275a326e4416600cea2601696e4ae03b239e717e87a290a00dbc1ba4f6df28290@127.0.0.1 1000 + +./target/debug/lnp-cli info + +echo -n "Temp. channel id: " +read tchid + +./target/debug/lnp-cli fund "$tchid" 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0 + diff --git a/shell/_lnp-cli b/shell/_lnp-cli index ed2bdf0..5bf9be5 100644 --- a/shell/_lnp-cli +++ b/shell/_lnp-cli @@ -259,6 +259,8 @@ _arguments "${_arguments_options[@]}" \ ;; (transfer) _arguments "${_arguments_options[@]}" \ +'-a+[Asset ticker in which the invoice should be issued]' \ +'--asset=[Asset ticker in which the invoice should be issued]' \ '-d+[Data directory path]: :_files -/' \ '--data-dir=[Data directory path]: :_files -/' \ '-c+[Path to the configuration file]: :_files' \ @@ -277,8 +279,8 @@ _arguments "${_arguments_options[@]}" \ '--help[Prints help information]' \ '-V[Prints version information]' \ '--version[Prints version information]' \ +':channel -- Channel to which the funding must be added:' \ ':amount -- Asset amount to invoice, in atomic unit (satoshis or smallest asset unit type):' \ -'::asset -- Asset ticker in which the invoice should be issued:' \ && ret=0 ;; (invoice) diff --git a/shell/_lnp-cli.ps1 b/shell/_lnp-cli.ps1 index eb0b2e4..4ec345f 100644 --- a/shell/_lnp-cli.ps1 +++ b/shell/_lnp-cli.ps1 @@ -249,6 +249,8 @@ Register-ArgumentCompleter -Native -CommandName 'lnp-cli' -ScriptBlock { break } 'lnp-cli;transfer' { + [CompletionResult]::new('-a', 'a', [CompletionResultType]::ParameterName, 'Asset ticker in which the invoice should be issued') + [CompletionResult]::new('--asset', 'asset', [CompletionResultType]::ParameterName, 'Asset ticker in which the invoice should be issued') [CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Data directory path') [CompletionResult]::new('--data-dir', 'data-dir', [CompletionResultType]::ParameterName, 'Data directory path') [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Path to the configuration file') diff --git a/shell/lnp-cli.bash b/shell/lnp-cli.bash index 8abc392..bacb067 100644 --- a/shell/lnp-cli.bash +++ b/shell/lnp-cli.bash @@ -855,13 +855,21 @@ _lnp-cli() { return 0 ;; lnp__cli__transfer) - opts=" -d -c -v -T -m -x -n -h -V --data-dir --config --verbose --tor-proxy --msg-socket --ctl-socket --chain --help --version " + opts=" -a -d -c -v -T -m -x -n -h -V --asset --data-dir --config --verbose --tor-proxy --msg-socket --ctl-socket --chain --help --version " if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in + --asset) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -a) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --data-dir) COMPREPLY=($(compgen -f "${cur}")) return 0 diff --git a/src/channeld/runtime.rs b/src/channeld/runtime.rs index ae752a9..5f5633d 100644 --- a/src/channeld/runtime.rs +++ b/src/channeld/runtime.rs @@ -77,7 +77,6 @@ pub fn run( remote_keys: dumb!(), offered_htlc: empty!(), received_htlc: empty!(), - resolved_htlc: empty!(), is_originator: false, obscuring_factor: 0, enquirer: None, @@ -119,7 +118,6 @@ pub struct Runtime { offered_htlc: Vec, received_htlc: Vec, - resolved_htlc: Vec, is_originator: bool, obscuring_factor: u64, @@ -284,7 +282,7 @@ impl Runtime { let _ = self.report_progress_to(senders, &enquirer, msg); } - Request::PeerMessage(Messages::FundingSigned(funding_signed)) => { + Request::PeerMessage(Messages::FundingSigned(_funding_signed)) => { // TODO: // 1. Get commitment tx // 2. Verify signature @@ -314,9 +312,10 @@ impl Runtime { self.send_peer( senders, Messages::FundingLocked(funding_locked), - ); + )?; self.state = Lifecycle::Active; + self.local_capacity = self.params.funding_satoshis; // Ignoring possible error here: do not want to // halt the channel just because the client disconnected @@ -350,18 +349,19 @@ impl Runtime { } Request::PeerMessage(Messages::UpdateAddHtlc(update_add_htlc)) => { - let commitment_signed = + let _commitment_signed = self.htlc_receive(senders, update_add_htlc)?; } Request::PeerMessage(Messages::CommitmentSigned( - commitment_signed, + _commitment_signed, )) => {} - Request::PeerMessage(Messages::RevokeAndAck(revoke_ack)) => {} + Request::PeerMessage(Messages::RevokeAndAck(_revoke_ack)) => {} Request::PeerMessage(Messages::AssignFunds(assign_req)) => { self.refill( + senders, assign_req.consignment, assign_req.outpoint, assign_req.blinding, @@ -458,6 +458,7 @@ impl Runtime { self.enquirer = source.into(); self.refill( + senders, refill_req.consignment.clone(), refill_req.outpoint, refill_req.blinding, @@ -808,8 +809,6 @@ impl Runtime { &mut self, senders: &mut Senders, ) -> Result<(), Error> { - let enquirer = self.enquirer.clone(); - let mut engine = sha256::Hash::engine(); if self.is_originator { engine.input(&self.local_keys.payment_basepoint.serialize()); @@ -877,6 +876,18 @@ impl Runtime { ) -> Result { let enquirer = self.enquirer.clone(); + let available = if let Some(asset_id) = transfer_req.asset { + self.local_balances.get(&asset_id).copied().unwrap_or(0) + } else { + self.local_capacity + }; + + if available < transfer_req.amount { + Err(Error::Other(s!( + "You do not have required amount of the asset" + )))? + } + info!( "{} {} {} to the remote peer", "Transferring".promo(), @@ -909,11 +920,22 @@ impl Runtime { asset_id: transfer_req.asset, }; self.total_payments += 1; + match transfer_req.asset { + Some(asset_id) => { + self.local_balances.get_mut(&asset_id).map(|balance| { + *balance -= transfer_req.amount; + }); + + let entry = self.remote_balances.entry(asset_id).or_insert(0); + *entry += transfer_req.amount; + } + None => { + self.local_capacity -= transfer_req.amount; + self.remote_capacity += transfer_req.amount; + } + } - let msg = format!( - "{}, awaiting for peer signature", - "Funding transferred".ended() - ); + let msg = format!("{}", "Funding transferred".ended()); info!("{}", msg); let _ = self.report_progress_to(senders, &enquirer, msg); @@ -922,10 +944,13 @@ impl Runtime { pub fn refill( &mut self, + senders: &mut Senders, consignment: Consignment, outpoint: OutPoint, blinding: u64, ) -> Result<(), Error> { + let enquirer = self.enquirer.clone(); + debug!("Validating consignment with RGB Node ..."); self.request_rbg20(rgb_node::api::fungible::Request::Validate( consignment.clone(), @@ -951,21 +976,38 @@ impl Runtime { for (id, balances) in balances { let asset_id = AssetId::from(id); let balance: u64 = balances.into_iter().sum(); - debug!("Adding {} of {} to balance", balance, asset_id); + info!( + "{} {} of {} to balance", + "Adding".promo(), + balance.promoter(), + asset_id.promoter() + ); + let msg = format!( + "adding {} of {} to balance", + balance.ender(), + asset_id.ender() + ); + let _ = self.report_progress_to(senders, &enquirer, msg); + self.local_balances.insert(asset_id, balance); } } _ => Err(Error::Other(s!("Unrecognized RGB Node response")))?, } + let _ = self.report_success_to( + senders, + &enquirer, + Some("transfer completed"), + ); Ok(()) } pub fn htlc_receive( &mut self, - senders: &mut Senders, + _senders: &mut Senders, update_add_htlc: message::UpdateAddHtlc, - ) -> Result { + ) -> Result { trace!("Updating HTLCs with {:?}", update_add_htlc); // TODO: Use From/To for message <-> Htlc conversion in LNP/BP // Core lib @@ -977,13 +1019,28 @@ impl Runtime { }; self.received_htlc.push(htlc); + match update_add_htlc.asset_id { + Some(asset_id) => { + self.remote_balances.get_mut(&asset_id).map(|balance| { + *balance -= update_add_htlc.amount_msat; + }); + + let entry = self.local_balances.entry(asset_id).or_insert(0); + *entry += update_add_htlc.amount_msat; + } + None => { + self.remote_capacity -= update_add_htlc.amount_msat; + self.local_capacity += update_add_htlc.amount_msat; + } + } + + Ok(()) + // TODO: // 1. Generate new commitment tx // 2. Generate new transitions and anchor, commit into tx // 3. Sign commitment tx // 4. Generate HTLCs, tweak etc each of them // 3. Send response - - unimplemented!() } } diff --git a/src/cli/command.rs b/src/cli/command.rs index aca46c7..298c58b 100644 --- a/src/cli/command.rs +++ b/src/cli/command.rs @@ -180,6 +180,22 @@ impl Exec for Command { runtime.report_progress()?; } + Command::Transfer { + channel, + amount, + asset, + } => { + runtime.request( + channel.clone().into(), + Request::Transfer(request::Transfer { + channeld: channel.clone().into(), + amount: *amount, + asset: asset.map(|id| id.into()), + }), + )?; + runtime.report_progress()?; + } + Command::Refill { channel, consignment, diff --git a/src/cli/opts.rs b/src/cli/opts.rs index c5b8a8e..8cad4fb 100644 --- a/src/cli/opts.rs +++ b/src/cli/opts.rs @@ -19,6 +19,7 @@ use std::str::FromStr; use lnpbp::bitcoin::OutPoint; use lnpbp::lnp::{ChannelId, FramingProtocol, PartialNodeAddr, TempChannelId}; +use lnpbp::rgb::ContractId; /// Command-line tool for working with LNP node #[derive(Clap, Clone, PartialEq, Eq, Debug)] @@ -151,13 +152,16 @@ pub enum Command { /// Do an invoiceless direct payment Transfer { + /// Channel to which the funding must be added + channel: ChannelId, + /// Asset amount to invoice, in atomic unit (satoshis or smallest asset /// unit type) amount: u64, /// Asset ticker in which the invoice should be issued - #[clap(default_value = "btc")] - asset: String, + #[clap(short, long)] + asset: Option, }, /// Create an invoice diff --git a/src/peerd/runtime.rs b/src/peerd/runtime.rs index ea9a755..118bc15 100644 --- a/src/peerd/runtime.rs +++ b/src/peerd/runtime.rs @@ -31,8 +31,6 @@ use lnpbp_services::peer; use crate::rpc::{request::PeerInfo, Request, ServiceBus}; use crate::{Config, CtlServer, Error, LogStyle, Service, ServiceId}; -pub struct MessageFilter {} - pub fn run( config: Config, connection: PeerConnection,