diff --git a/Justfile b/Justfile new file mode 100644 index 00000000..7b3c5da9 --- /dev/null +++ b/Justfile @@ -0,0 +1,46 @@ +set quiet := true +msrv := "1.63" + +# list of recipes +default: + just --list + +# format the project code +fmt: + cargo +nightly fmt + +# lint the project, skip examples if using msrv +clippy: fmt + if rustc --version | fgrep -q "{{msrv}}"; then \ + cargo clippy --workspace --exclude 'example_*' --all-features --tests; \ + else \ + cargo clippy --all-features --tests; \ + fi + +# build the project, skip examples if using msrv +build: fmt + if rustc --version | fgrep -q "{{msrv}}"; then \ + cargo build --workspace --exclude 'example_*' --all-features --tests; \ + else \ + cargo build --all-features --tests; \ + fi + +# test the project, skip examples if using msrv +test: + if rustc --version | fgrep -q "{{msrv}}"; then \ + cargo test --workspace --exclude 'example_*' --all-features --tests; \ + else \ + cargo test --all-features --tests; \ + fi + +# clean the project target directory +clean: + cargo clean + +# set the rust version to stable +stable: clean + rustup override set stable; cargo update + +# set the rust version to the msrv and pin dependencies +msrv: clean + rustup override set {{msrv}}; cargo update; ./ci/pin-msrv.sh \ No newline at end of file diff --git a/rust-version b/rust-version index f288d111..f6342716 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1.85.0 +1.87.0 diff --git a/wallet/src/wallet/mod.rs b/wallet/src/wallet/mod.rs index 58f5057b..28dc3d6a 100644 --- a/wallet/src/wallet/mod.rs +++ b/wallet/src/wallet/mod.rs @@ -226,9 +226,9 @@ pub enum LoadMismatch { /// Keychain identifying the descriptor. keychain: KeychainKind, /// The loaded descriptor. - loaded: Option, + loaded: Box>, /// The expected descriptor. - expected: Option, + expected: Box>, }, } @@ -258,11 +258,9 @@ impl fmt::Display for LoadMismatch { f, "Descriptor mismatch for {} keychain: loaded {}, expected {}", keychain, - loaded - .as_ref() - .map_or("None".to_string(), |d| d.to_string()), + loaded.clone().map_or("None".to_string(), |d| d.to_string()), expected - .as_ref() + .clone() .map_or("None".to_string(), |d| d.to_string()) ) } @@ -278,7 +276,7 @@ impl From for LoadError { impl From for LoadWithPersistError { fn from(mismatch: LoadMismatch) -> Self { - Self::InvalidChangeSet(LoadError::Mismatch(mismatch)) + Self::InvalidChangeSet(Box::new(LoadError::Mismatch(mismatch))) } } @@ -559,8 +557,8 @@ impl Wallet { if descriptor.descriptor_id() != exp_desc.descriptor_id() { return Err(LoadError::Mismatch(LoadMismatch::Descriptor { keychain: KeychainKind::External, - loaded: Some(descriptor), - expected: Some(exp_desc), + loaded: Box::new(Some(descriptor)), + expected: Box::new(Some(exp_desc)), })); } if params.extract_keys { @@ -569,8 +567,8 @@ impl Wallet { } else { return Err(LoadError::Mismatch(LoadMismatch::Descriptor { keychain: KeychainKind::External, - loaded: Some(descriptor), - expected: None, + loaded: Box::new(Some(descriptor)), + expected: Box::new(None), })); } } @@ -588,8 +586,8 @@ impl Wallet { let (exp_desc, _) = make_desc(&secp, network).map_err(LoadError::Descriptor)?; return Err(LoadError::Mismatch(LoadMismatch::Descriptor { keychain: KeychainKind::Internal, - loaded: None, - expected: Some(exp_desc), + loaded: Box::new(None), + expected: Box::new(Some(exp_desc)), })); } } @@ -603,8 +601,8 @@ impl Wallet { None => { return Err(LoadError::Mismatch(LoadMismatch::Descriptor { keychain: KeychainKind::Internal, - loaded: Some(desc), - expected: None, + loaded: Box::new(Some(desc)), + expected: Box::new(None), })) } // parameters must match @@ -615,8 +613,8 @@ impl Wallet { if desc.descriptor_id() != exp_desc.descriptor_id() { return Err(LoadError::Mismatch(LoadMismatch::Descriptor { keychain: KeychainKind::Internal, - loaded: Some(desc), - expected: Some(exp_desc), + loaded: Box::new(Some(desc)), + expected: Box::new(Some(exp_desc)), })); } if params.extract_keys { diff --git a/wallet/src/wallet/persisted.rs b/wallet/src/wallet/persisted.rs index 48203cc4..72396049 100644 --- a/wallet/src/wallet/persisted.rs +++ b/wallet/src/wallet/persisted.rs @@ -150,7 +150,9 @@ impl PersistedWallet

