Skip to content

Commit

Permalink
add wallet unpack command (#433)
Browse files Browse the repository at this point in the history
  • Loading branch information
yeastplume authored Jun 11, 2020
1 parent f71e7c1 commit 5e20f5f
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 30 deletions.
12 changes: 9 additions & 3 deletions api/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2123,6 +2123,7 @@ where
///
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using
/// * `slatepack` - A string representing an armored slatepack
/// * `decrypt` - If true and the slatepack message content is encrypted, attempt to decrypt
///
/// # Returns
/// * Ok with a [Slatepack](../grin_wallet_libwallet/slatepack/types/struct.Slatepack.html) if successful
Expand All @@ -2142,13 +2143,18 @@ where
/// # let slatepack_string = String::from("");
/// // .. receive a slatepack from somewhere
/// let res = api_owner.decode_slatepack_message(
/// slatepack_string
/// slatepack_string,
/// false,
/// );
///
/// ```
pub fn decode_slatepack_message(&self, slatepack: String) -> Result<Slatepack, Error> {
owner::decode_slatepack_message(slatepack)
pub fn decode_slatepack_message(
&self,
slatepack: String,
decrypt: bool,
) -> Result<Slatepack, Error> {
owner::decode_slatepack_message(slatepack, decrypt)
}

// PAYMENT PROOFS
Expand Down
17 changes: 13 additions & 4 deletions api/src/owner_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1577,7 +1577,8 @@ pub trait OwnerRpc {
"jsonrpc": "2.0",
"method": "decode_slatepack_message",
"params": {
"message": "BEGINSLATEPACK. 8GQrdcwdLKJD28F 3a9siP7ZhZgAh7w\nBR2EiZHza5WMWmZ Cc8zBUemrrYRjhq j3VBwA8vYnvXXKU\nBDmQBN2yKgmR8mX UzvXHezfznA61d7 qFZYChhz94vd8Ew\nNEPLz7jmcVN2C3w wrfHbeiLubYozP2 uhLouFiYRrbe3fQ\n4uhWGfT3sQYXScT dAeo29EaZJpfauh j8VL5jsxST2SPHq\nnzXFC2w9yYVjt7D ju7GSgHEp5aHz9R xstGbHjbsb4JQod\nkYLuELta1ohUwDD pvjhyJmsbLcsPei k5AQhZsJ8RJGBtY\nbou6cU7tZeFJvor 4LB9CBfFB3pmVWD vSLd5RPS75dcnHP\nnbXD8mSDZ8hJS2Q A9wgvppWzuWztJ2 dLUU8f9tLJgsRBw\nYZAs71HiVeg7. ENDSLATEPACK.\n"
"message": "BEGINSLATEPACK. 8GQrdcwdLKJD28F 3a9siP7ZhZgAh7w\nBR2EiZHza5WMWmZ Cc8zBUemrrYRjhq j3VBwA8vYnvXXKU\nBDmQBN2yKgmR8mX UzvXHezfznA61d7 qFZYChhz94vd8Ew\nNEPLz7jmcVN2C3w wrfHbeiLubYozP2 uhLouFiYRrbe3fQ\n4uhWGfT3sQYXScT dAeo29EaZJpfauh j8VL5jsxST2SPHq\nnzXFC2w9yYVjt7D ju7GSgHEp5aHz9R xstGbHjbsb4JQod\nkYLuELta1ohUwDD pvjhyJmsbLcsPei k5AQhZsJ8RJGBtY\nbou6cU7tZeFJvor 4LB9CBfFB3pmVWD vSLd5RPS75dcnHP\nnbXD8mSDZ8hJS2Q A9wgvppWzuWztJ2 dLUU8f9tLJgsRBw\nYZAs71HiVeg7. ENDSLATEPACK.\n",
"decrypt" : false
},
"id": 1
}
Expand All @@ -1601,7 +1602,11 @@ pub trait OwnerRpc {
```
*/

fn decode_slatepack_message(&self, message: String) -> Result<Slatepack, ErrorKind>;
fn decode_slatepack_message(
&self,
message: String,
decrypt: bool,
) -> Result<Slatepack, ErrorKind>;

/**
Networked version of [Owner::retrieve_payment_proof](struct.Owner.html#method.retrieve_payment_proof).
Expand Down Expand Up @@ -2069,8 +2074,12 @@ where
Ok(VersionedSlate::into_version(slate, version).map_err(|e| e.kind())?)
}

fn decode_slatepack_message(&self, message: String) -> Result<Slatepack, ErrorKind> {
Owner::decode_slatepack_message(self, message).map_err(|e| e.kind())
fn decode_slatepack_message(
&self,
message: String,
decrypt: bool,
) -> Result<Slatepack, ErrorKind> {
Owner::decode_slatepack_message(self, message, decrypt).map_err(|e| e.kind())
}

fn retrieve_payment_proof(
Expand Down
84 changes: 81 additions & 3 deletions controller/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::impls::SlateGetter as _;
use crate::impls::{HttpSlateSender, PathToSlate, PathToSlatepack, SlatePutter};
use crate::keychain;
use crate::libwallet::{
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, Slate, SlateVersion,
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, Slate, SlateVersion, Slatepack,
SlatepackAddress, Slatepacker, SlatepackerArgs, WalletLCProvider,
};
use crate::util::secp::key::SecretKey;
Expand Down Expand Up @@ -603,7 +603,7 @@ where
});
let pts = PathToSlatepack::new(f.into(), &packer, true);
sl = Some(pts.get_tx()?.0);
ret_address = pts.get_slatepack()?.sender;
ret_address = pts.get_slatepack(true)?.sender;
Ok(())
})?;
}
Expand All @@ -626,7 +626,7 @@ where
|api, m| {
slate =
api.slate_from_slatepack_message(m, message.clone(), vec![0])?;
let slatepack = api.decode_slatepack_message(message)?;
let slatepack = api.decode_slatepack_message(message, true)?;
ret_address = slatepack.sender;
Ok(())
},
Expand Down Expand Up @@ -713,6 +713,84 @@ where
}
}

pub fn unpack<L, C, K>(
owner_api: &mut Owner<L, C, K>,
keychain_mask: Option<&SecretKey>,
args: ReceiveArgs,
) -> Result<(), Error>
where
L: WalletLCProvider<'static, C, K> + 'static,
C: NodeClient + 'static,
K: keychain::Keychain + 'static,
{
let mut slatepack = match args.input_file {
Some(f) => {
let packer = Slatepacker::new(SlatepackerArgs {
sender: None,
recipients: vec![],
dec_key: None,
});
PathToSlatepack::new(f.into(), &packer, true).get_slatepack(false)?
}
None => match args.input_slatepack_message {
Some(mes) => {
let mut sp = Slatepack::default();
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, _| {
sp = api.decode_slatepack_message(mes, false)?;
Ok(())
})?;
sp
}
None => {
return Err(ErrorKind::ArgumentError("Invalid Slatepack Input".into()).into());
}
},
};
println!();
println!("SLATEPACK CONTENTS");
println!("------------------");
println!("{}", slatepack);
println!("------------------");

let packer = Slatepacker::new(SlatepackerArgs {
sender: None,
recipients: vec![],
dec_key: None,
});

if slatepack.mode == 1 {
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let dec_key = api.get_slatepack_secret_key(m, 0)?;
match slatepack.try_decrypt_payload(Some(&dec_key)) {
Ok(_) => {
println!("Slatepack is encrypted for this wallet");
println!();
println!("DECRYPTED SLATEPACK");
println!("-------------------");
println!("{}", slatepack);
let slate = packer.get_slate(&slatepack)?;
println!();
println!("DECRYPTED SLATE");
println!("---------------");
println!("{}", slate);
}
Err(_) => {
println!("Slatepack payload cannot be decrypted by this wallet");
}
}
Ok(())
})?;
} else {
let slate = packer.get_slate(&slatepack)?;
println!("Slatepack is not encrypted");
println!();
println!("SLATE");
println!("-----");
println!("{}", slate);
}
Ok(())
}

/// Finalize command args
#[derive(Clone)]
pub struct FinalizeArgs {
Expand Down
4 changes: 2 additions & 2 deletions controller/tests/slatepack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ fn slate_from_packed(
if armored {
file = format!("{}.armored", file);
}
let slatepack = PathToSlatepack::new(file.into(), &packer, armored).get_slatepack()?;
let slatepack = PathToSlatepack::new(file.into(), &packer, armored).get_slatepack(true)?;
Ok((slatepack.clone(), packer.get_slate(&slatepack)?))
}

Expand Down Expand Up @@ -496,7 +496,7 @@ fn slatepack_api_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
let enc_addr = api.get_slatepack_address(m, 0)?;
let slatepack = api.create_slatepack_message(m, &slate, Some(0), vec![enc_addr])?;
println!("{}", slatepack);
let slatepack_raw = api.decode_slatepack_message(slatepack.clone())?;
let slatepack_raw = api.decode_slatepack_message(slatepack.clone(), true)?;
println!("{}", slatepack_raw);
let decoded_slate = api.slate_from_slatepack_message(m, slatepack, vec![0])?;
println!("{}", decoded_slate);
Expand Down
6 changes: 3 additions & 3 deletions impls/src/adapters/slatepack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ impl<'a> PathToSlatepack<'a> {
Ok(data)
}

pub fn get_slatepack(&self) -> Result<Slatepack, Error> {
pub fn get_slatepack(&self, decrypt: bool) -> Result<Slatepack, Error> {
let data = self.get_slatepack_file_contents()?;
self.packer.deser_slatepack(data)
self.packer.deser_slatepack(data, decrypt)
}
}

Expand Down Expand Up @@ -80,7 +80,7 @@ impl<'a> SlatePutter for PathToSlatepack<'a> {
impl<'a> SlateGetter for PathToSlatepack<'a> {
fn get_tx(&self) -> Result<(Slate, bool), Error> {
let data = self.get_slatepack_file_contents()?;
let slatepack = self.packer.deser_slatepack(data)?;
let slatepack = self.packer.deser_slatepack(data, true)?;
Ok((self.packer.get_slate(&slatepack)?, true))
}
}
8 changes: 4 additions & 4 deletions libwallet/src/api_impl/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ where
recipients: vec![],
dec_key: None,
});
let slatepack = packer.deser_slatepack(slatepack.as_bytes().to_vec())?;
let slatepack = packer.deser_slatepack(slatepack.as_bytes().to_vec(), true)?;
return packer.get_slate(&slatepack);
} else {
for index in secret_indices {
Expand All @@ -183,7 +183,7 @@ where
recipients: vec![],
dec_key: (&dec_key).as_ref(),
});
let res = packer.deser_slatepack(slatepack.as_bytes().to_vec());
let res = packer.deser_slatepack(slatepack.as_bytes().to_vec(), true);
let slatepack = match res {
Ok(sp) => sp,
Err(_) => {
Expand All @@ -201,13 +201,13 @@ where
}

/// Decode a slatepack message, to allow viewing
pub fn decode_slatepack_message(slatepack: String) -> Result<Slatepack, Error> {
pub fn decode_slatepack_message(slatepack: String, decrypt: bool) -> Result<Slatepack, Error> {
let packer = Slatepacker::new(SlatepackerArgs {
sender: None,
recipients: vec![],
dec_key: None,
});
packer.deser_slatepack(slatepack.as_bytes().to_vec())
packer.deser_slatepack(slatepack.as_bytes().to_vec(), decrypt)
}

/// retrieve outputs
Expand Down
6 changes: 4 additions & 2 deletions libwallet/src/slatepack/packer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl<'a> Slatepacker<'a> {
}

/// return slatepack
pub fn deser_slatepack(&self, data: Vec<u8>) -> Result<Slatepack, Error> {
pub fn deser_slatepack(&self, data: Vec<u8>, decrypt: bool) -> Result<Slatepack, Error> {
// check if data is armored, if so, remove and continue
if data.len() < super::armor::HEADER.len() {
let msg = format!("Data too short");
Expand Down Expand Up @@ -90,7 +90,9 @@ impl<'a> Slatepacker<'a> {
};

slatepack.ver_check_warn();
slatepack.try_decrypt_payload(self.0.dec_key)?;
if decrypt {
slatepack.try_decrypt_payload(self.0.dec_key)?;
}
Ok(slatepack)
}

Expand Down
26 changes: 17 additions & 9 deletions src/bin/grin-wallet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ subcommands:
long: run_foreign
takes_value: false
- send:
about: Builds a transaction to send coins and sends to the specified listener directly
about: Builds a transaction to send coins and sends to the recipient via the Slatepack workflow
args:
- amount:
help: Number of coins to send with optional fraction, e.g. 12.423
Expand Down Expand Up @@ -119,7 +119,7 @@ subcommands:
default_value: "1"
takes_value: true
- dest:
help: Send the transaction to the provided server (start with http://) or save as file.
help: Intended recipient's Slatepack Address (or http listener address (DEPRECATED))
short: d
long: dest
takes_value: true
Expand All @@ -146,16 +146,24 @@ subcommands:
help: Output a V4 slate prior to HF3 block
long: v4
takes_value: false
- unpack:
about: Unpack and display an armored Slatepack Message, decrypting if possible
args:
- input:
help: File containing a Slatepack Message
short: i
long: input
takes_value: true
- receive:
about: Processes a transaction file to accept a transfer from a sender
about: Processes a Slatepack Message to accept a transfer from a sender
args:
- input:
help: Partial transaction to process, expects the sender's transaction file.
help: File containing a Slatepack Message
short: i
long: input
takes_value: true
- finalize:
about: Processes a receiver's transaction file to finalize a transfer.
about: Processes a Slatepack Message to finalize a transfer.
args:
- input:
help: Partial transaction to process, expects the receiver's transaction file.
Expand All @@ -171,13 +179,13 @@ subcommands:
short: n
long: nopost
- invoice:
about: Initialize an invoice transaction.
about: Initialize an invoice transaction, outputting a Slatepack Message with the result
args:
- amount:
help: Number of coins to invoice with optional fraction, e.g. 12.423
index: 1
- dest:
help: Name of destination slate output file
help: Intended recipient's Slatepack Address
short: d
long: dest
takes_value: true
Expand Down Expand Up @@ -209,12 +217,12 @@ subcommands:
short: e
long: estimate-selection
- dest:
help: Send the transaction to the provided server (start with http://) or save as file.
help: The Slatepack address of the invoicing party's wallet (will override the address contained in the Slatepack)
short: d
long: dest
takes_value: true
- input:
help: Partial transaction to process, expects the invoicer's transaction file.
help: Incoming Slatepack Message to process
short: i
long: input
takes_value: true
Expand Down
30 changes: 30 additions & 0 deletions src/cmd/wallet_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,32 @@ pub fn parse_receive_args(args: &ArgMatches) -> Result<command::ReceiveArgs, Par
})
}

pub fn parse_unpack_args(args: &ArgMatches) -> Result<command::ReceiveArgs, ParseError> {
// input file
let input_file = match args.is_present("input") {
true => {
let file = args.value_of("input").unwrap().to_owned();
// validate input
if !Path::new(&file).is_file() {
let msg = format!("File {} not found.", &file);
return Err(ParseError::ArgumentError(msg));
}
Some(file)
}
false => None,
};

let mut input_slatepack_message = None;
if input_file.is_none() {
input_slatepack_message = Some(prompt_slatepack()?);
}

Ok(command::ReceiveArgs {
input_file,
input_slatepack_message,
})
}

pub fn parse_finalize_args(args: &ArgMatches) -> Result<command::FinalizeArgs, ParseError> {
let fluff = args.is_present("fluff");
let nopost = args.is_present("nopost");
Expand Down Expand Up @@ -1134,6 +1160,10 @@ where
test_mode,
)
}
("unpack", Some(args)) => {
let a = arg_parse!(parse_unpack_args(&args));
command::unpack(owner_api, km, a)
}
("finalize", Some(args)) => {
let a = arg_parse!(parse_finalize_args(&args));
command::finalize(owner_api, km, a)
Expand Down

0 comments on commit 5e20f5f

Please sign in to comment.