Skip to content

Commit

Permalink
WIP: zcash_client_sqlite: Add Orchard support.
Browse files Browse the repository at this point in the history
Fixes #1176
  • Loading branch information
nuttycom committed Mar 6, 2024
1 parent 7def8c0 commit c118979
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 13 deletions.
2 changes: 1 addition & 1 deletion zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ and this library adheres to Rust's notion of
- `zcash_client_backend::zip321::render::amount_str` now takes a
`NonNegativeAmount` rather than a signed `Amount` as its argument.
- `zcash_client_backend::zip321::parse::parse_amount` now parses a
`NonNegativeAmount` rather than a signed `Amount`. Also, it
`NonNegativeAmount` rather than a signed `Amount`.
- `zcash_client_backend::zip321::TransactionRequest::total` now
returns `Result<_, BalanceError>` instead of `Result<_, ()>`.

Expand Down
4 changes: 2 additions & 2 deletions zcash_client_backend/src/zip321.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,8 @@ mod render {
format!("address{}={}", param_index(idx), addr.encode(params))
}

/// Converts a [`NonNegativeAmount`] value to a correctly formatted decimal ZEC string.
/// value for inclusion in a ZIP 321 URI.
/// Converts a [`NonNegativeAmount`] value to a correctly formatted decimal ZEC
/// string for inclusion in a ZIP 321 URI.
pub fn amount_str(amount: NonNegativeAmount) -> String {
let coins = u64::from(amount) / COIN;
let zats = u64::from(amount) % COIN;
Expand Down
36 changes: 31 additions & 5 deletions zcash_client_sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub(crate) const PRUNING_DEPTH: u32 = 100;
pub(crate) const VERIFY_LOOKAHEAD: u32 = 10;

pub(crate) const SAPLING_TABLES_PREFIX: &str = "sapling";
pub(crate) const ORCHARD_TABLES_PREFIX: &str = "orchard";

#[cfg(not(feature = "transparent-inputs"))]
pub(crate) const UA_TRANSPARENT: bool = false;
Expand Down Expand Up @@ -902,7 +903,7 @@ impl<P: consensus::Parameters> WalletCommitmentTrees for WalletDb<rusqlite::Conn
>;

#[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 @@ -913,16 +914,41 @@ impl<P: consensus::Parameters> WalletCommitmentTrees for WalletDb<rusqlite::Conn
) -> Result<A, E>,
E: From<ShardTreeError<Self::Error>>,
{
todo!()
let tx = self
.conn

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

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L917-L918

Added lines #L917 - L918 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 925 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L920-L925

Added lines #L920 - L925 were not covered by tests
};

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

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

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L928-L930

Added lines #L928 - L930 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 940 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L939-L940

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

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

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L942

Added line #L942 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 947 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L944-L947

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

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

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L949-L951

Added lines #L949 - L951 were not covered by tests
}
}

Expand Down
3 changes: 1 addition & 2 deletions zcash_client_sqlite/src/wallet/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ use uuid::Uuid;
use zcash_client_backend::keys::AddressGenerationError;
use zcash_primitives::{consensus, transaction::components::amount::BalanceError};

use crate::WalletDb;

use super::commitment_tree;
use crate::WalletDb;

mod migrations;

Expand Down
1 change: 1 addition & 0 deletions zcash_client_sqlite/src/wallet/init/migrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod addresses_table;
mod full_account_ids;
mod initial_setup;
mod nullifier_map;
mod orchard_shardtree;
mod received_notes_nullable_nf;
mod receiving_key_scopes;
mod sapling_memo_consistency;
Expand Down
133 changes: 133 additions & 0 deletions zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//! This migration adds tables to the wallet database that are needed to persist Orchard note
//! commitment tree data using the `shardtree` crate.

use std::collections::HashSet;

use rusqlite::{self, named_params, OptionalExtension};
use schemer;
use schemer_rusqlite::RusqliteMigration;

use tracing::debug;
use uuid::Uuid;

use zcash_primitives::consensus::{self, BlockHeight};

use crate::wallet::{
block_height_extrema,
init::{migrations::received_notes_nullable_nf, WalletMigrationError},
};

pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x3a6487f7_e068_42bb_9d12_6bb8dbe6da00);

pub(super) struct Migration<P> {
pub(super) params: P,
pub(super) orchard_init_height: BlockHeight,
}

impl<P> schemer::Migration for Migration<P> {
fn id(&self) -> Uuid {
MIGRATION_ID

Check warning on line 29 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L28-L29

Added lines #L28 - L29 were not covered by tests
}

fn dependencies(&self) -> HashSet<Uuid> {
[received_notes_nullable_nf::MIGRATION_ID]

Check warning on line 33 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L32-L33

Added lines #L32 - L33 were not covered by tests
.into_iter()
.collect()
}

fn description(&self) -> &'static str {
"Add support for storage of Orchard note commitment tree data using the `shardtree` crate."

Check warning on line 39 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L38-L39

Added lines #L38 - L39 were not covered by tests
}
}

