Skip to content
This repository has been archived by the owner on Dec 9, 2023. It is now read-only.

Allow multiple transfers by CLI #236

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 26 additions & 16 deletions cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// You should have received a copy of the MIT License along with this software.
// If not, see <https://opensource.org/licenses/MIT>.

use std::collections::BTreeSet;
use std::collections::{BTreeMap, BTreeSet};
use std::{fs, io};

use amplify::IoError;
Expand All @@ -20,7 +20,7 @@ use microservices::shell::Exec;
use psbt::Psbt;
use rgb::blank::BlankBundle;
use rgb::psbt::{RgbExt, RgbInExt};
use rgb::{Node, StateTransfer, Transition, TransitionBundle};
use rgb::{Node, SealEndpoint, StateTransfer, Transition, TransitionBundle};
use rgb_rpc::{Client, ContractValidity};
use strict_encoding::{StrictDecode, StrictEncode};

Expand Down Expand Up @@ -93,10 +93,7 @@ impl TransferCommand {
format!("Composing consignment for state transfer for contract {}", contract_id)
}
Self::Combine { .. } => s!("Preparing PSBT for the state transfer"),
Self::Finalize {
send: Some(addr), ..
} => format!("Finalizing state transfer and sending it to {}", addr),
Self::Finalize { send: None, .. } => s!("Finalizing state transfer"),
Self::Finalize { .. } => s!("Finalizing state transfers"),
Self::Consume { .. } => s!("Verifying and consuming state transfer"),
}
}
Expand Down Expand Up @@ -261,23 +258,36 @@ impl Exec for Opts {
}

TransferCommand::Finalize {
endseal,
psbt: psbt_in,
consignment_in,
consignment_out,
endseals,
send,
psbt_out,
} => {
let psbt_bytes = fs::read(&psbt_in)?;
let psbt = Psbt::deserialize(&psbt_bytes)?;
let consignment = StateTransfer::strict_file_load(&consignment_in)?;
let transfer = client.transfer(consignment, endseals, psbt, send, progress)?;

transfer
.consignment
.strict_file_save(consignment_out.unwrap_or(consignment_in))?;
let mut consig_paths = BTreeMap::new();
let transfers: Vec<(StateTransfer, Vec<SealEndpoint>)> = endseal
.into_iter()
.map(|b| -> (StateTransfer, Vec<SealEndpoint>) {
let consignment =
StateTransfer::strict_file_load(b.consignment.clone())
.expect("Valid consignment file");
consig_paths.insert(consignment.contract_id(), b.consignment);
(consignment, b.endseals)
})
.collect();

let psbt_bytes = transfer.psbt.serialize();
let transfers = client.finalize_transfers(transfers, psbt, progress)?;
for transfer in transfers.consignments {
if consig_paths.contains_key(&transfer.contract_id()) {
let path = consig_paths
.get(&transfer.contract_id())
.expect("Invalid consignment path");
let _ = transfer.strict_file_save(path);
}
}

let psbt_bytes = transfers.psbt.serialize();
fs::write(psbt_out.unwrap_or(psbt_in), psbt_bytes)?;
}

Expand Down
25 changes: 10 additions & 15 deletions cli/src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
use std::path::PathBuf;

use bitcoin::OutPoint;
use internet2::addr::{NodeAddr, ServiceAddr};
use internet2::addr::ServiceAddr;
use lnpbp::chain::Chain;
use rgb::schema::TransitionType;
use rgb::{Contract, ContractId, SealEndpoint};
use rgb_rpc::{Reveal, RGB_NODE_RPC_ENDPOINT};
use rgb::{Contract, ContractId};
use rgb_rpc::{NewTransfer, Reveal, RGB_NODE_RPC_ENDPOINT};

