mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-17 15:21:39 +02:00
add wallet unpack command (#433)
This commit is contained in:
+9
-3
@@ -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
@@ -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(
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user