Skip to content

Commit

Permalink
feat(wallet): add check for network and genesis_hash consistency
Browse files Browse the repository at this point in the history
- add new `MismatchError::Genesis` and `DescriptorError::Mismatch` error
  variants, when the genesis_hash parameter and network are
  inconsistent.
- add check on `create_with_params` to check that `genesis_hash` and
  `network` genesis hash are consistent, return `Descriptor::Mismatch`
  error otherwise.
- add check on `load_with_params` to check that `check_genesis_hash`
  is also consistent with the genesis hash of current loaded `network`,
  return the `LoadMismatch` error variant otherwise.
  • Loading branch information
oleonardolima committed Dec 16, 2024
1 parent dbc6a1e commit e60e101
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 1 deletion.
15 changes: 15 additions & 0 deletions crates/wallet/src/descriptor/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ pub enum Error {
Hex(bitcoin::hex::HexToBytesError),
/// The provided wallet descriptors are identical
ExternalAndInternalAreTheSame,
/// The provided parameters mismatch
Mismatch(MismatchError),
}

impl From<crate::keys::KeyError> for Error {
Expand Down Expand Up @@ -83,6 +85,7 @@ impl fmt::Display for Error {
Self::ExternalAndInternalAreTheSame => {
write!(f, "External and internal descriptors are the same")
}
Self::Mismatch(mismatch) => write!(f, "The provided parameters mismatch: {mismatch:?}"),
}
}
}
Expand Down Expand Up @@ -125,3 +128,15 @@ impl From<crate::descriptor::policy::PolicyError> for Error {
Error::Policy(err)
}
}

#[derive(Debug, PartialEq)]
/// Represents a mismatch within the parameters that passed as [`CreateParams`].
pub enum MismatchError {
/// Genesis hash does not match.
Genesis {
/// The genesis hash for the given network parameter.
network: bitcoin::BlockHash,
/// The genesis hash given as parameter.
parameter: bitcoin::BlockHash,
},
}
21 changes: 20 additions & 1 deletion crates/wallet/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ pub mod signer;
pub mod tx_builder;
pub(crate) mod utils;

use crate::collections::{BTreeMap, HashMap, HashSet};
use crate::descriptor::{
check_wallet_descriptor, error::Error as DescriptorError, policy::BuildSatisfaction,
DerivedDescriptor, DescriptorMeta, ExtendedDescriptor, ExtractPolicy, IntoWalletDescriptor,
Expand All @@ -74,6 +73,10 @@ use crate::wallet::{
tx_builder::{FeePolicy, TxBuilder, TxParams},
utils::{check_nsequence_rbf, After, Older, SecpCtx},
};
use crate::{
collections::{BTreeMap, HashMap, HashSet},
descriptor::error::MismatchError,
};

// re-exports
pub use bdk_chain::Balance;
Expand Down Expand Up @@ -372,6 +375,14 @@ impl Wallet {
let genesis_hash = params
.genesis_hash
.unwrap_or(genesis_block(network).block_hash());

if genesis_hash.ne(&genesis_block(network).block_hash()) {
return Err(DescriptorError::Mismatch(MismatchError::Genesis {
network: genesis_block(network).block_hash(),
parameter: genesis_hash,
}));
}

let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash);

let (descriptor, mut descriptor_keymap) = (params.descriptor)(&secp, network)?;
Expand Down Expand Up @@ -506,6 +517,14 @@ impl Wallet {
expected: exp_genesis_hash,
}));
}

let network_genesis_hash = genesis_block(network).block_hash();
if network_genesis_hash != exp_genesis_hash {
return Err(LoadError::Mismatch(LoadMismatch::Genesis {
loaded: network_genesis_hash,
expected: exp_genesis_hash,
}));
}
}

let descriptor = changeset
Expand Down
19 changes: 19 additions & 0 deletions crates/wallet/tests/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use anyhow::Context;
use assert_matches::assert_matches;
use bdk_chain::{BlockId, ChainPosition, ConfirmationBlockTime};
use bdk_wallet::coin_selection::{self, LargestFirstCoinSelection};
use bdk_wallet::descriptor::error::MismatchError;
use bdk_wallet::descriptor::{calc_checksum, DescriptorError, IntoWalletDescriptor};
use bdk_wallet::error::CreateTxError;
use bdk_wallet::psbt::PsbtUtils;
Expand Down Expand Up @@ -355,6 +356,24 @@ fn test_error_external_and_internal_are_the_same() {
);
}

#[test]
fn test_create_genesis_hash_and_network_consistency() {
let (external_desc, internal_desc) = get_test_tr_single_sig_xprv_and_change_desc();
let mainnet_genesis_hash = BlockHash::from_byte_array(ChainHash::BITCOIN.to_bytes());
let err = Wallet::create(external_desc, internal_desc)
.genesis_hash(mainnet_genesis_hash)
.network(Network::Regtest)
.create_wallet_no_persist();

assert!(
matches!(
&err,
Err(DescriptorError::Mismatch(MismatchError::Genesis { .. }))
),
"unexpected network and genesis_hash parameter check result: `genesis_hash` network (Mainnet) does not match network parameter (Regtest)",
);
}

#[test]
fn test_descriptor_checksum() {
let (wallet, _) = get_funded_wallet_wpkh();
Expand Down

0 comments on commit e60e101

Please sign in to comment.