mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-11-05 15:23:54 +01:00
Slatepack address index on send (#821)
* Store address_index into tx log entry to get address and decrypt slatepack message, increment over all values * Provide address index on send and issue_invoice command * Keep 0 index for receive * Use sender address index at payment proof Rust API users need to update to SlatepackAddressIndex and the Slatepack methods Keep a wallet database backup for pending transactions and saved address indices. Seed recovery alone does not restore these, and the address counter restarts at 1.
This commit is contained in:
+70
-68
@@ -19,19 +19,20 @@ use crate::apiwallet::{try_slatepack_sync_workflow, Owner};
|
||||
use crate::config::{TorConfig, WalletConfig, WALLET_CONFIG_FILE_NAME};
|
||||
use crate::core::{core, global};
|
||||
use crate::error::Error;
|
||||
use crate::impls::PathToSlatepack;
|
||||
use crate::impls::SlateGetter as _;
|
||||
use crate::keychain;
|
||||
use crate::libwallet::api_impl::owner::{self, decrypt_slatepack, deserialize_slatepack};
|
||||
use crate::libwallet::api_impl::types::update_tx_slate_state;
|
||||
use crate::libwallet::slatepack::get_slatepack_file_contents;
|
||||
use crate::libwallet::slatepack::SlatepackAddressIndex;
|
||||
use crate::libwallet::{
|
||||
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, Slate, SlateState, Slatepack,
|
||||
SlatepackAddress, Slatepacker, SlatepackerArgs, WalletLCProvider,
|
||||
SlatepackAddress, WalletLCProvider,
|
||||
};
|
||||
use crate::libwallet::{wallet_lock, WalletHandle};
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::{Mutex, ZeroingString};
|
||||
use crate::{controller, display};
|
||||
|
||||
use grin_wallet_libwallet::wallet_lock;
|
||||
use qr_code::QrCode;
|
||||
use serde_json as json;
|
||||
use std::fs::File;
|
||||
@@ -341,6 +342,7 @@ pub struct SendArgs {
|
||||
pub outfile: Option<String>,
|
||||
pub bridge: Option<String>,
|
||||
pub slatepack_qr: bool,
|
||||
pub address_index: Option<SlatepackAddressIndex>,
|
||||
}
|
||||
|
||||
fn max_retry_args(mut init_args: InitTxArgs, amount: u64, max_inputs: u32) -> InitTxArgs {
|
||||
@@ -412,6 +414,7 @@ where
|
||||
selection_strategy_is_use_all: strategy == "all",
|
||||
refresh_outputs_from_node: !info_updated,
|
||||
estimate_only: Some(true),
|
||||
address_index: args.address_index,
|
||||
..Default::default()
|
||||
};
|
||||
let result = owner_api.init_send_tx(keychain_mask, init_args.clone());
|
||||
@@ -456,6 +459,7 @@ where
|
||||
payment_proof_recipient_address,
|
||||
ttl_blocks: args.ttl_blocks,
|
||||
late_lock: Some(args.late_lock),
|
||||
address_index: args.address_index,
|
||||
..Default::default()
|
||||
};
|
||||
let init_send_tx = |init_args: InitTxArgs| -> Result<Slate, libwallet::Error> {
|
||||
@@ -505,6 +509,11 @@ where
|
||||
}
|
||||
|
||||
let output_sp = |owner_api: &mut Owner<L, C, K>, lock_outputs: bool| -> Result<(), Error> {
|
||||
let sender_index = {
|
||||
wallet_lock!(owner_api.wallet_inst, w);
|
||||
let context = w.get_private_context(keychain_mask, slate.id.as_bytes())?;
|
||||
context.payment_proof_derivation_index
|
||||
};
|
||||
Ok(output_slatepack(
|
||||
owner_api,
|
||||
keychain_mask,
|
||||
@@ -514,6 +523,7 @@ where
|
||||
lock_outputs,
|
||||
false,
|
||||
args.slatepack_qr,
|
||||
sender_index,
|
||||
)?)
|
||||
};
|
||||
|
||||
@@ -567,6 +577,7 @@ pub fn output_slatepack<L, C, K>(
|
||||
lock: bool,
|
||||
finalizing: bool,
|
||||
show_qr: bool,
|
||||
sender_index: Option<SlatepackAddressIndex>,
|
||||
) -> Result<(), libwallet::Error>
|
||||
where
|
||||
L: WalletLCProvider<'static, C, K> + 'static,
|
||||
@@ -579,7 +590,8 @@ where
|
||||
Some(a) => vec![a],
|
||||
None => vec![],
|
||||
};
|
||||
let message = owner_api.create_slatepack_message(keychain_mask, slate, Some(0), recipients)?;
|
||||
let message =
|
||||
owner_api.create_slatepack_message(keychain_mask, slate, sender_index, recipients)?;
|
||||
let tld = owner_api.get_top_level_directory()?;
|
||||
|
||||
// create a directory to which files will be output
|
||||
@@ -653,42 +665,30 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
let mut ret_address = None;
|
||||
let slate = match filename {
|
||||
let (slate, sender_address) = match filename {
|
||||
Some(f) => {
|
||||
// otherwise, get slate from slatepack
|
||||
let dec_key = owner_api.get_slatepack_secret_key(keychain_mask, 0)?;
|
||||
let packer = Slatepacker::new(SlatepackerArgs {
|
||||
sender: None,
|
||||
recipients: vec![],
|
||||
dec_key: Some(&dec_key),
|
||||
});
|
||||
let pts = PathToSlatepack::new(f.into(), &packer, true);
|
||||
let sl = Some(pts.get_tx()?.0);
|
||||
ret_address = pts.get_slatepack(true)?.sender;
|
||||
sl
|
||||
let data = get_slatepack_file_contents(&f.into())?;
|
||||
let sp = deserialize_slatepack(
|
||||
&data,
|
||||
owner_api.wallet_inst.clone(),
|
||||
keychain_mask,
|
||||
vec![SlatepackAddressIndex(0)],
|
||||
)?;
|
||||
let sl = sp.get_slate()?;
|
||||
(sl, sp.sender)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let slate = match slate {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
// try and parse directly from input_slatepack_message
|
||||
match message {
|
||||
Some(message) => {
|
||||
let slate = owner_api.slate_from_slatepack_message(
|
||||
let sp = owner_api.decode_slatepack_message(
|
||||
keychain_mask,
|
||||
message.clone(),
|
||||
vec![0],
|
||||
vec![SlatepackAddressIndex(0)],
|
||||
)?;
|
||||
let slatepack = owner_api.decode_slatepack_message(
|
||||
keychain_mask,
|
||||
message.clone(),
|
||||
vec![0],
|
||||
)?;
|
||||
ret_address = slatepack.sender;
|
||||
slate
|
||||
let sl = sp.get_slate()?;
|
||||
(sl, sp.sender)
|
||||
}
|
||||
None => {
|
||||
let msg = "No slate provided via file or direct input";
|
||||
@@ -697,7 +697,7 @@ where
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok((slate, ret_address))
|
||||
Ok((slate, sender_address))
|
||||
}
|
||||
|
||||
/// Receive command argument
|
||||
@@ -775,6 +775,7 @@ where
|
||||
false,
|
||||
false,
|
||||
args.slatepack_qr,
|
||||
None,
|
||||
)?)
|
||||
};
|
||||
|
||||
@@ -790,8 +791,7 @@ where
|
||||
Ok(s) => {
|
||||
// Update slate state.
|
||||
{
|
||||
let mut w_lock = owner_api.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
wallet_lock!(owner_api.wallet_inst, w);
|
||||
let parent_key_id = w.parent_key_id();
|
||||
match update_tx_slate_state(w, keychain_mask, &parent_key_id, &s) {
|
||||
Ok(_) => {}
|
||||
@@ -814,25 +814,18 @@ where
|
||||
}
|
||||
|
||||
pub fn read_slatepack(args: ReceiveArgs) -> Result<Slatepack, Error> {
|
||||
let packer = Slatepacker::new(SlatepackerArgs {
|
||||
sender: None,
|
||||
recipients: vec![],
|
||||
dec_key: None,
|
||||
});
|
||||
let slatepack = match args.input_file {
|
||||
Some(f) => PathToSlatepack::new(f.into(), &packer, true).get_slatepack(false)?,
|
||||
let data = match args.input_file {
|
||||
Some(f) => get_slatepack_file_contents(&f.into())?,
|
||||
None => match args.input_slatepack_message {
|
||||
Some(message) => packer.deser_slatepack(message.as_bytes(), false)?,
|
||||
None => {
|
||||
return Err(Error::ArgumentError("Invalid Slatepack Input".into()));
|
||||
}
|
||||
Some(message) => message.into_bytes(),
|
||||
None => return Err(Error::ArgumentError("Invalid Slatepack Input".into())),
|
||||
},
|
||||
};
|
||||
Ok(slatepack)
|
||||
Ok(owner::parse_slatepack(&data)?)
|
||||
}
|
||||
|
||||
pub fn unpack<L, C, K>(
|
||||
owner_api: &mut Owner<L, C, K>,
|
||||
wallet_inst: WalletHandle<'static, L, C, K>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
mut slatepack: Slatepack,
|
||||
) -> Result<(), Error>
|
||||
@@ -847,33 +840,32 @@ where
|
||||
println!("{}", slatepack);
|
||||
println!("------------------");
|
||||
|
||||
let packer = Slatepacker::new(SlatepackerArgs {
|
||||
sender: None,
|
||||
recipients: vec![],
|
||||
dec_key: None,
|
||||
});
|
||||
|
||||
if slatepack.mode == 1 {
|
||||
let dec_key = owner_api.get_slatepack_secret_key(keychain_mask, 0)?;
|
||||
match slatepack.try_decrypt_payload(Some(&dec_key)) {
|
||||
Ok(_) => {
|
||||
match decrypt_slatepack(
|
||||
&mut slatepack,
|
||||
wallet_inst,
|
||||
keychain_mask,
|
||||
vec![SlatepackAddressIndex(0)],
|
||||
)
|
||||
.and_then(|_| slatepack.get_slate())
|
||||
{
|
||||
Ok(s) => {
|
||||
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);
|
||||
println!("{}", s);
|
||||
}
|
||||
Err(_) => {
|
||||
println!("Slatepack payload cannot be decrypted by this wallet");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let slate = packer.get_slate(&slatepack)?;
|
||||
let slate = slatepack.get_slate()?;
|
||||
println!("Slatepack is not encrypted");
|
||||
println!();
|
||||
println!("SLATE");
|
||||
@@ -904,7 +896,7 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
let (mut slate, _ret_address) = parse_slatepack(
|
||||
let (mut slate, _) = parse_slatepack(
|
||||
owner_api,
|
||||
keychain_mask,
|
||||
args.input_file.clone(),
|
||||
@@ -975,6 +967,7 @@ where
|
||||
false,
|
||||
true,
|
||||
args.slatepack_qr,
|
||||
None,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
@@ -984,11 +977,11 @@ where
|
||||
pub struct IssueInvoiceArgs {
|
||||
/// Slatepack address
|
||||
pub dest: Option<String>,
|
||||
/// issue invoice tx args
|
||||
/// Issue invoice tx args
|
||||
pub issue_args: IssueInvoiceTxArgs,
|
||||
/// output file override
|
||||
/// Output file override
|
||||
pub outfile: Option<String>,
|
||||
/// show slatepack as QR code
|
||||
/// Show slatepack as QR code
|
||||
pub slatepack_qr: bool,
|
||||
}
|
||||
|
||||
@@ -1009,8 +1002,13 @@ where
|
||||
.transpose()?;
|
||||
let issue_args = args.issue_args.clone();
|
||||
|
||||
let slate = owner_api.issue_invoice_tx(keychain_mask, issue_args)?;
|
||||
let slate = owner_api.issue_invoice_tx(keychain_mask, issue_args.clone())?;
|
||||
|
||||
let sender_index = {
|
||||
wallet_lock!(owner_api.wallet_inst, w);
|
||||
let context = w.get_private_context(keychain_mask, slate.id.as_bytes())?;
|
||||
context.payment_proof_derivation_index
|
||||
};
|
||||
output_slatepack(
|
||||
owner_api,
|
||||
keychain_mask,
|
||||
@@ -1020,6 +1018,7 @@ where
|
||||
false,
|
||||
false,
|
||||
args.slatepack_qr,
|
||||
sender_index,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -1133,6 +1132,7 @@ where
|
||||
true,
|
||||
false,
|
||||
args.slatepack_qr,
|
||||
None,
|
||||
)?)
|
||||
};
|
||||
|
||||
@@ -1314,7 +1314,7 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
let (slate, _ret_address) = parse_slatepack(
|
||||
let (slate, _) = parse_slatepack(
|
||||
owner_api,
|
||||
keychain_mask,
|
||||
args.input_file,
|
||||
@@ -1462,7 +1462,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Payment Proof Address
|
||||
/// Show wallet's slatepack address.
|
||||
pub fn address<L, C, K>(
|
||||
owner_api: &mut Owner<L, C, K>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
@@ -1472,8 +1472,10 @@ where
|
||||
C: NodeClient + 'static,
|
||||
K: keychain::Keychain + 'static,
|
||||
{
|
||||
// Just address at derivation index 0 for now
|
||||
let address = owner_api.get_slatepack_address(keychain_mask, 0)?;
|
||||
// Just address at derivation index 0 for now,
|
||||
// cause sender encrypts message for address,
|
||||
// and we don't know its derivation path index.
|
||||
let address = owner_api.get_slatepack_address(keychain_mask, SlatepackAddressIndex(0))?;
|
||||
let account = account_label(owner_api)?;
|
||||
println!();
|
||||
println!("Address for account - {}", account);
|
||||
|
||||
@@ -55,6 +55,7 @@ use grin_wallet_config::config::{
|
||||
};
|
||||
use grin_wallet_impls::tor::arti::{start_tor_service, stop_tor_service};
|
||||
use grin_wallet_impls::tor::process::TorProcess;
|
||||
use grin_wallet_libwallet::slatepack::SlatepackAddressIndex;
|
||||
use http_body_util::{BodyExt, Full};
|
||||
use hyper::body::Incoming;
|
||||
use tokio::sync::mpsc;
|
||||
@@ -255,8 +256,9 @@ where
|
||||
let w_inst = lc.wallet_inst()?;
|
||||
let k = w_inst.keychain(mask.as_ref())?;
|
||||
let parent_key_id = w_inst.parent_key_id();
|
||||
let sec_key = address::address_from_derivation_path(&k, &parent_key_id, 0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
let sec_key =
|
||||
address::address_from_derivation_path(&k, &parent_key_id, SlatepackAddressIndex(0))
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
let tor_dir = format!("{}/tor/listener", lc.get_top_level_directory()?);
|
||||
let onion_address = OnionV3Address::from_private(&sec_key.0)
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::libwallet::{
|
||||
TxLogEntry, TxLogEntryType, ViewWallet, WalletInfo,
|
||||
};
|
||||
use crate::util::ToHex;
|
||||
|
||||
use grin_wallet_libwallet::slatepack::SlatepackAddressIndex;
|
||||
use prettytable;
|
||||
use prettytable::format::{FormatBuilder, LinePosition, LineSeparator};
|
||||
use std::io::prelude::Write;
|
||||
@@ -541,7 +541,8 @@ pub fn accounts(acct_mappings: Vec<AcctPathMapping>) {
|
||||
bMG->"Spendable balance",
|
||||
]);
|
||||
for m in acct_mappings {
|
||||
let slatepack_path = address::address_derivation_path(&m.path, 0).to_bip_32_string();
|
||||
let slatepack_path =
|
||||
address::address_derivation_path(&m.path, SlatepackAddressIndex(0)).to_bip_32_string();
|
||||
let spendable = if let Some(info) = m.info {
|
||||
amount_to_hr_string(info.amount_currently_spendable, true)
|
||||
} else {
|
||||
|
||||
@@ -32,6 +32,7 @@ use grin_wallet_libwallet::{InitTxArgs, IssueInvoiceTxArgs};
|
||||
#[macro_use]
|
||||
mod common;
|
||||
use common::{clean_output_dir, create_wallet_proxy, setup};
|
||||
use grin_wallet_libwallet::slatepack::SlatepackAddressIndex;
|
||||
|
||||
/// self send impl
|
||||
fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), libwallet::Error> {
|
||||
@@ -235,7 +236,7 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(),
|
||||
format!("{}/standard_pp_S3.txbin", test_dir),
|
||||
),
|
||||
};
|
||||
let address = Some(api2.get_slatepack_address(mask2, 0)?);
|
||||
let address = Some(api2.get_slatepack_address(mask2, SlatepackAddressIndex(0))?);
|
||||
|
||||
// send to send
|
||||
let args = InitTxArgs {
|
||||
|
||||
@@ -28,6 +28,7 @@ use std::time::Duration;
|
||||
#[macro_use]
|
||||
mod common;
|
||||
use common::{clean_output_dir, create_wallet_proxy, setup};
|
||||
use grin_wallet_libwallet::slatepack::SlatepackAddressIndex;
|
||||
|
||||
/// Various tests on accounts within the same wallet
|
||||
fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
@@ -78,7 +79,7 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err
|
||||
let _ =
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
let address = Some(api2.get_slatepack_address(mask2, 0)?);
|
||||
let address = Some(api2.get_slatepack_address(mask2, SlatepackAddressIndex(0))?);
|
||||
|
||||
println!("Public address is: {:?}", address);
|
||||
let amount = 60_000_000_000;
|
||||
@@ -121,7 +122,7 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err
|
||||
slate_i.payment_proof.as_ref().unwrap().receiver_address
|
||||
);
|
||||
assert!(pp.receiver_signature.is_some());
|
||||
assert_eq!(pp.sender_address_path, 0);
|
||||
assert_eq!(pp.sender_address_path, SlatepackAddressIndex(1));
|
||||
assert_eq!(pp.sender_signature, None);
|
||||
|
||||
// check we should get an error at this point since proof is not complete
|
||||
|
||||
@@ -30,6 +30,7 @@ use std::time::Duration;
|
||||
#[macro_use]
|
||||
mod common;
|
||||
use common::{clean_output_dir, create_wallet_proxy, setup};
|
||||
use grin_wallet_libwallet::slatepack::SlatepackAddressIndex;
|
||||
|
||||
/// self send impl
|
||||
fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
@@ -171,7 +172,9 @@ fn late_lock_self_send_proof() -> Result<(), libwallet::Error> {
|
||||
amount: core::consensus::REWARD,
|
||||
minimum_confirmations: 2,
|
||||
late_lock: Some(true),
|
||||
payment_proof_recipient_address: Some(api1.get_slatepack_address(mask1, 0)?),
|
||||
payment_proof_recipient_address: Some(
|
||||
api1.get_slatepack_address(mask1, SlatepackAddressIndex(0))?,
|
||||
),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
|
||||
+298
-93
@@ -20,25 +20,30 @@ extern crate grin_wallet_impls as impls;
|
||||
use grin_core as core;
|
||||
use grin_wallet_config::GlobalWalletConfig;
|
||||
use grin_wallet_libwallet as libwallet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use impls::test_framework::{self, LocalWalletClient};
|
||||
use impls::{PathToSlatepack, SlatePutter as _};
|
||||
use impls::DefaultLCProvider;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::{fs, thread};
|
||||
|
||||
use grin_wallet_libwallet::{
|
||||
InitTxArgs, InitTxSendArgs, IssueInvoiceTxArgs, Slate, Slatepack, SlatepackAddress,
|
||||
Slatepacker, SlatepackerArgs,
|
||||
slatepack, Error, InitTxArgs, InitTxSendArgs, IssueInvoiceTxArgs, Slate, Slatepack,
|
||||
SlatepackAddress, SlatepackBin, WalletHandle,
|
||||
};
|
||||
|
||||
use ed25519_dalek::SigningKey as edDalekSecretKey;
|
||||
use ed25519_dalek::VerifyingKey as edDalekPublicKey;
|
||||
|
||||
#[macro_use]
|
||||
mod common;
|
||||
use common::{clean_output_dir, create_wallet_proxy, setup};
|
||||
use grin_keychain::ExtKeychain;
|
||||
use grin_util::secp::SecretKey;
|
||||
use grin_wallet_libwallet::api_impl::owner::{decrypt_slatepack, deserialize_slatepack};
|
||||
use grin_wallet_libwallet::slatepack::{get_slatepack_file_contents, SlatepackAddressIndex};
|
||||
use grin_wallet_util::byte_ser;
|
||||
|
||||
fn output_slatepack(
|
||||
slate: &Slate,
|
||||
@@ -47,35 +52,55 @@ fn output_slatepack(
|
||||
use_bin: bool,
|
||||
sender: Option<SlatepackAddress>,
|
||||
recipients: Vec<SlatepackAddress>,
|
||||
) -> Result<(), libwallet::Error> {
|
||||
let packer = Slatepacker::new(SlatepackerArgs {
|
||||
sender,
|
||||
recipients,
|
||||
dec_key: None,
|
||||
});
|
||||
) -> Result<(), Error> {
|
||||
let mut file = file.into();
|
||||
if armored {
|
||||
file = format!("{}.armored", file);
|
||||
}
|
||||
PathToSlatepack::new(file.into(), &packer, armored).put_tx(slate, use_bin)
|
||||
let slatepack = slate.create_slatepack(sender, recipients)?;
|
||||
let mut pub_tx = File::create(&file)?;
|
||||
if use_bin {
|
||||
if armored {
|
||||
let armored = slatepack.armor()?;
|
||||
pub_tx.write_all(armored.as_bytes())?;
|
||||
} else {
|
||||
pub_tx.write_all(
|
||||
&byte_ser::to_bytes(&SlatepackBin(slatepack)).map_err(|_| Error::SlatepackSer)?,
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
pub_tx.write_all(
|
||||
serde_json::to_string_pretty(&slatepack)
|
||||
.map_err(|_| Error::SlateSer)?
|
||||
.as_bytes(),
|
||||
)?;
|
||||
}
|
||||
pub_tx.sync_all()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn slate_from_packed(
|
||||
wallet_inst: WalletHandle<
|
||||
DefaultLCProvider<LocalWalletClient, ExtKeychain>,
|
||||
LocalWalletClient,
|
||||
ExtKeychain,
|
||||
>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
file: &str,
|
||||
armored: bool,
|
||||
dec_key: Option<&edDalekSecretKey>,
|
||||
) -> Result<(Slatepack, Slate), libwallet::Error> {
|
||||
let packer = Slatepacker::new(SlatepackerArgs {
|
||||
sender: None,
|
||||
recipients: vec![],
|
||||
dec_key,
|
||||
});
|
||||
) -> Result<(Slatepack, Slate), Error> {
|
||||
let mut file = file.into();
|
||||
if armored {
|
||||
file = format!("{}.armored", file);
|
||||
}
|
||||
let slatepack = PathToSlatepack::new(file.into(), &packer, armored).get_slatepack(true)?;
|
||||
Ok((slatepack.clone(), packer.get_slate(&slatepack)?))
|
||||
let data = get_slatepack_file_contents(&file.into())?;
|
||||
let slatepack = deserialize_slatepack(
|
||||
&data,
|
||||
wallet_inst,
|
||||
keychain_mask,
|
||||
vec![SlatepackAddressIndex(0)],
|
||||
)?;
|
||||
Ok((slatepack.clone(), slatepack.get_slate()?))
|
||||
}
|
||||
|
||||
/// self send impl
|
||||
@@ -84,7 +109,7 @@ fn slatepack_exchange_test_impl(
|
||||
use_bin: bool,
|
||||
use_armored: bool,
|
||||
use_encryption: bool,
|
||||
) -> Result<(), libwallet::Error> {
|
||||
) -> Result<(), Error> {
|
||||
// Create a new proxy to simulate server and wallet responses
|
||||
let mut wallet_proxy = create_wallet_proxy(test_dir);
|
||||
let chain = wallet_proxy.chain.clone();
|
||||
@@ -134,41 +159,49 @@ fn slatepack_exchange_test_impl(
|
||||
api2.create_account_path(mask2, "account1")?;
|
||||
api2.create_account_path(mask2, "account2")?;
|
||||
|
||||
// Get some mining done
|
||||
{
|
||||
wallet_inst!(wallet1, w);
|
||||
w.set_account_by_name("mining")?;
|
||||
}
|
||||
|
||||
{
|
||||
wallet_inst!(wallet2, w);
|
||||
w.set_account_by_name("account1")?;
|
||||
}
|
||||
|
||||
// Get some mining done
|
||||
let mut bh = 10u64;
|
||||
let _ =
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
let (recipients_1, dec_key_1, sender_1) = match use_encryption {
|
||||
let (recipients_1, sender_1) = match use_encryption {
|
||||
true => {
|
||||
let sec_key = api1.get_slatepack_secret_key(mask1, 0)?;
|
||||
let sec_key = api1.get_slatepack_secret_key(mask1, SlatepackAddressIndex(0))?;
|
||||
let pub_key = edDalekPublicKey::from(&sec_key);
|
||||
let rec_address = SlatepackAddress::new(&pub_key);
|
||||
(
|
||||
vec![rec_address.clone()],
|
||||
Some(sec_key),
|
||||
Some(rec_address.clone()),
|
||||
)
|
||||
|
||||
let sen_index = SlatepackAddressIndex(7);
|
||||
let sec_key = api1.get_slatepack_secret_key(mask1, sen_index)?;
|
||||
let pub_key = edDalekPublicKey::from(&sec_key);
|
||||
let sen_address = SlatepackAddress::new(&pub_key);
|
||||
(vec![rec_address.clone()], Some(sen_address.clone()))
|
||||
}
|
||||
false => (vec![], None, None),
|
||||
false => (vec![], None),
|
||||
};
|
||||
|
||||
let (recipients_2, dec_key_2, sender_2) = match use_encryption {
|
||||
let (recipients_2, sender_2) = match use_encryption {
|
||||
true => {
|
||||
let sec_key = api2.get_slatepack_secret_key(mask2, 0)?;
|
||||
let sec_key = api2.get_slatepack_secret_key(mask2, SlatepackAddressIndex(0))?;
|
||||
let pub_key = edDalekPublicKey::from(&sec_key);
|
||||
let rec_address = SlatepackAddress::new(&pub_key);
|
||||
(
|
||||
vec![rec_address.clone()],
|
||||
Some(sec_key),
|
||||
Some(rec_address.clone()),
|
||||
)
|
||||
|
||||
let sen_index = SlatepackAddressIndex(11);
|
||||
let sec_key = api2.get_slatepack_secret_key(mask2, sen_index)?;
|
||||
let pub_key = edDalekPublicKey::from(&sec_key);
|
||||
let sen_address = SlatepackAddress::new(&pub_key);
|
||||
(vec![rec_address.clone()], Some(sen_address.clone()))
|
||||
}
|
||||
false => (vec![], None, None),
|
||||
false => (vec![], None),
|
||||
};
|
||||
|
||||
let (send_file, receive_file, final_file) = match use_bin {
|
||||
@@ -190,7 +223,7 @@ fn slatepack_exchange_test_impl(
|
||||
assert_eq!(wallet1_info.total, bh * reward);
|
||||
// send to send
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: Some("mining".to_owned()),
|
||||
address_index: Some(SlatepackAddressIndex(7)),
|
||||
amount: reward * 2,
|
||||
minimum_confirmations: 2,
|
||||
max_outputs: 500,
|
||||
@@ -210,14 +243,8 @@ fn slatepack_exchange_test_impl(
|
||||
)?;
|
||||
api1.tx_lock_outputs(mask1, &slate)?;
|
||||
|
||||
// Get some mining done
|
||||
{
|
||||
wallet_inst!(wallet2, w);
|
||||
w.set_account_by_name("account1")?;
|
||||
}
|
||||
|
||||
let (mut slatepack, mut slate) =
|
||||
slate_from_packed(&send_file, use_armored, dec_key_2.as_ref())?;
|
||||
let (slatepack, mut slate) =
|
||||
slate_from_packed(wallet2.clone(), mask2, &send_file, use_armored)?;
|
||||
|
||||
// wallet 2 receives file, completes, sends file back
|
||||
wallet::controller::foreign_single_use(
|
||||
@@ -231,8 +258,8 @@ fn slatepack_exchange_test_impl(
|
||||
&receive_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
// re-encrypt for sender!
|
||||
sender_2.clone(),
|
||||
// re-encrypt for sender!
|
||||
match slatepack.sender.clone() {
|
||||
Some(s) => vec![s.clone()],
|
||||
None => vec![],
|
||||
@@ -243,23 +270,34 @@ fn slatepack_exchange_test_impl(
|
||||
)?;
|
||||
|
||||
// wallet 1 finalizes and posts
|
||||
let (_, mut slate) = slate_from_packed(&receive_file, use_armored, dec_key_1.as_ref())?;
|
||||
let (slatepack, mut slate) =
|
||||
slate_from_packed(wallet1.clone(), mask1, &receive_file, use_armored)?;
|
||||
slate = api1.finalize_tx(mask1, &slate)?;
|
||||
// Output final file for reference
|
||||
output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?;
|
||||
output_slatepack(
|
||||
&slate,
|
||||
&final_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_1.clone(),
|
||||
match slatepack.sender {
|
||||
Some(s) => vec![s.clone()],
|
||||
None => vec![],
|
||||
},
|
||||
)?;
|
||||
api1.post_tx(mask1, &slate, false)?;
|
||||
bh += 1;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
bh += 3;
|
||||
|
||||
// Check total in mining account
|
||||
// Check total in wallet 1 account
|
||||
let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward - reward * 2);
|
||||
|
||||
// Check total in 'wallet 2' account
|
||||
// Check total in wallet 2 account
|
||||
let (wallet2_refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?;
|
||||
assert!(wallet2_refreshed);
|
||||
assert_eq!(wallet2_info.last_confirmed_height, bh);
|
||||
@@ -281,10 +319,11 @@ fn slatepack_exchange_test_impl(
|
||||
};
|
||||
|
||||
let args = IssueInvoiceTxArgs {
|
||||
address_index: Some(SlatepackAddressIndex(11)),
|
||||
amount: 1000000000,
|
||||
..Default::default()
|
||||
};
|
||||
let mut slate = api2.issue_invoice_tx(mask2, args)?;
|
||||
let slate = api2.issue_invoice_tx(mask2, args)?;
|
||||
output_slatepack(
|
||||
&slate,
|
||||
&send_file,
|
||||
@@ -303,9 +342,8 @@ fn slatepack_exchange_test_impl(
|
||||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let res = slate_from_packed(&send_file, use_armored, dec_key_1.as_ref())?;
|
||||
slatepack = res.0;
|
||||
slate = res.1;
|
||||
let (slatepack, mut slate) =
|
||||
slate_from_packed(wallet1.clone(), mask1, &send_file, use_armored)?;
|
||||
slate = api1.process_invoice_tx(mask1, &slate, args)?;
|
||||
api1.tx_lock_outputs(mask1, &slate)?;
|
||||
output_slatepack(
|
||||
@@ -314,25 +352,16 @@ fn slatepack_exchange_test_impl(
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_1.clone(),
|
||||
match slatepack.sender.clone() {
|
||||
match slatepack.sender {
|
||||
Some(s) => vec![s.clone()],
|
||||
None => vec![],
|
||||
},
|
||||
)?;
|
||||
wallet::controller::foreign_single_use(
|
||||
wallet2.clone(),
|
||||
PathBuf::from(test_dir),
|
||||
mask2_i.clone(),
|
||||
|api| {
|
||||
// Wallet 2 receives the invoice transaction
|
||||
let res = slate_from_packed(&receive_file, use_armored, dec_key_2.as_ref())?;
|
||||
slate = res.1;
|
||||
slate = api.finalize_tx(&slate, false)?;
|
||||
output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?;
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
api1.post_tx(mask1, &slate, false)?;
|
||||
// Wallet 2 receives the invoice transaction
|
||||
let (_, mut slate) = slate_from_packed(wallet2.clone(), mask2, &receive_file, use_armored)?;
|
||||
slate = api2.finalize_tx(mask2, &slate)?;
|
||||
output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?;
|
||||
api2.post_tx(mask2, &slate, false)?;
|
||||
|
||||
// Standard, with payment proof
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
@@ -349,17 +378,17 @@ fn slatepack_exchange_test_impl(
|
||||
),
|
||||
};
|
||||
|
||||
let address = Some(api2.get_slatepack_address(mask2, 0)?);
|
||||
|
||||
// send to send
|
||||
// send from 1st wallet
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: Some("mining".to_owned()),
|
||||
address_index: Some(SlatepackAddressIndex(7)),
|
||||
amount: reward,
|
||||
minimum_confirmations: 2,
|
||||
max_outputs: 500,
|
||||
num_change_outputs: 1,
|
||||
selection_strategy_is_use_all: true,
|
||||
payment_proof_recipient_address: address.clone(),
|
||||
payment_proof_recipient_address: Some(
|
||||
api2.get_slatepack_address(mask2, SlatepackAddressIndex(0))?,
|
||||
),
|
||||
..Default::default()
|
||||
};
|
||||
let mut slate = api1.init_send_tx(mask1, args)?;
|
||||
@@ -373,21 +402,21 @@ fn slatepack_exchange_test_impl(
|
||||
)?;
|
||||
api1.tx_lock_outputs(mask1, &slate)?;
|
||||
|
||||
// receive at 2nd wallet
|
||||
wallet::controller::foreign_single_use(
|
||||
wallet2.clone(),
|
||||
PathBuf::from(test_dir),
|
||||
mask2_i.clone(),
|
||||
|api| {
|
||||
let res = slate_from_packed(&send_file, use_armored, dec_key_2.as_ref())?;
|
||||
let slatepack = res.0;
|
||||
slate = res.1;
|
||||
let (slatepack, mut slate) =
|
||||
slate_from_packed(wallet2.clone(), mask2, &send_file, use_armored)?;
|
||||
slate = api.receive_tx(&slate, None, None)?;
|
||||
output_slatepack(
|
||||
&slate,
|
||||
&receive_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_2,
|
||||
sender_2.clone(),
|
||||
match slatepack.sender {
|
||||
Some(s) => vec![s.clone()],
|
||||
None => vec![],
|
||||
@@ -398,7 +427,7 @@ fn slatepack_exchange_test_impl(
|
||||
)?;
|
||||
|
||||
// wallet 1 finalizes and posts
|
||||
let res = slate_from_packed(&receive_file, use_armored, dec_key_1.as_ref())?;
|
||||
let res = slate_from_packed(wallet1.clone(), mask1, &receive_file, use_armored)?;
|
||||
slate = res.1;
|
||||
slate = api1.finalize_tx(mask1, &slate)?;
|
||||
// Output final file for reference
|
||||
@@ -450,7 +479,6 @@ fn slatepack_api_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: Some("mining".to_owned()),
|
||||
amount: reward * 2,
|
||||
minimum_confirmations: 2,
|
||||
max_outputs: 500,
|
||||
@@ -458,15 +486,141 @@ fn slatepack_api_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
||||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
for index in [SlatepackAddressIndex::MAX + 1, u32::MAX] {
|
||||
assert!(matches!(
|
||||
api1.init_send_tx(
|
||||
mask1,
|
||||
InitTxArgs {
|
||||
address_index: Some(SlatepackAddressIndex(index)),
|
||||
..args.clone()
|
||||
}
|
||||
),
|
||||
Err(Error::SlatepackAddress(_))
|
||||
));
|
||||
assert!(matches!(
|
||||
api1.issue_invoice_tx(
|
||||
mask1,
|
||||
IssueInvoiceTxArgs {
|
||||
amount: reward,
|
||||
address_index: Some(SlatepackAddressIndex(index)),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
Err(Error::SlatepackAddress(_))
|
||||
));
|
||||
}
|
||||
api1.init_send_tx(
|
||||
mask1,
|
||||
InitTxArgs {
|
||||
estimate_only: Some(true),
|
||||
..args.clone()
|
||||
},
|
||||
)?;
|
||||
let slate = api1.init_send_tx(mask1, args)?;
|
||||
// create an encrypted slatepack (just encrypted for self)
|
||||
let enc_addr = api1.get_slatepack_address(mask1, 0)?;
|
||||
let slatepack = api1.create_slatepack_message(mask1, &slate, Some(0), vec![enc_addr])?;
|
||||
println!("{}", slatepack);
|
||||
let slatepack_raw = api1.decode_slatepack_message(mask1, slatepack.clone(), vec![0])?;
|
||||
println!("{}", slatepack_raw);
|
||||
let decoded_slate = api1.slate_from_slatepack_message(mask1, slatepack, vec![0])?;
|
||||
println!("{}", decoded_slate);
|
||||
let address_index = SlatepackAddressIndex(0);
|
||||
let enc_addr = api1.get_slatepack_address(mask1, address_index)?;
|
||||
let slatepack =
|
||||
api1.create_slatepack_message(mask1, &slate, Some(address_index), vec![enc_addr])?;
|
||||
let mut encrypted = api1.decode_slatepack_message(mask1, slatepack.clone(), vec![])?;
|
||||
assert_eq!(encrypted.mode, 1);
|
||||
decrypt_slatepack(&mut encrypted, wallet1.clone(), mask1, vec![address_index])?;
|
||||
assert_eq!(encrypted.get_slate()?.id, slate.id);
|
||||
let slatepack_raw =
|
||||
api1.decode_slatepack_message(mask1, slatepack.clone(), vec![address_index])?;
|
||||
assert_eq!(slatepack_raw.mode, 0);
|
||||
assert_eq!(slatepack_raw.get_slate()?.id, slate.id);
|
||||
let decoded_slate = api1.slate_from_slatepack_message(mask1, slatepack, vec![address_index])?;
|
||||
assert_eq!(decoded_slate.id, slate.id);
|
||||
|
||||
let unknown_index = SlatepackAddressIndex(77);
|
||||
let unknown_address = api1.get_slatepack_address(mask1, unknown_index)?;
|
||||
let message = api1.create_slatepack_message(mask1, &slate, None, vec![unknown_address])?;
|
||||
let encrypted = api1.decode_slatepack_message(mask1, message.clone(), vec![])?;
|
||||
let decoded = api1.decode_slatepack_message(mask1, message.clone(), vec![address_index])?;
|
||||
assert_eq!(decoded.mode, 1);
|
||||
assert_eq!(decoded.payload, encrypted.payload);
|
||||
assert!(matches!(
|
||||
api1.slate_from_slatepack_message(mask1, message.clone(), vec![address_index]),
|
||||
Err(Error::SlatepackDecryption(_))
|
||||
));
|
||||
let mut api1 = api1;
|
||||
assert!(matches!(
|
||||
wallet::command::parse_slatepack(&mut api1, mask1, None, Some(message)),
|
||||
Err(wallet::Error::LibWallet(Error::SlatepackDecryption(_)))
|
||||
));
|
||||
|
||||
let index = {
|
||||
wallet_inst!(wallet1, w);
|
||||
w.get_private_context(mask1, slate.id.as_bytes())?
|
||||
.payment_proof_derivation_index
|
||||
.unwrap()
|
||||
};
|
||||
assert_eq!(index, SlatepackAddressIndex(1));
|
||||
let address = api1.get_slatepack_address(mask1, index)?;
|
||||
let message = api1.create_slatepack_message(mask1, &slate, None, vec![address])?;
|
||||
let decoded = api1.decode_slatepack_message(mask1, message.clone(), vec![address_index])?;
|
||||
assert_eq!(decoded.mode, 0);
|
||||
assert_eq!(decoded.get_slate()?.id, slate.id);
|
||||
|
||||
api1.create_account_path(mask1, "other")?;
|
||||
api1.set_active_account(mask1, "other")?;
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 6, false)?;
|
||||
api1.set_active_account(mask1, "default")?;
|
||||
let invoice = api1.issue_invoice_tx(
|
||||
mask1,
|
||||
IssueInvoiceTxArgs {
|
||||
amount: reward,
|
||||
dest_acct_name: Some("other".into()),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
let send = api1.init_send_tx(
|
||||
mask1,
|
||||
InitTxArgs {
|
||||
amount: reward,
|
||||
src_acct_name: Some("other".into()),
|
||||
minimum_confirmations: 2,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
api1.set_active_account(mask1, "other")?;
|
||||
let next = api1.issue_invoice_tx(
|
||||
mask1,
|
||||
IssueInvoiceTxArgs {
|
||||
amount: reward,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
for (slate, expected) in [(&invoice, 1), (&send, 2), (&next, 3)] {
|
||||
wallet_inst!(wallet1, w);
|
||||
let context = w.get_private_context(mask1, slate.id.as_bytes())?;
|
||||
assert_eq!(context.parent_key_id, w.parent_key_id());
|
||||
assert_eq!(
|
||||
context.payment_proof_derivation_index,
|
||||
Some(SlatepackAddressIndex(expected))
|
||||
);
|
||||
}
|
||||
api1.set_active_account(mask1, "default")?;
|
||||
let invoice = api1.issue_invoice_tx(
|
||||
mask1,
|
||||
IssueInvoiceTxArgs {
|
||||
amount: reward,
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
{
|
||||
wallet_inst!(wallet1, w);
|
||||
assert_eq!(
|
||||
w.get_private_context(mask1, invoice.id.as_bytes())?
|
||||
.payment_proof_derivation_index,
|
||||
Some(SlatepackAddressIndex(2))
|
||||
);
|
||||
}
|
||||
|
||||
api1.close_wallet(None)?;
|
||||
let encrypted = api1.decode_slatepack_message(None, message, vec![])?;
|
||||
assert_eq!(encrypted.mode, 1);
|
||||
|
||||
// let logging finish
|
||||
stopper.store(false, Ordering::Relaxed);
|
||||
@@ -526,7 +680,6 @@ fn slatepack_address_validation(test_dir: &'static str) -> Result<(), libwallet:
|
||||
)?;
|
||||
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: Some("mining".to_owned()),
|
||||
amount: reward,
|
||||
minimum_confirmations: 2,
|
||||
max_outputs: 500,
|
||||
@@ -566,6 +719,15 @@ fn slatepack_address_validation(test_dir: &'static str) -> Result<(), libwallet:
|
||||
fluff: false,
|
||||
skip_tor: Some(true),
|
||||
});
|
||||
let missing_config = PathBuf::from(test_dir).join("missing.toml");
|
||||
let api = grin_wallet_api::Owner::new(wallet1.clone(), None, missing_config);
|
||||
assert!(api
|
||||
.process_invoice_tx(mask1, &slate, valid_args.clone())
|
||||
.is_err());
|
||||
{
|
||||
wallet_inst!(wallet1, w);
|
||||
assert!(w.get_private_context(mask1, slate.id.as_bytes()).is_err());
|
||||
}
|
||||
api1.process_invoice_tx(mask1, &slate, valid_args.clone())?;
|
||||
api1.init_send_tx(mask1, valid_args)?;
|
||||
|
||||
@@ -660,3 +822,46 @@ fn slatepack_address() {
|
||||
}
|
||||
clean_output_dir(test_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_file_contents() {
|
||||
let test_dir = "test_output/slatepack_file_contents";
|
||||
setup(test_dir);
|
||||
|
||||
fs::create_dir_all(test_dir).unwrap();
|
||||
let sp_path = PathBuf::from(test_dir).join("pack_file");
|
||||
|
||||
// set Slatepack file to minimum allowable size
|
||||
{
|
||||
let f = File::create(sp_path.clone()).unwrap();
|
||||
f.set_len(slatepack::min_size()).unwrap();
|
||||
}
|
||||
|
||||
let mut pack_path = get_slatepack_file_contents(&sp_path);
|
||||
assert!(pack_path.is_ok());
|
||||
|
||||
// set Slatepack file to maximum allowable size
|
||||
{
|
||||
let f = File::create(sp_path.clone()).unwrap();
|
||||
f.set_len(slatepack::max_size()).unwrap();
|
||||
}
|
||||
pack_path = get_slatepack_file_contents(&sp_path);
|
||||
assert!(pack_path.is_ok());
|
||||
|
||||
// set Slatepack file below minimum allowable size
|
||||
{
|
||||
let f = File::create(sp_path.clone()).unwrap();
|
||||
f.set_len(slatepack::min_size() - 1).unwrap();
|
||||
}
|
||||
pack_path = get_slatepack_file_contents(&sp_path);
|
||||
assert!(pack_path.is_err());
|
||||
|
||||
// set Slatepack file above maximum allowable size
|
||||
{
|
||||
let f = File::create(sp_path.clone()).unwrap();
|
||||
f.set_len(slatepack::max_size() + 1).unwrap();
|
||||
}
|
||||
pack_path = get_slatepack_file_contents(&sp_path);
|
||||
assert!(pack_path.is_err());
|
||||
clean_output_dir(test_dir);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user