merged new updates

This commit is contained in:
DenioD
2019-10-20 23:12:03 +02:00
parent 457c3ea61e
commit 8c9523ad90
11 changed files with 1153 additions and 291 deletions

126
lib/src/lightwallet/bugs.rs Normal file
View File

@@ -0,0 +1,126 @@
///
/// In v1.0 of zecwallet-cli, there was a bug that incorrectly derived HD wallet keys after the first key. That is, the
/// first key, address was correct, but subsequent ones were not.
///
/// The issue was that the 32-byte seed was directly being used to derive then subsequent addresses instead of the
/// 64-byte pkdf2(seed). The issue affected both t and z addresses
///
/// To fix the bug, we need to:
/// 1. Check if the wallet has more than 1 address for t or z addresses
/// 2. Move any funds in these addresses to the first address
/// 3. Re-derive the addresses
use super::LightWallet;
use crate::lightclient::LightClient;
use json::object;
use bip39::{Mnemonic, Language};
pub struct BugBip39Derivation {}
impl BugBip39Derivation {
/// Check if this bug exists in the wallet
pub fn has_bug(client: &LightClient) -> bool {
let wallet = client.wallet.read().unwrap();
if wallet.zaddress.read().unwrap().len() <= 1 {
return false;
}
// The seed bytes is the raw entropy. To pass it to HD wallet generation,
// we need to get the 64 byte bip39 entropy
let bip39_seed = bip39::Seed::new(&Mnemonic::from_entropy(&wallet.seed, Language::English).unwrap(), "");
// Check z addresses
for pos in 0..wallet.zaddress.read().unwrap().len() {
let (_, _, address) =
LightWallet::get_zaddr_from_bip39seed(&wallet.config, &bip39_seed.as_bytes(), pos as u32);
if address != wallet.zaddress.read().unwrap()[pos] {
return true;
}
}
// Check t addresses
for pos in 0..wallet.taddresses.read().unwrap().len() {
let sk = LightWallet::get_taddr_from_bip39seed(&wallet.config, &bip39_seed.as_bytes(), pos as u32);
let address = wallet.address_from_sk(&sk);
if address != wallet.taddresses.read().unwrap()[pos] {
return true;
}
}
false
}
/// Automatically fix the bug if it exists in the wallet
pub fn fix_bug(client: &LightClient) -> String {
use zcash_primitives::transaction::components::amount::DEFAULT_FEE;
use std::convert::TryInto;
if !BugBip39Derivation::has_bug(client) {
let r = object!{
"has_bug" => false
};
return r.pretty(2);
}
// Tranfer money
// 1. The desination is z address #0
let zaddr = client.do_address()["z_addresses"][0].as_str().unwrap().to_string();
let balance_json = client.do_balance();
let fee: u64 = DEFAULT_FEE.try_into().unwrap();
let amount: u64 = balance_json["zbalance"].as_u64().unwrap()
+ balance_json["tbalance"].as_u64().unwrap()
- fee;
let txid = if amount > 0 {
match client.do_send(vec![(&zaddr, amount, None)]) {
Ok(txid) => txid,
Err(e) => {
let r = object!{
"has_bug" => true,
"fixed" => false,
"error" => e,
};
return r.pretty(2);
}
}
} else {
"".to_string()
};
// regen addresses
let wallet = client.wallet.read().unwrap();
let num_zaddrs = wallet.zaddress.read().unwrap().len();
let num_taddrs = wallet.taddresses.read().unwrap().len();
wallet.extsks.write().unwrap().truncate(1);
wallet.extfvks.write().unwrap().truncate(1);
wallet.zaddress.write().unwrap().truncate(1);
wallet.tkeys.write().unwrap().truncate(1);
wallet.taddresses.write().unwrap().truncate(1);
for _ in 1..num_zaddrs {
wallet.add_zaddr();
}
for _ in 1..num_taddrs {
wallet.add_taddr();
}
let r = object!{
"has_bug" => true,
"fixed" => true,
"txid" => txid,
};
return r.pretty(2);
}
}

