mirror of
https://github.com/Qortal/piratewallet-light-cli.git
synced 2025-07-30 03:41:28 +00:00
Refactor sapling address generation based on chain
This commit is contained in:
@@ -6,7 +6,7 @@ use zcash_client_backend::encoding::{decode_payment_address, decode_transparent_
|
|||||||
use zcash_primitives::legacy::TransparentAddress;
|
use zcash_primitives::legacy::TransparentAddress;
|
||||||
|
|
||||||
use zcash_client_backend::constants::testnet::{
|
use zcash_client_backend::constants::testnet::{
|
||||||
B58_PUBKEY_ADDRESS_PREFIX, B58_SCRIPT_ADDRESS_PREFIX, HRP_SAPLING_PAYMENT_ADDRESS,
|
B58_PUBKEY_ADDRESS_PREFIX, B58_SCRIPT_ADDRESS_PREFIX,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An address that funds can be sent to.
|
/// An address that funds can be sent to.
|
||||||
@@ -28,9 +28,9 @@ impl From<TransparentAddress> for RecipientAddress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RecipientAddress {
|
impl RecipientAddress {
|
||||||
pub fn from_str(s: &str) -> Option<Self> {
|
pub fn from_str(s: &str, hrp_sapling_address: &str) -> Option<Self> {
|
||||||
// Try to match a sapling z address
|
// Try to match a sapling z address
|
||||||
if let Some(pa) = match decode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, s) {
|
if let Some(pa) = match decode_payment_address(hrp_sapling_address, s) {
|
||||||
Ok(ret) => ret,
|
Ok(ret) => ret,
|
||||||
Err(_) => None
|
Err(_) => None
|
||||||
}
|
}
|
||||||
|
@@ -16,7 +16,7 @@ use json::{object, JsonValue};
|
|||||||
use zcash_primitives::transaction::{TxId, Transaction};
|
use zcash_primitives::transaction::{TxId, Transaction};
|
||||||
use zcash_primitives::note_encryption::Memo;
|
use zcash_primitives::note_encryption::Memo;
|
||||||
use zcash_client_backend::{
|
use zcash_client_backend::{
|
||||||
constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS, encoding::encode_payment_address,
|
constants::testnet, constants::mainnet, constants::regtest, encoding::encode_payment_address,
|
||||||
};
|
};
|
||||||
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
@@ -97,6 +97,16 @@ impl LightClientConfig {
|
|||||||
log_path.into_boxed_path()
|
log_path.into_boxed_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_initial_state(&self) -> Option<(u64, &str, &str)> {
|
||||||
|
match &self.chain_name[..] {
|
||||||
|
"test" => Some((600000,
|
||||||
|
"0107385846c7451480912c294b6ce1ee1feba6c2619079fd9104f6e71e4d8fe7",
|
||||||
|
"01690698411e3f8badea7da885e556d7aba365a797e9b20b44ac0946dced14b23c001001ab2a18a5a86aa5d77e43b69071b21770b6fe6b3c26304dcaf7f96c0bb3fed74d000186482712fa0f2e5aa2f2700c4ed49ef360820f323d34e2b447b78df5ec4dfa0401a332e89a21afb073cb1db7d6f07396b56a95e97454b9bca5a63d0ebc575d3a33000000000001c9d3564eff54ebc328eab2e4f1150c3637f4f47516f879a0cfebdf49fe7b1d5201c104705fac60a85596010e41260d07f3a64f38f37a112eaef41cd9d736edc5270145e3d4899fcd7f0f1236ae31eafb3f4b65ad6b11a17eae1729cec09bd3afa01a000000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
|
||||||
|
)),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_server_or_default(server: Option<String>) -> String {
|
pub fn get_server_or_default(server: Option<String>) -> String {
|
||||||
match server {
|
match server {
|
||||||
Some(s) => if s.starts_with("http://") {s} else { "http://".to_string() + &s}
|
Some(s) => if s.starts_with("http://") {s} else { "http://".to_string() + &s}
|
||||||
@@ -104,6 +114,15 @@ impl LightClientConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hrp_sapling_address(&self) -> &str {
|
||||||
|
match &self.chain_name[..] {
|
||||||
|
"main" => mainnet::HRP_SAPLING_PAYMENT_ADDRESS,
|
||||||
|
"test" => testnet::HRP_SAPLING_PAYMENT_ADDRESS,
|
||||||
|
"regtest" => regtest::HRP_SAPLING_PAYMENT_ADDRESS,
|
||||||
|
c => panic!("Unknown chain {}", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LightClient {
|
pub struct LightClient {
|
||||||
@@ -119,9 +138,14 @@ pub struct LightClient {
|
|||||||
impl LightClient {
|
impl LightClient {
|
||||||
|
|
||||||
pub fn set_wallet_initial_state(&self) {
|
pub fn set_wallet_initial_state(&self) {
|
||||||
self.wallet.set_initial_block(600000,
|
use std::convert::TryInto;
|
||||||
"0107385846c7451480912c294b6ce1ee1feba6c2619079fd9104f6e71e4d8fe7",
|
|
||||||
"01690698411e3f8badea7da885e556d7aba365a797e9b20b44ac0946dced14b23c001001ab2a18a5a86aa5d77e43b69071b21770b6fe6b3c26304dcaf7f96c0bb3fed74d000186482712fa0f2e5aa2f2700c4ed49ef360820f323d34e2b447b78df5ec4dfa0401a332e89a21afb073cb1db7d6f07396b56a95e97454b9bca5a63d0ebc575d3a33000000000001c9d3564eff54ebc328eab2e4f1150c3637f4f47516f879a0cfebdf49fe7b1d5201c104705fac60a85596010e41260d07f3a64f38f37a112eaef41cd9d736edc5270145e3d4899fcd7f0f1236ae31eafb3f4b65ad6b11a17eae1729cec09bd3afa01a000000011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39");
|
let state = self.config.get_initial_state();
|
||||||
|
|
||||||
|
match state {
|
||||||
|
Some((height, hash, tree)) => self.wallet.set_initial_block(height.try_into().unwrap(), hash, tree),
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(seed_phrase: Option<String>, config: &LightClientConfig) -> io::Result<Self> {
|
pub fn new(seed_phrase: Option<String>, config: &LightClientConfig) -> io::Result<Self> {
|
||||||
@@ -134,7 +158,7 @@ impl LightClient {
|
|||||||
|
|
||||||
let mut file_buffer = BufReader::new(File::open(config.get_wallet_path())?);
|
let mut file_buffer = BufReader::new(File::open(config.get_wallet_path())?);
|
||||||
|
|
||||||
let wallet = LightWallet::read(&mut file_buffer)?;
|
let wallet = LightWallet::read(&mut file_buffer, config)?;
|
||||||
LightClient {
|
LightClient {
|
||||||
wallet : Arc::new(wallet),
|
wallet : Arc::new(wallet),
|
||||||
config : config.clone(),
|
config : config.clone(),
|
||||||
@@ -143,7 +167,7 @@ impl LightClient {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let l = LightClient {
|
let l = LightClient {
|
||||||
wallet : Arc::new(LightWallet::new(seed_phrase)?),
|
wallet : Arc::new(LightWallet::new(seed_phrase, config)?),
|
||||||
config : config.clone(),
|
config : config.clone(),
|
||||||
sapling_output : vec![],
|
sapling_output : vec![],
|
||||||
sapling_spend : vec![]
|
sapling_spend : vec![]
|
||||||
@@ -183,7 +207,7 @@ impl LightClient {
|
|||||||
pub fn do_address(&self) -> json::JsonValue {
|
pub fn do_address(&self) -> json::JsonValue {
|
||||||
// Collect z addresses
|
// Collect z addresses
|
||||||
let z_addresses = self.wallet.address.iter().map( |ad| {
|
let z_addresses = self.wallet.address.iter().map( |ad| {
|
||||||
encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &ad)
|
encode_payment_address(self.config.hrp_sapling_address(), &ad)
|
||||||
}).collect::<Vec<String>>();
|
}).collect::<Vec<String>>();
|
||||||
|
|
||||||
// Collect t addresses
|
// Collect t addresses
|
||||||
@@ -200,7 +224,7 @@ impl LightClient {
|
|||||||
pub fn do_balance(&self) -> json::JsonValue {
|
pub fn do_balance(&self) -> json::JsonValue {
|
||||||
// Collect z addresses
|
// Collect z addresses
|
||||||
let z_addresses = self.wallet.address.iter().map( |ad| {
|
let z_addresses = self.wallet.address.iter().map( |ad| {
|
||||||
let address = encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &ad);
|
let address = encode_payment_address(self.config.hrp_sapling_address(), &ad);
|
||||||
object!{
|
object!{
|
||||||
"address" => address.clone(),
|
"address" => address.clone(),
|
||||||
"zbalance" => self.wallet.zbalance(Some(address.clone())),
|
"zbalance" => self.wallet.zbalance(Some(address.clone())),
|
||||||
@@ -296,7 +320,7 @@ impl LightClient {
|
|||||||
"created_in_txid" => format!("{}", txid),
|
"created_in_txid" => format!("{}", txid),
|
||||||
"value" => nd.note.value,
|
"value" => nd.note.value,
|
||||||
"is_change" => nd.is_change,
|
"is_change" => nd.is_change,
|
||||||
"address" => nd.note_address(),
|
"address" => self.wallet.note_address(nd),
|
||||||
"spent" => nd.spent.map(|spent_txid| format!("{}", spent_txid)),
|
"spent" => nd.spent.map(|spent_txid| format!("{}", spent_txid)),
|
||||||
"unconfirmed_spent" => nd.unconfirmed_spent.map(|spent_txid| format!("{}", spent_txid)),
|
"unconfirmed_spent" => nd.unconfirmed_spent.map(|spent_txid| format!("{}", spent_txid)),
|
||||||
})
|
})
|
||||||
@@ -418,7 +442,7 @@ impl LightClient {
|
|||||||
"block_height" => v.block,
|
"block_height" => v.block,
|
||||||
"txid" => format!("{}", v.txid),
|
"txid" => format!("{}", v.txid),
|
||||||
"amount" => nd.note.value as i64,
|
"amount" => nd.note.value as i64,
|
||||||
"address" => nd.note_address().unwrap(),
|
"address" => self.wallet.note_address(nd),
|
||||||
"memo" => match &nd.memo {
|
"memo" => match &nd.memo {
|
||||||
Some(memo) => {
|
Some(memo) => {
|
||||||
match memo.to_utf8() {
|
match memo.to_utf8() {
|
||||||
|
@@ -4,11 +4,6 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|||||||
use pairing::bls12_381::{Bls12};
|
use pairing::bls12_381::{Bls12};
|
||||||
use ff::{PrimeField, PrimeFieldRepr};
|
use ff::{PrimeField, PrimeFieldRepr};
|
||||||
|
|
||||||
use zcash_client_backend::{
|
|
||||||
constants::testnet::{HRP_SAPLING_PAYMENT_ADDRESS,},
|
|
||||||
encoding::encode_payment_address,
|
|
||||||
};
|
|
||||||
|
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
block::BlockHash,
|
block::BlockHash,
|
||||||
merkle_tree::{CommitmentTree, IncrementalWitness},
|
merkle_tree::{CommitmentTree, IncrementalWitness},
|
||||||
@@ -239,12 +234,6 @@ impl SaplingNoteData {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn note_address(&self) -> Option<String> {
|
|
||||||
match self.extfvk.fvk.vk.into_payment_address(self.diversifier, &JUBJUB) {
|
|
||||||
Some(pa) => Some(encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &pa)),
|
|
||||||
None => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@@ -14,7 +14,7 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
|||||||
use pairing::bls12_381::{Bls12};
|
use pairing::bls12_381::{Bls12};
|
||||||
|
|
||||||
use zcash_client_backend::{
|
use zcash_client_backend::{
|
||||||
constants::testnet::{HRP_SAPLING_PAYMENT_ADDRESS,B58_PUBKEY_ADDRESS_PREFIX,},
|
constants::testnet::{B58_PUBKEY_ADDRESS_PREFIX,},
|
||||||
encoding::encode_payment_address,
|
encoding::encode_payment_address,
|
||||||
proto::compact_formats::CompactBlock, welding_rig::scan_block,
|
proto::compact_formats::CompactBlock, welding_rig::scan_block,
|
||||||
};
|
};
|
||||||
@@ -35,21 +35,21 @@ use zcash_primitives::{
|
|||||||
primitives::{PaymentAddress},
|
primitives::{PaymentAddress},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod data;
|
|
||||||
pub mod extended_key;
|
|
||||||
|
|
||||||
use data::{BlockData, WalletTx, Utxo, SaplingNoteData, SpendableNote};
|
use data::{BlockData, WalletTx, Utxo, SaplingNoteData, SpendableNote};
|
||||||
|
|
||||||
use crate::address;
|
use crate::address;
|
||||||
use crate::prover;
|
use crate::prover;
|
||||||
|
use crate::LightClientConfig;
|
||||||
|
|
||||||
use sha2::{Sha256, Digest};
|
use sha2::{Sha256, Digest};
|
||||||
|
|
||||||
|
|
||||||
const ANCHOR_OFFSET: u32 = 1;
|
|
||||||
|
|
||||||
const SAPLING_ACTIVATION_HEIGHT: i32 = 280_000;
|
pub mod data;
|
||||||
|
pub mod extended_key;
|
||||||
|
|
||||||
|
|
||||||
|
const ANCHOR_OFFSET: u32 = 1;
|
||||||
|
|
||||||
fn now() -> f64 {
|
fn now() -> f64 {
|
||||||
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as f64
|
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() as f64
|
||||||
@@ -122,6 +122,9 @@ pub struct LightWallet {
|
|||||||
|
|
||||||
blocks: Arc<RwLock<Vec<BlockData>>>,
|
blocks: Arc<RwLock<Vec<BlockData>>>,
|
||||||
pub txs: Arc<RwLock<HashMap<TxId, WalletTx>>>,
|
pub txs: Arc<RwLock<HashMap<TxId, WalletTx>>>,
|
||||||
|
|
||||||
|
// Non-serialized fields
|
||||||
|
config: LightClientConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LightWallet {
|
impl LightWallet {
|
||||||
@@ -145,7 +148,7 @@ impl LightWallet {
|
|||||||
(extsk, extfvk, address)
|
(extsk, extfvk, address)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(seed_phrase: Option<String>) -> io::Result<Self> {
|
pub fn new(seed_phrase: Option<String>, config: &LightClientConfig) -> io::Result<Self> {
|
||||||
use rand::{FromEntropy, ChaChaRng, Rng};
|
use rand::{FromEntropy, ChaChaRng, Rng};
|
||||||
|
|
||||||
let mut seed_bytes = [0u8; 32];
|
let mut seed_bytes = [0u8; 32];
|
||||||
@@ -176,12 +179,13 @@ impl LightWallet {
|
|||||||
tkeys: vec![tpk],
|
tkeys: vec![tpk],
|
||||||
blocks: Arc::new(RwLock::new(vec![])),
|
blocks: Arc::new(RwLock::new(vec![])),
|
||||||
txs: Arc::new(RwLock::new(HashMap::new())),
|
txs: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
config: config.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
pub fn read<R: Read>(mut reader: R, config: &LightClientConfig) -> io::Result<Self> {
|
||||||
let version = reader.read_u64::<LittleEndian>()?;
|
let version = reader.read_u64::<LittleEndian>()?;
|
||||||
assert_eq!(version, LightWallet::serialized_version());
|
assert!(version <= LightWallet::serialized_version());
|
||||||
info!("Reading wallet version {}", version);
|
info!("Reading wallet version {}", version);
|
||||||
|
|
||||||
// Seed
|
// Seed
|
||||||
@@ -220,7 +224,8 @@ impl LightWallet {
|
|||||||
address: addresses,
|
address: addresses,
|
||||||
tkeys: vec![tpk],
|
tkeys: vec![tpk],
|
||||||
blocks: Arc::new(RwLock::new(blocks)),
|
blocks: Arc::new(RwLock::new(blocks)),
|
||||||
txs: Arc::new(RwLock::new(txs))
|
txs: Arc::new(RwLock::new(txs)),
|
||||||
|
config: config.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +256,12 @@ impl LightWallet {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn note_address(&self, note: &SaplingNoteData) -> Option<String> {
|
||||||
|
match note.extfvk.fvk.vk.into_payment_address(note.diversifier, &JUBJUB) {
|
||||||
|
Some(pa) => Some(encode_payment_address(self.config.hrp_sapling_address(), &pa)),
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clears all the downloaded blocks and resets the state back to the inital block.
|
// Clears all the downloaded blocks and resets the state back to the inital block.
|
||||||
// After this, the wallet's initial state will need to be set
|
// After this, the wallet's initial state will need to be set
|
||||||
@@ -315,12 +325,10 @@ impl LightWallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn last_scanned_height(&self) -> i32 {
|
pub fn last_scanned_height(&self) -> i32 {
|
||||||
self.blocks
|
self.blocks.read().unwrap()
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.last()
|
.last()
|
||||||
.map(|block| block.height)
|
.map(|block| block.height)
|
||||||
.unwrap_or(SAPLING_ACTIVATION_HEIGHT - 1)
|
.unwrap_or(self.config.sapling_activation_height as i32 - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines the target height for a transaction, and the offset from which to
|
/// Determines the target height for a transaction, and the offset from which to
|
||||||
@@ -382,7 +390,7 @@ impl LightWallet {
|
|||||||
.filter(|nd| { // TODO, this whole section is shared with verified_balance. Refactor it.
|
.filter(|nd| { // TODO, this whole section is shared with verified_balance. Refactor it.
|
||||||
match addr.clone() {
|
match addr.clone() {
|
||||||
Some(a) => a == encode_payment_address(
|
Some(a) => a == encode_payment_address(
|
||||||
HRP_SAPLING_PAYMENT_ADDRESS,
|
self.config.hrp_sapling_address(),
|
||||||
&nd.extfvk.fvk.vk
|
&nd.extfvk.fvk.vk
|
||||||
.into_payment_address(nd.diversifier, &JUBJUB).unwrap()
|
.into_payment_address(nd.diversifier, &JUBJUB).unwrap()
|
||||||
),
|
),
|
||||||
@@ -436,7 +444,7 @@ impl LightWallet {
|
|||||||
.filter(|nd| { // TODO, this whole section is shared with verified_balance. Refactor it.
|
.filter(|nd| { // TODO, this whole section is shared with verified_balance. Refactor it.
|
||||||
match addr.clone() {
|
match addr.clone() {
|
||||||
Some(a) => a == encode_payment_address(
|
Some(a) => a == encode_payment_address(
|
||||||
HRP_SAPLING_PAYMENT_ADDRESS,
|
self.config.hrp_sapling_address(),
|
||||||
&nd.extfvk.fvk.vk
|
&nd.extfvk.fvk.vk
|
||||||
.into_payment_address(nd.diversifier, &JUBJUB).unwrap()
|
.into_payment_address(nd.diversifier, &JUBJUB).unwrap()
|
||||||
),
|
),
|
||||||
@@ -598,7 +606,7 @@ impl LightWallet {
|
|||||||
// This could be a chane or an outgoing transaction
|
// This could be a chane or an outgoing transaction
|
||||||
println!("Recovered outgoing for {} to {} :{:?}",
|
println!("Recovered outgoing for {} to {} :{:?}",
|
||||||
note.value,
|
note.value,
|
||||||
encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &address),
|
encode_payment_address(self.config.hrp_sapling_address(), &address),
|
||||||
memo.to_utf8())
|
memo.to_utf8())
|
||||||
},
|
},
|
||||||
None => {}
|
None => {}
|
||||||
@@ -787,7 +795,7 @@ impl LightWallet {
|
|||||||
let extfvk = &self.extfvks[0];
|
let extfvk = &self.extfvks[0];
|
||||||
let ovk = extfvk.fvk.ovk;
|
let ovk = extfvk.fvk.ovk;
|
||||||
|
|
||||||
let to = match address::RecipientAddress::from_str(to) {
|
let to = match address::RecipientAddress::from_str(to, self.config.hrp_sapling_address()) {
|
||||||
Some(to) => to,
|
Some(to) => to,
|
||||||
None => {
|
None => {
|
||||||
eprintln!("Invalid recipient address");
|
eprintln!("Invalid recipient address");
|
||||||
|
Reference in New Issue
Block a user