{ ) -> Result> { let existing = P::initialize(persister).map_err(CreateWithPersistError::Persist)?; if !existing.is_empty() { - return Err(CreateWithPersistError::DataAlreadyExists(existing)); + return Err(CreateWithPersistError::DataAlreadyExists(Box::new( + existing, + ))); } let mut inner = Wallet::create_with_params(params).map_err(CreateWithPersistError::Descriptor)?; @@ -176,7 +178,7 @@ impl PersistedWallet

{ _marker: PhantomData, }) }) - .map_err(LoadWithPersistError::InvalidChangeSet) + .map_err(|cs| LoadWithPersistError::InvalidChangeSet(Box::new(cs))) } /// Persist staged changes of wallet into `persister`. @@ -207,7 +209,9 @@ impl PersistedWallet

{ .await .map_err(CreateWithPersistError::Persist)?; if !existing.is_empty() { - return Err(CreateWithPersistError::DataAlreadyExists(existing)); + return Err(CreateWithPersistError::DataAlreadyExists(Box::new( + existing, + ))); } let mut inner = Wallet::create_with_params(params).map_err(CreateWithPersistError::Descriptor)?; @@ -237,7 +241,7 @@ impl PersistedWallet

{ _marker: PhantomData, }) }) - .map_err(LoadWithPersistError::InvalidChangeSet) + .map_err(|cs| LoadWithPersistError::InvalidChangeSet(Box::new(cs))) } /// Persist staged changes of wallet into an async `persister`. @@ -295,7 +299,7 @@ impl WalletPersister for bdk_chain::rusqlite::Connection { #[derive(Debug)] pub enum FileStoreError { /// Error when loading from the store. - Load(bdk_file_store::StoreErrorWithDump), + Load(Box>), /// Error when writing to the store. Write(std::io::Error), } @@ -322,7 +326,7 @@ impl WalletPersister for bdk_file_store::Store { persister .dump() .map(Option::unwrap_or_default) - .map_err(FileStoreError::Load) + .map_err(|e| FileStoreError::Load(Box::new(e))) } fn persist(persister: &mut Self, changeset: &ChangeSet) -> Result<(), Self::Error> { @@ -336,7 +340,7 @@ pub enum LoadWithPersistError { /// Error from persistence. Persist(E), /// Occurs when the loaded changeset cannot construct [`Wallet`]. - InvalidChangeSet(crate::LoadError), + InvalidChangeSet(Box), } impl fmt::Display for LoadWithPersistError { @@ -357,7 +361,7 @@ pub enum CreateWithPersistError { /// Error from persistence. Persist(E), /// Persister already has wallet data. - DataAlreadyExists(ChangeSet), + DataAlreadyExists(Box), /// Occurs when the loaded changeset cannot construct [`Wallet`]. Descriptor(DescriptorError), } diff --git a/wallet/tests/wallet.rs b/wallet/tests/wallet.rs index fc6bf165..29168f46 100644 --- a/wallet/tests/wallet.rs +++ b/wallet/tests/wallet.rs @@ -151,40 +151,64 @@ fn wallet_load_checks() -> anyhow::Result<()> { .network(network) .create_wallet(&mut create_db(&file_path)?)?; + let _expected_err = LoadWithPersistError::::InvalidChangeSet(Box::new( + LoadError::Mismatch(LoadMismatch::Network { + loaded: Network::Testnet, + expected: Network::Regtest, + }), + )); assert_matches!( Wallet::load() .check_network(Network::Regtest) .load_wallet(&mut open_db(&file_path)?), - Err(LoadWithPersistError::InvalidChangeSet(LoadError::Mismatch( - LoadMismatch::Network { - loaded: Network::Testnet, - expected: Network::Regtest, - } - ))), + Err(_expected_err), "unexpected network check result: Regtest (check) is not Testnet (loaded)", ); let mainnet_hash = BlockHash::from_byte_array(ChainHash::BITCOIN.to_bytes()); + let _expected_err = LoadWithPersistError::::InvalidChangeSet(Box::new( + LoadError::Mismatch(LoadMismatch::Genesis { + loaded: BlockHash::from_byte_array(ChainHash::REGTEST.to_bytes()), + expected: mainnet_hash, + }), + )); assert_matches!( Wallet::load().check_genesis_hash(mainnet_hash).load_wallet(&mut open_db(&file_path)?), - Err(LoadWithPersistError::InvalidChangeSet(LoadError::Mismatch(LoadMismatch::Genesis { .. }))), + Err(_expected_err), "unexpected genesis hash check result: mainnet hash (check) is not testnet hash (loaded)", ); + let secp = Secp256k1::new(); + let external_desc_pub = Descriptor::parse_descriptor(&secp, external_desc) + .expect("invalid external descriptor") + .0; + let internal_desc_pub = Descriptor::parse_descriptor(&secp, internal_desc) + .expect("invalid internal descriptor") + .0; + let _expected_err = LoadWithPersistError::::InvalidChangeSet(Box::new( + LoadError::Mismatch(LoadMismatch::Descriptor { + keychain: KeychainKind::External, + loaded: Box::new(Some(external_desc_pub.clone())), + expected: Box::new(Some(internal_desc_pub.clone())), + }), + )); assert_matches!( Wallet::load() .descriptor(KeychainKind::External, Some(internal_desc)) .load_wallet(&mut open_db(&file_path)?), - Err(LoadWithPersistError::InvalidChangeSet(LoadError::Mismatch( - LoadMismatch::Descriptor { .. } - ))), + Err(_expected_err), "unexpected descriptors check result", ); + let _expected_err = LoadWithPersistError::::InvalidChangeSet(Box::new( + LoadError::Mismatch(LoadMismatch::Descriptor { + keychain: KeychainKind::External, + loaded: Box::new(Some(internal_desc_pub.clone())), + expected: Box::new(None), + }), + )); assert_matches!( Wallet::load() .descriptor(KeychainKind::External, Option::<&str>::None) .load_wallet(&mut open_db(&file_path)?), - Err(LoadWithPersistError::InvalidChangeSet(LoadError::Mismatch( - LoadMismatch::Descriptor { .. } - ))), + Err(_expected_err), "unexpected descriptors check result", ); // check setting keymaps @@ -318,10 +342,17 @@ fn single_descriptor_wallet_persist_and_recover() { .descriptor(KeychainKind::Internal, Some(desc)) .extract_keys() .load_wallet(&mut db); + let _expected_err = LoadWithPersistError::::InvalidChangeSet(Box::new( + LoadError::Mismatch(LoadMismatch::Descriptor { + keychain: KeychainKind::Internal, + loaded: Box::new(None), + expected: Box::new(Some(exp_desc)), + }), + )); + //if keychain == && loaded.is_none() && expected == Some(exp_desc); assert_matches!( err, - Err(LoadWithPersistError::InvalidChangeSet(LoadError::Mismatch(LoadMismatch::Descriptor { keychain, loaded, expected }))) - if keychain == KeychainKind::Internal && loaded.is_none() && expected == Some(exp_desc), + Err(_expected_err), "single descriptor wallet should refuse change descriptor param" ); }