From d55fa094644f989371275dd5480372141e2f9fed Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Thu, 6 Jul 2023 08:18:57 -0600 Subject: [PATCH] Add a check to ensure that blocks passed to `put_blocks` are sequential. --- zcash_client_backend/src/data_api.rs | 2 ++ zcash_client_sqlite/src/error.rs | 4 ++++ zcash_client_sqlite/src/lib.rs | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/zcash_client_backend/src/data_api.rs b/zcash_client_backend/src/data_api.rs index ceae06764..ad7a8bdda 100644 --- a/zcash_client_backend/src/data_api.rs +++ b/zcash_client_backend/src/data_api.rs @@ -494,6 +494,8 @@ pub trait WalletWrite: WalletRead { /// Updates the state of the wallet database by persisting the provided block information, /// along with the note commitments that were detected when scanning the block for transactions /// pertaining to this wallet. + /// + /// `blocks` must be sequential, in order of increasing block height fn put_blocks( &mut self, block: Vec>, diff --git a/zcash_client_sqlite/src/error.rs b/zcash_client_sqlite/src/error.rs index 1dd14f1c2..9058359d4 100644 --- a/zcash_client_sqlite/src/error.rs +++ b/zcash_client_sqlite/src/error.rs @@ -57,6 +57,9 @@ pub enum SqliteClientError { /// different hash. This indicates that a required rewind was not performed. BlockConflict(BlockHeight), + /// A range of blocks provided to the database as a unit was non-sequential + NonSequentialBlocks, + /// A requested rewind would violate invariants of the storage layer. The payload returned with /// this error is (safe rewind height, requested height). RequestedRewindInvalid(BlockHeight, BlockHeight), @@ -118,6 +121,7 @@ impl fmt::Display for SqliteClientError { SqliteClientError::Io(e) => write!(f, "{}", e), SqliteClientError::InvalidMemo(e) => write!(f, "{}", e), SqliteClientError::BlockConflict(h) => write!(f, "A block hash conflict occurred at height {}; rewind required.", u32::from(*h)), + SqliteClientError::NonSequentialBlocks => write!(f, "`put_blocks` requires that the provided block range be sequential"), SqliteClientError::DiversifierIndexOutOfRange => write!(f, "The space of available diversifier indices is exhausted"), SqliteClientError::KeyDerivationError(acct_id) => write!(f, "Key derivation failed for account {:?}", acct_id), SqliteClientError::AccountIdDiscontinuity => write!(f, "Wallet account identifiers must be sequential."), diff --git a/zcash_client_sqlite/src/lib.rs b/zcash_client_sqlite/src/lib.rs index 4bb84e596..1686145ad 100644 --- a/zcash_client_sqlite/src/lib.rs +++ b/zcash_client_sqlite/src/lib.rs @@ -412,6 +412,10 @@ impl WalletWrite for WalletDb let mut end_height = None; for block in blocks.into_iter() { + if end_height.iter().any(|prev| block.height() != *prev + 1) { + return Err(SqliteClientError::NonSequentialBlocks); + } + // Insert the block into the database. wallet::put_block( wdb.conn.0,