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

zcash_client_sqlite: Add database tables for Orchard #1254

Merged
merged 2 commits into from
Mar 11, 2024
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
3 changes: 3 additions & 0 deletions zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ and this library adheres to Rust's notion of
- `SentTransaction::new`
- `ORCHARD_SHARD_HEIGHT`
- `BlockMetadata::orchard_tree_size`
- `WalletSummary::next_orchard_subtree_index`
- `chain::ScanSummary::{spent_orchard_note_count, received_orchard_note_count}`
- `zcash_client_backend::fees`:
- `orchard`
Expand Down Expand Up @@ -64,6 +65,8 @@ and this library adheres to Rust's notion of
- `fn put_orchard_subtree_roots`
- Added method `WalletRead::validate_seed`
- Removed `Error::AccountNotFound` variant.
- `WalletSummary::new` now takes an additional `next_orchard_subtree_index`
argument when the `orchard` feature flag is enabled.
- `zcash_client_backend::decrypt`:
- Fields of `DecryptedOutput` are now private. Use `DecryptedOutput::new`
and the newly provided accessors instead.
Expand Down
16 changes: 14 additions & 2 deletions zcash_client_backend/src/data_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@
fully_scanned_height: BlockHeight,
scan_progress: Option<Ratio<u64>>,
next_sapling_subtree_index: u64,
#[cfg(feature = "orchard")]
next_orchard_subtree_index: u64,
}

impl<AccountId: Eq + Hash> WalletSummary<AccountId> {
Expand All @@ -362,14 +364,17 @@
chain_tip_height: BlockHeight,
fully_scanned_height: BlockHeight,
scan_progress: Option<Ratio<u64>>,
next_sapling_subtree_idx: u64,
next_sapling_subtree_index: u64,
#[cfg(feature = "orchard")] next_orchard_subtree_index: u64,
str4d marked this conversation as resolved.
Show resolved Hide resolved
) -> Self {
Self {
account_balances,
chain_tip_height,
fully_scanned_height,
scan_progress,
next_sapling_subtree_index: next_sapling_subtree_idx,
next_sapling_subtree_index,
#[cfg(feature = "orchard")]
next_orchard_subtree_index,
}
}

Expand Down Expand Up @@ -405,6 +410,13 @@
self.next_sapling_subtree_index
}

/// Returns the Orchard subtree index that should start the next range of subtree
/// roots passed to [`WalletCommitmentTrees::put_orchard_subtree_roots`].
#[cfg(feature = "orchard")]
pub fn next_orchard_subtree_index(&self) -> u64 {
self.next_orchard_subtree_index

Check warning on line 417 in zcash_client_backend/src/data_api.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_backend/src/data_api.rs#L416-L417

Added lines #L416 - L417 were not covered by tests
}

/// Returns whether or not wallet scanning is complete.
pub fn is_synced(&self) -> bool {
self.chain_tip_height == self.fully_scanned_height
Expand Down
1 change: 1 addition & 0 deletions zcash_client_sqlite/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ and this library adheres to Rust's notion of
- `init::WalletMigrationError` has added variants:
- `WalletMigrationError::AddressGeneration`
- `WalletMigrationError::CannotRevert`
- The `v_transactions` and `v_tx_outputs` views now include Orchard notes.

## [0.9.1] - 2024-03-09

Expand Down
57 changes: 47 additions & 10 deletions zcash_client_sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@
>;

#[cfg(feature = "orchard")]
fn with_orchard_tree_mut<F, A, E>(&mut self, _callback: F) -> Result<A, E>
fn with_orchard_tree_mut<F, A, E>(&mut self, mut callback: F) -> Result<A, E>
where
for<'a> F: FnMut(
&'a mut ShardTree<
Expand All @@ -967,16 +967,41 @@
) -> Result<A, E>,
E: From<ShardTreeError<Self::Error>>,
{
todo!()
let tx = self
.conn

Check warning on line 971 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L970-L971

Added lines #L970 - L971 were not covered by tests
.transaction()
.map_err(|e| ShardTreeError::Storage(commitment_tree::Error::Query(e)))?;
let shard_store = SqliteShardStore::from_connection(&tx, ORCHARD_TABLES_PREFIX)
.map_err(|e| ShardTreeError::Storage(commitment_tree::Error::Query(e)))?;
let result = {
let mut shardtree = ShardTree::new(shard_store, PRUNING_DEPTH.try_into().unwrap());
callback(&mut shardtree)?

Check warning on line 978 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L973-L978

Added lines #L973 - L978 were not covered by tests
};

tx.commit()
.map_err(|e| ShardTreeError::Storage(commitment_tree::Error::Query(e)))?;
Ok(result)

Check warning on line 983 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L981-L983

Added lines #L981 - L983 were not covered by tests
}

