Skip to content

Commit

Permalink
WIP: Add Orchard note commitment tree.
Browse files Browse the repository at this point in the history
  • Loading branch information
nuttycom committed Mar 7, 2024
1 parent bdab673 commit fc37367
Show file tree
Hide file tree
Showing 8 changed files with 476 additions and 97 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions zcash_client_sqlite/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ zcash_client_backend = { workspace = true, features = ["unstable-serialization",
zcash_encoding.workspace = true
zcash_keys = { workspace = true, features = ["orchard", "sapling"] }
zcash_primitives.workspace = true
zcash_protocol.workspace = true
zip32.workspace = true

# Dependencies exposed in a public API:
Expand Down
46 changes: 38 additions & 8 deletions zcash_client_sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ pub(crate) const PRUNING_DEPTH: u32 = 100;
pub(crate) const VERIFY_LOOKAHEAD: u32 = 10;

pub(crate) const SAPLING_TABLES_PREFIX: &str = "sapling";
#[cfg(feature = "orchard")]
pub(crate) const ORCHARD_TABLES_PREFIX: &str = "orchard";

#[cfg(not(feature = "transparent-inputs"))]
pub(crate) const UA_TRANSPARENT: bool = false;
Expand Down Expand Up @@ -576,9 +578,12 @@ impl<P: consensus::Parameters> WalletWrite for WalletDb<rusqlite::Connection, P>
)?;

note_positions.extend(block.transactions().iter().flat_map(|wtx| {
wtx.sapling_outputs()
.iter()
.map(|out| out.note_commitment_tree_position())
wtx.sapling_outputs().iter().map(|out| {
(
ShieldedProtocol::Sapling,
out.note_commitment_tree_position(),
)
})
}));

last_scanned_height = Some(block.height());
Expand Down Expand Up @@ -897,7 +902,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 @@ -908,16 +913,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 917 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L916-L917

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

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L919-L924

Added lines #L919 - L924 were not covered by tests
};

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

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

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L927-L929

Added lines #L927 - L929 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 939 in zcash_client_sqlite/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L938-L939

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

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

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L941

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

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L943-L946

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

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

View check run for this annotation

Codecov / codecov/patch

zcash_client_sqlite/src/lib.rs#L948-L950

Added lines #L948 - L950 were not covered by tests
}
}

Expand Down
74 changes: 72 additions & 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 Expand Up @@ -262,6 +261,31 @@ mod tests {
ON UPDATE RESTRICT,
CONSTRAINT nf_uniq UNIQUE (spend_pool, nf)
)",
"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
)",
"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)
)",
"CREATE TABLE orchard_tree_checkpoints (
checkpoint_id INTEGER PRIMARY KEY,
position INTEGER
)",
"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)
)",
r#"CREATE TABLE "sapling_received_notes" (
id INTEGER PRIMARY KEY,
tx INTEGER NOT NULL,
Expand Down Expand Up @@ -388,6 +412,52 @@ mod tests {
}

let expected_views = vec![
// v_orchard_shard_scan_ranges
format!(
"CREATE VIEW v_orchard_shard_scan_ranges AS
SELECT
shard.shard_index,
shard.shard_index << 16 AS start_position,
(shard.shard_index + 1) << 16 AS end_position_exclusive,
IFNULL(prev_shard.subtree_end_height, {}) AS subtree_start_height,
shard.subtree_end_height,
shard.contains_marked,
scan_queue.block_range_start,
scan_queue.block_range_end,
scan_queue.priority
FROM orchard_tree_shards shard
LEFT OUTER JOIN orchard_tree_shards prev_shard
ON shard.shard_index = prev_shard.shard_index + 1
-- Join with scan ranges that overlap with the subtree's involved blocks.
INNER JOIN scan_queue ON (
subtree_start_height < scan_queue.block_range_end AND
(
scan_queue.block_range_start <= shard.subtree_end_height OR
shard.subtree_end_height IS NULL
)
)",
u32::from(st.network().activation_height(NetworkUpgrade::Nu5).unwrap()),
),
//v_orchard_shard_unscanned_ranges
format!(
"CREATE VIEW v_orchard_shard_unscanned_ranges AS
WITH wallet_birthday AS (SELECT MIN(birthday_height) AS height FROM accounts)
SELECT
shard_index,
start_position,
end_position_exclusive,
subtree_start_height,
subtree_end_height,
contains_marked,
block_range_start,
block_range_end,
priority
FROM v_orchard_shard_scan_ranges
INNER JOIN wallet_birthday
WHERE priority > {}
AND block_range_end > wallet_birthday.height",
priority_code(&ScanPriority::Scanned),
),
// v_sapling_shard_scan_ranges
format!(
"CREATE VIEW v_sapling_shard_scan_ranges AS
Expand Down
34 changes: 19 additions & 15 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 All @@ -24,7 +25,7 @@ use std::rc::Rc;

use schemer_rusqlite::RusqliteMigration;
use secrecy::SecretVec;
use zcash_primitives::consensus;
use zcash_protocol::consensus;

use super::WalletMigrationError;

Expand All @@ -45,20 +46,20 @@ pub(super) fn all_migrations<P: consensus::Parameters + 'static>(
// |
// v_transactions_net
// |
// received_notes_nullable_nf
// / | \
// / | \
// shardtree_support sapling_memo_consistency nullifier_map
// / \ \
// add_account_birthdays receiving_key_scopes v_transactions_transparent_history
// | \ | |
// v_sapling_shard_unscanned_ranges \ | v_tx_outputs_use_legacy_false
// | \ | |
// wallet_summaries \ | v_transactions_shielding_balance
// \ | |
// \ | v_transactions_note_uniqueness
// \ | /
// full_account_ids
// received_notes_nullable_nf------
// / | \
// / | \
// --------------- shardtree_support sapling_memo_consistency nullifier_map
// / / \ \
// orchard_shardtree add_account_birthdays receiving_key_scopes v_transactions_transparent_history
// | \ | |
// v_sapling_shard_unscanned_ranges \ | v_tx_outputs_use_legacy_false
// | \ | |
// wallet_summaries \ | v_transactions_shielding_balance
// \ | |
// \ | v_transactions_note_uniqueness
// \ | /
// full_account_ids
vec![
Box::new(initial_setup::Migration {}),
Box::new(utxos_table::Migration {}),
Expand Down Expand Up @@ -98,5 +99,8 @@ pub(super) fn all_migrations<P: consensus::Parameters + 'static>(
params: params.clone(),
}),
Box::new(full_account_ids::Migration { seed }),
Box::new(orchard_shardtree::Migration {
params: params.clone(),
}),
]
}
Loading

0 comments on commit fc37367

Please sign in to comment.