2022-07-22 09:19:11 -07:00
|
|
|
//! Error types for Zebra's state.
|
|
|
|
|
2020-10-09 01:37:24 -07:00
|
|
|
use std::sync::Arc;
|
2020-12-02 20:48:34 -08:00
|
|
|
|
|
|
|
use chrono::{DateTime, Utc};
|
2020-10-09 01:37:24 -07:00
|
|
|
use thiserror::Error;
|
|
|
|
|
2021-07-22 16:40:15 -07:00
|
|
|
use zebra_chain::{
|
2021-08-25 06:57:07 -07:00
|
|
|
amount::{self, NegativeAllowed, NonNegative},
|
|
|
|
block,
|
|
|
|
history_tree::HistoryTreeError,
|
|
|
|
orchard, sapling, sprout, transaction, transparent,
|
|
|
|
value_balance::{ValueBalance, ValueBalanceError},
|
|
|
|
work::difficulty::CompactDifficulty,
|
2021-07-22 16:40:15 -07:00
|
|
|
};
|
2020-12-02 20:48:34 -08:00
|
|
|
|
2021-07-28 21:23:50 -07:00
|
|
|
use crate::constants::MIN_TRANSPARENT_COINBASE_MATURITY;
|
|
|
|
|
2020-10-09 01:37:24 -07:00
|
|
|
/// A wrapper for type erased errors that is itself clonable and implements the
|
|
|
|
/// Error trait
|
|
|
|
#[derive(Debug, Error, Clone)]
|
|
|
|
#[error(transparent)]
|
|
|
|
pub struct CloneError {
|
|
|
|
source: Arc<dyn std::error::Error + Send + Sync + 'static>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<CommitBlockError> for CloneError {
|
|
|
|
fn from(source: CommitBlockError) -> Self {
|
|
|
|
let source = Arc::new(source);
|
|
|
|
Self { source }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<BoxError> for CloneError {
|
|
|
|
fn from(source: BoxError) -> Self {
|
|
|
|
let source = Arc::from(source);
|
|
|
|
Self { source }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A boxed [`std::error::Error`].
|
|
|
|
pub type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
|
|
|
|
|
|
|
|
/// An error describing the reason a block could not be committed to the state.
|
2021-08-11 06:42:40 -07:00
|
|
|
#[derive(Debug, Error, PartialEq, Eq)]
|
2023-03-01 22:30:01 -08:00
|
|
|
#[error("block is not contextually valid: {}", .0)]
|
2020-10-09 01:37:24 -07:00
|
|
|
pub struct CommitBlockError(#[from] ValidateContextError);
|
|
|
|
|
|
|
|
/// An error describing why a block failed contextual validation.
|
2022-11-29 20:40:15 -08:00
|
|
|
#[derive(Debug, Error, Clone, PartialEq, Eq)]
|
2020-10-09 01:37:24 -07:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
#[allow(missing_docs)]
|
2020-10-09 01:37:24 -07:00
|
|
|
pub enum ValidateContextError {
|
change(state): Write non-finalized blocks to the state in a separate thread, to avoid network and RPC hangs (#5257)
* Add a new block commit task and channels, that don't do anything yet
* Add last_block_hash_sent to the state service, to avoid database accesses
* Update last_block_hash_sent regardless of commit errors
* Rename a field to StateService.max_queued_finalized_height
* Commit finalized blocks to the state in a separate task
* Check for panics in the block write task
* Wait for the block commit task in tests, and check for errors
* Always run a proptest that sleeps once
* Add extra debugging to state shutdowns
* Work around a RocksDB shutdown bug
* Close the finalized block channel when we're finished with it
* Only reset state queue once per error
* Update some TODOs
* Add a module doc comment
* Drop channels and check for closed channels in the block commit task
* Close state channels and tasks on drop
* Remove some duplicate fields across StateService and ReadStateService
* Try tweaking the shutdown steps
* Update and clarify some comments
* Clarify another comment
* Don't try to cancel RocksDB background work on drop
* Fix up some comments
* Remove some duplicate code
* Remove redundant workarounds for shutdown issues
* Remode a redundant channel close in the block commit task
* Remove a mistaken `!force` shutdown condition
* Remove duplicate force-shutdown code and explain it better
* Improve RPC error logging
* Wait for chain tip updates in the RPC tests
* Wait 2 seconds for chain tip updates before skipping them
* Remove an unnecessary block_in_place()
* Fix some test error messages that were changed by earlier fixes
* Expand some comments, fix typos
Co-authored-by: Marek <mail@marek.onl>
* Actually drop children of failed blocks
* Explain why we drop descendants of failed blocks
* Clarify a comment
* Wait for chain tip updates in a failing test on macOS
* Clean duplicate finalized blocks when the non-finalized state activates
* Send an error when receiving a duplicate finalized block
* Update checkpoint block behaviour, document its consensus rule
* Wait for chain tip changes in inbound_block_height_lookahead_limit test
* Wait for the genesis block to commit in the fake peer set mempool tests
* Disable unreliable mempool verification check in the send transaction test
* Appease rustfmt
* Use clear_finalized_block_queue() everywhere that blocks are dropped
* Document how Finalized and NonFinalized clones are different
* sends non-finalized blocks to the block write task
* passes ZebraDb to commit_new_chain, commit_block, and no_duplicates_in_finalized_chain instead of FinalizedState
* Update zebra-state/src/service/write.rs
Co-authored-by: teor <teor@riseup.net>
* updates comments, renames send_process_queued, other minor cleanup
* update assert_block_can_be_validated comment
* removes `mem` field from StateService
* removes `disk` field from StateService and updates block_iter to use `ZebraDb` instead of the finalized state
* updates tests that use the disk to use read_service.db instead
* moves best_tip to a read fn and returns finalized & non-finalized states from setup instead of the state service
* changes `contextual_validity` to get the network from the finalized_state instead of another param
* swaps out StateService with FinalizedState and NonFinalizedState in tests
* adds NotReadyToBeCommitted error and returns it from validate_and_commit when a blocks parent hash is not in any chain
* removes NonFinalizedWriteCmd and calls, moves update_latest_channels above rsp_tx.send
* makes parent_errors_map an indexmap
* clears non-finalized block queue when the receiver is dropped and when the StateService is being dropped
* sends non-finalized blocks to the block write task
* passes ZebraDb to commit_new_chain, commit_block, and no_duplicates_in_finalized_chain instead of FinalizedState
* updates comments, renames send_process_queued, other minor cleanup
* Update zebra-state/src/service/write.rs
Co-authored-by: teor <teor@riseup.net>
* update assert_block_can_be_validated comment
* removes `mem` field from StateService
* removes `disk` field from StateService and updates block_iter to use `ZebraDb` instead of the finalized state
* updates tests that use the disk to use read_service.db instead
* moves best_tip to a read fn and returns finalized & non-finalized states from setup instead of the state service
* changes `contextual_validity` to get the network from the finalized_state instead of another param
* swaps out StateService with FinalizedState and NonFinalizedState in tests
* adds NotReadyToBeCommitted error and returns it from validate_and_commit when a blocks parent hash is not in any chain
* removes NonFinalizedWriteCmd and calls, moves update_latest_channels above rsp_tx.send
* makes parent_errors_map an indexmap
* clears non-finalized block queue when the receiver is dropped and when the StateService is being dropped
* removes duplicate field definitions on StateService that were a result of a bad merge
* update NotReadyToBeCommitted error message
* Appear rustfmt
* Fix doc links
* Rename a function to initial_contextual_validity()
* Do error tasks on Err, and success tasks on Ok
* Simplify parent_error_map truncation
* Rewrite best_tip() to use tip()
* Rename latest_mem() to latest_non_finalized_state()
```sh
fastmod latest_mem latest_non_finalized_state zebra*
cargo fmt --all
```
* Simplify latest_non_finalized_state() using a new WatchReceiver API
* Expand some error messages
* Send the result after updating the channels, and document why
* wait for chain_tip_update before cancelling download in mempool_cancel_mined
* adds `sent_non_finalized_block_hashes` field to StateService
* adds batched sent_hash insertions and checks sent hashes in queue_and_commit_non_finalized before adding a block to the queue
* check that the `curr_buf` in SentHashes is not empty before pushing it to the `sent_bufs`
* Apply suggestions from code review
Co-authored-by: teor <teor@riseup.net>
* Fix rustfmt
* Check for finalized block heights using zs_contains()
* adds known_utxos field to SentHashes
* updates comment on SentHashes.add method
* Apply suggestions from code review
Co-authored-by: teor <teor@riseup.net>
* return early when there's a duplicate hash in QueuedBlocks.queue instead of panicking
* Make finalized UTXOs near the final checkpoint available for full block verification
* Replace a checkpoint height literal with the actual config
* Update mainnet and testnet checkpoints - 7 October 2022
* Fix some state service init arguments
* Allow more lookahead in the downloader, but less lookahead in the syncer
* Add the latest config to the tests, and fix the latest config check
* Increase the number of finalized blocks checked for non-finalized block UTXO spends
* fix(log): reduce verbose logs for block commits (#5348)
* Remove some verbose block write channel logs
* Only warn about tracing endpoint if the address is actually set
* Use CloneError instead of formatting a non-cloneable error
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
* Increase block verify timeout
* Work around a known block timeout bug by using a shorter timeout
Co-authored-by: teor <teor@riseup.net>
Co-authored-by: Marek <mail@marek.onl>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2022-10-11 12:25:45 -07:00
|
|
|
#[error("block parent not found in any chain")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
NotReadyToBeCommitted,
|
|
|
|
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block height {candidate_height:?} is lower than the current finalized height {finalized_tip_height:?}")]
|
2020-10-09 01:37:24 -07:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
OrphanedBlock {
|
|
|
|
candidate_height: block::Height,
|
|
|
|
finalized_tip_height: block::Height,
|
|
|
|
},
|
2020-11-12 20:26:16 -08:00
|
|
|
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block height {candidate_height:?} is not one greater than its parent block's height {parent_height:?}")]
|
2020-11-12 20:26:16 -08:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
NonSequentialBlock {
|
|
|
|
candidate_height: block::Height,
|
|
|
|
parent_height: block::Height,
|
|
|
|
},
|
2020-11-19 00:05:48 -08:00
|
|
|
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block time {candidate_time:?} is less than or equal to the median-time-past for the block {median_time_past:?}")]
|
2020-12-02 20:28:42 -08:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
TimeTooEarly {
|
|
|
|
candidate_time: DateTime<Utc>,
|
|
|
|
median_time_past: DateTime<Utc>,
|
|
|
|
},
|
2020-12-02 20:28:42 -08:00
|
|
|
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block time {candidate_time:?} is greater than the median-time-past for the block plus 90 minutes {block_time_max:?}")]
|
2020-12-02 20:28:42 -08:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
TimeTooLate {
|
|
|
|
candidate_time: DateTime<Utc>,
|
|
|
|
block_time_max: DateTime<Utc>,
|
|
|
|
},
|
2020-12-02 20:28:42 -08:00
|
|
|
|
2020-12-03 15:59:54 -08:00
|
|
|
#[error("block difficulty threshold {difficulty_threshold:?} is not equal to the expected difficulty for the block {expected_difficulty:?}")]
|
2020-11-19 00:05:48 -08:00
|
|
|
#[non_exhaustive]
|
2020-12-02 20:48:34 -08:00
|
|
|
InvalidDifficultyThreshold {
|
|
|
|
difficulty_threshold: CompactDifficulty,
|
|
|
|
expected_difficulty: CompactDifficulty,
|
|
|
|
},
|
2021-07-14 05:06:43 -07:00
|
|
|
|
2021-07-22 16:40:15 -07:00
|
|
|
#[error("transparent double-spend: {outpoint:?} is spent twice in {location:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
DuplicateTransparentSpend {
|
|
|
|
outpoint: transparent::OutPoint,
|
|
|
|
location: &'static str,
|
|
|
|
},
|
|
|
|
|
|
|
|
#[error("missing transparent output: possible double-spend of {outpoint:?} in {location:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
MissingTransparentOutput {
|
|
|
|
outpoint: transparent::OutPoint,
|
|
|
|
location: &'static str,
|
|
|
|
},
|
|
|
|
|
|
|
|
#[error("out-of-order transparent spend: {outpoint:?} is created by a later transaction in the same block")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
EarlyTransparentSpend { outpoint: transparent::OutPoint },
|
|
|
|
|
2021-07-28 21:23:50 -07:00
|
|
|
#[error(
|
|
|
|
"unshielded transparent coinbase spend: {outpoint:?} \
|
|
|
|
must be spent in a transaction which only has shielded outputs"
|
|
|
|
)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
UnshieldedTransparentCoinbaseSpend { outpoint: transparent::OutPoint },
|
|
|
|
|
|
|
|
#[error(
|
|
|
|
"immature transparent coinbase spend: \
|
|
|
|
attempt to spend {outpoint:?} at {spend_height:?}, \
|
|
|
|
but spends are invalid before {min_spend_height:?}, \
|
|
|
|
which is {MIN_TRANSPARENT_COINBASE_MATURITY:?} blocks \
|
|
|
|
after it was created at {created_height:?}"
|
|
|
|
)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
ImmatureTransparentCoinbaseSpend {
|
|
|
|
outpoint: transparent::OutPoint,
|
|
|
|
spend_height: block::Height,
|
|
|
|
min_spend_height: block::Height,
|
|
|
|
created_height: block::Height,
|
|
|
|
},
|
|
|
|
|
2021-07-14 05:06:43 -07:00
|
|
|
#[error("sprout double-spend: duplicate nullifier: {nullifier:?}, in finalized state: {in_finalized_state:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
DuplicateSproutNullifier {
|
|
|
|
nullifier: sprout::Nullifier,
|
|
|
|
in_finalized_state: bool,
|
|
|
|
},
|
Reject duplicate Sapling and Orchard nullifiers (#2497)
* Add sapling and orchard duplicate nullifier errors
* Reject duplicate finalized sapling and orchard nullifiers
Reject duplicate sapling and orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is already in the finalized state.
* Reject duplicate non-finalized sapling and orchard nullifiers
Reject duplicate sapling and orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block, or
* an earlier block in the non-finalized chain.
* Refactor sprout nullifier tests to remove common code
* Add sapling nullifier tests
Test that the state rejects duplicate sapling nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block,
* an earlier block in the non-finalized chain, or
* the finalized state.
* Add orchard nullifier tests
Test that the state rejects duplicate orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block,
* an earlier block in the non-finalized chain, or
* the finalized state.
* Check for specific nullifiers in the state in tests
* Replace slices with vectors in arguments
* Remove redundant code and variables
* Simplify sapling TransferData tests
Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
* Remove an extra :
* Remove redundant vec!
Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
2021-07-19 17:39:05 -07:00
|
|
|
|
|
|
|
#[error("sapling double-spend: duplicate nullifier: {nullifier:?}, in finalized state: {in_finalized_state:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
DuplicateSaplingNullifier {
|
|
|
|
nullifier: sapling::Nullifier,
|
|
|
|
in_finalized_state: bool,
|
|
|
|
},
|
|
|
|
|
|
|
|
#[error("orchard double-spend: duplicate nullifier: {nullifier:?}, in finalized state: {in_finalized_state:?}")]
|
|
|
|
#[non_exhaustive]
|
|
|
|
DuplicateOrchardNullifier {
|
|
|
|
nullifier: orchard::Nullifier,
|
|
|
|
in_finalized_state: bool,
|
|
|
|
},
|
2021-07-28 20:49:36 -07:00
|
|
|
|
2021-08-09 10:22:26 -07:00
|
|
|
#[error(
|
2021-08-25 06:57:07 -07:00
|
|
|
"the remaining value in the transparent transaction value pool MUST be nonnegative:\n\
|
|
|
|
{amount_error:?},\n\
|
|
|
|
{height:?}, index in block: {tx_index_in_block:?}, {transaction_hash:?}"
|
2021-08-09 10:22:26 -07:00
|
|
|
)]
|
2021-07-28 20:49:36 -07:00
|
|
|
#[non_exhaustive]
|
2021-08-09 10:22:26 -07:00
|
|
|
NegativeRemainingTransactionValue {
|
|
|
|
amount_error: amount::Error,
|
|
|
|
height: block::Height,
|
|
|
|
tx_index_in_block: usize,
|
2021-08-25 06:57:07 -07:00
|
|
|
transaction_hash: transaction::Hash,
|
2021-08-09 10:22:26 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
#[error(
|
2021-08-25 06:57:07 -07:00
|
|
|
"error calculating the remaining value in the transaction value pool:\n\
|
|
|
|
{amount_error:?},\n\
|
|
|
|
{height:?}, index in block: {tx_index_in_block:?}, {transaction_hash:?}"
|
2021-08-09 10:22:26 -07:00
|
|
|
)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
CalculateRemainingTransactionValue {
|
|
|
|
amount_error: amount::Error,
|
|
|
|
height: block::Height,
|
|
|
|
tx_index_in_block: usize,
|
2021-08-25 06:57:07 -07:00
|
|
|
transaction_hash: transaction::Hash,
|
2021-08-09 10:22:26 -07:00
|
|
|
},
|
|
|
|
|
|
|
|
#[error(
|
2021-08-25 06:57:07 -07:00
|
|
|
"error calculating value balances for the remaining value in the transaction value pool:\n\
|
|
|
|
{value_balance_error:?},\n\
|
|
|
|
{height:?}, index in block: {tx_index_in_block:?}, {transaction_hash:?}"
|
2021-08-09 10:22:26 -07:00
|
|
|
)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
CalculateTransactionValueBalances {
|
|
|
|
value_balance_error: ValueBalanceError,
|
|
|
|
height: block::Height,
|
|
|
|
tx_index_in_block: usize,
|
2021-08-25 06:57:07 -07:00
|
|
|
transaction_hash: transaction::Hash,
|
|
|
|
},
|
|
|
|
|
|
|
|
#[error(
|
|
|
|
"error calculating the block chain value pool change:\n\
|
|
|
|
{value_balance_error:?},\n\
|
|
|
|
{height:?}, {block_hash:?},\n\
|
|
|
|
transactions: {transaction_count:?}, spent UTXOs: {spent_utxo_count:?}"
|
|
|
|
)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
CalculateBlockChainValueChange {
|
|
|
|
value_balance_error: ValueBalanceError,
|
|
|
|
height: block::Height,
|
|
|
|
block_hash: block::Hash,
|
|
|
|
transaction_count: usize,
|
|
|
|
spent_utxo_count: usize,
|
|
|
|
},
|
|
|
|
|
|
|
|
#[error(
|
|
|
|
"error adding value balances to the chain value pool:\n\
|
|
|
|
{value_balance_error:?},\n\
|
|
|
|
{chain_value_pools:?},\n\
|
|
|
|
{block_value_pool_change:?},\n\
|
|
|
|
{height:?}"
|
|
|
|
)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
AddValuePool {
|
|
|
|
value_balance_error: ValueBalanceError,
|
|
|
|
chain_value_pools: ValueBalance<NonNegative>,
|
|
|
|
block_value_pool_change: ValueBalance<NegativeAllowed>,
|
|
|
|
height: Option<block::Height>,
|
2021-07-28 20:49:36 -07:00
|
|
|
},
|
2021-07-29 06:37:18 -07:00
|
|
|
|
2022-07-22 09:19:11 -07:00
|
|
|
#[error("error updating a note commitment tree")]
|
|
|
|
NoteCommitmentTreeError(#[from] zebra_chain::parallel::tree::NoteCommitmentTreeError),
|
2021-08-11 06:42:40 -07:00
|
|
|
|
|
|
|
#[error("error building the history tree")]
|
2022-11-29 20:40:15 -08:00
|
|
|
HistoryTreeError(#[from] Arc<HistoryTreeError>),
|
2021-08-17 07:49:27 -07:00
|
|
|
|
|
|
|
#[error("block contains an invalid commitment")]
|
|
|
|
InvalidBlockCommitment(#[from] block::CommitmentError),
|
2021-11-30 08:05:35 -08:00
|
|
|
|
2022-07-22 09:19:11 -07:00
|
|
|
#[error(
|
|
|
|
"unknown Sprout anchor: {anchor:?},\n\
|
|
|
|
{height:?}, index in block: {tx_index_in_block:?}, {transaction_hash:?}"
|
|
|
|
)]
|
2021-11-30 08:05:35 -08:00
|
|
|
#[non_exhaustive]
|
2022-07-22 09:19:11 -07:00
|
|
|
UnknownSproutAnchor {
|
|
|
|
anchor: sprout::tree::Root,
|
2022-11-29 20:40:15 -08:00
|
|
|
height: Option<block::Height>,
|
|
|
|
tx_index_in_block: Option<usize>,
|
2022-07-22 09:19:11 -07:00
|
|
|
transaction_hash: transaction::Hash,
|
|
|
|
},
|
2021-11-30 08:05:35 -08:00
|
|
|
|
2022-07-22 09:19:11 -07:00
|
|
|
#[error(
|
|
|
|
"unknown Sapling anchor: {anchor:?},\n\
|
|
|
|
{height:?}, index in block: {tx_index_in_block:?}, {transaction_hash:?}"
|
|
|
|
)]
|
2021-11-30 08:05:35 -08:00
|
|
|
#[non_exhaustive]
|
2022-07-22 09:19:11 -07:00
|
|
|
UnknownSaplingAnchor {
|
|
|
|
anchor: sapling::tree::Root,
|
2022-11-29 20:40:15 -08:00
|
|
|
height: Option<block::Height>,
|
|
|
|
tx_index_in_block: Option<usize>,
|
2022-07-22 09:19:11 -07:00
|
|
|
transaction_hash: transaction::Hash,
|
|
|
|
},
|
2021-11-30 08:05:35 -08:00
|
|
|
|
2022-07-22 09:19:11 -07:00
|
|
|
#[error(
|
|
|
|
"unknown Orchard anchor: {anchor:?},\n\
|
|
|
|
{height:?}, index in block: {tx_index_in_block:?}, {transaction_hash:?}"
|
|
|
|
)]
|
2021-11-30 08:05:35 -08:00
|
|
|
#[non_exhaustive]
|
2022-07-22 09:19:11 -07:00
|
|
|
UnknownOrchardAnchor {
|
|
|
|
anchor: orchard::tree::Root,
|
2022-11-29 20:40:15 -08:00
|
|
|
height: Option<block::Height>,
|
|
|
|
tx_index_in_block: Option<usize>,
|
2022-07-22 09:19:11 -07:00
|
|
|
transaction_hash: transaction::Hash,
|
|
|
|
},
|
2021-07-14 05:06:43 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Trait for creating the corresponding duplicate nullifier error from a nullifier.
|
2023-05-16 14:06:46 -07:00
|
|
|
pub trait DuplicateNullifierError {
|
2021-07-14 05:06:43 -07:00
|
|
|
/// Returns the corresponding duplicate nullifier error for `self`.
|
|
|
|
fn duplicate_nullifier_error(&self, in_finalized_state: bool) -> ValidateContextError;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DuplicateNullifierError for sprout::Nullifier {
|
|
|
|
fn duplicate_nullifier_error(&self, in_finalized_state: bool) -> ValidateContextError {
|
|
|
|
ValidateContextError::DuplicateSproutNullifier {
|
|
|
|
nullifier: *self,
|
|
|
|
in_finalized_state,
|
|
|
|
}
|
|
|
|
}
|
2020-10-09 01:37:24 -07:00
|
|
|
}
|
Reject duplicate Sapling and Orchard nullifiers (#2497)
* Add sapling and orchard duplicate nullifier errors
* Reject duplicate finalized sapling and orchard nullifiers
Reject duplicate sapling and orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is already in the finalized state.
* Reject duplicate non-finalized sapling and orchard nullifiers
Reject duplicate sapling and orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block, or
* an earlier block in the non-finalized chain.
* Refactor sprout nullifier tests to remove common code
* Add sapling nullifier tests
Test that the state rejects duplicate sapling nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block,
* an earlier block in the non-finalized chain, or
* the finalized state.
* Add orchard nullifier tests
Test that the state rejects duplicate orchard nullifiers in a new block,
when the block is added to a non-finalized chain,
and the duplicate nullifier is in:
* the same shielded data,
* the same transaction,
* the same block,
* an earlier block in the non-finalized chain, or
* the finalized state.
* Check for specific nullifiers in the state in tests
* Replace slices with vectors in arguments
* Remove redundant code and variables
* Simplify sapling TransferData tests
Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
* Remove an extra :
* Remove redundant vec!
Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
2021-07-19 17:39:05 -07:00
|
|
|
|
|
|
|
impl DuplicateNullifierError for sapling::Nullifier {
|
|
|
|
fn duplicate_nullifier_error(&self, in_finalized_state: bool) -> ValidateContextError {
|
|
|
|
ValidateContextError::DuplicateSaplingNullifier {
|
|
|
|
nullifier: *self,
|
|
|
|
in_finalized_state,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DuplicateNullifierError for orchard::Nullifier {
|
|
|
|
fn duplicate_nullifier_error(&self, in_finalized_state: bool) -> ValidateContextError {
|
|
|
|
ValidateContextError::DuplicateOrchardNullifier {
|
|
|
|
nullifier: *self,
|
|
|
|
in_finalized_state,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|