mirror of
https://github.com/Qortal/piratewallet-light-cli.git
synced 2025-02-15 19:35:46 +00:00
Fetch all txns in a block
This commit is contained in:
parent
6033c531bd
commit
225db64240
@ -20,7 +20,6 @@ hex = "0.3"
|
|||||||
protobuf = "2"
|
protobuf = "2"
|
||||||
rustyline = "5.0.2"
|
rustyline = "5.0.2"
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
rand = "0.5.6"
|
|
||||||
json = "0.12.0"
|
json = "0.12.0"
|
||||||
shellwords = "1.0.0"
|
shellwords = "1.0.0"
|
||||||
tiny-bip39 = "0.6.2"
|
tiny-bip39 = "0.6.2"
|
||||||
@ -37,6 +36,7 @@ webpki = "0.19.1"
|
|||||||
webpki-roots = "0.16.0"
|
webpki-roots = "0.16.0"
|
||||||
tower-h2 = { git = "https://github.com/tower-rs/tower-h2" }
|
tower-h2 = { git = "https://github.com/tower-rs/tower-h2" }
|
||||||
rust-embed = "5.1.0"
|
rust-embed = "5.1.0"
|
||||||
|
rand = "0.7.2"
|
||||||
|
|
||||||
[dependencies.bellman]
|
[dependencies.bellman]
|
||||||
git = "https://github.com/adityapk00/librustzcash.git"
|
git = "https://github.com/adityapk00/librustzcash.git"
|
||||||
@ -72,8 +72,7 @@ features = ["ff_derive"]
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tower-grpc-build = { git = "https://github.com/tower-rs/tower-grpc", features = ["tower-hyper"] }
|
tower-grpc-build = { git = "https://github.com/tower-rs/tower-grpc", features = ["tower-hyper"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
rand_core = "0.5.1"
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = false
|
debug = false
|
@ -171,8 +171,8 @@ pub fn get_info(uri: http::Uri, no_cert: bool) -> Result<LightdInfo, String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn fetch_blocks<F : 'static + std::marker::Send>(uri: &http::Uri, start_height: u64, end_height: u64, no_cert: bool, c: F)
|
pub fn fetch_blocks<F : 'static + std::marker::Send>(uri: &http::Uri, start_height: u64, end_height: u64, no_cert: bool, mut c: F)
|
||||||
where F : Fn(&[u8]) {
|
where F : FnMut(&[u8], u64) {
|
||||||
let runner = make_grpc_client!(uri.scheme_str().unwrap(), uri.host().unwrap(), uri.port_part().unwrap(), no_cert)
|
let runner = make_grpc_client!(uri.scheme_str().unwrap(), uri.host().unwrap(), uri.port_part().unwrap(), no_cert)
|
||||||
.and_then(move |mut client| {
|
.and_then(move |mut client| {
|
||||||
let bs = BlockId{ height: start_height, hash: vec!()};
|
let bs = BlockId{ height: start_height, hash: vec!()};
|
||||||
@ -191,7 +191,7 @@ pub fn fetch_blocks<F : 'static + std::marker::Send>(uri: &http::Uri, start_heig
|
|||||||
let mut encoded_buf = vec![];
|
let mut encoded_buf = vec![];
|
||||||
|
|
||||||
b.encode(&mut encoded_buf).unwrap();
|
b.encode(&mut encoded_buf).unwrap();
|
||||||
c(&encoded_buf);
|
c(&encoded_buf, b.height);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -2,7 +2,9 @@ use crate::lightwallet::LightWallet;
|
|||||||
|
|
||||||
use log::{info, warn, error};
|
use log::{info, warn, error};
|
||||||
|
|
||||||
use std::sync::{Arc};
|
use rand::{rngs::OsRng, seq::SliceRandom};
|
||||||
|
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
use std::sync::atomic::{AtomicU64, AtomicI32, AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicU64, AtomicI32, AtomicUsize, Ordering};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -583,6 +585,11 @@ impl LightClient {
|
|||||||
|
|
||||||
let mut total_reorg = 0;
|
let mut total_reorg = 0;
|
||||||
|
|
||||||
|
// Collect all txns in blocks that we have a tx in. We'll fetch all these
|
||||||
|
// txs along with our own, so that the server doesn't learn which ones
|
||||||
|
// belong to us.
|
||||||
|
let all_new_txs = Arc::new(RwLock::new(vec![]));
|
||||||
|
|
||||||
// Fetch CompactBlocks in increments
|
// Fetch CompactBlocks in increments
|
||||||
loop {
|
loop {
|
||||||
let local_light_wallet = self.wallet.clone();
|
let local_light_wallet = self.wallet.clone();
|
||||||
@ -599,23 +606,26 @@ impl LightClient {
|
|||||||
|
|
||||||
// Fetch compact blocks
|
// Fetch compact blocks
|
||||||
info!("Fetching blocks {}-{}", start_height, end_height);
|
info!("Fetching blocks {}-{}", start_height, end_height);
|
||||||
|
let all_txs = all_new_txs.clone();
|
||||||
|
|
||||||
let last_invalid_height = Arc::new(AtomicI32::new(0));
|
let last_invalid_height = Arc::new(AtomicI32::new(0));
|
||||||
let last_invalid_height_inner = last_invalid_height.clone();
|
let last_invalid_height_inner = last_invalid_height.clone();
|
||||||
fetch_blocks(&self.get_server_uri(), start_height, end_height, self.config.no_cert_verification,
|
fetch_blocks(&self.get_server_uri(), start_height, end_height, self.config.no_cert_verification,
|
||||||
move |encoded_block: &[u8]| {
|
move |encoded_block: &[u8], height: u64| {
|
||||||
// Process the block only if there were no previous errors
|
// Process the block only if there were no previous errors
|
||||||
if last_invalid_height_inner.load(Ordering::SeqCst) > 0 {
|
if last_invalid_height_inner.load(Ordering::SeqCst) > 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match local_light_wallet.scan_block(encoded_block) {
|
match local_light_wallet.scan_block(encoded_block) {
|
||||||
Ok(_) => {},
|
Ok(block_txns) => {
|
||||||
|
all_txs.write().unwrap().copy_from_slice(&block_txns.iter().map(|txid| (txid.clone(), height as i32)).collect::<Vec<_>>()[..]);
|
||||||
|
},
|
||||||
Err(invalid_height) => {
|
Err(invalid_height) => {
|
||||||
// Block at this height seems to be invalid, so invalidate up till that point
|
// Block at this height seems to be invalid, so invalidate up till that point
|
||||||
last_invalid_height_inner.store(invalid_height, Ordering::SeqCst);
|
last_invalid_height_inner.store(invalid_height, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
local_bytes_downloaded.fetch_add(encoded_block.len(), Ordering::SeqCst);
|
local_bytes_downloaded.fetch_add(encoded_block.len(), Ordering::SeqCst);
|
||||||
});
|
});
|
||||||
@ -683,12 +693,16 @@ impl LightClient {
|
|||||||
|
|
||||||
// We need to first copy over the Txids from the wallet struct, because
|
// We need to first copy over the Txids from the wallet struct, because
|
||||||
// we need to free the read lock from here (Because we'll self.wallet.txs later)
|
// we need to free the read lock from here (Because we'll self.wallet.txs later)
|
||||||
let txids_to_fetch: Vec<(TxId, i32)> = self.wallet.txs.read().unwrap().values()
|
let mut txids_to_fetch: Vec<(TxId, i32)> = self.wallet.txs.read().unwrap().values()
|
||||||
.filter(|wtx| wtx.full_tx_scanned == false)
|
.filter(|wtx| wtx.full_tx_scanned == false)
|
||||||
.map(|wtx| (wtx.txid, wtx.block))
|
.map(|wtx| (wtx.txid, wtx.block))
|
||||||
.collect::<Vec<(TxId, i32)>>();
|
.collect::<Vec<(TxId, i32)>>();
|
||||||
|
|
||||||
info!("Fetching {} new txids", txids_to_fetch.len());
|
info!("Fetching {} new txids, along with {} decoy", txids_to_fetch.len(), all_new_txs.read().unwrap().len());
|
||||||
|
txids_to_fetch.extend_from_slice(&all_new_txs.read().unwrap()[..]);
|
||||||
|
|
||||||
|
let mut rng = OsRng;
|
||||||
|
txids_to_fetch.shuffle(&mut rng);
|
||||||
|
|
||||||
// And go and fetch the txids, getting the full transaction, so we can
|
// And go and fetch the txids, getting the full transaction, so we can
|
||||||
// read the memos
|
// read the memos
|
||||||
|
@ -5,6 +5,8 @@ use std::collections::{HashMap, HashSet};
|
|||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::io::{Error, ErrorKind};
|
use std::io::{Error, ErrorKind};
|
||||||
|
|
||||||
|
use rand::{Rng, rngs::OsRng};
|
||||||
|
|
||||||
use log::{info, warn, error};
|
use log::{info, warn, error};
|
||||||
|
|
||||||
use protobuf::parse_from_bytes;
|
use protobuf::parse_from_bytes;
|
||||||
@ -165,14 +167,12 @@ impl LightWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(seed_phrase: Option<String>, config: &LightClientConfig, latest_block: u64) -> io::Result<Self> {
|
pub fn new(seed_phrase: Option<String>, config: &LightClientConfig, latest_block: u64) -> io::Result<Self> {
|
||||||
use rand::{FromEntropy, ChaChaRng, Rng};
|
|
||||||
|
|
||||||
// This is the source entropy that corresponds to the 24-word seed phrase
|
// This is the source entropy that corresponds to the 24-word seed phrase
|
||||||
let mut seed_bytes = [0u8; 32];
|
let mut seed_bytes = [0u8; 32];
|
||||||
|
|
||||||
if seed_phrase.is_none() {
|
if seed_phrase.is_none() {
|
||||||
// Create a random seed.
|
// Create a random seed.
|
||||||
let mut system_rng = ChaChaRng::from_entropy();
|
let mut system_rng = OsRng;
|
||||||
system_rng.fill(&mut seed_bytes);
|
system_rng.fill(&mut seed_bytes);
|
||||||
} else {
|
} else {
|
||||||
seed_bytes.copy_from_slice(&Mnemonic::from_phrase(seed_phrase.expect("should have a seed phrase"),
|
seed_bytes.copy_from_slice(&Mnemonic::from_phrase(seed_phrase.expect("should have a seed phrase"),
|
||||||
@ -881,8 +881,8 @@ impl LightWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scan a block. Will return an error with the block height that failed to scan
|
// Scan a block. Will return an error with the block height that failed to scan
|
||||||
pub fn scan_block(&self, block: &[u8]) -> Result<(), i32> {
|
pub fn scan_block(&self, block_bytes: &[u8]) -> Result<Vec<TxId>, i32> {
|
||||||
let block: CompactBlock = match parse_from_bytes(block) {
|
let block: CompactBlock = match parse_from_bytes(block_bytes) {
|
||||||
Ok(block) => block,
|
Ok(block) => block,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Could not parse CompactBlock from bytes: {}", e);
|
error!("Could not parse CompactBlock from bytes: {}", e);
|
||||||
@ -900,7 +900,7 @@ impl LightWallet {
|
|||||||
return Err(height);
|
return Err(height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(())
|
return Ok(vec![]);
|
||||||
} else if height != (self.last_scanned_height() + 1) {
|
} else if height != (self.last_scanned_height() + 1) {
|
||||||
error!(
|
error!(
|
||||||
"Block is not height-sequential (expected {}, found {})",
|
"Block is not height-sequential (expected {}, found {})",
|
||||||
@ -978,7 +978,7 @@ impl LightWallet {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
scan_block(
|
scan_block(
|
||||||
block,
|
block.clone(),
|
||||||
&self.extfvks.read().unwrap(),
|
&self.extfvks.read().unwrap(),
|
||||||
&nf_refs[..],
|
&nf_refs[..],
|
||||||
&mut block_data.tree,
|
&mut block_data.tree,
|
||||||
@ -986,6 +986,18 @@ impl LightWallet {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// If this block had any new Txs, return the list of ALL txids in this block,
|
||||||
|
// so the wallet can fetch them all as a decoy.
|
||||||
|
let all_txs = if !new_txs.is_empty() {
|
||||||
|
block.vtx.iter().map(|vtx| {
|
||||||
|
let mut t = [0u8; 32];
|
||||||
|
t.copy_from_slice(&vtx.hash[..]);
|
||||||
|
TxId{0: t}
|
||||||
|
}).collect::<Vec<TxId>>()
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
for tx in new_txs {
|
for tx in new_txs {
|
||||||
// Mark notes as spent.
|
// Mark notes as spent.
|
||||||
let mut total_shielded_value_spent: u64 = 0;
|
let mut total_shielded_value_spent: u64 = 0;
|
||||||
@ -1023,9 +1035,7 @@ impl LightWallet {
|
|||||||
tx_entry.total_shielded_value_spent = total_shielded_value_spent;
|
tx_entry.total_shielded_value_spent = total_shielded_value_spent;
|
||||||
|
|
||||||
// Save notes.
|
// Save notes.
|
||||||
for output in tx
|
for output in tx.shielded_outputs
|
||||||
.shielded_outputs
|
|
||||||
.into_iter()
|
|
||||||
{
|
{
|
||||||
info!("Received sapling output");
|
info!("Received sapling output");
|
||||||
|
|
||||||
@ -1059,7 +1069,8 @@ impl LightWallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
|
Ok(all_txs)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_to_address(
|
pub fn send_to_address(
|
||||||
@ -1284,9 +1295,10 @@ impl LightWallet {
|
|||||||
pub mod tests {
|
pub mod tests {
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::io::{Error};
|
use std::io::{Error};
|
||||||
|
use rand::{RngCore, rngs::OsRng};
|
||||||
|
|
||||||
use ff::{Field, PrimeField, PrimeFieldRepr};
|
use ff::{Field, PrimeField, PrimeFieldRepr};
|
||||||
use pairing::bls12_381::Bls12;
|
use pairing::bls12_381::Bls12;
|
||||||
use rand_core::{RngCore, OsRng};
|
|
||||||
use protobuf::{Message, UnknownFields, CachedSize, RepeatedField};
|
use protobuf::{Message, UnknownFields, CachedSize, RepeatedField};
|
||||||
use zcash_client_backend::{encoding::encode_payment_address,
|
use zcash_client_backend::{encoding::encode_payment_address,
|
||||||
proto::compact_formats::{
|
proto::compact_formats::{
|
||||||
@ -1938,7 +1950,8 @@ pub mod tests {
|
|||||||
chain_name: "test".to_string(),
|
chain_name: "test".to_string(),
|
||||||
sapling_activation_height: 0,
|
sapling_activation_height: 0,
|
||||||
consensus_branch_id: "000000".to_string(),
|
consensus_branch_id: "000000".to_string(),
|
||||||
anchor_offset: 0
|
anchor_offset: 0,
|
||||||
|
no_cert_verification: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2860,7 +2873,8 @@ pub mod tests {
|
|||||||
chain_name: "main".to_string(),
|
chain_name: "main".to_string(),
|
||||||
sapling_activation_height: 0,
|
sapling_activation_height: 0,
|
||||||
consensus_branch_id: "000000".to_string(),
|
consensus_branch_id: "000000".to_string(),
|
||||||
anchor_offset: 1
|
anchor_offset: 1,
|
||||||
|
no_cert_verification: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let seed_phrase = Some("chimney better bulb horror rebuild whisper improve intact letter giraffe brave rib appear bulk aim burst snap salt hill sad merge tennis phrase raise".to_string());
|
let seed_phrase = Some("chimney better bulb horror rebuild whisper improve intact letter giraffe brave rib appear bulk aim burst snap salt hill sad merge tennis phrase raise".to_string());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user