add wallet unpack command (#433)

This commit is contained in:
Yeastplume
2020-06-11 08:34:00 +01:00
committed by GitHub
parent f71e7c1218
commit 5e20f5f0c8
9 changed files with 164 additions and 31 deletions
+9 -3
View File
@@ -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
@@ -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
+13 -4
View File
@@ -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
}
@@ -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).
@@ -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(
+81 -3
View File
@@ -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;
@@ -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(())
})?;
}
@@ -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(())
},
@@ -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 {
+2 -2
View File
@@ -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)?))
}
@@ -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);
+3 -3
View File
@@ -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)
}
}
@@ -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))
}
}
+4 -4
View File
@@ -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 {
@@ -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(_) => {
@@ -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
+4 -2
View File
@@ -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");
@@ -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)
}
+18 -10
View File
@@ -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
@@ -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
@@ -146,16 +146,24 @@ subcommands:
help: Output a V4 slate prior to HF3 block
long: v4
takes_value: false
- receive:
about: Processes a transaction file to accept a transfer from a sender
- unpack:
about: Unpack and display an armored Slatepack Message, decrypting if possible
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
- receive:
about: Processes a Slatepack Message to accept a transfer from a sender
args:
- input:
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.
@@ -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
@@ -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
+30
View File
@@ -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");
@@ -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)