/// Command-line tool for working with RGB node
#[derive(Parser, Clone, PartialEq, Eq, Debug)]
Expand Down Expand Up @@ -151,14 +151,10 @@ pub enum TransferCommand {
/// (LNP Node).
#[display("finalize ...")]
Finalize {
/// Bifrost server to send state transfer to
#[clap(short, long)]
send: Option<NodeAddr>,

/// Beneficiary blinded TXO seal - or witness transaction output numbers
/// containing allocations for the beneficiary.
#[clap(short, long = "endseal", required = true)]
endseals: Vec<SealEndpoint>,
endseal: Vec<NewTransfer>,

/// The final PSBT (not modified).
psbt: PathBuf,
Expand All @@ -167,13 +163,12 @@ pub enum TransferCommand {
/// information. If not given, the source PSBT file is overwritten.
#[clap(short = 'o', long = "out")]
psbt_out: Option<PathBuf>,
// /// State transfer consignment draft file prepared with `compose` command.
// consignment_in: PathBuf,

/// State transfer consignment draft file prepared with `compose` command.
consignment_in: PathBuf,

/// Output file to save the final consignment. If not given, the source
/// consignment file is overwritten.
consignment_out: Option<PathBuf>,
// /// Output file to save the final consignment. If not given, the source
// /// consignment file is overwritten.
// consignment_out: Option<PathBuf>,
},

/// Validate incoming transfer consignment and consume it into the stash.
Expand All @@ -194,7 +189,7 @@ pub enum TransferCommand {
/// Examples:
///
/// tapret1st@<outpoint>#<blinding_factor>
/// opret1st@<outpoint>#<blinding_factor>
/// opret1st@<outpoint>#<blinding_factor>
#[clap(short, long)]
reveal: Option<Reveal>,
},
Expand Down
29 changes: 3 additions & 26 deletions rpc/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use std::thread::sleep;
use std::time::Duration;

use bitcoin::{OutPoint, Txid};
use internet2::addr::{NodeAddr, ServiceAddr};
use internet2::addr::ServiceAddr;
use internet2::ZmqSocketType;
use lnpbp::chain::Chain;
use microservices::esb::{self, BusId, ClientId};
Expand All @@ -22,10 +22,10 @@ use psbt::Psbt;
use rgb::schema::TransitionType;
use rgb::{Contract, ContractId, ContractState, ContractStateMap, SealEndpoint, StateTransfer};

use crate::messages::{FinalizeTransfersRes, HelloReq, TransferFinalize, TransfersReq};
use crate::messages::{FinalizeTransfersRes, HelloReq, TransfersReq};
use crate::{
AcceptReq, BusMsg, ComposeReq, ContractValidity, Error, FailureCode, OutpointFilter, Reveal,
RpcMsg, ServiceId, TransferReq,
RpcMsg, ServiceId,
};

// We have just a single service bus (RPC), so we can use any id
Expand Down Expand Up @@ -218,29 +218,6 @@ impl Client {
}
}

pub fn transfer(
&mut self,
consignment: StateTransfer,
endseals: Vec<SealEndpoint>,
psbt: Psbt,
beneficiary: Option<NodeAddr>,
progress: impl Fn(String),
) -> Result<TransferFinalize, Error> {
self.request(RpcMsg::Transfer(TransferReq {
consignment,
endseals,
psbt,
beneficiary,
}))?;
loop {
match self.response()?.failure_to_error()? {
RpcMsg::StateTransferFinalize(transfer) => return Ok(transfer),
RpcMsg::Progress(info) => progress(info),
_ => return Err(Error::UnexpectedServerResponse),
}
}
}

pub fn finalize_transfers(
&mut self,
transfers: Vec<(StateTransfer, Vec<SealEndpoint>)>,
Expand Down
6 changes: 3 additions & 3 deletions rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ pub mod client;
mod error;
mod messages;
mod service_id;
mod reveal;
mod structs;

pub use client::Client;
pub use error::{Error, FailureCode};
pub(crate) use messages::BusMsg;
pub use messages::{
AcceptReq, ComposeReq, ContractValidity, FinalizeTransfersRes, HelloReq, OutpointFilter,
RpcMsg, TransferFinalize, TransferReq, TransfersReq,
RpcMsg, TransfersReq,
};
pub use reveal::Reveal;
pub use service_id::ServiceId;
pub use structs::{NewTransfer, Reveal};

pub const RGB_NODE_RPC_ENDPOINT: &str = "0.0.0.0:63963";
25 changes: 0 additions & 25 deletions rpc/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use std::collections::BTreeSet;

use bitcoin::{OutPoint, Txid};
use internet2::addr::NodeAddr;
use internet2::presentation;
use lnpbp::chain::Chain;
use microservices::rpc;
Expand Down Expand Up @@ -71,9 +70,6 @@ pub enum RpcMsg {
#[display("process_disclosure({0})")]
ProcessDisclosure(Txid),

#[display(inner)]
Transfer(TransferReq),

#[display(inner)]
FinalizeTransfers(TransfersReq),

Expand All @@ -97,9 +93,6 @@ pub enum RpcMsg {
#[display("state_transfer(...)")]
StateTransfer(StateTransfer),

#[display("state_transfer_finalize(...)")]
StateTransferFinalize(TransferFinalize),

#[display("state_transfer_finalize(...)")]
FinalizedTransfers(FinalizeTransfersRes),

Expand Down Expand Up @@ -190,24 +183,6 @@ pub struct ComposeReq {
pub outpoints: OutpointFilter,
}

#[derive(Clone, PartialEq, Eq, Debug, Display)]
#[derive(NetworkEncode, NetworkDecode)]
#[display("transfer(...)")]
pub struct TransferReq {
pub consignment: StateTransfer,
pub endseals: Vec<SealEndpoint>,
pub psbt: Psbt,
pub beneficiary: Option<NodeAddr>,
}

#[derive(Clone, PartialEq, Eq, Debug, Display)]
#[derive(NetworkEncode, NetworkDecode)]
#[display("transfer_complete(...)")]
pub struct TransferFinalize {
pub consignment: StateTransfer,
pub psbt: Psbt,
}

#[derive(Clone, PartialEq, Eq, Debug, Display)]
#[derive(NetworkEncode, NetworkDecode)]
#[display("transfers_req(...)")]
Expand Down
82 changes: 82 additions & 0 deletions rpc/src/reveal.rs → rpc/src/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use bitcoin::OutPoint;
use bp::seals::txout::CloseMethod;
use rgb::SealEndpoint;

#[derive(From, PartialEq, Eq, Debug, Clone, StrictEncode, StrictDecode)]
pub struct Reveal {
Expand Down Expand Up @@ -115,3 +116,84 @@ impl ::std::error::Error for ParseRevealError {
}
}
}

#[derive(From, PartialEq, Eq, Debug, Clone, StrictEncode, StrictDecode)]
pub struct NewTransfer {
/// Beneficiary blinded TXO seal - or witness transaction output numbers
/// containing allocations for the beneficiary.
pub endseals: Vec<SealEndpoint>,

/// State transfer consignment draft file prepared with `compose` command.
pub consignment: String,
}

/// An error in parsing an OutPoint.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ParseNewTransferError {
/// Error in seal endpoint part.
SealEndpoint,
/// Error in consignment part.
Consignment,
/// Error in general format.
Format,
}

impl std::fmt::Display for ParseNewTransferError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
ParseNewTransferError::SealEndpoint => write!(f, "error parsing SealEndpoint"),
ParseNewTransferError::Consignment => write!(f, "error parsing Consignment"),
ParseNewTransferError::Format => todo!(),
}
}
}

impl std::fmt::Display for NewTransfer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let endseals: Vec<String> =
self.endseals.clone().into_iter().map(|e| e.to_string()).collect();
let endseals = endseals.join(",");
write!(f, "{}:{}", endseals, self.consignment)
}
}

impl ::core::str::FromStr for NewTransfer {
type Err = ParseNewTransferError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let find_consig = s.find(':');
let index_consig = match find_consig {
Some(index) => index,
_ => return Err(ParseNewTransferError::Format),
};

println!("{}", "passou aqui");
if index_consig == 0 || index_consig == s.len() - 1 {
return Err(ParseNewTransferError::Format);
}

let find_endseals = s.find(',');
let endseals = match find_endseals {
Some(_) => s[..index_consig]
.split(',')
.into_iter()
.map(|e| SealEndpoint::from_str(e).expect("Error in SealEndpoint part"))
.collect(),
_ => {
vec![SealEndpoint::from_str(&s[..index_consig]).expect("Error in SealEndpoint part")]
}
};

Ok(NewTransfer {
endseals,
consignment: match String::try_from(&s[index_consig + 1..]) {
Ok(it) => it,
Err(_) => return Err(ParseNewTransferError::Consignment),
},
})
}
}

impl ::std::error::Error for ParseNewTransferError {
fn cause(&self) -> Option<&dyn ::std::error::Error> { None }
}
8 changes: 2 additions & 6 deletions shell/_rgb-cli
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,8 @@ _arguments "${_arguments_options[@]}" \
;;
(finalize)
_arguments "${_arguments_options[@]}" \
'-s+[Bifrost server to send state transfer to]:SEND: ' \
'--send=[Bifrost server to send state transfer to]:SEND: ' \
'*-e+[Beneficiary blinded TXO seal - or witness transaction output numbers containing allocations for the beneficiary]:ENDSEALS: ' \
'*--endseal=[Beneficiary blinded TXO seal - or witness transaction output numbers containing allocations for the beneficiary]:ENDSEALS: ' \
'*-e+[Beneficiary blinded TXO seal - or witness transaction output numbers containing allocations for the beneficiary]:ENDSEAL: ' \
'*--endseal=[Beneficiary blinded TXO seal - or witness transaction output numbers containing allocations for the beneficiary]:ENDSEAL: ' \
'-o+[Output file to save the PSBT updated with state transition(s) information. If not given, the source PSBT file is overwritten]:PSBT_OUT: ' \
'--out=[Output file to save the PSBT updated with state transition(s) information. If not given, the source PSBT file is overwritten]:PSBT_OUT: ' \
'-R+[ZMQ socket for connecting daemon RPC interface]:CONNECT: ' \
Expand All @@ -262,8 +260,6 @@ _arguments "${_arguments_options[@]}" \
'*-v[Set verbosity level]' \
'*--verbose[Set verbosity level]' \
':psbt -- The final PSBT (not modified):' \
':consignment-in -- State transfer consignment draft file prepared with `compose` command:' \
'::consignment-out -- Output file to save the final consignment. If not given, the source consignment file is overwritten:' \
&& ret=0
;;
(consume)
Expand Down
2 changes: 0 additions & 2 deletions shell/_rgb-cli.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,6 @@ Register-ArgumentCompleter -Native -CommandName 'rgb-cli' -ScriptBlock {
break
}
'rgb-cli;transfer;finalize' {
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Bifrost server to send state transfer to')
[CompletionResult]::new('--send', 'send', [CompletionResultType]::ParameterName, 'Bifrost server to send state transfer to')
[CompletionResult]::new('-e', 'e', [CompletionResultType]::ParameterName, 'Beneficiary blinded TXO seal - or witness transaction output numbers containing allocations for the beneficiary')
[CompletionResult]::new('--endseal', 'endseal', [CompletionResultType]::ParameterName, 'Beneficiary blinded TXO seal - or witness transaction output numbers containing allocations for the beneficiary')
[CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'Output file to save the PSBT updated with state transition(s) information. If not given, the source PSBT file is overwritten')
Expand Down
Loading