@@ -332,6 +332,44 @@ impl Command for UnlockCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct LockCommand {}
|
||||||
|
impl Command for LockCommand {
|
||||||
|
fn help(&self) -> String {
|
||||||
|
let mut h = vec![];
|
||||||
|
h.push("Lock a wallet that's been temporarily unlocked. You should already have encryption enabled.");
|
||||||
|
h.push("Note 1: This will remove all spending keys from memory. The wallet remains encrypted on disk");
|
||||||
|
h.push("Note 2: If you've forgotten the password, the only way to recover the wallet is to restore");
|
||||||
|
h.push(" from the seed phrase.");
|
||||||
|
h.push("Usage:");
|
||||||
|
h.push("lock");
|
||||||
|
h.push("");
|
||||||
|
h.push("Example:");
|
||||||
|
h.push("lock");
|
||||||
|
|
||||||
|
h.join("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn short_help(&self) -> String {
|
||||||
|
"Lock a wallet that's been temporarily unlocked".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exec(&self, args: &[&str], lightclient: &LightClient) -> String {
|
||||||
|
if args.len() != 0 {
|
||||||
|
return self.help();
|
||||||
|
}
|
||||||
|
|
||||||
|
match lightclient.wallet.write().unwrap().lock() {
|
||||||
|
Ok(_) => object!{ "result" => "success" },
|
||||||
|
Err(e) => object!{
|
||||||
|
"result" => "error",
|
||||||
|
"error" => e.to_string()
|
||||||
|
}
|
||||||
|
}.pretty(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct SendCommand {}
|
struct SendCommand {}
|
||||||
impl Command for SendCommand {
|
impl Command for SendCommand {
|
||||||
fn help(&self) -> String {
|
fn help(&self) -> String {
|
||||||
@@ -665,6 +703,7 @@ pub fn get_commands() -> Box<HashMap<String, Box<dyn Command>>> {
|
|||||||
map.insert("encrypt".to_string(), Box::new(EncryptCommand{}));
|
map.insert("encrypt".to_string(), Box::new(EncryptCommand{}));
|
||||||
map.insert("decrypt".to_string(), Box::new(DecryptCommand{}));
|
map.insert("decrypt".to_string(), Box::new(DecryptCommand{}));
|
||||||
map.insert("unlock".to_string(), Box::new(UnlockCommand{}));
|
map.insert("unlock".to_string(), Box::new(UnlockCommand{}));
|
||||||
|
map.insert("lock".to_string(), Box::new(LockCommand{}));
|
||||||
map.insert("fixbip39bug".to_string(), Box::new(FixBip39BugCommand{}));
|
map.insert("fixbip39bug".to_string(), Box::new(FixBip39BugCommand{}));
|
||||||
|
|
||||||
Box::new(map)
|
Box::new(map)
|
||||||
|
|||||||
@@ -594,8 +594,8 @@ impl LightWallet {
|
|||||||
pub fn encrypt(&mut self, passwd: String) -> io::Result<()> {
|
pub fn encrypt(&mut self, passwd: String) -> io::Result<()> {
|
||||||
use sodiumoxide::crypto::secretbox;
|
use sodiumoxide::crypto::secretbox;
|
||||||
|
|
||||||
if self.encrypted && !self.unlocked {
|
if self.encrypted {
|
||||||
return Err(io::Error::new(ErrorKind::AlreadyExists, "Wallet is already encrypted and locked"));
|
return Err(io::Error::new(ErrorKind::AlreadyExists, "Wallet is already encrypted"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the doublesha256 of the password, which is the right length
|
// Get the doublesha256 of the password, which is the right length
|
||||||
@@ -615,6 +615,14 @@ impl LightWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn lock(&mut self) -> io::Result<()> {
|
pub fn lock(&mut self) -> io::Result<()> {
|
||||||
|
if !self.encrypted {
|
||||||
|
return Err(io::Error::new(ErrorKind::AlreadyExists, "Wallet is not encrypted"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.unlocked {
|
||||||
|
return Err(io::Error::new(ErrorKind::AlreadyExists, "Wallet is already locked"));
|
||||||
|
}
|
||||||
|
|
||||||
// Empty the seed and the secret keys
|
// Empty the seed and the secret keys
|
||||||
self.seed.copy_from_slice(&[0u8; 32]);
|
self.seed.copy_from_slice(&[0u8; 32]);
|
||||||
self.tkeys = Arc::new(RwLock::new(vec![]));
|
self.tkeys = Arc::new(RwLock::new(vec![]));
|
||||||
@@ -842,15 +850,11 @@ impl LightWallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan the full Tx and update memos for incoming shielded transactions
|
// Scan the full Tx and update memos for incoming shielded transactions.
|
||||||
pub fn scan_full_tx(&self, tx: &Transaction, height: i32, datetime: u64) {
|
pub fn scan_full_tx(&self, tx: &Transaction, height: i32, datetime: u64) {
|
||||||
// Scan all the inputs to see if we spent any transparent funds in this tx
|
|
||||||
|
|
||||||
// TODO: Save this object
|
|
||||||
let secp = secp256k1::Secp256k1::new();
|
|
||||||
|
|
||||||
let mut total_transparent_spend: u64 = 0;
|
let mut total_transparent_spend: u64 = 0;
|
||||||
|
|
||||||
|
// Scan all the inputs to see if we spent any transparent funds in this tx
|
||||||
for vin in tx.vin.iter() {
|
for vin in tx.vin.iter() {
|
||||||
// Find the txid in the list of utxos that we have.
|
// Find the txid in the list of utxos that we have.
|
||||||
let txid = TxId {0: vin.prevout.hash};
|
let txid = TxId {0: vin.prevout.hash};
|
||||||
@@ -890,19 +894,15 @@ impl LightWallet {
|
|||||||
.total_transparent_value_spent = total_transparent_spend;
|
.total_transparent_value_spent = total_transparent_spend;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Iterate over all transparent addresses. This is currently looking only at
|
|
||||||
// the first one.
|
|
||||||
// Scan for t outputs
|
// Scan for t outputs
|
||||||
let all_pubkeys = self.tkeys.read().unwrap().iter()
|
let all_taddresses = self.taddresses.read().unwrap().iter()
|
||||||
.map(|sk|
|
.map(|a| a.clone())
|
||||||
secp256k1::PublicKey::from_secret_key(&secp, sk).serialize()
|
.collect::<Vec<_>>();
|
||||||
)
|
for address in all_taddresses {
|
||||||
.collect::<Vec<[u8; secp256k1::constants::PUBLIC_KEY_SIZE]>>();
|
|
||||||
for pubkey in all_pubkeys {
|
|
||||||
for (n, vout) in tx.vout.iter().enumerate() {
|
for (n, vout) in tx.vout.iter().enumerate() {
|
||||||
match vout.script_pubkey.address() {
|
match vout.script_pubkey.address() {
|
||||||
Some(TransparentAddress::PublicKey(hash)) => {
|
Some(TransparentAddress::PublicKey(hash)) => {
|
||||||
if hash[..] == ripemd160::Ripemd160::digest(&Sha256::digest(&pubkey))[..] {
|
if address == hash.to_base58check(&self.config.base58_pubkey_address(), &[]) {
|
||||||
// This is our address. Add this as an output to the txid
|
// This is our address. Add this as an output to the txid
|
||||||
self.add_toutput_to_wtx(height, datetime, &tx.txid(), &vout, n as u64);
|
self.add_toutput_to_wtx(height, datetime, &tx.txid(), &vout, n as u64);
|
||||||
}
|
}
|
||||||
@@ -1316,6 +1316,8 @@ impl LightWallet {
|
|||||||
|
|
||||||
let total_value = tos.iter().map(|to| to.1).sum::<u64>();
|
let total_value = tos.iter().map(|to| to.1).sum::<u64>();
|
||||||
|
|
||||||
|
// TODO: Check for duplicates in destination addresses
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"0: Creating transaction sending {} ztoshis to {} addresses",
|
"0: Creating transaction sending {} ztoshis to {} addresses",
|
||||||
total_value, tos.len()
|
total_value, tos.len()
|
||||||
@@ -3150,6 +3152,10 @@ pub mod tests {
|
|||||||
|
|
||||||
let seed = wallet.seed;
|
let seed = wallet.seed;
|
||||||
|
|
||||||
|
// Trying to lock a wallet that's not encrpyted is an error
|
||||||
|
assert!(wallet.lock().is_err());
|
||||||
|
|
||||||
|
// Encrypt the wallet
|
||||||
wallet.encrypt("somepassword".to_string()).unwrap();
|
wallet.encrypt("somepassword".to_string()).unwrap();
|
||||||
|
|
||||||
// Encrypting an already encrypted wallet should fail
|
// Encrypting an already encrypted wallet should fail
|
||||||
@@ -3194,6 +3200,9 @@ pub mod tests {
|
|||||||
wallet.lock().unwrap();
|
wallet.lock().unwrap();
|
||||||
wallet.write(&mut vec![]).expect("Serialize wallet");
|
wallet.write(&mut vec![]).expect("Serialize wallet");
|
||||||
|
|
||||||
|
// Locking an already locked wallet is an error
|
||||||
|
assert!(wallet.lock().is_err());
|
||||||
|
|
||||||
// Try from a deserialized, locked wallet
|
// Try from a deserialized, locked wallet
|
||||||
let mut wallet2 = LightWallet::read(&serialized_data[..], &config).unwrap();
|
let mut wallet2 = LightWallet::read(&serialized_data[..], &config).unwrap();
|
||||||
wallet2.unlock("somepassword".to_string()).unwrap();
|
wallet2.unlock("somepassword".to_string()).unwrap();
|
||||||
|
|||||||
@@ -74,13 +74,13 @@ impl BugBip39Derivation {
|
|||||||
|
|
||||||
// Tranfer money
|
// Tranfer money
|
||||||
// 1. The desination is z address #0
|
// 1. The desination is z address #0
|
||||||
println!("Sending funds to ourself.");
|
|
||||||
let zaddr = client.do_address()["z_addresses"][0].as_str().unwrap().to_string();
|
let zaddr = client.do_address()["z_addresses"][0].as_str().unwrap().to_string();
|
||||||
let balance_json = client.do_balance();
|
let balance_json = client.do_balance();
|
||||||
let amount: u64 = balance_json["zbalance"].as_u64().unwrap()
|
let amount: u64 = balance_json["zbalance"].as_u64().unwrap()
|
||||||
+ balance_json["tbalance"].as_u64().unwrap();
|
+ balance_json["tbalance"].as_u64().unwrap();
|
||||||
|
|
||||||
let txid = if amount > 0 {
|
let txid = if amount > 0 {
|
||||||
|
println!("Sending funds to ourself.");
|
||||||
let fee: u64 = DEFAULT_FEE.try_into().unwrap();
|
let fee: u64 = DEFAULT_FEE.try_into().unwrap();
|
||||||
match client.do_send(vec![(&zaddr, amount-fee, None)]) {
|
match client.do_send(vec![(&zaddr, amount-fee, None)]) {
|
||||||
Ok(txid) => txid,
|
Ok(txid) => txid,
|
||||||
|
|||||||
Reference in New Issue
Block a user