Unified viewing keys
This commit is contained in:
parent
25a2e28e74
commit
74a6310784
11
binding.h
11
binding.h
|
@ -44,6 +44,11 @@ typedef struct CResult_u64 {
|
|||
char *error;
|
||||
} CResult_u64;
|
||||
|
||||
typedef struct CResult {
|
||||
char value; // dummy
|
||||
char *error;
|
||||
} CResult;
|
||||
|
||||
void dummy_export(void);
|
||||
|
||||
void dart_post_cobject(DartPostCObjectFnType ptr);
|
||||
|
@ -68,6 +73,10 @@ struct CResult_u32 new_account(uint8_t coin, char *name, char *data, int32_t ind
|
|||
|
||||
void new_sub_account(char *name, int32_t index, uint32_t count);
|
||||
|
||||
CResult convert_to_watchonly(uint8_t coin, uint32_t id_account);
|
||||
|
||||
struct CResult_____c_char get_backup(uint8_t coin, uint32_t id_account);
|
||||
|
||||
struct CResult_____c_char get_address(uint8_t coin, uint32_t id_account, uint8_t ua_type);
|
||||
|
||||
void import_transparent_key(uint8_t coin, uint32_t id_account, char *path);
|
||||
|
@ -115,7 +124,7 @@ struct CResult_____c_char prepare_multi_payment(uint8_t coin,
|
|||
|
||||
struct CResult_____c_char transaction_report(uint8_t coin, char *plan);
|
||||
|
||||
struct CResult_____c_char sign(uint8_t coin, uint32_t account, char *tx, int64_t port);
|
||||
struct CResult_____c_char sign(uint8_t coin, uint32_t account, char *tx, int64_t _port);
|
||||
|
||||
struct CResult_____c_char sign_and_broadcast(uint8_t coin, uint32_t account, char *tx_plan);
|
||||
|
||||
|
|
|
@ -5,18 +5,23 @@
|
|||
use crate::coinconfig::CoinConfig;
|
||||
use crate::db::AccountData;
|
||||
use crate::key2::decode_key;
|
||||
use crate::orchard::OrchardKeyBytes;
|
||||
use crate::taddr::{derive_taddr, derive_tkeys};
|
||||
use crate::transaction::retrieve_tx_info;
|
||||
use crate::unified::UnifiedAddressType;
|
||||
use crate::zip32::derive_zip32;
|
||||
use crate::{connect_lightwalletd, AccountInfo, KeyPack};
|
||||
use crate::{AccountInfo, KeyPack};
|
||||
use anyhow::anyhow;
|
||||
use bip39::{Language, Mnemonic};
|
||||
use orchard::keys::{FullViewingKey, Scope};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::RngCore;
|
||||
use serde::Serialize;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use zcash_address::unified::{Address as UA, Receiver};
|
||||
use zcash_address::{ToAddress, ZcashAddress};
|
||||
use zcash_client_backend::encoding::{decode_extended_full_viewing_key, encode_payment_address};
|
||||
use zcash_client_backend::keys::UnifiedFullViewingKey;
|
||||
use zcash_primitives::consensus::Parameters;
|
||||
|
||||
/// Create a new account
|
||||
|
@ -77,7 +82,7 @@ pub fn new_sub_account(name: &str, index: Option<u32>, count: u32) -> anyhow::Re
|
|||
|
||||
fn new_account_with_key(coin: u8, name: &str, key: &str, index: u32) -> anyhow::Result<u32> {
|
||||
let c = CoinConfig::get(coin);
|
||||
let (seed, sk, ivk, pa) = decode_key(coin, key, index)?;
|
||||
let (seed, sk, ivk, pa, ofvk) = decode_key(coin, key, index)?;
|
||||
let db = c.db()?;
|
||||
let account = db.get_account_id(&ivk)?;
|
||||
let account = match account {
|
||||
|
@ -89,7 +94,14 @@ fn new_account_with_key(coin: u8, name: &str, key: &str, index: u32) -> anyhow::
|
|||
db.create_taddr(account)?;
|
||||
}
|
||||
if c.chain.has_unified() {
|
||||
db.create_orchard(account)?;
|
||||
match ofvk {
|
||||
Some(fvk) => {
|
||||
db.store_orchard_fvk(account, &fvk.to_bytes())?;
|
||||
}
|
||||
None => {
|
||||
db.create_orchard(account)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
db.store_ua_settings(account, false, true, c.chain.has_unified())?;
|
||||
account
|
||||
|
@ -98,6 +110,50 @@ fn new_account_with_key(coin: u8, name: &str, key: &str, index: u32) -> anyhow::
|
|||
Ok(account)
|
||||
}
|
||||
|
||||
pub fn convert_to_watchonly(coin: u8, id_account: u32) -> anyhow::Result<()> {
|
||||
let c = CoinConfig::get(coin);
|
||||
let db = c.db()?;
|
||||
db.convert_to_watchonly(id_account)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_backup_package(coin: u8, id_account: u32) -> anyhow::Result<Backup> {
|
||||
let c = CoinConfig::get(coin);
|
||||
let network = c.chain.network();
|
||||
let db = c.db()?;
|
||||
let AccountData {
|
||||
name,
|
||||
seed,
|
||||
sk,
|
||||
fvk,
|
||||
aindex,
|
||||
..
|
||||
} = db.get_account_info(id_account)?;
|
||||
let orchard_keys = db.get_orchard(id_account)?;
|
||||
let fvk = match orchard_keys {
|
||||
None => fvk,
|
||||
Some(OrchardKeyBytes { fvk: ofvk, .. }) => {
|
||||
// orchard sk is not serializable and must derived from seed
|
||||
let sapling_efvk = decode_extended_full_viewing_key(
|
||||
network.hrp_sapling_extended_full_viewing_key(),
|
||||
&fvk,
|
||||
)
|
||||
.unwrap();
|
||||
let sapling_dfvk = sapling_efvk.to_diversifiable_full_viewing_key();
|
||||
let orchard_fvk = orchard::keys::FullViewingKey::from_bytes(&ofvk);
|
||||
let ufvk = UnifiedFullViewingKey::new(Some(sapling_dfvk), orchard_fvk).unwrap();
|
||||
ufvk.encode(network)
|
||||
}
|
||||
};
|
||||
Ok(Backup {
|
||||
name,
|
||||
seed,
|
||||
index: aindex,
|
||||
sk,
|
||||
ivk: fvk,
|
||||
})
|
||||
}
|
||||
|
||||
/// Update the transparent secret key for the given account from a derivation path
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -146,8 +202,26 @@ pub fn new_diversified_address() -> anyhow::Result<String> {
|
|||
.find_address(diversifier_index)
|
||||
.ok_or_else(|| anyhow::anyhow!("Cannot generate new address"))?;
|
||||
db.store_diversifier(c.id_account, &new_diversifier_index)?;
|
||||
let pa = encode_payment_address(c.chain.network().hrp_sapling_payment_address(), &pa);
|
||||
Ok(pa)
|
||||
|
||||
let orchard_keys = db.get_orchard(c.id_account)?;
|
||||
let address = match orchard_keys {
|
||||
Some(orchard_keys) => {
|
||||
let orchard_fvk = FullViewingKey::from_bytes(&orchard_keys.fvk).unwrap();
|
||||
let index = diversifier_index.0; // any sapling index is fine for orchard
|
||||
let orchard_address = orchard_fvk.address_at(index, Scope::External);
|
||||
let unified_address = UA(vec![
|
||||
Receiver::Sapling(pa.to_bytes()),
|
||||
Receiver::Orchard(orchard_address.to_raw_address_bytes()),
|
||||
]);
|
||||
let address = ZcashAddress::from_unified(
|
||||
c.chain.network().address_network().unwrap(),
|
||||
unified_address,
|
||||
);
|
||||
address.encode()
|
||||
}
|
||||
None => encode_payment_address(c.chain.network().hrp_sapling_payment_address(), &pa),
|
||||
};
|
||||
Ok(address)
|
||||
}
|
||||
|
||||
/// Retrieve the transparent balance for the current account from the LWD server
|
||||
|
@ -256,7 +330,7 @@ pub fn import_from_zwl(coin: u8, name: &str, data: &str) -> anyhow::Result<()> {
|
|||
let db = c.db()?;
|
||||
for (i, key) in sks.iter().enumerate() {
|
||||
let name = format!("{}-{}", name, i + 1);
|
||||
let (seed, sk, ivk, pa) = decode_key(coin, key, 0)?;
|
||||
let (seed, sk, ivk, pa, _ufvk) = decode_key(coin, key, 0)?;
|
||||
db.store_account(&name, seed.as_deref(), 0, sk.as_deref(), &ivk, &pa)?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -351,3 +425,12 @@ pub fn decode_unified_address(coin: u8, address: &str) -> anyhow::Result<String>
|
|||
let res = crate::decode_unified_address(c.chain.network(), address)?;
|
||||
Ok(res.to_string())
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Backup {
|
||||
name: String,
|
||||
seed: Option<String>,
|
||||
index: u32,
|
||||
sk: Option<String>,
|
||||
ivk: String,
|
||||
}
|
||||
|
|
|
@ -175,6 +175,23 @@ pub unsafe extern "C" fn new_sub_account(name: *mut c_char, index: i32, count: u
|
|||
log_error(res)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn convert_to_watchonly(coin: u8, id_account: u32) -> CResult<()> {
|
||||
let res = crate::api::account::convert_to_watchonly(coin, id_account);
|
||||
to_cresult(res)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_backup(coin: u8, id_account: u32) -> CResult<*mut c_char> {
|
||||
let res = || {
|
||||
let backup = crate::api::account::get_backup_package(coin, id_account)?;
|
||||
let backup_str = serde_json::to_string(&backup)?;
|
||||
Ok::<_, anyhow::Error>(backup_str)
|
||||
};
|
||||
|
||||
to_cresult_str(res())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_address(
|
||||
coin: u8,
|
||||
|
@ -291,6 +308,7 @@ pub async unsafe extern "C" fn get_latest_height() -> CResult<u32> {
|
|||
to_cresult(height)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn report_progress(progress: Progress, port: i64) {
|
||||
if port != 0 {
|
||||
let progress = match progress.end() {
|
||||
|
@ -452,7 +470,7 @@ pub async unsafe extern "C" fn sign(
|
|||
coin: u8,
|
||||
account: u32,
|
||||
tx: *mut c_char,
|
||||
port: i64,
|
||||
_port: i64,
|
||||
) -> CResult<*mut c_char> {
|
||||
from_c_str!(tx);
|
||||
let res = async {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::api::account::get_unified_address;
|
||||
use crate::api::recipient::{RecipientMemo, RecipientShort};
|
||||
use crate::api::recipient::RecipientMemo;
|
||||
use crate::api::sync::get_latest_height;
|
||||
pub use crate::broadcast_tx;
|
||||
use crate::note_selection::{FeeFlat, FeeZIP327, Order, TransactionReport};
|
||||
use crate::note_selection::{FeeFlat, Order};
|
||||
use crate::{
|
||||
build_tx, fetch_utxos, get_secret_keys, note_selection, AccountData, CoinConfig, DbAdapter,
|
||||
TransactionBuilderConfig, TransactionBuilderError, TransactionPlan, TxBuilderContext,
|
||||
|
@ -12,9 +12,10 @@ use rand::rngs::OsRng;
|
|||
use std::cmp::min;
|
||||
use std::slice;
|
||||
use std::str::FromStr;
|
||||
use zcash_primitives::memo::{Memo, MemoBytes, TextMemo};
|
||||
use zcash_primitives::memo::{Memo, MemoBytes};
|
||||
use zcash_primitives::transaction::builder::Progress;
|
||||
|
||||
#[allow(dead_code)]
|
||||
type PaymentProgressCallback = Box<dyn Fn(Progress) + Send + Sync>;
|
||||
|
||||
pub async fn build_tx_plan(
|
||||
|
@ -29,7 +30,6 @@ pub async fn build_tx_plan(
|
|||
let (fvk, checkpoint_height) = {
|
||||
let db = c.db()?;
|
||||
let AccountData { fvk, .. } = db.get_account_info(account)?;
|
||||
let anchor_height = last_height.saturating_sub(confirmations);
|
||||
let checkpoint_height = get_checkpoint_height(&db, last_height, confirmations)?;
|
||||
(fvk, checkpoint_height)
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::db::ZMessage;
|
||||
use crate::{AccountData, CoinConfig};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Deserialize;
|
||||
use std::str::FromStr;
|
||||
use zcash_primitives::memo::Memo;
|
||||
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
use crate::coinconfig::CoinConfig;
|
||||
use crate::scan::{AMProgressCallback, Progress};
|
||||
use crate::sync::CTree;
|
||||
use crate::{AccountData, BlockId, ChainError, CompactTxStreamerClient, DbAdapter};
|
||||
use crate::{AccountData, BlockId, CompactTxStreamerClient, DbAdapter};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use tonic::transport::Channel;
|
||||
use tonic::Request;
|
||||
use zcash_primitives::sapling::Note;
|
||||
|
||||
const DEFAULT_CHUNK_SIZE: u32 = 100_000;
|
||||
|
||||
/// Asynchronously perform warp sync
|
||||
/// # Arguments
|
||||
/// * `coin`: 0 for zcash, 1 for ycash
|
||||
|
|
|
@ -62,6 +62,7 @@ pub fn init_coin(coin: u8, db_path: &str) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
/// Upgrade database schema for given coin and db path
|
||||
/// Used from ywallet
|
||||
pub fn migrate_coin(coin: u8, db_path: &str) -> anyhow::Result<()> {
|
||||
let chain = get_coin_chain(get_coin_type(coin));
|
||||
DbAdapter::migrate_db(chain.network(), db_path, chain.has_unified())?;
|
||||
|
|
30
src/db.rs
30
src/db.rs
|
@ -204,6 +204,18 @@ impl DbAdapter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn convert_to_watchonly(&self, id_account: u32) -> anyhow::Result<()> {
|
||||
self.connection.execute(
|
||||
"UPDATE accounts SET seed = NULL, sk = NULL WHERE id_account = ?1",
|
||||
params![id_account],
|
||||
)?;
|
||||
self.connection.execute(
|
||||
"UPDATE orchard_addrs SET sk = NULL WHERE account = ?1",
|
||||
params![id_account],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_sapling_fvks(&self) -> anyhow::Result<Vec<SaplingViewKey>> {
|
||||
let mut statement = self
|
||||
.connection
|
||||
|
@ -318,17 +330,17 @@ impl DbAdapter {
|
|||
sapling_tree.write(&mut sapling_bb)?;
|
||||
connection.execute(
|
||||
"INSERT INTO blocks(height, hash, timestamp)
|
||||
VALUES (?1, ?2, ?3)",
|
||||
VALUES (?1, ?2, ?3) ON CONFLICT DO NOTHING",
|
||||
params![height, hash, timestamp],
|
||||
)?;
|
||||
connection.execute(
|
||||
"INSERT INTO sapling_tree(height, tree) VALUES (?1, ?2)",
|
||||
"INSERT INTO sapling_tree(height, tree) VALUES (?1, ?2) ON CONFLICT DO NOTHING",
|
||||
params![height, &sapling_bb],
|
||||
)?;
|
||||
let mut orchard_bb: Vec<u8> = vec![];
|
||||
orchard_tree.write(&mut orchard_bb)?;
|
||||
connection.execute(
|
||||
"INSERT INTO orchard_tree(height, tree) VALUES (?1, ?2)",
|
||||
"INSERT INTO orchard_tree(height, tree) VALUES (?1, ?2) ON CONFLICT DO NOTHING",
|
||||
params![height, &orchard_bb],
|
||||
)?;
|
||||
log::debug!("-block");
|
||||
|
@ -859,6 +871,14 @@ impl DbAdapter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn store_orchard_fvk(&self, account: u32, fvk: &[u8; 96]) -> anyhow::Result<()> {
|
||||
self.connection.execute(
|
||||
"INSERT INTO orchard_addrs(account, sk, fvk) VALUES (?1, NULL, ?2) ON CONFLICT DO NOTHING",
|
||||
params![account, fvk],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn find_account_by_fvk(&self, fvk: &str) -> anyhow::Result<Option<u32>> {
|
||||
let account = self
|
||||
.connection
|
||||
|
@ -881,10 +901,10 @@ impl DbAdapter {
|
|||
"SELECT sk, fvk FROM orchard_addrs WHERE account = ?1",
|
||||
params![account],
|
||||
|row| {
|
||||
let sk: Vec<u8> = row.get(0)?;
|
||||
let sk: Option<Vec<u8>> = row.get(0)?;
|
||||
let fvk: Vec<u8> = row.get(1)?;
|
||||
Ok(OrchardKeyBytes {
|
||||
sk: sk.try_into().unwrap(),
|
||||
sk: sk.map(|sk| sk.try_into().unwrap()),
|
||||
fvk: fvk.try_into().unwrap(),
|
||||
})
|
||||
},
|
||||
|
|
|
@ -49,12 +49,14 @@ macro_rules! accumulate_scalar {
|
|||
};
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn pedersen_hash(depth: u8, left: &Hash, right: &Hash) -> Hash {
|
||||
let p = pedersen_hash_inner(depth, left, right);
|
||||
|
||||
p.to_affine().get_u().to_repr()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn pedersen_hash_inner(depth: u8, left: &Hash, right: &Hash) -> ExtendedPoint {
|
||||
let mut result = ExtendedPoint::identity();
|
||||
let mut bitoffset = 0;
|
||||
|
@ -116,6 +118,7 @@ pub fn pedersen_hash_inner(depth: u8, left: &Hash, right: &Hash) -> ExtendedPoin
|
|||
result
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn generator_multiplication(
|
||||
acc: &Fr,
|
||||
gens: &[ExtendedNielsPoint],
|
||||
|
|
33
src/key2.rs
33
src/key2.rs
|
@ -1,9 +1,11 @@
|
|||
use crate::coinconfig::CoinConfig;
|
||||
use anyhow::anyhow;
|
||||
use bip39::{Language, Mnemonic, Seed};
|
||||
use zcash_client_backend::encoding::{
|
||||
decode_extended_full_viewing_key, decode_extended_spending_key,
|
||||
encode_extended_full_viewing_key, encode_extended_spending_key, encode_payment_address,
|
||||
};
|
||||
use zcash_client_backend::keys::UnifiedFullViewingKey;
|
||||
use zcash_primitives::consensus::{Network, Parameters};
|
||||
use zcash_primitives::zip32::{ChildIndex, ExtendedFullViewingKey, ExtendedSpendingKey};
|
||||
|
||||
|
@ -11,26 +13,44 @@ pub fn decode_key(
|
|||
coin: u8,
|
||||
key: &str,
|
||||
index: u32,
|
||||
) -> anyhow::Result<(Option<String>, Option<String>, String, String)> {
|
||||
) -> anyhow::Result<(
|
||||
Option<String>,
|
||||
Option<String>,
|
||||
String,
|
||||
String,
|
||||
Option<orchard::keys::FullViewingKey>,
|
||||
)> {
|
||||
let c = CoinConfig::get(coin);
|
||||
let network = c.chain.network();
|
||||
let res = if let Ok(mnemonic) = Mnemonic::from_phrase(key, Language::English) {
|
||||
let (sk, ivk, pa) = derive_secret_key(network, &mnemonic, index)?;
|
||||
Ok((Some(key.to_string()), Some(sk), ivk, pa))
|
||||
Ok((Some(key.to_string()), Some(sk), ivk, pa, None))
|
||||
} else if let Ok(sk) =
|
||||
decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), key)
|
||||
{
|
||||
let (ivk, pa) = derive_viewing_key(network, &sk)?;
|
||||
Ok((None, Some(key.to_string()), ivk, pa))
|
||||
Ok((None, Some(key.to_string()), ivk, pa, None))
|
||||
} else if let Ok(fvk) =
|
||||
decode_extended_full_viewing_key(network.hrp_sapling_extended_full_viewing_key(), key)
|
||||
{
|
||||
let pa = derive_address(network, &fvk)?;
|
||||
Ok((None, None, key.to_string(), pa))
|
||||
Ok((None, None, key.to_string(), pa, None))
|
||||
} else if let Ok(ufvk) = UnifiedFullViewingKey::decode(network, key) {
|
||||
let sapling_dfvk = ufvk
|
||||
.sapling()
|
||||
.ok_or(anyhow!("UFVK must contain a sapling key"))?;
|
||||
let sapling_efvk =
|
||||
ExtendedFullViewingKey::from_diversifiable_full_viewing_key(&sapling_dfvk);
|
||||
let key = encode_extended_full_viewing_key(
|
||||
network.hrp_sapling_extended_full_viewing_key(),
|
||||
&sapling_efvk,
|
||||
);
|
||||
let pa = derive_address(network, &sapling_efvk)?;
|
||||
let orchard_key = ufvk.orchard().cloned();
|
||||
Ok((None, None, key, pa, orchard_key))
|
||||
} else {
|
||||
Err(anyhow::anyhow!("Not a valid key"))
|
||||
};
|
||||
// TODO: Accept UA viewing key
|
||||
res
|
||||
}
|
||||
|
||||
|
@ -49,6 +69,9 @@ pub fn is_valid_key(coin: u8, key: &str) -> i8 {
|
|||
{
|
||||
return 2;
|
||||
}
|
||||
if UnifiedFullViewingKey::decode(network, key).is_ok() {
|
||||
return 3;
|
||||
}
|
||||
// TODO: Accept UA viewing key
|
||||
-1
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
pub mod lw_rpc;
|
||||
|
||||
// Mainnet
|
||||
const LWD_URL: &str = "https://mainnet.lightwalletd.com:9067";
|
||||
// const LWD_URL: &str = "https://mainnet.lightwalletd.com:9067";
|
||||
// pub const LWD_URL: &str = "https://lwdv3.zecwallet.co";
|
||||
// pub const LWD_URL: &str = "http://lwd.hanh.me:9067";
|
||||
// pub const LWD_URL: &str = "http://127.0.0.1:9067";
|
||||
|
|
|
@ -10,15 +10,13 @@ use rocket::response::Responder;
|
|||
use rocket::serde::{json::Json, Deserialize, Serialize};
|
||||
use rocket::{response, Request, Response, State};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read};
|
||||
use std::sync::Mutex;
|
||||
use thiserror::Error;
|
||||
use warp_api_ffi::api::payment_uri::PaymentURI;
|
||||
use warp_api_ffi::api::recipient::{Recipient, RecipientMemo, RecipientShort};
|
||||
use warp_api_ffi::{
|
||||
build_tx, get_best_server, get_secret_keys, AccountData, AccountInfo, AccountRec, CoinConfig,
|
||||
KeyPack, RaptorQDrops, TransactionBuilderConfig, TransactionPlan, Tx, TxBuilderContext, TxRec,
|
||||
build_tx, get_secret_keys, AccountData, AccountInfo, AccountRec, CoinConfig, KeyPack,
|
||||
RaptorQDrops, TransactionPlan, TxRec,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
|
|
|
@ -10,7 +10,6 @@ use std::str::FromStr;
|
|||
pub use utxo::fetch_utxos;
|
||||
|
||||
use crate::api::recipient::Recipient;
|
||||
use optimize::{allocate_funds, fill, group_orders, outputs_for_change, select_inputs, sum_utxos};
|
||||
use thiserror::Error;
|
||||
use ua::decode;
|
||||
use zcash_primitives::memo::Memo;
|
||||
|
@ -37,6 +36,7 @@ mod utxo;
|
|||
|
||||
pub const MAX_ATTEMPTS: usize = 10;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn recipients_to_orders(recipients: &[Recipient]) -> Result<Vec<Order>> {
|
||||
let orders: Result<Vec<_>> = recipients
|
||||
.iter()
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
use super::decode;
|
||||
use super::types::*;
|
||||
use crate::coinconfig::get_prover;
|
||||
use crate::note_selection::fee::FeeFlat;
|
||||
use crate::note_selection::{build_tx_plan, fetch_utxos};
|
||||
use crate::orchard::{get_proving_key, OrchardHasher, ORCHARD_ROOTS};
|
||||
use crate::sapling::{SaplingHasher, SAPLING_ROOTS};
|
||||
use crate::sync::tree::TreeCheckpoint;
|
||||
use crate::sync::Witness;
|
||||
use crate::{broadcast_tx, init_coin, set_active, set_coin_lwd_url, AccountData, CoinConfig, Hash};
|
||||
use crate::{AccountData, CoinConfig};
|
||||
use anyhow::anyhow;
|
||||
use jubjub::Fr;
|
||||
use orchard::builder::Builder as OrchardBuilder;
|
||||
|
@ -16,7 +13,6 @@ use orchard::keys::{FullViewingKey, Scope, SpendAuthorizingKey, SpendingKey};
|
|||
use orchard::note::Nullifier;
|
||||
use orchard::value::NoteValue;
|
||||
use orchard::{Address, Anchor, Bundle};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use ripemd::{Digest, Ripemd160};
|
||||
use secp256k1::{All, PublicKey, Secp256k1, SecretKey};
|
||||
|
@ -25,7 +21,6 @@ use std::str::FromStr;
|
|||
use zcash_client_backend::encoding::decode_extended_spending_key;
|
||||
use zcash_primitives::consensus::{BlockHeight, BranchId, Network, Parameters};
|
||||
use zcash_primitives::legacy::TransparentAddress;
|
||||
use zcash_primitives::memo::MemoBytes;
|
||||
use zcash_primitives::merkle_tree::IncrementalWitness;
|
||||
use zcash_primitives::sapling::prover::TxProver;
|
||||
use zcash_primitives::sapling::{Diversifier, Node, PaymentAddress, Rseed};
|
||||
|
@ -292,7 +287,7 @@ pub fn get_secret_keys(coin: u8, account: u32) -> anyhow::Result<SecretKeys> {
|
|||
|
||||
let orchard_sk = db
|
||||
.get_orchard(account)?
|
||||
.map(|ob| SpendingKey::from_bytes(ob.sk).unwrap());
|
||||
.and_then(|ob| ob.sk.map(|sk| SpendingKey::from_bytes(sk).unwrap()));
|
||||
|
||||
let sk = SecretKeys {
|
||||
transparent: transparent_sk,
|
||||
|
@ -301,68 +296,3 @@ pub fn get_secret_keys(coin: u8, account: u32) -> anyhow::Result<SecretKeys> {
|
|||
};
|
||||
Ok(sk)
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn dummy_test() {
|
||||
let _ = env_logger::try_init();
|
||||
init_coin(0, "./zec.db").unwrap();
|
||||
set_coin_lwd_url(0, "http://127.0.0.1:9067");
|
||||
|
||||
let c = CoinConfig::get(0);
|
||||
log::info!("Start test");
|
||||
let height = {
|
||||
let db = c.db.as_ref().unwrap();
|
||||
let db = db.lock().unwrap();
|
||||
db.get_last_sync_height().unwrap().unwrap()
|
||||
};
|
||||
log::info!("Height {}", height);
|
||||
|
||||
const REGTEST_CHANGE: &str = "uregtest1mxy5wq2n0xw57nuxa4lqpl358zw4vzyfgadsn5jungttmqcv6nx6cpx465dtpzjzw0vprjle4j4nqqzxtkuzm93regvgg4xce0un5ec6tedquc469zjhtdpkxz04kunqqyasv4rwvcweh3ue0ku0payn29stl2pwcrghyzscrrju9ar57rn36wgz74nmynwcyw27rjd8yk477l97ez8";
|
||||
let mut config = TransactionBuilderConfig::new(REGTEST_CHANGE);
|
||||
|
||||
log::info!("Getting signing keys");
|
||||
let keys = get_secret_keys(0, 1).unwrap();
|
||||
|
||||
log::info!("Building signing context");
|
||||
let context = TxBuilderContext::from_height(0, height).unwrap();
|
||||
|
||||
log::info!("Getting available notes");
|
||||
let utxos = fetch_utxos(0, 1, height).await.unwrap();
|
||||
// let notes: Vec<_> = utxos.into_iter().filter(|utxo| utxo.source.pool() == Pool::Orchard).collect();
|
||||
|
||||
log::info!("Preparing outputs");
|
||||
let mut orders = vec![];
|
||||
orders.push(Order::new(
|
||||
1,
|
||||
"tmWXoSBwPoCjJCNZjw4P7heoVMcT2Ronrqq",
|
||||
10000,
|
||||
MemoBytes::empty(),
|
||||
));
|
||||
orders.push(Order::new(2, "zregtestsapling1qzy9wafd2axnenul6t6wav76dys6s8uatsq778mpmdvmx4k9myqxsd9m73aqdgc7gwnv53wga4j", 20000, MemoBytes::empty()));
|
||||
orders.push(Order::new(3, "uregtest1mzt5lx5s5u8kczlfr82av97kjckmfjfuq8y9849h6cl9chhdekxsm6r9dklracflqwplrnfzm5rucp5txfdm04z5myrde8y3y5rayev8", 30000, MemoBytes::empty()));
|
||||
orders.push(Order::new(4, "uregtest1yvucqfqnmq5ldc6fkvuudlsjhxg56hxph9ymmcnmpzpywd752ym8sr5l5d24wqn4enz3gakk6alf5hlpw2cjs3jjrcdae3nksrefyum5x400f9gs3ak9yllcr8czhrlnjufuuy7n5mh", 40000, MemoBytes::empty()));
|
||||
orders.push(Order::new(5, "uregtest1wqgc0cm50a7a647qrdglgj62fl40q8njsrcfkt2mzlsmj979rdmsdwuysypc6ewxjxz0zc48kmm35jwx4q6c4fgqwkmmqyhwlep4n2hc0229vf6cahcnesr38y7gyzfx6pa8zg9jvv9", 50000, MemoBytes::empty()));
|
||||
orders.push(Order::new(6, "uregtest1usu9eyxgqu48sa8lqug6ccjc7vcam3mt3a5t7jvyxj7pq5dgdtkjgkqzsyh9pfeav9970xddp2c9h5x44drwnz4f0zwc894k3vt380g6kfsg9j9fmnpljye9r56d94njsv40uaam392xvmky2v38dh3yhayz44z6xv402slujuhwy3mg", 60000, MemoBytes::empty()));
|
||||
orders.push(Order::new(7, "uregtest1mxy5wq2n0xw57nuxa4lqpl358zw4vzyfgadsn5jungttmqcv6nx6cpx465dtpzjzw0vprjle4j4nqqzxtkuzm93regvgg4xce0un5ec6tedquc469zjhtdpkxz04kunqqyasv4rwvcweh3ue0ku0payn29stl2pwcrghyzscrrju9ar57rn36wgz74nmynwcyw27rjd8yk477l97ez8", 70000, MemoBytes::empty()));
|
||||
|
||||
log::info!("Building tx plan");
|
||||
let tx_plan =
|
||||
build_tx_plan::<FeeFlat>("", 0, &Hash::default(), &utxos, &mut orders, &config).unwrap();
|
||||
log::info!("Plan: {}", serde_json::to_string(&tx_plan).unwrap());
|
||||
|
||||
log::info!("Building tx");
|
||||
let tx = build_tx(c.chain.network(), &keys, &tx_plan, OsRng).unwrap();
|
||||
println!("{}", hex::encode(&tx));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn submit_tx() {
|
||||
let _ = env_logger::try_init();
|
||||
init_coin(0, "./zec.db").unwrap();
|
||||
set_coin_lwd_url(0, "http://127.0.0.1:9067");
|
||||
set_active(0);
|
||||
let tx = "";
|
||||
|
||||
let r = broadcast_tx(&hex::decode(tx).unwrap()).await.unwrap();
|
||||
log::info!("{}", r);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ use crate::note_selection::TransactionBuilderError::TxTooComplex;
|
|||
use crate::note_selection::{TransactionBuilderError, MAX_ATTEMPTS};
|
||||
use crate::Hash;
|
||||
use anyhow::anyhow;
|
||||
use std::str::FromStr;
|
||||
use zcash_primitives::memo::{Memo, MemoBytes};
|
||||
use zcash_primitives::memo::MemoBytes;
|
||||
|
||||
pub fn sum_utxos(utxos: &[UTXO]) -> Result<PoolAllocation> {
|
||||
let mut pool = PoolAllocation::default();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::note_selection::types::{TransactionOutput, TransactionReport};
|
||||
use crate::note_selection::{Destination, Source};
|
||||
use crate::TransactionPlan;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::serde_as;
|
||||
|
|
|
@ -7,7 +7,6 @@ use serde::{Deserialize, Serialize};
|
|||
use serde_hex::{SerHex, Strict};
|
||||
use serde_with::serde_as;
|
||||
use zcash_client_backend::encoding::{encode_payment_address, AddressCodec};
|
||||
use zcash_params::coin::CoinType::Zcash;
|
||||
use zcash_primitives::consensus::{Network, Parameters};
|
||||
use zcash_primitives::legacy::TransparentAddress;
|
||||
use zcash_primitives::memo::MemoBytes;
|
||||
|
|
|
@ -3,7 +3,7 @@ use orchard::keys::{FullViewingKey, Scope, SpendingKey};
|
|||
use orchard::Address;
|
||||
|
||||
pub struct OrchardKeyBytes {
|
||||
pub sk: [u8; 32],
|
||||
pub sk: Option<[u8; 32]>,
|
||||
pub fvk: [u8; 96],
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ pub fn derive_orchard_keys(coin_type: u32, seed: &str, account_index: u32) -> Or
|
|||
let sk = SpendingKey::from_zip32_seed(seed.as_bytes(), coin_type, account_index).unwrap();
|
||||
let fvk = FullViewingKey::from(&sk);
|
||||
OrchardKeyBytes {
|
||||
sk: sk.to_bytes().clone(),
|
||||
sk: Some(sk.to_bytes().clone()),
|
||||
fvk: fvk.to_bytes(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,8 @@ use crate::db::ReceivedNote;
|
|||
use crate::sync::{
|
||||
CompactOutputBytes, DecryptedNote, Node, OutputPosition, TrialDecrypter, ViewKey,
|
||||
};
|
||||
use crate::{CompactTx, DbAdapterBuilder};
|
||||
use orchard::keys::Scope;
|
||||
use crate::CompactTx;
|
||||
use orchard::note_encryption::OrchardDomain;
|
||||
use zcash_note_encryption;
|
||||
use zcash_params::coin::CoinType;
|
||||
use zcash_primitives::consensus::{BlockHeight, Parameters};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
|
|
@ -91,11 +91,13 @@ pub struct RecipientSummary {
|
|||
pub amount: u64,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct TxBuilder {
|
||||
pub tx: Tx,
|
||||
coin_type: CoinType,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl TxBuilder {
|
||||
pub fn new(coin_type: CoinType, height: u32) -> Self {
|
||||
TxBuilder {
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::db::AccountViewKey;
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::chain::{download_chain, DecryptNode};
|
||||
use crate::transaction::{get_transaction_details, retrieve_tx_info, GetTransactionDetailRequest};
|
||||
use crate::transaction::get_transaction_details;
|
||||
use crate::{
|
||||
connect_lightwalletd, ChainError, CoinConfig, CompactBlock, CompactSaplingOutput, CompactTx,
|
||||
DbAdapterBuilder,
|
||||
|
@ -224,12 +224,6 @@ async fn sync_async_inner<'a>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn latest_height(ld_url: &str) -> anyhow::Result<u32> {
|
||||
let mut client = connect_lightwalletd(ld_url).await?;
|
||||
let height = get_latest_height(&mut client).await?;
|
||||
Ok(height)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
// test function
|
||||
pub fn trial_decrypt_one(
|
||||
|
|
|
@ -4,13 +4,11 @@ use crate::unified::orchard_as_unified;
|
|||
use crate::{AccountData, CoinConfig, CompactTxStreamerClient, DbAdapter, Hash, TxFilter};
|
||||
use orchard::keys::{FullViewingKey, IncomingViewingKey, OutgoingViewingKey, Scope};
|
||||
use orchard::note_encryption::OrchardDomain;
|
||||
use orchard::value::ValueCommitment;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use tonic::transport::Channel;
|
||||
use tonic::Request;
|
||||
use zcash_address::{ToAddress, ZcashAddress};
|
||||
use zcash_client_backend::encoding::{
|
||||
decode_extended_full_viewing_key, encode_payment_address, encode_transparent_address,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue