Skip to content

Commit

Permalink
Require BlockSource::with_blocks fail on non-existent from_height
Browse files Browse the repository at this point in the history
Previously this was not clearly specified, and the implementations in
`zcash_client_sqlite` behaved similarly to when `from_height = None`.

Closes #892.
  • Loading branch information
str4d committed Aug 9, 2023
1 parent 81d1928 commit 44abd34
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 2 deletions.
3 changes: 2 additions & 1 deletion zcash_client_backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ and this library adheres to Rust's notion of
permits the caller to control the starting position of the scan range.
In addition, the `limit` parameter is now required and has type `usize`.
- `chain::BlockSource::with_blocks` now takes its limit as an `Option<usize>`
instead of `Option<u32>`.
instead of `Option<u32>`. It is also now required to return an error if
`from_height` is set to a block that does not exist in `self`.
- A new `CommitmentTree` variant has been added to `data_api::error::Error`
- `wallet::{create_spend_to_address, create_proposed_transaction,
shield_transparent_funds}` all now require that `WalletCommitmentTrees` be
Expand Down
2 changes: 2 additions & 0 deletions zcash_client_backend/src/data_api/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ pub trait BlockSource {
/// `from_height`, applying the provided callback to each block. If `from_height`
/// is `None` then scanning will begin at the first available block.
///
/// Returns an error if `from_height` is set to a block that does not exist in `self`.
///
/// * `WalletErrT`: the types of errors produced by the wallet operations performed
/// as part of processing each row.
/// * `NoteRefT`: the type of note identifiers in the wallet data store, for use in
Expand Down
8 changes: 7 additions & 1 deletion zcash_client_sqlite/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ and this library adheres to Rust's notion of
a note could be spent with fewer than `min_confirmations` confirmations if the
wallet did not contain enough observed blocks to satisfy the `min_confirmations`
value specified; this situation is now treated as an error.
- A `BlockConflict` variant has been added to `zcash_client_sqlite::error::SqliteClientError`
- `zcash_client_sqlite::error::SqliteClientError` has new error variants:
- `SqliteClientError::BlockConflict`
- `SqliteClientError::CacheMiss`
- `zcash_client_backend::FsBlockDbError` has a new error variant:
- `FsBlockDbError::CacheMiss`
- `zcash_client_sqlite::FsBlockDb::write_block_metadata` now overwrites any
existing metadata entries that have the same height as a new entry.

Expand All @@ -39,6 +43,8 @@ and this library adheres to Rust's notion of
- Fixed an off-by-one error in the `BlockSource` implementation for the SQLite-backed
`BlockDb` block database which could result in blocks being skipped at the start of
scan ranges.
- `zcash_client_sqlite::{BlockDb, FsBlockDb}::with_blocks` now return an error
if `from_height` is set to a block height that does not exist in the cache.
- `WalletDb::get_transaction` no longer returns an error when called on a transaction
that has not yet been mined, unless the transaction's consensus branch ID cannot be
determined by other means.
Expand Down
34 changes: 34 additions & 0 deletions zcash_client_sqlite/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,20 @@ where
])
.map_err(to_chain_error)?;

// Only look for the `from_height` in the scanned blocks if it is set.
let mut from_height_found = from_height.is_none();
while let Some(row) = rows.next().map_err(to_chain_error)? {
let height = BlockHeight::from_u32(row.get(0).map_err(to_chain_error)?);
if !from_height_found {
// We will only perform this check on the first row.
let from_height = from_height.expect("can only reach here if set");
if from_height != height {
return Err(to_chain_error(SqliteClientError::CacheMiss(from_height)));
} else {
from_height_found = true;
}
}

let data: Vec<u8> = row.get(1).map_err(to_chain_error)?;
let block = CompactBlock::decode(&data[..]).map_err(to_chain_error)?;
if block.height() != height {
Expand All @@ -73,6 +85,11 @@ where
with_row(block)?;
}

if !from_height_found {
let from_height = from_height.expect("can only reach here if set");
return Err(to_chain_error(SqliteClientError::CacheMiss(from_height)));
}

Ok(())
}

Expand Down Expand Up @@ -260,8 +277,20 @@ where
)
.map_err(to_chain_error)?;

// Only look for the `from_height` in the scanned blocks if it is set.
let mut from_height_found = from_height.is_none();
for row_result in rows {
let cbr = row_result.map_err(to_chain_error)?;
if !from_height_found {
// We will only perform this check on the first row.
let from_height = from_height.expect("can only reach here if set");
if from_height != cbr.height {
return Err(to_chain_error(FsBlockDbError::CacheMiss(from_height)));
} else {
from_height_found = true;
}
}

let mut block_file =
File::open(cbr.block_file_path(&cache.blocks_dir)).map_err(to_chain_error)?;
let mut block_data = vec![];
Expand All @@ -282,6 +311,11 @@ where
with_block(block)?;
}

if !from_height_found {
let from_height = from_height.expect("can only reach here if set");
return Err(to_chain_error(FsBlockDbError::CacheMiss(from_height)));
}

Ok(())
}

Expand Down
3 changes: 3 additions & 0 deletions zcash_client_sqlite/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ pub enum SqliteClientError {
/// An error occurred in inserting data into or accessing data from one of the wallet's note
/// commitment trees.
CommitmentTree(ShardTreeError<commitment_tree::Error>),

CacheMiss(BlockHeight),
}

impl error::Error for SqliteClientError {
Expand Down Expand Up @@ -128,6 +130,7 @@ impl fmt::Display for SqliteClientError {
#[cfg(feature = "transparent-inputs")]
SqliteClientError::AddressNotRecognized(_) => write!(f, "The address associated with a received txo is not identifiable as belonging to the wallet."),
SqliteClientError::CommitmentTree(err) => write!(f, "An error occurred accessing or updating note commitment tree data: {}.", err),
SqliteClientError::CacheMiss(height) => write!(f, "Requested height {} does not exist in the block cache.", height),
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions zcash_client_sqlite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,7 @@ pub enum FsBlockDbError {
InvalidBlockstoreRoot(PathBuf),
InvalidBlockPath(PathBuf),
CorruptedData(String),
CacheMiss(BlockHeight),
}

#[cfg(feature = "unstable")]
Expand Down Expand Up @@ -1047,6 +1048,13 @@ impl std::fmt::Display for FsBlockDbError {
e,
)
}
FsBlockDbError::CacheMiss(height) => {
write!(
f,
"Requested height {} does not exist in the block cache",
height
)
}
}
}
}
Expand Down

0 comments on commit 44abd34

Please sign in to comment.