zcash_client_backend: Add Orchard spends to `create_proposed_transaction`
This commit is contained in:
parent
c6656c108b
commit
f27f601b7d
|
@ -17,6 +17,8 @@ and this library adheres to Rust's notion of
|
||||||
- `BlockMetadata::orchard_tree_size`
|
- `BlockMetadata::orchard_tree_size`
|
||||||
- `ScannedBlock::orchard`
|
- `ScannedBlock::orchard`
|
||||||
- `ScannedBlockCommitments::orchard`
|
- `ScannedBlockCommitments::orchard`
|
||||||
|
- `ORCHARD_SHARD_HEIGHT`
|
||||||
|
- `BlockMetadata::orchard_tree_size`
|
||||||
- `zcash_client_backend::fees::orchard`
|
- `zcash_client_backend::fees::orchard`
|
||||||
- `zcash_client_backend::fees::ChangeValue::orchard`
|
- `zcash_client_backend::fees::ChangeValue::orchard`
|
||||||
- `zcash_client_backend::wallet`:
|
- `zcash_client_backend::wallet`:
|
||||||
|
@ -29,6 +31,10 @@ and this library adheres to Rust's notion of
|
||||||
- Changes to the `WalletRead` trait:
|
- Changes to the `WalletRead` trait:
|
||||||
- Added `get_orchard_nullifiers`
|
- Added `get_orchard_nullifiers`
|
||||||
- `ShieldedProtocol` has a new `Orchard` variant.
|
- `ShieldedProtocol` has a new `Orchard` variant.
|
||||||
|
- `WalletCommitmentTrees` has new members when the `orchard` feature is enabled:
|
||||||
|
- `type OrchardShardStore`
|
||||||
|
- `fn with_orchard_tree_mut`
|
||||||
|
- `fn put_orchard_subtree_roots`
|
||||||
- `zcash_client_backend::fees`:
|
- `zcash_client_backend::fees`:
|
||||||
- Arguments to `ChangeStrategy::compute_balance` have changed.
|
- Arguments to `ChangeStrategy::compute_balance` have changed.
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use incrementalmerkletree::{frontier::Frontier, Retention};
|
use incrementalmerkletree::{frontier::Frontier, Retention};
|
||||||
use sapling::{Node, NOTE_COMMITMENT_TREE_DEPTH};
|
use sapling;
|
||||||
use secrecy::SecretVec;
|
use secrecy::SecretVec;
|
||||||
use shardtree::{error::ShardTreeError, store::ShardStore, ShardTree};
|
use shardtree::{error::ShardTreeError, store::ShardStore, ShardTree};
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
|
@ -51,6 +51,13 @@ pub mod wallet;
|
||||||
/// `lightwalletd` when using the `GetSubtreeRoots` GRPC call.
|
/// `lightwalletd` when using the `GetSubtreeRoots` GRPC call.
|
||||||
pub const SAPLING_SHARD_HEIGHT: u8 = sapling::NOTE_COMMITMENT_TREE_DEPTH / 2;
|
pub const SAPLING_SHARD_HEIGHT: u8 = sapling::NOTE_COMMITMENT_TREE_DEPTH / 2;
|
||||||
|
|
||||||
|
/// The height of subtree roots in the Orchard note commitment tree.
|
||||||
|
///
|
||||||
|
/// This conforms to the structure of subtree data returned by
|
||||||
|
/// `lightwalletd` when using the `GetSubtreeRoots` GRPC call.
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
pub const ORCHARD_SHARD_HEIGHT: u8 = { orchard::NOTE_COMMITMENT_TREE_DEPTH as u8 } / 2;
|
||||||
|
|
||||||
/// An enumeration of constraints that can be applied when querying for nullifiers for notes
|
/// An enumeration of constraints that can be applied when querying for nullifiers for notes
|
||||||
/// belonging to the wallet.
|
/// belonging to the wallet.
|
||||||
pub enum NullifierQuery {
|
pub enum NullifierQuery {
|
||||||
|
@ -870,7 +877,7 @@ impl SentTransactionOutput {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AccountBirthday {
|
pub struct AccountBirthday {
|
||||||
height: BlockHeight,
|
height: BlockHeight,
|
||||||
sapling_frontier: Frontier<Node, NOTE_COMMITMENT_TREE_DEPTH>,
|
sapling_frontier: Frontier<sapling::Node, { sapling::NOTE_COMMITMENT_TREE_DEPTH }>,
|
||||||
recover_until: Option<BlockHeight>,
|
recover_until: Option<BlockHeight>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,7 +918,7 @@ impl AccountBirthday {
|
||||||
#[cfg(feature = "test-dependencies")]
|
#[cfg(feature = "test-dependencies")]
|
||||||
pub fn from_parts(
|
pub fn from_parts(
|
||||||
height: BlockHeight,
|
height: BlockHeight,
|
||||||
sapling_frontier: Frontier<Node, NOTE_COMMITMENT_TREE_DEPTH>,
|
sapling_frontier: Frontier<sapling::Node, { sapling::NOTE_COMMITMENT_TREE_DEPTH }>,
|
||||||
recover_until: Option<BlockHeight>,
|
recover_until: Option<BlockHeight>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -944,7 +951,9 @@ impl AccountBirthday {
|
||||||
|
|
||||||
/// Returns the Sapling note commitment tree frontier as of the end of the block at
|
/// Returns the Sapling note commitment tree frontier as of the end of the block at
|
||||||
/// [`Self::height`].
|
/// [`Self::height`].
|
||||||
pub fn sapling_frontier(&self) -> &Frontier<Node, NOTE_COMMITMENT_TREE_DEPTH> {
|
pub fn sapling_frontier(
|
||||||
|
&self,
|
||||||
|
) -> &Frontier<sapling::Node, { sapling::NOTE_COMMITMENT_TREE_DEPTH }> {
|
||||||
&self.sapling_frontier
|
&self.sapling_frontier
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1081,13 +1090,15 @@ pub trait WalletWrite: WalletRead {
|
||||||
/// also provide operations related to Orchard note commitment trees in the future.
|
/// also provide operations related to Orchard note commitment trees in the future.
|
||||||
pub trait WalletCommitmentTrees {
|
pub trait WalletCommitmentTrees {
|
||||||
type Error;
|
type Error;
|
||||||
|
/// The type of the backing [`ShardStore`] for the Sapling note commitment tree.
|
||||||
type SaplingShardStore<'a>: ShardStore<
|
type SaplingShardStore<'a>: ShardStore<
|
||||||
H = sapling::Node,
|
H = sapling::Node,
|
||||||
CheckpointId = BlockHeight,
|
CheckpointId = BlockHeight,
|
||||||
Error = Self::Error,
|
Error = Self::Error,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
///
|
/// Evaluates the given callback function with a reference to the Sapling
|
||||||
|
/// note commitment tree maintained by the wallet.
|
||||||
fn with_sapling_tree_mut<F, A, E>(&mut self, callback: F) -> Result<A, E>
|
fn with_sapling_tree_mut<F, A, E>(&mut self, callback: F) -> Result<A, E>
|
||||||
where
|
where
|
||||||
for<'a> F: FnMut(
|
for<'a> F: FnMut(
|
||||||
|
@ -1099,12 +1110,48 @@ pub trait WalletCommitmentTrees {
|
||||||
) -> Result<A, E>,
|
) -> Result<A, E>,
|
||||||
E: From<ShardTreeError<Self::Error>>;
|
E: From<ShardTreeError<Self::Error>>;
|
||||||
|
|
||||||
/// Adds a sequence of note commitment tree subtree roots to the data store.
|
/// Adds a sequence of Sapling note commitment tree subtree roots to the data store.
|
||||||
|
///
|
||||||
|
/// Each such value should be the Merkle root of a subtree of the Sapling note commitment tree
|
||||||
|
/// containing 2^[`SAPLING_SHARD_HEIGHT`] note commitments.
|
||||||
fn put_sapling_subtree_roots(
|
fn put_sapling_subtree_roots(
|
||||||
&mut self,
|
&mut self,
|
||||||
start_index: u64,
|
start_index: u64,
|
||||||
roots: &[CommitmentTreeRoot<sapling::Node>],
|
roots: &[CommitmentTreeRoot<sapling::Node>],
|
||||||
) -> Result<(), ShardTreeError<Self::Error>>;
|
) -> Result<(), ShardTreeError<Self::Error>>;
|
||||||
|
|
||||||
|
/// The type of the backing [`ShardStore`] for the Orchard note commitment tree.
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
type OrchardShardStore<'a>: ShardStore<
|
||||||
|
H = orchard::tree::MerkleHashOrchard,
|
||||||
|
CheckpointId = BlockHeight,
|
||||||
|
Error = Self::Error,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Evaluates the given callback function with a reference to the Orchard
|
||||||
|
/// note commitment tree maintained by the wallet.
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
fn with_orchard_tree_mut<F, A, E>(&mut self, callback: F) -> Result<A, E>
|
||||||
|
where
|
||||||
|
for<'a> F: FnMut(
|
||||||
|
&'a mut ShardTree<
|
||||||
|
Self::OrchardShardStore<'a>,
|
||||||
|
{ ORCHARD_SHARD_HEIGHT * 2 },
|
||||||
|
ORCHARD_SHARD_HEIGHT,
|
||||||
|
>,
|
||||||
|
) -> Result<A, E>,
|
||||||
|
E: From<ShardTreeError<Self::Error>>;
|
||||||
|
|
||||||
|
/// Adds a sequence of Orchard note commitment tree subtree roots to the data store.
|
||||||
|
///
|
||||||
|
/// Each such value should be the Merkle root of a subtree of the Orchard note commitment tree
|
||||||
|
/// containing 2^[`ORCHARD_SHARD_HEIGHT`] note commitments.
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
fn put_orchard_subtree_roots(
|
||||||
|
&mut self,
|
||||||
|
start_index: u64,
|
||||||
|
roots: &[CommitmentTreeRoot<orchard::tree::MerkleHashOrchard>],
|
||||||
|
) -> Result<(), ShardTreeError<Self::Error>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "test-dependencies")]
|
#[cfg(feature = "test-dependencies")]
|
||||||
|
@ -1138,6 +1185,9 @@ pub mod testing {
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use {crate::wallet::TransparentAddressMetadata, zcash_primitives::legacy::TransparentAddress};
|
use {crate::wallet::TransparentAddressMetadata, zcash_primitives::legacy::TransparentAddress};
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
use super::ORCHARD_SHARD_HEIGHT;
|
||||||
|
|
||||||
pub struct MockWalletDb {
|
pub struct MockWalletDb {
|
||||||
pub network: Network,
|
pub network: Network,
|
||||||
pub sapling_tree: ShardTree<
|
pub sapling_tree: ShardTree<
|
||||||
|
@ -1145,6 +1195,12 @@ pub mod testing {
|
||||||
{ SAPLING_SHARD_HEIGHT * 2 },
|
{ SAPLING_SHARD_HEIGHT * 2 },
|
||||||
SAPLING_SHARD_HEIGHT,
|
SAPLING_SHARD_HEIGHT,
|
||||||
>,
|
>,
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
pub orchard_tree: ShardTree<
|
||||||
|
MemoryShardStore<orchard::tree::MerkleHashOrchard, BlockHeight>,
|
||||||
|
{ ORCHARD_SHARD_HEIGHT * 2 },
|
||||||
|
ORCHARD_SHARD_HEIGHT,
|
||||||
|
>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MockWalletDb {
|
impl MockWalletDb {
|
||||||
|
@ -1152,6 +1208,8 @@ pub mod testing {
|
||||||
Self {
|
Self {
|
||||||
network,
|
network,
|
||||||
sapling_tree: ShardTree::new(MemoryShardStore::empty(), 100),
|
sapling_tree: ShardTree::new(MemoryShardStore::empty(), 100),
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
orchard_tree: ShardTree::new(MemoryShardStore::empty(), 100),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1406,5 +1464,43 @@ pub mod testing {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
type OrchardShardStore<'a> =
|
||||||
|
MemoryShardStore<orchard::tree::MerkleHashOrchard, BlockHeight>;
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
fn with_orchard_tree_mut<F, A, E>(&mut self, mut callback: F) -> Result<A, E>
|
||||||
|
where
|
||||||
|
for<'a> F: FnMut(
|
||||||
|
&'a mut ShardTree<
|
||||||
|
Self::OrchardShardStore<'a>,
|
||||||
|
{ ORCHARD_SHARD_HEIGHT * 2 },
|
||||||
|
ORCHARD_SHARD_HEIGHT,
|
||||||
|
>,
|
||||||
|
) -> Result<A, E>,
|
||||||
|
E: From<ShardTreeError<Self::Error>>,
|
||||||
|
{
|
||||||
|
callback(&mut self.orchard_tree)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a sequence of note commitment tree subtree roots to the data store.
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
fn put_orchard_subtree_roots(
|
||||||
|
&mut self,
|
||||||
|
start_index: u64,
|
||||||
|
roots: &[CommitmentTreeRoot<orchard::tree::MerkleHashOrchard>],
|
||||||
|
) -> Result<(), ShardTreeError<Self::Error>> {
|
||||||
|
self.with_orchard_tree_mut(|t| {
|
||||||
|
for (root, i) in roots.iter().zip(0u64..) {
|
||||||
|
let root_addr =
|
||||||
|
Address::from_parts(ORCHARD_SHARD_HEIGHT.into(), start_index + i);
|
||||||
|
t.insert(root_addr, *root.root_hash())?;
|
||||||
|
}
|
||||||
|
Ok::<_, ShardTreeError<Self::Error>>(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -682,28 +682,24 @@ where
|
||||||
let sapling_inputs = inputs
|
let sapling_inputs = inputs
|
||||||
.notes()
|
.notes()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|selected| {
|
.filter_map(|selected| match selected.note() {
|
||||||
match selected.note() {
|
Note::Sapling(note) => {
|
||||||
Note::Sapling(note) => {
|
let key = match selected.spending_key_scope() {
|
||||||
let key = match selected.spending_key_scope() {
|
Scope::External => usk.sapling().clone(),
|
||||||
Scope::External => usk.sapling().clone(),
|
Scope::Internal => usk.sapling().derive_internal(),
|
||||||
Scope::Internal => usk.sapling().derive_internal(),
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let merkle_path = sapling_tree.witness_at_checkpoint_id_caching(
|
sapling_tree
|
||||||
|
.witness_at_checkpoint_id_caching(
|
||||||
selected.note_commitment_tree_position(),
|
selected.note_commitment_tree_position(),
|
||||||
&inputs.anchor_height(),
|
&inputs.anchor_height(),
|
||||||
)?;
|
)
|
||||||
|
.map(|merkle_path| Some((key, note, merkle_path)))
|
||||||
Ok((key, note, merkle_path))
|
.map_err(Error::from)
|
||||||
}
|
.transpose()
|
||||||
#[cfg(feature = "orchard")]
|
|
||||||
Note::Orchard(_) => {
|
|
||||||
// FIXME: Implement this once `Proposal` has been refactored to
|
|
||||||
// include Orchard notes.
|
|
||||||
panic!("Orchard spends are not yet supported");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
Note::Orchard(_) => None,
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, Error<_, _, _, _>>>()?;
|
.collect::<Result<Vec<_>, Error<_, _, _, _>>>()?;
|
||||||
|
|
||||||
|
@ -712,6 +708,39 @@ where
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
let (orchard_anchor, orchard_inputs) = proposal_step.shielded_inputs().map_or_else(
|
||||||
|
|| Ok((Some(orchard::Anchor::empty_tree()), vec![])),
|
||||||
|
|inputs| {
|
||||||
|
wallet_db.with_orchard_tree_mut::<_, _, Error<_, _, _, _>>(|orchard_tree| {
|
||||||
|
let anchor = orchard_tree
|
||||||
|
.root_at_checkpoint_id(&inputs.anchor_height())?
|
||||||
|
.into();
|
||||||
|
|
||||||
|
let orchard_inputs = inputs
|
||||||
|
.notes()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|selected| match selected.note() {
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
Note::Orchard(note) => orchard_tree
|
||||||
|
.witness_at_checkpoint_id_caching(
|
||||||
|
selected.note_commitment_tree_position(),
|
||||||
|
&inputs.anchor_height(),
|
||||||
|
)
|
||||||
|
.map(|merkle_path| Some((note, merkle_path)))
|
||||||
|
.map_err(Error::from)
|
||||||
|
.transpose(),
|
||||||
|
Note::Sapling(_) => None,
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, Error<_, _, _, _>>>()?;
|
||||||
|
|
||||||
|
Ok((Some(anchor), orchard_inputs))
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
#[cfg(not(feature = "orchard"))]
|
||||||
|
let orchard_anchor = None;
|
||||||
|
|
||||||
// Create the transaction. The type of the proposal ensures that there
|
// Create the transaction. The type of the proposal ensures that there
|
||||||
// are no possible transparent inputs, so we ignore those
|
// are no possible transparent inputs, so we ignore those
|
||||||
let mut builder = Builder::new(
|
let mut builder = Builder::new(
|
||||||
|
@ -719,12 +748,17 @@ where
|
||||||
min_target_height,
|
min_target_height,
|
||||||
BuildConfig::Standard {
|
BuildConfig::Standard {
|
||||||
sapling_anchor: Some(sapling_anchor),
|
sapling_anchor: Some(sapling_anchor),
|
||||||
orchard_anchor: None,
|
orchard_anchor,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
for (key, note, merkle_path) in sapling_inputs.into_iter() {
|
for (sapling_key, sapling_note, merkle_path) in sapling_inputs.into_iter() {
|
||||||
builder.add_sapling_spend(&key, note.clone(), merkle_path)?;
|
builder.add_sapling_spend(&sapling_key, sapling_note.clone(), merkle_path)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
for (orchard_note, merkle_path) in orchard_inputs.into_iter() {
|
||||||
|
builder.add_orchard_spend(usk.orchard(), *orchard_note, merkle_path.into())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
|
|
|
@ -74,6 +74,9 @@ use zcash_client_backend::{
|
||||||
|
|
||||||
use crate::{error::SqliteClientError, wallet::commitment_tree::SqliteShardStore};
|
use crate::{error::SqliteClientError, wallet::commitment_tree::SqliteShardStore};
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
use zcash_client_backend::data_api::ORCHARD_SHARD_HEIGHT;
|
||||||
|
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
use {
|
use {
|
||||||
zcash_client_backend::wallet::TransparentAddressMetadata,
|
zcash_client_backend::wallet::TransparentAddressMetadata,
|
||||||
|
@ -805,6 +808,37 @@ impl<P: consensus::Parameters> WalletCommitmentTrees for WalletDb<rusqlite::Conn
|
||||||
.map_err(|e| ShardTreeError::Storage(commitment_tree::Error::Query(e)))?;
|
.map_err(|e| ShardTreeError::Storage(commitment_tree::Error::Query(e)))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
type OrchardShardStore<'a> = SqliteShardStore<
|
||||||
|
&'a rusqlite::Transaction<'a>,
|
||||||
|
orchard::tree::MerkleHashOrchard,
|
||||||
|
ORCHARD_SHARD_HEIGHT,
|
||||||
|
>;
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
fn with_orchard_tree_mut<F, A, E>(&mut self, _callback: F) -> Result<A, E>
|
||||||
|
where
|
||||||
|
for<'a> F: FnMut(
|
||||||
|
&'a mut ShardTree<
|
||||||
|
Self::OrchardShardStore<'a>,
|
||||||
|
{ ORCHARD_SHARD_HEIGHT * 2 },
|
||||||
|
ORCHARD_SHARD_HEIGHT,
|
||||||
|
>,
|
||||||
|
) -> Result<A, E>,
|
||||||
|
E: From<ShardTreeError<Self::Error>>,
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
fn put_orchard_subtree_roots(
|
||||||
|
&mut self,
|
||||||
|
_start_index: u64,
|
||||||
|
_roots: &[CommitmentTreeRoot<orchard::tree::MerkleHashOrchard>],
|
||||||
|
) -> Result<(), ShardTreeError<Self::Error>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'conn, P: consensus::Parameters> WalletCommitmentTrees for WalletDb<SqlTransaction<'conn>, P> {
|
impl<'conn, P: consensus::Parameters> WalletCommitmentTrees for WalletDb<SqlTransaction<'conn>, P> {
|
||||||
|
@ -845,6 +879,37 @@ impl<'conn, P: consensus::Parameters> WalletCommitmentTrees for WalletDb<SqlTran
|
||||||
roots,
|
roots,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
type OrchardShardStore<'a> = SqliteShardStore<
|
||||||
|
&'a rusqlite::Transaction<'a>,
|
||||||
|
orchard::tree::MerkleHashOrchard,
|
||||||
|
ORCHARD_SHARD_HEIGHT,
|
||||||
|
>;
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
fn with_orchard_tree_mut<F, A, E>(&mut self, _callback: F) -> Result<A, E>
|
||||||
|
where
|
||||||
|
for<'a> F: FnMut(
|
||||||
|
&'a mut ShardTree<
|
||||||
|
Self::OrchardShardStore<'a>,
|
||||||
|
{ ORCHARD_SHARD_HEIGHT * 2 },
|
||||||
|
ORCHARD_SHARD_HEIGHT,
|
||||||
|
>,
|
||||||
|
) -> Result<A, E>,
|
||||||
|
E: From<ShardTreeError<Self::Error>>,
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "orchard")]
|
||||||
|
fn put_orchard_subtree_roots(
|
||||||
|
&mut self,
|
||||||
|
_start_index: u64,
|
||||||
|
_roots: &[CommitmentTreeRoot<orchard::tree::MerkleHashOrchard>],
|
||||||
|
) -> Result<(), ShardTreeError<Self::Error>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle for the SQLite block source.
|
/// A handle for the SQLite block source.
|
||||||
|
|
Loading…
Reference in New Issue