#[cfg(feature = "orchard")]
fn put_orchard_subtree_roots(
&mut self,
_start_index: u64,
_roots: &[CommitmentTreeRoot<orchard::tree::MerkleHashOrchard>],
start_index: u64,
roots: &[CommitmentTreeRoot<orchard::tree::MerkleHashOrchard>],
) -> Result<(), ShardTreeError<Self::Error>> {
todo!()
let tx = self
.conn

Check warning on line 993 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L992-L993

Added lines #L992 - L993 were not covered by tests
.transaction()
.map_err(|e| ShardTreeError::Storage(commitment_tree::Error::Query(e)))?;

Check warning on line 995 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L995

Added line #L995 was not covered by tests
put_shard_roots::<_, { ORCHARD_SHARD_HEIGHT * 2 }, ORCHARD_SHARD_HEIGHT>(
&tx,
ORCHARD_TABLES_PREFIX,
start_index,
roots,

Check warning on line 1000 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L997-L1000

Added lines #L997 - L1000 were not covered by tests
)?;
tx.commit()
.map_err(|e| ShardTreeError::Storage(commitment_tree::Error::Query(e)))?;
Ok(())

Check warning on line 1004 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L1002-L1004

Added lines #L1002 - L1004 were not covered by tests
}
}

Expand Down Expand Up @@ -1027,7 +1052,7 @@
>;

#[cfg(feature = "orchard")]
fn with_orchard_tree_mut<F, A, E>(&mut self, _callback: F) -> Result<A, E>
fn with_orchard_tree_mut<F, A, E>(&mut self, mut callback: F) -> Result<A, E>
where
for<'a> F: FnMut(
&'a mut ShardTree<
Expand All @@ -1038,16 +1063,28 @@
) -> Result<A, E>,
E: From<ShardTreeError<Self::Error>>,
{
todo!()
let mut shardtree = ShardTree::new(
SqliteShardStore::from_connection(self.conn.0, ORCHARD_TABLES_PREFIX)
.map_err(|e| ShardTreeError::Storage(commitment_tree::Error::Query(e)))?,
PRUNING_DEPTH.try_into().unwrap(),

Check warning on line 1069 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L1067-L1069

Added lines #L1067 - L1069 were not covered by tests
);
let result = callback(&mut shardtree)?;

Check warning on line 1071 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L1071

Added line #L1071 was not covered by tests

Ok(result)

Check warning on line 1073 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L1073

Added line #L1073 was not covered by tests
}

#[cfg(feature = "orchard")]
fn put_orchard_subtree_roots(
&mut self,
_start_index: u64,
_roots: &[CommitmentTreeRoot<orchard::tree::MerkleHashOrchard>],
start_index: u64,
roots: &[CommitmentTreeRoot<orchard::tree::MerkleHashOrchard>],
) -> Result<(), ShardTreeError<Self::Error>> {
todo!()
put_shard_roots::<_, { orchard::NOTE_COMMITMENT_TREE_DEPTH as u8 }, ORCHARD_SHARD_HEIGHT>(
self.conn.0,
ORCHARD_TABLES_PREFIX,
start_index,
roots,

Check warning on line 1086 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L1083-L1086

Added lines #L1083 - L1086 were not covered by tests
)
}
}

Expand Down
23 changes: 10 additions & 13 deletions zcash_client_sqlite/src/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@
fn add_spend<R: RngCore + CryptoRng>(
&self,
ctx: &mut CompactTx,
nf: Self::Nullifier,
revealed_spent_note_nullifier: Self::Nullifier,
rng: &mut R,
) {
// Generate a dummy recipient.
Expand All @@ -977,7 +977,7 @@
};

let (cact, _) = compact_orchard_action(
nf,
revealed_spent_note_nullifier,

Check warning on line 980 in zcash_client_sqlite/src/testing.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/testing.rs#L980

Added line #L980 was not covered by tests
recipient,
NonNegativeAmount::ZERO,
self.orchard_ovk(zip32::Scope::Internal),
Expand All @@ -997,7 +997,7 @@
mut rng: &mut R,
) -> Self::Nullifier {
// Generate a dummy nullifier
let nullifier =
let revealed_spent_note_nullifier =

Check warning on line 1000 in zcash_client_sqlite/src/testing.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/testing.rs#L1000

Added line #L1000 was not covered by tests
orchard::note::Nullifier::from_bytes(&pallas::Base::random(&mut rng).to_repr())
.unwrap();

Expand All @@ -1008,7 +1008,7 @@
};

let (cact, note) = compact_orchard_action(
nullifier,
revealed_spent_note_nullifier,

Check warning on line 1011 in zcash_client_sqlite/src/testing.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/testing.rs#L1011

Added line #L1011 was not covered by tests
self.address_at(j, scope),
value,
self.orchard_ovk(scope),
Expand All @@ -1025,7 +1025,7 @@
ctx: &mut CompactTx,
_: &P,
_: BlockHeight,
nf: Self::Nullifier,
revealed_spent_note_nullifier: Self::Nullifier,
req: AddressType,
value: NonNegativeAmount,
_: u32,
Expand All @@ -1038,14 +1038,15 @@
};

