Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync integration balance methods #1632

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
490 changes: 248 additions & 242 deletions libtonode-tests/tests/concrete.rs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions libtonode-tests/tests/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ async fn sync_status() {
let lightclient = LightClient::create_from_wallet_base_async(
WalletBase::from_string(HOSPITAL_MUSEUM_SEED.to_string()),
&config,
2_750_000,
// 2_670_000,
// 2_750_000,
2_496_152,
true,
)
.await
Expand Down
550 changes: 276 additions & 274 deletions libtonode-tests/tests/wallet.rs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions zingo-sync/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name = "zingo-sync"
version = "0.1.0"
edition = "2021"

[features]
wallet_pack = []

[dependencies]
# Zingo
zingo-netutils = { path = "../zingo-netutils" }
Expand Down
6 changes: 4 additions & 2 deletions zingo-sync/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
//! Entrypoint: [`crate::sync::sync`]
//!
//! Terminology:
//! Chain height - highest block height of best chain from the server
//! Wallet height - highest block height of blockchain known to the wallet. Commonly used, to determine the chain height
//! Chain height - highest block height of best chain from the server.
//! Wallet height - highest block height of blockchain known to the wallet. Commonly used to determine the chain height
//! of the previous sync, before the server is contacted to update the wallet height to the new chain height.
//! Fully scanned height - block height in which the wallet has completed scanning all blocks equal to and below this height.

Expand All @@ -25,3 +25,5 @@ pub mod sync;
pub mod traits;
pub(crate) mod utils;
pub mod witness;

pub(crate) const MAX_BATCH_OUTPUTS: usize = 16_384; // 2^14
178 changes: 145 additions & 33 deletions zingo-sync/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ pub struct WalletBlock {
#[getset(skip)]
txids: Vec<TxId>,
tree_boundaries: TreeBoundaries,
// TODO: optional price
}

impl WalletBlock {
Expand Down Expand Up @@ -282,7 +283,9 @@ pub struct WalletTransaction {
#[getset(get = "pub")]
transaction: zcash_primitives::transaction::Transaction,
#[getset(get_copy = "pub")]
confirmation_status: ConfirmationStatus,
status: ConfirmationStatus,
#[getset(skip)]
transparent_coins: Vec<TransparentCoin>,
#[getset(skip)]
sapling_notes: Vec<SaplingNote>,
#[getset(skip)]
Expand All @@ -291,26 +294,24 @@ pub struct WalletTransaction {
outgoing_sapling_notes: Vec<OutgoingSaplingNote>,
#[getset(skip)]
outgoing_orchard_notes: Vec<OutgoingOrchardNote>,
#[getset(skip)]
transparent_coins: Vec<TransparentCoin>,
}

impl WalletTransaction {
#[allow(clippy::too_many_arguments)]
pub fn from_parts(
txid: TxId,
transaction: zcash_primitives::transaction::Transaction,
confirmation_status: ConfirmationStatus,
status: ConfirmationStatus,
transparent_coins: Vec<TransparentCoin>,
sapling_notes: Vec<SaplingNote>,
orchard_notes: Vec<OrchardNote>,
outgoing_sapling_notes: Vec<OutgoingSaplingNote>,
outgoing_orchard_notes: Vec<OutgoingOrchardNote>,
transparent_coins: Vec<TransparentCoin>,
) -> Self {
Self {
txid,
transaction,
confirmation_status,
status,
sapling_notes,
orchard_notes,
outgoing_sapling_notes,
Expand All @@ -319,6 +320,13 @@ impl WalletTransaction {
}
}

pub fn transparent_coins(&self) -> &[TransparentCoin] {
&self.transparent_coins
}

pub fn transparent_coins_mut(&mut self) -> Vec<&mut TransparentCoin> {
self.transparent_coins.iter_mut().collect()
}
pub fn sapling_notes(&self) -> &[SaplingNote] {
&self.sapling_notes
}
Expand All @@ -342,54 +350,39 @@ impl WalletTransaction {
pub fn outgoing_orchard_notes(&self) -> &[OutgoingOrchardNote] {
&self.outgoing_orchard_notes
}

pub fn transparent_coins(&self) -> &[TransparentCoin] {
&self.transparent_coins
}

pub fn transparent_coins_mut(&mut self) -> Vec<&mut TransparentCoin> {
self.transparent_coins.iter_mut().collect()
}
}

impl std::fmt::Debug for WalletTransaction {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("WalletTransaction")
.field("confirmation_status", &self.confirmation_status)
.field("confirmation_status", &self.status)
.field("transparent_coins", &self.transparent_coins)
.field("sapling_notes", &self.sapling_notes)
.field("orchard_notes", &self.orchard_notes)
.field("outgoing_sapling_notes", &self.outgoing_sapling_notes)
.field("outgoing_orchard_notes", &self.outgoing_orchard_notes)
.field("transparent_coins", &self.transparent_coins)
.finish()
}
}
pub type SaplingNote = WalletNote<sapling_crypto::Note, sapling_crypto::Nullifier>;
pub type OrchardNote = WalletNote<orchard::Note, orchard::note::Nullifier>;

/// Wallet note, shielded output with metadata relevant to the wallet
#[derive(Debug, Getters, CopyGetters, Setters)]
#[derive(Debug, Clone)]
pub struct WalletNote<N, Nf: Copy> {
/// Output ID
#[getset(get_copy = "pub")]
output_id: OutputId,
pub(crate) output_id: OutputId,
/// Identifier for key used to decrypt output
#[getset(get_copy = "pub")]
key_id: KeyId,
pub(crate) key_id: KeyId,
/// Decrypted note with recipient and value
#[getset(get = "pub")]
note: N,
pub(crate) note: N,
/// Derived nullifier
#[getset(get_copy = "pub")]
nullifier: Option<Nf>, //TODO: syncing without nullifier deriving key
pub(crate) nullifier: Option<Nf>, //TODO: syncing without nullifier deriving key
/// Commitment tree leaf position
#[getset(get_copy = "pub")]
position: Option<Position>,
pub(crate) position: Option<Position>,
/// Memo
#[getset(get = "pub")]
memo: Memo,
#[getset(get = "pub", set = "pub")]
spending_transaction: Option<TxId>,
pub(crate) memo: Memo,
/// Transaction this note was spent in.
/// If `None`, note is not spent.
pub(crate) spending_transaction: Option<TxId>,
}

impl<N, Nf: Copy> WalletNote<N, Nf> {
Expand All @@ -414,6 +407,125 @@ impl<N, Nf: Copy> WalletNote<N, Nf> {
}
}

pub trait NoteInterface: Sized {
type ZcashNote;
type Nullifier: Copy;

/// Output ID
fn output_id(&self) -> OutputId;

/// Identifier for key used to decrypt output
fn key_id(&self) -> KeyId;

/// Decrypted note with recipient and value
fn note(&self) -> &Self::ZcashNote;

/// Derived nullifier
fn nullifier(&self) -> Option<Self::Nullifier>;

/// Commitment tree leaf position
fn position(&self) -> Option<Position>;

/// Memo
fn memo(&self) -> &Memo;

/// Txid of transaction this note was spent in.
/// If `None`, note is not spent.
fn spending_transaction(&self) -> Option<TxId>;

/// Note value.
fn value(&self) -> u64;

/// Notes within `transaction`.
fn transaction_notes(transaction: &WalletTransaction) -> &[Self];
}

pub type SaplingNote = WalletNote<sapling_crypto::Note, sapling_crypto::Nullifier>;

impl NoteInterface for SaplingNote {
type ZcashNote = sapling_crypto::Note;
type Nullifier = sapling_crypto::Nullifier;

fn output_id(&self) -> OutputId {
self.output_id
}

fn key_id(&self) -> KeyId {
self.key_id
}

fn note(&self) -> &Self::ZcashNote {
&self.note
}

fn nullifier(&self) -> Option<sapling_crypto::Nullifier> {
self.nullifier
}

fn position(&self) -> Option<Position> {
self.position
}

fn memo(&self) -> &Memo {
&self.memo
}

fn spending_transaction(&self) -> Option<TxId> {
self.spending_transaction
}

fn value(&self) -> u64 {
self.note.value().inner()
}

fn transaction_notes(transaction: &WalletTransaction) -> &[SaplingNote] {
transaction.sapling_notes()
}
}

pub type OrchardNote = WalletNote<orchard::Note, orchard::note::Nullifier>;

impl NoteInterface for OrchardNote {
type ZcashNote = orchard::Note;
type Nullifier = orchard::note::Nullifier;

fn output_id(&self) -> OutputId {
self.output_id
}

fn key_id(&self) -> KeyId {
self.key_id
}

fn note(&self) -> &Self::ZcashNote {
&self.note
}

fn nullifier(&self) -> Option<orchard::note::Nullifier> {
self.nullifier
}

fn position(&self) -> Option<Position> {
self.position
}

fn memo(&self) -> &Memo {
&self.memo
}

fn spending_transaction(&self) -> Option<TxId> {
self.spending_transaction
}

fn value(&self) -> u64 {
self.note.value().inner()
}

fn transaction_notes(transaction: &WalletTransaction) -> &[OrchardNote] {
transaction.orchard_notes()
}
}

pub type OutgoingSaplingNote = OutgoingNote<sapling_crypto::Note>;
pub type OutgoingOrchardNote = OutgoingNote<orchard::Note>;

Expand Down
4 changes: 2 additions & 2 deletions zingo-sync/src/scan/compact_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
keys::{KeyId, ScanningKeyOps, ScanningKeys},
primitives::{NullifierMap, OutputId, TreeBoundaries, WalletBlock},
witness::WitnessData,
MAX_BATCH_OUTPUTS,
};

use self::runners::{BatchRunners, DecryptedOutput};
Expand All @@ -34,8 +35,7 @@ use super::{

mod runners;

// TODO: move parameters to config module
const TRIAL_DECRYPT_TASK_SIZE: usize = 1_024; // 2^10
const TRIAL_DECRYPT_TASK_SIZE: usize = MAX_BATCH_OUTPUTS / 16;

pub(crate) fn scan_compact_blocks<P>(
compact_blocks: Vec<CompactBlock>,
Expand Down
2 changes: 1 addition & 1 deletion zingo-sync/src/scan/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ use crate::{
primitives::{Locator, WalletBlock},
sync,
traits::{SyncBlocks, SyncWallet},
MAX_BATCH_OUTPUTS,
};

use super::{compact_blocks::calculate_block_tree_boundaries, error::ScanError, scan, ScanResults};

const MAX_WORKER_POOLSIZE: usize = 2;
const MAX_BATCH_OUTPUTS: usize = 8_192; // 2^13

pub(crate) enum ScannerState {
Verification,
Expand Down
4 changes: 2 additions & 2 deletions zingo-sync/src/scan/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,11 +297,11 @@ pub(crate) fn scan_transaction<P: consensus::Parameters>(
transaction.txid(),
transaction,
confirmation_status,
transparent_coins,
sapling_notes,
orchard_notes,
outgoing_sapling_notes,
outgoing_orchard_notes,
transparent_coins,
))
}

Expand Down Expand Up @@ -430,7 +430,7 @@ fn parse_encoded_memos<N, Nf: Copy>(
let encoded_memos = wallet_notes
.iter()
.flat_map(|note| {
if let Memo::Arbitrary(ref encoded_memo_bytes) = note.memo() {
if let Memo::Arbitrary(ref encoded_memo_bytes) = note.memo {
Some(zingo_memo::parse_zingo_memo(*encoded_memo_bytes.as_ref()).unwrap())
} else {
None
Expand Down
6 changes: 3 additions & 3 deletions zingo-sync/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub(crate) mod state;
pub(crate) mod transparent;

const VERIFY_BLOCK_RANGE_SIZE: u32 = 10;
const MAX_VERIFICATION_WINDOW: u32 = 100;
pub(crate) const MAX_VERIFICATION_WINDOW: u32 = 100;

/// Syncs a wallet to the latest state of the blockchain
pub async fn sync<P, W>(
Expand Down Expand Up @@ -377,7 +377,7 @@ async fn process_mempool_transaction<W>(
.unwrap()
.get(&transaction.txid())
{
if tx.confirmation_status().is_confirmed() {
if tx.status().is_confirmed() {
return;
}
}
Expand Down Expand Up @@ -537,7 +537,7 @@ where
.get_wallet_transactions()
.unwrap()
.values()
.filter_map(|tx| tx.confirmation_status().get_confirmed_height())
.filter_map(|tx| tx.status().get_confirmed_height())
.collect::<Vec<_>>();

wallet.get_wallet_blocks_mut().unwrap().retain(|height, _| {
Expand Down
Loading
Loading