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

Commit

Permalink
allow many transfers by cli
Browse files Browse the repository at this point in the history
  • Loading branch information
crisdut committed Jan 9, 2023
1 parent 770ce83 commit e26532c
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 201 deletions.
40 changes: 25 additions & 15 deletions cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use psbt::Psbt;
use rgb::blank::BlankBundle;
use rgb::psbt::{RgbExt, RgbInExt};
use rgb::{Node, StateTransfer, Transition, TransitionBundle};
use rgb_rpc::{Client, ContractValidity};
use rgb_rpc::{Client, ContractValidity, NewTransfer, TransferReqs};
use strict_encoding::{StrictDecode, StrictEncode};

use crate::opts::{ContractCommand, OutpointCommand, TransferCommand};
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 transfer"),
Self::Consume { .. } => s!("Verifying and consuming state transfer"),
}
}
Expand Down Expand Up @@ -240,8 +237,9 @@ impl Exec for Opts {
let outpoints: BTreeSet<_> =
psbt.inputs.iter().map(|input| input.previous_outpoint).collect();
let state_map = client.outpoint_state(outpoints, progress)?;
let contract_ids = state_map.clone().into_keys().collect::<Vec<_>>();
for (cid, outpoint_map) in state_map {
if cid == contract_id {
if contract_ids.contains(&cid) {
continue;
}
let contract = client.contract(cid, vec![], progress)?;
Expand All @@ -262,20 +260,32 @@ impl Exec for Opts {

TransferCommand::Finalize {
psbt: psbt_in,
consignment_in,
consignment_out,
endseals,
send,
beneficiaries,
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 endseals = beneficiaries
.into_iter()
.map(|b| -> NewTransfer {
let consignment =
StateTransfer::strict_file_load(b.consignment.clone()).expect("");
NewTransfer {
consignment,
consignment_out: b.consignment,
endseals: vec![b.endseal],
}
})
.collect();

let request = TransferReqs { psbt, endseals };

let transfer = client.transfer(request, progress)?;

for transfer in transfer.transfers {
transfer.consignment.strict_file_save(transfer.consignment_out)?;
}

let psbt_bytes = transfer.psbt.serialize();
fs::write(psbt_out.unwrap_or(psbt_in), psbt_bytes)?;
Expand Down
21 changes: 5 additions & 16 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::{Beneficiary, 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>,
beneficiaries: Vec<Beneficiary>,

/// The final PSBT (not modified).
psbt: PathBuf,
Expand All @@ -167,13 +163,6 @@ 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,

/// 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 +183,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
20 changes: 7 additions & 13 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,12 @@ 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, TransferFinalize, TransferReqs, 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 @@ -220,18 +222,10 @@ impl Client {

pub fn transfer(
&mut self,
consignment: StateTransfer,
endseals: Vec<SealEndpoint>,
psbt: Psbt,
beneficiary: Option<NodeAddr>,
request: TransferReqs,
progress: impl Fn(String),
) -> Result<TransferFinalize, Error> {
self.request(RpcMsg::Transfer(TransferReq {
consignment,
endseals,
psbt,
beneficiary,
}))?;
self.request(RpcMsg::Transfer(request))?;
loop {
match self.response()?.failure_to_error()? {
RpcMsg::StateTransferFinalize(transfer) => return Ok(transfer),
Expand Down
8 changes: 4 additions & 4 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,
AcceptReq, ComposeReq, ContractValidity, FinalizeTransfersRes, HelloReq, NewTransfer,
OutpointFilter, RpcMsg, TransferFinalize, TransferReqs, TransferRes, TransfersReq,
};
pub use reveal::Reveal;
pub use service_id::ServiceId;
pub use structs::{Beneficiary, Reveal};

pub const RGB_NODE_RPC_ENDPOINT: &str = "0.0.0.0:63963";
24 changes: 19 additions & 5 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 @@ -72,7 +71,7 @@ pub enum RpcMsg {
ProcessDisclosure(Txid),

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

#[display(inner)]
FinalizeTransfers(TransfersReq),
Expand Down Expand Up @@ -193,21 +192,36 @@ pub struct ComposeReq {
#[derive(Clone, PartialEq, Eq, Debug, Display)]
#[derive(NetworkEncode, NetworkDecode)]
#[display("transfer(...)")]
pub struct TransferReq {
pub struct NewTransfer {
pub consignment: StateTransfer,
pub consignment_out: String,
pub endseals: Vec<SealEndpoint>,
}

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

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

#[derive(Clone, PartialEq, Eq, Debug, Display)]
#[derive(NetworkEncode, NetworkDecode)]
#[display("transfer_response(...)")]
pub struct TransferRes {
pub consignment: StateTransfer,
pub consignment_out: String,
}

#[derive(Clone, PartialEq, Eq, Debug, Display)]
#[derive(NetworkEncode, NetworkDecode)]
#[display("transfers_req(...)")]
Expand Down
77 changes: 77 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,79 @@ impl ::std::error::Error for ParseRevealError {
}
}
}

#[derive(From, PartialEq, Eq, Debug, Clone, StrictEncode, StrictDecode)]
pub struct Beneficiary {
/// Beneficiary blinded TXO seal - or witness transaction output numbers
/// containing allocations for the beneficiary.
pub endseal: 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 ParseBeneficiaryError {
/// Error in seal endpoint part.
SealEndpoint,
/// Error in consignment part.
Consignment,
/// Error in general format.
Format,
/// Size exceeds max.
TooLong,
}

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

impl std::fmt::Display for Beneficiary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.endseal, self.consignment)
}
}

impl ::core::str::FromStr for Beneficiary {
type Err = ParseBeneficiaryError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let find_endseal = s.find(':');
if find_endseal.is_none() {
return Err(ParseBeneficiaryError::Format);
}

let colon_endseal = find_endseal.unwrap();
if colon_endseal == 0 || colon_endseal == s.len() - 1 {
return Err(ParseBeneficiaryError::Format);
}

let colon_endseal = find_endseal.unwrap();
if colon_endseal == 0 || colon_endseal == s.len() - 1 {
return Err(ParseBeneficiaryError::Format);
}

Ok(Beneficiary {
endseal: match SealEndpoint::from_str(&s[..colon_endseal]) {
Ok(it) => it,
Err(_) => return Err(ParseBeneficiaryError::SealEndpoint),
},
consignment: match String::try_from(&s[colon_endseal + 1..]) {
Ok(it) => it,
Err(_) => return Err(ParseBeneficiaryError::Consignment),
},
})
}
}

impl ::std::error::Error for ParseBeneficiaryError {
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: ' \
'*-b+[Beneficiary blinded TXO seal - or witness transaction output numbers containing allocations for the beneficiary]:BENEFICIARIES: ' \
'*--endseal=[Beneficiary blinded TXO seal - or witness transaction output numbers containing allocations for the beneficiary]:BENEFICIARIES: ' \
'-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
4 changes: 1 addition & 3 deletions shell/_rgb-cli.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,7 @@ 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('-b', 'b', [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')
[CompletionResult]::new('--out', 'out', [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
12 changes: 2 additions & 10 deletions shell/rgb-cli.bash
Original file line number Diff line number Diff line change
Expand Up @@ -594,25 +594,17 @@ _rgb-cli() {
return 0
;;
rgb__cli__transfer__finalize)
opts="-s -e -o -h -R -n -v --send --endseal --out --help --rpc --chain --verbose <PSBT> <CONSIGNMENT_IN> <CONSIGNMENT_OUT>"
opts="-b -o -h -R -n -v --endseal --out --help --rpc --chain --verbose <PSBT>"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
--send)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-s)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--endseal)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
-e)
-b)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
Expand Down
Loading

0 comments on commit e26532c

Please sign in to comment.