let (cact, note) = compact_orchard_action(
nf,
revealed_spent_note_nullifier,

Check warning on line 1041 in zcash_client_sqlite/src/testing.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/testing.rs#L1041

Added line #L1041 was not covered by tests
self.address_at(j, scope),
value,
self.orchard_ovk(scope),
rng,
);
ctx.actions.push(cact);

// Return the nullifier of the newly created output note
note.nullifier(self)
}
}
Expand Down Expand Up @@ -1100,8 +1101,6 @@
ovk: Option<orchard::keys::OutgoingViewingKey>,
rng: &mut R,
) -> (CompactOrchardAction, orchard::Note) {
let nf = nullifier.to_bytes().to_vec();

let rseed = {
loop {
let mut bytes = [0; 32];
Expand All @@ -1120,16 +1119,14 @@
)
.unwrap();
let encryptor = OrchardNoteEncryption::new(ovk, note, *MemoBytes::empty().as_array());
let cmx = orchard::note::ExtractedNoteCommitment::from(note.commitment())
.to_bytes()
.to_vec();
let cmx = orchard::note::ExtractedNoteCommitment::from(note.commitment());

Check warning on line 1122 in zcash_client_sqlite/src/testing.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/testing.rs#L1122

Added line #L1122 was not covered by tests
let ephemeral_key = OrchardDomain::epk_bytes(encryptor.epk()).0.to_vec();
let enc_ciphertext = encryptor.encrypt_note_plaintext();

(
CompactOrchardAction {
nullifier: nf,
cmx,
nullifier: nullifier.to_bytes().to_vec(),
cmx: cmx.to_bytes().to_vec(),

Check warning on line 1129 in zcash_client_sqlite/src/testing.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/testing.rs#L1128-L1129

Added lines #L1128 - L1129 were not covered by tests
ephemeral_key,
ciphertext: enc_ciphertext.as_ref()[..52].to_vec(),
},
Expand Down
28 changes: 28 additions & 0 deletions zcash_client_sqlite/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@

use self::scanning::{parse_priority_code, priority_code, replace_queue_entries};

#[cfg(feature = "orchard")]
use {crate::ORCHARD_TABLES_PREFIX, zcash_client_backend::data_api::ORCHARD_SHARD_HEIGHT};

#[cfg(feature = "transparent-inputs")]
use {
crate::UtxoId,
Expand Down Expand Up @@ -948,6 +951,9 @@
drop(transparent_trace);
}

// The approach used here for Sapling and Orchard subtree indexing was a quick hack
// that has not yet been replaced. TODO: Make less hacky.
// https://github.com/zcash/librustzcash/issues/1249
let next_sapling_subtree_index = {
let shard_store =
SqliteShardStore::<_, ::sapling::Node, SAPLING_SHARD_HEIGHT>::from_connection(
Expand All @@ -967,12 +973,34 @@
.unwrap_or(0)
};

#[cfg(feature = "orchard")]
let next_orchard_subtree_index = {

Check warning on line 977 in zcash_client_sqlite/src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet.rs#L977

Added line #L977 was not covered by tests
let shard_store = SqliteShardStore::<
_,
::orchard::tree::MerkleHashOrchard,
ORCHARD_SHARD_HEIGHT,
>::from_connection(tx, ORCHARD_TABLES_PREFIX)?;

Check warning on line 982 in zcash_client_sqlite/src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet.rs#L982

Added line #L982 was not covered by tests

// The last shard will be incomplete, and we want the next range to overlap with
// the last complete shard, so return the index of the second-to-last shard root.
shard_store

Check warning on line 986 in zcash_client_sqlite/src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet.rs#L986

Added line #L986 was not covered by tests
.get_shard_roots()
.map_err(ShardTreeError::Storage)?

Check warning on line 988 in zcash_client_sqlite/src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet.rs#L988

Added line #L988 was not covered by tests
.iter()
.rev()
.nth(1)
.map(|addr| addr.index())

Check warning on line 992 in zcash_client_sqlite/src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet.rs#L992

Added line #L992 was not covered by tests
.unwrap_or(0)
};

let summary = WalletSummary::new(
account_balances,
chain_tip_height,
fully_scanned_height,
sapling_scan_progress,
next_sapling_subtree_index,
#[cfg(feature = "orchard")]
next_orchard_subtree_index,

Check warning on line 1003 in zcash_client_sqlite/src/wallet.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet.rs#L1002-L1003

Added lines #L1002 - L1003 were not covered by tests
);

Ok(Some(summary))
Expand Down
Loading
Loading