View File

@@ -267,7 +267,7 @@ impl Utxo {
let mut address_bytes = vec![0; address_len as usize];
reader.read_exact(&mut address_bytes)?;
let address = String::from_utf8(address_bytes).unwrap();
assert_eq!(address.chars().take(1).collect::<Vec<char>>()[0], 'R');
assert_eq!(address.chars().take(1).collect::<Vec<char>>()[0], 't');
let mut txid_bytes = [0; 32];
reader.read_exact(&mut txid_bytes)?;
@@ -362,8 +362,12 @@ impl OutgoingTxMetadata {
}
pub struct WalletTx {
// Block in which this tx was included
pub block: i32,
// Timestamp of Tx. Added in v4
pub datetime: u64,
// Txid of this transaction. It's duplicated here (It is also the Key in the HashMap that points to this
// WalletTx in LightWallet::txs)
pub txid: TxId,
@@ -386,17 +390,19 @@ pub struct WalletTx {
// All outgoing sapling sends to addresses outside this wallet
pub outgoing_metadata: Vec<OutgoingTxMetadata>,
// Whether this TxID was downloaded from the server and scanned for Memos
pub full_tx_scanned: bool,
}
impl WalletTx {
pub fn serialized_version() -> u64 {
return 3;
return 4;
}
pub fn new(height: i32, txid: &TxId) -> Self {
pub fn new(height: i32, datetime: u64, txid: &TxId) -> Self {
WalletTx {
block: height,
datetime,
txid: txid.clone(),
notes: vec![],
utxos: vec![],
@@ -413,6 +419,12 @@ impl WalletTx {
let block = reader.read_i32::<LittleEndian>()?;
let datetime = if version >= 4 {
reader.read_u64::<LittleEndian>()?
} else {
0
};
let mut txid_bytes = [0u8; 32];
reader.read_exact(&mut txid_bytes)?;
@@ -431,6 +443,7 @@ impl WalletTx {
Ok(WalletTx{
block,
datetime,
txid,
notes,
utxos,
@@ -446,6 +459,8 @@ impl WalletTx {
writer.write_i32::<LittleEndian>(self.block)?;
writer.write_u64::<LittleEndian>(self.datetime)?;
writer.write_all(&self.txid.0)?;
Vector::write(&mut writer, &self.notes, |w, nd| nd.write(w))?;
@@ -475,7 +490,8 @@ pub struct SpendableNote {
impl SpendableNote {
pub fn from(txid: TxId, nd: &SaplingNoteData, anchor_offset: usize, extsk: &ExtendedSpendingKey) -> Option<Self> {
// Include only notes that haven't been spent, or haven't been included in an unconfirmed spend yet.
if nd.spent.is_none() && nd.unconfirmed_spent.is_none() {
if nd.spent.is_none() && nd.unconfirmed_spent.is_none() &&
nd.witnesses.len() >= (anchor_offset + 1) {
let witness = nd.witnesses.get(nd.witnesses.len() - anchor_offset - 1);
witness.map(|w| SpendableNote {

View File

@@ -0,0 +1,20 @@
pub fn report_permission_error() {
let user = std::env::var("USER").expect(
"Unexpected error reading value of $USER!");
let home = std::env::var("HOME").expect(
"Unexpected error reading value of $HOME!");
let current_executable = std::env::current_exe()
.expect("Unexpected error reporting executable path!");
eprintln!("USER: {}", user);
eprintln!("HOME: {}", home);
eprintln!("Executable: {}", current_executable.display());
if home == "/" {
eprintln!("User {} must have permission to write to '{}.komodo/HUSH3/' .",
user,
home);
} else {
eprintln!("User {} must have permission to write to '{}/.komodo/HUSH3/ .",
user,
home);
}
}