impl<P: consensus::Parameters> RusqliteMigration for Migration<P> {
type Error = WalletMigrationError;

fn up(&self, transaction: &rusqlite::Transaction) -> Result<(), WalletMigrationError> {

Check warning on line 46 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L46

Added line #L46 was not covered by tests
// Add shard persistence
debug!("Creating tables for Orchard shard persistence");
transaction.execute_batch(

Check warning on line 49 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L48-L49

Added lines #L48 - L49 were not covered by tests
"CREATE TABLE orchard_tree_shards (
shard_index INTEGER PRIMARY KEY,
subtree_end_height INTEGER,
root_hash BLOB,
shard_data BLOB,
contains_marked INTEGER,
CONSTRAINT root_unique UNIQUE (root_hash)
);
CREATE TABLE orchard_tree_cap (
-- cap_id exists only to be able to take advantage of `ON CONFLICT`
-- upsert functionality; the table will only ever contain one row
cap_id INTEGER PRIMARY KEY,
cap_data BLOB NOT NULL
);",
)?;

// Add checkpoint persistence
debug!("Creating tables for checkpoint persistence");
transaction.execute_batch(

Check warning on line 68 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L67-L68

Added lines #L67 - L68 were not covered by tests
"CREATE TABLE orchard_tree_checkpoints (
checkpoint_id INTEGER PRIMARY KEY,
position INTEGER
);
CREATE TABLE orchard_tree_checkpoint_marks_removed (
checkpoint_id INTEGER NOT NULL,
mark_removed_position INTEGER NOT NULL,
FOREIGN KEY (checkpoint_id) REFERENCES orchard_tree_checkpoints(checkpoint_id)
ON DELETE CASCADE,
CONSTRAINT spend_position_unique UNIQUE (checkpoint_id, mark_removed_position)
);",
)?;

let _block_height_extrema = block_height_extrema(transaction)?;

Check warning on line 82 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L82

Added line #L82 was not covered by tests

// If a scan range exists that contains the Orchard init height, split it in two at the
// init height.
if let Some((start, end, priority_code)) = transaction

Check warning on line 86 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L86

Added line #L86 was not covered by tests
.query_row_and_then(
"SELECT block_range_start, block_range_end, priority
FROM scan_queue
WHERE block_range_start <= :orchard_init_height
AND block_range_end > :orchard_init_height",
named_params![":orchard_init_height": u32::from(self.orchard_init_height)],
|row| {
let start = BlockHeight::from(row.get::<_, u32>(0)?);
let end = BlockHeight::from(row.get::<_, u32>(1)?);
let priority_code: i64 = row.get(2)?;
Ok((start, end, priority_code))

Check warning on line 97 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L92-L97

Added lines #L92 - L97 were not covered by tests
},
)
.optional()?
{
transaction.execute(

Check warning on line 102 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L102

Added line #L102 was not covered by tests
"DELETE from scan_queue WHERE block_range_start = :start",
named_params![":start": u32::from(start)],

Check warning on line 104 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L104

Added line #L104 was not covered by tests
)?;
transaction.execute(

Check warning on line 106 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L106

Added line #L106 was not covered by tests
"INSERT INTO scan_queue (block_range_start, block_range_end, priority)
VALUES (:block_range_start, :block_range_end, :priority)",
named_params![
":block_range_start": u32::from(start),
":block_range_end": u32::from(self.orchard_init_height),
":priority": priority_code,

Check warning on line 112 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L109-L112

Added lines #L109 - L112 were not covered by tests
],
)?;
transaction.execute(

Check warning on line 115 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L115

Added line #L115 was not covered by tests
"INSERT INTO scan_queue (block_range_start, block_range_end, priority)
VALUES (:block_range_start, :block_range_end, :priority)",
named_params![
":block_range_start": u32::from(self.orchard_init_height),
":block_range_end": u32::from(end),
":priority": priority_code,

Check warning on line 121 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L118-L121

Added lines #L118 - L121 were not covered by tests
],
)?;
}

Ok(())

Check warning on line 126 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L126

Added line #L126 was not covered by tests
}

fn down(&self, _transaction: &rusqlite::Transaction) -> Result<(), WalletMigrationError> {

Check warning on line 129 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L129

Added line #L129 was not covered by tests
// TODO: something better than just panic?
panic!("Cannot revert this migration.");

Check warning on line 131 in zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs#L131

Added line #L131 was not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! This migration adds tables to the wallet database that are needed to persist note commitment
//! tree data using the `shardtree` crate, and migrates existing witness data into these data
//! structures.
//! This migration adds tables to the wallet database that are needed to persist Sapling note
//! commitment tree data using the `shardtree` crate, and migrates existing witness data into these
//! data structures.

use std::collections::{BTreeSet, HashSet};

Expand Down

0 comments on commit c118979

Please sign in to comment.