From: Alekos Filini Date: Mon, 7 Dec 2020 18:23:48 +0000 (+0100) Subject: [blog] Add the "Hello World" article X-Git-Url: http://internal-gitweb-vhost/script/%22https:/struct.DecoderReader.html?a=commitdiff_plain;h=defd52fe949a8cc59662ef08846ebfac05891ee1;p=bitcoindevkit.org [blog] Add the "Hello World" article --- diff --git a/config.toml b/config.toml index 8999b0fe5e..6fb055194b 100644 --- a/config.toml +++ b/config.toml @@ -30,6 +30,9 @@ custom_css = ["css/style.css", "css/jsonview.css", "css/blog.css"] # Used for social media preview cards images = ["images/logo-wide.jpg"] +# Disable the "copy to clipboard" button for inline code +disableInlineCopyToClipBoard = true + [permalinks] tags = "/blog/tags/:slug" author = "/blog/author/:slug" diff --git a/content/blog/2020/hello-world.md b/content/blog/2020/hello-world.md new file mode 100644 index 0000000000..520d829839 --- /dev/null +++ b/content/blog/2020/hello-world.md @@ -0,0 +1,208 @@ +--- +title: "Hello World!" +description: "Getting started using the BDK library in a very simple Rust project" +author: "Alekos Filini" +date: "2020-12-18" +tags: ["getting started", "rust"] +hidden: true +draft: false +--- + +## Introduction + +This article should serve as a "getting started" guide for developers who are considering integrating BDK in their own projects: it tries to introduce the reader to the basic concepts behind the library and some of its +modules and components that can be used to build a very simple functioning Bitcoin wallet. All the informations written in this article are valid for the current `master` git branch, and should remain valid for the upcoming [`v0.2.0` release](https://github.com/bitcoindevkit/bdk/projects/1) +which is planned to be tagged pretty soon. + +## Design Goals + +The main goal of the library is to be a solid foundation for Bitcoin wallets of any kind, on any platform: in practice this means that the library should be: + +- Very well reviewed and tested +- Lightweight, so that it can be used easily on mobile devices as well +- Extendable, so that it can be adapted to perfectly suit different use-cases +- Generalized, meaning that it supports different types of Bitcoin scripts and wallets through the use of [descriptors][descriptor] +- Reasonably easy to use, exposing a "high level" interface to the user and hiding all the complexity inside + +These goals have a direct impact on the design of the internal components of the library, and as a consequence on the APIs that are exposed to the final user, which might in some cases feel counter-intuitive at first. +Throughout the article I will try to focus on those points and try to explain them as best as I can. + +## The `Wallet` Structure + +The [`Wallet`][wallet] structure is in many ways the heart of the library: it represents an instance of a wallet and exposes some APIs to perform all the typical operations one might want to do with a Bitcoin wallet, +such as generating a new address, listing the transactions received, creating a transaction, etc. + +A `Wallet` instance can be constructed given at least one [descriptor] which would be used to derive both [`External`][KeychainKind] and [`Internal`][KeychainKind] addresses, or two if one prefers to keep them separated. `External` addresses are the +ones returned by an explicit [`Wallet::get_new_address()`][get_new_address] call, while `Internal` addresses are generated internally to receive the change whenever a new transaction is created. + +A `Wallet` also needs at least one other component to function properly, its [`Database`][Database]: it will be used as a *cache* to store the list of transactions synchronized with the blockchain, the UTXOs, the addresses generated, and a few other things. It's important +to note that the `Database` will never store any secret. Securely storing keys is explicitly left to the user of the library to implement, mainly because there isn't really one good way to do it, that would work reliably on every platform. On +mobile devices, for instance, the OS' keychain could be used, to allow unlocking the secrets with the use of biometric data (FaceID or fingerprint), while on desktop platform there isn't generally a similar +framework available and the user would have to implement something that meets their needs. It's not excluded that in the future we could provide a "reference implementation" of a secure multi-platform storage for keys, +but that would very likely be released as a separate module outside of the `Wallet` structure, or potentially even as a separate library that could be reused for other applications as well. + +Going back to our `Wallet`: given a descriptor and a `Database` we can build an "air-gapped", or "Offline" wallet: basically a wallet that physically doesn't have the ability to connect to the Bitcoin network. It will still be able to generate addresses and +sign [PSBTs][PSBT], but with a greatly reduced attack surface because a sizable part of the code that handles the logic to synchronize with the network would be entirely omitted in the final executable binary. + +This is how an `OfflineWallet` can be created. Notice that we are using [`MemoryDatabase`][MemoryDatabase] as our `Database`. We'll get to that in a second. + +```rust +use bdk::{Wallet, OfflineWallet}; +use bdk::database::MemoryDatabase; +use bdk::bitcoin::Network; + +fn main() -> Result<(), Box> { + let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/0/*)"; + let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/0'/0'/1/*)"; + + let wallet: OfflineWallet<_> = Wallet::new_offline( + external_descriptor, + Some(internal_descriptor), + Network::Testnet, + MemoryDatabase::new(), + )?; + + Ok(()) +} +``` + +Once we have our `Wallet` instance we can generate a new address and print it out: + +```rust +// ... + +println!("Generated Address: {}", wallet.get_new_address()?); +``` + +Building and running this code will print out: + +```text +Generated Address: tb1q7w0t936xp5p994qx506xj53gjdcmzjr2mkqghn +``` + +Before we've talked about the benefits of air-gapped wallet, but we should also talk about the disadvantages: the biggest one is the fact that it cannot create new transactions because +it doesn't know which UTXOs belong to the wallet. To get this information we generally need to `sync` with the network, but this wallet can't physically do that. + +To fix this we can add one more component to our `Wallet`: a [`Blockchain`][Blockchain] backend. In particular we are going to use the [`ElectrumBlockchain`][ElectrumBlockchain] which syncs with an `Electrum` server, +since that's available out of the box in BDK and is pretty fast. + +We can change our `Wallet` construction to look something like this: + +```rust +use bdk::blockchain::ElectrumBlockchain; +use bdk::electrum_client::Client; + +// ... + +let wallet = Wallet::new( + external_descriptor, + Some(internal_descriptor), + Network::Testnet, + MemoryDatabase::new(), + ElectrumBlockchain::from(Client::new("ssl://electrum.blockstream.info:60002").unwrap()), +)?; +``` + +This piece of code is very similar to the one we wrote before, but this time we are using the [`Wallet::new()`][Wallet_new] constructor instead of [`Wallet::new_offline()`][Wallet_new_offline], and this takes an extra argument for the `Blockchain` type to use. +Specifically here, we create an `ElectrumBlockchain` and connect to Blockstream's public Electrum Testnet servers over SSL. + +Now, since we are running in the `Testnet` network, we can try to get some funds from a faucet online to this address we've generated. Once we have an incoming transaction we can do the first `sync` of our *online* wallet. +this is again something that might seem counterintuitve at first: why do we have to manually ask the `Wallet` to *sync* itself? Can't it do it periodically in background? The answer is that yes, that would definitely be possible, +but it would remove some control on what's happening inside the wallet from the user. This can be especially problematic on mobile platforms, where the OS tries very aggressively to suspend apps in background to save +battery. Having a thread running and trying to make network requests while the app is in background would very likely cause errors or potentially crashes somewhere. So for this reason this operation has to be performed manually, +to allow the user to call that function only at the right time. + +```rust +use bdk::blockchain::noop_progress; + +// ... + +wallet.sync(noop_progress(), None)?; +``` + +In this case we are not interested in receiving updates about the progress, and we just want to use the default settings, so we use [`noop_progress()`][noop_progress] and `None` as arguments. This will make queries to the Electrum server +and store the list of transactions and UTXOs in our `Database`. In this case, we are using a `MemoryDatabase`, so those information are only going to be kept in RAM and dropped once our `Wallet` is dropped. This is very useful +for playing around and experimenting, but not so great for real world wallets: for that, you can use [sled][sled] which is supported out of the box or even use a custom database. More on that later! + +So now that we've synced with the blockchain we can create our first transaction. First of all, we will print out the balance of our wallet to make sure that our wallet has seen the incoming transaction. Then we +will create the actual transaction and we will specify some flags using the [`TxBuilder`][TxBuilder]. To finish it off, we will ask the wallet to sign the transaction and then broadcast it to the network. + +Right now we will not get into details of all the available options in `TxBuilder` since that is definitely out of scope of a "getting started" guide. For now you can just imagine the builder as your way to tell the library +how to build transactions. We'll come back to this in a future article. + +```rust +use std::str::FromStr; + +use bdk::bitcoin::Address; +use bdk::TxBuilder; + +// ... + +let balance = wallet.get_balance()?; +println!("Wallet balance in SAT: {}", balance); + +let faucet_address = Address::from_str("mkHS9ne12qx9pS9VojpwU5xtRd4T7X7ZUt")?; +let (unsigned_psbt, tx_details) = wallet.create_tx( + TxBuilder::with_recipients(vec![(faucet_address.script_pubkey(), balance / 2)]) + .enable_rbf(), +)?; +println!("Transaction details: {:#?}", tx_details); +``` + +In this case we are sending back half the balance to the faucet's address and we are also enabling RBF, since the default fees are at 1 satoshi/vbyte. With RBF we will be able to *bump the fees* of the transaction, should it get +stuck in the mempool due to the low fee rate. + +All that's left to do once we have our unsigned PSBT is to sign it: + +```rust +// ... + +let (signed_psbt, tx_finalized) = wallet.sign(unsigned_psbt, None)?; +assert!(tx_finalized, "Tx has not been finalized"); +``` + +And then broadcast it: + +```rust +// ... + +let raw_transaction = signed_psbt.extract_tx(); +let txid = wallet.broadcast(raw_transaction)?; +println!( + "Transaction sent! TXID: {txid}.\nExplorer URL: https://blockstream.info/testnet/tx/{txid}", + txid = txid +); +``` + +## Custom Database and Blockchain types + +We briefly mentioned before that for our example we used the `MemoryDatabase`, but that it could also be swapped for a different one: this is one example of the *modularity* of BDK. By default some database +types are implemented in the library, namely (as of now) the `MemoryDatabase` which only keeps data in RAM and the [sled][sled] database that can store data on a filesystem. But since the `Database` trait is public, +users of the library can also implement different database types more suitable for their use-case. + +The same is true for the `Blockchain` types: the library provides (through the use of opt-in features) an implementation for the `Electrum`, `Esplora` and `CompactFilters` (*Neutrino*) backends. Those again can also be +swapped with custom types if the user desires to do so. + +## Conclusion + +Hopefully this article will help you get started with BDK! This is just a very quick and gentle introduction to the library, and only barely scratches the surface of what's inside: we will keep publishing more +articles in the future to explain some of the more advanced features of BDK, like key generation, using complex [descriptors][descriptor] with multiple keys and/or timelocks, using external signers, etc. + +If you'd like to learn more about the library feel free to ask any questions in the comment section down below, or join our [Discord Community](https://discord.gg/d7NkDKm) to chat with us directly! + + +[descriptor]: /descriptors +[PSBT]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki +[sled]: https://docs.rs/sled/ + +[Wallet]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/struct.Wallet.html +[KeychainKind]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.KeychainKind.html +[get_new_address]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/struct.Wallet.html#method.get_new_address +[Database]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.Database.html +[MemoryDatabase]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/struct.MemoryDatabase.html +[Blockchain]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.Blockchain.html +[ElectrumBlockchain]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/struct.ElectrumBlockchain.html +[Wallet_new]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/struct.Wallet.html#method.new +[Wallet_new_offline]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/struct.Wallet.html#method.new_offline +[noop_progress]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.noop_progress.html +[TxBuilder]: /docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.TxBuilder.html diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/.lock b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/.lock new file mode 100644 index 0000000000..e69de29bb2 diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/COPYRIGHT.txt b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/COPYRIGHT.txt new file mode 100644 index 0000000000..af77776cca --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/COPYRIGHT.txt @@ -0,0 +1,45 @@ +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff, FiraSans-Medium.woff): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.woff, SourceCodePro-Semibold.woff): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif Pro (SourceSerifPro-Regular.ttf.woff, + SourceSerifPro-Bold.ttf.woff, SourceSerifPro-It.ttf.woff): + + Copyright 2014 Adobe Systems Incorporated (http://www.adobe.com/), with + Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of + Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerifPro-LICENSE.txt. + +This copyright file is intended to be distributed with rustdoc output. diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/FiraSans-LICENSE.txt b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/FiraSans-LICENSE.txt new file mode 100644 index 0000000000..d444ea92b6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/FiraSans-LICENSE.txt @@ -0,0 +1,94 @@ +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/FiraSans-Medium.woff b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/FiraSans-Medium.woff new file mode 100644 index 0000000000..7d742c5fb7 Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/FiraSans-Medium.woff differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/FiraSans-Regular.woff b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/FiraSans-Regular.woff new file mode 100644 index 0000000000..d8e0363f4e Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/FiraSans-Regular.woff differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/LICENSE-APACHE.txt b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/LICENSE-APACHE.txt new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/LICENSE-APACHE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/LICENSE-MIT.txt b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/LICENSE-MIT.txt new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/LICENSE-MIT.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceCodePro-LICENSE.txt b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceCodePro-LICENSE.txt new file mode 100644 index 0000000000..07542572e3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceCodePro-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceCodePro-Regular.woff b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceCodePro-Regular.woff new file mode 100644 index 0000000000..5576670903 Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceCodePro-Regular.woff differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceCodePro-Semibold.woff b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceCodePro-Semibold.woff new file mode 100644 index 0000000000..ca972a11dc Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceCodePro-Semibold.woff differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-Bold.ttf.woff b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-Bold.ttf.woff new file mode 100644 index 0000000000..ca254318fe Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-Bold.ttf.woff differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-It.ttf.woff b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-It.ttf.woff new file mode 100644 index 0000000000..a287bbe6ed Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-It.ttf.woff differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-LICENSE.md b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-LICENSE.md new file mode 100644 index 0000000000..22cb755f2f --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-LICENSE.md @@ -0,0 +1,93 @@ +Copyright 2014-2018 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-Regular.ttf.woff b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-Regular.ttf.woff new file mode 100644 index 0000000000..a3d55cfdf2 Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/SourceSerifPro-Regular.ttf.woff differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/ayu.css b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/ayu.css new file mode 100644 index 0000000000..ae61550be2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/ayu.css @@ -0,0 +1 @@ + body{background-color:#0f1419;color:#c5c5c5;}h1,h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod){color:white;}h1.fqn{border-bottom-color:#5c6773;}h1.fqn a{color:#fff;}h2,h3:not(.impl):not(.method):not(.type):not(.tymethod){border-bottom-color:#5c6773;}h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant){border:none;}.in-band{background-color:#0f1419;}.invisible{background:rgba(0,0,0,0);}code{color:#ffb454;}h3>code,h4>code,h5>code{color:#e6e1cf;}pre>code{color:#e6e1cf;}span code{color:#e6e1cf;}.docblock a>code{color:#39AFD7 !important;}.docblock code,.docblock-short code{background-color:#191f26;}pre{color:#e6e1cf;background-color:#191f26;}.sidebar{background-color:#14191f;}.logo-container.rust-logo>img{filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);}*{scrollbar-color:#5c6773 transparent;}.sidebar{scrollbar-color:#5c6773 transparent;}::-webkit-scrollbar-track{background-color:transparent;}::-webkit-scrollbar-thumb{background-color:#5c6773;}.sidebar::-webkit-scrollbar-track{background-color:transparent;}.sidebar::-webkit-scrollbar-thumb{background-color:#5c6773;}.sidebar .current{background-color:transparent;color:#ffb44c;}.source .sidebar{background-color:#0f1419;}.sidebar .location{border-color:#000;background-color:#0f1419;color:#fff;}.sidebar-elems .location{color:#ff7733;}.sidebar-elems .location a{color:#fff;}.sidebar .version{border-bottom-color:#424c57;}.sidebar-title{border-top-color:#5c6773;border-bottom-color:#5c6773;}.block a:hover{background:transparent;color:#ffb44c;}.line-numbers span{color:#5c6773;}.line-numbers .line-highlighted{color:#708090;background-color:rgba(255,236,164,0.06);padding-right:4px;border-right:1px solid #ffb44c;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5{border-bottom-color:#5c6773;}.docblock table,.docblock table td,.docblock table th{border-color:#5c6773;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#c5c5c5;}.content .highlighted{color:#000 !important;background-color:#c6afb3;}.content .highlighted a,.content .highlighted span{color:#000 !important;}.content .highlighted{background-color:#c6afb3;}.search-results a{color:#0096cf;}.search-results a span.desc{color:#c5c5c5;}.content .item-info::before{color:#ccc;}.content span.foreigntype,.content a.foreigntype{color:#ef57ff;}.content span.union,.content a.union{color:#98a01c;}.content span.constant,.content a.constant,.content span.static,.content a.static{color:#6380a0;}.content span.primitive,.content a.primitive{color:#32889b;}.content span.traitalias,.content a.traitalias{color:#57d399;}.content span.keyword,.content a.keyword{color:#de5249;}.content span.externcrate,.content span.mod,.content a.mod{color:#acccf9;}.content span.struct,.content a.struct{color:#ffa0a5;}.content span.enum,.content a.enum{color:#99e0c9;}.content span.trait,.content a.trait{color:#39AFD7;}.content span.type,.content a.type{color:#cfbcf5;}.content span.fn,.content a.fn,.content span.method,.content a.method,.content span.tymethod,.content a.tymethod,.content .fnname{color:#fdd687;}.content span.attr,.content a.attr,.content span.derive,.content a.derive,.content span.macro,.content a.macro{color:#a37acc;}pre.rust .comment{color:#788797;}pre.rust .doccomment{color:#a1ac88;}nav:not(.sidebar){border-bottom-color:#424c57;}nav.main .current{border-top-color:#5c6773;border-bottom-color:#5c6773;}nav.main .separator{border:1px solid #5c6773;}a{color:#c5c5c5;}.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),.docblock-short a:not(.srclink):not(.test-arrow),.item-info a,#help a{color:#39AFD7;}.collapse-toggle{color:#999;}#crate-search{color:#c5c5c5;background-color:#141920;box-shadow:0 0 0 1px #424c57,0 0 0 2px transparent;border-color:#424c57;}.search-input{color:#ffffff;background-color:#141920;box-shadow:0 0 0 1px #424c57,0 0 0 2px transparent;transition:box-shadow 150ms ease-in-out;}#crate-search+.search-input:focus{box-shadow:0 0 0 1px #148099,0 0 0 2px transparent;}.search-focus:disabled{color:#929292;}.module-item .stab{color:#000;}.stab.unstable,.stab.deprecated,.stab.portability{color:#c5c5c5;background:#314559 !important;border-style:none !important;border-radius:4px;padding:3px 6px 3px 6px;}.stab.portability>code{color:#e6e1cf;background-color:transparent;}#help>div{background:#14191f;box-shadow:0px 6px 20px 0px black;border:none;border-radius:4px;}#help>div>span{border-bottom-color:#5c6773;}.since{color:grey;}tr.result span.primitive::after,tr.result span.keyword::after{color:#788797;}.line-numbers :target{background-color:transparent;}pre.rust .number,pre.rust .string{color:#b8cc52;}pre.rust .kw,pre.rust .kw-2,pre.rust .prelude-ty,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .op,pre.rust .lifetime{color:#ff7733;}pre.rust .macro,pre.rust .macro-nonterminal{color:#a37acc;}pre.rust .question-mark{color:#ff9011;}pre.rust .self{color:#36a3d9;font-style:italic;}pre.rust .attribute{color:#e6e1cf;}pre.rust .attribute .ident,pre.rust .attribute .op{color:#e6e1cf;}.example-wrap>pre.line-number{color:#5c67736e;border:none;}a.test-arrow{font-size:100%;color:#788797;border-radius:4px;background-color:rgba(57,175,215,0.09);}a.test-arrow:hover{background-color:rgba(57,175,215,0.368);color:#c5c5c5;}.toggle-label{color:#999;}:target>code,:target>.in-band{background:rgba(255,236,164,0.06);border-right:3px solid rgba(255,180,76,0.85);}pre.compile_fail{border-left:2px solid rgba(255,0,0,.4);}pre.compile_fail:hover,.information:hover+pre.compile_fail{border-left:2px solid #f00;}pre.should_panic{border-left:2px solid rgba(255,0,0,.4);}pre.should_panic:hover,.information:hover+pre.should_panic{border-left:2px solid #f00;}pre.ignore{border-left:2px solid rgba(255,142,0,.6);}pre.ignore:hover,.information:hover+pre.ignore{border-left:2px solid #ff9200;}.tooltip.compile_fail{color:rgba(255,0,0,.5);}.information>.compile_fail:hover{color:#f00;}.tooltip.should_panic{color:rgba(255,0,0,.5);}.information>.should_panic:hover{color:#f00;}.tooltip.ignore{color:rgba(255,142,0,.6);}.information>.ignore:hover{color:#ff9200;}.search-failed a{color:#39AFD7;}.tooltip .tooltiptext{background-color:#314559;color:#c5c5c5;border:1px solid #5c6773;}.tooltip .tooltiptext::after{border-color:transparent #314559 transparent transparent;}.notable-traits-tooltiptext{background-color:#314559;border-color:#5c6773;}#titles>button.selected{background-color:#141920 !important;border-bottom:1px solid #ffb44c !important;border-top:none;}#titles>button:not(.selected){background-color:transparent !important;border:none;}#titles>button:hover{border-bottom:1px solid rgba(242,151,24,0.3);}#titles>button>div.count{color:#888;}.content .highlighted.mod,.content .highlighted.externcrate{}.search-input:focus{}.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro{}.content .highlighted.trait{}.content span.struct,.content a.struct,.block a.current.struct{}#titles>button:hover,#titles>button.selected{}.content .highlighted.traitalias{}.content span.type,.content a.type,.block a.current.type{}.content span.union,.content a.union,.block a.current.union{}.content .highlighted.foreigntype{}pre.rust .lifetime{}.content .highlighted.primitive{}.content .highlighted.constant,.content .highlighted.static{}.stab.unstable{}.content .highlighted.fn,.content .highlighted.method,.content .highlighted.tymethod{}h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod){}.content span.enum,.content a.enum,.block a.current.enum{}.content span.constant,.content a.constant,.block a.current.constant,.content span.static,.content a.static,.block a.current.static{}.content span.keyword,.content a.keyword,.block a.current.keyword{}pre.rust .comment{}.content .highlighted.enum{}.content .highlighted.struct{}.content .highlighted.keyword{}.content span.traitalias,.content a.traitalias,.block a.current.traitalias{}.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,.content .fnname{}pre.rust .kw{}pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,pre.rust .attribute .ident{}.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype{}pre.rust .doccomment{}.stab.deprecated{}.content .highlighted.attr,.content .highlighted.derive,.content .highlighted.macro{}.stab.portability{}.content .highlighted.union{}.content span.primitive,.content a.primitive,.block a.current.primitive{}.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod{}.content .highlighted.type{}pre.rust .kw-2,pre.rust .prelude-ty{}.content span.trait,.content a.trait,.block a.current.trait{}@media (max-width:700px){.sidebar-menu{background-color:#14191f;border-bottom-color:#5c6773;border-right-color:#5c6773;}.sidebar-elems{background-color:#14191f;border-right-color:#5c6773;}#sidebar-filler{background-color:#14191f;border-bottom-color:#5c6773;}}kbd{color:#c5c5c5;background-color:#314559;border-color:#5c6773;border-bottom-color:#5c6773;box-shadow-color:#c6cbd1;}#theme-picker,#settings-menu,.help-button{border-color:#5c6773;background-color:#0f1419;color:#fff;}#theme-picker>img,#settings-menu>img{filter:invert(100);}#theme-picker:hover,#theme-picker:focus,#settings-menu:hover,#settings-menu:focus,.help-button:hover,.help-button:focus{border-color:#e0e0e0;}#theme-choices{border-color:#5c6773;background-color:#0f1419;}#theme-choices>button:not(:first-child){border-top-color:#5c6773;}#theme-choices>button:hover,#theme-choices>button:focus{background-color:rgba(110,110,110,0.33);}@media (max-width:700px){#theme-picker{background:#0f1419;}}#all-types{background-color:#14191f;}#all-types:hover{background-color:rgba(70,70,70,0.33);}.search-results td span.alias{color:#c5c5c5;}.search-results td span.grey{color:#999;}#sidebar-toggle{background-color:#14191f;}#sidebar-toggle:hover{background-color:rgba(70,70,70,0.33);}#source-sidebar{background-color:#14191f;}#source-sidebar>.title{color:#fff;border-bottom-color:#5c6773;}div.files>a:hover,div.name:hover{background-color:#14191f;color:#ffb44c;}div.files>.selected{background-color:#14191f;color:#ffb44c;}.setting-line>.title{border-bottom-color:#5c6773;}input:checked+.slider{background-color:#ffb454 !important;} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/all.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/all.html new file mode 100644 index 0000000000..35d47a2b03 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/all.html @@ -0,0 +1,6 @@ +List of all items in this crate + +

[] + + List of all items

Structs

Enums

Traits

Macros

Functions

Typedefs

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/enum.AnyBlockchain.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/enum.AnyBlockchain.html new file mode 100644 index 0000000000..916f07b121 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/enum.AnyBlockchain.html @@ -0,0 +1,52 @@ +bdk::blockchain::any::AnyBlockchain - Rust + +

[][src]Enum bdk::blockchain::any::AnyBlockchain

pub enum AnyBlockchain {
+    Electrum(ElectrumBlockchain),
+    Esplora(EsploraBlockchain),
+    CompactFilters(CompactFiltersBlockchain),
+}

Type that can contain any of the Blockchain types defined by the library

+

It allows switching backend at runtime

+

See this module's documentation for a usage example.

+

+ Variants

+
This is supported on crate feature electrum only.

Electrum client

+
This is supported on crate feature esplora only.

Esplora client

+
CompactFilters(CompactFiltersBlockchain)
This is supported on crate feature compact_filters only.

Compact filters client

+

Trait Implementations

impl Blockchain for AnyBlockchain[src]

impl ConfigurableBlockchain for AnyBlockchain[src]

type Config = AnyBlockchainConfig

Type that contains the configuration

+

impl From<CompactFiltersBlockchain> for AnyBlockchain[src]

impl From<ElectrumBlockchain> for AnyBlockchain[src]

impl From<EsploraBlockchain> for AnyBlockchain[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> BlockchainMarker for T where
    T: Blockchain
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/enum.AnyBlockchainConfig.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/enum.AnyBlockchainConfig.html new file mode 100644 index 0000000000..a034ec2a32 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/enum.AnyBlockchainConfig.html @@ -0,0 +1,47 @@ +bdk::blockchain::any::AnyBlockchainConfig - Rust + +

[][src]Enum bdk::blockchain::any::AnyBlockchainConfig

pub enum AnyBlockchainConfig {
+    Electrum(ElectrumBlockchainConfig),
+    Esplora(EsploraBlockchainConfig),
+    CompactFilters(CompactFiltersBlockchainConfig),
+}

Type that can contain any of the blockchain configurations defined by the library

+

This allows storing a single configuration that can be loaded into an AnyBlockchain +instance. Wallets that plan to offer users the ability to switch blockchain backend at runtime +will find this particularly useful.

+

+ Variants

+
This is supported on crate feature electrum only.

Electrum client

+
This is supported on crate feature esplora only.

Esplora client

+
This is supported on crate feature compact_filters only.

Compact filters client

+

Trait Implementations

impl Debug for AnyBlockchainConfig[src]

impl<'de> Deserialize<'de> for AnyBlockchainConfig[src]

impl From<CompactFiltersBlockchainConfig> for AnyBlockchainConfig[src]

impl From<ElectrumBlockchainConfig> for AnyBlockchainConfig[src]

impl From<EsploraBlockchainConfig> for AnyBlockchainConfig[src]

impl Serialize for AnyBlockchainConfig[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/index.html new file mode 100644 index 0000000000..70a7a733eb --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/index.html @@ -0,0 +1,47 @@ +bdk::blockchain::any - Rust + +

[][src]Module bdk::blockchain::any

Runtime-checked blockchain types

+

This module provides the implementation of AnyBlockchain which allows switching the +inner Blockchain type at runtime.

+

Example

+

In this example both wallet_electrum and wallet_esplora have the same type of +Wallet<AnyBlockchain, MemoryDatabase>. This means that they could both, for instance, be +assigned to a struct member.

+ +
+let electrum_blockchain = ElectrumBlockchain::from(electrum_client::Client::new("...")?);
+let wallet_electrum: Wallet<AnyBlockchain, _> = Wallet::new(
+    "...",
+    None,
+    Network::Testnet,
+    MemoryDatabase::default(),
+    electrum_blockchain.into(),
+)?;
+
+let esplora_blockchain = EsploraBlockchain::new("...", None);
+let wallet_esplora: Wallet<AnyBlockchain, _> = Wallet::new(
+    "...",
+    None,
+    Network::Testnet,
+    MemoryDatabase::default(),
+    esplora_blockchain.into(),
+)?;
+
+

When paired with the use of ConfigurableBlockchain, it allows creating wallets with any +blockchain type supported using a single line of code:

+ +
+let config = serde_json::from_str("...")?;
+let blockchain = AnyBlockchain::from_config(&config)?;
+let wallet = Wallet::new(
+    "...",
+    None,
+    Network::Testnet,
+    MemoryDatabase::default(),
+    blockchain,
+)?;
+

Enums

+
AnyBlockchain

Type that can contain any of the Blockchain types defined by the library

+
AnyBlockchainConfig

Type that can contain any of the blockchain configurations defined by the library

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/sidebar-items.js new file mode 100644 index 0000000000..14144cf693 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/any/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["AnyBlockchain","Type that can contain any of the [`Blockchain`] types defined by the library"],["AnyBlockchainConfig","Type that can contain any of the blockchain configurations defined by the library"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/enum.CompactFiltersError.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/enum.CompactFiltersError.html new file mode 100644 index 0000000000..3fba9f11c4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/enum.CompactFiltersError.html @@ -0,0 +1,73 @@ +bdk::blockchain::compact_filters::CompactFiltersError - Rust + +

[][src]Enum bdk::blockchain::compact_filters::CompactFiltersError

pub enum CompactFiltersError {
+    InvalidResponse,
+    InvalidHeaders,
+    InvalidFilterHeader,
+    InvalidFilter,
+    MissingBlock,
+    DataCorruption,
+    NotConnected,
+    Timeout,
+    NoPeers,
+    DB(Error),
+    IO(Error),
+    BIP158(Error),
+    Time(SystemTimeError),
+    Global(Box<Error>),
+}
This is supported on crate feature compact_filters only.

An error that can occur during sync with a CompactFiltersBlockchain

+

+ Variants

+
InvalidResponse

A peer sent an invalid or unexpected response

+
InvalidHeaders

The headers returned are invalid

+
InvalidFilterHeader

The compact filter headers returned are invalid

+
InvalidFilter

The compact filter returned is invalid

+
MissingBlock

The peer is missing a block in the valid chain

+
DataCorruption

The data stored in the block filters storage are corrupted

+
NotConnected

A peer is not connected

+
Timeout

A peer took too long to reply to one of our messages

+
NoPeers

No peers have been specified

+
DB(Error)

Internal database error

+
IO(Error)

Internal I/O error

+
BIP158(Error)

Invalid BIP158 filter

+

Internal system time error

+
Global(Box<Error>)

Wrapper for crate::error::Error

+

Trait Implementations

impl Debug for CompactFiltersError[src]

impl Display for CompactFiltersError[src]

impl Error for CompactFiltersError[src]

impl From<CompactFiltersError> for Error[src]

impl From<Error> for CompactFiltersError[src]

impl From<Error> for CompactFiltersError[src]

impl From<Error> for CompactFiltersError[src]

impl From<Error> for CompactFiltersError[src]

impl From<SystemTimeError> for CompactFiltersError[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/index.html new file mode 100644 index 0000000000..53f3f770e2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/index.html @@ -0,0 +1,39 @@ +bdk::blockchain::compact_filters - Rust + +

[][src]Module bdk::blockchain::compact_filters

This is supported on crate feature compact_filters only.

Compact Filters

+

This module contains a multithreaded implementation of an Blockchain backend that +uses BIP157 (aka "Neutrino") to populate the wallet's database +by downloading compact filters from the P2P network.

+

Since there are currently very few peers "in the wild" that advertise the required service +flag, this implementation requires that one or more known peers are provided by the user. +No dns or other kinds of peer discovery are done internally.

+

Moreover, this module doesn't currently support detecting and resolving conflicts between +messages received by different peers. Thus, it's recommended to use this module by only +connecting to a single peer at a time, optionally by opening multiple connections if it's +desirable to use multiple threads at once to sync in parallel.

+

This is an EXPERIMENTAL feature, API and other major changes are expected.

+

Example

+
+let num_threads = 4;
+
+let mempool = Arc::new(Mempool::default());
+let peers = (0..num_threads)
+    .map(|_| {
+        Peer::connect(
+            "btcd-mainnet.lightning.computer:8333",
+            Arc::clone(&mempool),
+            Network::Bitcoin,
+        )
+    })
+    .collect::<Result<_, _>>()?;
+let blockchain = CompactFiltersBlockchain::new(peers, "./wallet-filters", Some(500_000))?;
+

Structs

+
BitcoinPeerConfig

Data to connect to a Bitcoin P2P peer

+
CompactFiltersBlockchain

Structure implementing the required blockchain traits

+
CompactFiltersBlockchainConfig

Configuration for a CompactFiltersBlockchain

+
Mempool

Container for unconfirmed, but valid Bitcoin transactions

+
Peer

A Bitcoin peer

+

Enums

+
CompactFiltersError

An error that can occur during sync with a CompactFiltersBlockchain

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/peer/struct.Mempool.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/peer/struct.Mempool.html new file mode 100644 index 0000000000..cd04378cbe --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/peer/struct.Mempool.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../../../bdk/blockchain/compact_filters/struct.Mempool.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/peer/struct.Peer.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/peer/struct.Peer.html new file mode 100644 index 0000000000..11332c3bdb --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/peer/struct.Peer.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../../../bdk/blockchain/compact_filters/struct.Peer.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/sidebar-items.js new file mode 100644 index 0000000000..187af79563 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["CompactFiltersError","An error that can occur during sync with a [`CompactFiltersBlockchain`]"]],"struct":[["BitcoinPeerConfig","Data to connect to a Bitcoin P2P peer"],["CompactFiltersBlockchain","Structure implementing the required blockchain traits"],["CompactFiltersBlockchainConfig","Configuration for a [`CompactFiltersBlockchain`]"],["Mempool","Container for unconfirmed, but valid Bitcoin transactions"],["Peer","A Bitcoin peer"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.BitcoinPeerConfig.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.BitcoinPeerConfig.html new file mode 100644 index 0000000000..822c73d161 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.BitcoinPeerConfig.html @@ -0,0 +1,40 @@ +bdk::blockchain::compact_filters::BitcoinPeerConfig - Rust + +

[][src]Struct bdk::blockchain::compact_filters::BitcoinPeerConfig

pub struct BitcoinPeerConfig {
+    pub address: String,
+    pub socks5: Option<String>,
+    pub socks5_credentials: Option<(String, String)>,
+}
This is supported on crate feature compact_filters only.

Data to connect to a Bitcoin P2P peer

+

+ Fields

address: String

Peer address such as 127.0.0.1:18333

+
socks5: Option<String>

Optional socks5 proxy

+
socks5_credentials: Option<(String, String)>

Optional socks5 proxy credentials

+

Trait Implementations

impl Debug for BitcoinPeerConfig[src]

impl<'de> Deserialize<'de> for BitcoinPeerConfig[src]

impl Serialize for BitcoinPeerConfig[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.CompactFiltersBlockchain.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.CompactFiltersBlockchain.html new file mode 100644 index 0000000000..c99aa78694 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.CompactFiltersBlockchain.html @@ -0,0 +1,49 @@ +bdk::blockchain::compact_filters::CompactFiltersBlockchain - Rust + +

[][src]Struct bdk::blockchain::compact_filters::CompactFiltersBlockchain

pub struct CompactFiltersBlockchain { /* fields omitted */ }
This is supported on crate feature compact_filters only.

Structure implementing the required blockchain traits

+

Example

+

See the blockchain::compact_filters module for a usage example.

+

Implementations

impl CompactFiltersBlockchain[src]

pub fn new<P: AsRef<Path>>(
    peers: Vec<Peer>,
    storage_dir: P,
    skip_blocks: Option<usize>
) -> Result<Self, CompactFiltersError>
[src]

Construct a new instance given a list of peers, a path to store headers and block +filters downloaded during the sync and optionally a number of blocks to ignore starting +from the genesis while scanning for the wallet's outputs.

+

For each Peer specified a new thread will be spawned to download and verify the filters +in parallel. It's currently recommended to only connect to a single peer to avoid +inconsistencies in the data returned, optionally with multiple connections in parallel to +speed-up the sync process.

+

Trait Implementations

impl Blockchain for CompactFiltersBlockchain[src]

impl ConfigurableBlockchain for CompactFiltersBlockchain[src]

type Config = CompactFiltersBlockchainConfig

Type that contains the configuration

+

impl Debug for CompactFiltersBlockchain[src]

impl From<CompactFiltersBlockchain> for AnyBlockchain[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> BlockchainMarker for T where
    T: Blockchain
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.CompactFiltersBlockchainConfig.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.CompactFiltersBlockchainConfig.html new file mode 100644 index 0000000000..0d8ad732f9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.CompactFiltersBlockchainConfig.html @@ -0,0 +1,43 @@ +bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig - Rust + +

[][src]Struct bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig

pub struct CompactFiltersBlockchainConfig {
+    pub peers: Vec<BitcoinPeerConfig>,
+    pub network: Network,
+    pub storage_dir: String,
+    pub skip_blocks: Option<usize>,
+}
This is supported on crate feature compact_filters only.

Configuration for a CompactFiltersBlockchain

+

+ Fields

peers: Vec<BitcoinPeerConfig>

List of peers to try to connect to for asking headers and filters

+
network: Network

Network used

+
storage_dir: String

Storage dir to save partially downloaded headers and full blocks

+
skip_blocks: Option<usize>

Optionally skip initial skip_blocks blocks (default: 0)

+

Trait Implementations

impl Debug for CompactFiltersBlockchainConfig[src]

impl<'de> Deserialize<'de> for CompactFiltersBlockchainConfig[src]

impl From<CompactFiltersBlockchainConfig> for AnyBlockchainConfig[src]

impl Serialize for CompactFiltersBlockchainConfig[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.Mempool.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.Mempool.html new file mode 100644 index 0000000000..e03a70996f --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.Mempool.html @@ -0,0 +1,39 @@ +bdk::blockchain::compact_filters::Mempool - Rust + +

[][src]Struct bdk::blockchain::compact_filters::Mempool

pub struct Mempool { /* fields omitted */ }
This is supported on crate feature compact_filters only.

Container for unconfirmed, but valid Bitcoin transactions

+

It is normally shared between Peers with the use of Arc, so that transactions are not +duplicated in memory.

+

Implementations

impl Mempool[src]

pub fn add_tx(&self, tx: Transaction)[src]

Add a transaction to the mempool

+

Note that this doesn't propagate the transaction to other +peers. To do that, broadcast should be used.

+

pub fn get_tx(&self, inventory: &Inventory) -> Option<Transaction>[src]

Look-up a transaction in the mempool given an [Inventory] request

+

pub fn has_tx(&self, txid: &Txid) -> bool[src]

Return whether or not the mempool contains a transaction with a given txid

+

pub fn iter_txs(&self) -> Vec<Transaction>[src]

Return the list of transactions contained in the mempool

+

Trait Implementations

impl Debug for Mempool[src]

impl Default for Mempool[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.Peer.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.Peer.html new file mode 100644 index 0000000000..5c3eb0c9a9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/compact_filters/struct.Peer.html @@ -0,0 +1,43 @@ +bdk::blockchain::compact_filters::Peer - Rust + +

[][src]Struct bdk::blockchain::compact_filters::Peer

pub struct Peer { /* fields omitted */ }
This is supported on crate feature compact_filters only.

A Bitcoin peer

+

Implementations

impl Peer[src]

pub fn connect<A: ToSocketAddrs>(
    address: A,
    mempool: Arc<Mempool>,
    network: Network
) -> Result<Self, CompactFiltersError>
[src]

Connect to a peer over a plaintext TCP connection

+

This function internally spawns a new thread that will monitor incoming messages from the +peer, and optionally reply to some of them transparently, like pings

+

pub fn connect_proxy<T: ToTargetAddr, P: ToSocketAddrs>(
    target: T,
    proxy: P,
    credentials: Option<(&str, &str)>,
    mempool: Arc<Mempool>,
    network: Network
) -> Result<Self, CompactFiltersError>
[src]

Connect to a peer through a SOCKS5 proxy, optionally by using some credentials, specified +as a tuple of (username, password)

+

This function internally spawns a new thread that will monitor incoming messages from the +peer, and optionally reply to some of them transparently, like pings

+

pub fn get_version(&self) -> &VersionMessage[src]

Return the [VersionMessage] sent by the peer

+

pub fn get_network(&self) -> Network[src]

Return the Bitcoin [Network] in use

+

pub fn get_mempool(&self) -> Arc<Mempool>[src]

Return the mempool used by this peer

+

pub fn is_connected(&self) -> bool[src]

Return whether or not the peer is still connected

+

pub fn send(&self, payload: NetworkMessage) -> Result<(), CompactFiltersError>[src]

Send a raw Bitcoin message to the peer

+

pub fn recv(
    &self,
    wait_for: &'static str,
    timeout: Option<Duration>
) -> Result<Option<NetworkMessage>, CompactFiltersError>
[src]

Waits for a specific incoming Bitcoin message, optionally with a timeout

+

Trait Implementations

impl Debug for Peer[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/index.html new file mode 100644 index 0000000000..10b5f8a1cd --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/index.html @@ -0,0 +1,15 @@ +bdk::blockchain::electrum - Rust + +

[][src]Module bdk::blockchain::electrum

This is supported on crate feature electrum only.

Electrum

+

This module defines a Blockchain struct that wraps an [electrum_client::Client] +and implements the logic required to populate the wallet's database by +querying the inner client.

+

Example

+
+let client = electrum_client::Client::new("ssl://electrum.blockstream.info:50002")?;
+let blockchain = ElectrumBlockchain::from(client);
+

Structs

+
ElectrumBlockchain

Wrapper over an Electrum Client that implements the required blockchain traits

+
ElectrumBlockchainConfig

Configuration for an ElectrumBlockchain

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/sidebar-items.js new file mode 100644 index 0000000000..1bd5458912 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"struct":[["ElectrumBlockchain","Wrapper over an Electrum Client that implements the required blockchain traits"],["ElectrumBlockchainConfig","Configuration for an [`ElectrumBlockchain`]"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/struct.ElectrumBlockchain.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/struct.ElectrumBlockchain.html new file mode 100644 index 0000000000..1d0542e6fe --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/struct.ElectrumBlockchain.html @@ -0,0 +1,42 @@ +bdk::blockchain::electrum::ElectrumBlockchain - Rust + +

[][src]Struct bdk::blockchain::electrum::ElectrumBlockchain

pub struct ElectrumBlockchain(_);
This is supported on crate feature electrum only.

Wrapper over an Electrum Client that implements the required blockchain traits

+

Example

+

See the blockchain::electrum module for a usage example.

+

Trait Implementations

impl Blockchain for ElectrumBlockchain[src]

impl ConfigurableBlockchain for ElectrumBlockchain[src]

type Config = ElectrumBlockchainConfig

Type that contains the configuration

+

impl From<Client> for ElectrumBlockchain[src]

impl From<ElectrumBlockchain> for AnyBlockchain[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> BlockchainMarker for T where
    T: Blockchain
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/struct.ElectrumBlockchainConfig.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/struct.ElectrumBlockchainConfig.html new file mode 100644 index 0000000000..f15a951de2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/electrum/struct.ElectrumBlockchainConfig.html @@ -0,0 +1,44 @@ +bdk::blockchain::electrum::ElectrumBlockchainConfig - Rust + +

[][src]Struct bdk::blockchain::electrum::ElectrumBlockchainConfig

pub struct ElectrumBlockchainConfig {
+    pub url: String,
+    pub socks5: Option<String>,
+    pub retry: u8,
+    pub timeout: u8,
+}
This is supported on crate feature electrum only.

Configuration for an ElectrumBlockchain

+

+ Fields

url: String

URL of the Electrum server (such as ElectrumX, Esplora, BWT) may start with ssl:// or tcp:// and include a port

+

eg. ssl://electrum.blockstream.info:60002

+
socks5: Option<String>

URL of the socks5 proxy server or a Tor service

+
retry: u8

Request retry count

+
timeout: u8

Request timeout (seconds)

+

Trait Implementations

impl Debug for ElectrumBlockchainConfig[src]

impl<'de> Deserialize<'de> for ElectrumBlockchainConfig[src]

impl From<ElectrumBlockchainConfig> for AnyBlockchainConfig[src]

impl Serialize for ElectrumBlockchainConfig[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/enum.Capability.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/enum.Capability.html new file mode 100644 index 0000000000..613d781903 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/enum.Capability.html @@ -0,0 +1,51 @@ +bdk::blockchain::Capability - Rust + +

[][src]Enum bdk::blockchain::Capability

pub enum Capability {
+    FullHistory,
+    GetAnyTx,
+    AccurateFees,
+}

Capabilities that can be supported by a Blockchain backend

+

+ Variants

+
FullHistory

Can recover the full history of a wallet and not only the set of currently spendable UTXOs

+
GetAnyTx

Can fetch any historical transaction given its txid

+
AccurateFees

Can compute accurate fees for the transactions found during sync

+

Trait Implementations

impl Clone for Capability[src]

impl Copy for Capability[src]

impl Debug for Capability[src]

impl Eq for Capability[src]

impl Hash for Capability[src]

impl PartialEq<Capability> for Capability[src]

impl StructuralEq for Capability[src]

impl StructuralPartialEq for Capability[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/enum.EsploraError.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/enum.EsploraError.html new file mode 100644 index 0000000000..3a45d9599c --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/enum.EsploraError.html @@ -0,0 +1,58 @@ +bdk::blockchain::esplora::EsploraError - Rust + +

[][src]Enum bdk::blockchain::esplora::EsploraError

pub enum EsploraError {
+    Reqwest(Error),
+    Parsing(ParseIntError),
+    BitcoinEncoding(Error),
+    Hex(Error),
+    TransactionNotFound(Txid),
+    HeaderHeightNotFound(u32),
+    HeaderHashNotFound(BlockHash),
+}
This is supported on crate feature esplora only.

Errors that can happen during a sync with EsploraBlockchain

+

+ Variants

+
Reqwest(Error)

Error with the HTTP call

+
Parsing(ParseIntError)

Invalid number returned

+
BitcoinEncoding(Error)

Invalid Bitcoin data returned

+
Hex(Error)

Invalid Hex data returned

+
TransactionNotFound(Txid)

Transaction not found

+
HeaderHeightNotFound(u32)

Header height not found

+
HeaderHashNotFound(BlockHash)

Header hash not found

+

Trait Implementations

impl Debug for EsploraError[src]

impl Display for EsploraError[src]

impl Error for EsploraError[src]

impl From<Error> for EsploraError[src]

impl From<Error> for EsploraError[src]

impl From<Error> for EsploraError[src]

impl From<EsploraError> for Error[src]

impl From<ParseIntError> for EsploraError[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/index.html new file mode 100644 index 0000000000..d6ed3b9df2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/index.html @@ -0,0 +1,15 @@ +bdk::blockchain::esplora - Rust + +

[][src]Module bdk::blockchain::esplora

This is supported on crate feature esplora only.

Esplora

+

This module defines a Blockchain struct that can query an Esplora backend +populate the wallet's database by

+

Example

+
+let blockchain = EsploraBlockchain::new("https://blockstream.info/testnet/api", None);
+

Structs

+
EsploraBlockchain

Structure that implements the logic to sync with Esplora

+
EsploraBlockchainConfig

Configuration for an EsploraBlockchain

+

Enums

+
EsploraError

Errors that can happen during a sync with EsploraBlockchain

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/sidebar-items.js new file mode 100644 index 0000000000..d4d17db97b --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["EsploraError","Errors that can happen during a sync with [`EsploraBlockchain`]"]],"struct":[["EsploraBlockchain","Structure that implements the logic to sync with Esplora"],["EsploraBlockchainConfig","Configuration for an [`EsploraBlockchain`]"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/struct.EsploraBlockchain.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/struct.EsploraBlockchain.html new file mode 100644 index 0000000000..b645d65ca6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/struct.EsploraBlockchain.html @@ -0,0 +1,43 @@ +bdk::blockchain::esplora::EsploraBlockchain - Rust + +

[][src]Struct bdk::blockchain::esplora::EsploraBlockchain

pub struct EsploraBlockchain(_);
This is supported on crate feature esplora only.

Structure that implements the logic to sync with Esplora

+

Example

+

See the blockchain::esplora module for a usage example.

+

Implementations

impl EsploraBlockchain[src]

pub fn new(base_url: &str, concurrency: Option<u8>) -> Self[src]

Create a new instance of the client from a base URL

+

Trait Implementations

impl Blockchain for EsploraBlockchain[src]

impl ConfigurableBlockchain for EsploraBlockchain[src]

type Config = EsploraBlockchainConfig

Type that contains the configuration

+

impl Debug for EsploraBlockchain[src]

impl From<EsploraBlockchain> for AnyBlockchain[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> BlockchainMarker for T where
    T: Blockchain
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/struct.EsploraBlockchainConfig.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/struct.EsploraBlockchainConfig.html new file mode 100644 index 0000000000..3f00c32c65 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/esplora/struct.EsploraBlockchainConfig.html @@ -0,0 +1,40 @@ +bdk::blockchain::esplora::EsploraBlockchainConfig - Rust + +

[][src]Struct bdk::blockchain::esplora::EsploraBlockchainConfig

pub struct EsploraBlockchainConfig {
+    pub base_url: String,
+    pub concurrency: Option<u8>,
+}
This is supported on crate feature esplora only.

Configuration for an EsploraBlockchain

+

+ Fields

base_url: String

Base URL of the esplora service

+

eg. https://blockstream.info/api/

+
concurrency: Option<u8>

Number of parallel requests sent to the esplora service (default: 4)

+

Trait Implementations

impl Debug for EsploraBlockchainConfig[src]

impl<'de> Deserialize<'de> for EsploraBlockchainConfig[src]

impl From<EsploraBlockchainConfig> for AnyBlockchainConfig[src]

impl Serialize for EsploraBlockchainConfig[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.log_progress.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.log_progress.html new file mode 100644 index 0000000000..8f223b1af9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.log_progress.html @@ -0,0 +1,5 @@ +bdk::blockchain::log_progress - Rust + +

[][src]Function bdk::blockchain::log_progress

pub fn log_progress() -> LogProgress

Create a nwe instance of LogProgress

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.noop_progress.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.noop_progress.html new file mode 100644 index 0000000000..07602022d5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.noop_progress.html @@ -0,0 +1,5 @@ +bdk::blockchain::noop_progress - Rust + +

[][src]Function bdk::blockchain::noop_progress

pub fn noop_progress() -> NoopProgress

Create a new instance of NoopProgress

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.progress.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.progress.html new file mode 100644 index 0000000000..f07065fd91 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/fn.progress.html @@ -0,0 +1,5 @@ +bdk::blockchain::progress - Rust + +

[][src]Function bdk::blockchain::progress

pub fn progress() -> (Sender<ProgressData>, Receiver<ProgressData>)

Shortcut to create a channel (pair of Sender and Receiver) that can transport ProgressData

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/index.html new file mode 100644 index 0000000000..15f7341c86 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/index.html @@ -0,0 +1,33 @@ +bdk::blockchain - Rust + +

[][src]Module bdk::blockchain

Blockchain backends

+

This module provides the implementation of a few commonly-used backends like +Electrum, Esplora and +Compact Filters/Neutrino, along with a generalized trait +Blockchain that can be implemented to build customized backends.

+

Re-exports

+
pub use any::AnyBlockchain;
pub use any::AnyBlockchainConfig;
pub use self::electrum::ElectrumBlockchain;
pub use self::electrum::ElectrumBlockchainConfig;
pub use self::esplora::EsploraBlockchain;
pub use self::compact_filters::CompactFiltersBlockchain;

Modules

+
any

Runtime-checked blockchain types

+
compact_filterscompact_filters

Compact Filters

+
electrumelectrum

Electrum

+
esploraesplora

Esplora

+

Structs

+
LogProgress

Type that implements Progress and logs at level INFO every update received

+
NoopProgress

Type that implements Progress and drops every update received

+
OfflineBlockchain

Type that only implements BlockchainMarker and is always "offline"

+

Enums

+
Capability

Capabilities that can be supported by a Blockchain backend

+

Traits

+
Blockchain

Trait that defines the actions that must be supported by a blockchain backend

+
BlockchainMarker

Marker trait for a blockchain backend

+
ConfigurableBlockchain

Trait for Blockchain types that can be created given a configuration

+
Progress

Trait for types that can receive and process progress updates during Blockchain::sync and +Blockchain::setup

+

Functions

+
log_progress

Create a nwe instance of LogProgress

+
noop_progress

Create a new instance of NoopProgress

+
progress

Shortcut to create a channel (pair of Sender and Receiver) that can transport ProgressData

+

Type Definitions

+
ProgressData

Data sent with a progress update over a channel

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/sidebar-items.js new file mode 100644 index 0000000000..7e42516826 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["Capability","Capabilities that can be supported by a [`Blockchain`] backend"]],"fn":[["log_progress","Create a nwe instance of [`LogProgress`]"],["noop_progress","Create a new instance of [`NoopProgress`]"],["progress","Shortcut to create a [`channel`] (pair of [`Sender`] and [`Receiver`]) that can transport [`ProgressData`]"]],"mod":[["any","Runtime-checked blockchain types"],["compact_filters","Compact Filters"],["electrum","Electrum"],["esplora","Esplora"]],"struct":[["LogProgress","Type that implements [`Progress`] and logs at level `INFO` every update received"],["NoopProgress","Type that implements [`Progress`] and drops every update received"],["OfflineBlockchain","Type that only implements [`BlockchainMarker`] and is always \"offline\""]],"trait":[["Blockchain","Trait that defines the actions that must be supported by a blockchain backend"],["BlockchainMarker","Marker trait for a blockchain backend"],["ConfigurableBlockchain","Trait for [`Blockchain`] types that can be created given a configuration"],["Progress","Trait for types that can receive and process progress updates during [`Blockchain::sync`] and [`Blockchain::setup`]"]],"type":[["ProgressData","Data sent with a progress update over a [`channel`]"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/struct.LogProgress.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/struct.LogProgress.html new file mode 100644 index 0000000000..37fecdf533 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/struct.LogProgress.html @@ -0,0 +1,36 @@ +bdk::blockchain::LogProgress - Rust + +

[][src]Struct bdk::blockchain::LogProgress

pub struct LogProgress;

Type that implements Progress and logs at level INFO every update received

+

Trait Implementations

impl Clone for LogProgress[src]

impl Progress for LogProgress[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/struct.NoopProgress.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/struct.NoopProgress.html new file mode 100644 index 0000000000..32da05a48d --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/struct.NoopProgress.html @@ -0,0 +1,36 @@ +bdk::blockchain::NoopProgress - Rust + +

[][src]Struct bdk::blockchain::NoopProgress

pub struct NoopProgress;

Type that implements Progress and drops every update received

+

Trait Implementations

impl Clone for NoopProgress[src]

impl Progress for NoopProgress[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/struct.OfflineBlockchain.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/struct.OfflineBlockchain.html new file mode 100644 index 0000000000..a828794792 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/struct.OfflineBlockchain.html @@ -0,0 +1,29 @@ +bdk::blockchain::OfflineBlockchain - Rust + +

[][src]Struct bdk::blockchain::OfflineBlockchain

pub struct OfflineBlockchain;

Type that only implements BlockchainMarker and is always "offline"

+

Trait Implementations

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.Blockchain.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.Blockchain.html new file mode 100644 index 0000000000..ccb3c3548b --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.Blockchain.html @@ -0,0 +1,36 @@ +bdk::blockchain::Blockchain - Rust + +

[][src]Trait bdk::blockchain::Blockchain

pub trait Blockchain: BlockchainMarker {
+    pub fn get_capabilities(&self) -> HashSet<Capability>;
+
pub fn setup<D: BatchDatabase, P: 'static + Progress>(
        &self,
        stop_gap: Option<usize>,
        database: &mut D,
        progress_update: P
    ) -> Result<(), Error>; +
pub fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>; +
pub fn broadcast(&self, tx: &Transaction) -> Result<(), Error>; +
pub fn get_height(&self) -> Result<u32, Error>; +
pub fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error>; + + pub fn sync<D: BatchDatabase, P: 'static + Progress>(
        &self,
        stop_gap: Option<usize>,
        database: &mut D,
        progress_update: P
    ) -> Result<(), Error> { ... } +}

Trait that defines the actions that must be supported by a blockchain backend

+

Required methods

pub fn get_capabilities(&self) -> HashSet<Capability>[src]

Return the set of Capability supported by this backend

+

pub fn setup<D: BatchDatabase, P: 'static + Progress>(
    &self,
    stop_gap: Option<usize>,
    database: &mut D,
    progress_update: P
) -> Result<(), Error>
[src]

Setup the backend and populate the internal database for the first time

+

This method is the equivalent of Blockchain::sync, but it's guaranteed to only be +called once, at the first Wallet::sync.

+

The rationale behind the distinction between sync and setup is that some custom backends +might need to perform specific actions only the first time they are synced.

+

For types that do not have that distinction, only this method can be implemented, since +Blockchain::sync defaults to calling this internally if not overridden.

+

pub fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>[src]

Fetch a transaction from the blockchain given its txid

+

pub fn broadcast(&self, tx: &Transaction) -> Result<(), Error>[src]

Broadcast a transaction

+

pub fn get_height(&self) -> Result<u32, Error>[src]

Return the current height

+

pub fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error>[src]

Estimate the fee rate required to confirm a transaction in a given target of blocks

+
Loading content...

Provided methods

pub fn sync<D: BatchDatabase, P: 'static + Progress>(
    &self,
    stop_gap: Option<usize>,
    database: &mut D,
    progress_update: P
) -> Result<(), Error>
[src]

Populate the internal database with transactions and UTXOs

+

If not overridden, it defaults to calling Blockchain::setup internally.

+

This method should implement the logic required to iterate over the list of the wallet's +script_pubkeys using Database::iter_script_pubkeys and look for relevant transactions +in the blockchain to populate the database with BatchOperations::set_tx and +BatchOperations::set_utxo.

+

This method should also take care of removing UTXOs that are seen as spent in the +blockchain, using BatchOperations::del_utxo.

+

The progress_update object can be used to give the caller updates about the progress by using +Progress::update.

+
Loading content...

Implementations on Foreign Types

impl<T: Blockchain> Blockchain for Arc<T>[src]

Loading content...

Implementors

impl Blockchain for AnyBlockchain[src]

impl Blockchain for CompactFiltersBlockchain[src]

This is supported on crate feature compact_filters only.

impl Blockchain for ElectrumBlockchain[src]

This is supported on crate feature electrum only.

impl Blockchain for EsploraBlockchain[src]

This is supported on crate feature esplora only.
Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.BlockchainMarker.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.BlockchainMarker.html new file mode 100644 index 0000000000..6b7b52152c --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.BlockchainMarker.html @@ -0,0 +1,14 @@ +bdk::blockchain::BlockchainMarker - Rust + +

[][src]Trait bdk::blockchain::BlockchainMarker

pub trait BlockchainMarker { }

Marker trait for a blockchain backend

+

This is a marker trait for blockchain types. It is automatically implemented for types that +implement Blockchain, so as a user of the library you won't have to implement this +manually.

+

Users of the library will probably never have to implement this trait manually, but they +could still need to import it to define types and structs with generics; +Implementing only the marker trait is pointless, since OfflineBlockchain +already does that, and whenever Blockchain is implemented, the marker trait is also +automatically implemented by the library.

+

Implementors

impl BlockchainMarker for OfflineBlockchain[src]

impl<T: Blockchain> BlockchainMarker for T[src]

The BlockchainMarker marker trait is automatically implemented for Blockchain types

+
Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.ConfigurableBlockchain.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.ConfigurableBlockchain.html new file mode 100644 index 0000000000..131ce0ecec --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.ConfigurableBlockchain.html @@ -0,0 +1,10 @@ +bdk::blockchain::ConfigurableBlockchain - Rust + +

[][src]Trait bdk::blockchain::ConfigurableBlockchain

pub trait ConfigurableBlockchain: Blockchain + Sized {
+    type Config: Debug;
+    pub fn from_config(config: &Self::Config) -> Result<Self, Error>;
+}

Trait for Blockchain types that can be created given a configuration

+

Associated Types

type Config: Debug[src]

Type that contains the configuration

+
Loading content...

Required methods

pub fn from_config(config: &Self::Config) -> Result<Self, Error>[src]

Create a new instance given a configuration

+
Loading content...

Implementors

impl ConfigurableBlockchain for AnyBlockchain[src]

type Config = AnyBlockchainConfig

impl ConfigurableBlockchain for CompactFiltersBlockchain[src]

This is supported on crate feature compact_filters only.

impl ConfigurableBlockchain for ElectrumBlockchain[src]

This is supported on crate feature electrum only.

type Config = ElectrumBlockchainConfig

impl ConfigurableBlockchain for EsploraBlockchain[src]

This is supported on crate feature esplora only.

type Config = EsploraBlockchainConfig

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.Progress.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.Progress.html new file mode 100644 index 0000000000..f2d54223cd --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/trait.Progress.html @@ -0,0 +1,11 @@ +bdk::blockchain::Progress - Rust + +

[][src]Trait bdk::blockchain::Progress

pub trait Progress: Send {
+    pub fn update(
        &self,
        progress: f32,
        message: Option<String>
    ) -> Result<(), Error>; +}

Trait for types that can receive and process progress updates during Blockchain::sync and +Blockchain::setup

+

Required methods

pub fn update(
    &self,
    progress: f32,
    message: Option<String>
) -> Result<(), Error>
[src]

Send a new progress update

+

The progress value should be in the range 0.0 - 100.0, and the message value is an +optional text message that can be displayed to the user.

+
Loading content...

Implementations on Foreign Types

impl Progress for Sender<ProgressData>[src]

Loading content...

Implementors

impl Progress for LogProgress[src]

impl Progress for NoopProgress[src]

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/type.ProgressData.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/type.ProgressData.html new file mode 100644 index 0000000000..43b5347cb5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/blockchain/type.ProgressData.html @@ -0,0 +1,5 @@ +bdk::blockchain::ProgressData - Rust + +

[][src]Type Definition bdk::blockchain::ProgressData

type ProgressData = (f32, Option<String>);

Data sent with a progress update over a channel

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/enum.AnyBatch.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/enum.AnyBatch.html new file mode 100644 index 0000000000..2780dfa143 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/enum.AnyBatch.html @@ -0,0 +1,50 @@ +bdk::database::any::AnyBatch - Rust + +

[][src]Enum bdk::database::any::AnyBatch

pub enum AnyBatch {
+    Memory(<MemoryDatabase as BatchDatabase>::Batch),
+    Sled(<Tree as BatchDatabase>::Batch),
+}

Type that contains any of the BatchDatabase::Batch types defined by the library

+

+ Variants

+

In-memory ephemeral database

+
Sled(<Tree as BatchDatabase>::Batch)
This is supported on crate feature key-value-db only.

Simple key-value embedded database based on [sled]

+

Trait Implementations

impl BatchOperations for AnyBatch[src]

impl From<<MemoryDatabase as BatchDatabase>::Batch> for AnyBatch[src]

impl From<<Tree as BatchDatabase>::Batch> for AnyBatch[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/enum.AnyDatabase.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/enum.AnyDatabase.html new file mode 100644 index 0000000000..ba702ed155 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/enum.AnyDatabase.html @@ -0,0 +1,70 @@ +bdk::database::any::AnyDatabase - Rust + +

[][src]Enum bdk::database::any::AnyDatabase

pub enum AnyDatabase {
+    Memory(MemoryDatabase),
+    Sled(Tree),
+}

Type that can contain any of the Database types defined by the library

+

It allows switching database type at runtime.

+

See this module's documentation for a usage example.

+

+ Variants

+

In-memory ephemeral database

+
Sled(Tree)
This is supported on crate feature key-value-db only.

Simple key-value embedded database based on [sled]

+

Trait Implementations

impl BatchDatabase for AnyDatabase[src]

type Batch = AnyBatch

Container for the operations

+

impl BatchOperations for AnyDatabase[src]

impl ConfigurableDatabase for AnyDatabase[src]

type Config = AnyDatabaseConfig

Type that contains the configuration

+

impl Database for AnyDatabase[src]

impl Debug for AnyDatabase[src]

impl From<MemoryDatabase> for AnyDatabase[src]

impl From<Tree> for AnyDatabase[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/enum.AnyDatabaseConfig.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/enum.AnyDatabaseConfig.html new file mode 100644 index 0000000000..c880a327c7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/enum.AnyDatabaseConfig.html @@ -0,0 +1,44 @@ +bdk::database::any::AnyDatabaseConfig - Rust + +

[][src]Enum bdk::database::any::AnyDatabaseConfig

pub enum AnyDatabaseConfig {
+    Memory(()),
+    Sled(SledDbConfiguration),
+}

Type that can contain any of the database configurations defined by the library

+

This allows storing a single configuration that can be loaded into an AnyDatabase +instance. Wallets that plan to offer users the ability to switch blockchain backend at runtime +will find this particularly useful.

+

+ Variants

+
Memory(())

Memory database has no config

+
This is supported on crate feature key-value-db only.

Simple key-value embedded database based on [sled]

+

Trait Implementations

impl Debug for AnyDatabaseConfig[src]

impl<'de> Deserialize<'de> for AnyDatabaseConfig[src]

impl From<()> for AnyDatabaseConfig[src]

impl From<SledDbConfiguration> for AnyDatabaseConfig[src]

impl Serialize for AnyDatabaseConfig[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/index.html new file mode 100644 index 0000000000..abe18b01fd --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/index.html @@ -0,0 +1,31 @@ +bdk::database::any - Rust + +

[][src]Module bdk::database::any

Runtime-checked database types

+

This module provides the implementation of AnyDatabase which allows switching the +inner Database type at runtime.

+

Example

+

In this example, wallet_memory and wallet_sled have the same type of Wallet<OfflineBlockchain, AnyDatabase>.

+ +
+let memory = MemoryDatabase::default().into();
+let wallet_memory: OfflineWallet<AnyDatabase> =
+    Wallet::new_offline("...", None, Network::Testnet, memory)?;
+
+let sled = sled::open("my-database")?.open_tree("default_tree")?.into();
+let wallet_sled: OfflineWallet<AnyDatabase> =
+    Wallet::new_offline("...", None, Network::Testnet, sled)?;
+

When paired with the use of ConfigurableDatabase, it allows creating wallets with any +database supported using a single line of code:

+ +
+let config = serde_json::from_str("...")?;
+let database = AnyDatabase::from_config(&config)?;
+let wallet: OfflineWallet<_> = Wallet::new_offline("...", None, Network::Testnet, database)?;
+

Structs

+
SledDbConfiguration

Configuration type for a [sled::Tree] database

+

Enums

+
AnyBatch

Type that contains any of the BatchDatabase::Batch types defined by the library

+
AnyDatabase

Type that can contain any of the Database types defined by the library

+
AnyDatabaseConfig

Type that can contain any of the database configurations defined by the library

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/sidebar-items.js new file mode 100644 index 0000000000..c0fb4445df --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["AnyBatch","Type that contains any of the [`BatchDatabase::Batch`] types defined by the library"],["AnyDatabase","Type that can contain any of the [`Database`] types defined by the library"],["AnyDatabaseConfig","Type that can contain any of the database configurations defined by the library"]],"struct":[["SledDbConfiguration","Configuration type for a [`sled::Tree`] database"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/struct.SledDbConfiguration.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/struct.SledDbConfiguration.html new file mode 100644 index 0000000000..634abca3dd --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/any/struct.SledDbConfiguration.html @@ -0,0 +1,39 @@ +bdk::database::any::SledDbConfiguration - Rust + +

[][src]Struct bdk::database::any::SledDbConfiguration

pub struct SledDbConfiguration {
+    pub path: String,
+    pub tree_name: String,
+}

Configuration type for a [sled::Tree] database

+

+ Fields

path: String

Main directory of the db

+
tree_name: String

Name of the database tree, a separated namespace for the data

+

Trait Implementations

impl Debug for SledDbConfiguration[src]

impl<'de> Deserialize<'de> for SledDbConfiguration[src]

impl From<SledDbConfiguration> for AnyDatabaseConfig[src]

impl Serialize for SledDbConfiguration[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/index.html new file mode 100644 index 0000000000..fb5d1a74e7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/index.html @@ -0,0 +1,22 @@ +bdk::database - Rust + +

[][src]Module bdk::database

Database types

+

This module provides the implementation of some defaults database types, along with traits that +can be implemented externally to let Wallets use customized databases.

+

It's important to note that the databases defined here only contains "blockchain-related" data. +They can be seen more as a cache than a critical piece of storage that contains secrets and +keys.

+

The currently recommended database is [sled], which is a pretty simple key-value embedded +database written in Rust. If the key-value-db feature is enabled (which by default is), +this library automatically implements all the required traits for [sled::Tree].

+

Re-exports

+
pub use any::AnyDatabase;
pub use any::AnyDatabaseConfig;
pub use memory::MemoryDatabase;

Modules

+
any

Runtime-checked database types

+
memory

In-memory ephemeral database

+

Traits

+
BatchDatabase

Trait for a database that supports batch operations

+
BatchOperations

Trait for operations that can be batched

+
ConfigurableDatabase

Trait for Database types that can be created given a configuration

+
Database

Trait for reading data from a database

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/index.html new file mode 100644 index 0000000000..ca05a688e0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/index.html @@ -0,0 +1,9 @@ +bdk::database::memory - Rust + +

[][src]Module bdk::database::memory

In-memory ephemeral database

+

This module defines an in-memory database type called MemoryDatabase that is based on a +BTreeMap.

+

Structs

+
MemoryDatabase

In-memory ephemeral database

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/sidebar-items.js new file mode 100644 index 0000000000..665f6718d0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"struct":[["MemoryDatabase","In-memory ephemeral database"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/struct.MemoryDatabase.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/struct.MemoryDatabase.html new file mode 100644 index 0000000000..a50d11bfaf --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/memory/struct.MemoryDatabase.html @@ -0,0 +1,68 @@ +bdk::database::memory::MemoryDatabase - Rust + +

[][src]Struct bdk::database::memory::MemoryDatabase

pub struct MemoryDatabase { /* fields omitted */ }

In-memory ephemeral database

+

This database can be used as a temporary storage for wallets that are not kept permanently on +a device, or on platforms that don't provide a filesystem, like wasm32.

+

Once it's dropped its content will be lost.

+

If you are looking for a permanent storage solution, you can try with the default key-value +database called [sled]. See the database module documentation for more defailts.

+

Implementations

impl MemoryDatabase[src]

pub fn new() -> Self[src]

Create a new empty database

+

Trait Implementations

impl BatchDatabase for MemoryDatabase[src]

type Batch = Self

Container for the operations

+

impl BatchOperations for MemoryDatabase[src]

impl ConfigurableDatabase for MemoryDatabase[src]

type Config = ()

Type that contains the configuration

+

impl Database for MemoryDatabase[src]

impl Debug for MemoryDatabase[src]

impl Default for MemoryDatabase[src]

impl From<<MemoryDatabase as BatchDatabase>::Batch> for AnyBatch[src]

impl From<MemoryDatabase> for AnyDatabase[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/sidebar-items.js new file mode 100644 index 0000000000..8349d566b5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"mod":[["any","Runtime-checked database types"],["memory","In-memory ephemeral database"]],"trait":[["BatchDatabase","Trait for a database that supports batch operations"],["BatchOperations","Trait for operations that can be batched"],["ConfigurableDatabase","Trait for [`Database`] types that can be created given a configuration"],["Database","Trait for reading data from a database"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.BatchDatabase.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.BatchDatabase.html new file mode 100644 index 0000000000..4edc4e5295 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.BatchDatabase.html @@ -0,0 +1,13 @@ +bdk::database::BatchDatabase - Rust + +

[][src]Trait bdk::database::BatchDatabase

pub trait BatchDatabase: Database {
+    type Batch: BatchOperations;
+    pub fn begin_batch(&self) -> Self::Batch;
+
pub fn commit_batch(&mut self, batch: Self::Batch) -> Result<(), Error>; +}

Trait for a database that supports batch operations

+

This trait defines the methods to start and apply a batch of operations.

+

Associated Types

type Batch: BatchOperations[src]

Container for the operations

+
Loading content...

Required methods

pub fn begin_batch(&self) -> Self::Batch[src]

Create a new batch container

+

pub fn commit_batch(&mut self, batch: Self::Batch) -> Result<(), Error>[src]

Consume and apply a batch of operations

+
Loading content...

Implementations on Foreign Types

impl BatchDatabase for Tree[src]

type Batch = Batch

Loading content...

Implementors

impl BatchDatabase for AnyDatabase[src]

type Batch = AnyBatch

impl BatchDatabase for MemoryDatabase[src]

type Batch = Self

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.BatchOperations.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.BatchOperations.html new file mode 100644 index 0000000000..43cec5ac1a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.BatchOperations.html @@ -0,0 +1,31 @@ +bdk::database::BatchOperations - Rust + +

[][src]Trait bdk::database::BatchOperations

pub trait BatchOperations {
+    pub fn set_script_pubkey(
        &mut self,
        script: &Script,
        keychain: KeychainKind,
        child: u32
    ) -> Result<(), Error>; +
pub fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error>; +
pub fn set_raw_tx(&mut self, transaction: &Transaction) -> Result<(), Error>; +
pub fn set_tx(
        &mut self,
        transaction: &TransactionDetails
    ) -> Result<(), Error>; +
pub fn set_last_index(
        &mut self,
        keychain: KeychainKind,
        value: u32
    ) -> Result<(), Error>; +
pub fn del_script_pubkey_from_path(
        &mut self,
        keychain: KeychainKind,
        child: u32
    ) -> Result<Option<Script>, Error>; +
pub fn del_path_from_script_pubkey(
        &mut self,
        script: &Script
    ) -> Result<Option<(KeychainKind, u32)>, Error>; +
pub fn del_utxo(
        &mut self,
        outpoint: &OutPoint
    ) -> Result<Option<UTXO>, Error>; +
pub fn del_raw_tx(
        &mut self,
        txid: &Txid
    ) -> Result<Option<Transaction>, Error>; +
pub fn del_tx(
        &mut self,
        txid: &Txid,
        include_raw: bool
    ) -> Result<Option<TransactionDetails>, Error>; +
pub fn del_last_index(
        &mut self,
        keychain: KeychainKind
    ) -> Result<Option<u32>, Error>; +}

Trait for operations that can be batched

+

This trait defines the list of operations that must be implemented on the Database type and +the BatchDatabase::Batch type.

+

Required methods

pub fn set_script_pubkey(
    &mut self,
    script: &Script,
    keychain: KeychainKind,
    child: u32
) -> Result<(), Error>
[src]

Store a script_pubkey along with its keychain and child number.

+

pub fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error>[src]

Store a UTXO

+

pub fn set_raw_tx(&mut self, transaction: &Transaction) -> Result<(), Error>[src]

Store a raw transaction

+

pub fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error>[src]

Store the metadata of a transaction

+

pub fn set_last_index(
    &mut self,
    keychain: KeychainKind,
    value: u32
) -> Result<(), Error>
[src]

Store the last derivation index for a given keychain.

+

pub fn del_script_pubkey_from_path(
    &mut self,
    keychain: KeychainKind,
    child: u32
) -> Result<Option<Script>, Error>
[src]

Delete a script_pubkey given the keychain and its child number.

+

pub fn del_path_from_script_pubkey(
    &mut self,
    script: &Script
) -> Result<Option<(KeychainKind, u32)>, Error>
[src]

Delete the data related to a specific script_pubkey, meaning the keychain and the child +number.

+

pub fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error>[src]

Delete a UTXO given its [OutPoint]

+

pub fn del_raw_tx(&mut self, txid: &Txid) -> Result<Option<Transaction>, Error>[src]

Delete a raw transaction given its [Txid]

+

pub fn del_tx(
    &mut self,
    txid: &Txid,
    include_raw: bool
) -> Result<Option<TransactionDetails>, Error>
[src]

Delete the metadata of a transaction and optionally the raw transaction itself

+

pub fn del_last_index(
    &mut self,
    keychain: KeychainKind
) -> Result<Option<u32>, Error>
[src]

Delete the last derivation index for a keychain.

+
Loading content...

Implementations on Foreign Types

impl BatchOperations for Tree[src]

impl BatchOperations for Batch[src]

Loading content...

Implementors

impl BatchOperations for AnyBatch[src]

impl BatchOperations for AnyDatabase[src]

impl BatchOperations for MemoryDatabase[src]

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.ConfigurableDatabase.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.ConfigurableDatabase.html new file mode 100644 index 0000000000..463d548462 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.ConfigurableDatabase.html @@ -0,0 +1,10 @@ +bdk::database::ConfigurableDatabase - Rust + +

[][src]Trait bdk::database::ConfigurableDatabase

pub trait ConfigurableDatabase: Database + Sized {
+    type Config: Debug;
+    pub fn from_config(config: &Self::Config) -> Result<Self, Error>;
+}

Trait for Database types that can be created given a configuration

+

Associated Types

type Config: Debug[src]

Type that contains the configuration

+
Loading content...

Required methods

pub fn from_config(config: &Self::Config) -> Result<Self, Error>[src]

Create a new instance given a configuration

+
Loading content...

Implementations on Foreign Types

impl ConfigurableDatabase for Tree[src]

type Config = SledDbConfiguration

Loading content...

Implementors

impl ConfigurableDatabase for AnyDatabase[src]

type Config = AnyDatabaseConfig

impl ConfigurableDatabase for MemoryDatabase[src]

type Config = ()

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.Database.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.Database.html new file mode 100644 index 0000000000..c776d70675 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/database/trait.Database.html @@ -0,0 +1,35 @@ +bdk::database::Database - Rust + +

[][src]Trait bdk::database::Database

pub trait Database: BatchOperations {
+    pub fn check_descriptor_checksum<B: AsRef<[u8]>>(
        &mut self,
        keychain: KeychainKind,
        bytes: B
    ) -> Result<(), Error>; +
pub fn iter_script_pubkeys(
        &self,
        keychain: Option<KeychainKind>
    ) -> Result<Vec<Script>, Error>; +
pub fn iter_utxos(&self) -> Result<Vec<UTXO>, Error>; +
pub fn iter_raw_txs(&self) -> Result<Vec<Transaction>, Error>; +
pub fn iter_txs(
        &self,
        include_raw: bool
    ) -> Result<Vec<TransactionDetails>, Error>; +
pub fn get_script_pubkey_from_path(
        &self,
        keychain: KeychainKind,
        child: u32
    ) -> Result<Option<Script>, Error>; +
pub fn get_path_from_script_pubkey(
        &self,
        script: &Script
    ) -> Result<Option<(KeychainKind, u32)>, Error>; +
pub fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error>; +
pub fn get_raw_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>; +
pub fn get_tx(
        &self,
        txid: &Txid,
        include_raw: bool
    ) -> Result<Option<TransactionDetails>, Error>; +
pub fn get_last_index(
        &self,
        keychain: KeychainKind
    ) -> Result<Option<u32>, Error>; +
pub fn increment_last_index(
        &mut self,
        keychain: KeychainKind
    ) -> Result<u32, Error>; +}

Trait for reading data from a database

+

This traits defines the operations that can be used to read data out of a database

+

Required methods

pub fn check_descriptor_checksum<B: AsRef<[u8]>>(
    &mut self,
    keychain: KeychainKind,
    bytes: B
) -> Result<(), Error>
[src]

Read and checks the descriptor checksum for a given keychain.

+

Should return Error::ChecksumMismatch if the +checksum doesn't match. If there's no checksum in the database, simply store it for the +next time.

+

pub fn iter_script_pubkeys(
    &self,
    keychain: Option<KeychainKind>
) -> Result<Vec<Script>, Error>
[src]

Return the list of script_pubkeys

+

pub fn iter_utxos(&self) -> Result<Vec<UTXO>, Error>[src]

Return the list of UTXOs

+

pub fn iter_raw_txs(&self) -> Result<Vec<Transaction>, Error>[src]

Return the list of raw transactions

+

pub fn iter_txs(
    &self,
    include_raw: bool
) -> Result<Vec<TransactionDetails>, Error>
[src]

Return the list of transactions metadata

+

pub fn get_script_pubkey_from_path(
    &self,
    keychain: KeychainKind,
    child: u32
) -> Result<Option<Script>, Error>
[src]

Fetch a script_pubkey given the child number of a keychain.

+

pub fn get_path_from_script_pubkey(
    &self,
    script: &Script
) -> Result<Option<(KeychainKind, u32)>, Error>
[src]

Fetch the keychain and child number of a given script_pubkey

+

pub fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error>[src]

Fetch a UTXO given its [OutPoint]

+

pub fn get_raw_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>[src]

Fetch a raw transaction given its [Txid]

+

pub fn get_tx(
    &self,
    txid: &Txid,
    include_raw: bool
) -> Result<Option<TransactionDetails>, Error>
[src]

Fetch the transaction metadata and optionally also the raw transaction

+

pub fn get_last_index(
    &self,
    keychain: KeychainKind
) -> Result<Option<u32>, Error>
[src]

Return the last defivation index for a keychain.

+

pub fn increment_last_index(
    &mut self,
    keychain: KeychainKind
) -> Result<u32, Error>
[src]

Increment the last derivation index for a keychain and return it

+

It should insert and return 0 if not present in the database

+
Loading content...

Implementations on Foreign Types

impl Database for Tree[src]

Loading content...

Implementors

impl Database for AnyDatabase[src]

impl Database for MemoryDatabase[src]

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/checksum/fn.get_checksum.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/checksum/fn.get_checksum.html new file mode 100644 index 0000000000..6b9e25e90a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/checksum/fn.get_checksum.html @@ -0,0 +1,5 @@ +bdk::descriptor::checksum::get_checksum - Rust + +

[][src]Function bdk::descriptor::checksum::get_checksum

pub fn get_checksum(desc: &str) -> Result<String, Error>

Compute the checksum of a descriptor

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/checksum/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/checksum/index.html new file mode 100644 index 0000000000..0c7f9bb96d --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/checksum/index.html @@ -0,0 +1,9 @@ +bdk::descriptor::checksum - Rust + +

[][src]Module bdk::descriptor::checksum

Descriptor checksum

+

This module contains a re-implementation of the function used by Bitcoin Core to calculate the +checksum of a descriptor

+

Functions

+
get_checksum

Compute the checksum of a descriptor

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/checksum/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/checksum/sidebar-items.js new file mode 100644 index 0000000000..e1add094a5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/checksum/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["get_checksum","Compute the checksum of a descriptor"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Descriptor.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Descriptor.html new file mode 100644 index 0000000000..42300b0891 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Descriptor.html @@ -0,0 +1,156 @@ +bdk::descriptor::Descriptor - Rust + +

[]Enum bdk::descriptor::Descriptor

pub enum Descriptor<Pk> where
    Pk: MiniscriptKey
{ + Bare(Miniscript<Pk, Bare>), + Pk(Pk), + Pkh(Pk), + Wpkh(Pk), + ShWpkh(Pk), + Sh(Miniscript<Pk, Legacy>), + Wsh(Miniscript<Pk, Segwitv0>), + ShWsh(Miniscript<Pk, Segwitv0>), + ShSortedMulti(SortedMultiVec<Pk, Legacy>), + WshSortedMulti(SortedMultiVec<Pk, Segwitv0>), + ShWshSortedMulti(SortedMultiVec<Pk, Segwitv0>), +}

Script descriptor

+

+ Variants

+
Bare(Miniscript<Pk, Bare>)

A raw scriptpubkey (including pay-to-pubkey) under Legacy context

+
Pk(Pk)

Pay-to-Pubkey

+
Pkh(Pk)

Pay-to-PubKey-Hash

+
Wpkh(Pk)

Pay-to-Witness-PubKey-Hash

+
ShWpkh(Pk)

Pay-to-Witness-PubKey-Hash inside P2SH

+

Pay-to-ScriptHash with Legacy context

+

Pay-to-Witness-ScriptHash with Segwitv0 context

+
ShWsh(Miniscript<Pk, Segwitv0>)

P2SH-P2WSH with Segwitv0 context

+
ShSortedMulti(SortedMultiVec<Pk, Legacy>)

Sortedmulti under P2SH

+
WshSortedMulti(SortedMultiVec<Pk, Segwitv0>)

Sortedmulti under P2WSH

+
ShWshSortedMulti(SortedMultiVec<Pk, Segwitv0>)

Sortedmulti under P2SH-P2WSH

+

Implementations

impl<Pk> Descriptor<Pk> where
    Pk: MiniscriptKey

pub fn translate_pk<Fpk, Fpkh, Q, E>(
    &self,
    translatefpk: Fpk,
    translatefpkh: Fpkh
) -> Result<Descriptor<Q>, E> where
    Fpk: FnMut(&Pk) -> Result<Q, E>,
    Fpkh: FnMut(&<Pk as MiniscriptKey>::Hash) -> Result<<Q as MiniscriptKey>::Hash, E>,
    Q: MiniscriptKey

Convert a descriptor using abstract keys to one using specific keys +This will panic if translatefpk returns an uncompressed key when +converting to a Segwit descriptor. To prevent this panic, ensure +translatefpk returns an error in this case instead.

+

pub fn sanity_check(&self) -> Result<(), Error>

Whether the descriptor is safe +Checks whether all the spend paths in the descriptor are possible +on the bitcoin network under the current standardness and consensus rules +Also checks whether the descriptor requires signauture on all spend paths +And whether the script is malleable. +In general, all the guarantees of miniscript hold only for safe scripts. +All the analysis guarantees of miniscript only hold safe scripts. +The signer may not be able to find satisfactions even if one exists

+

impl<Pk> Descriptor<Pk> where
    Pk: MiniscriptKey

pub fn address<ToPkCtx>(
    &self,
    network: Network,
    to_pk_ctx: ToPkCtx
) -> Option<Address> where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Computes the Bitcoin address of the descriptor, if one exists +to_pk_ctx denotes the ToPkCtx required for deriving bitcoin::PublicKey +from MiniscriptKey using ToPublicKey. +If MiniscriptKey is already is [bitcoin::PublicKey], then the context +would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey]

+

In general, this is defined by generic for the trait [trait.ToPublicKey]

+

pub fn script_pubkey<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> Script where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Computes the scriptpubkey of the descriptor +to_pk_ctx denotes the ToPkCtx required for deriving bitcoin::PublicKey +from MiniscriptKey using ToPublicKey. +If MiniscriptKey is already is [bitcoin::PublicKey], then the context +would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey]

+

In general, this is defined by generic for the trait ToPublicKey

+

pub fn unsigned_script_sig<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> Script where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Computes the scriptSig that will be in place for an unsigned +input spending an output with this descriptor. For pre-segwit +descriptors, which use the scriptSig for signatures, this +returns the empty script.

+

This is used in Segwit transactions to produce an unsigned +transaction whose txid will not change during signing (since +only the witness data will change). +to_pk_ctx denotes the ToPkCtx required for deriving bitcoin::PublicKey +from MiniscriptKey using ToPublicKey. +If MiniscriptKey is already is [bitcoin::PublicKey], then the context +would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey]

+

In general, this is defined by generic for the trait ToPublicKey

+

pub fn witness_script<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> Script where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Computes the "witness script" of the descriptor, i.e. the underlying +script before any hashing is done. For Bare, Pkh and Wpkh this +is the scriptPubkey; for ShWpkh and Sh this is the redeemScript; +for the others it is the witness script. +to_pk_ctx denotes the ToPkCtx required for deriving bitcoin::PublicKey +from MiniscriptKey using ToPublicKey. +If MiniscriptKey is already is [bitcoin::PublicKey], then the context +would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey]

+

In general, this is defined by generic for the trait ToPublicKey

+

pub fn get_satisfication<ToPkCtx, S>(
    &self,
    satisfier: S,
    to_pk_ctx: ToPkCtx
) -> Result<(Vec<Vec<u8, Global>, Global>, Script), Error> where
    Pk: ToPublicKey<ToPkCtx>,
    S: Satisfier<ToPkCtx, Pk>,
    ToPkCtx: Copy

Returns satisfying witness and scriptSig to spend an +output controlled by the given descriptor if it possible to +construct one using the satisfier S. +to_pk_ctx denotes the ToPkCtx required for deriving bitcoin::PublicKey +from MiniscriptKey using ToPublicKey. +If MiniscriptKey is already is [bitcoin::PublicKey], then the context +would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey]

+

In general, this is defined by generic for the trait ToPublicKey

+

pub fn satisfy<ToPkCtx, S>(
    &self,
    txin: &mut TxIn,
    satisfier: S,
    to_pk_ctx: ToPkCtx
) -> Result<(), Error> where
    Pk: ToPublicKey<ToPkCtx>,
    S: Satisfier<ToPkCtx, Pk>,
    ToPkCtx: Copy

Attempts to produce a satisfying witness and scriptSig to spend an +output controlled by the given descriptor; add the data to a given +TxIn output.

+

pub fn max_satisfaction_weight<ToPkCtx>(
    &self,
    to_pk_ctx: ToPkCtx
) -> Option<usize> where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Computes an upper bound on the weight of a satisfying witness to the +transaction. Assumes all signatures are 73 bytes, including push opcode +and sighash suffix. Includes the weight of the VarInts encoding the +scriptSig and witness stack length.

+

pub fn script_code<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> Script where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Get the scriptCode of a transaction output.

+

The scriptCode is the Script of the previous transaction output being serialized in the +sighash when evaluating a CHECKSIG & co. OP code. +to_pk_ctx denotes the ToPkCtx required for deriving bitcoin::PublicKey +from MiniscriptKey using ToPublicKey. +If MiniscriptKey is already is [bitcoin::PublicKey], then the context +would be [NullCtx] and [descriptor.DescriptorPublicKeyCtx] if MiniscriptKey is [descriptor.DescriptorPublicKey]

+

In general, this is defined by generic for the trait ToPublicKey

+

impl Descriptor<DescriptorPublicKey>

pub fn derive(
    &self,
    child_number: ChildNumber
) -> Descriptor<DescriptorPublicKey>

Derives all wildcard keys in the descriptor using the supplied child_number

+

pub fn parse_descriptor(
    s: &str
) -> Result<(Descriptor<DescriptorPublicKey>, HashMap<DescriptorPublicKey, DescriptorSecretKey, RandomState>), Error>

Parse a descriptor that may contain secret keys

+

Internally turns every secret key found into the corresponding public key and then returns a +a descriptor that only contains public keys and a map to lookup the secret key given a public key.

+

pub fn to_string_with_secret(
    &self,
    key_map: &HashMap<DescriptorPublicKey, DescriptorSecretKey, RandomState>
) -> String

Serialize a descriptor to string with its secret keys

+

Trait Implementations

impl<Pk> Clone for Descriptor<Pk> where
    Pk: MiniscriptKey + Clone

impl<Pk> Debug for Descriptor<Pk> where
    Pk: MiniscriptKey

impl<Pk> Display for Descriptor<Pk> where
    Pk: MiniscriptKey

impl<Pk> Eq for Descriptor<Pk> where
    Pk: MiniscriptKey + Eq

impl ExtractPolicy for Descriptor<DescriptorPublicKey>[src]

impl<Pk> FromStr for Descriptor<Pk> where
    Pk: MiniscriptKey,
    <Pk as FromStr>::Err: ToString,
    <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString

type Err = Error

The associated error which can be returned from parsing.

+

impl<Pk> FromTree for Descriptor<Pk> where
    Pk: MiniscriptKey,
    <Pk as FromStr>::Err: ToString,
    <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString

pub fn from_tree(top: &Tree<'_>) -> Result<Descriptor<Pk>, Error>

Parse an expression tree into a descriptor

+

impl<Pk> Liftable<Pk> for Descriptor<Pk> where
    Pk: MiniscriptKey

impl<Pk> Ord for Descriptor<Pk> where
    Pk: MiniscriptKey + Ord

impl<Pk> PartialEq<Descriptor<Pk>> for Descriptor<Pk> where
    Pk: MiniscriptKey + PartialEq<Pk>, 

impl<Pk> PartialOrd<Descriptor<Pk>> for Descriptor<Pk> where
    Pk: MiniscriptKey + PartialOrd<Pk>, 

impl<Pk> StructuralEq for Descriptor<Pk> where
    Pk: MiniscriptKey

impl<Pk> StructuralPartialEq for Descriptor<Pk> where
    Pk: MiniscriptKey

Auto Trait Implementations

impl<Pk> RefUnwindSafe for Descriptor<Pk> where
    Pk: RefUnwindSafe,
    <Pk as MiniscriptKey>::Hash: RefUnwindSafe
[src]

impl<Pk> Send for Descriptor<Pk> where
    Pk: Send + Sync,
    <Pk as MiniscriptKey>::Hash: Send + Sync
[src]

impl<Pk> Sync for Descriptor<Pk> where
    Pk: Send + Sync,
    <Pk as MiniscriptKey>::Hash: Send + Sync
[src]

impl<Pk> Unpin for Descriptor<Pk> where
    Pk: Unpin,
    <Pk as MiniscriptKey>::Hash: Unpin
[src]

impl<Pk> UnwindSafe for Descriptor<Pk> where
    Pk: RefUnwindSafe + UnwindSafe,
    <Pk as MiniscriptKey>::Hash: RefUnwindSafe + UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Legacy.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Legacy.html new file mode 100644 index 0000000000..ffb2ec62ab --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Legacy.html @@ -0,0 +1,103 @@ +bdk::descriptor::Legacy - Rust + +

[]Enum bdk::descriptor::Legacy

pub enum Legacy {}

Legacy ScriptContext +To be used as P2SH scripts +For creation of Bare scriptpubkeys, construct the Miniscript +under Bare ScriptContext

+

Trait Implementations

impl Clone for Legacy

impl Debug for Legacy

impl Eq for Legacy

impl Ord for Legacy

impl PartialEq<Legacy> for Legacy

impl PartialOrd<Legacy> for Legacy

impl ScriptContext for Legacy

impl StructuralEq for Legacy

impl StructuralPartialEq for Legacy

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<Ctx> ExtScriptContext for Ctx where
    Ctx: 'static + ScriptContext
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Segwitv0.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Segwitv0.html new file mode 100644 index 0000000000..8d6af85ba0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Segwitv0.html @@ -0,0 +1,100 @@ +bdk::descriptor::Segwitv0 - Rust + +

[]Enum bdk::descriptor::Segwitv0

pub enum Segwitv0 {}

Segwitv0 ScriptContext

+

Trait Implementations

impl Clone for Segwitv0

impl Debug for Segwitv0

impl Eq for Segwitv0

impl Ord for Segwitv0

impl PartialEq<Segwitv0> for Segwitv0

impl PartialOrd<Segwitv0> for Segwitv0

impl ScriptContext for Segwitv0

impl StructuralEq for Segwitv0

impl StructuralPartialEq for Segwitv0

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<Ctx> ExtScriptContext for Ctx where
    Ctx: 'static + ScriptContext
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Terminal.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Terminal.html new file mode 100644 index 0000000000..1cf838dcc4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/enum.Terminal.html @@ -0,0 +1,124 @@ +bdk::descriptor::Terminal - Rust + +

[]Enum bdk::descriptor::Terminal

pub enum Terminal<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey
{ + True, + False, + PkK(Pk), + PkH(<Pk as MiniscriptKey>::Hash), + After(u32), + Older(u32), + Sha256(Hash), + Hash256(Hash), + Ripemd160(Hash), + Hash160(Hash), + Alt(Arc<Miniscript<Pk, Ctx>>), + Swap(Arc<Miniscript<Pk, Ctx>>), + Check(Arc<Miniscript<Pk, Ctx>>), + DupIf(Arc<Miniscript<Pk, Ctx>>), + Verify(Arc<Miniscript<Pk, Ctx>>), + NonZero(Arc<Miniscript<Pk, Ctx>>), + ZeroNotEqual(Arc<Miniscript<Pk, Ctx>>), + AndV(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>), + AndB(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>), + AndOr(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>), + OrB(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>), + OrD(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>), + OrC(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>), + OrI(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>), + Thresh(usizeVec<Arc<Miniscript<Pk, Ctx>>, Global>), + Multi(usizeVec<Pk, Global>), +}

All AST elements

+

+ Variants

+
True

1

+
False

0

+
PkK(Pk)

<key>

+
PkH(<Pk as MiniscriptKey>::Hash)

DUP HASH160 <keyhash> EQUALVERIFY

+
After(u32)

n CHECKLOCKTIMEVERIFY

+
Older(u32)

n CHECKSEQUENCEVERIFY

+
Sha256(Hash)

SIZE 32 EQUALVERIFY SHA256 <hash> EQUAL

+
Hash256(Hash)

SIZE 32 EQUALVERIFY HASH256 <hash> EQUAL

+
Ripemd160(Hash)

SIZE 32 EQUALVERIFY RIPEMD160 <hash> EQUAL

+
Hash160(Hash)

SIZE 32 EQUALVERIFY HASH160 <hash> EQUAL

+
Alt(Arc<Miniscript<Pk, Ctx>>)

TOALTSTACK [E] FROMALTSTACK

+
Swap(Arc<Miniscript<Pk, Ctx>>)

SWAP [E1]

+
Check(Arc<Miniscript<Pk, Ctx>>)

[Kt]/[Ke] CHECKSIG

+
DupIf(Arc<Miniscript<Pk, Ctx>>)

DUP IF [V] ENDIF

+
Verify(Arc<Miniscript<Pk, Ctx>>)

[T] VERIFY

+
NonZero(Arc<Miniscript<Pk, Ctx>>)

SIZE 0NOTEQUAL IF Fn ENDIF

+
ZeroNotEqual(Arc<Miniscript<Pk, Ctx>>)

[X] 0NOTEQUAL

+
AndV(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>)

[V] [T]/[V]/[F]/[Kt]

+
AndB(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>)

[E] [W] BOOLAND

+
AndOr(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>)

[various] NOTIF [various] ELSE [various] ENDIF

+
OrB(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>)

[E] [W] BOOLOR

+
OrD(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>)

[E] IFDUP NOTIF [T]/[E] ENDIF

+
OrC(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>)

[E] NOTIF [V] ENDIF

+
OrI(Arc<Miniscript<Pk, Ctx>>, Arc<Miniscript<Pk, Ctx>>)

IF [various] ELSE [various] ENDIF

+
Thresh(usizeVec<Arc<Miniscript<Pk, Ctx>>, Global>)

[E] ([W] ADD)* k EQUAL

+
Multi(usizeVec<Pk, Global>)

k ()* n CHECKMULTISIG

+

Implementations

impl<Pk, Ctx> Terminal<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn translate_pk<FPk, FPkh, Q, Error>(
    &self,
    translatefpk: &mut FPk,
    translatefpkh: &mut FPkh
) -> Result<Terminal<Q, Ctx>, Error> where
    FPk: FnMut(&Pk) -> Result<Q, Error>,
    FPkh: FnMut(&<Pk as MiniscriptKey>::Hash) -> Result<<Q as MiniscriptKey>::Hash, Error>,
    Q: MiniscriptKey

Convert an AST element with one public key type to one of another +public key type .This will panic while converting to +Segwit Miniscript using uncompressed public keys

+

impl<Pk, Ctx> Terminal<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn encode<ToPkCtx>(&self, builder: Builder, to_pk_ctx: ToPkCtx) -> Builder where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Encode the element as a fragment of Bitcoin Script. The inverse +function, from Script to an AST element, is implemented in the +parse module.

+

pub fn script_size<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> usize where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Size, in bytes of the script-pubkey. If this Miniscript is used outside +of segwit (e.g. in a bare or P2SH descriptor), this quantity should be +multiplied by 4 to compute the weight.

+

In general, it is not recommended to use this function directly, but +to instead call the corresponding function on a Descriptor, which +will handle the segwit/non-segwit technicalities for you.

+

Trait Implementations

impl<Pk, Ctx> Clone for Terminal<Pk, Ctx> where
    Ctx: ScriptContext + Clone,
    Pk: MiniscriptKey + Clone,
    <Pk as MiniscriptKey>::Hash: Clone

impl<Pk, Ctx> Debug for Terminal<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> Display for Terminal<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> Eq for Terminal<Pk, Ctx> where
    Ctx: ScriptContext + Eq,
    Pk: MiniscriptKey + Eq,
    <Pk as MiniscriptKey>::Hash: Eq

impl<Pk, Ctx> FromTree for Terminal<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey,
    <Pk as FromStr>::Err: ToString,
    <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString

impl<Pk, Ctx> Hash for Terminal<Pk, Ctx> where
    Ctx: ScriptContext + Hash,
    Pk: MiniscriptKey + Hash,
    <Pk as MiniscriptKey>::Hash: Hash

impl<Pk, Ctx> Liftable<Pk> for Terminal<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> Ord for Terminal<Pk, Ctx> where
    Ctx: ScriptContext + Ord,
    Pk: MiniscriptKey + Ord,
    <Pk as MiniscriptKey>::Hash: Ord

impl<Pk, Ctx> PartialEq<Terminal<Pk, Ctx>> for Terminal<Pk, Ctx> where
    Ctx: ScriptContext + PartialEq<Ctx>,
    Pk: MiniscriptKey + PartialEq<Pk>,
    <Pk as MiniscriptKey>::Hash: PartialEq<<Pk as MiniscriptKey>::Hash>, 

impl<Pk, Ctx> PartialOrd<Terminal<Pk, Ctx>> for Terminal<Pk, Ctx> where
    Ctx: ScriptContext + PartialOrd<Ctx>,
    Pk: MiniscriptKey + PartialOrd<Pk>,
    <Pk as MiniscriptKey>::Hash: PartialOrd<<Pk as MiniscriptKey>::Hash>, 

impl<Pk, Ctx> StructuralEq for Terminal<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> StructuralPartialEq for Terminal<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Auto Trait Implementations

impl<Pk, Ctx> RefUnwindSafe for Terminal<Pk, Ctx> where
    Ctx: RefUnwindSafe,
    Pk: RefUnwindSafe,
    <Pk as MiniscriptKey>::Hash: RefUnwindSafe
[src]

impl<Pk, Ctx> Send for Terminal<Pk, Ctx> where
    Ctx: Send + Sync,
    Pk: Send + Sync,
    <Pk as MiniscriptKey>::Hash: Send + Sync
[src]

impl<Pk, Ctx> Sync for Terminal<Pk, Ctx> where
    Ctx: Send + Sync,
    Pk: Send + Sync,
    <Pk as MiniscriptKey>::Hash: Send + Sync
[src]

impl<Pk, Ctx> Unpin for Terminal<Pk, Ctx> where
    Pk: Unpin,
    <Pk as MiniscriptKey>::Hash: Unpin
[src]

impl<Pk, Ctx> UnwindSafe for Terminal<Pk, Ctx> where
    Ctx: RefUnwindSafe,
    Pk: RefUnwindSafe + UnwindSafe,
    <Pk as MiniscriptKey>::Hash: RefUnwindSafe + UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/error/enum.Error.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/error/enum.Error.html new file mode 100644 index 0000000000..f85b978722 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/error/enum.Error.html @@ -0,0 +1,65 @@ +bdk::descriptor::error::Error - Rust + +

[][src]Enum bdk::descriptor::error::Error

pub enum Error {
+    InvalidHDKeyPath,
+    Key(KeyError),
+    Policy(PolicyError),
+    InvalidDescriptorCharacter(char),
+    BIP32(Error),
+    Base58(Error),
+    PK(Error),
+    Miniscript(Error),
+    Hex(Error),
+}

Errors related to the parsing and usage of descriptors

+

+ Variants

+
InvalidHDKeyPath

Invalid HD Key path, such as having a wildcard but a length != 1

+

Error thrown while working with keys

+
Policy(PolicyError)

Error while extracting and manipulating policies

+
InvalidDescriptorCharacter(char)

Invalid character found in the descriptor checksum

+
BIP32(Error)

BIP32 error

+
Base58(Error)

Error during base58 decoding

+
PK(Error)

Key-related error

+
Miniscript(Error)

Miniscript error

+
Hex(Error)

Hex decoding error

+

Trait Implementations

impl Debug for Error[src]

impl Display for Error[src]

impl Error for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<KeyError> for Error[src]

impl From<PolicyError> for Error[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/error/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/error/index.html new file mode 100644 index 0000000000..7f40f8e520 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/error/index.html @@ -0,0 +1,7 @@ +bdk::descriptor::error - Rust + +

[][src]Module bdk::descriptor::error

Descriptor errors

+

Enums

+
Error

Errors related to the parsing and usage of descriptors

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/error/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/error/sidebar-items.js new file mode 100644 index 0000000000..1ad99d4faf --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/error/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["Error","Errors related to the parsing and usage of descriptors"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/index.html new file mode 100644 index 0000000000..ccb74e27c0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/index.html @@ -0,0 +1,39 @@ +bdk::descriptor - Rust + +

[][src]Module bdk::descriptor

Descriptors

+

This module contains generic utilities to work with descriptors, plus some re-exported types +from [miniscript].

+

Re-exports

+
pub use self::checksum::get_checksum;
pub use self::policy::Policy;

Modules

+
checksum

Descriptor checksum

+
error

Descriptor errors

+
policy

Descriptor policy

+
template

Descriptor templates

+

Structs

+
Miniscript

Top-level script AST type

+

Enums

+
Descriptor

Script descriptor

+
Legacy

Legacy ScriptContext +To be used as P2SH scripts +For creation of Bare scriptpubkeys, construct the Miniscript +under Bare ScriptContext

+
Segwitv0

Segwitv0 ScriptContext

+
Terminal

All AST elements

+

Traits

+
ExtractPolicy

Trait implemented on Descriptors to add a method to extract the spending policy

+
MiniscriptKey

Public key trait which can be converted to Hash type

+
ScriptContext

The ScriptContext for Miniscript. Additional type information associated with +miniscript that is used for carrying out checks that dependent on the +context under which the script is used. +For example, disallowing uncompressed keys in Segwit context

+
ToPublicKey

Trait describing public key types which can be converted to bitcoin pubkeys +The trait relies on Copy trait because in all practical usecases ToPkCtx +should contain references to objects which should be cheap to Copy.

+
ToWalletDescriptor

Trait for types which can be converted into an ExtendedDescriptor and a KeyMap usable by a wallet in a specific [Network]

+

Type Definitions

+
ExtendedDescriptor

Alias for a Descriptor that can contain extended keys using DescriptorPublicKey

+
HDKeyPaths

Alias for the type of maps that represent derivation paths in a psbt::Input or +psbt::Output

+
KeyMap

Alias type for a map of public key to secret key

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/enum.PolicyError.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/enum.PolicyError.html new file mode 100644 index 0000000000..c514b71eff --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/enum.PolicyError.html @@ -0,0 +1,55 @@ +bdk::descriptor::policy::PolicyError - Rust + +

[][src]Enum bdk::descriptor::policy::PolicyError

pub enum PolicyError {
+    NotEnoughItemsSelected(String),
+    TooManyItemsSelected(String),
+    IndexOutOfRange(usize),
+    AddOnLeaf,
+    AddOnPartialComplete,
+    MixedTimelockUnits,
+    IncompatibleConditions,
+}

Errors that can happen while extracting and manipulating policies

+

+ Variants

+
NotEnoughItemsSelected(String)

Not enough items are selected to satisfy a SatisfiableItem::Thresh

+
TooManyItemsSelected(String)

Too many items are selected to satisfy a SatisfiableItem::Thresh

+
IndexOutOfRange(usize)

Index out of range for an item to satisfy a SatisfiableItem::Thresh

+
AddOnLeaf

Can not add to an item that is Satisfaction::None or Satisfaction::Complete

+
AddOnPartialComplete

Can not add to an item that is Satisfaction::PartialComplete

+
MixedTimelockUnits

Can not merge CSV or timelock values unless both are less than or both are equal or greater than 500_000_000

+
IncompatibleConditions

Incompatible conditions (not currently used)

+

Trait Implementations

impl Debug for PolicyError[src]

impl Display for PolicyError[src]

impl Error for PolicyError[src]

impl From<PolicyError> for Error[src]

impl From<PolicyError> for Error[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/enum.Satisfaction.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/enum.Satisfaction.html new file mode 100644 index 0000000000..5c56c8e9b8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/enum.Satisfaction.html @@ -0,0 +1,75 @@ +bdk::descriptor::policy::Satisfaction - Rust + +

[][src]Enum bdk::descriptor::policy::Satisfaction

pub enum Satisfaction {
+    Partial {
+        n: usize,
+        m: usize,
+        items: Vec<usize>,
+        sorted: Option<bool>,
+        conditions: ConditionMap,
+    },
+    PartialComplete {
+        n: usize,
+        m: usize,
+        items: Vec<usize>,
+        sorted: Option<bool>,
+        conditions: FoldedConditionMap,
+    },
+    Complete {
+        condition: Condition,
+    },
+    None,
+}

Represent if and how much a policy item is satisfied by the wallet's descriptor

+

+ Variants

+
Partial

Only a partial satisfaction of some kind of threshold policy

+

Fields of Partial

n: usize

Total number of items

+
m: usize

Threshold

+
items: Vec<usize>

The items that can be satisfied by the descriptor

+
sorted: Option<bool>

Whether the items are sorted in lexicographic order (used by sortedmulti)

+
conditions: ConditionMap

Extra conditions that also need to be satisfied

+
PartialComplete

Can reach the threshold of some kind of threshold policy

+

Fields of PartialComplete

n: usize

Total number of items

+
m: usize

Threshold

+
items: Vec<usize>

The items that can be satisfied by the descriptor

+
sorted: Option<bool>

Whether the items are sorted in lexicographic order (used by sortedmulti)

+
conditions: FoldedConditionMap

Extra conditions that also need to be satisfied

+
Complete

Can satisfy the policy item

+

Fields of Complete

condition: Condition

Extra conditions that also need to be satisfied

+
None

Cannot satisfy or contribute to the policy item

+

Implementations

impl Satisfaction[src]

pub fn is_leaf(&self) -> bool[src]

Returns whether the Satisfaction is a leaf item

+

Trait Implementations

impl Clone for Satisfaction[src]

impl Debug for Satisfaction[src]

impl From<bool> for Satisfaction[src]

impl Serialize for Satisfaction[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/enum.SatisfiableItem.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/enum.SatisfiableItem.html new file mode 100644 index 0000000000..e5fa6b2346 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/enum.SatisfiableItem.html @@ -0,0 +1,91 @@ +bdk::descriptor::policy::SatisfiableItem - Rust + +

[][src]Enum bdk::descriptor::policy::SatisfiableItem

pub enum SatisfiableItem {
+    Signature(PKOrF),
+    SignatureKey(PKOrF),
+    SHA256Preimage {
+        hash: Hash,
+    },
+    HASH256Preimage {
+        hash: Hash,
+    },
+    RIPEMD160Preimage {
+        hash: Hash,
+    },
+    HASH160Preimage {
+        hash: Hash,
+    },
+    AbsoluteTimelock {
+        value: u32,
+    },
+    RelativeTimelock {
+        value: u32,
+    },
+    Multisig {
+        keys: Vec<PKOrF>,
+        threshold: usize,
+    },
+    Thresh {
+        items: Vec<Policy>,
+        threshold: usize,
+    },
+}

An item that needs to be satisfied

+

+ Variants

+
Signature(PKOrF)

Signature for a raw public key

+
SignatureKey(PKOrF)

Signature for an extended key fingerprint

+
SHA256Preimage

SHA256 preimage hash

+

Fields of SHA256Preimage

hash: Hash

The digest value

+
HASH256Preimage

Double SHA256 preimage hash

+

Fields of HASH256Preimage

hash: Hash

The digest value

+
RIPEMD160Preimage

RIPEMD160 preimage hash

+

Fields of RIPEMD160Preimage

hash: Hash

The digest value

+
HASH160Preimage

SHA256 then RIPEMD160 preimage hash

+

Fields of HASH160Preimage

hash: Hash

The digest value

+
AbsoluteTimelock

Absolute timeclock timestamp

+

Fields of AbsoluteTimelock

value: u32

The timestamp value

+
RelativeTimelock

Relative timelock locktime

+

Fields of RelativeTimelock

value: u32

The locktime value

+
Multisig

Multi-signature public keys with threshold count

+

Fields of Multisig

keys: Vec<PKOrF>

The raw public key or extended key fingerprint

+
threshold: usize

The required threshold count

+
Thresh

Threshold items with threshold count

+

Fields of Thresh

items: Vec<Policy>

The policy items

+
threshold: usize

The required threshold count

+

Implementations

impl SatisfiableItem[src]

pub fn is_leaf(&self) -> bool[src]

Returns whether the SatisfiableItem is a leaf item

+

pub fn id(&self) -> String[src]

Returns a unique id for the SatisfiableItem

+

Trait Implementations

impl Clone for SatisfiableItem[src]

impl Debug for SatisfiableItem[src]

impl From<SatisfiableItem> for Policy[src]

impl Serialize for SatisfiableItem[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/index.html new file mode 100644 index 0000000000..b63abf9c5b --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/index.html @@ -0,0 +1,30 @@ +bdk::descriptor::policy - Rust + +

[][src]Module bdk::descriptor::policy

Descriptor policy

+

This module implements the logic to extract and represent the spending policies of a descriptor +in a more human-readable format.

+

This is an EXPERIMENTAL feature, API and other major changes are expected.

+

Example

+
+let secp = Secp256k1::new();
+let desc = "wsh(and_v(v:pk(cV3oCth6zxZ1UVsHLnGothsWNsaoxRhC6aeNi5VbSdFpwUkgkEci),or_d(pk(cVMTy7uebJgvFaSBwcgvwk8qn8xSLc97dKow4MBetjrrahZoimm2),older(12960))))";
+
+let (extended_desc, key_map) = ExtendedDescriptor::parse_descriptor(desc)?;
+println!("{:?}", extended_desc);
+
+let signers = Arc::new(key_map.into());
+let policy = extended_desc.extract_policy(&signers, &secp)?;
+println!("policy: {}", serde_json::to_string(&policy)?);
+

Structs

+
Condition

An extra condition that must be satisfied but that is out of control of the user

+
PKOrF

Raw public key or extended key fingerprint

+
Policy

Descriptor spending policy

+

Enums

+
PolicyError

Errors that can happen while extracting and manipulating policies

+
Satisfaction

Represent if and how much a policy item is satisfied by the wallet's descriptor

+
SatisfiableItem

An item that needs to be satisfied

+

Type Definitions

+
ConditionMap

Type for a map of sets of Condition items keyed by each set's index

+
FoldedConditionMap

Type for a map of folded sets of Condition items keyed by a vector of the combined set's indexes

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/sidebar-items.js new file mode 100644 index 0000000000..4a150396ce --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["PolicyError","Errors that can happen while extracting and manipulating policies"],["Satisfaction","Represent if and how much a policy item is satisfied by the wallet's descriptor"],["SatisfiableItem","An item that needs to be satisfied"]],"struct":[["Condition","An extra condition that must be satisfied but that is out of control of the user"],["PKOrF","Raw public key or extended key fingerprint"],["Policy","Descriptor spending policy"]],"type":[["ConditionMap","Type for a map of sets of [`Condition`] items keyed by each set's index"],["FoldedConditionMap","Type for a map of folded sets of [`Condition`] items keyed by a vector of the combined set's indexes"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/struct.Condition.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/struct.Condition.html new file mode 100644 index 0000000000..494ddc412f --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/struct.Condition.html @@ -0,0 +1,62 @@ +bdk::descriptor::policy::Condition - Rust + +

[][src]Struct bdk::descriptor::policy::Condition

pub struct Condition {
+    pub csv: Option<u32>,
+    pub timelock: Option<u32>,
+}

An extra condition that must be satisfied but that is out of control of the user

+

+ Fields

csv: Option<u32>

Optional CheckSequenceVerify condition

+
timelock: Option<u32>

Optional timelock condition

+

Implementations

impl Condition[src]

pub fn is_null(&self) -> bool[src]

Returns true if there are no extra conditions to verify

+

Trait Implementations

impl Clone for Condition[src]

impl Copy for Condition[src]

impl Debug for Condition[src]

impl Default for Condition[src]

impl Eq for Condition[src]

impl Hash for Condition[src]

impl Ord for Condition[src]

impl PartialEq<Condition> for Condition[src]

impl PartialOrd<Condition> for Condition[src]

impl Serialize for Condition[src]

impl StructuralEq for Condition[src]

impl StructuralPartialEq for Condition[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/struct.PKOrF.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/struct.PKOrF.html new file mode 100644 index 0000000000..2033adda15 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/struct.PKOrF.html @@ -0,0 +1,38 @@ +bdk::descriptor::policy::PKOrF - Rust + +

[][src]Struct bdk::descriptor::policy::PKOrF

pub struct PKOrF { /* fields omitted */ }

Raw public key or extended key fingerprint

+

Trait Implementations

impl Clone for PKOrF[src]

impl Debug for PKOrF[src]

impl Default for PKOrF[src]

impl Serialize for PKOrF[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/struct.Policy.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/struct.Policy.html new file mode 100644 index 0000000000..edb84dab4d --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/struct.Policy.html @@ -0,0 +1,55 @@ +bdk::descriptor::policy::Policy - Rust + +

[][src]Struct bdk::descriptor::policy::Policy

pub struct Policy {
+    pub id: String,
+    pub item: SatisfiableItem,
+    pub satisfaction: Satisfaction,
+    pub contribution: Satisfaction,
+}

Descriptor spending policy

+

+ Fields

id: String

Identifier for this policy node

+
item: SatisfiableItem

Type of this policy node

+
satisfaction: Satisfaction

How a much given PSBT already satisfies this polcy node (currently unused)

+
contribution: Satisfaction

How the wallet's descriptor can satisfy this policy node

+

Implementations

impl Policy[src]

pub fn requires_path(&self) -> bool[src]

Return whether or not a specific path in the policy tree is required to unambiguously +create a transaction

+

What this means is that for some spending policies the user should select which paths in +the tree it intends to satisfy while signing, because the transaction must be created differently based +on that.

+

pub fn get_condition(
    &self,
    path: &BTreeMap<String, Vec<usize>>
) -> Result<Condition, PolicyError>
[src]

Return the conditions that are set by the spending policy for a given path in the +policy tree

+

Trait Implementations

impl Clone for Policy[src]

impl Debug for Policy[src]

impl From<SatisfiableItem> for Policy[src]

impl Serialize for Policy[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/type.ConditionMap.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/type.ConditionMap.html new file mode 100644 index 0000000000..04cdc96053 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/type.ConditionMap.html @@ -0,0 +1,5 @@ +bdk::descriptor::policy::ConditionMap - Rust + +

[][src]Type Definition bdk::descriptor::policy::ConditionMap

type ConditionMap = BTreeMap<usize, HashSet<Condition>>;

Type for a map of sets of Condition items keyed by each set's index

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/type.FoldedConditionMap.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/type.FoldedConditionMap.html new file mode 100644 index 0000000000..d677ccbae2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/policy/type.FoldedConditionMap.html @@ -0,0 +1,5 @@ +bdk::descriptor::policy::FoldedConditionMap - Rust + +

[][src]Type Definition bdk::descriptor::policy::FoldedConditionMap

type FoldedConditionMap = BTreeMap<Vec<usize>, HashSet<Condition>>;

Type for a map of folded sets of Condition items keyed by a vector of the combined set's indexes

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/sidebar-items.js new file mode 100644 index 0000000000..91b23d7fe1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["Descriptor","Script descriptor"],["Legacy","Legacy ScriptContext To be used as P2SH scripts For creation of Bare scriptpubkeys, construct the Miniscript under `Bare` ScriptContext"],["Segwitv0","Segwitv0 ScriptContext"],["Terminal","All AST elements"]],"mod":[["checksum","Descriptor checksum"],["error","Descriptor errors"],["policy","Descriptor policy"],["template","Descriptor templates"]],"struct":[["Miniscript","Top-level script AST type"]],"trait":[["ExtractPolicy","Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`]"],["MiniscriptKey","Public key trait which can be converted to Hash type"],["ScriptContext","The ScriptContext for Miniscript. Additional type information associated with miniscript that is used for carrying out checks that dependent on the context under which the script is used. For example, disallowing uncompressed keys in Segwit context"],["ToPublicKey","Trait describing public key types which can be converted to bitcoin pubkeys The trait relies on Copy trait because in all practical usecases `ToPkCtx` should contain references to objects which should be cheap to `Copy`."],["ToWalletDescriptor","Trait for types which can be converted into an [`ExtendedDescriptor`] and a [`KeyMap`] usable by a wallet in a specific [`Network`]"]],"type":[["ExtendedDescriptor","Alias for a [`Descriptor`] that can contain extended keys using [`DescriptorPublicKey`]"],["HDKeyPaths","Alias for the type of maps that represent derivation paths in a `psbt::Input` or `psbt::Output`"],["KeyMap","Alias type for a map of public key to secret key"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/struct.Miniscript.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/struct.Miniscript.html new file mode 100644 index 0000000000..1c5121d486 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/struct.Miniscript.html @@ -0,0 +1,206 @@ +bdk::descriptor::Miniscript - Rust + +

[]Struct bdk::descriptor::Miniscript

pub struct Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey
{ + pub node: Terminal<Pk, Ctx>, + pub ty: Type, + pub ext: ExtData, + // some fields omitted +}

Top-level script AST type

+

+ Fields

node: Terminal<Pk, Ctx>

A node in the Abstract Syntax Tree(

+
ty: Type

The correctness and malleability type information for the AST node

+
ext: ExtData

Additional information helpful for extra analysis.

+

Implementations

impl<Pk, Ctx> Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn requires_sig(&self) -> bool

Whether all spend paths of miniscript require a signature

+

pub fn is_non_malleable(&self) -> bool

Whether the miniscript is malleable

+

pub fn within_resource_limits(&self) -> bool

Whether the miniscript can exceed the resource limits(Opcodes, Stack limit etc)

+

pub fn has_mixed_timelocks(&self) -> bool

Whether the miniscript contains a combination of timelocks

+

pub fn has_repeated_keys(&self) -> bool

Whether the miniscript has repeated Pk or Pkh

+

pub fn sanity_check(&self) -> Result<(), AnalysisError>

Check whether the underlying Miniscript is safe under the current context +Lifting these polices would create a semantic representation that does +not represent the underlying semantics when miniscript is spent. +Signing logic may not find satisfaction even if one exists.

+

For most cases, users should be dealing with safe scripts. +Use this function to check whether the guarantees of library hold. +Most functions of the library like would still +work, but results cannot be relied upon

+

impl<Pk, Ctx> Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Iterator-related extensions for Miniscript

+

pub fn iter(&self) -> Iter<'_, Pk, Ctx>

Creates a new [Iter] iterator that will iterate over all Miniscript items within +AST by traversing its branches. For the specific algorithm please see +[Iter::next] function.

+

pub fn iter_pk(&self) -> PkIter<'_, Pk, Ctx>

Creates a new [PkIter] iterator that will iterate over all plain public keys (and not +key hash values) present in Miniscript items within AST by traversing all its branches. +For the specific algorithm please see [PkIter::next] function.

+

pub fn iter_pkh(&self) -> PkhIter<'_, Pk, Ctx>

Creates a new [PkhIter] iterator that will iterate over all public keys hashes (and not +plain public keys) present in Miniscript items within AST by traversing all its branches. +For the specific algorithm please see [PkhIter::next] function.

+

pub fn iter_pk_pkh(&self) -> PkPkhIter<'_, Pk, Ctx>

Creates a new [PkPkhIter] iterator that will iterate over all plain public keys and +key hash values present in Miniscript items within AST by traversing all its branches. +For the specific algorithm please see [PkPkhIter::next] function.

+

pub fn branches(&self) -> Vec<&Miniscript<Pk, Ctx>, Global>

Enumerates all child nodes of the current AST node (self) and returns a Vec referencing +them.

+

pub fn get_nth_child(&self, n: usize) -> Option<&Miniscript<Pk, Ctx>>

Returns child node with given index, if any

+

pub fn get_leaf_pk(&self) -> Vec<Pk, Global>

Returns Vec with cloned version of all public keys from the current miniscript item, +if any. Otherwise returns an empty Vec.

+

NB: The function analyzes only single miniscript item and not any of its descendants in AST. +To obtain a list of all public keys within AST use [fn.iter_pk()] function, for example +miniscript.iter_pubkeys().collect().

+

pub fn get_leaf_pkh(&self) -> Vec<<Pk as MiniscriptKey>::Hash, Global>

Returns Vec with hashes of all public keys from the current miniscript item, if any. +Otherwise returns an empty Vec.

+

For each public key the function computes hash; for each hash of the public key the function +returns its cloned copy.

+

NB: The function analyzes only single miniscript item and not any of its descendants in AST. +To obtain a list of all public key hashes within AST use [fn.iter_pkh()] function, +for example miniscript.iter_pubkey_hashes().collect().

+

pub fn get_leaf_pk_pkh(&self) -> Vec<PkPkh<Pk>, Global>

Returns Vec of [PkPkh] entries, representing either public keys or public key +hashes, depending on the data from the current miniscript item. If there is no public +keys or hashes, the function returns an empty Vec.

+

NB: The function analyzes only single miniscript item and not any of its descendants in AST. +To obtain a list of all public keys or hashes within AST use [fn.iter_pk_pkh()] +function, for example miniscript.iter_pubkeys_and_hashes().collect().

+

pub fn get_nth_pk(&self, n: usize) -> Option<Pk>

Returns Option::Some with cloned n'th public key from the current miniscript item, +if any. Otherwise returns Option::None.

+

NB: The function analyzes only single miniscript item and not any of its descendants in AST.

+

pub fn get_nth_pkh(&self, n: usize) -> Option<<Pk as MiniscriptKey>::Hash>

Returns Option::Some with hash of n'th public key from the current miniscript item, +if any. Otherwise returns Option::None.

+

For each public key the function computes hash; for each hash of the public key the function +returns it cloned copy.

+

NB: The function analyzes only single miniscript item and not any of its descendants in AST.

+

pub fn get_nth_pk_pkh(&self, n: usize) -> Option<PkPkh<Pk>>

Returns Option::Some with hash of n'th public key or hash from the current miniscript item, +if any. Otherwise returns Option::None.

+

NB: The function analyzes only single miniscript item and not any of its descendants in AST.

+

impl<Pk, Ctx> Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn from_ast(t: Terminal<Pk, Ctx>) -> Result<Miniscript<Pk, Ctx>, Error>

Add type information(Type and Extdata) to Miniscript based on +AstElem fragment. Dependent on display and clone because of Error +Display code of type_check.

+

impl<Pk, Ctx> Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn into_inner(self) -> Terminal<Pk, Ctx>

Extracts the AstElem representing the root of the miniscript

+

pub fn as_inner(&self) -> &Terminal<Pk, Ctx>

Get a reference to the inner AstElem representing the root of miniscript

+

impl<Ctx> Miniscript<PublicKey, Ctx> where
    Ctx: ScriptContext

pub fn parse_insane(
    script: &Script
) -> Result<Miniscript<PublicKey, Ctx>, Error>

Attempt to parse an insane(scripts don't clear sanity checks) +script into a Miniscript representation. +Use this to parse scripts with repeated pubkeys, timelock mixing, malleable +scripts without sig or scripts that can exceed resource limits. +Some of the analysis guarantees of miniscript are lost when dealing with +insane scripts. In general, in a multi-party setting users should only +accept sane scripts.

+

pub fn parse(script: &Script) -> Result<Miniscript<PublicKey, Ctx>, Error>

Attempt to parse a Script into Miniscript representation. +This function will fail parsing for scripts that do not clear +the [fn.analyzable.sanity_check] checks. Use [fn.parse_insane] to +parse such scripts.

+

impl<Pk, Ctx> Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn encode<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> Script where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Encode as a Bitcoin script

+

pub fn script_size<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> usize where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Size, in bytes of the script-pubkey. If this Miniscript is used outside +of segwit (e.g. in a bare or P2SH descriptor), this quantity should be +multiplied by 4 to compute the weight.

+

In general, it is not recommended to use this function directly, but +to instead call the corresponding function on a Descriptor, which +will handle the segwit/non-segwit technicalities for you.

+

impl<Pk, Ctx> Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn max_satisfaction_witness_elements(&self) -> Option<usize>

Maximum number of witness elements used to satisfy the Miniscript +fragment, including the witness script itself. Used to estimate +the weight of the VarInt that specifies this number in a serialized +transaction.

+

This function may return None on malformed Miniscript objects which do +not correspond to semantically sane Scripts. (Such scripts should be +rejected at parse time. Any exceptions are bugs.)

+

pub fn max_satisfaction_size(&self) -> Option<usize>

Maximum size, in bytes, of a satisfying witness. For Segwit outputs +one_cost should be set to 2, since the number 1 requires two +bytes to encode. For non-segwit outputs one_cost should be set to +1, since OP_1 is available in scriptSigs.

+

In general, it is not recommended to use this function directly, but +to instead call the corresponding function on a Descriptor, which +will handle the segwit/non-segwit technicalities for you.

+

All signatures are assumed to be 73 bytes in size, including the +length prefix (segwit) or push opcode (pre-segwit) and sighash +postfix.

+

impl<Pk, Ctx> Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn translate_pk<FPk, FPkh, Q, FuncError>(
    &self,
    translatefpk: &mut FPk,
    translatefpkh: &mut FPkh
) -> Result<Miniscript<Q, Ctx>, FuncError> where
    FPk: FnMut(&Pk) -> Result<Q, FuncError>,
    FPkh: FnMut(&<Pk as MiniscriptKey>::Hash) -> Result<<Q as MiniscriptKey>::Hash, FuncError>,
    Q: MiniscriptKey

This will panic if translatefpk returns an uncompressed key when +converting to a Segwit descriptor. To prevent this panic, ensure +translatefpk returns an error in this case instead.

+

pub fn from_str_insane(s: &str) -> Result<Miniscript<Pk, Ctx>, Error> where
    <Pk as FromStr>::Err: ToString,
    <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString

Attempt to parse an insane(scripts don't clear sanity checks) +from string into a Miniscript representation. +Use this to parse scripts with repeated pubkeys, timelock mixing, malleable +scripts without sig or scripts that can exceed resource limits. +Some of the analysis guarantees of miniscript are lost when dealing with +insane scripts. In general, in a multi-party setting users should only +accept sane scripts.

+

impl<Pk, Ctx> Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn satisfy<ToPkCtx, S>(
    &self,
    satisfier: S,
    to_pk_ctx: ToPkCtx
) -> Result<Vec<Vec<u8, Global>, Global>, Error> where
    Pk: ToPublicKey<ToPkCtx>,
    S: Satisfier<ToPkCtx, Pk>,
    ToPkCtx: Copy

Attempt to produce non-malleable satisfying witness for the +witness script represented by the parse tree

+

pub fn satisfy_malleable<ToPkCtx, S>(
    &self,
    satisfier: S,
    to_pk_ctx: ToPkCtx
) -> Result<Vec<Vec<u8, Global>, Global>, Error> where
    Pk: ToPublicKey<ToPkCtx>,
    S: Satisfier<ToPkCtx, Pk>,
    ToPkCtx: Copy

Attempt to produce a malleable satisfying witness for the +witness script represented by the parse tree

+

impl<Pk, Ctx> Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn lift_check(&self) -> Result<(), LiftError>

Lifting corresponds conversion of miniscript into Policy +[policy.semantic.Policy] for human readable or machine analysis. +However, naively lifting miniscripts can result in incorrect +interpretations that don't correspond underlying semantics when +we try to spend them on bitcoin network. +This can occur if the miniscript contains a

+
    +
  1. Timelock combination
  2. +
  3. Contains a spend that exceeds resource limits
  4. +
+

Trait Implementations

impl<Pk, Ctx> Clone for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext + Clone,
    Pk: MiniscriptKey + Clone

impl<Pk, Ctx> Debug for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> Display for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> Eq for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Eq of Miniscript must depend only on node and not the type information. +The type information and extra_properties can be deterministically determined +by the ast.

+

impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx>[src]

impl<Pk, Ctx> FromStr for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey,
    <Pk as FromStr>::Err: ToString,
    <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString

type Err = Error

The associated error which can be returned from parsing.

+

pub fn from_str(s: &str) -> Result<Miniscript<Pk, Ctx>, Error>

Parse a Miniscript from string and perform sanity checks +See [fn.from_str_insane] to parse scripts from string that +do not clear the [fn.analyzable.sanity_check] checks.

+

impl<Pk, Ctx> FromTree for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey,
    <Pk as FromStr>::Err: ToString,
    <<Pk as MiniscriptKey>::Hash as FromStr>::Err: ToString

pub fn from_tree(top: &Tree<'_>) -> Result<Miniscript<Pk, Ctx>, Error>

Parse an expression tree into a Miniscript. As a general rule, this +should not be called directly; rather go through the descriptor API.

+

impl<Pk, Ctx> Hash for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext + Hash,
    Pk: MiniscriptKey + Hash

impl<Pk, Ctx> Liftable<Pk> for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> Ord for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Ord of Miniscript must depend only on node and not the type information. +The type information and extra_properties can be deterministically determined +by the ast.

+

impl<Pk, Ctx> PartialEq<Miniscript<Pk, Ctx>> for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

PartialEq of Miniscript must depend only on node and not the type information. +The type information and extra_properties can be deterministically determined +by the ast.

+

impl<Pk, Ctx> PartialOrd<Miniscript<Pk, Ctx>> for Miniscript<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

PartialOrd of Miniscript must depend only on node and not the type information. +The type information and extra_properties can be deterministically determined +by the ast.

+

Auto Trait Implementations

impl<Pk, Ctx> RefUnwindSafe for Miniscript<Pk, Ctx> where
    Ctx: RefUnwindSafe,
    Pk: RefUnwindSafe,
    <Pk as MiniscriptKey>::Hash: RefUnwindSafe
[src]

impl<Pk, Ctx> Send for Miniscript<Pk, Ctx> where
    Ctx: Send + Sync,
    Pk: Send + Sync,
    <Pk as MiniscriptKey>::Hash: Send + Sync
[src]

impl<Pk, Ctx> Sync for Miniscript<Pk, Ctx> where
    Ctx: Send + Sync,
    Pk: Send + Sync,
    <Pk as MiniscriptKey>::Hash: Send + Sync
[src]

impl<Pk, Ctx> Unpin for Miniscript<Pk, Ctx> where
    Ctx: Unpin,
    Pk: Unpin,
    <Pk as MiniscriptKey>::Hash: Unpin
[src]

impl<Pk, Ctx> UnwindSafe for Miniscript<Pk, Ctx> where
    Ctx: RefUnwindSafe + UnwindSafe,
    Pk: RefUnwindSafe + UnwindSafe,
    <Pk as MiniscriptKey>::Hash: RefUnwindSafe + UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/index.html new file mode 100644 index 0000000000..a701f40721 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/index.html @@ -0,0 +1,21 @@ +bdk::descriptor::template - Rust + +

[][src]Module bdk::descriptor::template

Descriptor templates

+

This module contains the definition of various common script templates that are ready to be +used. See the documentation of each template for an example.

+

Structs

+
BIP44

BIP44 template. Expands to pkh(key/44'/0'/0'/{0,1}/*)

+
BIP44Public

BIP44 public template. Expands to pkh(key/{0,1}/*)

+
BIP49

BIP49 template. Expands to sh(wpkh(key/49'/0'/0'/{0,1}/*))

+
BIP49Public

BIP49 public template. Expands to sh(wpkh(key/{0,1}/*))

+
BIP84

BIP84 template. Expands to wpkh(key/84'/0'/0'/{0,1}/*)

+
BIP84Public

BIP84 public template. Expands to wpkh(key/{0,1}/*)

+
P2PKH

P2PKH template. Expands to a descriptor pkh(key)

+
P2WPKH

P2WPKH template. Expands to a descriptor wpkh(key)

+
P2WPKH_P2SH

P2WPKH-P2SH template. Expands to a descriptor sh(wpkh(key))

+

Traits

+
DescriptorTemplate

Trait for descriptor templates that can be built into a full descriptor

+

Type Definitions

+
DescriptorTemplateOut

Type alias for the return type of DescriptorTemplate, descriptor! and others

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/sidebar-items.js new file mode 100644 index 0000000000..1e10991c5b --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"struct":[["BIP44","BIP44 template. Expands to `pkh(key/44'/0'/0'/{0,1}/*)`"],["BIP44Public","BIP44 public template. Expands to `pkh(key/{0,1}/*)`"],["BIP49","BIP49 template. Expands to `sh(wpkh(key/49'/0'/0'/{0,1}/*))`"],["BIP49Public","BIP49 public template. Expands to `sh(wpkh(key/{0,1}/*))`"],["BIP84","BIP84 template. Expands to `wpkh(key/84'/0'/0'/{0,1}/*)`"],["BIP84Public","BIP84 public template. Expands to `wpkh(key/{0,1}/*)`"],["P2PKH","P2PKH template. Expands to a descriptor `pkh(key)`"],["P2WPKH","P2WPKH template. Expands to a descriptor `wpkh(key)`"],["P2WPKH_P2SH","P2WPKH-P2SH template. Expands to a descriptor `sh(wpkh(key))`"]],"trait":[["DescriptorTemplate","Trait for descriptor templates that can be built into a full descriptor"]],"type":[["DescriptorTemplateOut","Type alias for the return type of [`DescriptorTemplate`], `descriptor!` and others"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP44.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP44.html new file mode 100644 index 0000000000..e1665c341e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP44.html @@ -0,0 +1,47 @@ +bdk::descriptor::template::BIP44 - Rust + +

[][src]Struct bdk::descriptor::template::BIP44

pub struct BIP44<K: DerivableKey<Legacy>>(pub K, pub KeychainKind);

BIP44 template. Expands to pkh(key/44'/0'/0'/{0,1}/*)

+

Since there are hardened derivation steps, this template requires a private derivable key (generally a xprv/tprv).

+

See BIP44Public for a template that can work with a xpub/tpub.

+

Example

+
+use bdk::template::BIP44;
+
+let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    BIP44(key.clone(), KeychainKind::External),
+    Some(BIP44(key, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_new_address()?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)");
+

Trait Implementations

impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44<K>[src]

Auto Trait Implementations

impl<K> RefUnwindSafe for BIP44<K> where
    K: RefUnwindSafe
[src]

impl<K> Send for BIP44<K> where
    K: Send
[src]

impl<K> Sync for BIP44<K> where
    K: Sync
[src]

impl<K> Unpin for BIP44<K> where
    K: Unpin
[src]

impl<K> UnwindSafe for BIP44<K> where
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToWalletDescriptor for T where
    T: DescriptorTemplate
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP44Public.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP44Public.html new file mode 100644 index 0000000000..6eb406b0a5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP44Public.html @@ -0,0 +1,50 @@ +bdk::descriptor::template::BIP44Public - Rust + +

[][src]Struct bdk::descriptor::template::BIP44Public

pub struct BIP44Public<K: DerivableKey<Legacy>>(pub K, pub Fingerprint, pub KeychainKind);

BIP44 public template. Expands to pkh(key/{0,1}/*)

+

This assumes that the key used has already been derived with m/44'/0'/0'.

+

This template requires the parent fingerprint to populate correctly the metadata of PSBTs.

+

See BIP44 for a template that does the full derivation, but requires private data +for the key.

+

Example

+
+use bdk::template::BIP44Public;
+
+let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
+let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    BIP44Public(key.clone(), fingerprint, KeychainKind::External),
+    Some(BIP44Public(key, fingerprint, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_new_address()?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)");
+

Trait Implementations

impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44Public<K>[src]

Auto Trait Implementations

impl<K> RefUnwindSafe for BIP44Public<K> where
    K: RefUnwindSafe
[src]

impl<K> Send for BIP44Public<K> where
    K: Send
[src]

impl<K> Sync for BIP44Public<K> where
    K: Sync
[src]

impl<K> Unpin for BIP44Public<K> where
    K: Unpin
[src]

impl<K> UnwindSafe for BIP44Public<K> where
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToWalletDescriptor for T where
    T: DescriptorTemplate
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP49.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP49.html new file mode 100644 index 0000000000..2efbae9d75 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP49.html @@ -0,0 +1,47 @@ +bdk::descriptor::template::BIP49 - Rust + +

[][src]Struct bdk::descriptor::template::BIP49

pub struct BIP49<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);

BIP49 template. Expands to sh(wpkh(key/49'/0'/0'/{0,1}/*))

+

Since there are hardened derivation steps, this template requires a private derivable key (generally a xprv/tprv).

+

See BIP49Public for a template that can work with a xpub/tpub.

+

Example

+
+use bdk::template::BIP49;
+
+let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    BIP49(key.clone(), KeychainKind::External),
+    Some(BIP49(key, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_new_address()?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))");
+

Trait Implementations

impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49<K>[src]

Auto Trait Implementations

impl<K> RefUnwindSafe for BIP49<K> where
    K: RefUnwindSafe
[src]

impl<K> Send for BIP49<K> where
    K: Send
[src]

impl<K> Sync for BIP49<K> where
    K: Sync
[src]

impl<K> Unpin for BIP49<K> where
    K: Unpin
[src]

impl<K> UnwindSafe for BIP49<K> where
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToWalletDescriptor for T where
    T: DescriptorTemplate
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP49Public.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP49Public.html new file mode 100644 index 0000000000..7fff60cfd4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP49Public.html @@ -0,0 +1,50 @@ +bdk::descriptor::template::BIP49Public - Rust + +

[][src]Struct bdk::descriptor::template::BIP49Public

pub struct BIP49Public<K: DerivableKey<Segwitv0>>(pub K, pub Fingerprint, pub KeychainKind);

BIP49 public template. Expands to sh(wpkh(key/{0,1}/*))

+

This assumes that the key used has already been derived with m/49'/0'/0'.

+

This template requires the parent fingerprint to populate correctly the metadata of PSBTs.

+

See BIP49 for a template that does the full derivation, but requires private data +for the key.

+

Example

+
+use bdk::template::BIP49Public;
+
+let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
+let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    BIP49Public(key.clone(), fingerprint, KeychainKind::External),
+    Some(BIP49Public(key, fingerprint, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_new_address()?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))");
+

Trait Implementations

impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49Public<K>[src]

Auto Trait Implementations

impl<K> RefUnwindSafe for BIP49Public<K> where
    K: RefUnwindSafe
[src]

impl<K> Send for BIP49Public<K> where
    K: Send
[src]

impl<K> Sync for BIP49Public<K> where
    K: Sync
[src]

impl<K> Unpin for BIP49Public<K> where
    K: Unpin
[src]

impl<K> UnwindSafe for BIP49Public<K> where
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToWalletDescriptor for T where
    T: DescriptorTemplate
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP84.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP84.html new file mode 100644 index 0000000000..934b4dc733 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP84.html @@ -0,0 +1,47 @@ +bdk::descriptor::template::BIP84 - Rust + +

[][src]Struct bdk::descriptor::template::BIP84

pub struct BIP84<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);

BIP84 template. Expands to wpkh(key/84'/0'/0'/{0,1}/*)

+

Since there are hardened derivation steps, this template requires a private derivable key (generally a xprv/tprv).

+

See BIP84Public for a template that can work with a xpub/tpub.

+

Example

+
+use bdk::template::BIP84;
+
+let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    BIP84(key.clone(), KeychainKind::External),
+    Some(BIP84(key, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_new_address()?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)");
+

Trait Implementations

impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84<K>[src]

Auto Trait Implementations

impl<K> RefUnwindSafe for BIP84<K> where
    K: RefUnwindSafe
[src]

impl<K> Send for BIP84<K> where
    K: Send
[src]

impl<K> Sync for BIP84<K> where
    K: Sync
[src]

impl<K> Unpin for BIP84<K> where
    K: Unpin
[src]

impl<K> UnwindSafe for BIP84<K> where
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToWalletDescriptor for T where
    T: DescriptorTemplate
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP84Public.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP84Public.html new file mode 100644 index 0000000000..632706f146 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.BIP84Public.html @@ -0,0 +1,50 @@ +bdk::descriptor::template::BIP84Public - Rust + +

[][src]Struct bdk::descriptor::template::BIP84Public

pub struct BIP84Public<K: DerivableKey<Segwitv0>>(pub K, pub Fingerprint, pub KeychainKind);

BIP84 public template. Expands to wpkh(key/{0,1}/*)

+

This assumes that the key used has already been derived with m/84'/0'/0'.

+

This template requires the parent fingerprint to populate correctly the metadata of PSBTs.

+

See BIP84 for a template that does the full derivation, but requires private data +for the key.

+

Example

+
+use bdk::template::BIP84Public;
+
+let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
+let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    BIP84Public(key.clone(), fingerprint, KeychainKind::External),
+    Some(BIP84Public(key, fingerprint, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_new_address()?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)");
+

Trait Implementations

impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84Public<K>[src]

Auto Trait Implementations

impl<K> RefUnwindSafe for BIP84Public<K> where
    K: RefUnwindSafe
[src]

impl<K> Send for BIP84Public<K> where
    K: Send
[src]

impl<K> Sync for BIP84Public<K> where
    K: Sync
[src]

impl<K> Unpin for BIP84Public<K> where
    K: Unpin
[src]

impl<K> UnwindSafe for BIP84Public<K> where
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToWalletDescriptor for T where
    T: DescriptorTemplate
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.P2PKH.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.P2PKH.html new file mode 100644 index 0000000000..0678bdd7e4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.P2PKH.html @@ -0,0 +1,48 @@ +bdk::descriptor::template::P2PKH - Rust + +

[][src]Struct bdk::descriptor::template::P2PKH

pub struct P2PKH<K: ToDescriptorKey<Legacy>>(pub K);

P2PKH template. Expands to a descriptor pkh(key)

+

Example

+
+use bdk::template::P2PKH;
+
+let key =
+    bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    P2PKH(key),
+    None,
+    Network::Testnet,
+    MemoryDatabase::default(),
+)?;
+
+assert_eq!(
+    wallet.get_new_address()?.to_string(),
+    "mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT"
+);
+

Trait Implementations

impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for P2PKH<K>[src]

Auto Trait Implementations

impl<K> RefUnwindSafe for P2PKH<K> where
    K: RefUnwindSafe
[src]

impl<K> Send for P2PKH<K> where
    K: Send
[src]

impl<K> Sync for P2PKH<K> where
    K: Sync
[src]

impl<K> Unpin for P2PKH<K> where
    K: Unpin
[src]

impl<K> UnwindSafe for P2PKH<K> where
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToWalletDescriptor for T where
    T: DescriptorTemplate
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.P2WPKH.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.P2WPKH.html new file mode 100644 index 0000000000..4766fc25f8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.P2WPKH.html @@ -0,0 +1,48 @@ +bdk::descriptor::template::P2WPKH - Rust + +

[][src]Struct bdk::descriptor::template::P2WPKH

pub struct P2WPKH<K: ToDescriptorKey<Segwitv0>>(pub K);

P2WPKH template. Expands to a descriptor wpkh(key)

+

Example

+
+use bdk::template::P2WPKH;
+
+let key =
+    bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    P2WPKH(key),
+    None,
+    Network::Testnet,
+    MemoryDatabase::default(),
+)?;
+
+assert_eq!(
+    wallet.get_new_address()?.to_string(),
+    "tb1q4525hmgw265tl3drrl8jjta7ayffu6jf68ltjd"
+);
+

Trait Implementations

impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH<K>[src]

Auto Trait Implementations

impl<K> RefUnwindSafe for P2WPKH<K> where
    K: RefUnwindSafe
[src]

impl<K> Send for P2WPKH<K> where
    K: Send
[src]

impl<K> Sync for P2WPKH<K> where
    K: Sync
[src]

impl<K> Unpin for P2WPKH<K> where
    K: Unpin
[src]

impl<K> UnwindSafe for P2WPKH<K> where
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToWalletDescriptor for T where
    T: DescriptorTemplate
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.P2WPKH_P2SH.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.P2WPKH_P2SH.html new file mode 100644 index 0000000000..74f62aeac6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/struct.P2WPKH_P2SH.html @@ -0,0 +1,48 @@ +bdk::descriptor::template::P2WPKH_P2SH - Rust + +

[][src]Struct bdk::descriptor::template::P2WPKH_P2SH

pub struct P2WPKH_P2SH<K: ToDescriptorKey<Segwitv0>>(pub K);

P2WPKH-P2SH template. Expands to a descriptor sh(wpkh(key))

+

Example

+
+use bdk::template::P2WPKH_P2SH;
+
+let key =
+    bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    P2WPKH_P2SH(key),
+    None,
+    Network::Testnet,
+    MemoryDatabase::default(),
+)?;
+
+assert_eq!(
+    wallet.get_new_address()?.to_string(),
+    "2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5"
+);
+

Trait Implementations

impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH_P2SH<K>[src]

Auto Trait Implementations

impl<K> RefUnwindSafe for P2WPKH_P2SH<K> where
    K: RefUnwindSafe
[src]

impl<K> Send for P2WPKH_P2SH<K> where
    K: Send
[src]

impl<K> Sync for P2WPKH_P2SH<K> where
    K: Sync
[src]

impl<K> Unpin for P2WPKH_P2SH<K> where
    K: Unpin
[src]

impl<K> UnwindSafe for P2WPKH_P2SH<K> where
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToWalletDescriptor for T where
    T: DescriptorTemplate
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/trait.DescriptorTemplate.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/trait.DescriptorTemplate.html new file mode 100644 index 0000000000..8f3a721057 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/trait.DescriptorTemplate.html @@ -0,0 +1,23 @@ +bdk::descriptor::template::DescriptorTemplate - Rust + +

[][src]Trait bdk::descriptor::template::DescriptorTemplate

pub trait DescriptorTemplate {
+    pub fn build(self) -> Result<DescriptorTemplateOut, KeyError>;
+}

Trait for descriptor templates that can be built into a full descriptor

+

Since ToWalletDescriptor is implemented for any DescriptorTemplate, they can also be +passed directly to the Wallet constructor.

+

Example

+
+use bdk::keys::{KeyError, ToDescriptorKey};
+use bdk::miniscript::Legacy;
+use bdk::template::{DescriptorTemplate, DescriptorTemplateOut};
+
+struct MyP2PKH<K: ToDescriptorKey<Legacy>>(K);
+
+impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for MyP2PKH<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(bdk::descriptor!(pkh(self.0))?)
+    }
+}
+

Required methods

pub fn build(self) -> Result<DescriptorTemplateOut, KeyError>[src]

Build the complete descriptor

+
Loading content...

Implementors

impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44<K>[src]

impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44Public<K>[src]

impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49<K>[src]

impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49Public<K>[src]

impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84<K>[src]

impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84Public<K>[src]

impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for P2PKH<K>[src]

impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH<K>[src]

impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH_P2SH<K>[src]

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/type.DescriptorTemplateOut.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/type.DescriptorTemplateOut.html new file mode 100644 index 0000000000..2dc811d4f4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/template/type.DescriptorTemplateOut.html @@ -0,0 +1,6 @@ +bdk::descriptor::template::DescriptorTemplateOut - Rust + +

[][src]Type Definition bdk::descriptor::template::DescriptorTemplateOut

type DescriptorTemplateOut = (ExtendedDescriptor, KeyMap, ValidNetworks);

Type alias for the return type of DescriptorTemplate, descriptor! and others

+

Trait Implementations

impl ToWalletDescriptor for DescriptorTemplateOut[src]

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ExtractPolicy.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ExtractPolicy.html new file mode 100644 index 0000000000..1012bebadf --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ExtractPolicy.html @@ -0,0 +1,8 @@ +bdk::descriptor::ExtractPolicy - Rust + +

[][src]Trait bdk::descriptor::ExtractPolicy

pub trait ExtractPolicy {
+    pub fn extract_policy(
        &self,
        signers: &SignersContainer,
        secp: &Secp256k1<All>
    ) -> Result<Option<Policy>, Error>; +}

Trait implemented on Descriptors to add a method to extract the spending policy

+

Required methods

pub fn extract_policy(
    &self,
    signers: &SignersContainer,
    secp: &Secp256k1<All>
) -> Result<Option<Policy>, Error>
[src]

Extract the spending policy

+
Loading content...

Implementors

impl ExtractPolicy for Descriptor<DescriptorPublicKey>[src]

impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx>[src]

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.MiniscriptKey.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.MiniscriptKey.html new file mode 100644 index 0000000000..45e2f12a24 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.MiniscriptKey.html @@ -0,0 +1,16 @@ +bdk::descriptor::MiniscriptKey - Rust + +

[]Trait bdk::descriptor::MiniscriptKey

pub trait MiniscriptKey: Clone + Eq + Ord + Debug + Display + Hash + FromStr {
+    type Hash: Clone + Eq + Ord + Debug + Display + Hash + FromStr;
+    pub fn to_pubkeyhash(&self) -> Self::Hash;
+
+    pub fn is_uncompressed(&self) -> bool { ... }
+}

Public key trait which can be converted to Hash type

+

Associated Types

type Hash: Clone + Eq + Ord + Debug + Display + Hash + FromStr

The associated Hash type with the publicKey

+
Loading content...

Required methods

pub fn to_pubkeyhash(&self) -> Self::Hash

Converts an object to PublicHash

+
Loading content...

Provided methods

pub fn is_uncompressed(&self) -> bool

Check if the publicKey is uncompressed. The default +implementation returns false

+
Loading content...

Implementations on Foreign Types

impl MiniscriptKey for String

type Hash = String

impl MiniscriptKey for DummyKey

type Hash = DummyKeyHash

impl MiniscriptKey for PublicKey

pub fn is_uncompressed(&self) -> bool

is_uncompressed returns true only for +bitcoin::Publickey type if the underlying key is uncompressed.

+

type Hash = Hash

Loading content...

Implementors

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ScriptContext.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ScriptContext.html new file mode 100644 index 0000000000..c2bd80c5da --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ScriptContext.html @@ -0,0 +1,78 @@ +bdk::descriptor::ScriptContext - Rust + +

[]Trait bdk::descriptor::ScriptContext

pub trait ScriptContext: Sealed + Clone + PartialEq<Self> + Eq + Ord + PartialOrd<Self> + Debug {
+    pub fn check_terminal_non_malleable<Pk, Ctx>(
        _frag: &Terminal<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
; +
pub fn max_satisfaction_size<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Option<usize>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
; + + pub fn check_witness<Pk, Ctx>(
        _witness: &[Vec<u8, Global>]
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_global_consensus_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_global_policy_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_local_consensus_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_local_policy_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_global_validity<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_local_validity<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn top_level_type_check<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn other_top_level_checks<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn top_level_checks<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +}

The ScriptContext for Miniscript. Additional type information associated with +miniscript that is used for carrying out checks that dependent on the +context under which the script is used. +For example, disallowing uncompressed keys in Segwit context

+

Required methods

pub fn check_terminal_non_malleable<Pk, Ctx>(
    _frag: &Terminal<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Depending on ScriptContext, fragments can be malleable. For Example, +under Legacy context, PkH is malleable because it is possible to +estimate the cost of satisfaction because of compressed keys +This is currently only used in compiler code for removing malleable +compilations. +This does NOT recursively check if the children of the fragment are +valid or not. Since the compilation proceeds in a leaf to root fashion, +a recursive check is unnecessary.

+

pub fn max_satisfaction_size<Pk, Ctx>(ms: &Miniscript<Pk, Ctx>) -> Option<usize> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Depending on script context, the size of a satifaction witness may slightly differ.

+
Loading content...

Provided methods

pub fn check_witness<Pk, Ctx>(
    _witness: &[Vec<u8, Global>]
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check whether the given satisfaction is valid under the ScriptContext +For example, segwit satisfactions may fail if the witness len is more +3600 or number of stack elements are more than 100.

+

pub fn check_global_consensus_validity<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Depending on script Context, some of the Terminals might not +be valid under the current consensus rules. +Or some of the script resource limits may have been exceeded. +These miniscripts would never be accepted by the Bitcoin network and hence +it is safe to discard them +For example, in Segwit Context with MiniscriptKey as bitcoin::PublicKey +uncompressed public keys are non-standard and thus invalid. +In LegacyP2SH context, scripts above 520 bytes are invalid. +Post Tapscript upgrade, this would have to consider other nodes. +This does NOT recursively check the miniscript fragments.

+

pub fn check_global_policy_validity<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Depending on script Context, some of the script resource limits +may have been exceeded under the current bitcoin core policy rules +These miniscripts would never be accepted by the Bitcoin network and hence +it is safe to discard them. (unless explicitly disabled by non-standard flag) +For example, in Segwit Context with MiniscriptKey as bitcoin::PublicKey +scripts over 3600 bytes are invalid. +Post Tapscript upgrade, this would have to consider other nodes. +This does NOT recursively check the miniscript fragments.

+

pub fn check_local_consensus_validity<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Consensus rules at the Miniscript satisfaction time. +It is possible that some paths of miniscript may exceed resource limits +and our current satisfier and lifting analysis would not work correctly. +For example, satisfaction path(Legacy/Segwitv0) may require more than 201 opcodes.

+

pub fn check_local_policy_validity<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Policy rules at the Miniscript satisfaction time. +It is possible that some paths of miniscript may exceed resource limits +and our current satisfier and lifting analysis would not work correctly. +For example, satisfaction path in Legacy context scriptSig more +than 1650 bytes

+

pub fn check_global_validity<Pk, Ctx>(
    ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check the consensus + policy(if not disabled) rules that are not based +satisfaction

+

pub fn check_local_validity<Pk, Ctx>(
    ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check the consensus + policy(if not disabled) rules including the +ones for satisfaction

+

pub fn top_level_type_check<Pk, Ctx>(
    ms: &Miniscript<Pk, Ctx>
) -> Result<(), Error> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check whether the top-level is type B

+

pub fn other_top_level_checks<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), Error> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Other top level checks that are context specific

+

pub fn top_level_checks<Pk, Ctx>(ms: &Miniscript<Pk, Ctx>) -> Result<(), Error> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check top level consensus rules.

+
Loading content...

Implementations on Foreign Types

impl ScriptContext for Bare

Loading content...

Implementors

impl ScriptContext for Legacy

impl ScriptContext for Segwitv0

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ToPublicKey.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ToPublicKey.html new file mode 100644 index 0000000000..1c2cfde4f4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ToPublicKey.html @@ -0,0 +1,25 @@ +bdk::descriptor::ToPublicKey - Rust + +

[]Trait bdk::descriptor::ToPublicKey

pub trait ToPublicKey<ToPkCtx>: MiniscriptKey where
    ToPkCtx: Copy
{ + pub fn to_public_key(&self, to_pk_ctx: ToPkCtx) -> PublicKey; +
pub fn hash_to_hash160(hash: &Self::Hash, to_pk_ctx: ToPkCtx) -> Hash; + + pub fn serialized_len(&self, to_pk_ctx: ToPkCtx) -> usize { ... } +}

Trait describing public key types which can be converted to bitcoin pubkeys +The trait relies on Copy trait because in all practical usecases ToPkCtx +should contain references to objects which should be cheap to Copy.

+

Required methods

pub fn to_public_key(&self, to_pk_ctx: ToPkCtx) -> PublicKey

Converts an object to a public key +C represents additional context information that maybe +required for deriving a bitcoin::PublicKey from MiniscriptKey +You may require secp context for crypto operations +or additional information for substituting the wildcard in +extended pubkeys

+

pub fn hash_to_hash160(hash: &Self::Hash, to_pk_ctx: ToPkCtx) -> Hash

Converts a hashed version of the public key to a hash160 hash.

+

This method must be consistent with to_public_key, in the sense +that calling MiniscriptKey::to_pubkeyhash followed by this function +should give the same result as calling to_public_key and hashing +the result directly.

+
Loading content...

Provided methods

pub fn serialized_len(&self, to_pk_ctx: ToPkCtx) -> usize

Computes the size of a public key when serialized in a script, +including the length bytes

+
Loading content...

Implementations on Foreign Types

impl ToPublicKey<NullCtx> for DummyKey

impl ToPublicKey<NullCtx> for PublicKey

Loading content...

Implementors

impl<'secp, C> ToPublicKey<DescriptorPublicKeyCtx<'secp, C>> for DescriptorPublicKey where
    C: Verification, 

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ToWalletDescriptor.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ToWalletDescriptor.html new file mode 100644 index 0000000000..e748fbf297 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/trait.ToWalletDescriptor.html @@ -0,0 +1,10 @@ +bdk::descriptor::ToWalletDescriptor - Rust + +

[][src]Trait bdk::descriptor::ToWalletDescriptor

pub trait ToWalletDescriptor {
+    pub fn to_wallet_descriptor(
        self,
        network: Network
    ) -> Result<(ExtendedDescriptor, KeyMap), KeyError>; +}

Trait for types which can be converted into an ExtendedDescriptor and a KeyMap usable by a wallet in a specific [Network]

+

Required methods

pub fn to_wallet_descriptor(
    self,
    network: Network
) -> Result<(ExtendedDescriptor, KeyMap), KeyError>
[src]

Convert to wallet descriptor

+
Loading content...

Implementations on Foreign Types

impl<'_> ToWalletDescriptor for &'_ str[src]

impl<'_> ToWalletDescriptor for &'_ String[src]

impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap)[src]

Loading content...

Implementors

impl ToWalletDescriptor for DescriptorTemplateOut[src]

impl ToWalletDescriptor for ExtendedDescriptor[src]

impl<T: DescriptorTemplate> ToWalletDescriptor for T[src]

Turns a DescriptorTemplate into a valid wallet descriptor by calling its +build method

+
Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/type.ExtendedDescriptor.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/type.ExtendedDescriptor.html new file mode 100644 index 0000000000..846b405272 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/type.ExtendedDescriptor.html @@ -0,0 +1,6 @@ +bdk::descriptor::ExtendedDescriptor - Rust + +

[][src]Type Definition bdk::descriptor::ExtendedDescriptor

type ExtendedDescriptor = Descriptor<DescriptorPublicKey>;

Alias for a Descriptor that can contain extended keys using DescriptorPublicKey

+

Trait Implementations

impl ToWalletDescriptor for ExtendedDescriptor[src]

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/type.HDKeyPaths.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/type.HDKeyPaths.html new file mode 100644 index 0000000000..25850ae841 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/type.HDKeyPaths.html @@ -0,0 +1,6 @@ +bdk::descriptor::HDKeyPaths - Rust + +

[][src]Type Definition bdk::descriptor::HDKeyPaths

type HDKeyPaths = BTreeMap<PublicKey, KeySource>;

Alias for the type of maps that represent derivation paths in a psbt::Input or +psbt::Output

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/type.KeyMap.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/type.KeyMap.html new file mode 100644 index 0000000000..bfe0522027 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/descriptor/type.KeyMap.html @@ -0,0 +1,9 @@ +bdk::descriptor::KeyMap - Rust + +

[]Type Definition bdk::descriptor::KeyMap

type KeyMap = HashMap<DescriptorPublicKey, DescriptorSecretKey, RandomState>;

Alias type for a map of public key to secret key

+

This map is returned whenever a descriptor that contains secrets is parsed using +Descriptor::parse_descriptor, since the descriptor will always only contain +public keys. This map allows looking up the corresponding secret key given a +public key from the descriptor.

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.Error.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.Error.html new file mode 100644 index 0000000000..a6f2f695e6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.Error.html @@ -0,0 +1,148 @@ +bdk::Error - Rust + +

[][src]Enum bdk::Error

pub enum Error {
+    InvalidU32Bytes(Vec<u8>),
+    Generic(String),
+    ScriptDoesntHaveAddressForm,
+    SingleRecipientMultipleOutputs,
+    SingleRecipientNoInputs,
+    NoRecipients,
+    NoUtxosSelected,
+    OutputBelowDustLimit(usize),
+    InsufficientFunds,
+    BnBTotalTriesExceeded,
+    BnBNoExactMatch,
+    UnknownUTXO,
+    TransactionNotFound,
+    TransactionConfirmed,
+    IrreplaceableTransaction,
+    FeeRateTooLow {
+        required: FeeRate,
+    },
+    FeeTooLow {
+        required: u64,
+    },
+    MissingKeyOrigin(String),
+    Key(KeyError),
+    ChecksumMismatch,
+    SpendingPolicyRequired(KeychainKind),
+    InvalidPolicyPathError(PolicyError),
+    Signer(SignerError),
+    OfflineClient,
+    InvalidProgressValue(f32),
+    ProgressUpdateError,
+    InvalidOutpoint(OutPoint),
+    Descriptor(Error),
+    AddressValidator(AddressValidatorError),
+    Encode(Error),
+    Miniscript(Error),
+    BIP32(Error),
+    Secp256k1(Error),
+    JSON(Error),
+    Hex(Error),
+    PSBT(Error),
+    Electrum(Error),
+    Esplora(EsploraError),
+    CompactFilters(CompactFiltersError),
+    Sled(Error),
+}

Errors that can be thrown by the Wallet

+

+ Variants

+
InvalidU32Bytes(Vec<u8>)

Wrong number of bytes found when trying to convert to u32

+
Generic(String)

Generic error

+
ScriptDoesntHaveAddressForm

This error is thrown when trying to convert Bare and Public key script to address

+
SingleRecipientMultipleOutputs

Found multiple outputs when single_recipient option has been specified

+
SingleRecipientNoInputs

single_recipient option is selected but neither drain_wallet nor manually_selected_only are

+
NoRecipients

Cannot build a tx without recipients

+
NoUtxosSelected

manually_selected_only option is selected but no utxo has been passed

+
OutputBelowDustLimit(usize)

Output created is under the dust limit, 546 satoshis

+
InsufficientFunds

Wallet's UTXO set is not enough to cover recipient's requested plus fee

+
BnBTotalTriesExceeded

Branch and bound coin selection possible attempts with sufficiently big UTXO set could grow +exponentially, thus a limit is set, and when hit, this error is thrown

+
BnBNoExactMatch

Branch and bound coin selection tries to avoid needing a change by finding the right inputs for +the desired outputs plus fee, if there is not such combination this error is thrown

+
UnknownUTXO

Happens when trying to spend an UTXO that is not in the internal database

+
TransactionNotFound

Thrown when a tx is not found in the internal database

+
TransactionConfirmed

Happens when trying to bump a transaction that is already confirmed

+
IrreplaceableTransaction

Trying to replace a tx that has a sequence >= 0xFFFFFFFE

+
FeeRateTooLow

When bumping a tx the fee rate requested is lower than required

+

Fields of FeeRateTooLow

required: FeeRate

Required fee rate (satoshi/vbyte)

+
FeeTooLow

When bumping a tx the absolute fee requested is lower than replaced tx absolute fee

+

Fields of FeeTooLow

required: u64

Required fee absolute value (satoshi)

+
MissingKeyOrigin(String)

In order to use the TxBuilder::add_global_xpubs option every extended +key in the descriptor must either be a master key itself (having depth = 0) or have an +explicit origin provided

+

Error while working with keys

+
ChecksumMismatch

Descriptor checksum mismatch

+
SpendingPolicyRequired(KeychainKind)

Spending policy is not compatible with this KeychainKind

+
InvalidPolicyPathError(PolicyError)

Error while extracting and manipulating policies

+
Signer(SignerError)

Signing error

+
OfflineClient

Thrown when trying to call a method that requires a network connection, Wallet::sync and Wallet::broadcast +This error is thrown when creating the Client for the first time, while recovery attempts are tried +during the sync

+
InvalidProgressValue(f32)

Progress value must be between 0.0 (included) and 100.0 (included)

+
ProgressUpdateError

Progress update error (maybe the channel has been closed)

+
InvalidOutpoint(OutPoint)

Requested outpoint doesn't exist in the tx (vout greater than available outputs)

+
Descriptor(Error)

Error related to the parsing and usage of descriptors

+
AddressValidator(AddressValidatorError)

Error that can be returned to fail the validation of an address

+
Encode(Error)

Encoding error

+
Miniscript(Error)

Miniscript error

+
BIP32(Error)

BIP32 error

+
Secp256k1(Error)

An ECDSA error

+
JSON(Error)

Error serializing or deserializing JSON data

+
Hex(Error)

Hex decoding error

+
PSBT(Error)

Partially signed bitcoin transaction error

+
Electrum(Error)

Electrum client error

+
Esplora(EsploraError)

Esplora client error

+
CompactFilters(CompactFiltersError)

Compact filters client error)

+
Sled(Error)

Sled database error

+

Trait Implementations

impl Debug for Error[src]

impl Display for Error[src]

impl Error for Error[src]

impl From<AddressValidatorError> for Error[src]

impl From<CompactFiltersError> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for CompactFiltersError[src]

This is supported on crate feature compact_filters only.

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<Error> for Error[src]

impl From<EsploraError> for Error[src]

impl From<KeyError> for Error[src]

impl From<PolicyError> for Error[src]

impl From<SignerError> for Error[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.KeychainKind.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.KeychainKind.html new file mode 100644 index 0000000000..491efbac18 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.KeychainKind.html @@ -0,0 +1,59 @@ +bdk::KeychainKind - Rust + +

[][src]Enum bdk::KeychainKind

pub enum KeychainKind {
+    External,
+    Internal,
+}

Types of keychains

+

+ Variants

+
External

External

+
Internal

Internal, usually used for change outputs

+

Implementations

impl KeychainKind[src]

pub fn as_byte(&self) -> u8[src]

Return KeychainKind as a byte

+

Trait Implementations

impl AsRef<[u8]> for KeychainKind[src]

impl Clone for KeychainKind[src]

impl Copy for KeychainKind[src]

impl Debug for KeychainKind[src]

impl<'de> Deserialize<'de> for KeychainKind[src]

impl Eq for KeychainKind[src]

impl Hash for KeychainKind[src]

impl PartialEq<KeychainKind> for KeychainKind[src]

impl Serialize for KeychainKind[src]

impl StructuralEq for KeychainKind[src]

impl StructuralPartialEq for KeychainKind[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Base32Len for T where
    T: AsRef<[u8]>, 

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<'f, T> CheckBase32<Vec<u5, Global>> for T where
    T: AsRef<[u8]>, 

type Err = Error

Error type if conversion fails

+

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToBase32 for T where
    T: AsRef<[u8]>, 

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.ScriptType.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.ScriptType.html new file mode 100644 index 0000000000..fac96f212c --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/enum.ScriptType.html @@ -0,0 +1,58 @@ +bdk::ScriptType - Rust + +

[][src]Enum bdk::ScriptType

pub enum ScriptType {
+    External,
+    Internal,
+}

Types of script

+

+ Variants

+
External

External

+
Internal

Internal, usually used for change outputs

+

Implementations

impl ScriptType[src]

pub fn as_byte(&self) -> u8[src]

Trait Implementations

impl AsRef<[u8]> for ScriptType[src]

impl Clone for ScriptType[src]

impl Copy for ScriptType[src]

impl Debug for ScriptType[src]

impl<'de> Deserialize<'de> for ScriptType[src]

impl Eq for ScriptType[src]

impl Hash for ScriptType[src]

impl PartialEq<ScriptType> for ScriptType[src]

impl Serialize for ScriptType[src]

impl StructuralEq for ScriptType[src]

impl StructuralPartialEq for ScriptType[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Base32Len for T where
    T: AsRef<[u8]>, 

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<'f, T> CheckBase32<Vec<u5, Global>> for T where
    T: AsRef<[u8]>, 

type Err = Error

Error type if conversion fails

+

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToBase32 for T where
    T: AsRef<[u8]>, 

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/error/enum.Error.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/error/enum.Error.html new file mode 100644 index 0000000000..113a951037 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/error/enum.Error.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../bdk/enum.Error.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/index.html new file mode 100644 index 0000000000..8323289c69 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/index.html @@ -0,0 +1,167 @@ +bdk - Rust + +

[][src]Crate bdk

A modern, lightweight, descriptor-based wallet library written in Rust.

+

About

+

The BDK library aims to be the core building block for Bitcoin wallets of any kind.

+
    +
  • It uses Miniscript to support descriptors with generalized conditions. This exact same library can be used to build +single-sig wallets, multisigs, timelocked contracts and more.
  • +
  • It supports multiple blockchain backends and databases, allowing developers to choose exactly what's right for their projects.
  • +
  • It is built to be cross-platform: the core logic works on desktop, mobile, and even WebAssembly.
  • +
  • It is very easy to extend: developers can implement customized logic for blockchain backends, databases, signers, coin selection, and more, without having to fork and modify this library.
  • +
+

A Tour of BDK

+

BDK consists of a number of modules that provide a range of functionality +essential for implementing descriptor based Bitcoin wallet applications in Rust. In this +section, we will take a brief tour of BDK, summarizing the major APIs and +their uses.

+

The easiest way to get started is to add bdk to your dependencies with the default features. +The default features include a simple key-value database (sled) to cache +blockchain data and an electrum blockchain client to +interact with the bitcoin P2P network.

+
bdk = "0.2.0"
+
+

Sync the balance of a descriptor

Example

+
ⓘThis example is not tested
+use bdk::Wallet;
+use bdk::database::MemoryDatabase;
+use bdk::blockchain::{noop_progress, ElectrumBlockchain};
+
+use bdk::electrum_client::Client;
+
+fn main() -> Result<(), bdk::Error> {
+    let client = Client::new("ssl://electrum.blockstream.info:60002")?;
+    let wallet = Wallet::new(
+        "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
+        Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
+        bitcoin::Network::Testnet,
+        MemoryDatabase::default(),
+        ElectrumBlockchain::from(client)
+    )?;
+
+    wallet.sync(noop_progress(), None)?;
+
+    println!("Descriptor balance: {} SAT", wallet.get_balance()?);
+
+    Ok(())
+}
+

Generate a few addresses

Example

+
+use bdk::{Wallet, OfflineWallet};
+use bdk::database::MemoryDatabase;
+
+fn main() -> Result<(), bdk::Error> {
+    let wallet: OfflineWallet<_> = Wallet::new_offline(
+        "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
+        Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
+        bitcoin::Network::Testnet,
+        MemoryDatabase::default(),
+    )?;
+
+    println!("Address #0: {}", wallet.get_new_address()?);
+    println!("Address #1: {}", wallet.get_new_address()?);
+    println!("Address #2: {}", wallet.get_new_address()?);
+
+    Ok(())
+}
+

Create a transaction

Example

+
ⓘThis example is not tested
+use base64::decode;
+use bdk::{FeeRate, TxBuilder, Wallet};
+use bdk::database::MemoryDatabase;
+use bdk::blockchain::{noop_progress, ElectrumBlockchain};
+
+use bdk::electrum_client::Client;
+
+use bitcoin::consensus::serialize;
+
+fn main() -> Result<(), bdk::Error> {
+    let client = Client::new("ssl://electrum.blockstream.info:60002")?;
+    let wallet = Wallet::new(
+        "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
+        Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
+        bitcoin::Network::Testnet,
+        MemoryDatabase::default(),
+        ElectrumBlockchain::from(client)
+    )?;
+
+    wallet.sync(noop_progress(), None)?;
+
+    let send_to = wallet.get_new_address()?;
+    let (psbt, details) = wallet.create_tx(
+        TxBuilder::with_recipients(vec![(send_to.script_pubkey(), 50_000)])
+            .enable_rbf()
+            .do_not_spend_change()
+            .fee_rate(FeeRate::from_sat_per_vb(5.0))
+    )?;
+
+    println!("Transaction details: {:#?}", details);
+    println!("Unsigned PSBT: {}", base64::encode(&serialize(&psbt)));
+
+    Ok(())
+}
+

Sign a transaction

Example

+
ⓘThis example is not tested
+use base64::decode;
+use bdk::{Wallet, OfflineWallet};
+use bdk::database::MemoryDatabase;
+
+use bitcoin::consensus::deserialize;
+
+fn main() -> Result<(), bdk::Error> {
+    let wallet: OfflineWallet<_> = Wallet::new_offline(
+        "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
+        Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
+        bitcoin::Network::Testnet,
+        MemoryDatabase::default(),
+    )?;
+
+    let psbt = "...";
+    let psbt = deserialize(&base64::decode(psbt).unwrap())?;
+
+    let (signed_psbt, finalized) = wallet.sign(psbt, None)?;
+
+    Ok(())
+}
+

Feature flags

+

BDK uses a set of feature flags +to reduce the amount of compiled code by allowing projects to only enable the features they need. +By default, BDK enables two internal features, key-value-db and electrum.

+

If you are new to BDK we recommended that you use the default features which will enable +basic descriptor wallet functionality. More advanced users can disable the default features +(--no-default-features) and build the BDK library with only the features you need. +Below is a list of the available feature flags and the additional functionality they provide.

+
    +
  • all-keys: all features for working with bitcoin keys
  • +
  • async-interface: async functions in bdk traits
  • +
  • cli-utils: utilities for creating a command line interface wallet
  • +
  • keys-bip39: BIP-39 mnemonic codes for generating deterministic keys
  • +
+

Internal features

+

These features do not expose any new API, but influence internal implementation aspects of +BDK.

+
    +
  • compact_filters: compact_filters client protocol for interacting with the bitcoin P2P network
  • +
  • electrum: electrum client protocol for interacting with electrum servers
  • +
  • esplora: esplora client protocol for interacting with blockstream electrs servers
  • +
  • key-value-db: key value database based on sled for caching blockchain data
  • +
+

Re-exports

+
pub extern crate bitcoin;
pub extern crate miniscript;
pub extern crate electrum_client;
pub extern crate reqwest;
pub extern crate sled;
pub use descriptor::template;
pub use descriptor::HDKeyPaths;
pub use wallet::address_validator;
pub use wallet::signer;
pub use wallet::tx_builder::TxBuilder;
pub use wallet::OfflineWallet;
pub use wallet::Wallet;

Modules

+
blockchain

Blockchain backends

+
database

Database types

+
descriptor

Descriptors

+
keys

Key formats

+
wallet

Wallet

+

Macros

+
descriptor

Macro to write full descriptors with code

+
fragment

Macro to write descriptor fragments with code

+

Structs

+
FeeRate

Fee rate

+
TransactionDetails

A wallet transaction

+
UTXO

A wallet unspent output

+

Enums

+
Error

Errors that can be thrown by the Wallet

+
KeychainKind

Types of keychains

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/bip39/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/bip39/index.html new file mode 100644 index 0000000000..7beb4dcbbd --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/bip39/index.html @@ -0,0 +1,7 @@ +bdk::keys::bip39 - Rust + +

[][src]Module bdk::keys::bip39

This is supported on crate feature keys-bip39 only.

BIP-0039

+

Type Definitions

+
MnemonicWithPassphrase

Type for a BIP39 mnemonic with an optional passphrase

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/bip39/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/bip39/sidebar-items.js new file mode 100644 index 0000000000..e3212ff208 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/bip39/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"type":[["MnemonicWithPassphrase","Type for a BIP39 mnemonic with an optional passphrase"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/bip39/type.MnemonicWithPassphrase.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/bip39/type.MnemonicWithPassphrase.html new file mode 100644 index 0000000000..64af95a2d4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/bip39/type.MnemonicWithPassphrase.html @@ -0,0 +1,6 @@ +bdk::keys::bip39::MnemonicWithPassphrase - Rust + +

[][src]Type Definition bdk::keys::bip39::MnemonicWithPassphrase

type MnemonicWithPassphrase = (Mnemonic, Option<String>);
This is supported on crate feature keys-bip39 only.

Type for a BIP39 mnemonic with an optional passphrase

+

Trait Implementations

impl<Ctx: ScriptContext> DerivableKey<Ctx> for MnemonicWithPassphrase[src]

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.DescriptorKey.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.DescriptorKey.html new file mode 100644 index 0000000000..8e38293842 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.DescriptorKey.html @@ -0,0 +1,37 @@ +bdk::keys::DescriptorKey - Rust + +

[][src]Enum bdk::keys::DescriptorKey

pub enum DescriptorKey<Ctx: ScriptContext> {
+    // some variants omitted
+}

Container for public or secret keys

+

Implementations

impl<Ctx: ScriptContext> DescriptorKey<Ctx>[src]

pub fn from_public(public: DescriptorPublicKey, networks: ValidNetworks) -> Self[src]

Create an instance given a public key and a set of valid networks

+

pub fn from_secret(secret: DescriptorSecretKey, networks: ValidNetworks) -> Self[src]

Create an instance given a secret key and a set of valid networks

+

pub fn override_valid_networks(self, networks: ValidNetworks) -> Self[src]

Override the computed set of valid networks

+

Trait Implementations

impl<Ctx: Debug + ScriptContext> Debug for DescriptorKey<Ctx>[src]

impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorKey<Ctx>[src]

The "identity" conversion is used internally by some bdk::fragments

+

Auto Trait Implementations

impl<Ctx> RefUnwindSafe for DescriptorKey<Ctx> where
    Ctx: RefUnwindSafe
[src]

impl<Ctx> Send for DescriptorKey<Ctx> where
    Ctx: Send
[src]

impl<Ctx> Sync for DescriptorKey<Ctx> where
    Ctx: Sync
[src]

impl<Ctx> Unpin for DescriptorKey<Ctx> where
    Ctx: Unpin
[src]

impl<Ctx> UnwindSafe for DescriptorKey<Ctx> where
    Ctx: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.DescriptorPublicKey.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.DescriptorPublicKey.html new file mode 100644 index 0000000000..38c6c9e90c --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.DescriptorPublicKey.html @@ -0,0 +1,81 @@ +bdk::keys::DescriptorPublicKey - Rust + +

[]Enum bdk::keys::DescriptorPublicKey

pub enum DescriptorPublicKey {
+    SinglePub(DescriptorSinglePub),
+    XPub(DescriptorXKey<ExtendedPubKey>),
+}

The MiniscriptKey corresponding to Descriptors. This can +either be Single public key or a Xpub

+

+ Variants

+

Single Public Key

+
XPub(DescriptorXKey<ExtendedPubKey>)

Xpub

+

Implementations

impl DescriptorPublicKey

pub fn derive(self, child_number: ChildNumber) -> DescriptorPublicKey

Derives the specified child key if self is a wildcard xpub. Otherwise returns self.

+

Panics if given a hardened child number

+

Trait Implementations

impl Clone for DescriptorPublicKey

impl Debug for DescriptorPublicKey

impl Display for DescriptorPublicKey

impl Eq for DescriptorPublicKey

impl FromStr for DescriptorPublicKey

type Err = DescriptorKeyParseError

The associated error which can be returned from parsing.

+

impl Hash for DescriptorPublicKey

impl MiniscriptKey for DescriptorPublicKey

type Hash = DescriptorPublicKey

The associated Hash type with the publicKey

+

impl Ord for DescriptorPublicKey

impl PartialEq<DescriptorPublicKey> for DescriptorPublicKey

impl PartialOrd<DescriptorPublicKey> for DescriptorPublicKey

impl StructuralEq for DescriptorPublicKey

impl StructuralPartialEq for DescriptorPublicKey

impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorPublicKey[src]

impl<'secp, C> ToPublicKey<DescriptorPublicKeyCtx<'secp, C>> for DescriptorPublicKey where
    C: Verification, 

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.DescriptorSecretKey.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.DescriptorSecretKey.html new file mode 100644 index 0000000000..77ee6bed66 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.DescriptorSecretKey.html @@ -0,0 +1,48 @@ +bdk::keys::DescriptorSecretKey - Rust + +

[]Enum bdk::keys::DescriptorSecretKey

pub enum DescriptorSecretKey {
+    SinglePriv(DescriptorSinglePriv),
+    XPrv(DescriptorXKey<ExtendedPrivKey>),
+}

A Secret Key that can be either a single key or an Xprv

+

+ Variants

+

Single Secret Key

+
XPrv(DescriptorXKey<ExtendedPrivKey>)

Xprv

+

Implementations

impl DescriptorSecretKey

pub fn as_public<C>(
    &self,
    secp: &Secp256k1<C>
) -> Result<DescriptorPublicKey, DescriptorKeyParseError> where
    C: Signing, 

Return the public version of this key, by applying either +DescriptorSinglePriv::as_public or [DescriptorXKey<bip32::ExtendedPrivKey>::as_public] +depending on the type of key.

+

If the key is an "XPrv", the hardened derivation steps will be applied before converting it +to a public key. See the documentation of [DescriptorXKey<bip32::ExtendedPrivKey>::as_public] +for more details.

+

Trait Implementations

impl Debug for DescriptorSecretKey

impl Display for DescriptorSecretKey

impl FromStr for DescriptorSecretKey

type Err = DescriptorKeyParseError

The associated error which can be returned from parsing.

+

impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorSecretKey[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.KeyError.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.KeyError.html new file mode 100644 index 0000000000..ef3178668e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.KeyError.html @@ -0,0 +1,55 @@ +bdk::keys::KeyError - Rust + +

[][src]Enum bdk::keys::KeyError

pub enum KeyError {
+    InvalidScriptContext,
+    InvalidNetwork,
+    InvalidChecksum,
+    Message(String),
+    BIP32(Error),
+    Miniscript(Error),
+}

Errors thrown while working with keys

+

+ Variants

+
InvalidScriptContext

The key cannot exist in the given script context

+
InvalidNetwork

The key is not valid for the given network

+
InvalidChecksum

The key has an invalid checksum

+
Message(String)

Custom error message

+
BIP32(Error)

BIP32 error

+
Miniscript(Error)

Miniscript error

+

Trait Implementations

impl Debug for KeyError[src]

impl Display for KeyError[src]

impl Error for KeyError[src]

impl From<Error> for KeyError[src]

impl From<Error> for KeyError[src]

impl From<KeyError> for Error[src]

impl From<KeyError> for Error[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.ScriptContextEnum.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.ScriptContextEnum.html new file mode 100644 index 0000000000..9e93778129 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/enum.ScriptContextEnum.html @@ -0,0 +1,49 @@ +bdk::keys::ScriptContextEnum - Rust + +

[][src]Enum bdk::keys::ScriptContextEnum

pub enum ScriptContextEnum {
+    Legacy,
+    Segwitv0,
+}

Enum representation of the known valid ScriptContexts

+

+ Variants

+
Legacy

Legacy scripts

+
Segwitv0

Segwitv0 scripts

+

Implementations

impl ScriptContextEnum[src]

pub fn is_legacy(&self) -> bool[src]

Returns whether the script context is ScriptContextEnum::Legacy

+

pub fn is_segwit_v0(&self) -> bool[src]

Returns whether the script context is ScriptContextEnum::Segwitv0

+

Trait Implementations

impl Clone for ScriptContextEnum[src]

impl Copy for ScriptContextEnum[src]

impl Debug for ScriptContextEnum[src]

impl Eq for ScriptContextEnum[src]

impl PartialEq<ScriptContextEnum> for ScriptContextEnum[src]

impl StructuralEq for ScriptContextEnum[src]

impl StructuralPartialEq for ScriptContextEnum[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.any_network.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.any_network.html new file mode 100644 index 0000000000..76ff654177 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.any_network.html @@ -0,0 +1,5 @@ +bdk::keys::any_network - Rust + +

[][src]Function bdk::keys::any_network

pub fn any_network() -> ValidNetworks

Create a set containing mainnet, testnet and regtest

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.mainnet_network.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.mainnet_network.html new file mode 100644 index 0000000000..d0807b41c8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.mainnet_network.html @@ -0,0 +1,5 @@ +bdk::keys::mainnet_network - Rust + +

[][src]Function bdk::keys::mainnet_network

pub fn mainnet_network() -> ValidNetworks

Create a set only containing mainnet

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.merge_networks.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.merge_networks.html new file mode 100644 index 0000000000..86a3528a58 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.merge_networks.html @@ -0,0 +1,5 @@ +bdk::keys::merge_networks - Rust + +

[][src]Function bdk::keys::merge_networks

pub fn merge_networks(a: &ValidNetworks, b: &ValidNetworks) -> ValidNetworks

Compute the intersection of two sets

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.test_networks.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.test_networks.html new file mode 100644 index 0000000000..4071c41fd5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/fn.test_networks.html @@ -0,0 +1,5 @@ +bdk::keys::test_networks - Rust + +

[][src]Function bdk::keys::test_networks

pub fn test_networks() -> ValidNetworks

Create a set containing testnet and regtest

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/index.html new file mode 100644 index 0000000000..7442d78e48 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/index.html @@ -0,0 +1,37 @@ +bdk::keys - Rust + +

[][src]Module bdk::keys

Key formats

+

Modules

+
bip39keys-bip39

BIP-0039

+

Structs

+
DescriptorSinglePriv

A Single Descriptor Secret Key with optional origin information

+
DescriptorSinglePub

A Single Descriptor Key with optional origin information

+
GeneratedKey

Output of a GeneratableKey key generation

+
PrivateKeyGenerateOptions

Options for generating a [PrivateKey]

+
SortedMultiVec

Contents of a "sortedmulti" descriptor

+

Enums

+
DescriptorKey

Container for public or secret keys

+
DescriptorPublicKey

The MiniscriptKey corresponding to Descriptors. This can +either be Single public key or a Xpub

+
DescriptorSecretKey

A Secret Key that can be either a single key or an Xprv

+
KeyError

Errors thrown while working with keys

+
ScriptContextEnum

Enum representation of the known valid ScriptContexts

+

Traits

+
DerivableKey

Trait for keys that can be derived.

+
ExtScriptContext

Trait that adds extra useful methods to ScriptContexts

+
GeneratableDefaultOptions

Trait that allows generating a key with the default options

+
GeneratableKey

Trait for keys that can be generated

+
ScriptContext

The ScriptContext for Miniscript. Additional type information associated with +miniscript that is used for carrying out checks that dependent on the +context under which the script is used. +For example, disallowing uncompressed keys in Segwit context

+
ToDescriptorKey

Trait for objects that can be turned into a public or secret DescriptorKey

+

Functions

+
any_network

Create a set containing mainnet, testnet and regtest

+
mainnet_network

Create a set only containing mainnet

+
merge_networks

Compute the intersection of two sets

+
test_networks

Create a set containing testnet and regtest

+

Type Definitions

+
ValidNetworks

Set of valid networks for a key

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/sidebar-items.js new file mode 100644 index 0000000000..9ba16e1f5e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["DescriptorKey","Container for public or secret keys"],["DescriptorPublicKey","The MiniscriptKey corresponding to Descriptors. This can either be Single public key or a Xpub"],["DescriptorSecretKey","A Secret Key that can be either a single key or an Xprv"],["KeyError","Errors thrown while working with `keys`"],["ScriptContextEnum","Enum representation of the known valid [`ScriptContext`]s"]],"fn":[["any_network","Create a set containing mainnet, testnet and regtest"],["mainnet_network","Create a set only containing mainnet"],["merge_networks","Compute the intersection of two sets"],["test_networks","Create a set containing testnet and regtest"]],"mod":[["bip39","BIP-0039"]],"struct":[["DescriptorSinglePriv","A Single Descriptor Secret Key with optional origin information"],["DescriptorSinglePub","A Single Descriptor Key with optional origin information"],["GeneratedKey","Output of a [`GeneratableKey`] key generation"],["PrivateKeyGenerateOptions","Options for generating a [`PrivateKey`]"],["SortedMultiVec","Contents of a \"sortedmulti\" descriptor"]],"trait":[["DerivableKey","Trait for keys that can be derived."],["ExtScriptContext","Trait that adds extra useful methods to [`ScriptContext`]s"],["GeneratableDefaultOptions","Trait that allows generating a key with the default options"],["GeneratableKey","Trait for keys that can be generated"],["ScriptContext","The ScriptContext for Miniscript. Additional type information associated with miniscript that is used for carrying out checks that dependent on the context under which the script is used. For example, disallowing uncompressed keys in Segwit context"],["ToDescriptorKey","Trait for objects that can be turned into a public or secret [`DescriptorKey`]"]],"type":[["ValidNetworks","Set of valid networks for a key"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.DescriptorSinglePriv.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.DescriptorSinglePriv.html new file mode 100644 index 0000000000..13fd899c3a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.DescriptorSinglePriv.html @@ -0,0 +1,36 @@ +bdk::keys::DescriptorSinglePriv - Rust + +

[]Struct bdk::keys::DescriptorSinglePriv

pub struct DescriptorSinglePriv {
+    pub origin: Option<(Fingerprint, DerivationPath)>,
+    pub key: PrivateKey,
+}

A Single Descriptor Secret Key with optional origin information

+

+ Fields

origin: Option<(Fingerprint, DerivationPath)>

Origin information

+
key: PrivateKey

The key

+

Trait Implementations

impl Debug for DescriptorSinglePriv

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.DescriptorSinglePub.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.DescriptorSinglePub.html new file mode 100644 index 0000000000..6a9b79d215 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.DescriptorSinglePub.html @@ -0,0 +1,59 @@ +bdk::keys::DescriptorSinglePub - Rust + +

[]Struct bdk::keys::DescriptorSinglePub

pub struct DescriptorSinglePub {
+    pub origin: Option<(Fingerprint, DerivationPath)>,
+    pub key: PublicKey,
+}

A Single Descriptor Key with optional origin information

+

+ Fields

origin: Option<(Fingerprint, DerivationPath)>

Origin information

+
key: PublicKey

The key

+

Trait Implementations

impl Clone for DescriptorSinglePub

impl Debug for DescriptorSinglePub

impl Eq for DescriptorSinglePub

impl Hash for DescriptorSinglePub

impl Ord for DescriptorSinglePub

impl PartialEq<DescriptorSinglePub> for DescriptorSinglePub

impl PartialOrd<DescriptorSinglePub> for DescriptorSinglePub

impl StructuralEq for DescriptorSinglePub

impl StructuralPartialEq for DescriptorSinglePub

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.GeneratedKey.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.GeneratedKey.html new file mode 100644 index 0000000000..d92eab815c --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.GeneratedKey.html @@ -0,0 +1,34 @@ +bdk::keys::GeneratedKey - Rust + +

[][src]Struct bdk::keys::GeneratedKey

pub struct GeneratedKey<K, Ctx: ScriptContext> { /* fields omitted */ }

Output of a GeneratableKey key generation

+

Implementations

impl<K, Ctx: ScriptContext> GeneratedKey<K, Ctx>[src]

pub fn into_key(self) -> K[src]

Consumes self and returns the key

+

Trait Implementations

impl<K, Ctx: ScriptContext> Deref for GeneratedKey<K, Ctx>[src]

type Target = K

The resulting type after dereferencing.

+

impl<Ctx, K> DerivableKey<Ctx> for GeneratedKey<K, Ctx> where
    Ctx: ScriptContext,
    K: DerivableKey<Ctx>, 
[src]

impl<Ctx, K> ToDescriptorKey<Ctx> for GeneratedKey<K, Ctx> where
    Ctx: ScriptContext,
    K: ToDescriptorKey<Ctx>, 
[src]

Auto Trait Implementations

impl<K, Ctx> RefUnwindSafe for GeneratedKey<K, Ctx> where
    Ctx: RefUnwindSafe,
    K: RefUnwindSafe
[src]

impl<K, Ctx> Send for GeneratedKey<K, Ctx> where
    Ctx: Send,
    K: Send
[src]

impl<K, Ctx> Sync for GeneratedKey<K, Ctx> where
    Ctx: Sync,
    K: Sync
[src]

impl<K, Ctx> Unpin for GeneratedKey<K, Ctx> where
    Ctx: Unpin,
    K: Unpin
[src]

impl<K, Ctx> UnwindSafe for GeneratedKey<K, Ctx> where
    Ctx: UnwindSafe,
    K: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.PrivateKeyGenerateOptions.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.PrivateKeyGenerateOptions.html new file mode 100644 index 0000000000..af5794738a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.PrivateKeyGenerateOptions.html @@ -0,0 +1,42 @@ +bdk::keys::PrivateKeyGenerateOptions - Rust + +

[][src]Struct bdk::keys::PrivateKeyGenerateOptions

pub struct PrivateKeyGenerateOptions {
+    pub compressed: bool,
+}

Options for generating a [PrivateKey]

+

Defaults to creating compressed keys, which save on-chain bytes and fees

+

+ Fields

compressed: bool

Whether the generated key should be "compressed" or not

+

Trait Implementations

impl Clone for PrivateKeyGenerateOptions[src]

impl Copy for PrivateKeyGenerateOptions[src]

impl Debug for PrivateKeyGenerateOptions[src]

impl Default for PrivateKeyGenerateOptions[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.SortedMultiVec.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.SortedMultiVec.html new file mode 100644 index 0000000000..82ea82db66 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/struct.SortedMultiVec.html @@ -0,0 +1,96 @@ +bdk::keys::SortedMultiVec - Rust + +

[]Struct bdk::keys::SortedMultiVec

pub struct SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey
{ + pub k: usize, + pub pks: Vec<Pk, Global>, + // some fields omitted +}

Contents of a "sortedmulti" descriptor

+

+ Fields

k: usize

signatures required

+
pks: Vec<Pk, Global>

public keys inside sorted Multi

+

Implementations

impl<Pk, Ctx> SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn new(
    k: usize,
    pks: Vec<Pk, Global>
) -> Result<SortedMultiVec<Pk, Ctx>, Error>

Create a new instance of SortedMultiVec given a list of keys and the threshold

+

Internally checks all the applicable size limits and pubkey types limitations according to the current Ctx.

+

impl<Pk, Ctx> SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn translate_pk<FPk, Q, FuncError>(
    &self,
    translatefpk: &mut FPk
) -> Result<SortedMultiVec<Q, Ctx>, FuncError> where
    FPk: FnMut(&Pk) -> Result<Q, FuncError>,
    Q: MiniscriptKey

This will panic if translatefpk returns an uncompressed key when +converting to a Segwit descriptor. To prevent this panic, ensure +translatefpk returns an error in this case instead.

+

impl<Pk, Ctx> SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

pub fn sorted_node<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> Terminal<Pk, Ctx> where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Create Terminal::Multi containing sorted pubkeys

+

pub fn encode<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> Script where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Encode as a Bitcoin script

+

pub fn satisfy<ToPkCtx, S>(
    &self,
    satisfier: S,
    to_pk_ctx: ToPkCtx
) -> Result<Vec<Vec<u8, Global>, Global>, Error> where
    Pk: ToPublicKey<ToPkCtx>,
    S: Satisfier<ToPkCtx, Pk>,
    ToPkCtx: Copy

Attempt to produce a satisfying witness for the +witness script represented by the parse tree

+

pub fn script_size<ToPkCtx>(&self, to_pk_ctx: ToPkCtx) -> usize where
    Pk: ToPublicKey<ToPkCtx>,
    ToPkCtx: Copy

Size, in bytes of the script-pubkey. If this Miniscript is used outside +of segwit (e.g. in a bare or P2SH descriptor), this quantity should be +multiplied by 4 to compute the weight.

+

In general, it is not recommended to use this function directly, but +to instead call the corresponding function on a Descriptor, which +will handle the segwit/non-segwit technicalities for you.

+

pub fn max_satisfaction_witness_elements(&self) -> usize

Maximum number of witness elements used to satisfy the Miniscript +fragment, including the witness script itself. Used to estimate +the weight of the VarInt that specifies this number in a serialized +transaction.

+

This function may panic on malformed Miniscript objects which do +not correspond to semantically sane Scripts. (Such scripts should be +rejected at parse time. Any exceptions are bugs.)

+

pub fn max_satisfaction_size(&self, usize) -> usize

Maximum size, in bytes, of a satisfying witness. For Segwit outputs +one_cost should be set to 2, since the number 1 requires two +bytes to encode. For non-segwit outputs one_cost should be set to +1, since OP_1 is available in scriptSigs.

+

In general, it is not recommended to use this function directly, but +to instead call the corresponding function on a Descriptor, which +will handle the segwit/non-segwit technicalities for you.

+

All signatures are assumed to be 73 bytes in size, including the +length prefix (segwit) or push opcode (pre-segwit) and sighash +postfix.

+

This function may panic on malformed Miniscript objects which do not +correspond to semantically sane Scripts. (Such scripts should be +rejected at parse time. Any exceptions are bugs.)

+

Trait Implementations

impl<Pk, Ctx> Clone for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext + Clone,
    Pk: MiniscriptKey + Clone

impl<Pk, Ctx> Debug for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> Display for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> Eq for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext + Eq,
    Pk: MiniscriptKey + Eq

impl<Pk, Ctx> Liftable<Pk> for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> Ord for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext + Ord,
    Pk: MiniscriptKey + Ord

impl<Pk, Ctx> PartialEq<SortedMultiVec<Pk, Ctx>> for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext + PartialEq<Ctx>,
    Pk: MiniscriptKey + PartialEq<Pk>, 

impl<Pk, Ctx> PartialOrd<SortedMultiVec<Pk, Ctx>> for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext + PartialOrd<Ctx>,
    Pk: MiniscriptKey + PartialOrd<Pk>, 

impl<Pk, Ctx> StructuralEq for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

impl<Pk, Ctx> StructuralPartialEq for SortedMultiVec<Pk, Ctx> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Auto Trait Implementations

impl<Pk, Ctx> RefUnwindSafe for SortedMultiVec<Pk, Ctx> where
    Ctx: RefUnwindSafe,
    Pk: RefUnwindSafe
[src]

impl<Pk, Ctx> Send for SortedMultiVec<Pk, Ctx> where
    Ctx: Send,
    Pk: Send
[src]

impl<Pk, Ctx> Sync for SortedMultiVec<Pk, Ctx> where
    Ctx: Sync,
    Pk: Sync
[src]

impl<Pk, Ctx> Unpin for SortedMultiVec<Pk, Ctx> where
    Ctx: Unpin,
    Pk: Unpin
[src]

impl<Pk, Ctx> UnwindSafe for SortedMultiVec<Pk, Ctx> where
    Ctx: UnwindSafe,
    Pk: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.DerivableKey.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.DerivableKey.html new file mode 100644 index 0000000000..e5228642f7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.DerivableKey.html @@ -0,0 +1,15 @@ +bdk::keys::DerivableKey - Rust + +

[][src]Trait bdk::keys::DerivableKey

pub trait DerivableKey<Ctx: ScriptContext> {
+    pub fn add_metadata(
        self,
        origin: Option<KeySource>,
        derivation_path: DerivationPath
    ) -> Result<DescriptorKey<Ctx>, KeyError>; +}

Trait for keys that can be derived.

+

When extra metadata are provided, a DerivableKey can be transofrmed into a +DescriptorKey: the trait ToDescriptorKey is automatically implemented +for (DerivableKey, DerivationPath) and +(DerivableKey, KeySource, DerivationPath) tuples.

+

For key types that don't encode any indication about the path to use (like bip39), it's +generally recommended to implemented this trait instead of ToDescriptorKey. The same +rules regarding script context and valid networks apply.

+

Required methods

pub fn add_metadata(
    self,
    origin: Option<KeySource>,
    derivation_path: DerivationPath
) -> Result<DescriptorKey<Ctx>, KeyError>
[src]

Add a extra metadata, consume self and turn it into a DescriptorKey

+
Loading content...

Implementations on Foreign Types

impl<Ctx: ScriptContext> DerivableKey<Ctx> for Seed[src]

This is supported on crate feature keys-bip39 only.

impl<Ctx: ScriptContext> DerivableKey<Ctx> for Mnemonic[src]

This is supported on crate feature keys-bip39 only.

impl<Ctx: ScriptContext> DerivableKey<Ctx> for ExtendedPubKey[src]

impl<Ctx: ScriptContext> DerivableKey<Ctx> for ExtendedPrivKey[src]

Loading content...

Implementors

impl<Ctx, K> DerivableKey<Ctx> for GeneratedKey<K, Ctx> where
    Ctx: ScriptContext,
    K: DerivableKey<Ctx>, 
[src]

impl<Ctx: ScriptContext> DerivableKey<Ctx> for MnemonicWithPassphrase[src]

This is supported on crate feature keys-bip39 only.
Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.ExtScriptContext.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.ExtScriptContext.html new file mode 100644 index 0000000000..f22a12511a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.ExtScriptContext.html @@ -0,0 +1,13 @@ +bdk::keys::ExtScriptContext - Rust + +

[][src]Trait bdk::keys::ExtScriptContext

pub trait ExtScriptContext: ScriptContext {
+    pub fn as_enum() -> ScriptContextEnum;
+
+    pub fn is_legacy() -> bool { ... }
+
pub fn is_segwit_v0() -> bool { ... } +}

Trait that adds extra useful methods to ScriptContexts

+

Required methods

Loading content...

Provided methods

pub fn is_legacy() -> bool[src]

Returns whether the script context is Legacy

+

pub fn is_segwit_v0() -> bool[src]

Returns whether the script context is Segwitv0

+
Loading content...

Implementors

impl<Ctx: ScriptContext + 'static> ExtScriptContext for Ctx[src]

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.GeneratableDefaultOptions.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.GeneratableDefaultOptions.html new file mode 100644 index 0000000000..17759d7720 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.GeneratableDefaultOptions.html @@ -0,0 +1,13 @@ +bdk::keys::GeneratableDefaultOptions - Rust + +

[][src]Trait bdk::keys::GeneratableDefaultOptions

pub trait GeneratableDefaultOptions<Ctx>: GeneratableKey<Ctx> where
    Ctx: ScriptContext,
    Self::Options: Default
{ + pub fn generate_with_entropy_default(
        entropy: Self::Entropy
    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> { ... } +
pub fn generate_default() -> Result<GeneratedKey<Self, Ctx>, Self::Error> { ... } +}

Trait that allows generating a key with the default options

+

This trait is automatically implemented if the GeneratableKey::Options implements Default.

+

Provided methods

pub fn generate_with_entropy_default(
    entropy: Self::Entropy
) -> Result<GeneratedKey<Self, Ctx>, Self::Error>
[src]

Generate a key with the default options and a given entropy

+

pub fn generate_default() -> Result<GeneratedKey<Self, Ctx>, Self::Error>[src]

Generate a key with the default options and a random entropy

+
Loading content...

Implementors

impl<Ctx, K> GeneratableDefaultOptions<Ctx> for K where
    Ctx: ScriptContext,
    K: GeneratableKey<Ctx>,
    <K as GeneratableKey<Ctx>>::Options: Default
[src]

Automatic implementation of GeneratableDefaultOptions for GeneratableKeys where +Options implements Default

+
Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.GeneratableKey.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.GeneratableKey.html new file mode 100644 index 0000000000..5812454c1e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.GeneratableKey.html @@ -0,0 +1,22 @@ +bdk::keys::GeneratableKey - Rust + +

[][src]Trait bdk::keys::GeneratableKey

pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
+    type Entropy: AsMut<[u8]> + Default;
+    type Options;
+    type Error: Debug;
+    pub fn generate_with_entropy(
        options: Self::Options,
        entropy: Self::Entropy
    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error>; + + pub fn generate(
        options: Self::Options
    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> { ... } +}

Trait for keys that can be generated

+

The same rules about ScriptContext and ValidNetworks from ToDescriptorKey apply.

+

This trait is particularly useful when combined with DerivableKey: if Self +implements it, the returned GeneratedKey will also implement it. The same is true for +ToDescriptorKey: the generated keys can be directly used in descriptors if Self is also +ToDescriptorKey.

+

Associated Types

type Entropy: AsMut<[u8]> + Default[src]

Type specifying the amount of entropy required e.g. [u8;32]

+

type Options[src]

Extra options required by the generate_with_entropy

+

type Error: Debug[src]

Returned error in case of failure

+
Loading content...

Required methods

pub fn generate_with_entropy(
    options: Self::Options,
    entropy: Self::Entropy
) -> Result<GeneratedKey<Self, Ctx>, Self::Error>
[src]

Generate a key given the extra options and the entropy

+
Loading content...

Provided methods

pub fn generate(
    options: Self::Options
) -> Result<GeneratedKey<Self, Ctx>, Self::Error>
[src]

Generate a key given the options with a random entropy

+
Loading content...

Implementations on Foreign Types

impl<Ctx: ScriptContext> GeneratableKey<Ctx> for Mnemonic[src]

This is supported on crate feature keys-bip39 only.

type Entropy = [u8; 32]

type Options = (MnemonicType, Language)

type Error = Option<ErrorKind>

impl<Ctx: ScriptContext> GeneratableKey<Ctx> for ExtendedPrivKey[src]

type Entropy = [u8; 32]

type Options = ()

type Error = Error

impl<Ctx: ScriptContext> GeneratableKey<Ctx> for PrivateKey[src]

type Entropy = [u8; 32]

type Options = PrivateKeyGenerateOptions

type Error = Error

Loading content...

Implementors

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.ScriptContext.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.ScriptContext.html new file mode 100644 index 0000000000..c81e63ce76 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.ScriptContext.html @@ -0,0 +1,78 @@ +bdk::keys::ScriptContext - Rust + +

[]Trait bdk::keys::ScriptContext

pub trait ScriptContext: Sealed + Clone + PartialEq<Self> + Eq + Ord + PartialOrd<Self> + Debug {
+    pub fn check_terminal_non_malleable<Pk, Ctx>(
        _frag: &Terminal<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
; +
pub fn max_satisfaction_size<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Option<usize>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
; + + pub fn check_witness<Pk, Ctx>(
        _witness: &[Vec<u8, Global>]
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_global_consensus_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_global_policy_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_local_consensus_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_local_policy_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_global_validity<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn check_local_validity<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn top_level_type_check<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn other_top_level_checks<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +
pub fn top_level_checks<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Ctx: ScriptContext,
        Pk: MiniscriptKey
, + { ... } +}

The ScriptContext for Miniscript. Additional type information associated with +miniscript that is used for carrying out checks that dependent on the +context under which the script is used. +For example, disallowing uncompressed keys in Segwit context

+

Required methods

pub fn check_terminal_non_malleable<Pk, Ctx>(
    _frag: &Terminal<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Depending on ScriptContext, fragments can be malleable. For Example, +under Legacy context, PkH is malleable because it is possible to +estimate the cost of satisfaction because of compressed keys +This is currently only used in compiler code for removing malleable +compilations. +This does NOT recursively check if the children of the fragment are +valid or not. Since the compilation proceeds in a leaf to root fashion, +a recursive check is unnecessary.

+

pub fn max_satisfaction_size<Pk, Ctx>(ms: &Miniscript<Pk, Ctx>) -> Option<usize> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Depending on script context, the size of a satifaction witness may slightly differ.

+
Loading content...

Provided methods

pub fn check_witness<Pk, Ctx>(
    _witness: &[Vec<u8, Global>]
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check whether the given satisfaction is valid under the ScriptContext +For example, segwit satisfactions may fail if the witness len is more +3600 or number of stack elements are more than 100.

+

pub fn check_global_consensus_validity<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Depending on script Context, some of the Terminals might not +be valid under the current consensus rules. +Or some of the script resource limits may have been exceeded. +These miniscripts would never be accepted by the Bitcoin network and hence +it is safe to discard them +For example, in Segwit Context with MiniscriptKey as bitcoin::PublicKey +uncompressed public keys are non-standard and thus invalid. +In LegacyP2SH context, scripts above 520 bytes are invalid. +Post Tapscript upgrade, this would have to consider other nodes. +This does NOT recursively check the miniscript fragments.

+

pub fn check_global_policy_validity<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Depending on script Context, some of the script resource limits +may have been exceeded under the current bitcoin core policy rules +These miniscripts would never be accepted by the Bitcoin network and hence +it is safe to discard them. (unless explicitly disabled by non-standard flag) +For example, in Segwit Context with MiniscriptKey as bitcoin::PublicKey +scripts over 3600 bytes are invalid. +Post Tapscript upgrade, this would have to consider other nodes. +This does NOT recursively check the miniscript fragments.

+

pub fn check_local_consensus_validity<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Consensus rules at the Miniscript satisfaction time. +It is possible that some paths of miniscript may exceed resource limits +and our current satisfier and lifting analysis would not work correctly. +For example, satisfaction path(Legacy/Segwitv0) may require more than 201 opcodes.

+

pub fn check_local_policy_validity<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Policy rules at the Miniscript satisfaction time. +It is possible that some paths of miniscript may exceed resource limits +and our current satisfier and lifting analysis would not work correctly. +For example, satisfaction path in Legacy context scriptSig more +than 1650 bytes

+

pub fn check_global_validity<Pk, Ctx>(
    ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check the consensus + policy(if not disabled) rules that are not based +satisfaction

+

pub fn check_local_validity<Pk, Ctx>(
    ms: &Miniscript<Pk, Ctx>
) -> Result<(), ScriptContextError> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check the consensus + policy(if not disabled) rules including the +ones for satisfaction

+

pub fn top_level_type_check<Pk, Ctx>(
    ms: &Miniscript<Pk, Ctx>
) -> Result<(), Error> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check whether the top-level is type B

+

pub fn other_top_level_checks<Pk, Ctx>(
    _ms: &Miniscript<Pk, Ctx>
) -> Result<(), Error> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Other top level checks that are context specific

+

pub fn top_level_checks<Pk, Ctx>(ms: &Miniscript<Pk, Ctx>) -> Result<(), Error> where
    Ctx: ScriptContext,
    Pk: MiniscriptKey

Check top level consensus rules.

+
Loading content...

Implementations on Foreign Types

impl ScriptContext for Bare

Loading content...

Implementors

impl ScriptContext for Legacy

impl ScriptContext for Segwitv0

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.ToDescriptorKey.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.ToDescriptorKey.html new file mode 100644 index 0000000000..54802814ca --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/trait.ToDescriptorKey.html @@ -0,0 +1,112 @@ +bdk::keys::ToDescriptorKey - Rust + +

[][src]Trait bdk::keys::ToDescriptorKey

pub trait ToDescriptorKey<Ctx: ScriptContext>: Sized {
+    pub fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError>;
+}

Trait for objects that can be turned into a public or secret DescriptorKey

+

The generic type Ctx is used to define the context in which the key is valid: some key +formats, like the mnemonics used by Electrum wallets, encode internally whether the wallet is +legacy or segwit. Thus, trying to turn a valid legacy mnemonic into a DescriptorKey +that would become part of a segwit descriptor should fail.

+

For key types that do care about this, the ExtScriptContext trait provides some useful +methods that can be used to check at runtime which Ctx is being used.

+

For key types that can do this check statically (because they can only work within a +single Ctx), the "specialized" trait can be implemented to make the compiler handle the type +checking.

+

Keys also have control over the networks they support: constructing the return object with +DescriptorKey::from_public or DescriptorKey::from_secret allows to specify a set of +ValidNetworks.

+

Examples

+

Key type valid in any context:

+ +
+use bdk::bitcoin::PublicKey;
+
+use bdk::keys::{DescriptorKey, KeyError, ScriptContext, ToDescriptorKey};
+
+pub struct MyKeyType {
+    pubkey: PublicKey,
+}
+
+impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for MyKeyType {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        self.pubkey.to_descriptor_key()
+    }
+}
+

Key type that is only valid on mainnet:

+ +
+use bdk::bitcoin::PublicKey;
+
+use bdk::keys::{
+    mainnet_network, DescriptorKey, DescriptorPublicKey, DescriptorSinglePub, KeyError,
+    ScriptContext, ToDescriptorKey,
+};
+
+pub struct MyKeyType {
+    pubkey: PublicKey,
+}
+
+impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for MyKeyType {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        Ok(DescriptorKey::from_public(
+            DescriptorPublicKey::SinglePub(DescriptorSinglePub {
+                origin: None,
+                key: self.pubkey,
+            }),
+            mainnet_network(),
+        ))
+    }
+}
+

Key type that internally encodes in which context it's valid. The context is checked at runtime:

+ +
+use bdk::bitcoin::PublicKey;
+
+use bdk::keys::{DescriptorKey, ExtScriptContext, KeyError, ScriptContext, ToDescriptorKey};
+
+pub struct MyKeyType {
+    is_legacy: bool,
+    pubkey: PublicKey,
+}
+
+impl<Ctx: ScriptContext + 'static> ToDescriptorKey<Ctx> for MyKeyType {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        if Ctx::is_legacy() == self.is_legacy {
+            self.pubkey.to_descriptor_key()
+        } else {
+            Err(KeyError::InvalidScriptContext)
+        }
+    }
+}
+

Key type that can only work within miniscript::Segwitv0 context. Only the specialized version +of the trait is implemented.

+

This example deliberately fails to compile, to demonstrate how the compiler can catch when keys +are misused. In this case, the "segwit-only" key is used to build a pkh() descriptor, which +makes the compiler (correctly) fail.

+ +
ⓘThis example deliberately fails to compile
+use bdk::bitcoin::PublicKey;
+use std::str::FromStr;
+
+use bdk::keys::{DescriptorKey, KeyError, ToDescriptorKey};
+
+pub struct MySegwitOnlyKeyType {
+    pubkey: PublicKey,
+}
+
+impl ToDescriptorKey<bdk::miniscript::Segwitv0> for MySegwitOnlyKeyType {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<bdk::miniscript::Segwitv0>, KeyError> {
+        self.pubkey.to_descriptor_key()
+    }
+}
+
+let key = MySegwitOnlyKeyType {
+    pubkey: PublicKey::from_str("...")?,
+};
+let (descriptor, _, _) = bdk::descriptor!(pkh(key))?;
+//                                       ^^^^^ changing this to `wpkh` would make it compile
+
+

Required methods

pub fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError>[src]

Turn the key into a DescriptorKey within the requested ScriptContext

+
Loading content...

Implementations on Foreign Types

impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> ToDescriptorKey<Ctx> for (T, DerivationPath)[src]

impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> ToDescriptorKey<Ctx> for (T, KeySource, DerivationPath)[src]

impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PublicKey[src]

impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PrivateKey[src]

Loading content...

Implementors

impl<Ctx, K> ToDescriptorKey<Ctx> for GeneratedKey<K, Ctx> where
    Ctx: ScriptContext,
    K: ToDescriptorKey<Ctx>, 
[src]

impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorKey<Ctx>[src]

The "identity" conversion is used internally by some bdk::fragments

+

impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorPublicKey[src]

impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorSecretKey[src]

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/type.ValidNetworks.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/type.ValidNetworks.html new file mode 100644 index 0000000000..9156edfb16 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/keys/type.ValidNetworks.html @@ -0,0 +1,5 @@ +bdk::keys::ValidNetworks - Rust + +

[][src]Type Definition bdk::keys::ValidNetworks

type ValidNetworks = HashSet<Network>;

Set of valid networks for a key

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.descriptor!.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.descriptor!.html new file mode 100644 index 0000000000..990e1ba2f8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.descriptor!.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to macro.descriptor.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.descriptor.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.descriptor.html new file mode 100644 index 0000000000..58bf25b1ab --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.descriptor.html @@ -0,0 +1,76 @@ +bdk::descriptor - Rust + +

[][src]Macro bdk::descriptor

+macro_rules! descriptor {
+    ( bare ( $( $minisc:tt )* ) ) => { ... };
+    ( sh ( wsh ( $( $minisc:tt )* ) ) ) => { ... };
+    ( shwsh ( $( $minisc:tt )* ) ) => { ... };
+    ( pk $key:expr ) => { ... };
+    ( pkh $key:expr ) => { ... };
+    ( wpkh $key:expr ) => { ... };
+    ( sh ( wpkh ( $key:expr ) ) ) => { ... };
+    ( shwpkh ( $key:expr ) ) => { ... };
+    ( sh ( $( $minisc:tt )* ) ) => { ... };
+    ( wsh ( $( $minisc:tt )* ) ) => { ... };
+}
+

Macro to write full descriptors with code

+

This macro expands to a Result of +DescriptorTemplateOut and Error

+

Example

+

Signature plus timelock, equivalent to: sh(wsh(and_v(v:pk(...), older(...))))

+ +
+let my_key = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?;
+let my_timelock = 50;
+let (my_descriptor, my_keys_map, networks) = bdk::descriptor!(sh ( wsh ( and_v (+v pk my_key), ( older my_timelock ))))?;
+
+

2-of-3 that becomes a 1-of-3 after a timelock has expired. Both descriptor_a and descriptor_b are equivalent: the first +syntax is more suitable for a fixed number of items known at compile time, while the other accepts a +Vec of items, which makes it more suitable for writing dynamic descriptors.

+

They both produce the descriptor: wsh(thresh(2,pk(...),s:pk(...),sdv:older(...)))

+ +
+let my_key_1 = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?;
+let my_key_2 = bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
+let my_timelock = 50;
+
+let (descriptor_a, key_map_a, networks) = bdk::descriptor! {
+    wsh (
+        thresh 2, (pk my_key_1), (+s pk my_key_2), (+s+d+v older my_timelock)
+    )
+}?;
+
+let b_items = vec![
+    bdk::fragment!(pk my_key_1)?,
+    bdk::fragment!(+s pk my_key_2)?,
+    bdk::fragment!(+s+d+v older my_timelock)?,
+];
+let (descriptor_b, mut key_map_b, networks) = bdk::descriptor!( wsh ( thresh_vec 2, b_items ) )?;
+
+assert_eq!(descriptor_a, descriptor_b);
+assert_eq!(key_map_a.len(), key_map_b.len());
+
+

Simple 2-of-2 multi-signature, equivalent to: wsh(multi(2, ...))

+ +
+let my_key_1 = bitcoin::PublicKey::from_str(
+    "02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c",
+)?;
+let my_key_2 =
+    bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
+
+let (descriptor, key_map, networks) = bdk::descriptor! {
+    wsh (
+        multi 2, my_key_1, my_key_2
+    )
+}?;
+
+

Native-Segwit single-sig, equivalent to: wpkh(...)

+ +
+let my_key =
+    bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
+
+let (descriptor, key_map, networks) = bdk::descriptor!(wpkh(my_key))?;
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.fragment!.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.fragment!.html new file mode 100644 index 0000000000..1dbdb1fdc8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.fragment!.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to macro.fragment.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.fragment.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.fragment.html new file mode 100644 index 0000000000..d1031f5d0c --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/macro.fragment.html @@ -0,0 +1,44 @@ +bdk::fragment - Rust + +

[][src]Macro bdk::fragment

+macro_rules! fragment {
+    ( +a $( $inner:tt )* ) => { ... };
+    ( +s $( $inner:tt )* ) => { ... };
+    ( +c $( $inner:tt )* ) => { ... };
+    ( +d $( $inner:tt )* ) => { ... };
+    ( +v $( $inner:tt )* ) => { ... };
+    ( +j $( $inner:tt )* ) => { ... };
+    ( +n $( $inner:tt )* ) => { ... };
+    ( +t $( $inner:tt )* ) => { ... };
+    ( +l $( $inner:tt )* ) => { ... };
+    ( +u $( $inner:tt )* ) => { ... };
+    ( true ) => { ... };
+    ( false ) => { ... };
+    ( pk_k $key:expr ) => { ... };
+    ( pk $key:expr ) => { ... };
+    ( pk_h $key_hash:expr ) => { ... };
+    ( after $value:expr ) => { ... };
+    ( older $value:expr ) => { ... };
+    ( sha256 $hash:expr ) => { ... };
+    ( hash256 $hash:expr ) => { ... };
+    ( ripemd160 $hash:expr ) => { ... };
+    ( hash160 $hash:expr ) => { ... };
+    ( and_v ( $( $a:tt )* ), ( $( $b:tt )* ) ) => { ... };
+    ( and_b ( $( $a:tt )* ), ( $( $b:tt )* ) ) => { ... };
+    ( and_or ( $( $a:tt )* ), ( $( $b:tt )* ), ( $( $c:tt )* ) ) => { ... };
+    ( or_b ( $( $a:tt )* ), ( $( $b:tt )* ) ) => { ... };
+    ( or_d ( $( $a:tt )* ), ( $( $b:tt )* ) ) => { ... };
+    ( or_c ( $( $a:tt )* ), ( $( $b:tt )* ) ) => { ... };
+    ( or_i ( $( $a:tt )* ), ( $( $b:tt )* ) ) => { ... };
+    ( thresh_vec $thresh:expr, $items:expr ) => { ... };
+    ( thresh $thresh:expr $(, ( $( $item:tt )* ) )+ ) => { ... };
+    ( multi_vec $thresh:expr, $keys:expr ) => { ... };
+    ( multi $thresh:expr $(, $key:expr )+ ) => { ... };
+    ( sortedmulti $( $inner:tt )* ) => { ... };
+    ( sortedmulti_vec $( $inner:tt )* ) => { ... };
+}
+

Macro to write descriptor fragments with code

+

This macro will be expanded to an object of type Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), Error>. It allows writing +fragments of larger descriptors that can be pieced together using fragment!(thresh_vec ...).

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/sidebar-items.js new file mode 100644 index 0000000000..bc49a753f3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["Error","Errors that can be thrown by the `Wallet`"],["KeychainKind","Types of keychains"]],"macro":[["descriptor","Macro to write full descriptors with code"],["fragment","Macro to write descriptor fragments with code"]],"mod":[["blockchain","Blockchain backends"],["database","Database types"],["descriptor","Descriptors"],["keys","Key formats"],["wallet","Wallet"]],"struct":[["FeeRate","Fee rate"],["TransactionDetails","A wallet transaction"],["UTXO","A wallet unspent output"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/struct.FeeRate.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/struct.FeeRate.html new file mode 100644 index 0000000000..23ab6fa059 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/struct.FeeRate.html @@ -0,0 +1,51 @@ +bdk::FeeRate - Rust + +

[][src]Struct bdk::FeeRate

pub struct FeeRate(_);

Fee rate

+

Implementations

impl FeeRate[src]

pub fn from_btc_per_kvb(btc_per_kvb: f32) -> Self[src]

Create a new instance of FeeRate given a float fee rate in btc/kvbytes

+

pub fn from_sat_per_vb(sat_per_vb: f32) -> Self[src]

Create a new instance of FeeRate given a float fee rate in satoshi/vbyte

+

pub fn default_min_relay_fee() -> Self[src]

Create a new FeeRate with the default min relay fee value

+

pub fn as_sat_vb(&self) -> f32[src]

Return the value as satoshi/vbyte

+

Trait Implementations

impl Clone for FeeRate[src]

impl Copy for FeeRate[src]

impl Debug for FeeRate[src]

impl Default for FeeRate[src]

impl PartialEq<FeeRate> for FeeRate[src]

impl PartialOrd<FeeRate> for FeeRate[src]

impl StructuralPartialEq for FeeRate[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/struct.TransactionDetails.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/struct.TransactionDetails.html new file mode 100644 index 0000000000..52089b9ae3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/struct.TransactionDetails.html @@ -0,0 +1,59 @@ +bdk::TransactionDetails - Rust + +

[][src]Struct bdk::TransactionDetails

pub struct TransactionDetails {
+    pub transaction: Option<Transaction>,
+    pub txid: Txid,
+    pub timestamp: u64,
+    pub received: u64,
+    pub sent: u64,
+    pub fees: u64,
+    pub height: Option<u32>,
+}

A wallet transaction

+

+ Fields

transaction: Option<Transaction>

Optional transaction

+
txid: Txid

Transaction id

+
timestamp: u64

Timestamp

+
received: u64

Received value (sats)

+
sent: u64

Sent value (sats)

+
fees: u64

Fee value (sats)

+
height: Option<u32>

Confirmed in block height, None means unconfirmed

+

Trait Implementations

impl Clone for TransactionDetails[src]

impl Debug for TransactionDetails[src]

impl Default for TransactionDetails[src]

impl<'de> Deserialize<'de> for TransactionDetails[src]

impl Eq for TransactionDetails[src]

impl PartialEq<TransactionDetails> for TransactionDetails[src]

impl Serialize for TransactionDetails[src]

impl StructuralEq for TransactionDetails[src]

impl StructuralPartialEq for TransactionDetails[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/struct.UTXO.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/struct.UTXO.html new file mode 100644 index 0000000000..cbdf664fe6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/struct.UTXO.html @@ -0,0 +1,50 @@ +bdk::UTXO - Rust + +

[][src]Struct bdk::UTXO

pub struct UTXO {
+    pub outpoint: OutPoint,
+    pub txout: TxOut,
+    pub keychain: KeychainKind,
+}

A wallet unspent output

+

+ Fields

outpoint: OutPoint

Reference to a transaction output

+
txout: TxOut

Transaction output

+
keychain: KeychainKind

Type of keychain

+

Trait Implementations

impl Clone for UTXO[src]

impl Debug for UTXO[src]

impl<'de> Deserialize<'de> for UTXO[src]

impl Eq for UTXO[src]

impl PartialEq<UTXO> for UTXO[src]

impl Serialize for UTXO[src]

impl StructuralEq for UTXO[src]

impl StructuralPartialEq for UTXO[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/enum.KeychainKind.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/enum.KeychainKind.html new file mode 100644 index 0000000000..8b0b5f9399 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/enum.KeychainKind.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../bdk/enum.KeychainKind.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/enum.ScriptType.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/enum.ScriptType.html new file mode 100644 index 0000000000..b10e9a3fe6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/enum.ScriptType.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../bdk/enum.ScriptType.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/struct.FeeRate.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/struct.FeeRate.html new file mode 100644 index 0000000000..c8b0ec4f98 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/struct.FeeRate.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../bdk/struct.FeeRate.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/struct.TransactionDetails.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/struct.TransactionDetails.html new file mode 100644 index 0000000000..5db5e06868 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/struct.TransactionDetails.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../bdk/struct.TransactionDetails.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/struct.UTXO.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/struct.UTXO.html new file mode 100644 index 0000000000..1517bb40f5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/types/struct.UTXO.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../bdk/struct.UTXO.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/enum.AddressValidatorError.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/enum.AddressValidatorError.html new file mode 100644 index 0000000000..19c2ae0bf1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/enum.AddressValidatorError.html @@ -0,0 +1,60 @@ +bdk::wallet::address_validator::AddressValidatorError - Rust + +

[][src]Enum bdk::wallet::address_validator::AddressValidatorError

pub enum AddressValidatorError {
+    UserRejected,
+    ConnectionError,
+    TimeoutError,
+    InvalidScript,
+    Message(String),
+}

Errors that can be returned to fail the validation of an address

+

+ Variants

+
UserRejected

User rejected the address

+
ConnectionError

Network connection error

+
TimeoutError

Network request timeout error

+
InvalidScript

Invalid script

+
Message(String)

A custom error message

+

Trait Implementations

impl Clone for AddressValidatorError[src]

impl Debug for AddressValidatorError[src]

impl Display for AddressValidatorError[src]

impl Eq for AddressValidatorError[src]

impl Error for AddressValidatorError[src]

impl From<AddressValidatorError> for Error[src]

impl PartialEq<AddressValidatorError> for AddressValidatorError[src]

impl StructuralEq for AddressValidatorError[src]

impl StructuralPartialEq for AddressValidatorError[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/index.html new file mode 100644 index 0000000000..8779ce0ce5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/index.html @@ -0,0 +1,47 @@ +bdk::wallet::address_validator - Rust + +

[][src]Module bdk::wallet::address_validator

Address validation callbacks

+

The typical usage of those callbacks is for displaying the newly-generated address on a +hardware wallet, so that the user can cross-check its correctness.

+

More generally speaking though, these callbacks can also be used to "do something" every time +an address is generated, without necessarily checking or validating it.

+

An address validator can be attached to a Wallet by using the +Wallet::add_address_validator method, and +whenever a new address is generated (either explicitly by the user with +Wallet::get_new_address or internally to create a change +address) all the attached validators will be polled, in sequence. All of them must complete +successfully to continue.

+

Example

+
+struct PrintAddressAndContinue;
+
+impl AddressValidator for PrintAddressAndContinue {
+    fn validate(
+        &self,
+        keychain: KeychainKind,
+        hd_keypaths: &HDKeyPaths,
+        script: &Script
+    ) -> Result<(), AddressValidatorError> {
+        let address = Address::from_script(script, Network::Testnet)
+            .as_ref()
+            .map(Address::to_string)
+            .unwrap_or(script.to_string());
+        println!("New address of type {:?}: {}", keychain, address);
+        println!("HD keypaths: {:#?}", hd_keypaths);
+
+        Ok(())
+    }
+}
+
+let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+let mut wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+wallet.add_address_validator(Arc::new(PrintAddressAndContinue));
+
+let address = wallet.get_new_address()?;
+println!("Address: {}", address);
+

Enums

+
AddressValidatorError

Errors that can be returned to fail the validation of an address

+

Traits

+
AddressValidator

Trait to build address validators

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/sidebar-items.js new file mode 100644 index 0000000000..58959ba340 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["AddressValidatorError","Errors that can be returned to fail the validation of an address"]],"trait":[["AddressValidator","Trait to build address validators"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/trait.AddressValidator.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/trait.AddressValidator.html new file mode 100644 index 0000000000..ccd57983bc --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/address_validator/trait.AddressValidator.html @@ -0,0 +1,12 @@ +bdk::wallet::address_validator::AddressValidator - Rust + +

[][src]Trait bdk::wallet::address_validator::AddressValidator

pub trait AddressValidator: Send + Sync {
+    pub fn validate(
        &self,
        keychain: KeychainKind,
        hd_keypaths: &HDKeyPaths,
        script: &Script
    ) -> Result<(), AddressValidatorError>; +}

Trait to build address validators

+

All the address validators attached to a wallet with Wallet::add_address_validator will be polled +every time an address (external or internal) is generated by the wallet. Errors returned in the +validator will be propagated up to the original caller that triggered the address generation.

+

For a usage example see this module's documentation.

+

Required methods

pub fn validate(
    &self,
    keychain: KeychainKind,
    hd_keypaths: &HDKeyPaths,
    script: &Script
) -> Result<(), AddressValidatorError>
[src]

Validate or inspect an address

+
Loading content...

Implementors

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/constant.TXIN_BASE_WEIGHT.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/constant.TXIN_BASE_WEIGHT.html new file mode 100644 index 0000000000..424e9ede75 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/constant.TXIN_BASE_WEIGHT.html @@ -0,0 +1,4 @@ +bdk::wallet::coin_selection::TXIN_BASE_WEIGHT - Rust + +

[][src]Constant bdk::wallet::coin_selection::TXIN_BASE_WEIGHT

pub const TXIN_BASE_WEIGHT: usize = (32 + 4 + 4 + 1) * 4; // 0x0_000_000_000_000_0a4usize
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/index.html new file mode 100644 index 0000000000..6c2eea8d97 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/index.html @@ -0,0 +1,72 @@ +bdk::wallet::coin_selection - Rust + +

[][src]Module bdk::wallet::coin_selection

Coin selection

+

This module provides the trait CoinSelectionAlgorithm that can be implemented to +define custom coin selection algorithms.

+

The coin selection algorithm is not globally part of a Wallet, instead it +is selected whenever a Wallet::create_tx call is made, through +the use of the TxBuilder structure, specifically with +TxBuilder::coin_selection method.

+

The DefaultCoinSelectionAlgorithm selects the default coin selection algorithm that +TxBuilder uses, if it's not explicitly overridden.

+

Example

+
+#[derive(Debug)]
+struct AlwaysSpendEverything;
+
+impl<D: Database> CoinSelectionAlgorithm<D> for AlwaysSpendEverything {
+    fn coin_select(
+        &self,
+        database: &D,
+        required_utxos: Vec<(UTXO, usize)>,
+        optional_utxos: Vec<(UTXO, usize)>,
+        fee_rate: FeeRate,
+        amount_needed: u64,
+        fee_amount: f32,
+    ) -> Result<CoinSelectionResult, bdk::Error> {
+        let mut selected_amount = 0;
+        let mut additional_weight = 0;
+        let all_utxos_selected = required_utxos
+            .into_iter().chain(optional_utxos)
+            .scan((&mut selected_amount, &mut additional_weight), |(selected_amount, additional_weight), (utxo, weight)| {
+                **selected_amount += utxo.txout.value;
+                **additional_weight += TXIN_BASE_WEIGHT + weight;
+
+                Some(utxo)
+            })
+            .collect::<Vec<_>>();
+        let additional_fees = additional_weight as f32 * fee_rate.as_sat_vb() / 4.0;
+
+        if (fee_amount + additional_fees).ceil() as u64 + amount_needed > selected_amount {
+            return Err(bdk::Error::InsufficientFunds);
+        }
+
+        Ok(CoinSelectionResult {
+            selected: all_utxos_selected,
+            selected_amount,
+            fee_amount: fee_amount + additional_fees,
+        })
+    }
+}
+
+// create wallet, sync, ...
+
+let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+let (psbt, details) = wallet.create_tx(
+    TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
+        .coin_selection(AlwaysSpendEverything),
+)?;
+
+// inspect, sign, broadcast, ...
+
+

Structs

+
BranchAndBoundCoinSelection

Branch and bound coin selection

+
CoinSelectionResult

Result of a successful coin selection

+
LargestFirstCoinSelection

Simple and dumb coin selection

+

Traits

+
CoinSelectionAlgorithm

Trait for generalized coin selection algorithms

+

Type Definitions

+
DefaultCoinSelectionAlgorithm

Default coin selection algorithm used by TxBuilder if not +overridden

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/sidebar-items.js new file mode 100644 index 0000000000..8e7e293b89 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"struct":[["BranchAndBoundCoinSelection","Branch and bound coin selection"],["CoinSelectionResult","Result of a successful coin selection"],["LargestFirstCoinSelection","Simple and dumb coin selection"]],"trait":[["CoinSelectionAlgorithm","Trait for generalized coin selection algorithms"]],"type":[["DefaultCoinSelectionAlgorithm","Default coin selection algorithm used by `TxBuilder` if not overridden"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/struct.BranchAndBoundCoinSelection.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/struct.BranchAndBoundCoinSelection.html new file mode 100644 index 0000000000..3bab787572 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/struct.BranchAndBoundCoinSelection.html @@ -0,0 +1,34 @@ +bdk::wallet::coin_selection::BranchAndBoundCoinSelection - Rust + +

[][src]Struct bdk::wallet::coin_selection::BranchAndBoundCoinSelection

pub struct BranchAndBoundCoinSelection { /* fields omitted */ }

Branch and bound coin selection

+

Code adapted from Bitcoin Core's implementation and from Mark Erhardt Master's Thesis: http://murch.one/wp-content/uploads/2016/11/erhardt2016coinselection.pdf

+

Implementations

impl BranchAndBoundCoinSelection[src]

pub fn new(size_of_change: u64) -> Self[src]

Create new instance with target size for change output

+

Trait Implementations

impl<D: Database> CoinSelectionAlgorithm<D> for BranchAndBoundCoinSelection[src]

impl Debug for BranchAndBoundCoinSelection[src]

impl Default for BranchAndBoundCoinSelection[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/struct.CoinSelectionResult.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/struct.CoinSelectionResult.html new file mode 100644 index 0000000000..ac4969b233 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/struct.CoinSelectionResult.html @@ -0,0 +1,38 @@ +bdk::wallet::coin_selection::CoinSelectionResult - Rust + +

[][src]Struct bdk::wallet::coin_selection::CoinSelectionResult

pub struct CoinSelectionResult {
+    pub selected: Vec<UTXO>,
+    pub selected_amount: u64,
+    pub fee_amount: f32,
+}

Result of a successful coin selection

+

+ Fields

selected: Vec<UTXO>

List of outputs selected for use as inputs

+
selected_amount: u64

Sum of the selected inputs' value

+
fee_amount: f32

Total fee amount in satoshi

+

Trait Implementations

impl Debug for CoinSelectionResult[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/struct.LargestFirstCoinSelection.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/struct.LargestFirstCoinSelection.html new file mode 100644 index 0000000000..3694261e76 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/struct.LargestFirstCoinSelection.html @@ -0,0 +1,34 @@ +bdk::wallet::coin_selection::LargestFirstCoinSelection - Rust + +

[][src]Struct bdk::wallet::coin_selection::LargestFirstCoinSelection

pub struct LargestFirstCoinSelection;

Simple and dumb coin selection

+

This coin selection algorithm sorts the available UTXOs by value and then picks them starting +from the largest ones until the required amount is reached.

+

Trait Implementations

impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection[src]

impl Debug for LargestFirstCoinSelection[src]

impl Default for LargestFirstCoinSelection[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.html new file mode 100644 index 0000000000..d7b7b57eeb --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.html @@ -0,0 +1,23 @@ +bdk::wallet::coin_selection::CoinSelectionAlgorithm - Rust + +

[][src]Trait bdk::wallet::coin_selection::CoinSelectionAlgorithm

pub trait CoinSelectionAlgorithm<D: Database>: Debug {
+    pub fn coin_select(
        &self,
        database: &D,
        required_utxos: Vec<(UTXO, usize)>,
        optional_utxos: Vec<(UTXO, usize)>,
        fee_rate: FeeRate,
        amount_needed: u64,
        fee_amount: f32
    ) -> Result<CoinSelectionResult, Error>; +}

Trait for generalized coin selection algorithms

+

This trait can be implemented to make the Wallet use a customized coin +selection algorithm when it creates transactions.

+

For an example see this module's documentation.

+

Required methods

pub fn coin_select(
    &self,
    database: &D,
    required_utxos: Vec<(UTXO, usize)>,
    optional_utxos: Vec<(UTXO, usize)>,
    fee_rate: FeeRate,
    amount_needed: u64,
    fee_amount: f32
) -> Result<CoinSelectionResult, Error>
[src]

Perform the coin selection

+
    +
  • database: a reference to the wallet's database that can be used to lookup additional +details for a specific UTXO
  • +
  • required_utxos: the utxos that must be spent regardless of amount_needed with their +weight cost
  • +
  • optional_utxos: the remaining available utxos to satisfy amount_needed with their +weight cost
  • +
  • fee_rate: fee rate to use
  • +
  • amount_needed: the amount in satoshi to select
  • +
  • fee_amount: the amount of fees in satoshi already accumulated from adding outputs and +the transaction's header
  • +
+
Loading content...

Implementors

impl<D: Database> CoinSelectionAlgorithm<D> for BranchAndBoundCoinSelection[src]

impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection[src]

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/type.DefaultCoinSelectionAlgorithm.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/type.DefaultCoinSelectionAlgorithm.html new file mode 100644 index 0000000000..0cb914590e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/coin_selection/type.DefaultCoinSelectionAlgorithm.html @@ -0,0 +1,6 @@ +bdk::wallet::coin_selection::DefaultCoinSelectionAlgorithm - Rust + +

[][src]Type Definition bdk::wallet::coin_selection::DefaultCoinSelectionAlgorithm

type DefaultCoinSelectionAlgorithm = BranchAndBoundCoinSelection;

Default coin selection algorithm used by TxBuilder if not +overridden

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/export/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/export/index.html new file mode 100644 index 0000000000..bb91aa33f1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/export/index.html @@ -0,0 +1,36 @@ +bdk::wallet::export - Rust + +

[][src]Module bdk::wallet::export

Wallet export

+

This modules implements the wallet export format used by FullyNoded.

+

Examples

Import from JSON

+
+let import = r#"{
+    "descriptor": "wpkh([c258d2e4\/84h\/1h\/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe\/0\/*)",
+    "blockheight":1782088,
+    "label":"testnet"
+}"#;
+
+let import = WalletExport::from_str(import)?;
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    &import.descriptor(),
+    import.change_descriptor().as_ref(),
+    Network::Testnet,
+    MemoryDatabase::default(),
+)?;
+

Export a Wallet

+
+let wallet: OfflineWallet<_> = Wallet::new_offline(
+    "wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/0/*)",
+    Some("wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/1/*)"),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+let export = WalletExport::export_wallet(&wallet, "exported wallet", true)
+    .map_err(ToString::to_string)
+    .map_err(bdk::Error::Generic)?;
+
+println!("Exported: {}", export.to_string());
+

Structs

+
WalletExport

Structure that contains the export of a wallet

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/export/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/export/sidebar-items.js new file mode 100644 index 0000000000..06abb3c4ee --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/export/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"struct":[["WalletExport","Structure that contains the export of a wallet"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/export/struct.WalletExport.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/export/struct.WalletExport.html new file mode 100644 index 0000000000..cdef818514 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/export/struct.WalletExport.html @@ -0,0 +1,53 @@ +bdk::wallet::export::WalletExport - Rust + +

[][src]Struct bdk::wallet::export::WalletExport

pub struct WalletExport {
+    pub blockheight: u32,
+    pub label: String,
+    // some fields omitted
+}

Structure that contains the export of a wallet

+

For a usage example see this module's documentation.

+

+ Fields

blockheight: u32

Earliest block to rescan when looking for the wallet's transactions

+
label: String

Arbitrary label for the wallet

+

Implementations

impl WalletExport[src]

pub fn export_wallet<B: BlockchainMarker, D: BatchDatabase>(
    wallet: &Wallet<B, D>,
    label: &str,
    include_blockheight: bool
) -> Result<Self, &'static str>
[src]

Export a wallet

+

This function returns an error if it determines that the wallet's descriptor(s) are not +supported by Bitcoin Core or don't follow the standard derivation paths defined by BIP44 +and others.

+

If include_blockheight is true, this function will look into the wallet's database +for the oldest transaction it knows and use that as the earliest block to rescan.

+

If the database is empty or include_blockheight is false, the blockheight field +returned will be 0.

+

pub fn descriptor(&self) -> String[src]

Return the external descriptor

+

pub fn change_descriptor(&self) -> Option<String>[src]

Return the internal descriptor, if present

+

Trait Implementations

impl Debug for WalletExport[src]

impl<'de> Deserialize<'de> for WalletExport[src]

impl FromStr for WalletExport[src]

type Err = Error

The associated error which can be returned from parsing.

+

impl Serialize for WalletExport[src]

impl ToString for WalletExport[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> DeserializeOwned for T where
    T: for<'de> Deserialize<'de>, 
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/index.html new file mode 100644 index 0000000000..7f20cd4daf --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/index.html @@ -0,0 +1,19 @@ +bdk::wallet - Rust + +

[][src]Module bdk::wallet

Wallet

+

This module defines the Wallet structure.

+

Modules

+
address_validator

Address validation callbacks

+
coin_selection

Coin selection

+
export

Wallet export

+
signer

Generalized signers

+
time

Cross-platform time

+
tx_builder

Transaction builder

+

Structs

+
Wallet

A Bitcoin wallet

+

Traits

+
IsDust

Trait to check if a value is below the dust limit

+

Type Definitions

+
OfflineWallet

Type alias for a Wallet that uses OfflineBlockchain

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/sidebar-items.js new file mode 100644 index 0000000000..811ec3c2b5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"mod":[["address_validator","Address validation callbacks"],["coin_selection","Coin selection"],["export","Wallet export"],["signer","Generalized signers"],["time","Cross-platform time"],["tx_builder","Transaction builder"]],"struct":[["Wallet","A Bitcoin wallet"]],"trait":[["IsDust","Trait to check if a value is below the dust limit"]],"type":[["OfflineWallet","Type alias for a [`Wallet`] that uses [`OfflineBlockchain`]"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/enum.SignerError.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/enum.SignerError.html new file mode 100644 index 0000000000..7f44c5c3b9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/enum.SignerError.html @@ -0,0 +1,68 @@ +bdk::wallet::signer::SignerError - Rust + +

[][src]Enum bdk::wallet::signer::SignerError

pub enum SignerError {
+    MissingKey,
+    InvalidKey,
+    UserCanceled,
+    InputIndexOutOfRange,
+    MissingNonWitnessUtxo,
+    InvalidNonWitnessUtxo,
+    MissingWitnessUtxo,
+    MissingWitnessScript,
+    MissingHDKeypath,
+}

Signing error

+

+ Variants

+
MissingKey

The private key is missing for the required public key

+
InvalidKey

The private key in use has the right fingerprint but derives differently than expected

+
UserCanceled

The user canceled the operation

+
InputIndexOutOfRange

Input index is out of range

+
MissingNonWitnessUtxo

The non_witness_utxo field of the transaction is required to sign this input

+
InvalidNonWitnessUtxo

The non_witness_utxo specified is invalid

+
MissingWitnessUtxo

The witness_utxo field of the transaction is required to sign this input

+
MissingWitnessScript

The witness_script field of the transaction is requied to sign this input

+
MissingHDKeypath

The fingerprint and derivation path are missing from the psbt input

+

Trait Implementations

impl Clone for SignerError[src]

impl Debug for SignerError[src]

impl Display for SignerError[src]

impl Eq for SignerError[src]

impl Error for SignerError[src]

impl From<SignerError> for Error[src]

impl PartialEq<SignerError> for SignerError[src]

impl StructuralEq for SignerError[src]

impl StructuralPartialEq for SignerError[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/enum.SignerId.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/enum.SignerId.html new file mode 100644 index 0000000000..1a404225cd --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/enum.SignerId.html @@ -0,0 +1,63 @@ +bdk::wallet::signer::SignerId - Rust + +

[][src]Enum bdk::wallet::signer::SignerId

pub enum SignerId {
+    PkHash(Hash),
+    Fingerprint(Fingerprint),
+}

Identifier of a signer in the SignersContainers. Used as a key to find the right signer among +multiple of them

+

+ Variants

+
PkHash(Hash)

Bitcoin HASH160 (RIPEMD160 after SHA256) hash of an ECDSA public key

+
Fingerprint(Fingerprint)

The fingerprint of a BIP32 extended key

+

Trait Implementations

impl Clone for SignerId[src]

impl Debug for SignerId[src]

impl Eq for SignerId[src]

impl From<Fingerprint> for SignerId[src]

impl From<Hash> for SignerId[src]

impl Hash for SignerId[src]

impl Ord for SignerId[src]

impl PartialEq<SignerId> for SignerId[src]

impl PartialOrd<SignerId> for SignerId[src]

impl StructuralEq for SignerId[src]

impl StructuralPartialEq for SignerId[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/index.html new file mode 100644 index 0000000000..fee170e531 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/index.html @@ -0,0 +1,58 @@ +bdk::wallet::signer - Rust + +

[][src]Module bdk::wallet::signer

Generalized signers

+

This module provides the ability to add customized signers to a Wallet +through the Wallet::add_signer function.

+ +
+#[derive(Debug)]
+struct CustomSigner {
+    device: CustomHSM,
+}
+
+impl CustomSigner {
+    fn connect() -> Self {
+        CustomSigner { device: CustomHSM::connect() }
+    }
+}
+
+impl Signer for CustomSigner {
+    fn sign(
+        &self,
+        psbt: &mut psbt::PartiallySignedTransaction,
+        input_index: Option<usize>,
+        _secp: &Secp256k1<All>,
+    ) -> Result<(), SignerError> {
+        let input_index = input_index.ok_or(SignerError::InputIndexOutOfRange)?;
+        self.device.sign_input(psbt, input_index)?;
+
+        Ok(())
+    }
+
+    fn sign_whole_tx(&self) -> bool {
+        false
+    }
+}
+
+let custom_signer = CustomSigner::connect();
+
+let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+let mut wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+wallet.add_signer(
+    KeychainKind::External,
+    Fingerprint::from_str("e30f11b8").unwrap().into(),
+    SignerOrdering(200),
+    Arc::new(custom_signer)
+);
+
+

Structs

+
SignerOrdering

Defines the order in which signers are called

+
SignersContainer

Container for multiple signers

+

Enums

+
SignerError

Signing error

+
SignerId

Identifier of a signer in the SignersContainers. Used as a key to find the right signer among +multiple of them

+

Traits

+
Signer

Trait for signers

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/sidebar-items.js new file mode 100644 index 0000000000..8f3e3d79b6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["SignerError","Signing error"],["SignerId","Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among multiple of them"]],"struct":[["SignerOrdering","Defines the order in which signers are called"],["SignersContainer","Container for multiple signers"]],"trait":[["Signer","Trait for signers"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/struct.SignerOrdering.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/struct.SignerOrdering.html new file mode 100644 index 0000000000..6bd85ccaf8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/struct.SignerOrdering.html @@ -0,0 +1,55 @@ +bdk::wallet::signer::SignerOrdering - Rust + +

[][src]Struct bdk::wallet::signer::SignerOrdering

pub struct SignerOrdering(pub usize);

Defines the order in which signers are called

+

The default value is 100. Signers with an ordering above that will be called later, +and they will thus see the partial signatures added to the transaction once they get to sign +themselves.

+

Trait Implementations

impl Clone for SignerOrdering[src]

impl Debug for SignerOrdering[src]

impl Default for SignerOrdering[src]

impl Eq for SignerOrdering[src]

impl Ord for SignerOrdering[src]

impl PartialEq<SignerOrdering> for SignerOrdering[src]

impl PartialOrd<SignerOrdering> for SignerOrdering[src]

impl StructuralEq for SignerOrdering[src]

impl StructuralPartialEq for SignerOrdering[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/struct.SignersContainer.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/struct.SignersContainer.html new file mode 100644 index 0000000000..ebd6434357 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/struct.SignersContainer.html @@ -0,0 +1,46 @@ +bdk::wallet::signer::SignersContainer - Rust + +

[][src]Struct bdk::wallet::signer::SignersContainer

pub struct SignersContainer(_);

Container for multiple signers

+

Implementations

impl SignersContainer[src]

pub fn as_key_map(&self, secp: &Secp256k1<All>) -> KeyMap[src]

Create a map of public keys to secret keys

+

impl SignersContainer[src]

pub fn new() -> Self[src]

Default constructor

+

pub fn add_external(
    &mut self,
    id: SignerId,
    ordering: SignerOrdering,
    signer: Arc<dyn Signer>
) -> Option<Arc<dyn Signer>>
[src]

Adds an external signer to the container for the specified id. Optionally returns the +signer that was previously in the container, if any

+

pub fn remove(
    &mut self,
    id: SignerId,
    ordering: SignerOrdering
) -> Option<Arc<dyn Signer>>
[src]

Removes a signer from the container and returns it

+

pub fn ids(&self) -> Vec<&SignerId>[src]

Returns the list of identifiers of all the signers in the container

+

pub fn signers(&self) -> Vec<&Arc<dyn Signer>>[src]

Returns the list of signers in the container, sorted by lowest to highest ordering

+

pub fn find(&self, id: SignerId) -> Option<&Arc<dyn Signer>>[src]

Finds the signer with lowest ordering for a given id in the container.

+

Trait Implementations

impl Clone for SignersContainer[src]

impl Debug for SignersContainer[src]

impl Default for SignersContainer[src]

impl From<HashMap<DescriptorPublicKey, DescriptorSecretKey, RandomState>> for SignersContainer[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/trait.Signer.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/trait.Signer.html new file mode 100644 index 0000000000..95e96eab96 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/signer/trait.Signer.html @@ -0,0 +1,22 @@ +bdk::wallet::signer::Signer - Rust + +

[][src]Trait bdk::wallet::signer::Signer

pub trait Signer: Debug + Send + Sync {
+    pub fn sign(
        &self,
        psbt: &mut PartiallySignedTransaction,
        input_index: Option<usize>,
        secp: &Secp256k1<All>
    ) -> Result<(), SignerError>; +
pub fn sign_whole_tx(&self) -> bool; + + pub fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> { ... } +}

Trait for signers

+

This trait can be implemented to provide customized signers to the wallet. For an example see +this module's documentation.

+

Required methods

pub fn sign(
    &self,
    psbt: &mut PartiallySignedTransaction,
    input_index: Option<usize>,
    secp: &Secp256k1<All>
) -> Result<(), SignerError>
[src]

Sign a PSBT

+

The input_index argument is only provided if the wallet doesn't declare to sign the whole +transaction in one go (see Signer::sign_whole_tx). Otherwise its value is None and +can be ignored.

+

pub fn sign_whole_tx(&self) -> bool[src]

Return whether or not the signer signs the whole transaction in one go instead of every +input individually

+
Loading content...

Provided methods

pub fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey>[src]

Return the secret key for the signer

+

This is used internally to reconstruct the original descriptor that may contain secrets. +External signers that are meant to keep key isolated should just return None here (which +is the default for this method, if not overridden).

+
Loading content...

Implementations on Foreign Types

impl Signer for DescriptorXKey<ExtendedPrivKey>[src]

impl Signer for PrivateKey[src]

Loading content...

Implementors

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/struct.Wallet.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/struct.Wallet.html new file mode 100644 index 0000000000..9d76dc92f8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/struct.Wallet.html @@ -0,0 +1,92 @@ +bdk::wallet::Wallet - Rust + +

[][src]Struct bdk::wallet::Wallet

pub struct Wallet<B, D> { /* fields omitted */ }

A Bitcoin wallet

+

A wallet takes descriptors, a database and a +blockchain and implements the basic functions that a Bitcoin wallets +needs to operate, like generating addresses, returning the balance, +creating transactions, etc.

+

A wallet can be either "online" if the blockchain type provided +implements Blockchain, or "offline" OfflineBlockchain is used. Offline wallets only expose +methods that don't need any interaction with the blockchain to work.

+

Implementations

impl<B, D> Wallet<B, D> where
    B: BlockchainMarker,
    D: BatchDatabase
[src]

pub fn new_offline<E: ToWalletDescriptor>(
    descriptor: E,
    change_descriptor: Option<E>,
    network: Network,
    database: D
) -> Result<Self, Error>
[src]

Create a new "offline" wallet

+

pub fn get_new_address(&self) -> Result<Address, Error>[src]

Return a newly generated address using the external descriptor

+

pub fn is_mine(&self, script: &Script) -> Result<bool, Error>[src]

Return whether or not a script is part of this wallet (either internal or external)

+

pub fn list_unspent(&self) -> Result<Vec<UTXO>, Error>[src]

Return the list of unspent outputs of this wallet

+

Note that this methods only operate on the internal database, which first needs to be +Wallet::sync manually.

+

pub fn list_transactions(
    &self,
    include_raw: bool
) -> Result<Vec<TransactionDetails>, Error>
[src]

Return the list of transactions made and received by the wallet

+

Optionally fill the TransactionDetails::transaction field with the raw transaction if +include_raw is true.

+

Note that this methods only operate on the internal database, which first needs to be +Wallet::sync manually.

+

pub fn get_balance(&self) -> Result<u64, Error>[src]

Return the balance, meaning the sum of this wallet's unspent outputs' values

+

Note that this methods only operate on the internal database, which first needs to be +Wallet::sync manually.

+

pub fn add_signer(
    &mut self,
    keychain: KeychainKind,
    id: SignerId,
    ordering: SignerOrdering,
    signer: Arc<dyn Signer>
)
[src]

Add an external signer

+

See the signer module for an example.

+

pub fn add_address_validator(&mut self, validator: Arc<dyn AddressValidator>)[src]

Add an address validator

+

See the address_validator module for an example.

+

pub fn create_tx<Cs: CoinSelectionAlgorithm<D>>(
    &self,
    builder: TxBuilder<D, Cs, CreateTx>
) -> Result<(PSBT, TransactionDetails), Error>
[src]

Create a new transaction following the options specified in the builder

+

Example

+
+let (psbt, details) = wallet.create_tx(
+    TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
+)?;
+// sign and broadcast ...
+

pub fn bump_fee<Cs: CoinSelectionAlgorithm<D>>(
    &self,
    txid: &Txid,
    builder: TxBuilder<D, Cs, BumpFee>
) -> Result<(PSBT, TransactionDetails), Error>
[src]

Bump the fee of a transaction following the options specified in the builder

+

Return an error if the transaction is already confirmed or doesn't explicitly signal RBF.

+

NOTE: if the original transaction was made with TxBuilder::set_single_recipient, +the TxBuilder::maintain_single_recipient flag should be enabled to correctly reduce the +only output's value in order to increase the fees.

+

If the builder specifies some utxos that must be spent, they will be added to the +transaction regardless of whether they are necessary or not to cover additional fees.

+

Example

+
+let txid = Txid::from_str("faff0a466b70f5d5f92bd757a92c1371d4838bdd5bc53a06764e2488e51ce8f8").unwrap();
+let (psbt, details) = wallet.bump_fee(
+    &txid,
+    TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(5.0)),
+)?;
+// sign and broadcast ...
+

pub fn sign(
    &self,
    psbt: PSBT,
    assume_height: Option<u32>
) -> Result<(PSBT, bool), Error>
[src]

Sign a transaction with all the wallet's signers, in the order specified by every signer's +SignerOrdering

+

Example

+
+let (signed_psbt, finalized) = wallet.sign(psbt, None)?;
+

pub fn policies(&self, keychain: KeychainKind) -> Result<Option<Policy>, Error>[src]

Return the spending policies for the wallet's descriptor

+

pub fn public_descriptor(
    &self,
    keychain: KeychainKind
) -> Result<Option<ExtendedDescriptor>, Error>
[src]

Return the "public" version of the wallet's descriptor, meaning a new descriptor that has +the same structure but with every secret key removed

+

This can be used to build a watch-only version of a wallet

+

pub fn finalize_psbt(
    &self,
    psbt: PSBT,
    assume_height: Option<u32>
) -> Result<(PSBT, bool), Error>
[src]

Try to finalize a PSBT

+

pub fn secp_ctx(&self) -> &Secp256k1<All>[src]

Return the secp256k1 context used for all signing operations

+

impl<B, D> Wallet<B, D> where
    B: Blockchain,
    D: BatchDatabase
[src]

pub fn new<E: ToWalletDescriptor>(
    descriptor: E,
    change_descriptor: Option<E>,
    network: Network,
    database: D,
    client: B
) -> Result<Self, Error>
[src]

Create a new "online" wallet

+

pub fn sync<P: 'static + Progress>(
    &self,
    progress_update: P,
    max_address_param: Option<u32>
) -> Result<(), Error>
[src]

Sync the internal database with the blockchain

+

pub fn client(&self) -> Option<&B>[src]

Return a reference to the internal blockchain client

+

pub fn network(&self) -> Network[src]

Get the Bitcoin network the wallet is using.

+

pub fn broadcast(&self, tx: Transaction) -> Result<Txid, Error>[src]

Broadcast a transaction to the network

+

Auto Trait Implementations

impl<B, D> !RefUnwindSafe for Wallet<B, D>[src]

impl<B, D> Send for Wallet<B, D> where
    B: Send,
    D: Send
[src]

impl<B, D> !Sync for Wallet<B, D>[src]

impl<B, D> Unpin for Wallet<B, D> where
    B: Unpin,
    D: Unpin
[src]

impl<B, D> !UnwindSafe for Wallet<B, D>[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/time/fn.get_timestamp.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/time/fn.get_timestamp.html new file mode 100644 index 0000000000..7d78ed14eb --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/time/fn.get_timestamp.html @@ -0,0 +1,5 @@ +bdk::wallet::time::get_timestamp - Rust + +

[][src]Function bdk::wallet::time::get_timestamp

pub fn get_timestamp() -> u64

Return the current timestamp in seconds

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/time/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/time/index.html new file mode 100644 index 0000000000..29b8cd1da8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/time/index.html @@ -0,0 +1,11 @@ +bdk::wallet::time - Rust + +

[][src]Module bdk::wallet::time

Cross-platform time

+

This module provides a function to get the current timestamp that works on all the platforms +supported by the library.

+

It can be useful to compare it with the timestamps found in +TransactionDetails.

+

Functions

+
get_timestamp

Return the current timestamp in seconds

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/time/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/time/sidebar-items.js new file mode 100644 index 0000000000..22164ef49f --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/time/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["get_timestamp","Return the current timestamp in seconds"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/trait.IsDust.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/trait.IsDust.html new file mode 100644 index 0000000000..dade076dc1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/trait.IsDust.html @@ -0,0 +1,8 @@ +bdk::wallet::IsDust - Rust + +

[][src]Trait bdk::wallet::IsDust

pub trait IsDust {
+    pub fn is_dust(&self) -> bool;
+}

Trait to check if a value is below the dust limit

+

Required methods

pub fn is_dust(&self) -> bool[src]

Check whether or not a value is below dust limit

+
Loading content...

Implementations on Foreign Types

impl IsDust for u64[src]

Loading content...

Implementors

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/enum.ChangeSpendPolicy.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/enum.ChangeSpendPolicy.html new file mode 100644 index 0000000000..2bfd8fc4f6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/enum.ChangeSpendPolicy.html @@ -0,0 +1,63 @@ +bdk::wallet::tx_builder::ChangeSpendPolicy - Rust + +

[][src]Enum bdk::wallet::tx_builder::ChangeSpendPolicy

pub enum ChangeSpendPolicy {
+    ChangeAllowed,
+    OnlyChange,
+    ChangeForbidden,
+}

Policy regarding the use of change outputs when creating a transaction

+

+ Variants

+
ChangeAllowed

Use both change and non-change outputs (default)

+
OnlyChange

Only use change outputs (see TxBuilder::only_spend_change)

+
ChangeForbidden

Only use non-change outputs (see TxBuilder::do_not_spend_change)

+

Trait Implementations

impl Clone for ChangeSpendPolicy[src]

impl Copy for ChangeSpendPolicy[src]

impl Debug for ChangeSpendPolicy[src]

impl Default for ChangeSpendPolicy[src]

impl Eq for ChangeSpendPolicy[src]

impl Hash for ChangeSpendPolicy[src]

impl Ord for ChangeSpendPolicy[src]

impl PartialEq<ChangeSpendPolicy> for ChangeSpendPolicy[src]

impl PartialOrd<ChangeSpendPolicy> for ChangeSpendPolicy[src]

impl StructuralEq for ChangeSpendPolicy[src]

impl StructuralPartialEq for ChangeSpendPolicy[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/enum.TxOrdering.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/enum.TxOrdering.html new file mode 100644 index 0000000000..26672be49f --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/enum.TxOrdering.html @@ -0,0 +1,64 @@ +bdk::wallet::tx_builder::TxOrdering - Rust + +

[][src]Enum bdk::wallet::tx_builder::TxOrdering

pub enum TxOrdering {
+    Shuffle,
+    Untouched,
+    BIP69Lexicographic,
+}

Ordering of the transaction's inputs and outputs

+

+ Variants

+
Shuffle

Randomized (default)

+
Untouched

Unchanged

+
BIP69Lexicographic

BIP69 / Lexicographic

+

Implementations

impl TxOrdering[src]

pub fn sort_tx(&self, tx: &mut Transaction)[src]

Sort transaction inputs and outputs by TxOrdering variant

+

Trait Implementations

impl Clone for TxOrdering[src]

impl Copy for TxOrdering[src]

impl Debug for TxOrdering[src]

impl Default for TxOrdering[src]

impl Eq for TxOrdering[src]

impl Hash for TxOrdering[src]

impl Ord for TxOrdering[src]

impl PartialEq<TxOrdering> for TxOrdering[src]

impl PartialOrd<TxOrdering> for TxOrdering[src]

impl StructuralEq for TxOrdering[src]

impl StructuralPartialEq for TxOrdering[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<Q, K> Equivalent<K> for Q where
    K: Borrow<Q> + ?Sized,
    Q: Eq + ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/index.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/index.html new file mode 100644 index 0000000000..ae1593ff1b --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/index.html @@ -0,0 +1,23 @@ +bdk::wallet::tx_builder - Rust + +

[][src]Module bdk::wallet::tx_builder

Transaction builder

+

Example

+
+// Create a transaction with one output to `to_address` of 50_000 satoshi, with a custom fee rate
+// of 5.0 satoshi/vbyte, only spending non-change outputs and with RBF signaling
+// enabled
+let builder = TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
+    .fee_rate(FeeRate::from_sat_per_vb(5.0))
+    .do_not_spend_change()
+    .enable_rbf();
+

Structs

+
BumpFee

Wallet::bump_fee context

+
CreateTx

Wallet::create_tx context

+
TxBuilder

A transaction builder

+

Enums

+
ChangeSpendPolicy

Policy regarding the use of change outputs when creating a transaction

+
TxOrdering

Ordering of the transaction's inputs and outputs

+

Traits

+
TxBuilderContext

Context in which the TxBuilder is valid

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/sidebar-items.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/sidebar-items.js new file mode 100644 index 0000000000..76461e4a13 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["ChangeSpendPolicy","Policy regarding the use of change outputs when creating a transaction"],["TxOrdering","Ordering of the transaction's inputs and outputs"]],"struct":[["BumpFee","`Wallet::bump_fee` context"],["CreateTx","`Wallet::create_tx` context"],["TxBuilder","A transaction builder"]],"trait":[["TxBuilderContext","Context in which the [`TxBuilder`] is valid"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.BumpFee.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.BumpFee.html new file mode 100644 index 0000000000..f7a5030e23 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.BumpFee.html @@ -0,0 +1,37 @@ +bdk::wallet::tx_builder::BumpFee - Rust + +

[][src]Struct bdk::wallet::tx_builder::BumpFee

pub struct BumpFee;

Trait Implementations

impl Clone for BumpFee[src]

impl Debug for BumpFee[src]

impl Default for BumpFee[src]

impl TxBuilderContext for BumpFee[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.CreateTx.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.CreateTx.html new file mode 100644 index 0000000000..e333ecd81b --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.CreateTx.html @@ -0,0 +1,37 @@ +bdk::wallet::tx_builder::CreateTx - Rust + +

[][src]Struct bdk::wallet::tx_builder::CreateTx

pub struct CreateTx;

Trait Implementations

impl Clone for CreateTx[src]

impl Debug for CreateTx[src]

impl Default for CreateTx[src]

impl TxBuilderContext for CreateTx[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.TxBuilder.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.TxBuilder.html new file mode 100644 index 0000000000..dfad991d27 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/struct.TxBuilder.html @@ -0,0 +1,152 @@ +bdk::wallet::tx_builder::TxBuilder - Rust + +

[][src]Struct bdk::wallet::tx_builder::TxBuilder

pub struct TxBuilder<D: Database, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext> { /* fields omitted */ }

A transaction builder

+

This structure contains the configuration that the wallet must follow to build a transaction.

+

For an example see this module's documentation;

+

Implementations

impl<D: Database, Ctx: TxBuilderContext> TxBuilder<D, DefaultCoinSelectionAlgorithm, Ctx>[src]

pub fn new() -> Self[src]

Create an empty builder

+

impl<D: Database, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext> TxBuilder<D, Cs, Ctx>[src]

pub fn fee_rate(self, fee_rate: FeeRate) -> Self[src]

Set a custom fee rate

+

pub fn fee_absolute(self, fee_amount: u64) -> Self[src]

Set an absolute fee

+

pub fn policy_path(
    self,
    policy_path: BTreeMap<String, Vec<usize>>,
    keychain: KeychainKind
) -> Self
[src]

Set the policy path to use while creating the transaction for a given keychain.

+

This method accepts a map where the key is the policy node id (see +Policy::id) and the value is the list of the indexes of +the items that are intended to be satisfied from the policy node (see +SatisfiableItem::Thresh::items).

+

Example

+

An example of when the policy path is needed is the following descriptor: +wsh(thresh(2,pk(A),sj:and_v(v:pk(B),n:older(6)),snj:and_v(v:pk(C),after(630000)))), +derived from the miniscript policy thresh(2,pk(A),and(pk(B),older(6)),and(pk(C),after(630000))). +It declares three descriptor fragments, and at the top level it uses thresh() to +ensure that at least two of them are satisfied. The individual fragments are:

+
    +
  1. pk(A)
  2. +
  3. and(pk(B),older(6))
  4. +
  5. and(pk(C),after(630000))
  6. +
+

When those conditions are combined in pairs, it's clear that the transaction needs to be created +differently depending on how the user intends to satisfy the policy afterwards:

+
    +
  • If fragments 1 and 2 are used, the transaction will need to use a specific +n_sequence in order to spend an OP_CSV branch.
  • +
  • If fragments 1 and 3 are used, the transaction will need to use a specific locktime +in order to spend an OP_CLTV branch.
  • +
  • If fragments 2 and 3 are used, the transaction will need both.
  • +
+

When the spending policy is represented as a tree (see +Wallet::policies), every node +is assigned a unique identifier that can be used in the policy path to specify which of +the node's children the user intends to satisfy: for instance, assuming the thresh() +root node of this example has an id of aabbccdd, the policy path map would look like:

+

{ "aabbccdd" => [0, 1] }

+

where the key is the node's id, and the value is a list of the children that should be +used, in no particular order.

+

If a particularly complex descriptor has multiple ambiguous thresholds in its structure, +multiple entries can be added to the map, one for each node that requires an explicit path.

+ +
+let mut path = BTreeMap::new();
+path.insert("aabbccdd".to_string(), vec![0, 1]);
+
+let builder = TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
+    .policy_path(path, KeychainKind::External);
+

pub fn utxos(self, utxos: Vec<OutPoint>) -> Self[src]

Replace the internal list of utxos that must be spent with a new list

+

These have priority over the "unspendable" utxos, meaning that if a utxo is present both in +the "utxos" and the "unspendable" list, it will be spent.

+

pub fn add_utxo(self, utxo: OutPoint) -> Self[src]

Add a utxo to the internal list of utxos that must be spent

+

These have priority over the "unspendable" utxos, meaning that if a utxo is present both in +the "utxos" and the "unspendable" list, it will be spent.

+

pub fn manually_selected_only(self) -> Self[src]

Only spend utxos added by add_utxo and utxos.

+

The wallet will not add additional utxos to the transaction even if they are needed to +make the transaction valid.

+

pub fn unspendable(self, unspendable: Vec<OutPoint>) -> Self[src]

Replace the internal list of unspendable utxos with a new list

+

It's important to note that the "must-be-spent" utxos added with TxBuilder::utxos and +TxBuilder::add_utxo have priority over these. See the docs of the two linked methods +for more details.

+

pub fn add_unspendable(self, unspendable: OutPoint) -> Self[src]

Add a utxo to the internal list of unspendable utxos

+

It's important to note that the "must-be-spent" utxos added with TxBuilder::utxos and +TxBuilder::add_utxo have priority over this. See the docs of the two linked methods +for more details.

+

pub fn sighash(self, sighash: SigHashType) -> Self[src]

Sign with a specific sig hash

+

Use this option very carefully

+

pub fn ordering(self, ordering: TxOrdering) -> Self[src]

Choose the ordering for inputs and outputs of the transaction

+

pub fn nlocktime(self, locktime: u32) -> Self[src]

Use a specific nLockTime while creating the transaction

+

This can cause conflicts if the wallet's descriptors contain an "after" (OP_CLTV) operator.

+

pub fn version(self, version: i32) -> Self[src]

Build a transaction with a specific version

+

The version should always be greater than 0 and greater than 1 if the wallet's +descriptors contain an "older" (OP_CSV) operator.

+

pub fn do_not_spend_change(self) -> Self[src]

Do not spend change outputs

+

This effectively adds all the change outputs to the "unspendable" list. See +TxBuilder::unspendable.

+

pub fn only_spend_change(self) -> Self[src]

Only spend change outputs

+

This effectively adds all the non-change outputs to the "unspendable" list. See +TxBuilder::unspendable.

+

pub fn change_policy(self, change_policy: ChangeSpendPolicy) -> Self[src]

pub fn force_non_witness_utxo(self) -> Self[src]

Fill-in the psbt::Input::non_witness_utxo field even if the wallet only has SegWit +descriptors.

+

This is useful for signers which always require it, like Trezor hardware wallets.

+

pub fn include_output_redeem_witness_script(self) -> Self[src]

Fill-in the psbt::Output::redeem_script and +psbt::Output::witness_script fields.

+

This is useful for signers which always require it, like ColdCard hardware wallets.

+

pub fn add_global_xpubs(self) -> Self[src]

Fill-in the PSBT_GLOBAL_XPUB field with the extended keys contained in both the external +and internal descriptors

+

This is useful for offline signers that take part to a multisig. Some hardware wallets like +BitBox and ColdCard are known to require this.

+

pub fn drain_wallet(self) -> Self[src]

Spend all the available inputs. This respects filters like TxBuilder::unspendable and the change policy.

+

pub fn coin_selection<P: CoinSelectionAlgorithm<D>>(
    self,
    coin_selection: P
) -> TxBuilder<D, P, Ctx>
[src]

Choose the coin selection algorithm

+

Overrides the DefaultCoinSelectionAlgorithm.

+

impl<D: Database> TxBuilder<D, DefaultCoinSelectionAlgorithm, CreateTx>[src]

pub fn with_recipients(recipients: Vec<(Script, u64)>) -> Self[src]

Create a builder starting from a list of recipients

+

impl<D: Database, Cs: CoinSelectionAlgorithm<D>> TxBuilder<D, Cs, CreateTx>[src]

pub fn set_recipients(self, recipients: Vec<(Script, u64)>) -> Self[src]

Replace the recipients already added with a new list

+

pub fn add_recipient(self, script_pubkey: Script, amount: u64) -> Self[src]

Add a recipient to the internal list

+

pub fn set_single_recipient(self, recipient: Script) -> Self[src]

Set a single recipient that will get all the selected funds minus the fee. No change will +be created

+

This method overrides any recipient set with set_recipients or +add_recipient.

+

It can only be used in conjunction with drain_wallet to send the +entire content of the wallet (minus filters) to a single recipient or with a +list of manually selected UTXOs by enabling manually_selected_only +and selecting them with utxos or add_utxo.

+

When bumping the fees of a transaction made with this option, the user should remeber to +add maintain_single_recipient to correctly update the +single output instead of adding one more for the change.

+

pub fn enable_rbf(self) -> Self[src]

Enable signaling RBF

+

This will use the default nSequence value of 0xFFFFFFFD.

+

pub fn enable_rbf_with_sequence(self, nsequence: u32) -> Self[src]

Enable signaling RBF with a specific nSequence value

+

This can cause conflicts if the wallet's descriptors contain an "older" (OP_CSV) operator +and the given nsequence is lower than the CSV value.

+

If the nsequence is higher than 0xFFFFFFFD an error will be thrown, since it would not +be a valid nSequence to signal RBF.

+

impl<D: Database> TxBuilder<D, DefaultCoinSelectionAlgorithm, BumpFee>[src]

pub fn maintain_single_recipient(self) -> Self[src]

Bump the fees of a transaction made with set_single_recipient

+

Unless extra inputs are specified with add_utxo or utxos, this flag will make +bump_fee reduce the value of the existing output, or fail if it would be consumed +entirely given the higher new fee rate.

+

If extra inputs are added and they are not entirely consumed in fees, a change output will not +be added; the existing output will simply grow in value.

+

Fails if the transaction has more than one outputs.

+

Trait Implementations

impl<D: Debug + Database, Cs: Debug + CoinSelectionAlgorithm<D>, Ctx: Debug + TxBuilderContext> Debug for TxBuilder<D, Cs, Ctx>[src]

impl<D: Database, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext> Default for TxBuilder<D, Cs, Ctx> where
    Cs: Default
[src]

Auto Trait Implementations

impl<D, Cs, Ctx> RefUnwindSafe for TxBuilder<D, Cs, Ctx> where
    Cs: RefUnwindSafe,
    Ctx: RefUnwindSafe,
    D: RefUnwindSafe
[src]

impl<D, Cs, Ctx> Send for TxBuilder<D, Cs, Ctx> where
    Cs: Send,
    Ctx: Send,
    D: Send
[src]

impl<D, Cs, Ctx> Sync for TxBuilder<D, Cs, Ctx> where
    Cs: Sync,
    Ctx: Sync,
    D: Sync
[src]

impl<D, Cs, Ctx> Unpin for TxBuilder<D, Cs, Ctx> where
    Cs: Unpin,
    Ctx: Unpin,
    D: Unpin
[src]

impl<D, Cs, Ctx> UnwindSafe for TxBuilder<D, Cs, Ctx> where
    Cs: UnwindSafe,
    Ctx: UnwindSafe,
    D: UnwindSafe
[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T> Instrument for T[src]

impl<T> Instrument for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

+

impl<T> Same<T> for T

type Output = T

Should always be Self

+

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

+

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

+

impl<V, T> VZip<V> for T where
    V: MultiLane<T>, 

\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/trait.TxBuilderContext.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/trait.TxBuilderContext.html new file mode 100644 index 0000000000..081df97ad3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/tx_builder/trait.TxBuilderContext.html @@ -0,0 +1,5 @@ +bdk::wallet::tx_builder::TxBuilderContext - Rust + +

[][src]Trait bdk::wallet::tx_builder::TxBuilderContext

pub trait TxBuilderContext: Debug + Default + Clone { }

Context in which the TxBuilder is valid

+

Implementors

impl TxBuilderContext for BumpFee[src]

impl TxBuilderContext for CreateTx[src]

Loading content...
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/type.OfflineWallet.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/type.OfflineWallet.html new file mode 100644 index 0000000000..cdc5549ea9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/type.OfflineWallet.html @@ -0,0 +1,5 @@ +bdk::wallet::OfflineWallet - Rust + +

[][src]Type Definition bdk::wallet::OfflineWallet

type OfflineWallet<D> = Wallet<OfflineBlockchain, D>;

Type alias for a Wallet that uses OfflineBlockchain

+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/utils/trait.IsDust.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/utils/trait.IsDust.html new file mode 100644 index 0000000000..71ab5675d6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/bdk/wallet/utils/trait.IsDust.html @@ -0,0 +1,10 @@ + + + + + + +

Redirecting to ../../../bdk/wallet/trait.IsDust.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/brush.svg b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/brush.svg new file mode 100644 index 0000000000..ea266e856a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/brush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/dark.css b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/dark.css new file mode 100644 index 0000000000..774d43d747 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/dark.css @@ -0,0 +1 @@ +body{background-color:#353535;color:#ddd;}h1,h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod){color:#ddd;}h1.fqn{border-bottom-color:#d2d2d2;}h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod){border-bottom-color:#d2d2d2;}.in-band{background-color:#353535;}.invisible{background:rgba(0,0,0,0);}.docblock code,.docblock-short code{background-color:#2A2A2A;}pre{background-color:#2A2A2A;}.sidebar{background-color:#505050;}.logo-container.rust-logo>img{filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff)}*{scrollbar-color:rgb(64,65,67) #717171;}.sidebar{scrollbar-color:rgba(32,34,37,.6) transparent;}::-webkit-scrollbar-track{background-color:#717171;}::-webkit-scrollbar-thumb{background-color:rgba(32,34,37,.6);}.sidebar::-webkit-scrollbar-track{background-color:#717171;}.sidebar::-webkit-scrollbar-thumb{background-color:rgba(32,34,37,.6);}.sidebar .current{background-color:#333;}.source .sidebar{background-color:#353535;}.sidebar .location{border-color:#fff;background:#575757;color:#DDD;}.sidebar .version{border-bottom-color:#DDD;}.sidebar-title{border-top-color:#777;border-bottom-color:#777;}.block a:hover{background:#444;}.line-numbers span{color:#3B91E2;}.line-numbers .line-highlighted{background-color:#0a042f !important;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5{border-bottom-color:#DDD;}.docblock table,.docblock table td,.docblock table th{border-color:#ddd;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#ddd;}.content .highlighted{color:#eee !important;background-color:#616161;}.content .highlighted a,.content .highlighted span{color:#eee !important;}.content .highlighted.trait{background-color:#013191;}.content .highlighted.traitalias{background-color:#013191;}.content .highlighted.mod,.content .highlighted.externcrate{background-color:#afc6e4;}.content .highlighted.mod{background-color:#803a1b;}.content .highlighted.externcrate{background-color:#396bac;}.content .highlighted.enum{background-color:#5b4e68;}.content .highlighted.struct{background-color:#194e9f;}.content .highlighted.union{background-color:#b7bd49;}.content .highlighted.fn,.content .highlighted.method,.content .highlighted.tymethod{background-color:#4950ed;}.content .highlighted.type{background-color:#38902c;}.content .highlighted.foreigntype{background-color:#b200d6;}.content .highlighted.attr,.content .highlighted.derive,.content .highlighted.macro{background-color:#217d1c;}.content .highlighted.constant,.content .highlighted.static{background-color:#0063cc;}.content .highlighted.primitive{background-color:#00708a;}.content .highlighted.keyword{background-color:#884719;}.content .item-info::before{color:#ccc;}.content span.enum,.content a.enum,.block a.current.enum{color:#82b089;}.content span.struct,.content a.struct,.block a.current.struct{color:#2dbfb8;}.content span.type,.content a.type,.block a.current.type{color:#ff7f00;}.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype{color:#dd7de8;}.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro{color:#09bd00;}.content span.union,.content a.union,.block a.current.union{color:#a6ae37;}.content span.constant,.content a.constant,.block a.current.constant,.content span.static,.content a.static,.block a.current.static{color:#82a5c9;}.content span.primitive,.content a.primitive,.block a.current.primitive{color:#43aec7;}.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod{color:#bda000;}.content span.trait,.content a.trait,.block a.current.trait{color:#b78cf2;}.content span.traitalias,.content a.traitalias,.block a.current.traitalias{color:#b397da;}.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,.content .fnname{color:#2BAB63;}.content span.keyword,.content a.keyword,.block a.current.keyword{color:#de5249;}pre.rust .comment{color:#8d8d8b;}pre.rust .doccomment{color:#8ca375;}nav:not(.sidebar){border-bottom-color:#4e4e4e;}nav.main .current{border-top-color:#eee;border-bottom-color:#eee;}nav.main .separator{border-color:#eee;}a{color:#ddd;}.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),.docblock-short a:not(.srclink):not(.test-arrow),.item-info a,#help a{color:#D2991D;}a.test-arrow{color:#dedede;}.collapse-toggle{color:#999;}#crate-search{color:#111;background-color:#f0f0f0;border-color:#000;box-shadow:0 0 0 1px #000,0 0 0 2px transparent;}.search-input{color:#111;background-color:#f0f0f0;box-shadow:0 0 0 1px #000,0 0 0 2px transparent;}.search-input:focus{border-color:#008dfd;}.search-focus:disabled{background-color:#c5c4c4;}#crate-search+.search-input:focus{box-shadow:0 0 8px 4px #078dd8;}.module-item .stab{color:#ddd;}.stab.unstable{background:#FFF5D6;border-color:#FFC600;color:#2f2f2f;}.stab.deprecated{background:#F3DFFF;border-color:#7F0087;color:#2f2f2f;}.stab.portability{background:#C4ECFF;border-color:#7BA5DB;color:#2f2f2f;}.stab.portability>code{color:#ddd;}#help>div{background:#4d4d4d;border-color:#bfbfbf;}#help>div>span{border-bottom-color:#bfbfbf;}#help dt{border-color:#bfbfbf;background:rgba(0,0,0,0);color:black;}.since{color:grey;}tr.result span.primitive::after,tr.result span.keyword::after{color:#ddd;}.line-numbers :target{background-color:transparent;}pre.rust .kw{color:#ab8ac1;}pre.rust .kw-2,pre.rust .prelude-ty{color:#769acb;}pre.rust .number,pre.rust .string{color:#83a300;}pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,pre.rust .attribute .ident{color:#ee6868;}pre.rust .macro,pre.rust .macro-nonterminal{color:#3E999F;}pre.rust .lifetime{color:#d97f26;}pre.rust .question-mark{color:#ff9011;}.example-wrap>pre.line-number{border-color:#4a4949;}a.test-arrow{background-color:rgba(78,139,202,0.2);}a.test-arrow:hover{background-color:#4e8bca;}.toggle-label{color:#999;}:target>code,:target>.in-band{background-color:#494a3d;border-right:3px solid #bb7410;}pre.compile_fail{border-left:2px solid rgba(255,0,0,.8);}pre.compile_fail:hover,.information:hover+pre.compile_fail{border-left:2px solid #f00;}pre.should_panic{border-left:2px solid rgba(255,0,0,.8);}pre.should_panic:hover,.information:hover+pre.should_panic{border-left:2px solid #f00;}pre.ignore{border-left:2px solid rgba(255,142,0,.6);}pre.ignore:hover,.information:hover+pre.ignore{border-left:2px solid #ff9200;}.tooltip.compile_fail{color:rgba(255,0,0,.8);}.information>.compile_fail:hover{color:#f00;}.tooltip.should_panic{color:rgba(255,0,0,.8);}.information>.should_panic:hover{color:#f00;}.tooltip.ignore{color:rgba(255,142,0,.6);}.information>.ignore:hover{color:#ff9200;}.search-failed a{color:#0089ff;}.tooltip .tooltiptext{background-color:#000;color:#fff;border-color:#000;}.tooltip .tooltiptext::after{border-color:transparent black transparent transparent;}.notable-traits-tooltiptext{background-color:#111;border-color:#777;}#titles>button:not(.selected){background-color:#252525;border-top-color:#252525;}#titles>button:hover,#titles>button.selected{border-top-color:#0089ff;background-color:#353535;}#titles>button>div.count{color:#888;}@media (max-width:700px){.sidebar-menu{background-color:#505050;border-bottom-color:#e0e0e0;border-right-color:#e0e0e0;}.sidebar-elems{background-color:#505050;border-right-color:#000;}#sidebar-filler{background-color:#505050;border-bottom-color:#e0e0e0;}}kbd{color:#000;background-color:#fafbfc;border-color:#d1d5da;border-bottom-color:#c6cbd1;box-shadow-color:#c6cbd1;}#theme-picker,#settings-menu,.help-button{border-color:#e0e0e0;background:#f0f0f0;color:#000;}#theme-picker:hover,#theme-picker:focus,#settings-menu:hover,#settings-menu:focus,.help-button:hover,.help-button:focus{border-color:#ffb900;}#theme-choices{border-color:#e0e0e0;background-color:#353535;}#theme-choices>button:not(:first-child){border-top-color:#e0e0e0;}#theme-choices>button:hover,#theme-choices>button:focus{background-color:#4e4e4e;}@media (max-width:700px){#theme-picker{background:#f0f0f0;}}#all-types{background-color:#505050;}#all-types:hover{background-color:#606060;}.search-results td span.alias{color:#fff;}.search-results td span.grey{color:#ccc;}#sidebar-toggle{background-color:#565656;}#sidebar-toggle:hover{background-color:#676767;}#source-sidebar{background-color:#565656;}#source-sidebar>.title{border-bottom-color:#ccc;}div.files>a:hover,div.name:hover{background-color:#444;}div.files>.selected{background-color:#333;}.setting-line>.title{border-bottom-color:#ddd;} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/down-arrow.svg b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/down-arrow.svg new file mode 100644 index 0000000000..35437e77a7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/down-arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/favicon-16x16.png b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/favicon-16x16.png new file mode 100644 index 0000000000..7cfe6c1355 Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/favicon-16x16.png differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/favicon-32x32.png b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/favicon-32x32.png new file mode 100644 index 0000000000..5109c1de8b Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/favicon-32x32.png differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/favicon.svg b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/favicon.svg new file mode 100644 index 0000000000..8b34b51198 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/favicon.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/alloc/string/trait.ToString.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/alloc/string/trait.ToString.js new file mode 100644 index 0000000000..5f6129873e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/alloc/string/trait.ToString.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl ToString for WalletExport","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.Blockchain.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.Blockchain.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.Blockchain.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.BlockchainMarker.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.BlockchainMarker.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.BlockchainMarker.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.ConfigurableBlockchain.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.ConfigurableBlockchain.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.ConfigurableBlockchain.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.Progress.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.Progress.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/blockchain/trait.Progress.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.BatchDatabase.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.BatchDatabase.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.BatchDatabase.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.BatchOperations.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.BatchOperations.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.BatchOperations.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.ConfigurableDatabase.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.ConfigurableDatabase.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.ConfigurableDatabase.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.Database.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.Database.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/database/trait.Database.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/template/trait.DescriptorTemplate.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/template/trait.DescriptorTemplate.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/template/trait.DescriptorTemplate.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.ExtractPolicy.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.ExtractPolicy.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.ExtractPolicy.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.MiniscriptKey.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.MiniscriptKey.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.MiniscriptKey.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.ToPublicKey.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.ToPublicKey.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.ToPublicKey.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.ToWalletDescriptor.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.ToWalletDescriptor.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/descriptor/trait.ToWalletDescriptor.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.DerivableKey.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.DerivableKey.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.DerivableKey.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.ExtScriptContext.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.ExtScriptContext.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.ExtScriptContext.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.GeneratableDefaultOptions.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.GeneratableDefaultOptions.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.GeneratableDefaultOptions.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.GeneratableKey.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.GeneratableKey.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.GeneratableKey.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.ScriptContext.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.ScriptContext.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.ScriptContext.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.ToDescriptorKey.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.ToDescriptorKey.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/keys/trait.ToDescriptorKey.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/signer/trait.Signer.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/signer/trait.Signer.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/signer/trait.Signer.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/trait.IsDust.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/trait.IsDust.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/trait.IsDust.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/tx_builder/trait.TxBuilderContext.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/tx_builder/trait.TxBuilderContext.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/bdk/wallet/tx_builder/trait.TxBuilderContext.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/clone/trait.Clone.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/clone/trait.Clone.js new file mode 100644 index 0000000000..a7ef0cbabd --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/clone/trait.Clone.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Clone for Capability","synthetic":false,"types":[]},{"text":"impl Clone for NoopProgress","synthetic":false,"types":[]},{"text":"impl Clone for LogProgress","synthetic":false,"types":[]},{"text":"impl Clone for PKOrF","synthetic":false,"types":[]},{"text":"impl Clone for SatisfiableItem","synthetic":false,"types":[]},{"text":"impl Clone for Satisfaction","synthetic":false,"types":[]},{"text":"impl Clone for Policy","synthetic":false,"types":[]},{"text":"impl Clone for Condition","synthetic":false,"types":[]},{"text":"impl Clone for ScriptContextEnum","synthetic":false,"types":[]},{"text":"impl Clone for PrivateKeyGenerateOptions","synthetic":false,"types":[]},{"text":"impl Clone for KeychainKind","synthetic":false,"types":[]},{"text":"impl Clone for FeeRate","synthetic":false,"types":[]},{"text":"impl Clone for UTXO","synthetic":false,"types":[]},{"text":"impl Clone for TransactionDetails","synthetic":false,"types":[]},{"text":"impl Clone for AddressValidatorError","synthetic":false,"types":[]},{"text":"impl Clone for SignerId","synthetic":false,"types":[]},{"text":"impl Clone for SignerError","synthetic":false,"types":[]},{"text":"impl Clone for SignerOrdering","synthetic":false,"types":[]},{"text":"impl Clone for SignersContainer","synthetic":false,"types":[]},{"text":"impl Clone for CreateTx","synthetic":false,"types":[]},{"text":"impl Clone for BumpFee","synthetic":false,"types":[]},{"text":"impl Clone for TxOrdering","synthetic":false,"types":[]},{"text":"impl Clone for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.Eq.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.Eq.js new file mode 100644 index 0000000000..7e8d7dc356 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.Eq.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Eq for Capability","synthetic":false,"types":[]},{"text":"impl Eq for Condition","synthetic":false,"types":[]},{"text":"impl Eq for ScriptContextEnum","synthetic":false,"types":[]},{"text":"impl Eq for KeychainKind","synthetic":false,"types":[]},{"text":"impl Eq for UTXO","synthetic":false,"types":[]},{"text":"impl Eq for TransactionDetails","synthetic":false,"types":[]},{"text":"impl Eq for AddressValidatorError","synthetic":false,"types":[]},{"text":"impl Eq for SignerId","synthetic":false,"types":[]},{"text":"impl Eq for SignerError","synthetic":false,"types":[]},{"text":"impl Eq for SignerOrdering","synthetic":false,"types":[]},{"text":"impl Eq for TxOrdering","synthetic":false,"types":[]},{"text":"impl Eq for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.Ord.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.Ord.js new file mode 100644 index 0000000000..66d7a0f62f --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.Ord.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Ord for Condition","synthetic":false,"types":[]},{"text":"impl Ord for SignerId","synthetic":false,"types":[]},{"text":"impl Ord for SignerOrdering","synthetic":false,"types":[]},{"text":"impl Ord for TxOrdering","synthetic":false,"types":[]},{"text":"impl Ord for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.PartialEq.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.PartialEq.js new file mode 100644 index 0000000000..31a908a5b9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.PartialEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl PartialEq<Capability> for Capability","synthetic":false,"types":[]},{"text":"impl PartialEq<Condition> for Condition","synthetic":false,"types":[]},{"text":"impl PartialEq<ScriptContextEnum> for ScriptContextEnum","synthetic":false,"types":[]},{"text":"impl PartialEq<KeychainKind> for KeychainKind","synthetic":false,"types":[]},{"text":"impl PartialEq<FeeRate> for FeeRate","synthetic":false,"types":[]},{"text":"impl PartialEq<UTXO> for UTXO","synthetic":false,"types":[]},{"text":"impl PartialEq<TransactionDetails> for TransactionDetails","synthetic":false,"types":[]},{"text":"impl PartialEq<AddressValidatorError> for AddressValidatorError","synthetic":false,"types":[]},{"text":"impl PartialEq<SignerId> for SignerId","synthetic":false,"types":[]},{"text":"impl PartialEq<SignerError> for SignerError","synthetic":false,"types":[]},{"text":"impl PartialEq<SignerOrdering> for SignerOrdering","synthetic":false,"types":[]},{"text":"impl PartialEq<TxOrdering> for TxOrdering","synthetic":false,"types":[]},{"text":"impl PartialEq<ChangeSpendPolicy> for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.PartialOrd.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.PartialOrd.js new file mode 100644 index 0000000000..dd7d82b585 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/cmp/trait.PartialOrd.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl PartialOrd<Condition> for Condition","synthetic":false,"types":[]},{"text":"impl PartialOrd<FeeRate> for FeeRate","synthetic":false,"types":[]},{"text":"impl PartialOrd<SignerId> for SignerId","synthetic":false,"types":[]},{"text":"impl PartialOrd<SignerOrdering> for SignerOrdering","synthetic":false,"types":[]},{"text":"impl PartialOrd<TxOrdering> for TxOrdering","synthetic":false,"types":[]},{"text":"impl PartialOrd<ChangeSpendPolicy> for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/convert/trait.AsRef.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/convert/trait.AsRef.js new file mode 100644 index 0000000000..5b2db4abf7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/convert/trait.AsRef.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl AsRef<[u8]> for KeychainKind","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/convert/trait.From.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/convert/trait.From.js new file mode 100644 index 0000000000..3d6411eda8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/convert/trait.From.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<AddressValidatorError> for Error","synthetic":false,"types":[]},{"text":"impl From<PolicyError> for Error","synthetic":false,"types":[]},{"text":"impl From<SignerError> for Error","synthetic":false,"types":[]},{"text":"impl From<KeyError> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<EsploraError> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<CompactFiltersError> for Error","synthetic":false,"types":[]},{"text":"impl From<ElectrumBlockchain> for AnyBlockchain","synthetic":false,"types":[]},{"text":"impl From<EsploraBlockchain> for AnyBlockchain","synthetic":false,"types":[]},{"text":"impl From<CompactFiltersBlockchain> for AnyBlockchain","synthetic":false,"types":[]},{"text":"impl From<ElectrumBlockchainConfig> for AnyBlockchainConfig","synthetic":false,"types":[]},{"text":"impl From<EsploraBlockchainConfig> for AnyBlockchainConfig","synthetic":false,"types":[]},{"text":"impl From<CompactFiltersBlockchainConfig> for AnyBlockchainConfig","synthetic":false,"types":[]},{"text":"impl From<Client> for ElectrumBlockchain","synthetic":false,"types":[]},{"text":"impl From<Error> for EsploraError","synthetic":false,"types":[]},{"text":"impl From<ParseIntError> for EsploraError","synthetic":false,"types":[]},{"text":"impl From<Error> for EsploraError","synthetic":false,"types":[]},{"text":"impl From<Error> for EsploraError","synthetic":false,"types":[]},{"text":"impl From<Error> for CompactFiltersError","synthetic":false,"types":[]},{"text":"impl From<Error> for CompactFiltersError","synthetic":false,"types":[]},{"text":"impl From<Error> for CompactFiltersError","synthetic":false,"types":[]},{"text":"impl From<SystemTimeError> for CompactFiltersError","synthetic":false,"types":[]},{"text":"impl From<Error> for CompactFiltersError","synthetic":false,"types":[]},{"text":"impl From<MemoryDatabase> for AnyDatabase","synthetic":false,"types":[]},{"text":"impl From<Tree> for AnyDatabase","synthetic":false,"types":[]},{"text":"impl From<<MemoryDatabase as BatchDatabase>::Batch> for AnyBatch","synthetic":false,"types":[]},{"text":"impl From<<Tree as BatchDatabase>::Batch> for AnyBatch","synthetic":false,"types":[]},{"text":"impl From<()> for AnyDatabaseConfig","synthetic":false,"types":[]},{"text":"impl From<SledDbConfiguration> for AnyDatabaseConfig","synthetic":false,"types":[]},{"text":"impl From<KeyError> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<Error> for Error","synthetic":false,"types":[]},{"text":"impl From<PolicyError> for Error","synthetic":false,"types":[]},{"text":"impl From<bool> for Satisfaction","synthetic":false,"types":[]},{"text":"impl From<SatisfiableItem> for Policy","synthetic":false,"types":[]},{"text":"impl From<Error> for KeyError","synthetic":false,"types":[]},{"text":"impl From<Error> for KeyError","synthetic":false,"types":[]},{"text":"impl From<Hash> for SignerId","synthetic":false,"types":[]},{"text":"impl From<Fingerprint> for SignerId","synthetic":false,"types":[]},{"text":"impl From<HashMap<DescriptorPublicKey, DescriptorSecretKey, RandomState>> for SignersContainer","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/default/trait.Default.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/default/trait.Default.js new file mode 100644 index 0000000000..748e3f274e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/default/trait.Default.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Default for Mempool","synthetic":false,"types":[]},{"text":"impl Default for MemoryDatabase","synthetic":false,"types":[]},{"text":"impl Default for PKOrF","synthetic":false,"types":[]},{"text":"impl Default for Condition","synthetic":false,"types":[]},{"text":"impl Default for PrivateKeyGenerateOptions","synthetic":false,"types":[]},{"text":"impl Default for FeeRate","synthetic":false,"types":[]},{"text":"impl Default for TransactionDetails","synthetic":false,"types":[]},{"text":"impl Default for LargestFirstCoinSelection","synthetic":false,"types":[]},{"text":"impl Default for BranchAndBoundCoinSelection","synthetic":false,"types":[]},{"text":"impl Default for SignerOrdering","synthetic":false,"types":[]},{"text":"impl Default for SignersContainer","synthetic":false,"types":[]},{"text":"impl Default for CreateTx","synthetic":false,"types":[]},{"text":"impl Default for BumpFee","synthetic":false,"types":[]},{"text":"impl<D: Database, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext> Default for TxBuilder<D, Cs, Ctx> where
    Cs: Default, 
","synthetic":false,"types":[]},{"text":"impl Default for TxOrdering","synthetic":false,"types":[]},{"text":"impl Default for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/fmt/trait.Debug.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/fmt/trait.Debug.js new file mode 100644 index 0000000000..b3638c12d9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/fmt/trait.Debug.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Debug for Error","synthetic":false,"types":[]},{"text":"impl Debug for AnyBlockchainConfig","synthetic":false,"types":[]},{"text":"impl Debug for ElectrumBlockchainConfig","synthetic":false,"types":[]},{"text":"impl Debug for EsploraBlockchain","synthetic":false,"types":[]},{"text":"impl Debug for EsploraBlockchainConfig","synthetic":false,"types":[]},{"text":"impl Debug for EsploraError","synthetic":false,"types":[]},{"text":"impl Debug for Mempool","synthetic":false,"types":[]},{"text":"impl Debug for Peer","synthetic":false,"types":[]},{"text":"impl Debug for CompactFiltersBlockchain","synthetic":false,"types":[]},{"text":"impl Debug for BitcoinPeerConfig","synthetic":false,"types":[]},{"text":"impl Debug for CompactFiltersBlockchainConfig","synthetic":false,"types":[]},{"text":"impl Debug for CompactFiltersError","synthetic":false,"types":[]},{"text":"impl Debug for Capability","synthetic":false,"types":[]},{"text":"impl Debug for AnyDatabase","synthetic":false,"types":[]},{"text":"impl Debug for SledDbConfiguration","synthetic":false,"types":[]},{"text":"impl Debug for AnyDatabaseConfig","synthetic":false,"types":[]},{"text":"impl Debug for MemoryDatabase","synthetic":false,"types":[]},{"text":"impl Debug for Error","synthetic":false,"types":[]},{"text":"impl Debug for PKOrF","synthetic":false,"types":[]},{"text":"impl Debug for SatisfiableItem","synthetic":false,"types":[]},{"text":"impl Debug for Satisfaction","synthetic":false,"types":[]},{"text":"impl Debug for Policy","synthetic":false,"types":[]},{"text":"impl Debug for Condition","synthetic":false,"types":[]},{"text":"impl Debug for PolicyError","synthetic":false,"types":[]},{"text":"impl<Ctx: Debug + ScriptContext> Debug for DescriptorKey<Ctx>","synthetic":false,"types":[]},{"text":"impl Debug for ScriptContextEnum","synthetic":false,"types":[]},{"text":"impl Debug for PrivateKeyGenerateOptions","synthetic":false,"types":[]},{"text":"impl Debug for KeyError","synthetic":false,"types":[]},{"text":"impl Debug for KeychainKind","synthetic":false,"types":[]},{"text":"impl Debug for FeeRate","synthetic":false,"types":[]},{"text":"impl Debug for UTXO","synthetic":false,"types":[]},{"text":"impl Debug for TransactionDetails","synthetic":false,"types":[]},{"text":"impl Debug for AddressValidatorError","synthetic":false,"types":[]},{"text":"impl Debug for CoinSelectionResult","synthetic":false,"types":[]},{"text":"impl Debug for LargestFirstCoinSelection","synthetic":false,"types":[]},{"text":"impl Debug for BranchAndBoundCoinSelection","synthetic":false,"types":[]},{"text":"impl Debug for WalletExport","synthetic":false,"types":[]},{"text":"impl Debug for SignerId","synthetic":false,"types":[]},{"text":"impl Debug for SignerError","synthetic":false,"types":[]},{"text":"impl Debug for SignerOrdering","synthetic":false,"types":[]},{"text":"impl Debug for SignersContainer","synthetic":false,"types":[]},{"text":"impl Debug for CreateTx","synthetic":false,"types":[]},{"text":"impl Debug for BumpFee","synthetic":false,"types":[]},{"text":"impl<D: Debug + Database, Cs: Debug + CoinSelectionAlgorithm<D>, Ctx: Debug + TxBuilderContext> Debug for TxBuilder<D, Cs, Ctx>","synthetic":false,"types":[]},{"text":"impl Debug for TxOrdering","synthetic":false,"types":[]},{"text":"impl Debug for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/fmt/trait.Display.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/fmt/trait.Display.js new file mode 100644 index 0000000000..ce37b5523e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/fmt/trait.Display.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Display for Error","synthetic":false,"types":[]},{"text":"impl Display for EsploraError","synthetic":false,"types":[]},{"text":"impl Display for CompactFiltersError","synthetic":false,"types":[]},{"text":"impl Display for Error","synthetic":false,"types":[]},{"text":"impl Display for PolicyError","synthetic":false,"types":[]},{"text":"impl Display for KeyError","synthetic":false,"types":[]},{"text":"impl Display for AddressValidatorError","synthetic":false,"types":[]},{"text":"impl Display for SignerError","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/hash/trait.Hash.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/hash/trait.Hash.js new file mode 100644 index 0000000000..64f360015e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/hash/trait.Hash.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Hash for Capability","synthetic":false,"types":[]},{"text":"impl Hash for Condition","synthetic":false,"types":[]},{"text":"impl Hash for KeychainKind","synthetic":false,"types":[]},{"text":"impl Hash for SignerId","synthetic":false,"types":[]},{"text":"impl Hash for TxOrdering","synthetic":false,"types":[]},{"text":"impl Hash for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Copy.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Copy.js new file mode 100644 index 0000000000..243d52c881 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Copy.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Copy for Capability","synthetic":false,"types":[]},{"text":"impl Copy for Condition","synthetic":false,"types":[]},{"text":"impl Copy for ScriptContextEnum","synthetic":false,"types":[]},{"text":"impl Copy for PrivateKeyGenerateOptions","synthetic":false,"types":[]},{"text":"impl Copy for KeychainKind","synthetic":false,"types":[]},{"text":"impl Copy for FeeRate","synthetic":false,"types":[]},{"text":"impl Copy for TxOrdering","synthetic":false,"types":[]},{"text":"impl Copy for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Freeze.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Freeze.js new file mode 100644 index 0000000000..d8ca791082 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Freeze.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Freeze for Error","synthetic":true,"types":[]},{"text":"impl !Freeze for AnyBlockchain","synthetic":true,"types":[]},{"text":"impl Freeze for AnyBlockchainConfig","synthetic":true,"types":[]},{"text":"impl !Freeze for ElectrumBlockchain","synthetic":true,"types":[]},{"text":"impl Freeze for ElectrumBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Freeze for EsploraBlockchain","synthetic":true,"types":[]},{"text":"impl Freeze for EsploraBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Freeze for EsploraError","synthetic":true,"types":[]},{"text":"impl !Freeze for Mempool","synthetic":true,"types":[]},{"text":"impl Freeze for Peer","synthetic":true,"types":[]},{"text":"impl Freeze for CompactFiltersBlockchain","synthetic":true,"types":[]},{"text":"impl Freeze for BitcoinPeerConfig","synthetic":true,"types":[]},{"text":"impl Freeze for CompactFiltersBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Freeze for CompactFiltersError","synthetic":true,"types":[]},{"text":"impl Freeze for Capability","synthetic":true,"types":[]},{"text":"impl Freeze for OfflineBlockchain","synthetic":true,"types":[]},{"text":"impl Freeze for NoopProgress","synthetic":true,"types":[]},{"text":"impl Freeze for LogProgress","synthetic":true,"types":[]},{"text":"impl Freeze for AnyDatabase","synthetic":true,"types":[]},{"text":"impl Freeze for AnyBatch","synthetic":true,"types":[]},{"text":"impl Freeze for SledDbConfiguration","synthetic":true,"types":[]},{"text":"impl Freeze for AnyDatabaseConfig","synthetic":true,"types":[]},{"text":"impl Freeze for MemoryDatabase","synthetic":true,"types":[]},{"text":"impl Freeze for Error","synthetic":true,"types":[]},{"text":"impl Freeze for PKOrF","synthetic":true,"types":[]},{"text":"impl Freeze for SatisfiableItem","synthetic":true,"types":[]},{"text":"impl Freeze for Satisfaction","synthetic":true,"types":[]},{"text":"impl Freeze for Policy","synthetic":true,"types":[]},{"text":"impl Freeze for Condition","synthetic":true,"types":[]},{"text":"impl Freeze for PolicyError","synthetic":true,"types":[]},{"text":"impl<K> Freeze for P2PKH<K> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl<K> Freeze for P2WPKH_P2SH<K> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl<K> Freeze for P2WPKH<K> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl<K> Freeze for BIP44<K> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl<K> Freeze for BIP44Public<K> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl<K> Freeze for BIP49<K> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl<K> Freeze for BIP49Public<K> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl<K> Freeze for BIP84<K> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl<K> Freeze for BIP84Public<K> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl<Ctx> Freeze for DescriptorKey<Ctx>","synthetic":true,"types":[]},{"text":"impl Freeze for ScriptContextEnum","synthetic":true,"types":[]},{"text":"impl<K, Ctx> Freeze for GeneratedKey<K, Ctx> where
    K: Freeze, 
","synthetic":true,"types":[]},{"text":"impl Freeze for PrivateKeyGenerateOptions","synthetic":true,"types":[]},{"text":"impl Freeze for KeyError","synthetic":true,"types":[]},{"text":"impl Freeze for KeychainKind","synthetic":true,"types":[]},{"text":"impl Freeze for FeeRate","synthetic":true,"types":[]},{"text":"impl Freeze for UTXO","synthetic":true,"types":[]},{"text":"impl Freeze for TransactionDetails","synthetic":true,"types":[]},{"text":"impl Freeze for AddressValidatorError","synthetic":true,"types":[]},{"text":"impl Freeze for CoinSelectionResult","synthetic":true,"types":[]},{"text":"impl Freeze for LargestFirstCoinSelection","synthetic":true,"types":[]},{"text":"impl Freeze for BranchAndBoundCoinSelection","synthetic":true,"types":[]},{"text":"impl Freeze for WalletExport","synthetic":true,"types":[]},{"text":"impl Freeze for SignerId","synthetic":true,"types":[]},{"text":"impl Freeze for SignerError","synthetic":true,"types":[]},{"text":"impl Freeze for SignerOrdering","synthetic":true,"types":[]},{"text":"impl Freeze for SignersContainer","synthetic":true,"types":[]},{"text":"impl Freeze for CreateTx","synthetic":true,"types":[]},{"text":"impl Freeze for BumpFee","synthetic":true,"types":[]},{"text":"impl<D, Cs, Ctx> Freeze for TxBuilder<D, Cs, Ctx> where
    Cs: Freeze, 
","synthetic":true,"types":[]},{"text":"impl Freeze for TxOrdering","synthetic":true,"types":[]},{"text":"impl Freeze for ChangeSpendPolicy","synthetic":true,"types":[]},{"text":"impl<B, D> !Freeze for Wallet<B, D>","synthetic":true,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Send.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Send.js new file mode 100644 index 0000000000..b500695f51 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Send.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Send for Error","synthetic":true,"types":[]},{"text":"impl Send for AnyBlockchain","synthetic":true,"types":[]},{"text":"impl Send for AnyBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Send for ElectrumBlockchain","synthetic":true,"types":[]},{"text":"impl Send for ElectrumBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Send for EsploraBlockchain","synthetic":true,"types":[]},{"text":"impl Send for EsploraBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Send for EsploraError","synthetic":true,"types":[]},{"text":"impl Send for Mempool","synthetic":true,"types":[]},{"text":"impl Send for Peer","synthetic":true,"types":[]},{"text":"impl Send for CompactFiltersBlockchain","synthetic":true,"types":[]},{"text":"impl Send for BitcoinPeerConfig","synthetic":true,"types":[]},{"text":"impl Send for CompactFiltersBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Send for CompactFiltersError","synthetic":true,"types":[]},{"text":"impl Send for Capability","synthetic":true,"types":[]},{"text":"impl Send for OfflineBlockchain","synthetic":true,"types":[]},{"text":"impl Send for NoopProgress","synthetic":true,"types":[]},{"text":"impl Send for LogProgress","synthetic":true,"types":[]},{"text":"impl !Send for AnyDatabase","synthetic":true,"types":[]},{"text":"impl !Send for AnyBatch","synthetic":true,"types":[]},{"text":"impl Send for SledDbConfiguration","synthetic":true,"types":[]},{"text":"impl Send for AnyDatabaseConfig","synthetic":true,"types":[]},{"text":"impl !Send for MemoryDatabase","synthetic":true,"types":[]},{"text":"impl Send for Error","synthetic":true,"types":[]},{"text":"impl Send for PKOrF","synthetic":true,"types":[]},{"text":"impl Send for SatisfiableItem","synthetic":true,"types":[]},{"text":"impl Send for Satisfaction","synthetic":true,"types":[]},{"text":"impl Send for Policy","synthetic":true,"types":[]},{"text":"impl Send for Condition","synthetic":true,"types":[]},{"text":"impl Send for PolicyError","synthetic":true,"types":[]},{"text":"impl<K> Send for P2PKH<K> where
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl<K> Send for P2WPKH_P2SH<K> where
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl<K> Send for P2WPKH<K> where
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl<K> Send for BIP44<K> where
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl<K> Send for BIP44Public<K> where
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl<K> Send for BIP49<K> where
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl<K> Send for BIP49Public<K> where
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl<K> Send for BIP84<K> where
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl<K> Send for BIP84Public<K> where
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl<Ctx> Send for DescriptorKey<Ctx> where
    Ctx: Send, 
","synthetic":true,"types":[]},{"text":"impl Send for ScriptContextEnum","synthetic":true,"types":[]},{"text":"impl<K, Ctx> Send for GeneratedKey<K, Ctx> where
    Ctx: Send,
    K: Send, 
","synthetic":true,"types":[]},{"text":"impl Send for PrivateKeyGenerateOptions","synthetic":true,"types":[]},{"text":"impl Send for KeyError","synthetic":true,"types":[]},{"text":"impl Send for KeychainKind","synthetic":true,"types":[]},{"text":"impl Send for FeeRate","synthetic":true,"types":[]},{"text":"impl Send for UTXO","synthetic":true,"types":[]},{"text":"impl Send for TransactionDetails","synthetic":true,"types":[]},{"text":"impl Send for AddressValidatorError","synthetic":true,"types":[]},{"text":"impl Send for CoinSelectionResult","synthetic":true,"types":[]},{"text":"impl Send for LargestFirstCoinSelection","synthetic":true,"types":[]},{"text":"impl Send for BranchAndBoundCoinSelection","synthetic":true,"types":[]},{"text":"impl Send for WalletExport","synthetic":true,"types":[]},{"text":"impl Send for SignerId","synthetic":true,"types":[]},{"text":"impl Send for SignerError","synthetic":true,"types":[]},{"text":"impl Send for SignerOrdering","synthetic":true,"types":[]},{"text":"impl Send for SignersContainer","synthetic":true,"types":[]},{"text":"impl Send for CreateTx","synthetic":true,"types":[]},{"text":"impl Send for BumpFee","synthetic":true,"types":[]},{"text":"impl<D, Cs, Ctx> Send for TxBuilder<D, Cs, Ctx> where
    Cs: Send,
    Ctx: Send,
    D: Send, 
","synthetic":true,"types":[]},{"text":"impl Send for TxOrdering","synthetic":true,"types":[]},{"text":"impl Send for ChangeSpendPolicy","synthetic":true,"types":[]},{"text":"impl<B, D> Send for Wallet<B, D> where
    B: Send,
    D: Send, 
","synthetic":true,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.StructuralEq.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.StructuralEq.js new file mode 100644 index 0000000000..f127d77e7c --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.StructuralEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl StructuralEq for Capability","synthetic":false,"types":[]},{"text":"impl StructuralEq for Condition","synthetic":false,"types":[]},{"text":"impl StructuralEq for ScriptContextEnum","synthetic":false,"types":[]},{"text":"impl StructuralEq for KeychainKind","synthetic":false,"types":[]},{"text":"impl StructuralEq for UTXO","synthetic":false,"types":[]},{"text":"impl StructuralEq for TransactionDetails","synthetic":false,"types":[]},{"text":"impl StructuralEq for AddressValidatorError","synthetic":false,"types":[]},{"text":"impl StructuralEq for SignerId","synthetic":false,"types":[]},{"text":"impl StructuralEq for SignerError","synthetic":false,"types":[]},{"text":"impl StructuralEq for SignerOrdering","synthetic":false,"types":[]},{"text":"impl StructuralEq for TxOrdering","synthetic":false,"types":[]},{"text":"impl StructuralEq for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.StructuralPartialEq.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.StructuralPartialEq.js new file mode 100644 index 0000000000..76d66b9984 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.StructuralPartialEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl StructuralPartialEq for Capability","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for Condition","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for ScriptContextEnum","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for KeychainKind","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for FeeRate","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for UTXO","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for TransactionDetails","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for AddressValidatorError","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for SignerId","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for SignerError","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for SignerOrdering","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for TxOrdering","synthetic":false,"types":[]},{"text":"impl StructuralPartialEq for ChangeSpendPolicy","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Sync.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Sync.js new file mode 100644 index 0000000000..a66b5513b1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Sync.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Sync for Error","synthetic":true,"types":[]},{"text":"impl Sync for AnyBlockchain","synthetic":true,"types":[]},{"text":"impl Sync for AnyBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Sync for ElectrumBlockchain","synthetic":true,"types":[]},{"text":"impl Sync for ElectrumBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Sync for EsploraBlockchain","synthetic":true,"types":[]},{"text":"impl Sync for EsploraBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Sync for EsploraError","synthetic":true,"types":[]},{"text":"impl Sync for Mempool","synthetic":true,"types":[]},{"text":"impl Sync for Peer","synthetic":true,"types":[]},{"text":"impl Sync for CompactFiltersBlockchain","synthetic":true,"types":[]},{"text":"impl Sync for BitcoinPeerConfig","synthetic":true,"types":[]},{"text":"impl Sync for CompactFiltersBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Sync for CompactFiltersError","synthetic":true,"types":[]},{"text":"impl Sync for Capability","synthetic":true,"types":[]},{"text":"impl Sync for OfflineBlockchain","synthetic":true,"types":[]},{"text":"impl Sync for NoopProgress","synthetic":true,"types":[]},{"text":"impl Sync for LogProgress","synthetic":true,"types":[]},{"text":"impl !Sync for AnyDatabase","synthetic":true,"types":[]},{"text":"impl !Sync for AnyBatch","synthetic":true,"types":[]},{"text":"impl Sync for SledDbConfiguration","synthetic":true,"types":[]},{"text":"impl Sync for AnyDatabaseConfig","synthetic":true,"types":[]},{"text":"impl !Sync for MemoryDatabase","synthetic":true,"types":[]},{"text":"impl Sync for Error","synthetic":true,"types":[]},{"text":"impl Sync for PKOrF","synthetic":true,"types":[]},{"text":"impl Sync for SatisfiableItem","synthetic":true,"types":[]},{"text":"impl Sync for Satisfaction","synthetic":true,"types":[]},{"text":"impl Sync for Policy","synthetic":true,"types":[]},{"text":"impl Sync for Condition","synthetic":true,"types":[]},{"text":"impl Sync for PolicyError","synthetic":true,"types":[]},{"text":"impl<K> Sync for P2PKH<K> where
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl<K> Sync for P2WPKH_P2SH<K> where
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl<K> Sync for P2WPKH<K> where
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl<K> Sync for BIP44<K> where
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl<K> Sync for BIP44Public<K> where
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl<K> Sync for BIP49<K> where
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl<K> Sync for BIP49Public<K> where
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl<K> Sync for BIP84<K> where
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl<K> Sync for BIP84Public<K> where
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl<Ctx> Sync for DescriptorKey<Ctx> where
    Ctx: Sync, 
","synthetic":true,"types":[]},{"text":"impl Sync for ScriptContextEnum","synthetic":true,"types":[]},{"text":"impl<K, Ctx> Sync for GeneratedKey<K, Ctx> where
    Ctx: Sync,
    K: Sync, 
","synthetic":true,"types":[]},{"text":"impl Sync for PrivateKeyGenerateOptions","synthetic":true,"types":[]},{"text":"impl Sync for KeyError","synthetic":true,"types":[]},{"text":"impl Sync for KeychainKind","synthetic":true,"types":[]},{"text":"impl Sync for FeeRate","synthetic":true,"types":[]},{"text":"impl Sync for UTXO","synthetic":true,"types":[]},{"text":"impl Sync for TransactionDetails","synthetic":true,"types":[]},{"text":"impl Sync for AddressValidatorError","synthetic":true,"types":[]},{"text":"impl Sync for CoinSelectionResult","synthetic":true,"types":[]},{"text":"impl Sync for LargestFirstCoinSelection","synthetic":true,"types":[]},{"text":"impl Sync for BranchAndBoundCoinSelection","synthetic":true,"types":[]},{"text":"impl Sync for WalletExport","synthetic":true,"types":[]},{"text":"impl Sync for SignerId","synthetic":true,"types":[]},{"text":"impl Sync for SignerError","synthetic":true,"types":[]},{"text":"impl Sync for SignerOrdering","synthetic":true,"types":[]},{"text":"impl Sync for SignersContainer","synthetic":true,"types":[]},{"text":"impl Sync for CreateTx","synthetic":true,"types":[]},{"text":"impl Sync for BumpFee","synthetic":true,"types":[]},{"text":"impl<D, Cs, Ctx> Sync for TxBuilder<D, Cs, Ctx> where
    Cs: Sync,
    Ctx: Sync,
    D: Sync, 
","synthetic":true,"types":[]},{"text":"impl Sync for TxOrdering","synthetic":true,"types":[]},{"text":"impl Sync for ChangeSpendPolicy","synthetic":true,"types":[]},{"text":"impl<B, D> !Sync for Wallet<B, D>","synthetic":true,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Unpin.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Unpin.js new file mode 100644 index 0000000000..4897f83303 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/marker/trait.Unpin.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Unpin for Error","synthetic":true,"types":[]},{"text":"impl Unpin for AnyBlockchain","synthetic":true,"types":[]},{"text":"impl Unpin for AnyBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Unpin for ElectrumBlockchain","synthetic":true,"types":[]},{"text":"impl Unpin for ElectrumBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Unpin for EsploraBlockchain","synthetic":true,"types":[]},{"text":"impl Unpin for EsploraBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Unpin for EsploraError","synthetic":true,"types":[]},{"text":"impl Unpin for Mempool","synthetic":true,"types":[]},{"text":"impl Unpin for Peer","synthetic":true,"types":[]},{"text":"impl Unpin for CompactFiltersBlockchain","synthetic":true,"types":[]},{"text":"impl Unpin for BitcoinPeerConfig","synthetic":true,"types":[]},{"text":"impl Unpin for CompactFiltersBlockchainConfig","synthetic":true,"types":[]},{"text":"impl Unpin for CompactFiltersError","synthetic":true,"types":[]},{"text":"impl Unpin for Capability","synthetic":true,"types":[]},{"text":"impl Unpin for OfflineBlockchain","synthetic":true,"types":[]},{"text":"impl Unpin for NoopProgress","synthetic":true,"types":[]},{"text":"impl Unpin for LogProgress","synthetic":true,"types":[]},{"text":"impl Unpin for AnyDatabase","synthetic":true,"types":[]},{"text":"impl Unpin for AnyBatch","synthetic":true,"types":[]},{"text":"impl Unpin for SledDbConfiguration","synthetic":true,"types":[]},{"text":"impl Unpin for AnyDatabaseConfig","synthetic":true,"types":[]},{"text":"impl Unpin for MemoryDatabase","synthetic":true,"types":[]},{"text":"impl Unpin for Error","synthetic":true,"types":[]},{"text":"impl Unpin for PKOrF","synthetic":true,"types":[]},{"text":"impl Unpin for SatisfiableItem","synthetic":true,"types":[]},{"text":"impl Unpin for Satisfaction","synthetic":true,"types":[]},{"text":"impl Unpin for Policy","synthetic":true,"types":[]},{"text":"impl Unpin for Condition","synthetic":true,"types":[]},{"text":"impl Unpin for PolicyError","synthetic":true,"types":[]},{"text":"impl<K> Unpin for P2PKH<K> where
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl<K> Unpin for P2WPKH_P2SH<K> where
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl<K> Unpin for P2WPKH<K> where
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl<K> Unpin for BIP44<K> where
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl<K> Unpin for BIP44Public<K> where
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl<K> Unpin for BIP49<K> where
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl<K> Unpin for BIP49Public<K> where
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl<K> Unpin for BIP84<K> where
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl<K> Unpin for BIP84Public<K> where
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl<Ctx> Unpin for DescriptorKey<Ctx> where
    Ctx: Unpin, 
","synthetic":true,"types":[]},{"text":"impl Unpin for ScriptContextEnum","synthetic":true,"types":[]},{"text":"impl<K, Ctx> Unpin for GeneratedKey<K, Ctx> where
    Ctx: Unpin,
    K: Unpin, 
","synthetic":true,"types":[]},{"text":"impl Unpin for PrivateKeyGenerateOptions","synthetic":true,"types":[]},{"text":"impl Unpin for KeyError","synthetic":true,"types":[]},{"text":"impl Unpin for KeychainKind","synthetic":true,"types":[]},{"text":"impl Unpin for FeeRate","synthetic":true,"types":[]},{"text":"impl Unpin for UTXO","synthetic":true,"types":[]},{"text":"impl Unpin for TransactionDetails","synthetic":true,"types":[]},{"text":"impl Unpin for AddressValidatorError","synthetic":true,"types":[]},{"text":"impl Unpin for CoinSelectionResult","synthetic":true,"types":[]},{"text":"impl Unpin for LargestFirstCoinSelection","synthetic":true,"types":[]},{"text":"impl Unpin for BranchAndBoundCoinSelection","synthetic":true,"types":[]},{"text":"impl Unpin for WalletExport","synthetic":true,"types":[]},{"text":"impl Unpin for SignerId","synthetic":true,"types":[]},{"text":"impl Unpin for SignerError","synthetic":true,"types":[]},{"text":"impl Unpin for SignerOrdering","synthetic":true,"types":[]},{"text":"impl Unpin for SignersContainer","synthetic":true,"types":[]},{"text":"impl Unpin for CreateTx","synthetic":true,"types":[]},{"text":"impl Unpin for BumpFee","synthetic":true,"types":[]},{"text":"impl<D, Cs, Ctx> Unpin for TxBuilder<D, Cs, Ctx> where
    Cs: Unpin,
    Ctx: Unpin,
    D: Unpin, 
","synthetic":true,"types":[]},{"text":"impl Unpin for TxOrdering","synthetic":true,"types":[]},{"text":"impl Unpin for ChangeSpendPolicy","synthetic":true,"types":[]},{"text":"impl<B, D> Unpin for Wallet<B, D> where
    B: Unpin,
    D: Unpin, 
","synthetic":true,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/ops/deref/trait.Deref.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/ops/deref/trait.Deref.js new file mode 100644 index 0000000000..2f7bc5e869 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/ops/deref/trait.Deref.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl<K, Ctx: ScriptContext> Deref for GeneratedKey<K, Ctx>","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/str/traits/trait.FromStr.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/str/traits/trait.FromStr.js new file mode 100644 index 0000000000..b5dbd1e30a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/core/str/traits/trait.FromStr.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl FromStr for WalletExport","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/serde/de/trait.Deserialize.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/serde/de/trait.Deserialize.js new file mode 100644 index 0000000000..209a5d4358 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/serde/de/trait.Deserialize.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl<'de> Deserialize<'de> for AnyBlockchainConfig","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for ElectrumBlockchainConfig","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for EsploraBlockchainConfig","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for BitcoinPeerConfig","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for CompactFiltersBlockchainConfig","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for SledDbConfiguration","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for AnyDatabaseConfig","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for KeychainKind","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for UTXO","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for TransactionDetails","synthetic":false,"types":[]},{"text":"impl<'de> Deserialize<'de> for WalletExport","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/serde/ser/trait.Serialize.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/serde/ser/trait.Serialize.js new file mode 100644 index 0000000000..9429b901e9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/serde/ser/trait.Serialize.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Serialize for AnyBlockchainConfig","synthetic":false,"types":[]},{"text":"impl Serialize for ElectrumBlockchainConfig","synthetic":false,"types":[]},{"text":"impl Serialize for EsploraBlockchainConfig","synthetic":false,"types":[]},{"text":"impl Serialize for BitcoinPeerConfig","synthetic":false,"types":[]},{"text":"impl Serialize for CompactFiltersBlockchainConfig","synthetic":false,"types":[]},{"text":"impl Serialize for SledDbConfiguration","synthetic":false,"types":[]},{"text":"impl Serialize for AnyDatabaseConfig","synthetic":false,"types":[]},{"text":"impl Serialize for PKOrF","synthetic":false,"types":[]},{"text":"impl Serialize for SatisfiableItem","synthetic":false,"types":[]},{"text":"impl Serialize for Satisfaction","synthetic":false,"types":[]},{"text":"impl Serialize for Policy","synthetic":false,"types":[]},{"text":"impl Serialize for Condition","synthetic":false,"types":[]},{"text":"impl Serialize for KeychainKind","synthetic":false,"types":[]},{"text":"impl Serialize for UTXO","synthetic":false,"types":[]},{"text":"impl Serialize for TransactionDetails","synthetic":false,"types":[]},{"text":"impl Serialize for WalletExport","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/std/error/trait.Error.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/std/error/trait.Error.js new file mode 100644 index 0000000000..70a9b18acb --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/std/error/trait.Error.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Error for Error","synthetic":false,"types":[]},{"text":"impl Error for EsploraError","synthetic":false,"types":[]},{"text":"impl Error for CompactFiltersError","synthetic":false,"types":[]},{"text":"impl Error for Error","synthetic":false,"types":[]},{"text":"impl Error for PolicyError","synthetic":false,"types":[]},{"text":"impl Error for KeyError","synthetic":false,"types":[]},{"text":"impl Error for AddressValidatorError","synthetic":false,"types":[]},{"text":"impl Error for SignerError","synthetic":false,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/std/panic/trait.RefUnwindSafe.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/std/panic/trait.RefUnwindSafe.js new file mode 100644 index 0000000000..c48e9d7209 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/std/panic/trait.RefUnwindSafe.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl !RefUnwindSafe for Error","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for AnyBlockchain","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for AnyBlockchainConfig","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for ElectrumBlockchain","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for ElectrumBlockchainConfig","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for EsploraBlockchain","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for EsploraBlockchainConfig","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for EsploraError","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for Mempool","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for Peer","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for CompactFiltersBlockchain","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for BitcoinPeerConfig","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for CompactFiltersBlockchainConfig","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for CompactFiltersError","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for Capability","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for OfflineBlockchain","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for NoopProgress","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for LogProgress","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for AnyDatabase","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for AnyBatch","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for SledDbConfiguration","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for AnyDatabaseConfig","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for MemoryDatabase","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for Error","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for PKOrF","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for SatisfiableItem","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for Satisfaction","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for Policy","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for Condition","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for PolicyError","synthetic":true,"types":[]},{"text":"impl<K> RefUnwindSafe for P2PKH<K> where
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> RefUnwindSafe for P2WPKH_P2SH<K> where
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> RefUnwindSafe for P2WPKH<K> where
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> RefUnwindSafe for BIP44<K> where
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> RefUnwindSafe for BIP44Public<K> where
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> RefUnwindSafe for BIP49<K> where
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> RefUnwindSafe for BIP49Public<K> where
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> RefUnwindSafe for BIP84<K> where
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> RefUnwindSafe for BIP84Public<K> where
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<Ctx> RefUnwindSafe for DescriptorKey<Ctx> where
    Ctx: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for ScriptContextEnum","synthetic":true,"types":[]},{"text":"impl<K, Ctx> RefUnwindSafe for GeneratedKey<K, Ctx> where
    Ctx: RefUnwindSafe,
    K: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for PrivateKeyGenerateOptions","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for KeyError","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for KeychainKind","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for FeeRate","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for UTXO","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for TransactionDetails","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for AddressValidatorError","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for CoinSelectionResult","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for LargestFirstCoinSelection","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for BranchAndBoundCoinSelection","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for WalletExport","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for SignerId","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for SignerError","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for SignerOrdering","synthetic":true,"types":[]},{"text":"impl !RefUnwindSafe for SignersContainer","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for CreateTx","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for BumpFee","synthetic":true,"types":[]},{"text":"impl<D, Cs, Ctx> RefUnwindSafe for TxBuilder<D, Cs, Ctx> where
    Cs: RefUnwindSafe,
    Ctx: RefUnwindSafe,
    D: RefUnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for TxOrdering","synthetic":true,"types":[]},{"text":"impl RefUnwindSafe for ChangeSpendPolicy","synthetic":true,"types":[]},{"text":"impl<B, D> !RefUnwindSafe for Wallet<B, D>","synthetic":true,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/std/panic/trait.UnwindSafe.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/std/panic/trait.UnwindSafe.js new file mode 100644 index 0000000000..a18b454332 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/implementors/std/panic/trait.UnwindSafe.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl !UnwindSafe for Error","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for AnyBlockchain","synthetic":true,"types":[]},{"text":"impl UnwindSafe for AnyBlockchainConfig","synthetic":true,"types":[]},{"text":"impl UnwindSafe for ElectrumBlockchain","synthetic":true,"types":[]},{"text":"impl UnwindSafe for ElectrumBlockchainConfig","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for EsploraBlockchain","synthetic":true,"types":[]},{"text":"impl UnwindSafe for EsploraBlockchainConfig","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for EsploraError","synthetic":true,"types":[]},{"text":"impl UnwindSafe for Mempool","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for Peer","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for CompactFiltersBlockchain","synthetic":true,"types":[]},{"text":"impl UnwindSafe for BitcoinPeerConfig","synthetic":true,"types":[]},{"text":"impl UnwindSafe for CompactFiltersBlockchainConfig","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for CompactFiltersError","synthetic":true,"types":[]},{"text":"impl UnwindSafe for Capability","synthetic":true,"types":[]},{"text":"impl UnwindSafe for OfflineBlockchain","synthetic":true,"types":[]},{"text":"impl UnwindSafe for NoopProgress","synthetic":true,"types":[]},{"text":"impl UnwindSafe for LogProgress","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for AnyDatabase","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for AnyBatch","synthetic":true,"types":[]},{"text":"impl UnwindSafe for SledDbConfiguration","synthetic":true,"types":[]},{"text":"impl UnwindSafe for AnyDatabaseConfig","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for MemoryDatabase","synthetic":true,"types":[]},{"text":"impl UnwindSafe for Error","synthetic":true,"types":[]},{"text":"impl UnwindSafe for PKOrF","synthetic":true,"types":[]},{"text":"impl UnwindSafe for SatisfiableItem","synthetic":true,"types":[]},{"text":"impl UnwindSafe for Satisfaction","synthetic":true,"types":[]},{"text":"impl UnwindSafe for Policy","synthetic":true,"types":[]},{"text":"impl UnwindSafe for Condition","synthetic":true,"types":[]},{"text":"impl UnwindSafe for PolicyError","synthetic":true,"types":[]},{"text":"impl<K> UnwindSafe for P2PKH<K> where
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> UnwindSafe for P2WPKH_P2SH<K> where
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> UnwindSafe for P2WPKH<K> where
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> UnwindSafe for BIP44<K> where
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> UnwindSafe for BIP44Public<K> where
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> UnwindSafe for BIP49<K> where
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> UnwindSafe for BIP49Public<K> where
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> UnwindSafe for BIP84<K> where
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<K> UnwindSafe for BIP84Public<K> where
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl<Ctx> UnwindSafe for DescriptorKey<Ctx> where
    Ctx: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl UnwindSafe for ScriptContextEnum","synthetic":true,"types":[]},{"text":"impl<K, Ctx> UnwindSafe for GeneratedKey<K, Ctx> where
    Ctx: UnwindSafe,
    K: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl UnwindSafe for PrivateKeyGenerateOptions","synthetic":true,"types":[]},{"text":"impl UnwindSafe for KeyError","synthetic":true,"types":[]},{"text":"impl UnwindSafe for KeychainKind","synthetic":true,"types":[]},{"text":"impl UnwindSafe for FeeRate","synthetic":true,"types":[]},{"text":"impl UnwindSafe for UTXO","synthetic":true,"types":[]},{"text":"impl UnwindSafe for TransactionDetails","synthetic":true,"types":[]},{"text":"impl UnwindSafe for AddressValidatorError","synthetic":true,"types":[]},{"text":"impl UnwindSafe for CoinSelectionResult","synthetic":true,"types":[]},{"text":"impl UnwindSafe for LargestFirstCoinSelection","synthetic":true,"types":[]},{"text":"impl UnwindSafe for BranchAndBoundCoinSelection","synthetic":true,"types":[]},{"text":"impl UnwindSafe for WalletExport","synthetic":true,"types":[]},{"text":"impl UnwindSafe for SignerId","synthetic":true,"types":[]},{"text":"impl UnwindSafe for SignerError","synthetic":true,"types":[]},{"text":"impl UnwindSafe for SignerOrdering","synthetic":true,"types":[]},{"text":"impl !UnwindSafe for SignersContainer","synthetic":true,"types":[]},{"text":"impl UnwindSafe for CreateTx","synthetic":true,"types":[]},{"text":"impl UnwindSafe for BumpFee","synthetic":true,"types":[]},{"text":"impl<D, Cs, Ctx> UnwindSafe for TxBuilder<D, Cs, Ctx> where
    Cs: UnwindSafe,
    Ctx: UnwindSafe,
    D: UnwindSafe, 
","synthetic":true,"types":[]},{"text":"impl UnwindSafe for TxOrdering","synthetic":true,"types":[]},{"text":"impl UnwindSafe for ChangeSpendPolicy","synthetic":true,"types":[]},{"text":"impl<B, D> !UnwindSafe for Wallet<B, D>","synthetic":true,"types":[]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/light.css b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/light.css new file mode 100644 index 0000000000..5a9d516b52 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/light.css @@ -0,0 +1 @@ + body{background-color:white;color:black;}h1,h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod){color:black;}h1.fqn{border-bottom-color:#D5D5D5;}h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod){border-bottom-color:#DDDDDD;}.in-band{background-color:white;}.invisible{background:rgba(0,0,0,0);}.docblock code,.docblock-short code{background-color:#F5F5F5;}pre{background-color:#F5F5F5;}.sidebar{background-color:#F1F1F1;}*{scrollbar-color:rgba(36,37,39,0.6) #e6e6e6;}.sidebar{scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;}.logo-container.rust-logo>img{}::-webkit-scrollbar-track{background-color:#ecebeb;}::-webkit-scrollbar-thumb{background-color:rgba(36,37,39,0.6);}.sidebar::-webkit-scrollbar-track{background-color:#dcdcdc;}.sidebar::-webkit-scrollbar-thumb{background-color:rgba(36,37,39,0.6);}.sidebar .current{background-color:#fff;}.source .sidebar{background-color:#fff;}.sidebar .location{border-color:#000;background-color:#fff;color:#333;}.sidebar .version{border-bottom-color:#DDD;}.sidebar-title{border-top-color:#777;border-bottom-color:#777;}.block a:hover{background:#F5F5F5;}.line-numbers span{color:#c67e2d;}.line-numbers .line-highlighted{background-color:#f6fdb0 !important;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5{border-bottom-color:#ddd;}.docblock table,.docblock table td,.docblock table th{border-color:#ddd;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#4E4C4C;}.content .highlighted{color:#000 !important;background-color:#ccc;}.content .highlighted a,.content .highlighted span{color:#000 !important;}.content .highlighted.trait{background-color:#c7b6ff;}.content .highlighted.traitalias{background-color:#c7b6ff;}.content .highlighted.mod,.content .highlighted.externcrate{background-color:#afc6e4;}.content .highlighted.enum{background-color:#b4d1b9;}.content .highlighted.struct{background-color:#e7b1a0;}.content .highlighted.union{background-color:#b7bd49;}.content .highlighted.fn,.content .highlighted.method,.content .highlighted.tymethod{background-color:#c6afb3;}.content .highlighted.type{background-color:#ffc891;}.content .highlighted.foreigntype{background-color:#f5c4ff;}.content .highlighted.attr,.content .highlighted.derive,.content .highlighted.macro{background-color:#8ce488;}.content .highlighted.constant,.content .highlighted.static{background-color:#c3e0ff;}.content .highlighted.primitive{background-color:#9aecff;}.content .highlighted.keyword{background-color:#f99650;}.content .item-info::before{color:#ccc;}.content span.enum,.content a.enum,.block a.current.enum{color:#508157;}.content span.struct,.content a.struct,.block a.current.struct{color:#ad448e;}.content span.type,.content a.type,.block a.current.type{color:#ba5d00;}.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype{color:#cd00e2;}.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro{color:#068000;}.content span.union,.content a.union,.block a.current.union{color:#767b27;}.content span.constant,.content a.constant,.block a.current.constant,.content span.static,.content a.static,.block a.current.static{color:#546e8a;}.content span.primitive,.content a.primitive,.block a.current.primitive{color:#2c8093;}.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod{color:#4d76ae;}.content span.trait,.content a.trait,.block a.current.trait{color:#7c5af3;}.content span.traitalias,.content a.traitalias,.block a.current.traitalias{color:#6841f1;}.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,.content .fnname{color:#9a6e31;}.content span.keyword,.content a.keyword,.block a.current.keyword{color:#de5249;}pre.rust .comment{color:#8E908C;}pre.rust .doccomment{color:#4D4D4C;}nav:not(.sidebar){border-bottom-color:#e0e0e0;}nav.main .current{border-top-color:#000;border-bottom-color:#000;}nav.main .separator{border:1px solid #000;}a{color:#000;}.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),.docblock-short a:not(.srclink):not(.test-arrow),.item-info a,#help a{color:#3873AD;}a.test-arrow{color:#f5f5f5;}.collapse-toggle{color:#999;}#crate-search{color:#555;background-color:white;border-color:#e0e0e0;box-shadow:0 0 0 1px #e0e0e0,0 0 0 2px transparent;}.search-input{color:#555;background-color:white;box-shadow:0 0 0 1px #e0e0e0,0 0 0 2px transparent;}.search-input:focus{border-color:#66afe9;}.search-focus:disabled{background-color:#e6e6e6;}#crate-search+.search-input:focus{box-shadow:0 0 8px #078dd8;}.module-item .stab{color:#000;}.stab.unstable{background:#FFF5D6;border-color:#FFC600;}.stab.deprecated{background:#F3DFFF;border-color:#7F0087;}.stab.portability{background:#C4ECFF;border-color:#7BA5DB;}.stab.portability>code{color:#000;}#help>div{background:#e9e9e9;border-color:#bfbfbf;}#help>div>span{border-bottom-color:#bfbfbf;}.since{color:grey;}tr.result span.primitive::after,tr.result span.keyword::after{color:black;}.line-numbers :target{background-color:transparent;}pre.rust .kw{color:#8959A8;}pre.rust .kw-2,pre.rust .prelude-ty{color:#4271AE;}pre.rust .number,pre.rust .string{color:#718C00;}pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,pre.rust .attribute .ident{color:#C82829;}pre.rust .macro,pre.rust .macro-nonterminal{color:#3E999F;}pre.rust .lifetime{color:#B76514;}pre.rust .question-mark{color:#ff9011;}.example-wrap>pre.line-number{border-color:#c7c7c7;}a.test-arrow{background-color:rgba(78,139,202,0.2);}a.test-arrow:hover{background-color:#4e8bca;}.toggle-label{color:#999;}:target>code,:target>.in-band{background:#FDFFD3;border-right:3px solid #ffb44c;}pre.compile_fail{border-left:2px solid rgba(255,0,0,.5);}pre.compile_fail:hover,.information:hover+pre.compile_fail{border-left:2px solid #f00;}pre.should_panic{border-left:2px solid rgba(255,0,0,.5);}pre.should_panic:hover,.information:hover+pre.should_panic{border-left:2px solid #f00;}pre.ignore{border-left:2px solid rgba(255,142,0,.6);}pre.ignore:hover,.information:hover+pre.ignore{border-left:2px solid #ff9200;}.tooltip.compile_fail{color:rgba(255,0,0,.5);}.information>.compile_fail:hover{color:#f00;}.tooltip.should_panic{color:rgba(255,0,0,.5);}.information>.should_panic:hover{color:#f00;}.tooltip.ignore{color:rgba(255,142,0,.6);}.information>.ignore:hover{color:#ff9200;}.search-failed a{color:#0089ff;}.tooltip .tooltiptext{background-color:#000;color:#fff;}.tooltip .tooltiptext::after{border-color:transparent black transparent transparent;}.notable-traits-tooltiptext{background-color:#eee;border-color:#999;}#titles>button:not(.selected){background-color:#e6e6e6;border-top-color:#e6e6e6;}#titles>button:hover,#titles>button.selected{background-color:#ffffff;border-top-color:#0089ff;}#titles>button>div.count{color:#888;}@media (max-width:700px){.sidebar-menu{background-color:#F1F1F1;border-bottom-color:#e0e0e0;border-right-color:#e0e0e0;}.sidebar-elems{background-color:#F1F1F1;border-right-color:#000;}#sidebar-filler{background-color:#F1F1F1;border-bottom-color:#e0e0e0;}}kbd{color:#000;background-color:#fafbfc;border-color:#d1d5da;border-bottom-color:#c6cbd1;box-shadow-color:#c6cbd1;}#theme-picker,#settings-menu,.help-button{border-color:#e0e0e0;background-color:#fff;}#theme-picker:hover,#theme-picker:focus,#settings-menu:hover,#settings-menu:focus,.help-button:hover,.help-button:focus{border-color:#717171;}#theme-choices{border-color:#ccc;background-color:#fff;}#theme-choices>button:not(:first-child){border-top-color:#e0e0e0;}#theme-choices>button:hover,#theme-choices>button:focus{background-color:#eee;}@media (max-width:700px){#theme-picker{background:#fff;}}#all-types{background-color:#fff;}#all-types:hover{background-color:#f9f9f9;}.search-results td span.alias{color:#000;}.search-results td span.grey{color:#999;}#sidebar-toggle{background-color:#F1F1F1;}#sidebar-toggle:hover{background-color:#E0E0E0;}#source-sidebar{background-color:#F1F1F1;}#source-sidebar>.title{border-bottom-color:#ccc;}div.files>a:hover,div.name:hover{background-color:#E0E0E0;}div.files>.selected{background-color:#fff;}.setting-line>.title{border-bottom-color:#D5D5D5;} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/main.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/main.js new file mode 100644 index 0000000000..03cfb2cc39 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/main.js @@ -0,0 +1,8 @@ +if(!String.prototype.startsWith){String.prototype.startsWith=function(searchString,position){position=position||0;return this.indexOf(searchString,position)===position}}if(!String.prototype.endsWith){String.prototype.endsWith=function(suffix,length){var l=length||this.length;return this.indexOf(suffix,l-suffix.length)!==-1}}if(!DOMTokenList.prototype.add){DOMTokenList.prototype.add=function(className){if(className&&!hasClass(this,className)){if(this.className&&this.className.length>0){this.className+=" "+className}else{this.className=className}}}}if(!DOMTokenList.prototype.remove){DOMTokenList.prototype.remove=function(className){if(className&&this.className){this.className=(" "+this.className+" ").replace(" "+className+" "," ").trim()}}}function getVirtualKey(ev){if("key"in ev&&typeof ev.key!="undefined"){return ev.key}var c=ev.charCode||ev.keyCode;if(c==27){return"Escape"}return String.fromCharCode(c)}function getSearchInput(){return document.getElementsByClassName("search-input")[0]}function getSearchElement(){return document.getElementById("search")}function getThemesElement(){return document.getElementById("theme-choices")}function getThemePickerElement(){return document.getElementById("theme-picker")}function focusSearchBar(){getSearchInput().focus()}function defocusSearchBar(){getSearchInput().blur()}(function(){"use strict";var itemTypes=["mod","externcrate","import","struct","enum","fn","type","static","trait","impl","tymethod","method","structfield","variant","macro","primitive","associatedtype","constant","associatedconstant","union","foreigntype","keyword","existential","attr","derive","traitalias"];var disableShortcuts=getSettingValue("disable-shortcuts")==="true";var search_input=getSearchInput();var searchTimeout=null;var toggleAllDocsId="toggle-all-docs";var currentTab=0;var mouseMovedAfterSearch=true;var titleBeforeSearch=document.title;var searchTitle=null;function clearInputTimeout(){if(searchTimeout!==null){clearTimeout(searchTimeout);searchTimeout=null}}function getPageId(){if(window.location.hash){var tmp=window.location.hash.replace(/^#/,"");if(tmp.length>0){return tmp}}return null}function showSidebar(){var elems=document.getElementsByClassName("sidebar-elems")[0];if(elems){addClass(elems,"show-it")}var sidebar=document.getElementsByClassName("sidebar")[0];if(sidebar){addClass(sidebar,"mobile");var filler=document.getElementById("sidebar-filler");if(!filler){var div=document.createElement("div");div.id="sidebar-filler";sidebar.appendChild(div)}}}function hideSidebar(){var elems=document.getElementsByClassName("sidebar-elems")[0];if(elems){removeClass(elems,"show-it")}var sidebar=document.getElementsByClassName("sidebar")[0];removeClass(sidebar,"mobile");var filler=document.getElementById("sidebar-filler");if(filler){filler.remove()}document.getElementsByTagName("body")[0].style.marginTop=""}function showSearchResults(search){if(search===null||typeof search==='undefined'){search=getSearchElement()}addClass(main,"hidden");removeClass(search,"hidden");mouseMovedAfterSearch=false;document.title=searchTitle}function hideSearchResults(search){if(search===null||typeof search==='undefined'){search=getSearchElement()}addClass(search,"hidden");removeClass(main,"hidden");document.title=titleBeforeSearch}var TY_PRIMITIVE=itemTypes.indexOf("primitive");var TY_KEYWORD=itemTypes.indexOf("keyword");function getQueryStringParams(){var params={};window.location.search.substring(1).split("&").map(function(s){var pair=s.split("=");params[decodeURIComponent(pair[0])]=typeof pair[1]==="undefined"?null:decodeURIComponent(pair[1])});return params}function browserSupportsHistoryApi(){return window.history&&typeof window.history.pushState==="function"}function isHidden(elem){return elem.offsetHeight===0}var main=document.getElementById("main");var savedHash="";function handleHashes(ev){var elem;var search=getSearchElement();if(ev!==null&&search&&!hasClass(search,"hidden")&&ev.newURL){hideSearchResults(search);var hash=ev.newURL.slice(ev.newURL.indexOf("#")+1);if(browserSupportsHistoryApi()){history.replaceState(hash,"","?search=#"+hash)}elem=document.getElementById(hash);if(elem){elem.scrollIntoView()}}if(savedHash!==window.location.hash){savedHash=window.location.hash;if(savedHash.length===0){return}elem=document.getElementById(savedHash.slice(1));if(!elem||!isHidden(elem)){return}var parent=elem.parentNode;if(parent&&hasClass(parent,"impl-items")){onEachLazy(parent.getElementsByClassName("collapsed"),function(e){if(e.parentNode===parent){e.click();return true}});if(isHidden(elem)){if(hasClass(parent.lastElementChild,"collapse-toggle")){parent.lastElementChild.click()}}}}}function highlightSourceLines(match,ev){if(typeof match==="undefined"){hideSidebar();match=window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/)}if(!match){return}var from=parseInt(match[1],10);var to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(to0){collapseDocs(collapses[0],"show")}}}}function getHelpElement(){buildHelperPopup();return document.getElementById("help")}function displayHelp(display,ev,help){help=help?help:getHelpElement();if(display===true){if(hasClass(help,"hidden")){ev.preventDefault();removeClass(help,"hidden");addClass(document.body,"blur")}}else if(hasClass(help,"hidden")===false){ev.preventDefault();addClass(help,"hidden");removeClass(document.body,"blur")}}function handleEscape(ev){var help=getHelpElement();var search=getSearchElement();if(hasClass(help,"hidden")===false){displayHelp(false,ev,help)}else if(hasClass(search,"hidden")===false){clearInputTimeout();ev.preventDefault();hideSearchResults(search)}defocusSearchBar();hideThemeButtonState()}function handleShortcut(ev){if(ev.ctrlKey||ev.altKey||ev.metaKey||disableShortcuts===true){return}if(document.activeElement.tagName==="INPUT"){switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break}}else{switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break;case"s":case"S":displayHelp(false,ev);ev.preventDefault();focusSearchBar();break;case"+":case"-":ev.preventDefault();toggleAllDocs();break;case"?":displayHelp(true,ev);break;case"t":case"T":displayHelp(false,ev);ev.preventDefault();var themePicker=getThemePickerElement();themePicker.click();themePicker.focus();break;default:var themePicker=getThemePickerElement();if(themePicker.parentNode.contains(ev.target)){handleThemeKeyDown(ev)}}}}function handleThemeKeyDown(ev){var active=document.activeElement;var themes=getThemesElement();switch(getVirtualKey(ev)){case"ArrowUp":ev.preventDefault();if(active.previousElementSibling&&ev.target.id!=="theme-picker"){active.previousElementSibling.focus()}else{showThemeButtonState();themes.lastElementChild.focus()}break;case"ArrowDown":ev.preventDefault();if(active.nextElementSibling&&ev.target.id!=="theme-picker"){active.nextElementSibling.focus()}else{showThemeButtonState();themes.firstElementChild.focus()}break;case"Enter":case"Return":case"Space":if(ev.target.id==="theme-picker"&&themes.style.display==="none"){ev.preventDefault();showThemeButtonState();themes.firstElementChild.focus()}break;case"Home":ev.preventDefault();themes.firstElementChild.focus();break;case"End":ev.preventDefault();themes.lastElementChild.focus();break}}function findParentElement(elem,tagName){do{if(elem&&elem.tagName===tagName){return elem}elem=elem.parentNode}while(elem);return null}document.addEventListener("keypress",handleShortcut);document.addEventListener("keydown",handleShortcut);function resetMouseMoved(ev){mouseMovedAfterSearch=true}document.addEventListener("mousemove",resetMouseMoved);var handleSourceHighlight=(function(){var prev_line_id=0;var set_fragment=function(name){var x=window.scrollX,y=window.scrollY;if(browserSupportsHistoryApi()){history.replaceState(null,null,"#"+name);highlightSourceLines()}else{location.replace("#"+name)}window.scrollTo(x,y)};return function(ev){var cur_line_id=parseInt(ev.target.id,10);ev.preventDefault();if(ev.shiftKey&&prev_line_id){if(prev_line_id>cur_line_id){var tmp=prev_line_id;prev_line_id=cur_line_id;cur_line_id=tmp}set_fragment(prev_line_id+"-"+cur_line_id)}else{prev_line_id=cur_line_id;set_fragment(cur_line_id)}}}());document.addEventListener("click",function(ev){if(hasClass(ev.target,"help-button")){displayHelp(true,ev)}else if(hasClass(ev.target,"collapse-toggle")){collapseDocs(ev.target,"toggle")}else if(hasClass(ev.target.parentNode,"collapse-toggle")){collapseDocs(ev.target.parentNode,"toggle")}else if(ev.target.tagName==="SPAN"&&hasClass(ev.target.parentNode,"line-numbers")){handleSourceHighlight(ev)}else if(hasClass(getHelpElement(),"hidden")===false){var help=getHelpElement();var is_inside_help_popup=ev.target!==help&&help.contains(ev.target);if(is_inside_help_popup===false){addClass(help,"hidden");removeClass(document.body,"blur")}}else{var a=findParentElement(ev.target,"A");if(a&&a.hash){expandSection(a.hash.replace(/^#/,""))}}});(function(){var x=document.getElementsByClassName("version-selector");if(x.length>0){x[0].onchange=function(){var i,match,url=document.location.href,stripped="",len=rootPath.match(/\.\.\//g).length+1;for(i=0;i-1){var obj=searchIndex[results[i].id];obj.lev=results[i].lev;if(isType!==true||obj.type){var res=buildHrefAndPath(obj);obj.displayPath=pathSplitter(res[0]);obj.fullPath=obj.displayPath+obj.name;obj.fullPath+="|"+obj.ty;obj.href=res[1];out.push(obj);if(out.length>=MAX_RESULTS){break}}}}return out}function sortResults(results,isType){var ar=[];for(var entry in results){if(hasOwnProperty(results,entry)){ar.push(results[entry])}}results=ar;var i;var nresults=results.length;for(i=0;ib?+1:-1)}a=(aaa.index<0);b=(bbb.index<0);if(a!==b){return a-b}a=aaa.index;b=bbb.index;if(a!==b){return a-b}if((aaa.item.ty===TY_PRIMITIVE&&bbb.item.ty!==TY_KEYWORD)||(aaa.item.ty===TY_KEYWORD&&bbb.item.ty!==TY_PRIMITIVE)){return-1}if((bbb.item.ty===TY_PRIMITIVE&&aaa.item.ty!==TY_PRIMITIVE)||(bbb.item.ty===TY_KEYWORD&&aaa.item.ty!==TY_KEYWORD)){return 1}a=(aaa.item.desc==="");b=(bbb.item.desc==="");if(a!==b){return a-b}a=aaa.item.ty;b=bbb.item.ty;if(a!==b){return a-b}a=aaa.item.path;b=bbb.item.path;if(a!==b){return(a>b?+1:-1)}return 0});var length=results.length;for(i=0;i"));return{name:val.substring(0,val.indexOf("<")),generics:values.split(/\s*,\s*/),}}return{name:val,generics:[],}}function getObjectFromId(id){if(typeof id==="number"){return searchIndex[id]}return{'name':id}}function checkGenerics(obj,val){var lev_distance=MAX_LEV_DISTANCE+1;if(val.generics.length>0){if(obj.length>GENERICS_DATA&&obj[GENERICS_DATA].length>=val.generics.length){var elems=obj[GENERICS_DATA].slice(0);var total=0;var done=0;var vlength=val.generics.length;for(var y=0;yGENERICS_DATA&&obj[GENERICS_DATA].length>=val.generics.length){var elems=obj[GENERICS_DATA].slice(0);var allFound=true;for(var y=0;allFound===true&&yGENERICS_DATA&&obj[GENERICS_DATA].length!==0){var tmp_lev=checkGenerics(obj,val);if(tmp_lev<=MAX_LEV_DISTANCE){return tmp_lev}}else{return 0}}if(literalSearch===true){if(obj.length>GENERICS_DATA&&obj[GENERICS_DATA].length>0){var length=obj[GENERICS_DATA].length;for(x=0;xGENERICS_DATA&&obj[GENERICS_DATA].length>0){var olength=obj[GENERICS_DATA].length;for(x=0;x0){var length=obj.type[INPUTS_DATA].length;for(var i=0;iOUTPUT_DATA){var ret=obj.type[OUTPUT_DATA];if(typeof ret[0]==="string"){ret=[ret]}for(var x=0;xlength){return MAX_LEV_DISTANCE+1}for(var i=0;ilength){break}var lev_total=0;var aborted=false;for(var x=0;xMAX_LEV_DISTANCE){aborted=true;break}lev_total+=lev}if(aborted===false){ret_lev=Math.min(ret_lev,Math.round(lev_total/clength))}}return ret_lev}function typePassesFilter(filter,type){if(filter<=NO_TYPE_FILTER)return true;if(filter===type)return true;var name=itemTypes[type];switch(itemTypes[filter]){case"constant":return name==="associatedconstant";case"fn":return name==="method"||name==="tymethod";case"type":return name==="primitive"||name==="associatedtype";case"trait":return name==="traitalias"}return false}function generateId(ty){if(ty.parent&&ty.parent.name){return itemTypes[ty.ty]+ty.path+ty.parent.name+ty.name}return itemTypes[ty.ty]+ty.path+ty.name}function createAliasFromItem(item){return{crate:item.crate,name:item.name,path:item.path,desc:item.desc,ty:item.ty,parent:item.parent,type:item.type,is_alias:true,}}function handleAliases(ret,query,filterCrates){var aliases=[];var crateAliases=[];var i;if(filterCrates!==undefined){if(ALIASES[filterCrates]&&ALIASES[filterCrates][query.search]){for(i=0;iMAX_RESULTS){ret.others.pop()}};onEach(aliases,pushFunc);onEach(crateAliases,pushFunc)}var nSearchWords=searchWords.length;var i;var ty;var fullId;var returned;var in_args;if((val.charAt(0)==="\""||val.charAt(0)==="'")&&val.charAt(val.length-1)===val.charAt(0)){val=extractGenerics(val.substr(1,val.length-2));for(i=0;i")>-1){var trimmer=function(s){return s.trim()};var parts=val.split("->").map(trimmer);var input=parts[0];var inputs=input.split(",").map(trimmer).sort();for(i=0;i1?paths.length-1:1);var lev;for(j=0;j1){lev=checkPath(contains,paths[paths.length-1],ty);if(lev>MAX_LEV_DISTANCE){continue}else if(lev>0){lev_add=lev/10}}returned=MAX_LEV_DISTANCE+1;in_args=MAX_LEV_DISTANCE+1;var index=-1;lev=MAX_LEV_DISTANCE+1;fullId=generateId(ty);if(searchWords[j].indexOf(split[i])>-1||searchWords[j].indexOf(val)>-1||searchWords[j].replace(/_/g,"").indexOf(val)>-1){if(typePassesFilter(typeFilter,ty.ty)&&results[fullId]===undefined){index=searchWords[j].replace(/_/g,"").indexOf(val)}}if((lev=levenshtein(searchWords[j],val))<=MAX_LEV_DISTANCE){if(typePassesFilter(typeFilter,ty.ty)===false){lev=MAX_LEV_DISTANCE+1}else{lev+=1}}in_args=findArg(ty,valGenerics,false,typeFilter);returned=checkReturned(ty,valGenerics,false,typeFilter);lev+=lev_add;if(lev>0&&val.length>3&&searchWords[j].indexOf(val)>-1){if(val.length<6){lev-=1}else{lev=0}}if(in_args<=MAX_LEV_DISTANCE){if(results_in_args[fullId]===undefined){results_in_args[fullId]={id:j,index:index,lev:in_args,}}results_in_args[fullId].lev=Math.min(results_in_args[fullId].lev,in_args)}if(returned<=MAX_LEV_DISTANCE){if(results_returned[fullId]===undefined){results_returned[fullId]={id:j,index:index,lev:returned,}}results_returned[fullId].lev=Math.min(results_returned[fullId].lev,returned)}if(index!==-1||lev<=MAX_LEV_DISTANCE){if(index!==-1&&paths.length<2){lev=0}if(results[fullId]===undefined){results[fullId]={id:j,index:index,lev:lev,}}results[fullId].lev=Math.min(results[fullId].lev,lev)}}}var ret={"in_args":sortResults(results_in_args,true),"returned":sortResults(results_returned,true),"others":sortResults(results),};handleAliases(ret,query,filterCrates);return ret}function validateResult(name,path,keys,parent){for(var i=0;i-1||path.indexOf(keys[i])>-1||(parent!==undefined&&parent.name!==undefined&&parent.name.toLowerCase().indexOf(keys[i])>-1)||levenshtein(name,keys[i])<=MAX_LEV_DISTANCE)){return false}}return true}function getQuery(raw){var matches,type,query;query=raw;matches=query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);if(matches){type=matches[1].replace(/^const$/,"constant");query=query.substring(matches[0].length)}return{raw:raw,query:query,type:type,id:query+type}}function initSearchNav(){var hoverTimeout;var click_func=function(e){var el=e.target;while(el.tagName!=="TR"){el=el.parentNode}var dst=e.target.getElementsByTagName("a");if(dst.length<1){return}dst=dst[0];if(window.location.pathname===dst.pathname){hideSearchResults();document.location.href=dst.href}};var mouseover_func=function(e){if(mouseMovedAfterSearch){var el=e.target;while(el.tagName!=="TR"){el=el.parentNode}clearTimeout(hoverTimeout);hoverTimeout=setTimeout(function(){onEachLazy(document.getElementsByClassName("search-results"),function(e){onEachLazy(e.getElementsByClassName("result"),function(i_e){removeClass(i_e,"highlighted")})});addClass(el,"highlighted")},20)}};onEachLazy(document.getElementsByClassName("search-results"),function(e){onEachLazy(e.getElementsByClassName("result"),function(i_e){i_e.onclick=click_func;i_e.onmouseover=mouseover_func})});search_input.onkeydown=function(e){var actives=[[],[],[]];var current=0;onEachLazy(document.getElementById("results").childNodes,function(e){onEachLazy(e.getElementsByClassName("highlighted"),function(h_e){actives[current].push(h_e)});current+=1});if(e.which===38){if(e.ctrlKey){printTab(currentTab>0?currentTab-1:2)}else{if(!actives[currentTab].length||!actives[currentTab][0].previousElementSibling){return}addClass(actives[currentTab][0].previousElementSibling,"highlighted");removeClass(actives[currentTab][0],"highlighted")}e.preventDefault()}else if(e.which===40){if(e.ctrlKey){printTab(currentTab>1?0:currentTab+1)}else if(!actives[currentTab].length){var results=document.getElementById("results").childNodes;if(results.length>0){var res=results[currentTab].getElementsByClassName("result");if(res.length>0){addClass(res[0],"highlighted")}}}else if(actives[currentTab][0].nextElementSibling){addClass(actives[currentTab][0].nextElementSibling,"highlighted");removeClass(actives[currentTab][0],"highlighted")}e.preventDefault()}else if(e.which===13){if(actives[currentTab].length){document.location.href=actives[currentTab][0].getElementsByTagName("a")[0].href}}else if(e.which===16){}else if(actives[currentTab].length>0){removeClass(actives[currentTab][0],"highlighted")}}}function buildHrefAndPath(item){var displayPath;var href;var type=itemTypes[item.ty];var name=item.name;var path=item.path;if(type==="mod"){displayPath=path+"::";href=rootPath+path.replace(/::/g,"/")+"/"+name+"/index.html"}else if(type==="primitive"||type==="keyword"){displayPath="";href=rootPath+path.replace(/::/g,"/")+"/"+type+"."+name+".html"}else if(type==="externcrate"){displayPath="";href=rootPath+name+"/index.html"}else if(item.parent!==undefined){var myparent=item.parent;var anchor="#"+type+"."+name;var parentType=itemTypes[myparent.ty];var pageType=parentType;var pageName=myparent.name;if(parentType==="primitive"){displayPath=myparent.name+"::"}else if(type==="structfield"&&parentType==="variant"){var splitPath=item.path.split("::");var enumName=splitPath.pop();path=splitPath.join("::");displayPath=path+"::"+enumName+"::"+myparent.name+"::";anchor="#variant."+myparent.name+".field."+name;pageType="enum";pageName=enumName}else{displayPath=path+"::"+myparent.name+"::"}href=rootPath+path.replace(/::/g,"/")+"/"+pageType+"."+pageName+".html"+anchor}else{displayPath=item.path+"::";href=rootPath+item.path.replace(/::/g,"/")+"/"+type+"."+name+".html"}return[displayPath,href]}function escape(content){var h1=document.createElement("h1");h1.textContent=content;return h1.innerHTML}function pathSplitter(path){var tmp=""+path.replace(/::/g,"::");if(tmp.endsWith("")){return tmp.slice(0,tmp.length-6)}return tmp}function addTab(array,query,display){var extraStyle="";if(display===false){extraStyle=" style=\"display: none;\""}var output="";var duplicates={};var length=0;if(array.length>0){output="";array.forEach(function(item){var name,type;name=item.name;type=itemTypes[item.ty];if(item.is_alias!==true){if(duplicates[item.fullPath]){return}duplicates[item.fullPath]=true}length+=1;output+=""});output+="
"+""+(item.is_alias===true?(""+item.alias+"  - see "):"")+item.displayPath+""+name+""+""+""+item.desc+" 
"}else{output="
No results :(
"+"Try on DuckDuckGo?

"+"Or try looking in one of these:
"}return[output,length]}function makeTabHeader(tabNb,text,nbElems){if(currentTab===tabNb){return""}return""}function showResults(results){var search=getSearchElement();if(results.others.length===1&&getSettingValue("go-to-only-result")==="true"&&(!search.firstChild||search.firstChild.innerText!==getSearchLoadingText())){var elem=document.createElement("a");elem.href=results.others[0].href;elem.style.display="none";document.body.appendChild(elem);elem.click();return}var query=getQuery(search_input.value);currentResults=query.id;var ret_others=addTab(results.others,query);var ret_in_args=addTab(results.in_args,query,false);var ret_returned=addTab(results.returned,query,false);var output="

Results for "+escape(query.query)+(query.type?" (type: "+escape(query.type)+")":"")+"

"+"
"+makeTabHeader(0,"In Names",ret_others[1])+makeTabHeader(1,"In Parameters",ret_in_args[1])+makeTabHeader(2,"In Return Types",ret_returned[1])+"
"+ret_others[0]+ret_in_args[0]+ret_returned[0]+"
";search.innerHTML=output;showSearchResults(search);var tds=search.getElementsByTagName("td");var td_width=0;if(tds.length>0){td_width=tds[0].offsetWidth}var width=search.offsetWidth-40-td_width;onEachLazy(search.getElementsByClassName("desc"),function(e){e.style.width=width+"px"});initSearchNav();var elems=document.getElementById("titles").childNodes;elems[0].onclick=function(){printTab(0)};elems[1].onclick=function(){printTab(1)};elems[2].onclick=function(){printTab(2)};printTab(currentTab)}function execSearch(query,searchWords,filterCrates){function getSmallest(arrays,positions,notDuplicates){var start=null;for(var it=0;itpositions[it]&&(start===null||start>arrays[it][positions[it]].lev)&&!notDuplicates[arrays[it][positions[it]].fullPath]){start=arrays[it][positions[it]].lev}}return start}function mergeArrays(arrays){var ret=[];var positions=[];var notDuplicates={};for(var x=0;xpositions[x]&&arrays[x][positions[x]].lev===smallest&&!notDuplicates[arrays[x][positions[x]].fullPath]){ret.push(arrays[x][positions[x]]);notDuplicates[arrays[x][positions[x]].fullPath]=true;positions[x]+=1}}}return ret}var queries=query.raw.split(",");var results={"in_args":[],"returned":[],"others":[],};for(var i=0;i1){return{"in_args":mergeArrays(results.in_args),"returned":mergeArrays(results.returned),"others":mergeArrays(results.others),}}return{"in_args":results.in_args[0],"returned":results.returned[0],"others":results.others[0],}}function getFilterCrates(){var elem=document.getElementById("crate-search");if(elem&&elem.value!=="All crates"&&hasOwnProperty(rawSearchIndex,elem.value)){return elem.value}return undefined}function search(e,forced){var params=getQueryStringParams();var query=getQuery(search_input.value.trim());if(e){e.preventDefault()}if(query.query.length===0){return}if(forced!==true&&query.id===currentResults){if(query.query.length>0){putBackSearch(search_input)}return}searchTitle="Results for "+query.query+" - Rust";if(browserSupportsHistoryApi()){if(!history.state&&!params.search){history.pushState(query,"","?search="+encodeURIComponent(query.raw))}else{history.replaceState(query,"","?search="+encodeURIComponent(query.raw))}}var filterCrates=getFilterCrates();showResults(execSearch(query,index,filterCrates))}function buildIndex(rawSearchIndex){searchIndex=[];var searchWords=[];var i;var currentIndex=0;for(var crate in rawSearchIndex){if(!hasOwnProperty(rawSearchIndex,crate)){continue}var crateSize=0;searchWords.push(crate);searchIndex.push({crate:crate,ty:1,name:crate,path:"",desc:rawSearchIndex[crate].doc,type:null,});currentIndex+=1;var items=rawSearchIndex[crate].i;var paths=rawSearchIndex[crate].p;var aliases=rawSearchIndex[crate].a;var len=paths.length;for(i=0;i0){search_input.value=params.search;search(e)}else{search_input.value="";hideSearchResults()}})}search()}index=buildIndex(rawSearchIndex);startSearch();if(rootPath==="../"||rootPath==="./"){var sidebar=document.getElementsByClassName("sidebar-elems")[0];if(sidebar){var div=document.createElement("div");div.className="block crate";div.innerHTML="

Crates

";var ul=document.createElement("ul");div.appendChild(ul);var crates=[];for(var crate in rawSearchIndex){if(!hasOwnProperty(rawSearchIndex,crate)){continue}crates.push(crate)}crates.sort();for(var i=0;i','`').replace('','`');return x.innerText}window.initSidebarItems=function(items){var sidebar=document.getElementsByClassName("sidebar-elems")[0];var current=window.sidebarCurrent;function block(shortty,longty){var filtered=items[shortty];if(!filtered){return}var div=document.createElement("div");div.className="block "+shortty;var h3=document.createElement("h3");h3.textContent=longty;div.appendChild(h3);var ul=document.createElement("ul");var length=filtered.length;for(var i=0;i"+""+"
"+code.outerHTML+"
";list.appendChild(display)}}};if(window.pending_implementors){window.register_implementors(window.pending_implementors)}function labelForToggleButton(sectionIsCollapsed){if(sectionIsCollapsed){return"+"}return"\u2212"}function onEveryMatchingChild(elem,className,func){if(elem&&className&&func){var length=elem.childNodes.length;var nodes=elem.childNodes;for(var i=0;i"+labelForToggleButton(sectionIsCollapsed)+"
]";return toggle}function createToggle(toggle,otherMessage,fontSize,extraClass,show){var span=document.createElement("span");span.className="toggle-label";if(show){span.style.display="none"}if(!otherMessage){span.innerHTML=" Expand description"}else{span.innerHTML=otherMessage}if(fontSize){span.style.fontSize=fontSize}var mainToggle=toggle.cloneNode(true);mainToggle.appendChild(span);var wrapper=document.createElement("div");wrapper.className="toggle-wrapper";if(!show){addClass(wrapper,"collapsed");var inner=mainToggle.getElementsByClassName("inner");if(inner&&inner.length>0){inner[0].innerHTML="+"}}if(extraClass){addClass(wrapper,extraClass)}wrapper.appendChild(mainToggle);return wrapper}(function(){var toggles=document.getElementById(toggleAllDocsId);if(toggles){toggles.onclick=toggleAllDocs}var toggle=createSimpleToggle(false);var hideMethodDocs=getSettingValue("auto-hide-method-docs")==="true";var hideImplementors=getSettingValue("auto-collapse-implementors")!=="false";var pageId=getPageId();var func=function(e){var next=e.nextElementSibling;if(next&&hasClass(next,"item-info")){next=next.nextElementSibling}if(!next){return}if(hasClass(next,"docblock")){var newToggle=toggle.cloneNode(true);insertAfter(newToggle,e.childNodes[e.childNodes.length-1]);if(hideMethodDocs===true&&hasClass(e,"method")===true){collapseDocs(newToggle,"hide",pageId)}}};var funcImpl=function(e){var next=e.nextElementSibling;if(next&&hasClass(next,"item-info")){next=next.nextElementSibling}if(next&&hasClass(next,"docblock")){next=next.nextElementSibling}if(!next){return}if(hasClass(e,"impl")&&(next.getElementsByClassName("method").length>0||next.getElementsByClassName("associatedconstant").length>0)){var newToggle=toggle.cloneNode(true);insertAfter(newToggle,e.childNodes[e.childNodes.length-1]);if(hideImplementors===true&&e.parentNode.id==="implementors-list"){collapseDocs(newToggle,"hide",pageId)}}};onEachLazy(document.getElementsByClassName("method"),func);onEachLazy(document.getElementsByClassName("associatedconstant"),func);onEachLazy(document.getElementsByClassName("impl"),funcImpl);var impl_call=function(){};if(hideMethodDocs===true){impl_call=function(e,newToggle){if(e.id.match(/^impl(?:-\d+)?$/)===null){if(hasClass(e,"impl")===true){collapseDocs(newToggle,"hide",pageId)}}}}var newToggle=document.createElement("a");newToggle.href="javascript:void(0)";newToggle.className="collapse-toggle hidden-default collapsed";newToggle.innerHTML="["+labelForToggleButton(true)+"] Show hidden undocumented items";function toggleClicked(){if(hasClass(this,"collapsed")){removeClass(this,"collapsed");onEachLazy(this.parentNode.getElementsByClassName("hidden"),function(x){if(hasClass(x,"content")===false){removeClass(x,"hidden");addClass(x,"x")}},true);this.innerHTML="["+labelForToggleButton(false)+"] Hide undocumented items"}else{addClass(this,"collapsed");onEachLazy(this.parentNode.getElementsByClassName("x"),function(x){if(hasClass(x,"content")===false){addClass(x,"hidden");removeClass(x,"x")}},true);this.innerHTML="["+labelForToggleButton(true)+"] Show hidden undocumented items"}}onEachLazy(document.getElementsByClassName("impl-items"),function(e){onEachLazy(e.getElementsByClassName("associatedconstant"),func);var hiddenElems=e.getElementsByClassName("hidden");var needToggle=false;var hlength=hiddenElems.length;for(var i=0;i"+getSearchLoadingText()+"";showSearchResults(search)}var sidebar_menu=document.getElementsByClassName("sidebar-menu")[0];if(sidebar_menu){sidebar_menu.onclick=function(){var sidebar=document.getElementsByClassName("sidebar")[0];if(hasClass(sidebar,"mobile")===true){hideSidebar()}else{showSidebar()}}}if(main){onEachLazy(main.getElementsByClassName("loading-content"),function(e){e.remove()});onEachLazy(main.childNodes,function(e){if(e.tagName==="H2"||e.tagName==="H3"){var nextTagName=e.nextElementSibling.tagName;if(nextTagName=="H2"||nextTagName=="H3"){e.nextElementSibling.style.display="flex"}else{e.nextElementSibling.style.display="block"}}})}function enableSearchInput(){if(search_input){search_input.removeAttribute('disabled')}}window.addSearchOptions=function(crates){var elem=document.getElementById("crate-search");if(!elem){enableSearchInput();return}var crates_text=[];if(Object.keys(crates).length>1){for(var crate in crates){if(hasOwnProperty(crates,crate)){crates_text.push(crate)}}}crates_text.sort(function(a,b){var lower_a=a.toLowerCase();var lower_b=b.toLowerCase();if(lower_alower_b){return 1}return 0});var savedCrate=getSettingValue("saved-filter-crate");for(var i=0;ithe rustdoc book.";var container=document.createElement("div");var shortcuts=[["?","Show this help dialog"],["S","Focus the search field"],["T","Focus the theme picker menu"],["↑","Move up in search results"],["↓","Move down in search results"],["ctrl + ↑ / ↓","Switch result tab"],["⏎","Go to active search result"],["+","Expand all sections"],["-","Collapse all sections"],].map(x=>"
"+x[0].split(" ").map((y,index)=>(index&1)===0?""+y+"":y).join("")+"
"+x[1]+"
").join("");var div_shortcuts=document.createElement("div");addClass(div_shortcuts,"shortcuts");div_shortcuts.innerHTML="

Keyboard Shortcuts

"+shortcuts+"
";var infos=["Prefix searches with a type followed by a colon (e.g., fn:) to \ + restrict the search to a given item kind.","Accepted kinds are: fn, mod, struct, \ + enum, trait, type, macro, \ + and const.","Search functions by type signature (e.g., vec -> usize or \ + * -> vec)","Search multiple things at once by splitting your query with comma (e.g., \ + str,u8 or String,struct:Vec,test)","You can look for items with an exact name by putting double quotes around \ + your request: \"string\"","Look for items inside another one by searching for a path: vec::Vec",].map(x=>"

"+x+"

").join("");var div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="

Search Tricks

"+infos;container.appendChild(book_info);container.appendChild(div_shortcuts);container.appendChild(div_infos);popup.appendChild(container);insertAfter(popup,getSearchElement());buildHelperPopup=function(){}}onHashChange(null);window.onhashchange=onHashChange}());window.onunload=function(){} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/normalize.css b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/normalize.css new file mode 100644 index 0000000000..6d692b50ca --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/normalize.css @@ -0,0 +1,2 @@ + /*! normalize.css v3.0.0 | MIT License | git.io/normalize */ +html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/noscript.css b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/noscript.css new file mode 100644 index 0000000000..5cbcb9016b --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/noscript.css @@ -0,0 +1 @@ + #main>h2+div,#main>h2+h3,#main>h3+div{display:block;}.loading-content{display:none;}#main>h2+div,#main>h3+div{display:block;}#main>h2+h3{display:flex;}#main .impl-items .hidden{display:block !important;} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/rust-logo.png b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/rust-logo.png new file mode 100644 index 0000000000..74b4bd6950 Binary files /dev/null and b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/rust-logo.png differ diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/rustdoc.css b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/rustdoc.css new file mode 100644 index 0000000000..061171efd1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/rustdoc.css @@ -0,0 +1 @@ + @font-face {font-family:'Fira Sans';font-style:normal;font-weight:400;src:local('Fira Sans'),url("FiraSans-Regular.woff") format('woff');}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:500;src:local('Fira Sans Medium'),url("FiraSans-Medium.woff") format('woff');}@font-face {font-family:'Source Serif Pro';font-style:normal;font-weight:400;src:local('Source Serif Pro'),url("SourceSerifPro-Regular.ttf.woff") format('woff');}@font-face {font-family:'Source Serif Pro';font-style:italic;font-weight:400;src:local('Source Serif Pro Italic'),url("SourceSerifPro-It.ttf.woff") format('woff');}@font-face {font-family:'Source Serif Pro';font-style:normal;font-weight:700;src:local('Source Serif Pro Bold'),url("SourceSerifPro-Bold.ttf.woff") format('woff');}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:400;src:url("SourceCodePro-Regular.woff") format('woff');}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:600;src:url("SourceCodePro-Semibold.woff") format('woff');}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}html{content:"";}@media (prefers-color-scheme:light){html{content:"light";}}@media (prefers-color-scheme:dark){html{content:"dark";}}body{font:16px/1.4 "Source Serif Pro",serif;margin:0;position:relative;padding:10px 15px 20px 15px;-webkit-font-feature-settings:"kern","liga";-moz-font-feature-settings:"kern","liga";font-feature-settings:"kern","liga";}h1{font-size:1.5em;}h2{font-size:1.4em;}h3{font-size:1.3em;}h1,h2,h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable),h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant){font-weight:500;margin:20px 0 15px 0;padding-bottom:6px;}h1.fqn{border-bottom:1px dashed;margin-top:0;}h1.fqn>.in-band>a:hover{text-decoration:underline;}h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant){border-bottom:1px solid;}h3.impl,h3.method,h4.method,h3.type,h4.type,h4.associatedconstant{flex-basis:100%;font-weight:600;margin-top:16px;margin-bottom:10px;position:relative;}h3.impl,h3.method,h3.type{padding-left:15px;}h1,h2,h3,h4,.sidebar,a.source,.search-input,.content table td:first-child>a,.collapse-toggle,div.item-list .out-of-band,#source-sidebar,#sidebar-toggle{font-family:"Fira Sans",sans-serif;}.content ul.crate a.crate{font:16px/1.6 "Fira Sans";}ol,ul{padding-left:25px;}ul ul,ol ul,ul ol,ol ol{margin-bottom:.6em;}p{margin:0 0 .6em 0;}summary{outline:none;}code,pre,a.test-arrow{font-family:"Source Code Pro",monospace;}.docblock code,.docblock-short code{border-radius:3px;padding:0 0.1em;}.docblock pre code,.docblock-short pre code,.docblock code.spotlight{padding:0;}.docblock code.spotlight :last-child{padding-bottom:0.6em;}pre{padding:14px;}.source .content pre{padding:20px;}img{max-width:100%;}li{position:relative;}.source .content{margin-top:50px;max-width:none;overflow:visible;margin-left:0px;min-width:70em;}nav.sub{font-size:16px;text-transform:uppercase;}.sidebar{width:200px;position:fixed;left:0;top:0;bottom:0;overflow:auto;}*{scrollbar-width:initial;}.sidebar{scrollbar-width:thin;}::-webkit-scrollbar{width:12px;}.sidebar::-webkit-scrollbar{width:8px;}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0;}.sidebar .block>ul>li{margin-right:-10px;}.content,nav{max-width:960px;}.hidden{display:none !important;}.logo-container{height:100px;width:100px;position:relative;margin:20px auto;display:block;margin-top:10px;}.logo-container>img{max-width:100px;max-height:100px;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:block;}.sidebar .location{border:1px solid;font-size:17px;margin:30px 10px 20px 10px;text-align:center;word-wrap:break-word;}.sidebar .version{font-size:15px;text-align:center;border-bottom:1px solid;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;}.location:empty{border:none;}.location a:first-child{font-weight:500;}.block{padding:0;margin-bottom:14px;}.block h2,.block h3{margin-top:0;margin-bottom:8px;text-align:center;}.block ul,.block li{margin:0 10px;padding:0;list-style:none;}.block a{display:block;text-overflow:ellipsis;overflow:hidden;line-height:15px;padding:7px 5px;font-size:14px;font-weight:300;transition:border 500ms ease-out;}.sidebar-title{border-top:1px solid;border-bottom:1px solid;text-align:center;font-size:17px;margin-bottom:5px;}.sidebar-links{margin-bottom:15px;}.sidebar-links>a{padding-left:10px;width:100%;}.sidebar-menu{display:none;}.content{padding:15px 0;}.source .content pre.rust{white-space:pre;overflow:auto;padding-left:0;}.rustdoc:not(.source) .example-wrap{display:inline-flex;margin-bottom:10px;position:relative;}.example-wrap{width:100%;}.example-wrap>pre.line-number{overflow:initial;border:1px solid;border-top-left-radius:5px;border-bottom-left-radius:5px;padding:13px 8px;text-align:right;}.rustdoc:not(.source) .example-wrap>pre.rust{width:100%;overflow-x:auto;}.rustdoc:not(.source) .example-wrap>pre{margin:0;}#search{margin-left:230px;position:relative;}#results{position:absolute;right:0;left:0;overflow:auto;}#results>table{width:100%;table-layout:fixed;margin-bottom:40px;}.content pre.line-numbers{float:left;border:none;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}.line-numbers span{cursor:pointer;}.docblock-short{overflow-wrap:anywhere;}.docblock-short p{display:inline;}.docblock-short p{overflow:hidden;text-overflow:ellipsis;margin:0;}.docblock code,.docblock-short code{white-space:pre-wrap;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5{border-bottom:1px solid;}#main>.docblock h1{font-size:1.3em;}#main>.docblock h2{font-size:1.15em;}#main>.docblock h3,#main>.docblock h4,#main>.docblock h5{font-size:1em;}#main>h2+div,#main>h2+h3,#main>h3+div{display:none;flex-wrap:wrap;}.docblock h1{font-size:1em;}.docblock h2{font-size:0.95em;}.docblock h3,.docblock h4,.docblock h5{font-size:0.9em;}.docblock{margin-left:24px;position:relative;}.content .out-of-band{float:right;font-size:23px;margin:0px;padding:0px;font-weight:normal;}h3.impl>.out-of-band{font-size:21px;}h4.method>.out-of-band{font-size:19px;}h4>code,h3>code,.invisible>code{max-width:calc(100% - 41px);display:block;}.invisible{width:100%;display:inline-block;}.content .in-band{margin:0px;padding:0px;}.in-band>code{display:inline-block;}#main{position:relative;}#main>.since{top:inherit;font-family:"Fira Sans",sans-serif;}.content table:not(.table-display){border-spacing:0 5px;}.content td{vertical-align:top;}.content td:first-child{padding-right:20px;}.content td p:first-child{margin-top:0;}.content td h1,.content td h2{margin-left:0;font-size:1.1em;}.content tr:first-child td{border-top:0;}.docblock table{margin:.5em 0;width:calc(100% - 2px);border:1px dashed;}.docblock table td{padding:.5em;border:1px dashed;}.docblock table th{padding:.5em;text-align:left;border:1px solid;}.fields+table{margin-bottom:1em;}.content .item-list{list-style-type:none;padding:0;}.content .multi-column{-moz-column-count:5;-moz-column-gap:2.5em;-webkit-column-count:5;-webkit-column-gap:2.5em;column-count:5;column-gap:2.5em;}.content .multi-column li{width:100%;display:inline-block;}.content .method{font-size:1em;position:relative;}.content .method .where,.content .fn .where,.content .where.fmt-newline{display:block;font-size:0.8em;}.content .methods>div:not(.notable-traits){margin-left:40px;margin-bottom:15px;}.content .docblock>.impl-items{margin-left:20px;margin-top:-34px;}.content .docblock>.impl-items>h4{border-bottom:0;}.content .docblock>.impl-items .table-display{margin:0;}.content .docblock>.impl-items table td{padding:0;}.toggle-wrapper.marg-left>.collapse-toggle{left:-24px;}.content .docblock>.impl-items .table-display,.impl-items table td{border:none;}.content .item-info code{font-size:90%;}.content .item-info{position:relative;margin-left:33px;margin-top:-13px;}.sub-variant>div>.item-info{margin-top:initial;}.content .item-info::before{content:'⬑';font-size:25px;position:absolute;top:-6px;left:-19px;}.content .impl-items .method,.content .impl-items>.type,.impl-items>.associatedconstant{margin-left:20px;}.content .impl-items .docblock,.content .impl-items .item-info{margin-bottom:.6em;}.content .impl-items>.item-info{margin-left:40px;}.methods>.item-info,.content .impl-items>.item-info{margin-top:-8px;}.impl-items{flex-basis:100%;}#main>.item-info{margin-top:0;}nav:not(.sidebar){border-bottom:1px solid;padding-bottom:10px;margin-bottom:10px;}nav.main{padding:20px 0;text-align:center;}nav.main .current{border-top:1px solid;border-bottom:1px solid;}nav.main .separator{border:1px solid;display:inline-block;height:23px;margin:0 20px;}nav.sum{text-align:right;}nav.sub form{display:inline;}nav.sub,.content{margin-left:230px;}a{text-decoration:none;background:transparent;}.small-section-header:hover>.anchor{display:initial;}.in-band:hover>.anchor,.impl:hover>.anchor{display:inline-block;position:absolute;}.anchor{display:none;position:absolute;left:-7px;}.anchor.field{left:-5px;}.small-section-header>.anchor{left:-28px;padding-right:10px;}.anchor:before{content:'\2002\00a7\2002';}.docblock a:not(.srclink):not(.test-arrow):hover,.docblock-short a:not(.srclink):not(.test-arrow):hover,.item-info a{text-decoration:underline;}.invisible>.srclink,h4>code+.srclink,h3>code+.srclink{position:absolute;top:0;right:0;font-size:17px;font-weight:normal;}.block a.current.crate{font-weight:500;}.search-container{position:relative;}.search-container>div{display:inline-flex;width:calc(100% - 63px);}#crate-search{margin-top:5px;padding:6px;padding-right:19px;flex:none;border:0;border-right:0;border-radius:4px 0 0 4px;outline:none;cursor:pointer;border-right:1px solid;-moz-appearance:none;-webkit-appearance:none;text-indent:0.01px;text-overflow:"";background-repeat:no-repeat;background-color:transparent;background-size:20px;background-position:calc(100% - 1px) 56%;}.search-container>.top-button{position:absolute;right:0;top:10px;}.search-input{-moz-box-sizing:border-box !important;box-sizing:border-box !important;outline:none;border:none;border-radius:1px;margin-top:5px;padding:10px 16px;font-size:17px;transition:border-color 300ms ease;transition:border-radius 300ms ease-in-out;transition:box-shadow 300ms ease-in-out;width:100%;}#crate-search+.search-input{border-radius:0 1px 1px 0;width:calc(100% - 32px);}.search-input:focus{border-radius:2px;border:0;outline:0;}.search-results .desc{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;display:block;}.search-results a{display:block;}.content .search-results td:first-child{padding-right:0;width:50%;}.content .search-results td:first-child a{padding-right:10px;}.content .search-results td:first-child a:after{clear:both;content:"";display:block;}.content .search-results td:first-child a span{float:left;}tr.result span.primitive::after{content:' (primitive type)';font-style:italic;}tr.result span.keyword::after{content:' (keyword)';font-style:italic;}body.blur>:not(#help){filter:blur(8px);-webkit-filter:blur(8px);opacity:.7;}#help{width:100%;height:100vh;position:fixed;top:0;left:0;display:flex;justify-content:center;align-items:center;}#help>div{flex:0 0 auto;box-shadow:0 0 6px rgba(0,0,0,.2);width:550px;height:auto;border:1px solid;}#help dt{float:left;clear:left;display:block;}#help>div>span{text-align:center;display:block;margin:10px 0;font-size:18px;border-bottom:1px solid #ccc;padding-bottom:4px;margin-bottom:6px;}#help dd{margin:5px 35px;}#help .infos{padding-left:0;}#help h1,#help h2{margin-top:0;}#help>div div{width:50%;float:left;padding:0 20px 20px 17px;;}.stab{display:table;border-width:1px;border-style:solid;padding:3px;margin-bottom:5px;font-size:90%;}.stab p{display:inline;}.stab summary{display:list-item;}.stab .emoji{font-size:1.5em;}.module-item .stab{border-radius:3px;display:inline-block;font-size:80%;line-height:1.2;margin-bottom:0;margin-right:.3em;padding:2px;vertical-align:text-bottom;}.module-item.unstable{opacity:0.65;}.since{font-weight:normal;font-size:initial;position:absolute;right:0;top:0;}.impl-items .since,.impl .since,.methods .since{flex-grow:0;padding-left:12px;padding-right:2px;position:initial;}.impl-items .srclink,.impl .srclink,.methods .srclink{flex-grow:0;font-size:17px;font-weight:normal;}.impl-items code,.impl code,.methods code{flex-grow:1;}.impl-items h4,h4.impl,h3.impl,.methods h3{display:flex;flex-basis:100%;font-size:16px;margin-bottom:12px;justify-content:space-between;}.variants_table{width:100%;}.variants_table tbody tr td:first-child{width:1%;}td.summary-column{width:100%;}.summary{padding-right:0px;}pre.rust .question-mark{font-weight:bold;}a.test-arrow{display:inline-block;position:absolute;padding:5px 10px 5px 10px;border-radius:5px;font-size:130%;top:5px;right:5px;z-index:1;}a.test-arrow:hover{text-decoration:none;}.section-header:hover a:before{position:absolute;left:-25px;padding-right:10px;content:'\2002\00a7\2002';}.section-header:hover a{text-decoration:none;}.section-header a{color:inherit;}.collapse-toggle{font-weight:300;position:absolute;left:-23px;top:0;}h3>.collapse-toggle,h4>.collapse-toggle{font-size:0.8em;top:5px;}.toggle-wrapper>.collapse-toggle{left:-24px;margin-top:0px;}.toggle-wrapper{position:relative;margin-top:0;}.toggle-wrapper.collapsed{height:25px;transition:height .2s;margin-bottom:.6em;}.collapse-toggle>.inner{display:inline-block;width:1.2ch;text-align:center;}.collapse-toggle.hidden-default{position:relative;margin-left:20px;}.since+.srclink{display:table-cell;padding-left:10px;}.item-spacer{width:100%;height:12px;}.out-of-band>span.since{position:initial;font-size:20px;margin-right:5px;}.toggle-wrapper>.collapse-toggle{left:0;}.variant+.toggle-wrapper+.docblock>p{margin-top:5px;}.sub-variant,.sub-variant>h3{margin-top:1px !important;}#main>.sub-variant>h3{font-size:15px;margin-left:25px;margin-bottom:5px;}.sub-variant>div{margin-left:20px;margin-bottom:10px;}.sub-variant>div>span{display:block;position:relative;}.toggle-label{display:inline-block;margin-left:4px;margin-top:3px;}.enum>.toggle-wrapper+.docblock,.struct>.toggle-wrapper+.docblock{margin-left:30px;margin-bottom:20px;margin-top:5px;}.docblock>.section-header:first-child{margin-left:15px;margin-top:0;}.docblock>.section-header:first-child:hover>a:before{left:-10px;}.enum>.collapsed,.struct>.collapsed{margin-bottom:25px;}#main>.variant,#main>.structfield{display:block;}.attributes{display:block;margin-top:0px !important;margin-right:0px;margin-bottom:0px !important;margin-left:30px;}.toggle-attributes.collapsed{margin-bottom:0;}.impl-items>.toggle-attributes{margin-left:20px;}.impl-items .attributes{font-weight:500;}:target>code{opacity:1;}.information{position:absolute;left:-25px;margin-top:7px;z-index:1;}.tooltip{position:relative;display:inline-block;cursor:pointer;}.tooltip .tooltiptext{width:120px;display:none;text-align:center;padding:5px 3px 3px 3px;border-radius:6px;margin-left:5px;top:-5px;left:105%;z-index:10;font-size:16px;}.tooltip .tooltiptext::after{content:" ";position:absolute;top:50%;left:16px;margin-top:-5px;border-width:5px;border-style:solid;}.tooltip:hover .tooltiptext{display:inline;}.tooltip.compile_fail,.tooltip.should_panic,.tooltip.ignore{font-weight:bold;font-size:20px;}.notable-traits-tooltip{display:inline-block;cursor:pointer;}.notable-traits:hover .notable-traits-tooltiptext,.notable-traits .notable-traits-tooltiptext.force-tooltip{display:inline-block;}.notable-traits .notable-traits-tooltiptext{display:none;padding:5px 3px 3px 3px;border-radius:6px;margin-left:5px;z-index:10;font-size:16px;cursor:default;position:absolute;border:1px solid;}.notable-traits-tooltip::after{content:"\00a0\00a0\00a0";}.notable-traits .notable,.notable-traits .docblock{margin:0;}.notable-traits .docblock code.content{margin:0;padding:0;font-size:20px;}pre.rust.rust-example-rendered{position:relative;}pre.rust{tab-size:4;-moz-tab-size:4;}.search-failed{text-align:center;margin-top:20px;}.search-failed>ul{text-align:left;max-width:570px;margin-left:auto;margin-right:auto;}#titles{height:35px;}#titles>button{float:left;width:33.3%;text-align:center;font-size:18px;cursor:pointer;border:0;border-top:2px solid;}#titles>button:not(:last-child){margin-right:1px;width:calc(33.3% - 1px);}#titles>button>div.count{display:inline-block;font-size:16px;}.notable-traits{cursor:pointer;z-index:2;margin-left:5px;}h4>.notable-traits{position:absolute;left:-44px;top:2px;}#all-types{text-align:center;border:1px solid;margin:0 10px;margin-bottom:10px;display:block;border-radius:7px;}#all-types>p{margin:5px 0;}#sidebar-toggle{position:fixed;top:30px;left:300px;z-index:10;padding:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;cursor:pointer;font-weight:bold;transition:left .5s;font-size:1.2em;border:1px solid;border-left:0;}#source-sidebar{position:fixed;top:0;bottom:0;left:0;width:300px;z-index:1;overflow:auto;transition:left .5s;border-right:1px solid;}#source-sidebar>.title{font-size:1.5em;text-align:center;border-bottom:1px solid;margin-bottom:6px;}.theme-picker{position:absolute;left:211px;top:19px;}.theme-picker button{outline:none;}#settings-menu,.help-button{position:absolute;top:10px;}#settings-menu{right:0;outline:none;}.help-button{right:30px;font-family:"Fira Sans",sans-serif;text-align:center;font-size:17px;}#theme-picker,#settings-menu,.help-button{padding:4px;width:27px;height:29px;border:1px solid;border-radius:3px;cursor:pointer;}#theme-choices{display:none;position:absolute;left:0;top:28px;border:1px solid;border-radius:3px;z-index:1;cursor:pointer;}#theme-choices>button{border:none;width:100%;padding:4px 8px;text-align:center;background:rgba(0,0,0,0);}#theme-choices>button:not(:first-child){border-top:1px solid;}@media (min-width:701px){.information:first-child>.tooltip{margin-top:16px;}}@media (max-width:700px){body{padding-top:0px;}.rustdoc>.sidebar{height:45px;min-height:40px;margin:0;margin-left:-15px;padding:0 15px;position:static;z-index:11;}.sidebar>.location{float:right;margin:0px;margin-top:2px;padding:3px 10px 1px 10px;min-height:39px;background:inherit;text-align:left;font-size:24px;}.sidebar .location:empty{padding:0;}.sidebar .logo-container{width:35px;height:35px;margin-top:5px;margin-bottom:5px;float:left;margin-left:50px;}.sidebar .logo-container>img{max-width:35px;max-height:35px;}.sidebar-menu{position:fixed;z-index:10;font-size:2rem;cursor:pointer;width:45px;left:0;text-align:center;display:block;border-bottom:1px solid;border-right:1px solid;height:45px;}.rustdoc.source>.sidebar>.sidebar-menu{display:none;}.sidebar-elems{position:fixed;z-index:1;left:0;top:45px;bottom:0;overflow-y:auto;border-right:1px solid;display:none;}.sidebar>.block.version{border-bottom:none;margin-top:12px;}nav.sub{width:calc(100% - 32px);float:right;}.content{margin-left:0px;}#main{margin-top:45px;padding:0;}.content .in-band{width:100%;}.content h4>.out-of-band{position:inherit;}.toggle-wrapper>.collapse-toggle{left:0px;}.toggle-wrapper{height:1.5em;}#search{margin-left:0;}.content .impl-items .method,.content .impl-items>.type,.impl-items>.associatedconstant{display:flex;}.anchor{display:none !important;}h1.fqn{overflow:initial;}.theme-picker{left:10px;top:54px;z-index:1;}h4>.notable-traits{position:absolute;left:-22px;top:24px;}#titles>button>div.count{float:left;width:100%;}#titles{height:50px;}.sidebar.mobile{position:fixed;width:100%;margin-left:0;background-color:rgba(0,0,0,0);height:100%;}.sidebar{width:calc(100% + 30px);}.show-it{display:block;width:246px;}.show-it>.block.items{margin:8px 0;}.show-it>.block.items>ul{margin:0;}.show-it>.block.items>ul>li{text-align:center;margin:2px 0;}.show-it>.block.items>ul>li>a{font-size:21px;}#sidebar-filler{position:fixed;left:45px;width:calc(100% - 45px);top:0;height:45px;z-index:-1;border-bottom:1px solid;}.collapse-toggle{left:-20px;}.impl>.collapse-toggle{left:-10px;}#all-types{margin:10px;}#sidebar-toggle{top:100px;width:30px;font-size:1.5rem;text-align:center;padding:0;}#source-sidebar{z-index:11;}#main>.line-numbers{margin-top:0;}.notable-traits .notable-traits-tooltiptext{left:0;top:100%;}.help-button{display:none;}.search-container>div{width:calc(100% - 32px);}}@media print{nav.sub,.content .out-of-band,.collapse-toggle{display:none;}}@media (max-width:416px){#titles,#titles>button{height:73px;}#main{margin-top:100px;}#main>table:not(.table-display) td{word-break:break-word;width:50%;}.search-container>div{display:block;width:calc(100% - 37px);}#crate-search{width:100%;border-radius:4px;border:0;}#crate-search+.search-input{width:calc(100% + 71px);margin-left:-36px;}#theme-picker,#settings-menu{padding:5px;width:31px;height:31px;}#theme-picker{margin-top:-2px;}#settings-menu{top:7px;}}h3.notable{margin:0;margin-bottom:13px;font-size:19px;}kbd{display:inline-block;padding:3px 5px;font:15px monospace;line-height:10px;vertical-align:middle;border:solid 1px;border-radius:3px;box-shadow:inset 0 -1px 0;cursor:default;}.hidden-by-impl-hider,.hidden-by-usual-hider{display:none !important;}#implementations-list>h3>span.in-band{width:100%;}.table-display{width:100%;border:0;border-collapse:collapse;border-spacing:0;font-size:16px;}.table-display tr td:first-child{padding-right:0;}.table-display tr td:last-child{float:right;}.table-display .out-of-band{position:relative;font-size:19px;display:block;}#implementors-list>.impl-items .table-display .out-of-band{font-size:17px;}.table-display td:hover .anchor{display:block;top:2px;left:-5px;}#main>ul{padding-left:10px;}#main>ul>li{list-style:none;}.non-exhaustive{margin-bottom:1em;}div.children{padding-left:27px;display:none;}div.name{cursor:pointer;position:relative;margin-left:16px;}div.files>a{display:block;padding:0 3px;}div.files>a:hover,div.name:hover{background-color:#a14b4b;}div.name.expand+.children{display:block;}div.name::before{content:"\25B6";padding-left:4px;font-size:0.7em;position:absolute;left:-16px;top:4px;}div.name.expand::before{transform:rotate(90deg);left:-15px;top:2px;}.type-decl>pre>.toggle-wrapper.toggle-attributes.top-attr{margin-left:0 !important;}.type-decl>pre>.docblock.attributes.top-attr{margin-left:1.8em !important;}.type-decl>pre>.toggle-attributes{margin-left:2.2em;}.type-decl>pre>.docblock.attributes{margin-left:4em;} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/search-index.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/search-index.js new file mode 100644 index 0000000000..328e2f87cd --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/search-index.js @@ -0,0 +1,4 @@ +var searchIndex = JSON.parse('{\ +"bdk":{"doc":"A modern, lightweight, descriptor-based wallet library …","i":[[0,"blockchain","bdk","Blockchain backends",null,null],[0,"any","bdk::blockchain","Runtime-checked blockchain types",null,null],[4,"AnyBlockchain","bdk::blockchain::any","Type that can contain any of the [Blockchain] types …",null,null],[13,"Electrum","","Electrum client",0,null],[13,"Esplora","","Esplora client",0,null],[13,"CompactFilters","","Compact filters client",0,null],[4,"AnyBlockchainConfig","","Type that can contain any of the blockchain …",null,null],[13,"Electrum","","Electrum client",1,null],[13,"Esplora","","Esplora client",1,null],[13,"CompactFilters","","Compact filters client",1,null],[0,"electrum","bdk::blockchain","Electrum",null,null],[3,"ElectrumBlockchain","bdk::blockchain::electrum","Wrapper over an Electrum Client that implements the …",null,null],[3,"ElectrumBlockchainConfig","","Configuration for an [ElectrumBlockchain]",null,null],[12,"url","","URL of the Electrum server (such as ElectrumX, Esplora, …",2,null],[12,"socks5","","URL of the socks5 proxy server or a Tor service",2,null],[12,"retry","","Request retry count",2,null],[12,"timeout","","Request timeout (seconds)",2,null],[0,"esplora","bdk::blockchain","Esplora",null,null],[3,"EsploraBlockchain","bdk::blockchain::esplora","Structure that implements the logic to sync with Esplora",null,null],[11,"new","","Create a new instance of the client from a base URL",3,[[["option",4]]]],[3,"EsploraBlockchainConfig","","Configuration for an [EsploraBlockchain]",null,null],[12,"base_url","","Base URL of the esplora service",4,null],[12,"concurrency","","Number of parallel requests sent to the esplora service …",4,null],[4,"EsploraError","","Errors that can happen during a sync with […",null,null],[13,"Reqwest","","Error with the HTTP call",5,null],[13,"Parsing","","Invalid number returned",5,null],[13,"BitcoinEncoding","","Invalid Bitcoin data returned",5,null],[13,"Hex","","Invalid Hex data returned",5,null],[13,"TransactionNotFound","","Transaction not found",5,null],[13,"HeaderHeightNotFound","","Header height not found",5,null],[13,"HeaderHashNotFound","","Header hash not found",5,null],[0,"compact_filters","bdk::blockchain","Compact Filters",null,null],[3,"Mempool","bdk::blockchain::compact_filters","Container for unconfirmed, but valid Bitcoin transactions",null,null],[3,"Peer","","A Bitcoin peer",null,null],[3,"CompactFiltersBlockchain","","Structure implementing the required blockchain traits",null,null],[11,"new","","Construct a new instance given a list of peers, a path to …",6,[[["peer",3],["asref",8],["option",4],["vec",3],["path",3]],[["compactfilterserror",4],["result",4]]]],[3,"BitcoinPeerConfig","","Data to connect to a Bitcoin P2P peer",null,null],[12,"address","","Peer address such as 127.0.0.1:18333",7,null],[12,"socks5","","Optional socks5 proxy",7,null],[12,"socks5_credentials","","Optional socks5 proxy credentials",7,null],[3,"CompactFiltersBlockchainConfig","","Configuration for a [CompactFiltersBlockchain]",null,null],[12,"peers","","List of peers to try to connect to for asking headers and …",8,null],[12,"network","","Network used",8,null],[12,"storage_dir","","Storage dir to save partially downloaded headers and full …",8,null],[12,"skip_blocks","","Optionally skip initial skip_blocks blocks (default: 0)",8,null],[4,"CompactFiltersError","","An error that can occur during sync with a […",null,null],[13,"InvalidResponse","","A peer sent an invalid or unexpected response",9,null],[13,"InvalidHeaders","","The headers returned are invalid",9,null],[13,"InvalidFilterHeader","","The compact filter headers returned are invalid",9,null],[13,"InvalidFilter","","The compact filter returned is invalid",9,null],[13,"MissingBlock","","The peer is missing a block in the valid chain",9,null],[13,"DataCorruption","","The data stored in the block filters storage are corrupted",9,null],[13,"NotConnected","","A peer is not connected",9,null],[13,"Timeout","","A peer took too long to reply to one of our messages",9,null],[13,"NoPeers","","No peers have been specified",9,null],[13,"DB","","Internal database error",9,null],[13,"IO","","Internal I/O error",9,null],[13,"BIP158","","Invalid BIP158 filter",9,null],[13,"Time","","Internal system time error",9,null],[13,"Global","","Wrapper for [crate::error::Error]",9,null],[4,"Capability","bdk::blockchain","Capabilities that can be supported by a [Blockchain] …",null,null],[13,"FullHistory","","Can recover the full history of a wallet and not only the …",10,null],[13,"GetAnyTx","","Can fetch any historical transaction given its txid",10,null],[13,"AccurateFees","","Can compute accurate fees for the transactions found …",10,null],[8,"BlockchainMarker","","Marker trait for a blockchain backend",null,null],[3,"OfflineBlockchain","","Type that only implements [BlockchainMarker] and is …",null,null],[8,"Blockchain","","Trait that defines the actions that must be supported by …",null,null],[10,"get_capabilities","","Return the set of [Capability] supported by this backend",11,[[],[["hashset",3],["capability",4]]]],[10,"setup","","Setup the backend and populate the internal database for …",11,[[["progress",8],["option",4]],[["error",4],["result",4]]]],[11,"sync","","Populate the internal database with transactions and UTXOs",11,[[["progress",8],["option",4]],[["error",4],["result",4]]]],[10,"get_tx","","Fetch a transaction from the blockchain given its txid",11,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[10,"broadcast","","Broadcast a transaction",11,[[["transaction",3]],[["error",4],["result",4]]]],[10,"get_height","","Return the current height",11,[[],[["result",4],["error",4]]]],[10,"estimate_fee","","Estimate the fee rate required to confirm a transaction …",11,[[],[["feerate",3],["error",4],["result",4]]]],[8,"ConfigurableBlockchain","","Trait for [Blockchain] types that can be created given a …",null,null],[16,"Config","","Type that contains the configuration",12,null],[10,"from_config","","Create a new instance given a configuration",12,[[],[["result",4],["error",4]]]],[6,"ProgressData","","Data sent with a progress update over a [channel]",null,null],[8,"Progress","","Trait for types that can receive and process progress …",null,null],[10,"update","","Send a new progress update",13,[[["string",3],["option",4]],[["error",4],["result",4]]]],[5,"progress","","Shortcut to create a [channel] (pair of [Sender] and […",null,[[]]],[3,"NoopProgress","","Type that implements [Progress] and drops every update …",null,null],[5,"noop_progress","","Create a new instance of [NoopProgress]",null,[[],["noopprogress",3]]],[3,"LogProgress","","Type that implements [Progress] and logs at level INFO …",null,null],[5,"log_progress","","Create a nwe instance of [LogProgress]",null,[[],["logprogress",3]]],[0,"database","bdk","Database types",null,null],[0,"any","bdk::database","Runtime-checked database types",null,null],[4,"AnyDatabase","bdk::database::any","Type that can contain any of the [Database] types defined …",null,null],[13,"Memory","","In-memory ephemeral database",14,null],[13,"Sled","","Simple key-value embedded database based on [sled]",14,null],[4,"AnyBatch","","Type that contains any of the [BatchDatabase::Batch] …",null,null],[13,"Memory","","In-memory ephemeral database",15,null],[13,"Sled","","Simple key-value embedded database based on [sled]",15,null],[3,"SledDbConfiguration","","Configuration type for a [sled::Tree] database",null,null],[12,"path","","Main directory of the db",16,null],[12,"tree_name","","Name of the database tree, a separated namespace for the …",16,null],[4,"AnyDatabaseConfig","","Type that can contain any of the database configurations …",null,null],[13,"Memory","","Memory database has no config",17,null],[13,"Sled","","Simple key-value embedded database based on [sled]",17,null],[0,"memory","bdk::database","In-memory ephemeral database",null,null],[3,"MemoryDatabase","bdk::database::memory","In-memory ephemeral database",null,null],[11,"new","","Create a new empty database",18,[[]]],[8,"BatchOperations","bdk::database","Trait for operations that can be batched",null,null],[10,"set_script_pubkey","","Store a script_pubkey along with its keychain and child …",19,[[["script",3],["keychainkind",4]],[["error",4],["result",4]]]],[10,"set_utxo","","Store a [UTXO]",19,[[["utxo",3]],[["error",4],["result",4]]]],[10,"set_raw_tx","","Store a raw transaction",19,[[["transaction",3]],[["error",4],["result",4]]]],[10,"set_tx","","Store the metadata of a transaction",19,[[["transactiondetails",3]],[["error",4],["result",4]]]],[10,"set_last_index","","Store the last derivation index for a given keychain.",19,[[["keychainkind",4]],[["error",4],["result",4]]]],[10,"del_script_pubkey_from_path","","Delete a script_pubkey given the keychain and its child …",19,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[10,"del_path_from_script_pubkey","","Delete the data related to a specific script_pubkey, …",19,[[["script",3]],[["error",4],["result",4],["option",4]]]],[10,"del_utxo","","Delete a [UTXO] given its [OutPoint]",19,[[["outpoint",3]],[["result",4],["option",4],["error",4]]]],[10,"del_raw_tx","","Delete a raw transaction given its [Txid]",19,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[10,"del_tx","","Delete the metadata of a transaction and optionally the …",19,[[["txid",3]],[["option",4],["result",4],["error",4]]]],[10,"del_last_index","","Delete the last derivation index for a keychain.",19,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[8,"Database","","Trait for reading data from a database",null,null],[10,"check_descriptor_checksum","","Read and checks the descriptor checksum for a given …",20,[[["asref",8],["keychainkind",4]],[["error",4],["result",4]]]],[10,"iter_script_pubkeys","","Return the list of script_pubkeys",20,[[["option",4],["keychainkind",4]],[["vec",3],["result",4],["error",4]]]],[10,"iter_utxos","","Return the list of [UTXO]s",20,[[],[["result",4],["vec",3],["error",4]]]],[10,"iter_raw_txs","","Return the list of raw transactions",20,[[],[["vec",3],["result",4],["error",4]]]],[10,"iter_txs","","Return the list of transactions metadata",20,[[],[["error",4],["result",4],["vec",3]]]],[10,"get_script_pubkey_from_path","","Fetch a script_pubkey given the child number of a …",20,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[10,"get_path_from_script_pubkey","","Fetch the keychain and child number of a given …",20,[[["script",3]],[["error",4],["result",4],["option",4]]]],[10,"get_utxo","","Fetch a [UTXO] given its [OutPoint]",20,[[["outpoint",3]],[["result",4],["option",4],["error",4]]]],[10,"get_raw_tx","","Fetch a raw transaction given its [Txid]",20,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[10,"get_tx","","Fetch the transaction metadata and optionally also the …",20,[[["txid",3]],[["option",4],["result",4],["error",4]]]],[10,"get_last_index","","Return the last defivation index for a keychain.",20,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[10,"increment_last_index","","Increment the last derivation index for a keychain and …",20,[[["keychainkind",4]],[["result",4],["error",4]]]],[8,"BatchDatabase","","Trait for a database that supports batch operations",null,null],[16,"Batch","","Container for the operations",21,null],[10,"begin_batch","","Create a new batch container",21,[[]]],[10,"commit_batch","","Consume and apply a batch of operations",21,[[],[["error",4],["result",4]]]],[8,"ConfigurableDatabase","","Trait for [Database] types that can be created given a …",null,null],[16,"Config","","Type that contains the configuration",22,null],[10,"from_config","","Create a new instance given a configuration",22,[[],[["result",4],["error",4]]]],[0,"descriptor","bdk","Descriptors",null,null],[6,"KeyMap","bdk::descriptor","Alias type for a map of public key to secret key",null,null],[4,"Descriptor","","Script descriptor",null,null],[13,"Bare","","A raw scriptpubkey (including pay-to-pubkey) under Legacy …",23,null],[13,"Pk","","Pay-to-Pubkey",23,null],[13,"Pkh","","Pay-to-PubKey-Hash",23,null],[13,"Wpkh","","Pay-to-Witness-PubKey-Hash",23,null],[13,"ShWpkh","","Pay-to-Witness-PubKey-Hash inside P2SH",23,null],[13,"Sh","","Pay-to-ScriptHash with Legacy context",23,null],[13,"Wsh","","Pay-to-Witness-ScriptHash with Segwitv0 context",23,null],[13,"ShWsh","","P2SH-P2WSH with Segwitv0 context",23,null],[13,"ShSortedMulti","","Sortedmulti under P2SH",23,null],[13,"WshSortedMulti","","Sortedmulti under P2WSH",23,null],[13,"ShWshSortedMulti","","Sortedmulti under P2SH-P2WSH",23,null],[4,"Legacy","","Legacy ScriptContext To be used as P2SH scripts For …",null,null],[3,"Miniscript","","Top-level script AST type",null,null],[12,"node","","A node in the Abstract Syntax Tree(",24,null],[12,"ty","","The correctness and malleability type information for the …",24,null],[12,"ext","","Additional information helpful for extra analysis.",24,null],[8,"MiniscriptKey","","Public key trait which can be converted to Hash type",null,null],[11,"is_uncompressed","","Check if the publicKey is uncompressed. The default …",25,[[]]],[16,"Hash","","The associated Hash type with the publicKey",25,null],[10,"to_pubkeyhash","","Converts an object to PublicHash",25,[[]]],[8,"ScriptContext","","The ScriptContext for Miniscript. Additional type …",null,null],[10,"check_terminal_non_malleable","","Depending on ScriptContext, fragments can be malleable. …",26,[[["terminal",4]],[["scriptcontexterror",4],["result",4]]]],[11,"check_witness","","Check whether the given satisfaction is valid under the …",26,[[],[["scriptcontexterror",4],["result",4]]]],[10,"max_satisfaction_size","","Depending on script context, the size of a satifaction …",26,[[["miniscript",3]],["option",4]]],[11,"check_global_consensus_validity","","Depending on script Context, some of the Terminals might …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_global_policy_validity","","Depending on script Context, some of the script resource …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_consensus_validity","","Consensus rules at the Miniscript satisfaction time. It …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_policy_validity","","Policy rules at the Miniscript satisfaction time. It is …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_global_validity","","Check the consensus + policy(if not disabled) rules that …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_validity","","Check the consensus + policy(if not disabled) rules …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"top_level_type_check","","Check whether the top-level is type B",26,[[["miniscript",3]],[["error",4],["result",4]]]],[11,"other_top_level_checks","","Other top level checks that are context specific",26,[[["miniscript",3]],[["error",4],["result",4]]]],[11,"top_level_checks","","Check top level consensus rules.",26,[[["miniscript",3]],[["error",4],["result",4]]]],[4,"Segwitv0","","Segwitv0 ScriptContext",null,null],[4,"Terminal","","All AST elements",null,null],[13,"True","","1",27,null],[13,"False","","0",27,null],[13,"PkK","","",27,null],[13,"PkH","","DUP HASH160 EQUALVERIFY",27,null],[13,"After","","n CHECKLOCKTIMEVERIFY",27,null],[13,"Older","","n CHECKSEQUENCEVERIFY",27,null],[13,"Sha256","","SIZE 32 EQUALVERIFY SHA256 EQUAL",27,null],[13,"Hash256","","SIZE 32 EQUALVERIFY HASH256 EQUAL",27,null],[13,"Ripemd160","","SIZE 32 EQUALVERIFY RIPEMD160 EQUAL",27,null],[13,"Hash160","","SIZE 32 EQUALVERIFY HASH160 EQUAL",27,null],[13,"Alt","","TOALTSTACK [E] FROMALTSTACK",27,null],[13,"Swap","","SWAP [E1]",27,null],[13,"Check","","[Kt]/[Ke] CHECKSIG",27,null],[13,"DupIf","","DUP IF [V] ENDIF",27,null],[13,"Verify","","[T] VERIFY",27,null],[13,"NonZero","","SIZE 0NOTEQUAL IF [Fn] ENDIF",27,null],[13,"ZeroNotEqual","","[X] 0NOTEQUAL",27,null],[13,"AndV","","[V] [T]/[V]/[F]/[Kt]",27,null],[13,"AndB","","[E] [W] BOOLAND",27,null],[13,"AndOr","","[various] NOTIF [various] ELSE [various] ENDIF",27,null],[13,"OrB","","[E] [W] BOOLOR",27,null],[13,"OrD","","[E] IFDUP NOTIF [T]/[E] ENDIF",27,null],[13,"OrC","","[E] NOTIF [V] ENDIF",27,null],[13,"OrI","","IF [various] ELSE [various] ENDIF",27,null],[13,"Thresh","","[E] ([W] ADD)* k EQUAL",27,null],[13,"Multi","","k ()* n CHECKMULTISIG",27,null],[8,"ToPublicKey","","Trait describing public key types which can be converted …",null,null],[10,"to_public_key","","Converts an object to a public key C represents …",28,[[],["publickey",3]]],[11,"serialized_len","","Computes the size of a public key when serialized in a …",28,[[]]],[10,"hash_to_hash160","","Converts a hashed version of the public key to a hash160 …",28,[[],["hash",3]]],[0,"checksum","","Descriptor checksum",null,null],[5,"get_checksum","bdk::descriptor::checksum","Compute the checksum of a descriptor",null,[[],[["result",4],["string",3],["error",4]]]],[0,"error","bdk::descriptor","Descriptor errors",null,null],[4,"Error","bdk::descriptor::error","Errors related to the parsing and usage of descriptors",null,null],[13,"InvalidHDKeyPath","","Invalid HD Key path, such as having a wildcard but a …",29,null],[13,"Key","","Error thrown while working with keys",29,null],[13,"Policy","","Error while extracting and manipulating policies",29,null],[13,"InvalidDescriptorCharacter","","Invalid character found in the descriptor checksum",29,null],[13,"BIP32","","BIP32 error",29,null],[13,"Base58","","Error during base58 decoding",29,null],[13,"PK","","Key-related error",29,null],[13,"Miniscript","","Miniscript error",29,null],[13,"Hex","","Hex decoding error",29,null],[0,"policy","bdk::descriptor","Descriptor policy",null,null],[3,"PKOrF","bdk::descriptor::policy","Raw public key or extended key fingerprint",null,null],[4,"SatisfiableItem","","An item that needs to be satisfied",null,null],[13,"Signature","","Signature for a raw public key",30,null],[13,"SignatureKey","","Signature for an extended key fingerprint",30,null],[13,"SHA256Preimage","","SHA256 preimage hash",30,null],[12,"hash","bdk::descriptor::policy::SatisfiableItem","The digest value",31,null],[13,"HASH256Preimage","bdk::descriptor::policy","Double SHA256 preimage hash",30,null],[12,"hash","bdk::descriptor::policy::SatisfiableItem","The digest value",32,null],[13,"RIPEMD160Preimage","bdk::descriptor::policy","RIPEMD160 preimage hash",30,null],[12,"hash","bdk::descriptor::policy::SatisfiableItem","The digest value",33,null],[13,"HASH160Preimage","bdk::descriptor::policy","SHA256 then RIPEMD160 preimage hash",30,null],[12,"hash","bdk::descriptor::policy::SatisfiableItem","The digest value",34,null],[13,"AbsoluteTimelock","bdk::descriptor::policy","Absolute timeclock timestamp",30,null],[12,"value","bdk::descriptor::policy::SatisfiableItem","The timestamp value",35,null],[13,"RelativeTimelock","bdk::descriptor::policy","Relative timelock locktime",30,null],[12,"value","bdk::descriptor::policy::SatisfiableItem","The locktime value",36,null],[13,"Multisig","bdk::descriptor::policy","Multi-signature public keys with threshold count",30,null],[12,"keys","bdk::descriptor::policy::SatisfiableItem","The raw public key or extended key fingerprint",37,null],[12,"threshold","","The required threshold count",37,null],[13,"Thresh","bdk::descriptor::policy","Threshold items with threshold count",30,null],[12,"items","bdk::descriptor::policy::SatisfiableItem","The policy items",38,null],[12,"threshold","","The required threshold count",38,null],[11,"is_leaf","bdk::descriptor::policy","Returns whether the [SatisfiableItem] is a leaf item",30,[[]]],[11,"id","","Returns a unique id for the [SatisfiableItem]",30,[[],["string",3]]],[6,"ConditionMap","","Type for a map of sets of [Condition] items keyed by each …",null,null],[6,"FoldedConditionMap","","Type for a map of folded sets of [Condition] items keyed …",null,null],[4,"Satisfaction","","Represent if and how much a policy item is satisfied by …",null,null],[13,"Partial","","Only a partial satisfaction of some kind of threshold …",39,null],[12,"n","bdk::descriptor::policy::Satisfaction","Total number of items",40,null],[12,"m","","Threshold",40,null],[12,"items","","The items that can be satisfied by the descriptor",40,null],[12,"sorted","","Whether the items are sorted in lexicographic order (used …",40,null],[12,"conditions","","Extra conditions that also need to be satisfied",40,null],[13,"PartialComplete","bdk::descriptor::policy","Can reach the threshold of some kind of threshold policy",39,null],[12,"n","bdk::descriptor::policy::Satisfaction","Total number of items",41,null],[12,"m","","Threshold",41,null],[12,"items","","The items that can be satisfied by the descriptor",41,null],[12,"sorted","","Whether the items are sorted in lexicographic order (used …",41,null],[12,"conditions","","Extra conditions that also need to be satisfied",41,null],[13,"Complete","bdk::descriptor::policy","Can satisfy the policy item",39,null],[12,"condition","bdk::descriptor::policy::Satisfaction","Extra conditions that also need to be satisfied",42,null],[13,"None","bdk::descriptor::policy","Cannot satisfy or contribute to the policy item",39,null],[11,"is_leaf","","Returns whether the [Satisfaction] is a leaf item",39,[[]]],[3,"Policy","","Descriptor spending policy",null,null],[12,"id","","Identifier for this policy node",43,null],[12,"item","","Type of this policy node",43,null],[12,"satisfaction","","How a much given PSBT already satisfies this polcy node …",43,null],[12,"contribution","","How the wallet\'s descriptor can satisfy this policy node",43,null],[3,"Condition","","An extra condition that must be satisfied but that is out …",null,null],[12,"csv","","Optional CheckSequenceVerify condition",44,null],[12,"timelock","","Optional timelock condition",44,null],[11,"is_null","","Returns true if there are no extra conditions to verify",44,[[]]],[4,"PolicyError","","Errors that can happen while extracting and manipulating …",null,null],[13,"NotEnoughItemsSelected","","Not enough items are selected to satisfy a […",45,null],[13,"TooManyItemsSelected","","Too many items are selected to satisfy a […",45,null],[13,"IndexOutOfRange","","Index out of range for an item to satisfy a […",45,null],[13,"AddOnLeaf","","Can not add to an item that is [Satisfaction::None] or […",45,null],[13,"AddOnPartialComplete","","Can not add to an item that is […",45,null],[13,"MixedTimelockUnits","","Can not merge CSV or timelock values unless both are less …",45,null],[13,"IncompatibleConditions","","Incompatible conditions (not currently used)",45,null],[11,"requires_path","","Return whether or not a specific path in the policy tree …",43,[[]]],[11,"get_condition","","Return the conditions that are set by the spending policy …",43,[[["btreemap",3]],[["condition",3],["result",4],["policyerror",4]]]],[0,"template","bdk::descriptor","Descriptor templates",null,null],[6,"DescriptorTemplateOut","bdk::descriptor::template","Type alias for the return type of [DescriptorTemplate], …",null,null],[8,"DescriptorTemplate","","Trait for descriptor templates that can be built into a …",null,null],[10,"build","","Build the complete descriptor",46,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[3,"P2PKH","","P2PKH template. Expands to a descriptor pkh(key)",null,null],[12,"0","","",47,null],[3,"P2WPKH_P2SH","","P2WPKH-P2SH template. Expands to a descriptor …",null,null],[12,"0","","",48,null],[3,"P2WPKH","","P2WPKH template. Expands to a descriptor wpkh(key)",null,null],[12,"0","","",49,null],[3,"BIP44","","BIP44 template. Expands to pkh(key/44\'/0\'/0\'/{0,1}/*)",null,null],[12,"0","","",50,null],[12,"1","","",50,null],[3,"BIP44Public","","BIP44 public template. Expands to pkh(key/{0,1}/*)",null,null],[12,"0","","",51,null],[12,"1","","",51,null],[12,"2","","",51,null],[3,"BIP49","","BIP49 template. Expands to sh(wpkh(key/49\'/0\'/0\'/{0,1}/*))",null,null],[12,"0","","",52,null],[12,"1","","",52,null],[3,"BIP49Public","","BIP49 public template. Expands to sh(wpkh(key/{0,1}/*))",null,null],[12,"0","","",53,null],[12,"1","","",53,null],[12,"2","","",53,null],[3,"BIP84","","BIP84 template. Expands to wpkh(key/84\'/0\'/0\'/{0,1}/*)",null,null],[12,"0","","",54,null],[12,"1","","",54,null],[3,"BIP84Public","","BIP84 public template. Expands to wpkh(key/{0,1}/*)",null,null],[12,"0","","",55,null],[12,"1","","",55,null],[12,"2","","",55,null],[6,"ExtendedDescriptor","bdk::descriptor","Alias for a [Descriptor] that can contain extended keys …",null,null],[6,"HDKeyPaths","","Alias for the type of maps that represent derivation …",null,null],[8,"ToWalletDescriptor","","Trait for types which can be converted into an […",null,null],[10,"to_wallet_descriptor","","Convert to wallet descriptor",56,[[["network",4]],[["result",4],["keyerror",4]]]],[8,"ExtractPolicy","","Trait implemented on [Descriptor]s to add a method to …",null,null],[10,"extract_policy","","Extract the spending [policy]",57,[[["signerscontainer",3],["secp256k1",3]],[["result",4],["error",4],["option",4]]]],[0,"keys","bdk","Key formats",null,null],[4,"DescriptorPublicKey","bdk::keys","The MiniscriptKey corresponding to Descriptors. This can …",null,null],[13,"SinglePub","","Single Public Key",58,null],[13,"XPub","","Xpub",58,null],[4,"DescriptorSecretKey","","A Secret Key that can be either a single key or an Xprv",null,null],[13,"SinglePriv","","Single Secret Key",59,null],[13,"XPrv","","Xprv",59,null],[3,"DescriptorSinglePriv","","A Single Descriptor Secret Key with optional origin …",null,null],[12,"origin","","Origin information",60,null],[12,"key","","The key",60,null],[3,"DescriptorSinglePub","","A Single Descriptor Key with optional origin information",null,null],[12,"origin","","Origin information",61,null],[12,"key","","The key",61,null],[3,"SortedMultiVec","","Contents of a \\\"sortedmulti\\\" descriptor",null,null],[12,"k","","signatures required",62,null],[12,"pks","","public keys inside sorted Multi",62,null],[8,"ScriptContext","","The ScriptContext for Miniscript. Additional type …",null,null],[10,"check_terminal_non_malleable","","Depending on ScriptContext, fragments can be malleable. …",26,[[["terminal",4]],[["scriptcontexterror",4],["result",4]]]],[11,"check_witness","","Check whether the given satisfaction is valid under the …",26,[[],[["scriptcontexterror",4],["result",4]]]],[10,"max_satisfaction_size","","Depending on script context, the size of a satifaction …",26,[[["miniscript",3]],["option",4]]],[11,"check_global_consensus_validity","","Depending on script Context, some of the Terminals might …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_global_policy_validity","","Depending on script Context, some of the script resource …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_consensus_validity","","Consensus rules at the Miniscript satisfaction time. It …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_policy_validity","","Policy rules at the Miniscript satisfaction time. It is …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_global_validity","","Check the consensus + policy(if not disabled) rules that …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_validity","","Check the consensus + policy(if not disabled) rules …",26,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"top_level_type_check","","Check whether the top-level is type B",26,[[["miniscript",3]],[["error",4],["result",4]]]],[11,"other_top_level_checks","","Other top level checks that are context specific",26,[[["miniscript",3]],[["error",4],["result",4]]]],[11,"top_level_checks","","Check top level consensus rules.",26,[[["miniscript",3]],[["error",4],["result",4]]]],[0,"bip39","","BIP-0039",null,null],[6,"MnemonicWithPassphrase","bdk::keys::bip39","Type for a BIP39 mnemonic with an optional passphrase",null,null],[6,"ValidNetworks","bdk::keys","Set of valid networks for a key",null,null],[5,"any_network","","Create a set containing mainnet, testnet and regtest",null,[[],["validnetworks",6]]],[5,"mainnet_network","","Create a set only containing mainnet",null,[[],["validnetworks",6]]],[5,"test_networks","","Create a set containing testnet and regtest",null,[[],["validnetworks",6]]],[5,"merge_networks","","Compute the intersection of two sets",null,[[["validnetworks",6]],["validnetworks",6]]],[4,"DescriptorKey","","Container for public or secret keys",null,null],[11,"from_public","","Create an instance given a public key and a set of valid …",63,[[["descriptorpublickey",4],["validnetworks",6]]]],[11,"from_secret","","Create an instance given a secret key and a set of valid …",63,[[["descriptorsecretkey",4],["validnetworks",6]]]],[11,"override_valid_networks","","Override the computed set of valid networks",63,[[["validnetworks",6]]]],[4,"ScriptContextEnum","","Enum representation of the known valid [ScriptContext]s",null,null],[13,"Legacy","","Legacy scripts",64,null],[13,"Segwitv0","","Segwitv0 scripts",64,null],[11,"is_legacy","","Returns whether the script context is […",64,[[]]],[11,"is_segwit_v0","","Returns whether the script context is […",64,[[]]],[8,"ExtScriptContext","","Trait that adds extra useful methods to [ScriptContext]s",null,null],[10,"as_enum","","Returns the [ScriptContext] as a [ScriptContextEnum]",65,[[],["scriptcontextenum",4]]],[11,"is_legacy","","Returns whether the script context is Legacy",65,[[]]],[11,"is_segwit_v0","","Returns whether the script context is Segwitv0",65,[[]]],[8,"ToDescriptorKey","","Trait for objects that can be turned into a public or …",null,null],[10,"to_descriptor_key","","Turn the key into a [DescriptorKey] within the requested […",66,[[],[["result",4],["descriptorkey",4],["keyerror",4]]]],[8,"DerivableKey","","Trait for keys that can be derived.",null,null],[10,"add_metadata","","Add a extra metadata, consume self and turn it into a […",67,[[["keysource",6],["derivationpath",3],["option",4]],[["result",4],["descriptorkey",4],["keyerror",4]]]],[3,"GeneratedKey","","Output of a [GeneratableKey] key generation",null,null],[11,"into_key","","Consumes self and returns the key",68,[[]]],[8,"GeneratableKey","","Trait for keys that can be generated",null,null],[16,"Entropy","","Type specifying the amount of entropy required e.g. [u8;32…",69,null],[16,"Options","","Extra options required by the generate_with_entropy",69,null],[16,"Error","","Returned error in case of failure",69,null],[10,"generate_with_entropy","","Generate a key given the extra options and the entropy",69,[[],[["result",4],["generatedkey",3]]]],[11,"generate","","Generate a key given the options with a random entropy",69,[[],[["result",4],["generatedkey",3]]]],[8,"GeneratableDefaultOptions","","Trait that allows generating a key with the default …",null,null],[11,"generate_with_entropy_default","","Generate a key with the default options and a given …",70,[[],[["result",4],["generatedkey",3]]]],[11,"generate_default","","Generate a key with the default options and a random …",70,[[],[["result",4],["generatedkey",3]]]],[3,"PrivateKeyGenerateOptions","","Options for generating a [PrivateKey]",null,null],[12,"compressed","","Whether the generated key should be \\\"compressed\\\" or not",71,null],[4,"KeyError","","Errors thrown while working with keys",null,null],[13,"InvalidScriptContext","","The key cannot exist in the given script context",72,null],[13,"InvalidNetwork","","The key is not valid for the given network",72,null],[13,"InvalidChecksum","","The key has an invalid checksum",72,null],[13,"Message","","Custom error message",72,null],[13,"BIP32","","BIP32 error",72,null],[13,"Miniscript","","Miniscript error",72,null],[0,"wallet","bdk","Wallet",null,null],[0,"address_validator","bdk::wallet","Address validation callbacks",null,null],[4,"AddressValidatorError","bdk::wallet::address_validator","Errors that can be returned to fail the validation of an …",null,null],[13,"UserRejected","","User rejected the address",73,null],[13,"ConnectionError","","Network connection error",73,null],[13,"TimeoutError","","Network request timeout error",73,null],[13,"InvalidScript","","Invalid script",73,null],[13,"Message","","A custom error message",73,null],[8,"AddressValidator","","Trait to build address validators",null,null],[10,"validate","","Validate or inspect an address",74,[[["script",3],["hdkeypaths",6],["keychainkind",4]],[["addressvalidatorerror",4],["result",4]]]],[0,"coin_selection","bdk::wallet","Coin selection",null,null],[6,"DefaultCoinSelectionAlgorithm","bdk::wallet::coin_selection","Default coin selection algorithm used by TxBuilder if not …",null,null],[3,"CoinSelectionResult","","Result of a successful coin selection",null,null],[12,"selected","","List of outputs selected for use as inputs",75,null],[12,"selected_amount","","Sum of the selected inputs\' value",75,null],[12,"fee_amount","","Total fee amount in satoshi",75,null],[8,"CoinSelectionAlgorithm","","Trait for generalized coin selection algorithms",null,null],[10,"coin_select","","Perform the coin selection",76,[[["feerate",3],["vec",3]],[["result",4],["error",4],["coinselectionresult",3]]]],[3,"LargestFirstCoinSelection","","Simple and dumb coin selection",null,null],[3,"BranchAndBoundCoinSelection","","Branch and bound coin selection",null,null],[11,"new","","Create new instance with target size for change output",77,[[]]],[0,"export","bdk::wallet","Wallet export",null,null],[3,"WalletExport","bdk::wallet::export","Structure that contains the export of a wallet",null,null],[12,"blockheight","","Earliest block to rescan when looking for the wallet\'s …",78,null],[12,"label","","Arbitrary label for the wallet",78,null],[11,"export_wallet","","Export a wallet",78,[[["wallet",3]],["result",4]]],[11,"descriptor","","Return the external descriptor",78,[[],["string",3]]],[11,"change_descriptor","","Return the internal descriptor, if present",78,[[],[["string",3],["option",4]]]],[0,"signer","bdk::wallet","Generalized signers",null,null],[4,"SignerId","bdk::wallet::signer","Identifier of a signer in the SignersContainers. Used as …",null,null],[13,"PkHash","","Bitcoin HASH160 (RIPEMD160 after SHA256) hash of an ECDSA …",79,null],[13,"Fingerprint","","The fingerprint of a BIP32 extended key",79,null],[4,"SignerError","","Signing error",null,null],[13,"MissingKey","","The private key is missing for the required public key",80,null],[13,"InvalidKey","","The private key in use has the right fingerprint but …",80,null],[13,"UserCanceled","","The user canceled the operation",80,null],[13,"InputIndexOutOfRange","","Input index is out of range",80,null],[13,"MissingNonWitnessUtxo","","The non_witness_utxo field of the transaction is required …",80,null],[13,"InvalidNonWitnessUtxo","","The non_witness_utxo specified is invalid",80,null],[13,"MissingWitnessUtxo","","The witness_utxo field of the transaction is required to …",80,null],[13,"MissingWitnessScript","","The witness_script field of the transaction is requied to …",80,null],[13,"MissingHDKeypath","","The fingerprint and derivation path are missing from the …",80,null],[8,"Signer","","Trait for signers",null,null],[10,"sign","","Sign a PSBT",81,[[["secp256k1",3],["partiallysignedtransaction",3],["option",4]],[["signererror",4],["result",4]]]],[10,"sign_whole_tx","","Return whether or not the signer signs the whole …",81,[[]]],[11,"descriptor_secret_key","","Return the secret key for the signer",81,[[],[["option",4],["descriptorsecretkey",4]]]],[3,"SignerOrdering","","Defines the order in which signers are called",null,null],[12,"0","","",82,null],[3,"SignersContainer","","Container for multiple signers",null,null],[11,"as_key_map","","Create a map of public keys to secret keys",83,[[["secp256k1",3]],["keymap",6]]],[11,"new","","Default constructor",83,[[]]],[11,"add_external","","Adds an external signer to the container for the …",83,[[["signer",8],["arc",3],["signerordering",3],["signerid",4]],[["arc",3],["option",4]]]],[11,"remove","","Removes a signer from the container and returns it",83,[[["signerordering",3],["signerid",4]],[["arc",3],["option",4]]]],[11,"ids","","Returns the list of identifiers of all the signers in the …",83,[[],[["signerid",4],["vec",3]]]],[11,"signers","","Returns the list of signers in the container, sorted by …",83,[[],[["vec",3],["arc",3]]]],[11,"find","","Finds the signer with lowest ordering for a given id in …",83,[[["signerid",4]],[["option",4],["arc",3]]]],[0,"time","bdk::wallet","Cross-platform time",null,null],[5,"get_timestamp","bdk::wallet::time","Return the current timestamp in seconds",null,[[]]],[0,"tx_builder","bdk::wallet","Transaction builder",null,null],[8,"TxBuilderContext","bdk::wallet::tx_builder","Context in which the [TxBuilder] is valid",null,null],[3,"CreateTx","","Wallet::create_tx context",null,null],[3,"BumpFee","","Wallet::bump_fee context",null,null],[3,"TxBuilder","","A transaction builder",null,null],[11,"new","","Create an empty builder",84,[[]]],[11,"fee_rate","","Set a custom fee rate",84,[[["feerate",3]]]],[11,"fee_absolute","","Set an absolute fee",84,[[]]],[11,"policy_path","","Set the policy path to use while creating the transaction …",84,[[["string",3],["btreemap",3],["vec",3],["keychainkind",4]]]],[11,"utxos","","Replace the internal list of utxos that must be spent …",84,[[["vec",3],["outpoint",3]]]],[11,"add_utxo","","Add a utxo to the internal list of utxos that must be …",84,[[["outpoint",3]]]],[11,"manually_selected_only","","Only spend utxos added by add_utxo and utxos.",84,[[]]],[11,"unspendable","","Replace the internal list of unspendable utxos with a new …",84,[[["vec",3],["outpoint",3]]]],[11,"add_unspendable","","Add a utxo to the internal list of unspendable utxos",84,[[["outpoint",3]]]],[11,"sighash","","Sign with a specific sig hash",84,[[["sighashtype",4]]]],[11,"ordering","","Choose the ordering for inputs and outputs of the …",84,[[["txordering",4]]]],[11,"nlocktime","","Use a specific nLockTime while creating the transaction",84,[[]]],[11,"version","","Build a transaction with a specific version",84,[[]]],[11,"do_not_spend_change","","Do not spend change outputs",84,[[]]],[11,"only_spend_change","","Only spend change outputs",84,[[]]],[11,"change_policy","","Set a specific [ChangeSpendPolicy]. See […",84,[[["changespendpolicy",4]]]],[11,"force_non_witness_utxo","","Fill-in the psbt::Input::non_witness_utxo field even if …",84,[[]]],[11,"include_output_redeem_witness_script","","Fill-in the psbt::Output::redeem_script and …",84,[[]]],[11,"add_global_xpubs","","Fill-in the PSBT_GLOBAL_XPUB field with the extended keys …",84,[[]]],[11,"drain_wallet","","Spend all the available inputs. This respects filters …",84,[[]]],[11,"coin_selection","","Choose the coin selection algorithm",84,[[["coinselectionalgorithm",8]],[["coinselectionalgorithm",8],["txbuilder",3]]]],[11,"with_recipients","","Create a builder starting from a list of recipients",84,[[["vec",3]]]],[11,"set_recipients","","Replace the recipients already added with a new list",84,[[["vec",3]]]],[11,"add_recipient","","Add a recipient to the internal list",84,[[["script",3]]]],[11,"set_single_recipient","","Set a single recipient that will get all the selected …",84,[[["script",3]]]],[11,"enable_rbf","","Enable signaling RBF",84,[[]]],[11,"enable_rbf_with_sequence","","Enable signaling RBF with a specific nSequence value",84,[[]]],[11,"maintain_single_recipient","","Bump the fees of a transaction made with …",84,[[]]],[4,"TxOrdering","","Ordering of the transaction\'s inputs and outputs",null,null],[13,"Shuffle","","Randomized (default)",85,null],[13,"Untouched","","Unchanged",85,null],[13,"BIP69Lexicographic","","BIP69 / Lexicographic",85,null],[11,"sort_tx","","Sort transaction inputs and outputs by [TxOrdering] …",85,[[["transaction",3]]]],[4,"ChangeSpendPolicy","","Policy regarding the use of change outputs when creating …",null,null],[13,"ChangeAllowed","","Use both change and non-change outputs (default)",86,null],[13,"OnlyChange","","Only use change outputs (see [TxBuilder::only_spend_change…",86,null],[13,"ChangeForbidden","","Only use non-change outputs (see […",86,null],[8,"IsDust","bdk::wallet","Trait to check if a value is below the dust limit",null,null],[10,"is_dust","","Check whether or not a value is below dust limit",87,[[]]],[6,"OfflineWallet","","Type alias for a [Wallet] that uses [OfflineBlockchain]",null,null],[3,"Wallet","","A Bitcoin wallet",null,null],[11,"new_offline","","Create a new \\\"offline\\\" wallet",88,[[["option",4],["network",4],["towalletdescriptor",8]],[["result",4],["error",4]]]],[11,"get_new_address","","Return a newly generated address using the external …",88,[[],[["address",3],["result",4],["error",4]]]],[11,"is_mine","","Return whether or not a script is part of this wallet …",88,[[["script",3]],[["result",4],["error",4]]]],[11,"list_unspent","","Return the list of unspent outputs of this wallet",88,[[],[["result",4],["vec",3],["error",4]]]],[11,"list_transactions","","Return the list of transactions made and received by the …",88,[[],[["error",4],["result",4],["vec",3]]]],[11,"get_balance","","Return the balance, meaning the sum of this wallet\'s …",88,[[],[["error",4],["result",4]]]],[11,"add_signer","","Add an external signer",88,[[["keychainkind",4],["signer",8],["arc",3],["signerordering",3],["signerid",4]]]],[11,"add_address_validator","","Add an address validator",88,[[["arc",3],["addressvalidator",8]]]],[11,"create_tx","","Create a new transaction following the options specified …",88,[[["coinselectionalgorithm",8],["txbuilder",3],["createtx",3]],[["result",4],["error",4]]]],[11,"bump_fee","","Bump the fee of a transaction following the options …",88,[[["txid",3],["coinselectionalgorithm",8],["txbuilder",3],["bumpfee",3]],[["result",4],["error",4]]]],[11,"sign","","Sign a transaction with all the wallet\'s signers, in the …",88,[[["option",4],["psbt",3]],[["result",4],["error",4]]]],[11,"policies","","Return the spending policies for the wallet\'s descriptor",88,[[["keychainkind",4]],[["error",4],["result",4],["option",4]]]],[11,"public_descriptor","","Return the \\\"public\\\" version of the wallet\'s descriptor, …",88,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"finalize_psbt","","Try to finalize a PSBT",88,[[["option",4],["psbt",3]],[["result",4],["error",4]]]],[11,"secp_ctx","","Return the secp256k1 context used for all signing …",88,[[],["secp256k1",3]]],[11,"new","","Create a new \\\"online\\\" wallet",88,[[["option",4],["network",4],["towalletdescriptor",8]],[["result",4],["error",4]]]],[11,"sync","","Sync the internal database with the blockchain",88,[[["option",4],["progress",8]],[["error",4],["result",4]]]],[11,"client","","Return a reference to the internal blockchain client",88,[[],["option",4]]],[11,"network","","Get the Bitcoin network the wallet is using.",88,[[],["network",4]]],[11,"broadcast","","Broadcast a transaction to the network",88,[[["transaction",3]],[["error",4],["result",4],["txid",3]]]],[4,"Error","bdk","Errors that can be thrown by the Wallet",null,null],[13,"InvalidU32Bytes","","Wrong number of bytes found when trying to convert to u32",89,null],[13,"Generic","","Generic error",89,null],[13,"ScriptDoesntHaveAddressForm","","This error is thrown when trying to convert Bare and …",89,null],[13,"SingleRecipientMultipleOutputs","","Found multiple outputs when single_recipient option has …",89,null],[13,"SingleRecipientNoInputs","","single_recipient option is selected but neither …",89,null],[13,"NoRecipients","","Cannot build a tx without recipients",89,null],[13,"NoUtxosSelected","","manually_selected_only option is selected but no utxo has …",89,null],[13,"OutputBelowDustLimit","","Output created is under the dust limit, 546 satoshis",89,null],[13,"InsufficientFunds","","Wallet\'s UTXO set is not enough to cover recipient\'s …",89,null],[13,"BnBTotalTriesExceeded","","Branch and bound coin selection possible attempts with …",89,null],[13,"BnBNoExactMatch","","Branch and bound coin selection tries to avoid needing a …",89,null],[13,"UnknownUTXO","","Happens when trying to spend an UTXO that is not in the …",89,null],[13,"TransactionNotFound","","Thrown when a tx is not found in the internal database",89,null],[13,"TransactionConfirmed","","Happens when trying to bump a transaction that is already …",89,null],[13,"IrreplaceableTransaction","","Trying to replace a tx that has a sequence >= 0xFFFFFFFE",89,null],[13,"FeeRateTooLow","","When bumping a tx the fee rate requested is lower than …",89,null],[12,"required","bdk::Error","Required fee rate (satoshi/vbyte)",90,null],[13,"FeeTooLow","bdk","When bumping a tx the absolute fee requested is lower …",89,null],[12,"required","bdk::Error","Required fee absolute value (satoshi)",91,null],[13,"MissingKeyOrigin","bdk","In order to use the TxBuilder::add_global_xpubs option …",89,null],[13,"Key","","Error while working with keys",89,null],[13,"ChecksumMismatch","","Descriptor checksum mismatch",89,null],[13,"SpendingPolicyRequired","","Spending policy is not compatible with this KeychainKind",89,null],[13,"InvalidPolicyPathError","","Error while extracting and manipulating policies",89,null],[13,"Signer","","Signing error",89,null],[13,"OfflineClient","","Thrown when trying to call a method that requires a …",89,null],[13,"InvalidProgressValue","","Progress value must be between 0.0 (included) and 100.0 …",89,null],[13,"ProgressUpdateError","","Progress update error (maybe the channel has been closed)",89,null],[13,"InvalidOutpoint","","Requested outpoint doesn\'t exist in the tx (vout greater …",89,null],[13,"Descriptor","","Error related to the parsing and usage of descriptors",89,null],[13,"AddressValidator","","Error that can be returned to fail the validation of an …",89,null],[13,"Encode","","Encoding error",89,null],[13,"Miniscript","","Miniscript error",89,null],[13,"BIP32","","BIP32 error",89,null],[13,"Secp256k1","","An ECDSA error",89,null],[13,"JSON","","Error serializing or deserializing JSON data",89,null],[13,"Hex","","Hex decoding error",89,null],[13,"PSBT","","Partially signed bitcoin transaction error",89,null],[13,"Electrum","","Electrum client error",89,null],[13,"Esplora","","Esplora client error",89,null],[13,"CompactFilters","","Compact filters client error)",89,null],[13,"Sled","","Sled database error",89,null],[4,"KeychainKind","","Types of keychains",null,null],[13,"External","","External",92,null],[13,"Internal","","Internal, usually used for change outputs",92,null],[3,"FeeRate","","Fee rate",null,null],[3,"UTXO","","A wallet unspent output",null,null],[12,"outpoint","","Reference to a transaction output",93,null],[12,"txout","","Transaction output",93,null],[12,"keychain","","Type of keychain",93,null],[3,"TransactionDetails","","A wallet transaction",null,null],[12,"transaction","","Optional transaction",94,null],[12,"txid","","Transaction id",94,null],[12,"timestamp","","Timestamp",94,null],[12,"received","","Received value (sats)",94,null],[12,"sent","","Sent value (sats)",94,null],[12,"fees","","Fee value (sats)",94,null],[12,"height","","Confirmed in block height, None means unconfirmed",94,null],[14,"descriptor","","Macro to write full descriptors with code",null,null],[14,"fragment","","Macro to write descriptor fragments with code",null,null],[11,"from","","",89,[[]]],[11,"into","","",89,[[]]],[11,"to_string","","",89,[[],["string",3]]],[11,"borrow","","",89,[[]]],[11,"borrow_mut","","",89,[[]]],[11,"try_from","","",89,[[],["result",4]]],[11,"try_into","","",89,[[],["result",4]]],[11,"type_id","","",89,[[],["typeid",3]]],[11,"vzip","","",89,[[]]],[11,"init","","",89,[[]]],[11,"deref","","",89,[[]]],[11,"deref_mut","","",89,[[]]],[11,"drop","","",89,[[]]],[11,"from","bdk::blockchain::any","",0,[[]]],[11,"into","","",0,[[]]],[11,"borrow","","",0,[[]]],[11,"borrow_mut","","",0,[[]]],[11,"try_from","","",0,[[],["result",4]]],[11,"try_into","","",0,[[],["result",4]]],[11,"type_id","","",0,[[],["typeid",3]]],[11,"vzip","","",0,[[]]],[11,"init","","",0,[[]]],[11,"deref","","",0,[[]]],[11,"deref_mut","","",0,[[]]],[11,"drop","","",0,[[]]],[11,"from","","",1,[[]]],[11,"into","","",1,[[]]],[11,"borrow","","",1,[[]]],[11,"borrow_mut","","",1,[[]]],[11,"try_from","","",1,[[],["result",4]]],[11,"try_into","","",1,[[],["result",4]]],[11,"type_id","","",1,[[],["typeid",3]]],[11,"vzip","","",1,[[]]],[11,"init","","",1,[[]]],[11,"deref","","",1,[[]]],[11,"deref_mut","","",1,[[]]],[11,"drop","","",1,[[]]],[11,"from","bdk::blockchain::electrum","",95,[[]]],[11,"into","","",95,[[]]],[11,"borrow","","",95,[[]]],[11,"borrow_mut","","",95,[[]]],[11,"try_from","","",95,[[],["result",4]]],[11,"try_into","","",95,[[],["result",4]]],[11,"type_id","","",95,[[],["typeid",3]]],[11,"vzip","","",95,[[]]],[11,"init","","",95,[[]]],[11,"deref","","",95,[[]]],[11,"deref_mut","","",95,[[]]],[11,"drop","","",95,[[]]],[11,"from","","",2,[[]]],[11,"into","","",2,[[]]],[11,"borrow","","",2,[[]]],[11,"borrow_mut","","",2,[[]]],[11,"try_from","","",2,[[],["result",4]]],[11,"try_into","","",2,[[],["result",4]]],[11,"type_id","","",2,[[],["typeid",3]]],[11,"vzip","","",2,[[]]],[11,"init","","",2,[[]]],[11,"deref","","",2,[[]]],[11,"deref_mut","","",2,[[]]],[11,"drop","","",2,[[]]],[11,"from","bdk::blockchain::esplora","",3,[[]]],[11,"into","","",3,[[]]],[11,"borrow","","",3,[[]]],[11,"borrow_mut","","",3,[[]]],[11,"try_from","","",3,[[],["result",4]]],[11,"try_into","","",3,[[],["result",4]]],[11,"type_id","","",3,[[],["typeid",3]]],[11,"vzip","","",3,[[]]],[11,"init","","",3,[[]]],[11,"deref","","",3,[[]]],[11,"deref_mut","","",3,[[]]],[11,"drop","","",3,[[]]],[11,"from","","",4,[[]]],[11,"into","","",4,[[]]],[11,"borrow","","",4,[[]]],[11,"borrow_mut","","",4,[[]]],[11,"try_from","","",4,[[],["result",4]]],[11,"try_into","","",4,[[],["result",4]]],[11,"type_id","","",4,[[],["typeid",3]]],[11,"vzip","","",4,[[]]],[11,"init","","",4,[[]]],[11,"deref","","",4,[[]]],[11,"deref_mut","","",4,[[]]],[11,"drop","","",4,[[]]],[11,"from","","",5,[[]]],[11,"into","","",5,[[]]],[11,"to_string","","",5,[[],["string",3]]],[11,"borrow","","",5,[[]]],[11,"borrow_mut","","",5,[[]]],[11,"try_from","","",5,[[],["result",4]]],[11,"try_into","","",5,[[],["result",4]]],[11,"type_id","","",5,[[],["typeid",3]]],[11,"vzip","","",5,[[]]],[11,"init","","",5,[[]]],[11,"deref","","",5,[[]]],[11,"deref_mut","","",5,[[]]],[11,"drop","","",5,[[]]],[11,"from","bdk::blockchain::compact_filters","",96,[[]]],[11,"into","","",96,[[]]],[11,"borrow","","",96,[[]]],[11,"borrow_mut","","",96,[[]]],[11,"try_from","","",96,[[],["result",4]]],[11,"try_into","","",96,[[],["result",4]]],[11,"type_id","","",96,[[],["typeid",3]]],[11,"vzip","","",96,[[]]],[11,"init","","",96,[[]]],[11,"deref","","",96,[[]]],[11,"deref_mut","","",96,[[]]],[11,"drop","","",96,[[]]],[11,"from","","",97,[[]]],[11,"into","","",97,[[]]],[11,"borrow","","",97,[[]]],[11,"borrow_mut","","",97,[[]]],[11,"try_from","","",97,[[],["result",4]]],[11,"try_into","","",97,[[],["result",4]]],[11,"type_id","","",97,[[],["typeid",3]]],[11,"vzip","","",97,[[]]],[11,"init","","",97,[[]]],[11,"deref","","",97,[[]]],[11,"deref_mut","","",97,[[]]],[11,"drop","","",97,[[]]],[11,"from","","",6,[[]]],[11,"into","","",6,[[]]],[11,"borrow","","",6,[[]]],[11,"borrow_mut","","",6,[[]]],[11,"try_from","","",6,[[],["result",4]]],[11,"try_into","","",6,[[],["result",4]]],[11,"type_id","","",6,[[],["typeid",3]]],[11,"vzip","","",6,[[]]],[11,"init","","",6,[[]]],[11,"deref","","",6,[[]]],[11,"deref_mut","","",6,[[]]],[11,"drop","","",6,[[]]],[11,"from","","",7,[[]]],[11,"into","","",7,[[]]],[11,"borrow","","",7,[[]]],[11,"borrow_mut","","",7,[[]]],[11,"try_from","","",7,[[],["result",4]]],[11,"try_into","","",7,[[],["result",4]]],[11,"type_id","","",7,[[],["typeid",3]]],[11,"vzip","","",7,[[]]],[11,"init","","",7,[[]]],[11,"deref","","",7,[[]]],[11,"deref_mut","","",7,[[]]],[11,"drop","","",7,[[]]],[11,"from","","",8,[[]]],[11,"into","","",8,[[]]],[11,"borrow","","",8,[[]]],[11,"borrow_mut","","",8,[[]]],[11,"try_from","","",8,[[],["result",4]]],[11,"try_into","","",8,[[],["result",4]]],[11,"type_id","","",8,[[],["typeid",3]]],[11,"vzip","","",8,[[]]],[11,"init","","",8,[[]]],[11,"deref","","",8,[[]]],[11,"deref_mut","","",8,[[]]],[11,"drop","","",8,[[]]],[11,"from","","",9,[[]]],[11,"into","","",9,[[]]],[11,"to_string","","",9,[[],["string",3]]],[11,"borrow","","",9,[[]]],[11,"borrow_mut","","",9,[[]]],[11,"try_from","","",9,[[],["result",4]]],[11,"try_into","","",9,[[],["result",4]]],[11,"type_id","","",9,[[],["typeid",3]]],[11,"vzip","","",9,[[]]],[11,"init","","",9,[[]]],[11,"deref","","",9,[[]]],[11,"deref_mut","","",9,[[]]],[11,"drop","","",9,[[]]],[11,"from","bdk::blockchain","",10,[[]]],[11,"into","","",10,[[]]],[11,"to_owned","","",10,[[]]],[11,"clone_into","","",10,[[]]],[11,"borrow","","",10,[[]]],[11,"borrow_mut","","",10,[[]]],[11,"try_from","","",10,[[],["result",4]]],[11,"try_into","","",10,[[],["result",4]]],[11,"type_id","","",10,[[],["typeid",3]]],[11,"vzip","","",10,[[]]],[11,"equivalent","","",10,[[]]],[11,"init","","",10,[[]]],[11,"deref","","",10,[[]]],[11,"deref_mut","","",10,[[]]],[11,"drop","","",10,[[]]],[11,"from","","",98,[[]]],[11,"into","","",98,[[]]],[11,"borrow","","",98,[[]]],[11,"borrow_mut","","",98,[[]]],[11,"try_from","","",98,[[],["result",4]]],[11,"try_into","","",98,[[],["result",4]]],[11,"type_id","","",98,[[],["typeid",3]]],[11,"vzip","","",98,[[]]],[11,"init","","",98,[[]]],[11,"deref","","",98,[[]]],[11,"deref_mut","","",98,[[]]],[11,"drop","","",98,[[]]],[11,"from","","",99,[[]]],[11,"into","","",99,[[]]],[11,"to_owned","","",99,[[]]],[11,"clone_into","","",99,[[]]],[11,"borrow","","",99,[[]]],[11,"borrow_mut","","",99,[[]]],[11,"try_from","","",99,[[],["result",4]]],[11,"try_into","","",99,[[],["result",4]]],[11,"type_id","","",99,[[],["typeid",3]]],[11,"vzip","","",99,[[]]],[11,"init","","",99,[[]]],[11,"deref","","",99,[[]]],[11,"deref_mut","","",99,[[]]],[11,"drop","","",99,[[]]],[11,"from","","",100,[[]]],[11,"into","","",100,[[]]],[11,"to_owned","","",100,[[]]],[11,"clone_into","","",100,[[]]],[11,"borrow","","",100,[[]]],[11,"borrow_mut","","",100,[[]]],[11,"try_from","","",100,[[],["result",4]]],[11,"try_into","","",100,[[],["result",4]]],[11,"type_id","","",100,[[],["typeid",3]]],[11,"vzip","","",100,[[]]],[11,"init","","",100,[[]]],[11,"deref","","",100,[[]]],[11,"deref_mut","","",100,[[]]],[11,"drop","","",100,[[]]],[11,"from","bdk::database::any","",14,[[]]],[11,"into","","",14,[[]]],[11,"borrow","","",14,[[]]],[11,"borrow_mut","","",14,[[]]],[11,"try_from","","",14,[[],["result",4]]],[11,"try_into","","",14,[[],["result",4]]],[11,"type_id","","",14,[[],["typeid",3]]],[11,"vzip","","",14,[[]]],[11,"init","","",14,[[]]],[11,"deref","","",14,[[]]],[11,"deref_mut","","",14,[[]]],[11,"drop","","",14,[[]]],[11,"from","","",15,[[]]],[11,"into","","",15,[[]]],[11,"borrow","","",15,[[]]],[11,"borrow_mut","","",15,[[]]],[11,"try_from","","",15,[[],["result",4]]],[11,"try_into","","",15,[[],["result",4]]],[11,"type_id","","",15,[[],["typeid",3]]],[11,"vzip","","",15,[[]]],[11,"init","","",15,[[]]],[11,"deref","","",15,[[]]],[11,"deref_mut","","",15,[[]]],[11,"drop","","",15,[[]]],[11,"from","","",16,[[]]],[11,"into","","",16,[[]]],[11,"borrow","","",16,[[]]],[11,"borrow_mut","","",16,[[]]],[11,"try_from","","",16,[[],["result",4]]],[11,"try_into","","",16,[[],["result",4]]],[11,"type_id","","",16,[[],["typeid",3]]],[11,"vzip","","",16,[[]]],[11,"init","","",16,[[]]],[11,"deref","","",16,[[]]],[11,"deref_mut","","",16,[[]]],[11,"drop","","",16,[[]]],[11,"from","","",17,[[]]],[11,"into","","",17,[[]]],[11,"borrow","","",17,[[]]],[11,"borrow_mut","","",17,[[]]],[11,"try_from","","",17,[[],["result",4]]],[11,"try_into","","",17,[[],["result",4]]],[11,"type_id","","",17,[[],["typeid",3]]],[11,"vzip","","",17,[[]]],[11,"init","","",17,[[]]],[11,"deref","","",17,[[]]],[11,"deref_mut","","",17,[[]]],[11,"drop","","",17,[[]]],[11,"from","bdk::database::memory","",18,[[]]],[11,"into","","",18,[[]]],[11,"borrow","","",18,[[]]],[11,"borrow_mut","","",18,[[]]],[11,"try_from","","",18,[[],["result",4]]],[11,"try_into","","",18,[[],["result",4]]],[11,"type_id","","",18,[[],["typeid",3]]],[11,"vzip","","",18,[[]]],[11,"init","","",18,[[]]],[11,"deref","","",18,[[]]],[11,"deref_mut","","",18,[[]]],[11,"drop","","",18,[[]]],[11,"from","bdk::descriptor","",23,[[]]],[11,"into","","",23,[[]]],[11,"to_owned","","",23,[[]]],[11,"clone_into","","",23,[[]]],[11,"to_string","","",23,[[],["string",3]]],[11,"borrow","","",23,[[]]],[11,"borrow_mut","","",23,[[]]],[11,"try_from","","",23,[[],["result",4]]],[11,"try_into","","",23,[[],["result",4]]],[11,"type_id","","",23,[[],["typeid",3]]],[11,"vzip","","",23,[[]]],[11,"equivalent","","",23,[[]]],[11,"init","","",23,[[]]],[11,"deref","","",23,[[]]],[11,"deref_mut","","",23,[[]]],[11,"drop","","",23,[[]]],[11,"as_enum","","",101,[[],["scriptcontextenum",4]]],[11,"from","","",101,[[]]],[11,"into","","",101,[[]]],[11,"to_owned","","",101,[[]]],[11,"clone_into","","",101,[[]]],[11,"borrow","","",101,[[]]],[11,"borrow_mut","","",101,[[]]],[11,"try_from","","",101,[[],["result",4]]],[11,"try_into","","",101,[[],["result",4]]],[11,"type_id","","",101,[[],["typeid",3]]],[11,"vzip","","",101,[[]]],[11,"equivalent","","",101,[[]]],[11,"init","","",101,[[]]],[11,"deref","","",101,[[]]],[11,"deref_mut","","",101,[[]]],[11,"drop","","",101,[[]]],[11,"from","","",24,[[]]],[11,"into","","",24,[[]]],[11,"to_owned","","",24,[[]]],[11,"clone_into","","",24,[[]]],[11,"to_string","","",24,[[],["string",3]]],[11,"borrow","","",24,[[]]],[11,"borrow_mut","","",24,[[]]],[11,"try_from","","",24,[[],["result",4]]],[11,"try_into","","",24,[[],["result",4]]],[11,"type_id","","",24,[[],["typeid",3]]],[11,"vzip","","",24,[[]]],[11,"equivalent","","",24,[[]]],[11,"init","","",24,[[]]],[11,"deref","","",24,[[]]],[11,"deref_mut","","",24,[[]]],[11,"drop","","",24,[[]]],[11,"as_enum","","",102,[[],["scriptcontextenum",4]]],[11,"from","","",102,[[]]],[11,"into","","",102,[[]]],[11,"to_owned","","",102,[[]]],[11,"clone_into","","",102,[[]]],[11,"borrow","","",102,[[]]],[11,"borrow_mut","","",102,[[]]],[11,"try_from","","",102,[[],["result",4]]],[11,"try_into","","",102,[[],["result",4]]],[11,"type_id","","",102,[[],["typeid",3]]],[11,"vzip","","",102,[[]]],[11,"equivalent","","",102,[[]]],[11,"init","","",102,[[]]],[11,"deref","","",102,[[]]],[11,"deref_mut","","",102,[[]]],[11,"drop","","",102,[[]]],[11,"from","","",27,[[]]],[11,"into","","",27,[[]]],[11,"to_owned","","",27,[[]]],[11,"clone_into","","",27,[[]]],[11,"to_string","","",27,[[],["string",3]]],[11,"borrow","","",27,[[]]],[11,"borrow_mut","","",27,[[]]],[11,"try_from","","",27,[[],["result",4]]],[11,"try_into","","",27,[[],["result",4]]],[11,"type_id","","",27,[[],["typeid",3]]],[11,"vzip","","",27,[[]]],[11,"equivalent","","",27,[[]]],[11,"init","","",27,[[]]],[11,"deref","","",27,[[]]],[11,"deref_mut","","",27,[[]]],[11,"drop","","",27,[[]]],[11,"from","bdk::descriptor::error","",29,[[]]],[11,"into","","",29,[[]]],[11,"to_string","","",29,[[],["string",3]]],[11,"borrow","","",29,[[]]],[11,"borrow_mut","","",29,[[]]],[11,"try_from","","",29,[[],["result",4]]],[11,"try_into","","",29,[[],["result",4]]],[11,"type_id","","",29,[[],["typeid",3]]],[11,"vzip","","",29,[[]]],[11,"init","","",29,[[]]],[11,"deref","","",29,[[]]],[11,"deref_mut","","",29,[[]]],[11,"drop","","",29,[[]]],[11,"from","bdk::descriptor::policy","",103,[[]]],[11,"into","","",103,[[]]],[11,"to_owned","","",103,[[]]],[11,"clone_into","","",103,[[]]],[11,"borrow","","",103,[[]]],[11,"borrow_mut","","",103,[[]]],[11,"try_from","","",103,[[],["result",4]]],[11,"try_into","","",103,[[],["result",4]]],[11,"type_id","","",103,[[],["typeid",3]]],[11,"vzip","","",103,[[]]],[11,"init","","",103,[[]]],[11,"deref","","",103,[[]]],[11,"deref_mut","","",103,[[]]],[11,"drop","","",103,[[]]],[11,"from","","",30,[[]]],[11,"into","","",30,[[]]],[11,"to_owned","","",30,[[]]],[11,"clone_into","","",30,[[]]],[11,"borrow","","",30,[[]]],[11,"borrow_mut","","",30,[[]]],[11,"try_from","","",30,[[],["result",4]]],[11,"try_into","","",30,[[],["result",4]]],[11,"type_id","","",30,[[],["typeid",3]]],[11,"vzip","","",30,[[]]],[11,"init","","",30,[[]]],[11,"deref","","",30,[[]]],[11,"deref_mut","","",30,[[]]],[11,"drop","","",30,[[]]],[11,"from","","",39,[[]]],[11,"into","","",39,[[]]],[11,"to_owned","","",39,[[]]],[11,"clone_into","","",39,[[]]],[11,"borrow","","",39,[[]]],[11,"borrow_mut","","",39,[[]]],[11,"try_from","","",39,[[],["result",4]]],[11,"try_into","","",39,[[],["result",4]]],[11,"type_id","","",39,[[],["typeid",3]]],[11,"vzip","","",39,[[]]],[11,"init","","",39,[[]]],[11,"deref","","",39,[[]]],[11,"deref_mut","","",39,[[]]],[11,"drop","","",39,[[]]],[11,"from","","",43,[[]]],[11,"into","","",43,[[]]],[11,"to_owned","","",43,[[]]],[11,"clone_into","","",43,[[]]],[11,"borrow","","",43,[[]]],[11,"borrow_mut","","",43,[[]]],[11,"try_from","","",43,[[],["result",4]]],[11,"try_into","","",43,[[],["result",4]]],[11,"type_id","","",43,[[],["typeid",3]]],[11,"vzip","","",43,[[]]],[11,"init","","",43,[[]]],[11,"deref","","",43,[[]]],[11,"deref_mut","","",43,[[]]],[11,"drop","","",43,[[]]],[11,"from","","",44,[[]]],[11,"into","","",44,[[]]],[11,"to_owned","","",44,[[]]],[11,"clone_into","","",44,[[]]],[11,"borrow","","",44,[[]]],[11,"borrow_mut","","",44,[[]]],[11,"try_from","","",44,[[],["result",4]]],[11,"try_into","","",44,[[],["result",4]]],[11,"type_id","","",44,[[],["typeid",3]]],[11,"vzip","","",44,[[]]],[11,"equivalent","","",44,[[]]],[11,"init","","",44,[[]]],[11,"deref","","",44,[[]]],[11,"deref_mut","","",44,[[]]],[11,"drop","","",44,[[]]],[11,"from","","",45,[[]]],[11,"into","","",45,[[]]],[11,"to_string","","",45,[[],["string",3]]],[11,"borrow","","",45,[[]]],[11,"borrow_mut","","",45,[[]]],[11,"try_from","","",45,[[],["result",4]]],[11,"try_into","","",45,[[],["result",4]]],[11,"type_id","","",45,[[],["typeid",3]]],[11,"vzip","","",45,[[]]],[11,"init","","",45,[[]]],[11,"deref","","",45,[[]]],[11,"deref_mut","","",45,[[]]],[11,"drop","","",45,[[]]],[11,"to_wallet_descriptor","bdk::descriptor::template","",47,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"from","","",47,[[]]],[11,"into","","",47,[[]]],[11,"borrow","","",47,[[]]],[11,"borrow_mut","","",47,[[]]],[11,"try_from","","",47,[[],["result",4]]],[11,"try_into","","",47,[[],["result",4]]],[11,"type_id","","",47,[[],["typeid",3]]],[11,"vzip","","",47,[[]]],[11,"init","","",47,[[]]],[11,"deref","","",47,[[]]],[11,"deref_mut","","",47,[[]]],[11,"drop","","",47,[[]]],[11,"to_wallet_descriptor","","",48,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"from","","",48,[[]]],[11,"into","","",48,[[]]],[11,"borrow","","",48,[[]]],[11,"borrow_mut","","",48,[[]]],[11,"try_from","","",48,[[],["result",4]]],[11,"try_into","","",48,[[],["result",4]]],[11,"type_id","","",48,[[],["typeid",3]]],[11,"vzip","","",48,[[]]],[11,"init","","",48,[[]]],[11,"deref","","",48,[[]]],[11,"deref_mut","","",48,[[]]],[11,"drop","","",48,[[]]],[11,"to_wallet_descriptor","","",49,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"from","","",49,[[]]],[11,"into","","",49,[[]]],[11,"borrow","","",49,[[]]],[11,"borrow_mut","","",49,[[]]],[11,"try_from","","",49,[[],["result",4]]],[11,"try_into","","",49,[[],["result",4]]],[11,"type_id","","",49,[[],["typeid",3]]],[11,"vzip","","",49,[[]]],[11,"init","","",49,[[]]],[11,"deref","","",49,[[]]],[11,"deref_mut","","",49,[[]]],[11,"drop","","",49,[[]]],[11,"to_wallet_descriptor","","",50,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"from","","",50,[[]]],[11,"into","","",50,[[]]],[11,"borrow","","",50,[[]]],[11,"borrow_mut","","",50,[[]]],[11,"try_from","","",50,[[],["result",4]]],[11,"try_into","","",50,[[],["result",4]]],[11,"type_id","","",50,[[],["typeid",3]]],[11,"vzip","","",50,[[]]],[11,"init","","",50,[[]]],[11,"deref","","",50,[[]]],[11,"deref_mut","","",50,[[]]],[11,"drop","","",50,[[]]],[11,"to_wallet_descriptor","","",51,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"from","","",51,[[]]],[11,"into","","",51,[[]]],[11,"borrow","","",51,[[]]],[11,"borrow_mut","","",51,[[]]],[11,"try_from","","",51,[[],["result",4]]],[11,"try_into","","",51,[[],["result",4]]],[11,"type_id","","",51,[[],["typeid",3]]],[11,"vzip","","",51,[[]]],[11,"init","","",51,[[]]],[11,"deref","","",51,[[]]],[11,"deref_mut","","",51,[[]]],[11,"drop","","",51,[[]]],[11,"to_wallet_descriptor","","",52,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"from","","",52,[[]]],[11,"into","","",52,[[]]],[11,"borrow","","",52,[[]]],[11,"borrow_mut","","",52,[[]]],[11,"try_from","","",52,[[],["result",4]]],[11,"try_into","","",52,[[],["result",4]]],[11,"type_id","","",52,[[],["typeid",3]]],[11,"vzip","","",52,[[]]],[11,"init","","",52,[[]]],[11,"deref","","",52,[[]]],[11,"deref_mut","","",52,[[]]],[11,"drop","","",52,[[]]],[11,"to_wallet_descriptor","","",53,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"from","","",53,[[]]],[11,"into","","",53,[[]]],[11,"borrow","","",53,[[]]],[11,"borrow_mut","","",53,[[]]],[11,"try_from","","",53,[[],["result",4]]],[11,"try_into","","",53,[[],["result",4]]],[11,"type_id","","",53,[[],["typeid",3]]],[11,"vzip","","",53,[[]]],[11,"init","","",53,[[]]],[11,"deref","","",53,[[]]],[11,"deref_mut","","",53,[[]]],[11,"drop","","",53,[[]]],[11,"to_wallet_descriptor","","",54,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"from","","",54,[[]]],[11,"into","","",54,[[]]],[11,"borrow","","",54,[[]]],[11,"borrow_mut","","",54,[[]]],[11,"try_from","","",54,[[],["result",4]]],[11,"try_into","","",54,[[],["result",4]]],[11,"type_id","","",54,[[],["typeid",3]]],[11,"vzip","","",54,[[]]],[11,"init","","",54,[[]]],[11,"deref","","",54,[[]]],[11,"deref_mut","","",54,[[]]],[11,"drop","","",54,[[]]],[11,"to_wallet_descriptor","","",55,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"from","","",55,[[]]],[11,"into","","",55,[[]]],[11,"borrow","","",55,[[]]],[11,"borrow_mut","","",55,[[]]],[11,"try_from","","",55,[[],["result",4]]],[11,"try_into","","",55,[[],["result",4]]],[11,"type_id","","",55,[[],["typeid",3]]],[11,"vzip","","",55,[[]]],[11,"init","","",55,[[]]],[11,"deref","","",55,[[]]],[11,"deref_mut","","",55,[[]]],[11,"drop","","",55,[[]]],[11,"from","bdk::keys","",58,[[]]],[11,"into","","",58,[[]]],[11,"to_owned","","",58,[[]]],[11,"clone_into","","",58,[[]]],[11,"to_string","","",58,[[],["string",3]]],[11,"borrow","","",58,[[]]],[11,"borrow_mut","","",58,[[]]],[11,"try_from","","",58,[[],["result",4]]],[11,"try_into","","",58,[[],["result",4]]],[11,"type_id","","",58,[[],["typeid",3]]],[11,"vzip","","",58,[[]]],[11,"equivalent","","",58,[[]]],[11,"init","","",58,[[]]],[11,"deref","","",58,[[]]],[11,"deref_mut","","",58,[[]]],[11,"drop","","",58,[[]]],[11,"from","","",59,[[]]],[11,"into","","",59,[[]]],[11,"to_string","","",59,[[],["string",3]]],[11,"borrow","","",59,[[]]],[11,"borrow_mut","","",59,[[]]],[11,"try_from","","",59,[[],["result",4]]],[11,"try_into","","",59,[[],["result",4]]],[11,"type_id","","",59,[[],["typeid",3]]],[11,"vzip","","",59,[[]]],[11,"init","","",59,[[]]],[11,"deref","","",59,[[]]],[11,"deref_mut","","",59,[[]]],[11,"drop","","",59,[[]]],[11,"from","","",60,[[]]],[11,"into","","",60,[[]]],[11,"borrow","","",60,[[]]],[11,"borrow_mut","","",60,[[]]],[11,"try_from","","",60,[[],["result",4]]],[11,"try_into","","",60,[[],["result",4]]],[11,"type_id","","",60,[[],["typeid",3]]],[11,"vzip","","",60,[[]]],[11,"init","","",60,[[]]],[11,"deref","","",60,[[]]],[11,"deref_mut","","",60,[[]]],[11,"drop","","",60,[[]]],[11,"from","","",61,[[]]],[11,"into","","",61,[[]]],[11,"to_owned","","",61,[[]]],[11,"clone_into","","",61,[[]]],[11,"borrow","","",61,[[]]],[11,"borrow_mut","","",61,[[]]],[11,"try_from","","",61,[[],["result",4]]],[11,"try_into","","",61,[[],["result",4]]],[11,"type_id","","",61,[[],["typeid",3]]],[11,"vzip","","",61,[[]]],[11,"equivalent","","",61,[[]]],[11,"init","","",61,[[]]],[11,"deref","","",61,[[]]],[11,"deref_mut","","",61,[[]]],[11,"drop","","",61,[[]]],[11,"from","","",62,[[]]],[11,"into","","",62,[[]]],[11,"to_owned","","",62,[[]]],[11,"clone_into","","",62,[[]]],[11,"to_string","","",62,[[],["string",3]]],[11,"borrow","","",62,[[]]],[11,"borrow_mut","","",62,[[]]],[11,"try_from","","",62,[[],["result",4]]],[11,"try_into","","",62,[[],["result",4]]],[11,"type_id","","",62,[[],["typeid",3]]],[11,"vzip","","",62,[[]]],[11,"equivalent","","",62,[[]]],[11,"init","","",62,[[]]],[11,"deref","","",62,[[]]],[11,"deref_mut","","",62,[[]]],[11,"drop","","",62,[[]]],[11,"from","","",63,[[]]],[11,"into","","",63,[[]]],[11,"borrow","","",63,[[]]],[11,"borrow_mut","","",63,[[]]],[11,"try_from","","",63,[[],["result",4]]],[11,"try_into","","",63,[[],["result",4]]],[11,"type_id","","",63,[[],["typeid",3]]],[11,"vzip","","",63,[[]]],[11,"init","","",63,[[]]],[11,"deref","","",63,[[]]],[11,"deref_mut","","",63,[[]]],[11,"drop","","",63,[[]]],[11,"from","","",64,[[]]],[11,"into","","",64,[[]]],[11,"to_owned","","",64,[[]]],[11,"clone_into","","",64,[[]]],[11,"borrow","","",64,[[]]],[11,"borrow_mut","","",64,[[]]],[11,"try_from","","",64,[[],["result",4]]],[11,"try_into","","",64,[[],["result",4]]],[11,"type_id","","",64,[[],["typeid",3]]],[11,"vzip","","",64,[[]]],[11,"equivalent","","",64,[[]]],[11,"init","","",64,[[]]],[11,"deref","","",64,[[]]],[11,"deref_mut","","",64,[[]]],[11,"drop","","",64,[[]]],[11,"from","","",68,[[]]],[11,"into","","",68,[[]]],[11,"borrow","","",68,[[]]],[11,"borrow_mut","","",68,[[]]],[11,"try_from","","",68,[[],["result",4]]],[11,"try_into","","",68,[[],["result",4]]],[11,"type_id","","",68,[[],["typeid",3]]],[11,"vzip","","",68,[[]]],[11,"init","","",68,[[]]],[11,"deref","","",68,[[]]],[11,"deref_mut","","",68,[[]]],[11,"drop","","",68,[[]]],[11,"from","","",71,[[]]],[11,"into","","",71,[[]]],[11,"to_owned","","",71,[[]]],[11,"clone_into","","",71,[[]]],[11,"borrow","","",71,[[]]],[11,"borrow_mut","","",71,[[]]],[11,"try_from","","",71,[[],["result",4]]],[11,"try_into","","",71,[[],["result",4]]],[11,"type_id","","",71,[[],["typeid",3]]],[11,"vzip","","",71,[[]]],[11,"init","","",71,[[]]],[11,"deref","","",71,[[]]],[11,"deref_mut","","",71,[[]]],[11,"drop","","",71,[[]]],[11,"from","","",72,[[]]],[11,"into","","",72,[[]]],[11,"to_string","","",72,[[],["string",3]]],[11,"borrow","","",72,[[]]],[11,"borrow_mut","","",72,[[]]],[11,"try_from","","",72,[[],["result",4]]],[11,"try_into","","",72,[[],["result",4]]],[11,"type_id","","",72,[[],["typeid",3]]],[11,"vzip","","",72,[[]]],[11,"init","","",72,[[]]],[11,"deref","","",72,[[]]],[11,"deref_mut","","",72,[[]]],[11,"drop","","",72,[[]]],[11,"from","bdk","",92,[[]]],[11,"into","","",92,[[]]],[11,"to_owned","","",92,[[]]],[11,"clone_into","","",92,[[]]],[11,"borrow","","",92,[[]]],[11,"borrow_mut","","",92,[[]]],[11,"try_from","","",92,[[],["result",4]]],[11,"try_into","","",92,[[],["result",4]]],[11,"type_id","","",92,[[],["typeid",3]]],[11,"write_base32","","",92,[[],["result",4]]],[11,"base32_len","","",92,[[]]],[11,"check_base32","","",92,[[],[["result",4],["vec",3]]]],[11,"vzip","","",92,[[]]],[11,"equivalent","","",92,[[]]],[11,"init","","",92,[[]]],[11,"deref","","",92,[[]]],[11,"deref_mut","","",92,[[]]],[11,"drop","","",92,[[]]],[11,"from","","",104,[[]]],[11,"into","","",104,[[]]],[11,"to_owned","","",104,[[]]],[11,"clone_into","","",104,[[]]],[11,"borrow","","",104,[[]]],[11,"borrow_mut","","",104,[[]]],[11,"try_from","","",104,[[],["result",4]]],[11,"try_into","","",104,[[],["result",4]]],[11,"type_id","","",104,[[],["typeid",3]]],[11,"vzip","","",104,[[]]],[11,"init","","",104,[[]]],[11,"deref","","",104,[[]]],[11,"deref_mut","","",104,[[]]],[11,"drop","","",104,[[]]],[11,"from","","",93,[[]]],[11,"into","","",93,[[]]],[11,"to_owned","","",93,[[]]],[11,"clone_into","","",93,[[]]],[11,"borrow","","",93,[[]]],[11,"borrow_mut","","",93,[[]]],[11,"try_from","","",93,[[],["result",4]]],[11,"try_into","","",93,[[],["result",4]]],[11,"type_id","","",93,[[],["typeid",3]]],[11,"vzip","","",93,[[]]],[11,"equivalent","","",93,[[]]],[11,"init","","",93,[[]]],[11,"deref","","",93,[[]]],[11,"deref_mut","","",93,[[]]],[11,"drop","","",93,[[]]],[11,"from","","",94,[[]]],[11,"into","","",94,[[]]],[11,"to_owned","","",94,[[]]],[11,"clone_into","","",94,[[]]],[11,"borrow","","",94,[[]]],[11,"borrow_mut","","",94,[[]]],[11,"try_from","","",94,[[],["result",4]]],[11,"try_into","","",94,[[],["result",4]]],[11,"type_id","","",94,[[],["typeid",3]]],[11,"vzip","","",94,[[]]],[11,"equivalent","","",94,[[]]],[11,"init","","",94,[[]]],[11,"deref","","",94,[[]]],[11,"deref_mut","","",94,[[]]],[11,"drop","","",94,[[]]],[11,"from","bdk::wallet::address_validator","",73,[[]]],[11,"into","","",73,[[]]],[11,"to_owned","","",73,[[]]],[11,"clone_into","","",73,[[]]],[11,"to_string","","",73,[[],["string",3]]],[11,"borrow","","",73,[[]]],[11,"borrow_mut","","",73,[[]]],[11,"try_from","","",73,[[],["result",4]]],[11,"try_into","","",73,[[],["result",4]]],[11,"type_id","","",73,[[],["typeid",3]]],[11,"vzip","","",73,[[]]],[11,"equivalent","","",73,[[]]],[11,"init","","",73,[[]]],[11,"deref","","",73,[[]]],[11,"deref_mut","","",73,[[]]],[11,"drop","","",73,[[]]],[11,"from","bdk::wallet::coin_selection","",75,[[]]],[11,"into","","",75,[[]]],[11,"borrow","","",75,[[]]],[11,"borrow_mut","","",75,[[]]],[11,"try_from","","",75,[[],["result",4]]],[11,"try_into","","",75,[[],["result",4]]],[11,"type_id","","",75,[[],["typeid",3]]],[11,"vzip","","",75,[[]]],[11,"init","","",75,[[]]],[11,"deref","","",75,[[]]],[11,"deref_mut","","",75,[[]]],[11,"drop","","",75,[[]]],[11,"from","","",105,[[]]],[11,"into","","",105,[[]]],[11,"borrow","","",105,[[]]],[11,"borrow_mut","","",105,[[]]],[11,"try_from","","",105,[[],["result",4]]],[11,"try_into","","",105,[[],["result",4]]],[11,"type_id","","",105,[[],["typeid",3]]],[11,"vzip","","",105,[[]]],[11,"init","","",105,[[]]],[11,"deref","","",105,[[]]],[11,"deref_mut","","",105,[[]]],[11,"drop","","",105,[[]]],[11,"from","","",77,[[]]],[11,"into","","",77,[[]]],[11,"borrow","","",77,[[]]],[11,"borrow_mut","","",77,[[]]],[11,"try_from","","",77,[[],["result",4]]],[11,"try_into","","",77,[[],["result",4]]],[11,"type_id","","",77,[[],["typeid",3]]],[11,"vzip","","",77,[[]]],[11,"init","","",77,[[]]],[11,"deref","","",77,[[]]],[11,"deref_mut","","",77,[[]]],[11,"drop","","",77,[[]]],[11,"from","bdk::wallet::export","",78,[[]]],[11,"into","","",78,[[]]],[11,"borrow","","",78,[[]]],[11,"borrow_mut","","",78,[[]]],[11,"try_from","","",78,[[],["result",4]]],[11,"try_into","","",78,[[],["result",4]]],[11,"type_id","","",78,[[],["typeid",3]]],[11,"vzip","","",78,[[]]],[11,"init","","",78,[[]]],[11,"deref","","",78,[[]]],[11,"deref_mut","","",78,[[]]],[11,"drop","","",78,[[]]],[11,"from","bdk::wallet::signer","",79,[[]]],[11,"into","","",79,[[]]],[11,"to_owned","","",79,[[]]],[11,"clone_into","","",79,[[]]],[11,"borrow","","",79,[[]]],[11,"borrow_mut","","",79,[[]]],[11,"try_from","","",79,[[],["result",4]]],[11,"try_into","","",79,[[],["result",4]]],[11,"type_id","","",79,[[],["typeid",3]]],[11,"vzip","","",79,[[]]],[11,"equivalent","","",79,[[]]],[11,"init","","",79,[[]]],[11,"deref","","",79,[[]]],[11,"deref_mut","","",79,[[]]],[11,"drop","","",79,[[]]],[11,"from","","",80,[[]]],[11,"into","","",80,[[]]],[11,"to_owned","","",80,[[]]],[11,"clone_into","","",80,[[]]],[11,"to_string","","",80,[[],["string",3]]],[11,"borrow","","",80,[[]]],[11,"borrow_mut","","",80,[[]]],[11,"try_from","","",80,[[],["result",4]]],[11,"try_into","","",80,[[],["result",4]]],[11,"type_id","","",80,[[],["typeid",3]]],[11,"vzip","","",80,[[]]],[11,"equivalent","","",80,[[]]],[11,"init","","",80,[[]]],[11,"deref","","",80,[[]]],[11,"deref_mut","","",80,[[]]],[11,"drop","","",80,[[]]],[11,"from","","",82,[[]]],[11,"into","","",82,[[]]],[11,"to_owned","","",82,[[]]],[11,"clone_into","","",82,[[]]],[11,"borrow","","",82,[[]]],[11,"borrow_mut","","",82,[[]]],[11,"try_from","","",82,[[],["result",4]]],[11,"try_into","","",82,[[],["result",4]]],[11,"type_id","","",82,[[],["typeid",3]]],[11,"vzip","","",82,[[]]],[11,"equivalent","","",82,[[]]],[11,"init","","",82,[[]]],[11,"deref","","",82,[[]]],[11,"deref_mut","","",82,[[]]],[11,"drop","","",82,[[]]],[11,"from","","",83,[[]]],[11,"into","","",83,[[]]],[11,"to_owned","","",83,[[]]],[11,"clone_into","","",83,[[]]],[11,"borrow","","",83,[[]]],[11,"borrow_mut","","",83,[[]]],[11,"try_from","","",83,[[],["result",4]]],[11,"try_into","","",83,[[],["result",4]]],[11,"type_id","","",83,[[],["typeid",3]]],[11,"vzip","","",83,[[]]],[11,"init","","",83,[[]]],[11,"deref","","",83,[[]]],[11,"deref_mut","","",83,[[]]],[11,"drop","","",83,[[]]],[11,"from","bdk::wallet::tx_builder","",106,[[]]],[11,"into","","",106,[[]]],[11,"to_owned","","",106,[[]]],[11,"clone_into","","",106,[[]]],[11,"borrow","","",106,[[]]],[11,"borrow_mut","","",106,[[]]],[11,"try_from","","",106,[[],["result",4]]],[11,"try_into","","",106,[[],["result",4]]],[11,"type_id","","",106,[[],["typeid",3]]],[11,"vzip","","",106,[[]]],[11,"init","","",106,[[]]],[11,"deref","","",106,[[]]],[11,"deref_mut","","",106,[[]]],[11,"drop","","",106,[[]]],[11,"from","","",107,[[]]],[11,"into","","",107,[[]]],[11,"to_owned","","",107,[[]]],[11,"clone_into","","",107,[[]]],[11,"borrow","","",107,[[]]],[11,"borrow_mut","","",107,[[]]],[11,"try_from","","",107,[[],["result",4]]],[11,"try_into","","",107,[[],["result",4]]],[11,"type_id","","",107,[[],["typeid",3]]],[11,"vzip","","",107,[[]]],[11,"init","","",107,[[]]],[11,"deref","","",107,[[]]],[11,"deref_mut","","",107,[[]]],[11,"drop","","",107,[[]]],[11,"from","","",84,[[]]],[11,"into","","",84,[[]]],[11,"borrow","","",84,[[]]],[11,"borrow_mut","","",84,[[]]],[11,"try_from","","",84,[[],["result",4]]],[11,"try_into","","",84,[[],["result",4]]],[11,"type_id","","",84,[[],["typeid",3]]],[11,"vzip","","",84,[[]]],[11,"init","","",84,[[]]],[11,"deref","","",84,[[]]],[11,"deref_mut","","",84,[[]]],[11,"drop","","",84,[[]]],[11,"from","","",85,[[]]],[11,"into","","",85,[[]]],[11,"to_owned","","",85,[[]]],[11,"clone_into","","",85,[[]]],[11,"borrow","","",85,[[]]],[11,"borrow_mut","","",85,[[]]],[11,"try_from","","",85,[[],["result",4]]],[11,"try_into","","",85,[[],["result",4]]],[11,"type_id","","",85,[[],["typeid",3]]],[11,"vzip","","",85,[[]]],[11,"equivalent","","",85,[[]]],[11,"init","","",85,[[]]],[11,"deref","","",85,[[]]],[11,"deref_mut","","",85,[[]]],[11,"drop","","",85,[[]]],[11,"from","","",86,[[]]],[11,"into","","",86,[[]]],[11,"to_owned","","",86,[[]]],[11,"clone_into","","",86,[[]]],[11,"borrow","","",86,[[]]],[11,"borrow_mut","","",86,[[]]],[11,"try_from","","",86,[[],["result",4]]],[11,"try_into","","",86,[[],["result",4]]],[11,"type_id","","",86,[[],["typeid",3]]],[11,"vzip","","",86,[[]]],[11,"equivalent","","",86,[[]]],[11,"init","","",86,[[]]],[11,"deref","","",86,[[]]],[11,"deref_mut","","",86,[[]]],[11,"drop","","",86,[[]]],[11,"from","bdk::wallet","",88,[[]]],[11,"into","","",88,[[]]],[11,"borrow","","",88,[[]]],[11,"borrow_mut","","",88,[[]]],[11,"try_from","","",88,[[],["result",4]]],[11,"try_into","","",88,[[],["result",4]]],[11,"type_id","","",88,[[],["typeid",3]]],[11,"vzip","","",88,[[]]],[11,"init","","",88,[[]]],[11,"deref","","",88,[[]]],[11,"deref_mut","","",88,[[]]],[11,"drop","","",88,[[]]],[11,"from_str","bdk::descriptor","",23,[[],[["result",4],["descriptor",4],["error",4]]]],[11,"from_str","bdk::keys","",59,[[],[["result",4],["descriptorsecretkey",4]]]],[11,"from_str","","",58,[[],[["descriptorpublickey",4],["result",4]]]],[11,"from_str","bdk::descriptor","Parse a Miniscript from string and perform sanity checks …",24,[[],[["miniscript",3],["result",4],["error",4]]]],[11,"hash","bdk::keys","",58,[[]]],[11,"hash","","",61,[[]]],[11,"hash","bdk::descriptor","",27,[[]]],[11,"hash","","",24,[[]]],[11,"eq","","",27,[[["terminal",4]]]],[11,"ne","","",27,[[["terminal",4]]]],[11,"eq","bdk::keys","",58,[[["descriptorpublickey",4]]]],[11,"ne","","",58,[[["descriptorpublickey",4]]]],[11,"eq","bdk::descriptor","",101,[[["legacy",4]]]],[11,"eq","","",24,[[["miniscript",3]]]],[11,"eq","","",23,[[["descriptor",4]]]],[11,"ne","","",23,[[["descriptor",4]]]],[11,"eq","bdk::keys","",61,[[["descriptorsinglepub",3]]]],[11,"ne","","",61,[[["descriptorsinglepub",3]]]],[11,"eq","bdk::descriptor","",102,[[["segwitv0",4]]]],[11,"eq","bdk::keys","",62,[[["sortedmultivec",3]]]],[11,"ne","","",62,[[["sortedmultivec",3]]]],[11,"cmp","bdk::descriptor","",101,[[["legacy",4]],["ordering",4]]],[11,"cmp","bdk::keys","",61,[[["descriptorsinglepub",3]],["ordering",4]]],[11,"cmp","","",62,[[["sortedmultivec",3]],["ordering",4]]],[11,"cmp","bdk::descriptor","",24,[[["miniscript",3]],["ordering",4]]],[11,"cmp","","",102,[[["segwitv0",4]],["ordering",4]]],[11,"cmp","","",23,[[["descriptor",4]],["ordering",4]]],[11,"cmp","bdk::keys","",58,[[["descriptorpublickey",4]],["ordering",4]]],[11,"cmp","bdk::descriptor","",27,[[["terminal",4]],["ordering",4]]],[11,"check_terminal_non_malleable","","",101,[[["terminal",4]],[["scriptcontexterror",4],["result",4]]]],[11,"check_witness","","",101,[[],[["scriptcontexterror",4],["result",4]]]],[11,"check_global_consensus_validity","","",101,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_consensus_validity","","",101,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_policy_validity","","",101,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"max_satisfaction_size","","",101,[[["miniscript",3]],["option",4]]],[11,"check_terminal_non_malleable","","",102,[[["terminal",4]],[["scriptcontexterror",4],["result",4]]]],[11,"check_witness","","",102,[[],[["scriptcontexterror",4],["result",4]]]],[11,"check_global_consensus_validity","","",102,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_consensus_validity","","",102,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_global_policy_validity","","",102,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"check_local_policy_validity","","",102,[[["miniscript",3]],[["scriptcontexterror",4],["result",4]]]],[11,"max_satisfaction_size","","",102,[[["miniscript",3]],["option",4]]],[11,"clone","","",102,[[],["segwitv0",4]]],[11,"clone","","",24,[[],["miniscript",3]]],[11,"clone","bdk::keys","",62,[[],["sortedmultivec",3]]],[11,"clone","bdk::descriptor","",27,[[],["terminal",4]]],[11,"clone","bdk::keys","",61,[[],["descriptorsinglepub",3]]],[11,"clone","bdk::descriptor","",23,[[],["descriptor",4]]],[11,"clone","","",101,[[],["legacy",4]]],[11,"clone","bdk::keys","",58,[[],["descriptorpublickey",4]]],[11,"fmt","bdk::descriptor","",27,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::keys","",60,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::descriptor","",102,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::keys","",58,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","","",62,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::descriptor","",23,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::keys","",59,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::descriptor","",24,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","","",101,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::keys","",61,[[["formatter",3]],[["error",3],["result",4]]]],[11,"to_pubkeyhash","","",58,[[],["descriptorpublickey",4]]],[11,"partial_cmp","","",58,[[["descriptorpublickey",4]],[["option",4],["ordering",4]]]],[11,"lt","","",58,[[["descriptorpublickey",4]]]],[11,"le","","",58,[[["descriptorpublickey",4]]]],[11,"gt","","",58,[[["descriptorpublickey",4]]]],[11,"ge","","",58,[[["descriptorpublickey",4]]]],[11,"partial_cmp","","",62,[[["sortedmultivec",3]],[["option",4],["ordering",4]]]],[11,"lt","","",62,[[["sortedmultivec",3]]]],[11,"le","","",62,[[["sortedmultivec",3]]]],[11,"gt","","",62,[[["sortedmultivec",3]]]],[11,"ge","","",62,[[["sortedmultivec",3]]]],[11,"partial_cmp","bdk::descriptor","",102,[[["segwitv0",4]],[["option",4],["ordering",4]]]],[11,"partial_cmp","","",24,[[["miniscript",3]],[["option",4],["ordering",4]]]],[11,"partial_cmp","bdk::keys","",61,[[["descriptorsinglepub",3]],[["option",4],["ordering",4]]]],[11,"lt","","",61,[[["descriptorsinglepub",3]]]],[11,"le","","",61,[[["descriptorsinglepub",3]]]],[11,"gt","","",61,[[["descriptorsinglepub",3]]]],[11,"ge","","",61,[[["descriptorsinglepub",3]]]],[11,"partial_cmp","bdk::descriptor","",101,[[["legacy",4]],[["option",4],["ordering",4]]]],[11,"partial_cmp","","",23,[[["descriptor",4]],[["option",4],["ordering",4]]]],[11,"lt","","",23,[[["descriptor",4]]]],[11,"le","","",23,[[["descriptor",4]]]],[11,"gt","","",23,[[["descriptor",4]]]],[11,"ge","","",23,[[["descriptor",4]]]],[11,"partial_cmp","","",27,[[["terminal",4]],[["option",4],["ordering",4]]]],[11,"lt","","",27,[[["terminal",4]]]],[11,"le","","",27,[[["terminal",4]]]],[11,"gt","","",27,[[["terminal",4]]]],[11,"ge","","",27,[[["terminal",4]]]],[11,"lift","bdk::keys","",62,[[],[["result",4],["policy",4],["error",4]]]],[11,"lift","bdk::descriptor","",24,[[],[["result",4],["policy",4],["error",4]]]],[11,"lift","","",23,[[],[["result",4],["policy",4],["error",4]]]],[11,"lift","","",27,[[],[["result",4],["policy",4],["error",4]]]],[11,"to_public_key","bdk::keys","",58,[[["descriptorpublickeyctx",3]],["publickey",3]]],[11,"hash_to_hash160","","",58,[[["descriptorpublickeyctx",3]],["hash",3]]],[11,"fmt","bdk::descriptor","",24,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","","",23,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::keys","",62,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::descriptor","",27,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","bdk::keys","",59,[[["formatter",3]],[["error",3],["result",4]]]],[11,"fmt","","",58,[[["formatter",3]],[["error",3],["result",4]]]],[11,"from_tree","bdk::descriptor","",27,[[["tree",3]],[["result",4],["terminal",4],["error",4]]]],[11,"from_tree","","Parse an expression tree into a Miniscript. As a general …",24,[[["tree",3]],[["miniscript",3],["result",4],["error",4]]]],[11,"from_tree","","Parse an expression tree into a descriptor",23,[[["tree",3]],[["result",4],["descriptor",4],["error",4]]]],[11,"from_config","bdk::blockchain::any","",0,[[],[["result",4],["error",4]]]],[11,"from_config","bdk::blockchain::electrum","",95,[[],[["result",4],["error",4]]]],[11,"from_config","bdk::blockchain::esplora","",3,[[],[["result",4],["error",4]]]],[11,"from_config","bdk::blockchain::compact_filters","",6,[[],[["result",4],["error",4]]]],[11,"update","bdk::blockchain","",99,[[["string",3],["option",4]],[["error",4],["result",4]]]],[11,"update","","",100,[[["string",3],["option",4]],[["error",4],["result",4]]]],[11,"set_script_pubkey","bdk::database::any","",14,[[["script",3],["keychainkind",4]],[["error",4],["result",4]]]],[11,"set_utxo","","",14,[[["utxo",3]],[["error",4],["result",4]]]],[11,"set_raw_tx","","",14,[[["transaction",3]],[["error",4],["result",4]]]],[11,"set_tx","","",14,[[["transactiondetails",3]],[["error",4],["result",4]]]],[11,"set_last_index","","",14,[[["keychainkind",4]],[["error",4],["result",4]]]],[11,"del_script_pubkey_from_path","","",14,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"del_path_from_script_pubkey","","",14,[[["script",3]],[["error",4],["result",4],["option",4]]]],[11,"del_utxo","","",14,[[["outpoint",3]],[["result",4],["option",4],["error",4]]]],[11,"del_raw_tx","","",14,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[11,"del_tx","","",14,[[["txid",3]],[["option",4],["result",4],["error",4]]]],[11,"del_last_index","","",14,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"set_script_pubkey","","",15,[[["script",3],["keychainkind",4]],[["error",4],["result",4]]]],[11,"set_utxo","","",15,[[["utxo",3]],[["error",4],["result",4]]]],[11,"set_raw_tx","","",15,[[["transaction",3]],[["error",4],["result",4]]]],[11,"set_tx","","",15,[[["transactiondetails",3]],[["error",4],["result",4]]]],[11,"set_last_index","","",15,[[["keychainkind",4]],[["error",4],["result",4]]]],[11,"del_script_pubkey_from_path","","",15,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"del_path_from_script_pubkey","","",15,[[["script",3]],[["error",4],["result",4],["option",4]]]],[11,"del_utxo","","",15,[[["outpoint",3]],[["result",4],["option",4],["error",4]]]],[11,"del_raw_tx","","",15,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[11,"del_tx","","",15,[[["txid",3]],[["option",4],["result",4],["error",4]]]],[11,"del_last_index","","",15,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"set_script_pubkey","bdk::database::memory","",18,[[["script",3],["keychainkind",4]],[["error",4],["result",4]]]],[11,"set_utxo","","",18,[[["utxo",3]],[["error",4],["result",4]]]],[11,"set_raw_tx","","",18,[[["transaction",3]],[["error",4],["result",4]]]],[11,"set_tx","","",18,[[["transactiondetails",3]],[["error",4],["result",4]]]],[11,"set_last_index","","",18,[[["keychainkind",4]],[["error",4],["result",4]]]],[11,"del_script_pubkey_from_path","","",18,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"del_path_from_script_pubkey","","",18,[[["script",3]],[["error",4],["result",4],["option",4]]]],[11,"del_utxo","","",18,[[["outpoint",3]],[["result",4],["option",4],["error",4]]]],[11,"del_raw_tx","","",18,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[11,"del_tx","","",18,[[["txid",3]],[["option",4],["result",4],["error",4]]]],[11,"del_last_index","","",18,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"check_descriptor_checksum","bdk::database::any","",14,[[["asref",8],["keychainkind",4]],[["error",4],["result",4]]]],[11,"iter_script_pubkeys","","",14,[[["option",4],["keychainkind",4]],[["vec",3],["result",4],["error",4]]]],[11,"iter_utxos","","",14,[[],[["result",4],["vec",3],["error",4]]]],[11,"iter_raw_txs","","",14,[[],[["vec",3],["result",4],["error",4]]]],[11,"iter_txs","","",14,[[],[["error",4],["result",4],["vec",3]]]],[11,"get_script_pubkey_from_path","","",14,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"get_path_from_script_pubkey","","",14,[[["script",3]],[["error",4],["result",4],["option",4]]]],[11,"get_utxo","","",14,[[["outpoint",3]],[["result",4],["option",4],["error",4]]]],[11,"get_raw_tx","","",14,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[11,"get_tx","","",14,[[["txid",3]],[["option",4],["result",4],["error",4]]]],[11,"get_last_index","","",14,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"increment_last_index","","",14,[[["keychainkind",4]],[["result",4],["error",4]]]],[11,"check_descriptor_checksum","bdk::database::memory","",18,[[["asref",8],["keychainkind",4]],[["error",4],["result",4]]]],[11,"iter_script_pubkeys","","",18,[[["option",4],["keychainkind",4]],[["vec",3],["result",4],["error",4]]]],[11,"iter_utxos","","",18,[[],[["result",4],["vec",3],["error",4]]]],[11,"iter_raw_txs","","",18,[[],[["vec",3],["result",4],["error",4]]]],[11,"iter_txs","","",18,[[],[["error",4],["result",4],["vec",3]]]],[11,"get_script_pubkey_from_path","","",18,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"get_path_from_script_pubkey","","",18,[[["script",3]],[["error",4],["result",4],["option",4]]]],[11,"get_utxo","","",18,[[["outpoint",3]],[["result",4],["option",4],["error",4]]]],[11,"get_raw_tx","","",18,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[11,"get_tx","","",18,[[["txid",3]],[["option",4],["result",4],["error",4]]]],[11,"get_last_index","","",18,[[["keychainkind",4]],[["result",4],["option",4],["error",4]]]],[11,"increment_last_index","","",18,[[["keychainkind",4]],[["result",4],["error",4]]]],[11,"begin_batch","bdk::database::any","",14,[[]]],[11,"commit_batch","","",14,[[],[["error",4],["result",4]]]],[11,"begin_batch","bdk::database::memory","",18,[[]]],[11,"commit_batch","","",18,[[],[["error",4],["result",4]]]],[11,"from_config","bdk::database::any","",14,[[],[["result",4],["error",4]]]],[11,"from_config","bdk::database::memory","",18,[[],[["result",4],["error",4]]]],[11,"build","bdk::descriptor::template","",47,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[11,"build","","",48,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[11,"build","","",49,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[11,"build","","",50,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[11,"build","","",51,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[11,"build","","",52,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[11,"build","","",53,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[11,"build","","",54,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[11,"build","","",55,[[],[["descriptortemplateout",6],["result",4],["keyerror",4]]]],[11,"to_wallet_descriptor","bdk","",108,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"to_wallet_descriptor","","",109,[[["network",4]],[["result",4],["keyerror",4]]]],[11,"extract_policy","bdk::descriptor","",24,[[["signerscontainer",3],["secp256k1",3]],[["result",4],["error",4],["option",4]]]],[11,"extract_policy","","",23,[[["signerscontainer",3],["secp256k1",3]],[["result",4],["error",4],["option",4]]]],[11,"to_descriptor_key","bdk::keys","",68,[[],[["result",4],["descriptorkey",4],["keyerror",4]]]],[11,"to_descriptor_key","","",63,[[],[["result",4],["descriptorkey",4],["keyerror",4]]]],[11,"to_descriptor_key","","",58,[[],[["result",4],["descriptorkey",4],["keyerror",4]]]],[11,"to_descriptor_key","","",59,[[],[["result",4],["descriptorkey",4],["keyerror",4]]]],[11,"add_metadata","bdk","",110,[[["keysource",6],["derivationpath",3],["option",4]],[["result",4],["descriptorkey",4],["keyerror",4]]]],[11,"add_metadata","bdk::keys","",68,[[["keysource",6],["derivationpath",3],["option",4]],[["result",4],["descriptorkey",4],["keyerror",4]]]],[11,"coin_select","bdk::wallet::coin_selection","",105,[[["feerate",3],["vec",3]],[["result",4],["error",4],["coinselectionresult",3]]]],[11,"coin_select","","",77,[[["feerate",3],["vec",3]],[["result",4],["error",4],["coinselectionresult",3]]]],[11,"get_capabilities","bdk::blockchain::any","",0,[[],[["hashset",3],["capability",4]]]],[11,"setup","","",0,[[["progress",8],["option",4]],[["error",4],["result",4]]]],[11,"sync","","",0,[[["progress",8],["option",4]],[["error",4],["result",4]]]],[11,"get_tx","","",0,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[11,"broadcast","","",0,[[["transaction",3]],[["error",4],["result",4]]]],[11,"get_height","","",0,[[],[["result",4],["error",4]]]],[11,"estimate_fee","","",0,[[],[["feerate",3],["error",4],["result",4]]]],[11,"get_capabilities","bdk::blockchain::electrum","",95,[[],[["hashset",3],["capability",4]]]],[11,"setup","","",95,[[["progress",8],["option",4]],[["error",4],["result",4]]]],[11,"get_tx","","",95,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[11,"broadcast","","",95,[[["transaction",3]],[["error",4],["result",4]]]],[11,"get_height","","",95,[[],[["result",4],["error",4]]]],[11,"estimate_fee","","",95,[[],[["feerate",3],["error",4],["result",4]]]],[11,"get_capabilities","bdk::blockchain::esplora","",3,[[],[["hashset",3],["capability",4]]]],[11,"setup","","",3,[[["progress",8],["option",4]],[["error",4],["result",4]]]],[11,"get_tx","","",3,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[11,"broadcast","","",3,[[["transaction",3]],[["error",4],["result",4]]]],[11,"get_height","","",3,[[],[["result",4],["error",4]]]],[11,"estimate_fee","","",3,[[],[["feerate",3],["error",4],["result",4]]]],[11,"get_capabilities","bdk::blockchain::compact_filters","",6,[[],[["hashset",3],["capability",4]]]],[11,"setup","","",6,[[["progress",8],["option",4]],[["error",4],["result",4]]]],[11,"get_tx","","",6,[[["txid",3]],[["result",4],["option",4],["error",4]]]],[11,"broadcast","","",6,[[["transaction",3]],[["error",4],["result",4]]]],[11,"get_height","","",6,[[],[["result",4],["error",4]]]],[11,"estimate_fee","","",6,[[],[["feerate",3],["error",4],["result",4]]]],[11,"as_ref","bdk","",92,[[]]],[11,"from","","",89,[[["error",4]]]],[11,"from","","",89,[[["addressvalidatorerror",4]]]],[11,"from","","",89,[[["policyerror",4]]]],[11,"from","","",89,[[["signererror",4]]]],[11,"from","","",89,[[["keyerror",4]],["error",4]]],[11,"from","","",89,[[["error",4]]]],[11,"from","","",89,[[["error",4]]]],[11,"from","","",89,[[["error",4]]]],[11,"from","","",89,[[["error",4]]]],[11,"from","","",89,[[["error",3]]]],[11,"from","","",89,[[["error",4]]]],[11,"from","","",89,[[["error",4]]]],[11,"from","","",89,[[["error",4]]]],[11,"from","","",89,[[["esploraerror",4]]]],[11,"from","","",89,[[["error",4]]]],[11,"from","","",89,[[["compactfilterserror",4]]]],[11,"from","bdk::blockchain::any","",0,[[["electrumblockchain",3]]]],[11,"from","","",0,[[["esplorablockchain",3]]]],[11,"from","","",0,[[["compactfiltersblockchain",3]]]],[11,"from","","",1,[[["electrumblockchainconfig",3]]]],[11,"from","","",1,[[["esplorablockchainconfig",3]]]],[11,"from","","",1,[[["compactfiltersblockchainconfig",3]]]],[11,"from","bdk::blockchain::electrum","",95,[[["client",3]]]],[11,"from","bdk::blockchain::esplora","",5,[[["error",3]]]],[11,"from","","",5,[[["parseinterror",3]]]],[11,"from","","",5,[[["error",4]]]],[11,"from","","",5,[[["error",4]]]],[11,"from","bdk::blockchain::compact_filters","",9,[[["error",3]]]],[11,"from","","",9,[[["error",3]]]],[11,"from","","",9,[[["error",4]]]],[11,"from","","",9,[[["systemtimeerror",3]]]],[11,"from","","",9,[[["error",4]]]],[11,"from","bdk::database::any","",14,[[["memorydatabase",3]]]],[11,"from","","",14,[[["tree",3]]]],[11,"from","","",15,[[]]],[11,"from","","",15,[[]]],[11,"from","","",17,[[]]],[11,"from","","",17,[[["sleddbconfiguration",3]]]],[11,"from","bdk::descriptor::error","",29,[[["keyerror",4]],["error",4]]],[11,"from","","",29,[[["error",4]]]],[11,"from","","",29,[[["error",4]]]],[11,"from","","",29,[[["error",4]]]],[11,"from","","",29,[[["error",4]]]],[11,"from","","",29,[[["error",4]]]],[11,"from","","",29,[[["policyerror",4]]]],[11,"from","bdk::descriptor::policy","",39,[[]]],[11,"from","","",43,[[["satisfiableitem",4]]]],[11,"from","bdk::keys","",72,[[["error",4]]]],[11,"from","","",72,[[["error",4]]]],[11,"from","bdk::wallet::signer","",79,[[["hash",3]],["signerid",4]]],[11,"from","","",79,[[["fingerprint",3]],["signerid",4]]],[11,"from","","",83,[[["keymap",6]],["signerscontainer",3]]],[11,"clone","bdk::blockchain","",10,[[],["capability",4]]],[11,"clone","","",99,[[],["noopprogress",3]]],[11,"clone","","",100,[[],["logprogress",3]]],[11,"clone","bdk::descriptor::policy","",103,[[],["pkorf",3]]],[11,"clone","","",30,[[],["satisfiableitem",4]]],[11,"clone","","",39,[[],["satisfaction",4]]],[11,"clone","","",43,[[],["policy",3]]],[11,"clone","","",44,[[],["condition",3]]],[11,"clone","bdk::keys","",64,[[],["scriptcontextenum",4]]],[11,"clone","","",71,[[],["privatekeygenerateoptions",3]]],[11,"clone","bdk","",92,[[],["keychainkind",4]]],[11,"clone","","",104,[[],["feerate",3]]],[11,"clone","","",93,[[],["utxo",3]]],[11,"clone","","",94,[[],["transactiondetails",3]]],[11,"clone","bdk::wallet::address_validator","",73,[[],["addressvalidatorerror",4]]],[11,"clone","bdk::wallet::signer","",79,[[],["signerid",4]]],[11,"clone","","",80,[[],["signererror",4]]],[11,"clone","","",82,[[],["signerordering",3]]],[11,"clone","","",83,[[],["signerscontainer",3]]],[11,"clone","bdk::wallet::tx_builder","",106,[[],["createtx",3]]],[11,"clone","","",107,[[],["bumpfee",3]]],[11,"clone","","",85,[[],["txordering",4]]],[11,"clone","","",86,[[],["changespendpolicy",4]]],[11,"default","bdk::blockchain::compact_filters","",96,[[],["mempool",3]]],[11,"default","bdk::database::memory","",18,[[],["memorydatabase",3]]],[11,"default","bdk::descriptor::policy","",103,[[],["pkorf",3]]],[11,"default","","",44,[[],["condition",3]]],[11,"default","bdk::keys","",71,[[]]],[11,"default","bdk","",104,[[]]],[11,"default","","",94,[[],["transactiondetails",3]]],[11,"default","bdk::wallet::coin_selection","",105,[[],["largestfirstcoinselection",3]]],[11,"default","","",77,[[]]],[11,"default","bdk::wallet::signer","",82,[[]]],[11,"default","","",83,[[],["signerscontainer",3]]],[11,"default","bdk::wallet::tx_builder","",106,[[],["createtx",3]]],[11,"default","","",107,[[],["bumpfee",3]]],[11,"default","","",84,[[]]],[11,"default","","",85,[[]]],[11,"default","","",86,[[]]],[11,"cmp","bdk::descriptor::policy","",44,[[["condition",3]],["ordering",4]]],[11,"cmp","bdk::wallet::signer","",79,[[["signerid",4]],["ordering",4]]],[11,"cmp","","",82,[[["signerordering",3]],["ordering",4]]],[11,"cmp","bdk::wallet::tx_builder","",85,[[["txordering",4]],["ordering",4]]],[11,"cmp","","",86,[[["changespendpolicy",4]],["ordering",4]]],[11,"eq","bdk::blockchain","",10,[[["capability",4]]]],[11,"eq","bdk::descriptor::policy","",44,[[["condition",3]]]],[11,"ne","","",44,[[["condition",3]]]],[11,"eq","bdk::keys","",64,[[["scriptcontextenum",4]]]],[11,"eq","bdk","",92,[[["keychainkind",4]]]],[11,"eq","","",104,[[["feerate",3]]]],[11,"ne","","",104,[[["feerate",3]]]],[11,"eq","","",93,[[["utxo",3]]]],[11,"ne","","",93,[[["utxo",3]]]],[11,"eq","","",94,[[["transactiondetails",3]]]],[11,"ne","","",94,[[["transactiondetails",3]]]],[11,"eq","bdk::wallet::address_validator","",73,[[["addressvalidatorerror",4]]]],[11,"ne","","",73,[[["addressvalidatorerror",4]]]],[11,"eq","bdk::wallet::signer","",79,[[["signerid",4]]]],[11,"ne","","",79,[[["signerid",4]]]],[11,"eq","","",80,[[["signererror",4]]]],[11,"eq","","",82,[[["signerordering",3]]]],[11,"ne","","",82,[[["signerordering",3]]]],[11,"eq","bdk::wallet::tx_builder","",85,[[["txordering",4]]]],[11,"eq","","",86,[[["changespendpolicy",4]]]],[11,"partial_cmp","bdk::descriptor::policy","",44,[[["condition",3]],[["ordering",4],["option",4]]]],[11,"lt","","",44,[[["condition",3]]]],[11,"le","","",44,[[["condition",3]]]],[11,"gt","","",44,[[["condition",3]]]],[11,"ge","","",44,[[["condition",3]]]],[11,"partial_cmp","bdk","",104,[[["feerate",3]],[["ordering",4],["option",4]]]],[11,"lt","","",104,[[["feerate",3]]]],[11,"le","","",104,[[["feerate",3]]]],[11,"gt","","",104,[[["feerate",3]]]],[11,"ge","","",104,[[["feerate",3]]]],[11,"partial_cmp","bdk::wallet::signer","",79,[[["signerid",4]],[["ordering",4],["option",4]]]],[11,"lt","","",79,[[["signerid",4]]]],[11,"le","","",79,[[["signerid",4]]]],[11,"gt","","",79,[[["signerid",4]]]],[11,"ge","","",79,[[["signerid",4]]]],[11,"partial_cmp","","",82,[[["signerordering",3]],[["ordering",4],["option",4]]]],[11,"lt","","",82,[[["signerordering",3]]]],[11,"le","","",82,[[["signerordering",3]]]],[11,"gt","","",82,[[["signerordering",3]]]],[11,"ge","","",82,[[["signerordering",3]]]],[11,"partial_cmp","bdk::wallet::tx_builder","",85,[[["txordering",4]],[["ordering",4],["option",4]]]],[11,"partial_cmp","","",86,[[["changespendpolicy",4]],[["ordering",4],["option",4]]]],[11,"to_string","bdk::wallet::export","",78,[[],["string",3]]],[11,"deref","bdk::keys","",68,[[]]],[11,"fmt","bdk","",89,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::blockchain::any","",1,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::blockchain::electrum","",2,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::blockchain::esplora","",3,[[["formatter",3]],["result",6]]],[11,"fmt","","",4,[[["formatter",3]],["result",6]]],[11,"fmt","","",5,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::blockchain::compact_filters","",96,[[["formatter",3]],["result",6]]],[11,"fmt","","",97,[[["formatter",3]],["result",6]]],[11,"fmt","","",6,[[["formatter",3]],["result",6]]],[11,"fmt","","",7,[[["formatter",3]],["result",6]]],[11,"fmt","","",8,[[["formatter",3]],["result",6]]],[11,"fmt","","",9,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::blockchain","",10,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::database::any","",14,[[["formatter",3]],["result",6]]],[11,"fmt","","",16,[[["formatter",3]],["result",6]]],[11,"fmt","","",17,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::database::memory","",18,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::descriptor::error","",29,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::descriptor::policy","",103,[[["formatter",3]],["result",6]]],[11,"fmt","","",30,[[["formatter",3]],["result",6]]],[11,"fmt","","",39,[[["formatter",3]],["result",6]]],[11,"fmt","","",43,[[["formatter",3]],["result",6]]],[11,"fmt","","",44,[[["formatter",3]],["result",6]]],[11,"fmt","","",45,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::keys","",63,[[["formatter",3]],["result",6]]],[11,"fmt","","",64,[[["formatter",3]],["result",6]]],[11,"fmt","","",71,[[["formatter",3]],["result",6]]],[11,"fmt","","",72,[[["formatter",3]],["result",6]]],[11,"fmt","bdk","",92,[[["formatter",3]],["result",6]]],[11,"fmt","","",104,[[["formatter",3]],["result",6]]],[11,"fmt","","",93,[[["formatter",3]],["result",6]]],[11,"fmt","","",94,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::wallet::address_validator","",73,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::wallet::coin_selection","",75,[[["formatter",3]],["result",6]]],[11,"fmt","","",105,[[["formatter",3]],["result",6]]],[11,"fmt","","",77,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::wallet::export","",78,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::wallet::signer","",79,[[["formatter",3]],["result",6]]],[11,"fmt","","",80,[[["formatter",3]],["result",6]]],[11,"fmt","","",82,[[["formatter",3]],["result",6]]],[11,"fmt","","",83,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::wallet::tx_builder","",106,[[["formatter",3]],["result",6]]],[11,"fmt","","",107,[[["formatter",3]],["result",6]]],[11,"fmt","","",84,[[["formatter",3]],["result",6]]],[11,"fmt","","",85,[[["formatter",3]],["result",6]]],[11,"fmt","","",86,[[["formatter",3]],["result",6]]],[11,"fmt","bdk","",89,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::blockchain::esplora","",5,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::blockchain::compact_filters","",9,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::descriptor::error","",29,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::descriptor::policy","",45,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::keys","",72,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::wallet::address_validator","",73,[[["formatter",3]],["result",6]]],[11,"fmt","bdk::wallet::signer","",80,[[["formatter",3]],["result",6]]],[11,"hash","bdk::blockchain","",10,[[]]],[11,"hash","bdk::descriptor::policy","",44,[[]]],[11,"hash","bdk","",92,[[]]],[11,"hash","bdk::wallet::signer","",79,[[]]],[11,"hash","bdk::wallet::tx_builder","",85,[[]]],[11,"hash","","",86,[[]]],[11,"from_str","bdk::wallet::export","",78,[[],["result",4]]],[11,"serialize","bdk::blockchain::any","",1,[[],["result",4]]],[11,"serialize","bdk::blockchain::electrum","",2,[[],["result",4]]],[11,"serialize","bdk::blockchain::esplora","",4,[[],["result",4]]],[11,"serialize","bdk::blockchain::compact_filters","",7,[[],["result",4]]],[11,"serialize","","",8,[[],["result",4]]],[11,"serialize","bdk::database::any","",16,[[],["result",4]]],[11,"serialize","","",17,[[],["result",4]]],[11,"serialize","bdk::descriptor::policy","",103,[[],["result",4]]],[11,"serialize","","",30,[[],["result",4]]],[11,"serialize","","",39,[[],["result",4]]],[11,"serialize","","",43,[[],["result",4]]],[11,"serialize","","",44,[[],["result",4]]],[11,"serialize","bdk","",92,[[],["result",4]]],[11,"serialize","","",93,[[],["result",4]]],[11,"serialize","","",94,[[],["result",4]]],[11,"serialize","bdk::wallet::export","",78,[[],["result",4]]],[11,"deserialize","bdk::blockchain::any","",1,[[],["result",4]]],[11,"deserialize","bdk::blockchain::electrum","",2,[[],["result",4]]],[11,"deserialize","bdk::blockchain::esplora","",4,[[],["result",4]]],[11,"deserialize","bdk::blockchain::compact_filters","",7,[[],["result",4]]],[11,"deserialize","","",8,[[],["result",4]]],[11,"deserialize","bdk::database::any","",16,[[],["result",4]]],[11,"deserialize","","",17,[[],["result",4]]],[11,"deserialize","bdk","",92,[[],["result",4]]],[11,"deserialize","","",93,[[],["result",4]]],[11,"deserialize","","",94,[[],["result",4]]],[11,"deserialize","bdk::wallet::export","",78,[[],["result",4]]],[11,"add_tx","bdk::blockchain::compact_filters","Add a transaction to the mempool",96,[[["transaction",3]]]],[11,"get_tx","","Look-up a transaction in the mempool given an [Inventory] …",96,[[["inventory",4]],[["option",4],["transaction",3]]]],[11,"has_tx","","Return whether or not the mempool contains a transaction …",96,[[["txid",3]]]],[11,"iter_txs","","Return the list of transactions contained in the mempool",96,[[],[["vec",3],["transaction",3]]]],[11,"connect","","Connect to a peer over a plaintext TCP connection",97,[[["tosocketaddrs",8],["network",4],["arc",3],["mempool",3]],[["compactfilterserror",4],["result",4]]]],[11,"connect_proxy","","Connect to a peer through a SOCKS5 proxy, optionally by …",97,[[["tosocketaddrs",8],["totargetaddr",8],["option",4],["network",4],["arc",3],["mempool",3]],[["compactfilterserror",4],["result",4]]]],[11,"get_version","","Return the [VersionMessage] sent by the peer",97,[[],["versionmessage",3]]],[11,"get_network","","Return the Bitcoin [Network] in use",97,[[],["network",4]]],[11,"get_mempool","","Return the mempool used by this peer",97,[[],[["arc",3],["mempool",3]]]],[11,"is_connected","","Return whether or not the peer is still connected",97,[[]]],[11,"send","","Send a raw Bitcoin message to the peer",97,[[["networkmessage",4]],[["result",4],["compactfilterserror",4]]]],[11,"recv","","Waits for a specific incoming Bitcoin message, optionally …",97,[[["duration",3],["option",4]],[["option",4],["compactfilterserror",4],["result",4]]]],[11,"translate_pk","bdk::descriptor","Convert a descriptor using abstract keys to one using …",23,[[],[["descriptor",4],["result",4]]]],[11,"sanity_check","","Whether the descriptor is safe Checks whether all the …",23,[[],[["error",4],["result",4]]]],[11,"address","","Computes the Bitcoin address of the descriptor, if one …",23,[[["network",4]],[["address",3],["option",4]]]],[11,"script_pubkey","","Computes the scriptpubkey of the descriptor to_pk_ctx …",23,[[],["script",3]]],[11,"unsigned_script_sig","","Computes the scriptSig that will be in place for an …",23,[[],["script",3]]],[11,"witness_script","","Computes the \\\"witness script\\\" of the descriptor, i.e. the …",23,[[],["script",3]]],[11,"get_satisfication","","Returns satisfying witness and scriptSig to spend an …",23,[[],[["error",4],["result",4]]]],[11,"satisfy","","Attempts to produce a satisfying witness and scriptSig to …",23,[[["txin",3]],[["error",4],["result",4]]]],[11,"max_satisfaction_weight","","Computes an upper bound on the weight of a satisfying …",23,[[],["option",4]]],[11,"script_code","","Get the scriptCode of a transaction output.",23,[[],["script",3]]],[11,"derive","","Derives all wildcard keys in the descriptor using the …",23,[[["childnumber",4]],[["descriptorpublickey",4],["descriptor",4]]]],[11,"parse_descriptor","","Parse a descriptor that may contain secret keys",23,[[],[["error",4],["result",4]]]],[11,"to_string_with_secret","","Serialize a descriptor to string with its secret keys",23,[[["hashmap",3]],["string",3]]],[11,"requires_sig","","Whether all spend paths of miniscript require a signature",24,[[]]],[11,"is_non_malleable","","Whether the miniscript is malleable",24,[[]]],[11,"within_resource_limits","","Whether the miniscript can exceed the resource …",24,[[]]],[11,"has_mixed_timelocks","","Whether the miniscript contains a combination of timelocks",24,[[]]],[11,"has_repeated_keys","","Whether the miniscript has repeated Pk or Pkh",24,[[]]],[11,"sanity_check","","Check whether the underlying Miniscript is safe under the …",24,[[],[["result",4],["analysiserror",4]]]],[11,"iter","","Creates a new [Iter] iterator that will iterate over all […",24,[[],["iter",3]]],[11,"iter_pk","","Creates a new [PkIter] iterator that will iterate over …",24,[[],["pkiter",3]]],[11,"iter_pkh","","Creates a new [PkhIter] iterator that will iterate over …",24,[[],["pkhiter",3]]],[11,"iter_pk_pkh","","Creates a new [PkPkhIter] iterator that will iterate over …",24,[[],["pkpkhiter",3]]],[11,"branches","","Enumerates all child nodes of the current AST node (self) …",24,[[],[["miniscript",3],["global",3],["vec",3]]]],[11,"get_nth_child","","Returns child node with given index, if any",24,[[],[["miniscript",3],["option",4]]]],[11,"get_leaf_pk","","Returns Vec with cloned version of all public keys from …",24,[[],[["global",3],["vec",3]]]],[11,"get_leaf_pkh","","Returns Vec with hashes of all public keys from the …",24,[[],[["global",3],["vec",3]]]],[11,"get_leaf_pk_pkh","","Returns Vec of [PkPkh] entries, representing either …",24,[[],[["global",3],["vec",3],["pkpkh",4]]]],[11,"get_nth_pk","","Returns Option::Some with cloned n\'th public key from the …",24,[[],["option",4]]],[11,"get_nth_pkh","","Returns Option::Some with hash of n\'th public key from …",24,[[],["option",4]]],[11,"get_nth_pk_pkh","","Returns Option::Some with hash of n\'th public key or hash …",24,[[],[["option",4],["pkpkh",4]]]],[11,"from_ast","","Add type information(Type and Extdata) to Miniscript …",24,[[["terminal",4]],[["miniscript",3],["result",4],["error",4]]]],[11,"into_inner","","Extracts the AstElem representing the root of the …",24,[[],["terminal",4]]],[11,"as_inner","","Get a reference to the inner AstElem representing the …",24,[[],["terminal",4]]],[11,"parse_insane","","Attempt to parse an insane(scripts don\'t clear sanity …",24,[[["script",3]],[["result",4],["miniscript",3],["error",4]]]],[11,"parse","","Attempt to parse a Script into Miniscript representation. …",24,[[["script",3]],[["result",4],["miniscript",3],["error",4]]]],[11,"encode","","Encode as a Bitcoin script",24,[[],["script",3]]],[11,"script_size","","Size, in bytes of the script-pubkey. If this Miniscript …",24,[[]]],[11,"max_satisfaction_witness_elements","","Maximum number of witness elements used to satisfy the …",24,[[],["option",4]]],[11,"max_satisfaction_size","","Maximum size, in bytes, of a satisfying witness. For …",24,[[],["option",4]]],[11,"translate_pk","","This will panic if translatefpk returns an uncompressed …",24,[[],[["miniscript",3],["result",4]]]],[11,"from_str_insane","","Attempt to parse an insane(scripts don\'t clear sanity …",24,[[],[["miniscript",3],["result",4],["error",4]]]],[11,"satisfy","","Attempt to produce non-malleable satisfying witness for …",24,[[],[["vec",3],["result",4],["error",4]]]],[11,"satisfy_malleable","","Attempt to produce a malleable satisfying witness for the …",24,[[],[["vec",3],["result",4],["error",4]]]],[11,"lift_check","","Lifting corresponds conversion of miniscript into Policy […",24,[[],[["lifterror",4],["result",4]]]],[11,"translate_pk","","Convert an AST element with one public key type to one of …",27,[[],[["terminal",4],["result",4]]]],[11,"encode","","Encode the element as a fragment of Bitcoin Script. The …",27,[[["builder",3]],["builder",3]]],[11,"script_size","","Size, in bytes of the script-pubkey. If this Miniscript …",27,[[]]],[11,"derive","bdk::keys","Derives the specified child key if self is a wildcard …",58,[[["childnumber",4]],["descriptorpublickey",4]]],[11,"as_public","","Return the public version of this key, by applying either …",59,[[["secp256k1",3]],[["result",4],["descriptorpublickey",4],["descriptorkeyparseerror",3]]]],[11,"new","","Create a new instance of SortedMultiVec given a list of …",62,[[["global",3],["vec",3]],[["error",4],["sortedmultivec",3],["result",4]]]],[11,"translate_pk","","This will panic if translatefpk returns an uncompressed …",62,[[],[["result",4],["sortedmultivec",3]]]],[11,"sorted_node","","Create Terminal::Multi containing sorted pubkeys",62,[[],["terminal",4]]],[11,"encode","","Encode as a Bitcoin script",62,[[],["script",3]]],[11,"satisfy","","Attempt to produce a satisfying witness for the witness …",62,[[],[["vec",3],["result",4],["error",4]]]],[11,"script_size","","Size, in bytes of the script-pubkey. If this Miniscript …",62,[[]]],[11,"max_satisfaction_witness_elements","","Maximum number of witness elements used to satisfy the …",62,[[]]],[11,"max_satisfaction_size","","Maximum size, in bytes, of a satisfying witness. For …",62,[[]]],[11,"as_byte","bdk","Return [KeychainKind] as a byte",92,[[]]],[11,"from_btc_per_kvb","","Create a new instance of [FeeRate] given a float fee rate …",104,[[]]],[11,"from_sat_per_vb","","Create a new instance of [FeeRate] given a float fee rate …",104,[[]]],[11,"default_min_relay_fee","","Create a new [FeeRate] with the default min relay fee …",104,[[]]],[11,"as_sat_vb","","Return the value as satoshi/vbyte",104,[[]]]],"p":[[4,"AnyBlockchain"],[4,"AnyBlockchainConfig"],[3,"ElectrumBlockchainConfig"],[3,"EsploraBlockchain"],[3,"EsploraBlockchainConfig"],[4,"EsploraError"],[3,"CompactFiltersBlockchain"],[3,"BitcoinPeerConfig"],[3,"CompactFiltersBlockchainConfig"],[4,"CompactFiltersError"],[4,"Capability"],[8,"Blockchain"],[8,"ConfigurableBlockchain"],[8,"Progress"],[4,"AnyDatabase"],[4,"AnyBatch"],[3,"SledDbConfiguration"],[4,"AnyDatabaseConfig"],[3,"MemoryDatabase"],[8,"BatchOperations"],[8,"Database"],[8,"BatchDatabase"],[8,"ConfigurableDatabase"],[4,"Descriptor"],[3,"Miniscript"],[8,"MiniscriptKey"],[8,"ScriptContext"],[4,"Terminal"],[8,"ToPublicKey"],[4,"Error"],[4,"SatisfiableItem"],[13,"SHA256Preimage"],[13,"HASH256Preimage"],[13,"RIPEMD160Preimage"],[13,"HASH160Preimage"],[13,"AbsoluteTimelock"],[13,"RelativeTimelock"],[13,"Multisig"],[13,"Thresh"],[4,"Satisfaction"],[13,"Partial"],[13,"PartialComplete"],[13,"Complete"],[3,"Policy"],[3,"Condition"],[4,"PolicyError"],[8,"DescriptorTemplate"],[3,"P2PKH"],[3,"P2WPKH_P2SH"],[3,"P2WPKH"],[3,"BIP44"],[3,"BIP44Public"],[3,"BIP49"],[3,"BIP49Public"],[3,"BIP84"],[3,"BIP84Public"],[8,"ToWalletDescriptor"],[8,"ExtractPolicy"],[4,"DescriptorPublicKey"],[4,"DescriptorSecretKey"],[3,"DescriptorSinglePriv"],[3,"DescriptorSinglePub"],[3,"SortedMultiVec"],[4,"DescriptorKey"],[4,"ScriptContextEnum"],[8,"ExtScriptContext"],[8,"ToDescriptorKey"],[8,"DerivableKey"],[3,"GeneratedKey"],[8,"GeneratableKey"],[8,"GeneratableDefaultOptions"],[3,"PrivateKeyGenerateOptions"],[4,"KeyError"],[4,"AddressValidatorError"],[8,"AddressValidator"],[3,"CoinSelectionResult"],[8,"CoinSelectionAlgorithm"],[3,"BranchAndBoundCoinSelection"],[3,"WalletExport"],[4,"SignerId"],[4,"SignerError"],[8,"Signer"],[3,"SignerOrdering"],[3,"SignersContainer"],[3,"TxBuilder"],[4,"TxOrdering"],[4,"ChangeSpendPolicy"],[8,"IsDust"],[3,"Wallet"],[4,"Error"],[13,"FeeRateTooLow"],[13,"FeeTooLow"],[4,"KeychainKind"],[3,"UTXO"],[3,"TransactionDetails"],[3,"ElectrumBlockchain"],[3,"Mempool"],[3,"Peer"],[3,"OfflineBlockchain"],[3,"NoopProgress"],[3,"LogProgress"],[4,"Legacy"],[4,"Segwitv0"],[3,"PKOrF"],[3,"FeeRate"],[3,"LargestFirstCoinSelection"],[3,"CreateTx"],[3,"BumpFee"],[6,"ExtendedDescriptor"],[6,"DescriptorTemplateOut"],[6,"MnemonicWithPassphrase"]]}\ +}'); +addSearchOptions(searchIndex);initSearch(searchIndex); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/settings.css b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/settings.css new file mode 100644 index 0000000000..670986588e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/settings.css @@ -0,0 +1 @@ +.setting-line{padding:5px;position:relative;}.setting-line>div{display:inline-block;vertical-align:top;font-size:17px;padding-top:2px;}.setting-line>.title{font-size:19px;width:100%;max-width:none;border-bottom:1px solid;}.toggle{position:relative;display:inline-block;width:45px;height:27px;margin-right:20px;}.toggle input{opacity:0;position:absolute;}.select-wrapper{float:right;position:relative;height:27px;min-width:25%;}.select-wrapper select{appearance:none;-moz-appearance:none;-webkit-appearance:none;background:none;border:2px solid #ccc;padding-right:28px;width:100%;}.select-wrapper img{pointer-events:none;position:absolute;right:0;bottom:0;background:#ccc;height:100%;width:28px;padding:0px 4px;}.select-wrapper select option{color:initial;}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;-webkit-transition:.3s;transition:.3s;}.slider:before{position:absolute;content:"";height:19px;width:19px;left:4px;bottom:4px;background-color:white;-webkit-transition:.3s;transition:.3s;}input:checked+.slider{background-color:#2196F3;}input:focus+.slider{box-shadow:0 0 0 2px #0a84ff,0 0 0 6px rgba(10,132,255,0.3);}input:checked+.slider:before{-webkit-transform:translateX(19px);-ms-transform:translateX(19px);transform:translateX(19px);}.setting-line>.sub-settings{padding-left:42px;width:100%;display:block;} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/settings.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/settings.html new file mode 100644 index 0000000000..ad50d10b1c --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/settings.html @@ -0,0 +1,6 @@ +Rustdoc settings + +

Rustdoc settings

Theme preferences
Use system theme
Preferred dark theme
Preferred light theme
+
Auto-hide item declarations
Auto-hide structs declaration
Auto-hide enums declaration
Auto-hide unions declaration
Auto-hide traits declaration
Auto-hide macros declaration
+
Auto-hide item attributes.
Auto-hide item methods' documentation
Auto-hide trait implementation documentation
Auto-hide implementors of a trait
Directly go to item in search if there is only one result
Show line numbers on code examples
Disable keyboard shortcuts
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/settings.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/settings.js new file mode 100644 index 0000000000..b4d6fdcd78 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/settings.js @@ -0,0 +1 @@ +(function(){function changeSetting(settingName,value){updateLocalStorage("rustdoc-"+settingName,value);switch(settingName){case"preferred-dark-theme":case"preferred-light-theme":case"use-system-theme":updateSystemTheme();break}}function handleKey(ev){if(ev.ctrlKey||ev.altKey||ev.metaKey){return}switch(getVirtualKey(ev)){case"Enter":case"Return":case"Space":ev.target.checked=!ev.target.checked;ev.preventDefault();break}}function setEvents(){onEachLazy(document.getElementsByClassName("slider"),function(elem){var toggle=elem.previousElementSibling;var settingId=toggle.id;var settingValue=getSettingValue(settingId);if(settingValue!==null){toggle.checked=settingValue==="true"}toggle.onchange=function(){changeSetting(this.id,this.checked)};toggle.onkeyup=handleKey;toggle.onkeyrelease=handleKey});onEachLazy(document.getElementsByClassName("select-wrapper"),function(elem){var select=elem.getElementsByTagName("select")[0];var settingId=select.id;var settingValue=getSettingValue(settingId);if(settingValue!==null){select.value=settingValue}select.onchange=function(){changeSetting(this.id,this.value)}})}window.addEventListener("DOMContentLoaded",setEvents)})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/source-files.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/source-files.js new file mode 100644 index 0000000000..1d8e89293a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/source-files.js @@ -0,0 +1,3 @@ +var N = null;var sourcesIndex = {}; +sourcesIndex["bdk"] = {"name":"","dirs":[{"name":"blockchain","dirs":[{"name":"compact_filters","files":["mod.rs","peer.rs","store.rs","sync.rs"]}],"files":["any.rs","electrum.rs","esplora.rs","mod.rs","utils.rs"]},{"name":"database","files":["any.rs","keyvalue.rs","memory.rs","mod.rs"]},{"name":"descriptor","files":["checksum.rs","dsl.rs","error.rs","mod.rs","policy.rs","template.rs"]},{"name":"keys","files":["bip39.rs","mod.rs"]},{"name":"psbt","files":["mod.rs"]},{"name":"wallet","files":["address_validator.rs","coin_selection.rs","export.rs","mod.rs","signer.rs","time.rs","tx_builder.rs","utils.rs"]}],"files":["error.rs","lib.rs","types.rs"]}; +createSourceSidebar(); diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/source-script.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/source-script.js new file mode 100644 index 0000000000..de663ca5a9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/source-script.js @@ -0,0 +1 @@ +function getCurrentFilePath(){var parts=window.location.pathname.split("/");var rootPathParts=window.rootPath.split("/");for(var i=0;i"){sidebar.style.left="";this.style.left="";child.innerText="<";updateLocalStorage("rustdoc-source-sidebar-show","true")}else{sidebar.style.left="-300px";this.style.left="0";child.innerText=">";updateLocalStorage("rustdoc-source-sidebar-show","false")}}function createSidebarToggle(){var sidebarToggle=document.createElement("div");sidebarToggle.id="sidebar-toggle";sidebarToggle.onclick=toggleSidebar;var inner1=document.createElement("div");inner1.style.position="relative";var inner2=document.createElement("div");inner2.style.paddingTop="3px";if(getCurrentValue("rustdoc-source-sidebar-show")==="true"){inner2.innerText="<"}else{inner2.innerText=">";sidebarToggle.style.left="0"}inner1.appendChild(inner2);sidebarToggle.appendChild(inner1);return sidebarToggle}function createSourceSidebar(){if(window.rootPath.endsWith("/")===false){window.rootPath+="/"}var main=document.getElementById("main");var sidebarToggle=createSidebarToggle();main.insertBefore(sidebarToggle,main.firstChild);var sidebar=document.createElement("div");sidebar.id="source-sidebar";if(getCurrentValue("rustdoc-source-sidebar-show")!=="true"){sidebar.style.left="-300px"}var currentFile=getCurrentFilePath();var hasFoundFile=false;var title=document.createElement("div");title.className="title";title.innerText="Files";sidebar.appendChild(title);Object.keys(sourcesIndex).forEach(function(key){sourcesIndex[key].name=key;hasFoundFile=createDirEntry(sourcesIndex[key],sidebar,"",currentFile,hasFoundFile)});main.insertBefore(sidebar,main.firstChild);var selected_elem=sidebar.getElementsByClassName("selected")[0];if(typeof selected_elem!=="undefined"){selected_elem.focus()}} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/any.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/any.rs.html new file mode 100644 index 0000000000..44fe66832a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/any.rs.html @@ -0,0 +1,470 @@ +any.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Runtime-checked blockchain types
+//!
+//! This module provides the implementation of [`AnyBlockchain`] which allows switching the
+//! inner [`Blockchain`] type at runtime.
+//!
+//! ## Example
+//!
+//! In this example both `wallet_electrum` and `wallet_esplora` have the same type of
+//! `Wallet<AnyBlockchain, MemoryDatabase>`. This means that they could both, for instance, be
+//! assigned to a struct member.
+//!
+//! ```no_run
+//! # use bitcoin::Network;
+//! # use bdk::blockchain::*;
+//! # use bdk::database::MemoryDatabase;
+//! # use bdk::Wallet;
+//! # #[cfg(feature = "electrum")]
+//! # {
+//! let electrum_blockchain = ElectrumBlockchain::from(electrum_client::Client::new("...")?);
+//! let wallet_electrum: Wallet<AnyBlockchain, _> = Wallet::new(
+//!     "...",
+//!     None,
+//!     Network::Testnet,
+//!     MemoryDatabase::default(),
+//!     electrum_blockchain.into(),
+//! )?;
+//! # }
+//!
+//! # #[cfg(feature = "esplora")]
+//! # {
+//! let esplora_blockchain = EsploraBlockchain::new("...", None);
+//! let wallet_esplora: Wallet<AnyBlockchain, _> = Wallet::new(
+//!     "...",
+//!     None,
+//!     Network::Testnet,
+//!     MemoryDatabase::default(),
+//!     esplora_blockchain.into(),
+//! )?;
+//! # }
+//!
+//! # Ok::<(), bdk::Error>(())
+//! ```
+//!
+//! When paired with the use of [`ConfigurableBlockchain`], it allows creating wallets with any
+//! blockchain type supported using a single line of code:
+//!
+//! ```no_run
+//! # use bitcoin::Network;
+//! # use bdk::blockchain::*;
+//! # use bdk::database::MemoryDatabase;
+//! # use bdk::Wallet;
+//! let config = serde_json::from_str("...")?;
+//! let blockchain = AnyBlockchain::from_config(&config)?;
+//! let wallet = Wallet::new(
+//!     "...",
+//!     None,
+//!     Network::Testnet,
+//!     MemoryDatabase::default(),
+//!     blockchain,
+//! )?;
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use super::*;
+
+macro_rules! impl_from {
+    ( $from:ty, $to:ty, $variant:ident, $( $cfg:tt )* ) => {
+        $( $cfg )*
+        impl From<$from> for $to {
+            fn from(inner: $from) -> Self {
+                <$to>::$variant(inner)
+            }
+        }
+    };
+}
+
+macro_rules! impl_inner_method {
+    ( $self:expr, $name:ident $(, $args:expr)* ) => {
+        match $self {
+            #[cfg(feature = "electrum")]
+            AnyBlockchain::Electrum(inner) => inner.$name( $($args, )* ),
+            #[cfg(feature = "esplora")]
+            AnyBlockchain::Esplora(inner) => inner.$name( $($args, )* ),
+            #[cfg(feature = "compact_filters")]
+            AnyBlockchain::CompactFilters(inner) => inner.$name( $($args, )* ),
+        }
+    }
+}
+
+/// Type that can contain any of the [`Blockchain`] types defined by the library
+///
+/// It allows switching backend at runtime
+///
+/// See [this module](crate::blockchain::any)'s documentation for a usage example.
+pub enum AnyBlockchain {
+    #[cfg(feature = "electrum")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "electrum")))]
+    /// Electrum client
+    Electrum(electrum::ElectrumBlockchain),
+    #[cfg(feature = "esplora")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "esplora")))]
+    /// Esplora client
+    Esplora(esplora::EsploraBlockchain),
+    #[cfg(feature = "compact_filters")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "compact_filters")))]
+    /// Compact filters client
+    CompactFilters(compact_filters::CompactFiltersBlockchain),
+}
+
+#[maybe_async]
+impl Blockchain for AnyBlockchain {
+    fn get_capabilities(&self) -> HashSet<Capability> {
+        maybe_await!(impl_inner_method!(self, get_capabilities))
+    }
+
+    fn setup<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        stop_gap: Option<usize>,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(impl_inner_method!(
+            self,
+            setup,
+            stop_gap,
+            database,
+            progress_update
+        ))
+    }
+    fn sync<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        stop_gap: Option<usize>,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(impl_inner_method!(
+            self,
+            sync,
+            stop_gap,
+            database,
+            progress_update
+        ))
+    }
+
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        maybe_await!(impl_inner_method!(self, get_tx, txid))
+    }
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        maybe_await!(impl_inner_method!(self, broadcast, tx))
+    }
+
+    fn get_height(&self) -> Result<u32, Error> {
+        maybe_await!(impl_inner_method!(self, get_height))
+    }
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        maybe_await!(impl_inner_method!(self, estimate_fee, target))
+    }
+}
+
+impl_from!(electrum::ElectrumBlockchain, AnyBlockchain, Electrum, #[cfg(feature = "electrum")]);
+impl_from!(esplora::EsploraBlockchain, AnyBlockchain, Esplora, #[cfg(feature = "esplora")]);
+impl_from!(compact_filters::CompactFiltersBlockchain, AnyBlockchain, CompactFilters, #[cfg(feature = "compact_filters")]);
+
+/// Type that can contain any of the blockchain configurations defined by the library
+///
+/// This allows storing a single configuration that can be loaded into an [`AnyBlockchain`]
+/// instance. Wallets that plan to offer users the ability to switch blockchain backend at runtime
+/// will find this particularly useful.
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
+pub enum AnyBlockchainConfig {
+    #[cfg(feature = "electrum")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "electrum")))]
+    /// Electrum client
+    Electrum(electrum::ElectrumBlockchainConfig),
+    #[cfg(feature = "esplora")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "esplora")))]
+    /// Esplora client
+    Esplora(esplora::EsploraBlockchainConfig),
+    #[cfg(feature = "compact_filters")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "compact_filters")))]
+    /// Compact filters client
+    CompactFilters(compact_filters::CompactFiltersBlockchainConfig),
+}
+
+impl ConfigurableBlockchain for AnyBlockchain {
+    type Config = AnyBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        Ok(match config {
+            #[cfg(feature = "electrum")]
+            AnyBlockchainConfig::Electrum(inner) => {
+                AnyBlockchain::Electrum(electrum::ElectrumBlockchain::from_config(inner)?)
+            }
+            #[cfg(feature = "esplora")]
+            AnyBlockchainConfig::Esplora(inner) => {
+                AnyBlockchain::Esplora(esplora::EsploraBlockchain::from_config(inner)?)
+            }
+            #[cfg(feature = "compact_filters")]
+            AnyBlockchainConfig::CompactFilters(inner) => AnyBlockchain::CompactFilters(
+                compact_filters::CompactFiltersBlockchain::from_config(inner)?,
+            ),
+        })
+    }
+}
+
+impl_from!(electrum::ElectrumBlockchainConfig, AnyBlockchainConfig, Electrum, #[cfg(feature = "electrum")]);
+impl_from!(esplora::EsploraBlockchainConfig, AnyBlockchainConfig, Esplora, #[cfg(feature = "esplora")]);
+impl_from!(compact_filters::CompactFiltersBlockchainConfig, AnyBlockchainConfig, CompactFilters, #[cfg(feature = "compact_filters")]);
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/mod.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/mod.rs.html new file mode 100644 index 0000000000..f9b808e361 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/mod.rs.html @@ -0,0 +1,1166 @@ +mod.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Compact Filters
+//!
+//! This module contains a multithreaded implementation of an [`Blockchain`] backend that
+//! uses BIP157 (aka "Neutrino") to populate the wallet's [database](crate::database::Database)
+//! by downloading compact filters from the P2P network.
+//!
+//! Since there are currently very few peers "in the wild" that advertise the required service
+//! flag, this implementation requires that one or more known peers are provided by the user.
+//! No dns or other kinds of peer discovery are done internally.
+//!
+//! Moreover, this module doesn't currently support detecting and resolving conflicts between
+//! messages received by different peers. Thus, it's recommended to use this module by only
+//! connecting to a single peer at a time, optionally by opening multiple connections if it's
+//! desirable to use multiple threads at once to sync in parallel.
+//!
+//! This is an **EXPERIMENTAL** feature, API and other major changes are expected.
+//!
+//! ## Example
+//!
+//! ```no_run
+//! # use std::sync::Arc;
+//! # use bitcoin::*;
+//! # use bdk::*;
+//! # use bdk::blockchain::compact_filters::*;
+//! let num_threads = 4;
+//!
+//! let mempool = Arc::new(Mempool::default());
+//! let peers = (0..num_threads)
+//!     .map(|_| {
+//!         Peer::connect(
+//!             "btcd-mainnet.lightning.computer:8333",
+//!             Arc::clone(&mempool),
+//!             Network::Bitcoin,
+//!         )
+//!     })
+//!     .collect::<Result<_, _>>()?;
+//! let blockchain = CompactFiltersBlockchain::new(peers, "./wallet-filters", Some(500_000))?;
+//! # Ok::<(), CompactFiltersError>(())
+//! ```
+
+use std::collections::HashSet;
+use std::fmt;
+use std::path::Path;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::{Arc, Mutex};
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+
+use bitcoin::network::message_blockdata::Inventory;
+use bitcoin::{Network, OutPoint, Transaction, Txid};
+
+use rocksdb::{Options, SliceTransform, DB};
+
+mod peer;
+mod store;
+mod sync;
+
+use super::{Blockchain, Capability, ConfigurableBlockchain, Progress};
+use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
+use crate::error::Error;
+use crate::types::{KeychainKind, TransactionDetails, UTXO};
+use crate::FeeRate;
+
+use peer::*;
+use store::*;
+use sync::*;
+
+pub use peer::{Mempool, Peer};
+
+const SYNC_HEADERS_COST: f32 = 1.0;
+const SYNC_FILTERS_COST: f32 = 11.6 * 1_000.0;
+const PROCESS_BLOCKS_COST: f32 = 20_000.0;
+
+/// Structure implementing the required blockchain traits
+///
+/// ## Example
+/// See the [`blockchain::compact_filters`](crate::blockchain::compact_filters) module for a usage example.
+#[derive(Debug)]
+pub struct CompactFiltersBlockchain {
+    peers: Vec<Arc<Peer>>,
+    headers: Arc<ChainStore<Full>>,
+    skip_blocks: Option<usize>,
+}
+
+impl CompactFiltersBlockchain {
+    /// Construct a new instance given a list of peers, a path to store headers and block
+    /// filters downloaded during the sync and optionally a number of blocks to ignore starting
+    /// from the genesis while scanning for the wallet's outputs.
+    ///
+    /// For each [`Peer`] specified a new thread will be spawned to download and verify the filters
+    /// in parallel. It's currently recommended to only connect to a single peer to avoid
+    /// inconsistencies in the data returned, optionally with multiple connections in parallel to
+    /// speed-up the sync process.
+    pub fn new<P: AsRef<Path>>(
+        peers: Vec<Peer>,
+        storage_dir: P,
+        skip_blocks: Option<usize>,
+    ) -> Result<Self, CompactFiltersError> {
+        if peers.is_empty() {
+            return Err(CompactFiltersError::NoPeers);
+        }
+
+        let mut opts = Options::default();
+        opts.create_if_missing(true);
+        opts.set_prefix_extractor(SliceTransform::create_fixed_prefix(16));
+
+        let network = peers[0].get_network();
+
+        let cfs = DB::list_cf(&opts, &storage_dir).unwrap_or(vec!["default".to_string()]);
+        let db = DB::open_cf(&opts, &storage_dir, &cfs)?;
+        let headers = Arc::new(ChainStore::new(db, network)?);
+
+        // try to recover partial snapshots
+        for cf_name in &cfs {
+            if !cf_name.starts_with("_headers:") {
+                continue;
+            }
+
+            info!("Trying to recover: {:?}", cf_name);
+            headers.recover_snapshot(cf_name)?;
+        }
+
+        Ok(CompactFiltersBlockchain {
+            peers: peers.into_iter().map(Arc::new).collect(),
+            headers,
+            skip_blocks,
+        })
+    }
+
+    /// Process a transaction by looking for inputs that spend from a UTXO in the database or
+    /// outputs that send funds to a know script_pubkey.
+    fn process_tx<D: BatchDatabase>(
+        &self,
+        database: &mut D,
+        tx: &Transaction,
+        height: Option<u32>,
+        timestamp: u64,
+        internal_max_deriv: &mut Option<u32>,
+        external_max_deriv: &mut Option<u32>,
+    ) -> Result<(), Error> {
+        let mut updates = database.begin_batch();
+
+        let mut incoming: u64 = 0;
+        let mut outgoing: u64 = 0;
+
+        let mut inputs_sum: u64 = 0;
+        let mut outputs_sum: u64 = 0;
+
+        // look for our own inputs
+        for (i, input) in tx.input.iter().enumerate() {
+            if let Some(previous_output) = database.get_previous_output(&input.previous_output)? {
+                inputs_sum += previous_output.value;
+
+                if database.is_mine(&previous_output.script_pubkey)? {
+                    outgoing += previous_output.value;
+
+                    debug!("{} input #{} is mine, removing from utxo", tx.txid(), i);
+                    updates.del_utxo(&input.previous_output)?;
+                }
+            }
+        }
+
+        for (i, output) in tx.output.iter().enumerate() {
+            // to compute the fees later
+            outputs_sum += output.value;
+
+            // this output is ours, we have a path to derive it
+            if let Some((keychain, child)) =
+                database.get_path_from_script_pubkey(&output.script_pubkey)?
+            {
+                debug!("{} output #{} is mine, adding utxo", tx.txid(), i);
+                updates.set_utxo(&UTXO {
+                    outpoint: OutPoint::new(tx.txid(), i as u32),
+                    txout: output.clone(),
+                    keychain,
+                })?;
+                incoming += output.value;
+
+                if keychain == KeychainKind::Internal
+                    && (internal_max_deriv.is_none() || child > internal_max_deriv.unwrap_or(0))
+                {
+                    *internal_max_deriv = Some(child);
+                } else if keychain == KeychainKind::External
+                    && (external_max_deriv.is_none() || child > external_max_deriv.unwrap_or(0))
+                {
+                    *external_max_deriv = Some(child);
+                }
+            }
+        }
+
+        if incoming > 0 || outgoing > 0 {
+            let tx = TransactionDetails {
+                txid: tx.txid(),
+                transaction: Some(tx.clone()),
+                received: incoming,
+                sent: outgoing,
+                height,
+                timestamp,
+                fees: inputs_sum.checked_sub(outputs_sum).unwrap_or(0),
+            };
+
+            info!("Saving tx {}", tx.txid);
+            updates.set_tx(&tx)?;
+        }
+
+        database.commit_batch(updates)?;
+
+        Ok(())
+    }
+}
+
+impl Blockchain for CompactFiltersBlockchain {
+    fn get_capabilities(&self) -> HashSet<Capability> {
+        vec![Capability::FullHistory].into_iter().collect()
+    }
+
+    fn setup<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        _stop_gap: Option<usize>, // TODO: move to electrum and esplora only
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        let first_peer = &self.peers[0];
+
+        let skip_blocks = self.skip_blocks.unwrap_or(0);
+
+        let cf_sync = Arc::new(CFSync::new(Arc::clone(&self.headers), skip_blocks, 0x00)?);
+
+        let initial_height = self.headers.get_height()?;
+        let total_bundles = (first_peer.get_version().start_height as usize)
+            .checked_sub(skip_blocks)
+            .map(|x| x / 1000)
+            .unwrap_or(0)
+            + 1;
+        let expected_bundles_to_sync = total_bundles
+            .checked_sub(cf_sync.pruned_bundles()?)
+            .unwrap_or(0);
+
+        let headers_cost = (first_peer.get_version().start_height as usize)
+            .checked_sub(initial_height)
+            .unwrap_or(0) as f32
+            * SYNC_HEADERS_COST;
+        let filters_cost = expected_bundles_to_sync as f32 * SYNC_FILTERS_COST;
+
+        let total_cost = headers_cost + filters_cost + PROCESS_BLOCKS_COST;
+
+        if let Some(snapshot) = sync::sync_headers(
+            Arc::clone(&first_peer),
+            Arc::clone(&self.headers),
+            |new_height| {
+                let local_headers_cost =
+                    new_height.checked_sub(initial_height).unwrap_or(0) as f32 * SYNC_HEADERS_COST;
+                progress_update.update(
+                    local_headers_cost / total_cost * 100.0,
+                    Some(format!("Synced headers to {}", new_height)),
+                )
+            },
+        )? {
+            if snapshot.work()? > self.headers.work()? {
+                info!("Applying snapshot with work: {}", snapshot.work()?);
+                self.headers.apply_snapshot(snapshot)?;
+            }
+        }
+
+        let synced_height = self.headers.get_height()?;
+        let buried_height = synced_height
+            .checked_sub(sync::BURIED_CONFIRMATIONS)
+            .unwrap_or(0);
+        info!("Synced headers to height: {}", synced_height);
+
+        cf_sync.prepare_sync(Arc::clone(&first_peer))?;
+
+        let all_scripts = Arc::new(
+            database
+                .iter_script_pubkeys(None)?
+                .into_iter()
+                .map(|s| s.to_bytes())
+                .collect::<Vec<_>>(),
+        );
+
+        let last_synced_block = Arc::new(Mutex::new(synced_height));
+        let synced_bundles = Arc::new(AtomicUsize::new(0));
+        let progress_update = Arc::new(Mutex::new(progress_update));
+
+        let mut threads = Vec::with_capacity(self.peers.len());
+        for peer in &self.peers {
+            let cf_sync = Arc::clone(&cf_sync);
+            let peer = Arc::clone(&peer);
+            let headers = Arc::clone(&self.headers);
+            let all_scripts = Arc::clone(&all_scripts);
+            let last_synced_block = Arc::clone(&last_synced_block);
+            let progress_update = Arc::clone(&progress_update);
+            let synced_bundles = Arc::clone(&synced_bundles);
+
+            let thread = std::thread::spawn(move || {
+                cf_sync.capture_thread_for_sync(
+                    peer,
+                    |block_hash, filter| {
+                        if !filter
+                            .match_any(block_hash, &mut all_scripts.iter().map(AsRef::as_ref))?
+                        {
+                            return Ok(false);
+                        }
+
+                        let block_height = headers.get_height_for(block_hash)?.unwrap_or(0);
+                        let saved_correct_block = match headers.get_full_block(block_height)? {
+                            Some(block) if &block.block_hash() == block_hash => true,
+                            _ => false,
+                        };
+
+                        if saved_correct_block {
+                            Ok(false)
+                        } else {
+                            let mut last_synced_block = last_synced_block.lock().unwrap();
+
+                            // If we download a block older than `last_synced_block`, we update it so that
+                            // we know to delete and re-process all txs starting from that height
+                            if block_height < *last_synced_block {
+                                *last_synced_block = block_height;
+                            }
+
+                            Ok(true)
+                        }
+                    },
+                    |index| {
+                        let synced_bundles = synced_bundles.fetch_add(1, Ordering::SeqCst);
+                        let local_filters_cost = synced_bundles as f32 * SYNC_FILTERS_COST;
+                        progress_update.lock().unwrap().update(
+                            (headers_cost + local_filters_cost) / total_cost * 100.0,
+                            Some(format!(
+                                "Synced filters {} - {}",
+                                index * 1000 + 1,
+                                (index + 1) * 1000
+                            )),
+                        )
+                    },
+                )
+            });
+
+            threads.push(thread);
+        }
+
+        for t in threads {
+            t.join().unwrap()?;
+        }
+
+        progress_update.lock().unwrap().update(
+            (headers_cost + filters_cost) / total_cost * 100.0,
+            Some("Processing downloaded blocks and mempool".into()),
+        )?;
+
+        // delete all txs newer than last_synced_block
+        let last_synced_block = *last_synced_block.lock().unwrap();
+        log::debug!(
+            "Dropping transactions newer than `last_synced_block` = {}",
+            last_synced_block
+        );
+        let mut updates = database.begin_batch();
+        for details in database.iter_txs(false)? {
+            match details.height {
+                Some(height) if (height as usize) < last_synced_block => continue,
+                _ => updates.del_tx(&details.txid, false)?,
+            };
+        }
+        database.commit_batch(updates)?;
+
+        first_peer.ask_for_mempool()?;
+
+        let mut internal_max_deriv = None;
+        let mut external_max_deriv = None;
+
+        for (height, block) in self.headers.iter_full_blocks()? {
+            for tx in &block.txdata {
+                self.process_tx(
+                    database,
+                    tx,
+                    Some(height as u32),
+                    0,
+                    &mut internal_max_deriv,
+                    &mut external_max_deriv,
+                )?;
+            }
+        }
+        for tx in first_peer.get_mempool().iter_txs().iter() {
+            self.process_tx(
+                database,
+                tx,
+                None,
+                0,
+                &mut internal_max_deriv,
+                &mut external_max_deriv,
+            )?;
+        }
+
+        let current_ext = database
+            .get_last_index(KeychainKind::External)?
+            .unwrap_or(0);
+        let first_ext_new = external_max_deriv.map(|x| x + 1).unwrap_or(0);
+        if first_ext_new > current_ext {
+            info!("Setting external index to {}", first_ext_new);
+            database.set_last_index(KeychainKind::External, first_ext_new)?;
+        }
+
+        let current_int = database
+            .get_last_index(KeychainKind::Internal)?
+            .unwrap_or(0);
+        let first_int_new = internal_max_deriv.map(|x| x + 1).unwrap_or(0);
+        if first_int_new > current_int {
+            info!("Setting internal index to {}", first_int_new);
+            database.set_last_index(KeychainKind::Internal, first_int_new)?;
+        }
+
+        info!("Dropping blocks until {}", buried_height);
+        self.headers.delete_blocks_until(buried_height)?;
+
+        progress_update
+            .lock()
+            .unwrap()
+            .update(100.0, Some("Done".into()))?;
+
+        Ok(())
+    }
+
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.peers[0]
+            .get_mempool()
+            .get_tx(&Inventory::Transaction(*txid)))
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        self.peers[0].broadcast_tx(tx.clone())?;
+
+        Ok(())
+    }
+
+    fn get_height(&self) -> Result<u32, Error> {
+        Ok(self.headers.get_height()? as u32)
+    }
+
+    fn estimate_fee(&self, _target: usize) -> Result<FeeRate, Error> {
+        // TODO
+        Ok(FeeRate::default())
+    }
+}
+
+/// Data to connect to a Bitcoin P2P peer
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct BitcoinPeerConfig {
+    /// Peer address such as 127.0.0.1:18333
+    pub address: String,
+    /// Optional socks5 proxy
+    pub socks5: Option<String>,
+    /// Optional socks5 proxy credentials
+    pub socks5_credentials: Option<(String, String)>,
+}
+
+/// Configuration for a [`CompactFiltersBlockchain`]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct CompactFiltersBlockchainConfig {
+    /// List of peers to try to connect to for asking headers and filters
+    pub peers: Vec<BitcoinPeerConfig>,
+    /// Network used
+    pub network: Network,
+    /// Storage dir to save partially downloaded headers and full blocks
+    pub storage_dir: String,
+    /// Optionally skip initial `skip_blocks` blocks (default: 0)
+    pub skip_blocks: Option<usize>,
+}
+
+impl ConfigurableBlockchain for CompactFiltersBlockchain {
+    type Config = CompactFiltersBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        let mempool = Arc::new(Mempool::default());
+        let peers = config
+            .peers
+            .iter()
+            .map(|peer_conf| match &peer_conf.socks5 {
+                None => Peer::connect(&peer_conf.address, Arc::clone(&mempool), config.network),
+                Some(proxy) => Peer::connect_proxy(
+                    peer_conf.address.as_str(),
+                    proxy,
+                    peer_conf
+                        .socks5_credentials
+                        .as_ref()
+                        .map(|(a, b)| (a.as_str(), b.as_str())),
+                    Arc::clone(&mempool),
+                    config.network,
+                ),
+            })
+            .collect::<Result<_, _>>()?;
+
+        Ok(CompactFiltersBlockchain::new(
+            peers,
+            &config.storage_dir,
+            config.skip_blocks,
+        )?)
+    }
+}
+
+/// An error that can occur during sync with a [`CompactFiltersBlockchain`]
+#[derive(Debug)]
+pub enum CompactFiltersError {
+    /// A peer sent an invalid or unexpected response
+    InvalidResponse,
+    /// The headers returned are invalid
+    InvalidHeaders,
+    /// The compact filter headers returned are invalid
+    InvalidFilterHeader,
+    /// The compact filter returned is invalid
+    InvalidFilter,
+    /// The peer is missing a block in the valid chain
+    MissingBlock,
+    /// The data stored in the block filters storage are corrupted
+    DataCorruption,
+
+    /// A peer is not connected
+    NotConnected,
+    /// A peer took too long to reply to one of our messages
+    Timeout,
+
+    /// No peers have been specified
+    NoPeers,
+
+    /// Internal database error
+    DB(rocksdb::Error),
+    /// Internal I/O error
+    IO(std::io::Error),
+    /// Invalid BIP158 filter
+    BIP158(bitcoin::util::bip158::Error),
+    /// Internal system time error
+    Time(std::time::SystemTimeError),
+
+    /// Wrapper for [`crate::error::Error`]
+    Global(Box<crate::error::Error>),
+}
+
+impl fmt::Display for CompactFiltersError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl std::error::Error for CompactFiltersError {}
+
+impl_error!(rocksdb::Error, DB, CompactFiltersError);
+impl_error!(std::io::Error, IO, CompactFiltersError);
+impl_error!(bitcoin::util::bip158::Error, BIP158, CompactFiltersError);
+impl_error!(std::time::SystemTimeError, Time, CompactFiltersError);
+
+impl From<crate::error::Error> for CompactFiltersError {
+    fn from(err: crate::error::Error) -> Self {
+        CompactFiltersError::Global(Box::new(err))
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/peer.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/peer.rs.html new file mode 100644 index 0000000000..16eba3f0d0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/peer.rs.html @@ -0,0 +1,1106 @@ +peer.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+use std::collections::HashMap;
+use std::net::{TcpStream, ToSocketAddrs};
+use std::sync::{Arc, Condvar, Mutex, RwLock};
+use std::thread;
+use std::time::{Duration, SystemTime, UNIX_EPOCH};
+
+use socks::{Socks5Stream, ToTargetAddr};
+
+use rand::{thread_rng, Rng};
+
+use bitcoin::consensus::Encodable;
+use bitcoin::hash_types::BlockHash;
+use bitcoin::hashes::Hash;
+use bitcoin::network::constants::ServiceFlags;
+use bitcoin::network::message::{NetworkMessage, RawNetworkMessage};
+use bitcoin::network::message_blockdata::*;
+use bitcoin::network::message_filter::*;
+use bitcoin::network::message_network::VersionMessage;
+use bitcoin::network::stream_reader::StreamReader;
+use bitcoin::network::Address;
+use bitcoin::{Block, Network, Transaction, Txid};
+
+use super::CompactFiltersError;
+
+type ResponsesMap = HashMap<&'static str, Arc<(Mutex<Vec<NetworkMessage>>, Condvar)>>;
+
+pub(crate) const TIMEOUT_SECS: u64 = 30;
+
+/// Container for unconfirmed, but valid Bitcoin transactions
+///
+/// It is normally shared between [`Peer`]s with the use of [`Arc`], so that transactions are not
+/// duplicated in memory.
+#[derive(Debug, Default)]
+pub struct Mempool {
+    txs: RwLock<HashMap<Txid, Transaction>>,
+}
+
+impl Mempool {
+    /// Add a transaction to the mempool
+    ///
+    /// Note that this doesn't propagate the transaction to other
+    /// peers. To do that, [`broadcast`](crate::blockchain::Blockchain::broadcast) should be used.
+    pub fn add_tx(&self, tx: Transaction) {
+        self.txs.write().unwrap().insert(tx.txid(), tx);
+    }
+
+    /// Look-up a transaction in the mempool given an [`Inventory`] request
+    pub fn get_tx(&self, inventory: &Inventory) -> Option<Transaction> {
+        let txid = match inventory {
+            Inventory::Error | Inventory::Block(_) | Inventory::WitnessBlock(_) => return None,
+            Inventory::Transaction(txid) => *txid,
+            Inventory::WitnessTransaction(wtxid) => Txid::from_inner(wtxid.into_inner()),
+        };
+        self.txs.read().unwrap().get(&txid).cloned()
+    }
+
+    /// Return whether or not the mempool contains a transaction with a given txid
+    pub fn has_tx(&self, txid: &Txid) -> bool {
+        self.txs.read().unwrap().contains_key(txid)
+    }
+
+    /// Return the list of transactions contained in the mempool
+    pub fn iter_txs(&self) -> Vec<Transaction> {
+        self.txs.read().unwrap().values().cloned().collect()
+    }
+}
+
+/// A Bitcoin peer
+#[derive(Debug)]
+pub struct Peer {
+    writer: Arc<Mutex<TcpStream>>,
+    responses: Arc<RwLock<ResponsesMap>>,
+
+    reader_thread: thread::JoinHandle<()>,
+    connected: Arc<RwLock<bool>>,
+
+    mempool: Arc<Mempool>,
+
+    version: VersionMessage,
+    network: Network,
+}
+
+impl Peer {
+    /// Connect to a peer over a plaintext TCP connection
+    ///
+    /// This function internally spawns a new thread that will monitor incoming messages from the
+    /// peer, and optionally reply to some of them transparently, like [pings](bitcoin::network::message::NetworkMessage::Ping)
+    pub fn connect<A: ToSocketAddrs>(
+        address: A,
+        mempool: Arc<Mempool>,
+        network: Network,
+    ) -> Result<Self, CompactFiltersError> {
+        let stream = TcpStream::connect(address)?;
+
+        Peer::from_stream(stream, mempool, network)
+    }
+
+    /// Connect to a peer through a SOCKS5 proxy, optionally by using some credentials, specified
+    /// as a tuple of `(username, password)`
+    ///
+    /// This function internally spawns a new thread that will monitor incoming messages from the
+    /// peer, and optionally reply to some of them transparently, like [pings](NetworkMessage::Ping)
+    pub fn connect_proxy<T: ToTargetAddr, P: ToSocketAddrs>(
+        target: T,
+        proxy: P,
+        credentials: Option<(&str, &str)>,
+        mempool: Arc<Mempool>,
+        network: Network,
+    ) -> Result<Self, CompactFiltersError> {
+        let socks_stream = if let Some((username, password)) = credentials {
+            Socks5Stream::connect_with_password(proxy, target, username, password)?
+        } else {
+            Socks5Stream::connect(proxy, target)?
+        };
+
+        Peer::from_stream(socks_stream.into_inner(), mempool, network)
+    }
+
+    /// Create a [`Peer`] from an already connected TcpStream
+    fn from_stream(
+        stream: TcpStream,
+        mempool: Arc<Mempool>,
+        network: Network,
+    ) -> Result<Self, CompactFiltersError> {
+        let writer = Arc::new(Mutex::new(stream.try_clone()?));
+        let responses: Arc<RwLock<ResponsesMap>> = Arc::new(RwLock::new(HashMap::new()));
+        let connected = Arc::new(RwLock::new(true));
+
+        let mut locked_writer = writer.lock().unwrap();
+
+        let reader_thread_responses = Arc::clone(&responses);
+        let reader_thread_writer = Arc::clone(&writer);
+        let reader_thread_mempool = Arc::clone(&mempool);
+        let reader_thread_connected = Arc::clone(&connected);
+        let reader_thread = thread::spawn(move || {
+            Self::reader_thread(
+                network,
+                stream,
+                reader_thread_responses,
+                reader_thread_writer,
+                reader_thread_mempool,
+                reader_thread_connected,
+            )
+        });
+
+        let timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() as i64;
+        let nonce = thread_rng().gen();
+        let receiver = Address::new(&locked_writer.peer_addr()?, ServiceFlags::NONE);
+        let sender = Address {
+            services: ServiceFlags::NONE,
+            address: [0u16; 8],
+            port: 0,
+        };
+
+        Self::_send(
+            &mut locked_writer,
+            network.magic(),
+            NetworkMessage::Version(VersionMessage::new(
+                ServiceFlags::WITNESS,
+                timestamp,
+                receiver,
+                sender,
+                nonce,
+                "MagicalBitcoinWallet".into(),
+                0,
+            )),
+        )?;
+        let version = if let NetworkMessage::Version(version) =
+            Self::_recv(&responses, "version", None)?.unwrap()
+        {
+            version
+        } else {
+            return Err(CompactFiltersError::InvalidResponse);
+        };
+
+        if let NetworkMessage::Verack = Self::_recv(&responses, "verack", None)?.unwrap() {
+            Self::_send(&mut locked_writer, network.magic(), NetworkMessage::Verack)?;
+        } else {
+            return Err(CompactFiltersError::InvalidResponse);
+        }
+
+        std::mem::drop(locked_writer);
+
+        Ok(Peer {
+            writer,
+            reader_thread,
+            responses,
+            connected,
+            mempool,
+            network,
+            version,
+        })
+    }
+
+    /// Send a Bitcoin network message
+    fn _send(
+        writer: &mut TcpStream,
+        magic: u32,
+        payload: NetworkMessage,
+    ) -> Result<(), CompactFiltersError> {
+        log::trace!("==> {:?}", payload);
+
+        let raw_message = RawNetworkMessage { magic, payload };
+
+        raw_message
+            .consensus_encode(writer)
+            .map_err(|_| CompactFiltersError::DataCorruption)?;
+
+        Ok(())
+    }
+
+    /// Wait for a specific incoming Bitcoin message, optionally with a timeout
+    fn _recv(
+        responses: &Arc<RwLock<ResponsesMap>>,
+        wait_for: &'static str,
+        timeout: Option<Duration>,
+    ) -> Result<Option<NetworkMessage>, CompactFiltersError> {
+        let message_resp = {
+            let mut lock = responses.write().unwrap();
+            let message_resp = lock.entry(wait_for).or_default();
+            Arc::clone(&message_resp)
+        };
+
+        let (lock, cvar) = &*message_resp;
+
+        let mut messages = lock.lock().unwrap();
+        while messages.is_empty() {
+            match timeout {
+                None => messages = cvar.wait(messages).unwrap(),
+                Some(t) => {
+                    let result = cvar.wait_timeout(messages, t).unwrap();
+                    if result.1.timed_out() {
+                        return Ok(None);
+                    }
+
+                    messages = result.0;
+                }
+            }
+        }
+
+        Ok(messages.pop())
+    }
+
+    /// Return the [`VersionMessage`] sent by the peer
+    pub fn get_version(&self) -> &VersionMessage {
+        &self.version
+    }
+
+    /// Return the Bitcoin [`Network`] in use
+    pub fn get_network(&self) -> Network {
+        self.network
+    }
+
+    /// Return the mempool used by this peer
+    pub fn get_mempool(&self) -> Arc<Mempool> {
+        Arc::clone(&self.mempool)
+    }
+
+    /// Return whether or not the peer is still connected
+    pub fn is_connected(&self) -> bool {
+        *self.connected.read().unwrap()
+    }
+
+    /// Internal function called once the `reader_thread` is spawned
+    fn reader_thread(
+        network: Network,
+        connection: TcpStream,
+        reader_thread_responses: Arc<RwLock<ResponsesMap>>,
+        reader_thread_writer: Arc<Mutex<TcpStream>>,
+        reader_thread_mempool: Arc<Mempool>,
+        reader_thread_connected: Arc<RwLock<bool>>,
+    ) {
+        macro_rules! check_disconnect {
+            ($call:expr) => {
+                match $call {
+                    Ok(good) => good,
+                    Err(e) => {
+                        log::debug!("Error {:?}", e);
+                        *reader_thread_connected.write().unwrap() = false;
+
+                        break;
+                    }
+                }
+            };
+        }
+
+        let mut reader = StreamReader::new(connection, None);
+        loop {
+            let raw_message: RawNetworkMessage = check_disconnect!(reader.read_next());
+
+            let in_message = if raw_message.magic != network.magic() {
+                continue;
+            } else {
+                raw_message.payload
+            };
+
+            log::trace!("<== {:?}", in_message);
+
+            match in_message {
+                NetworkMessage::Ping(nonce) => {
+                    check_disconnect!(Self::_send(
+                        &mut reader_thread_writer.lock().unwrap(),
+                        network.magic(),
+                        NetworkMessage::Pong(nonce),
+                    ));
+
+                    continue;
+                }
+                NetworkMessage::Alert(_) => continue,
+                NetworkMessage::GetData(ref inv) => {
+                    let (found, not_found): (Vec<_>, Vec<_>) = inv
+                        .into_iter()
+                        .map(|item| (*item, reader_thread_mempool.get_tx(item)))
+                        .partition(|(_, d)| d.is_some());
+                    for (_, found_tx) in found {
+                        check_disconnect!(Self::_send(
+                            &mut reader_thread_writer.lock().unwrap(),
+                            network.magic(),
+                            NetworkMessage::Tx(found_tx.unwrap()),
+                        ));
+                    }
+
+                    if !not_found.is_empty() {
+                        check_disconnect!(Self::_send(
+                            &mut reader_thread_writer.lock().unwrap(),
+                            network.magic(),
+                            NetworkMessage::NotFound(
+                                not_found.into_iter().map(|(i, _)| i).collect(),
+                            ),
+                        ));
+                    }
+                }
+                _ => {}
+            }
+
+            let message_resp = {
+                let mut lock = reader_thread_responses.write().unwrap();
+                let message_resp = lock.entry(in_message.cmd()).or_default();
+                Arc::clone(&message_resp)
+            };
+
+            let (lock, cvar) = &*message_resp;
+            let mut messages = lock.lock().unwrap();
+            messages.push(in_message);
+            cvar.notify_all();
+        }
+    }
+
+    /// Send a raw Bitcoin message to the peer
+    pub fn send(&self, payload: NetworkMessage) -> Result<(), CompactFiltersError> {
+        let mut writer = self.writer.lock().unwrap();
+        Self::_send(&mut writer, self.network.magic(), payload)
+    }
+
+    /// Waits for a specific incoming Bitcoin message, optionally with a timeout
+    pub fn recv(
+        &self,
+        wait_for: &'static str,
+        timeout: Option<Duration>,
+    ) -> Result<Option<NetworkMessage>, CompactFiltersError> {
+        Self::_recv(&self.responses, wait_for, timeout)
+    }
+}
+
+pub trait CompactFiltersPeer {
+    fn get_cf_checkpt(
+        &self,
+        filter_type: u8,
+        stop_hash: BlockHash,
+    ) -> Result<CFCheckpt, CompactFiltersError>;
+    fn get_cf_headers(
+        &self,
+        filter_type: u8,
+        start_height: u32,
+        stop_hash: BlockHash,
+    ) -> Result<CFHeaders, CompactFiltersError>;
+    fn get_cf_filters(
+        &self,
+        filter_type: u8,
+        start_height: u32,
+        stop_hash: BlockHash,
+    ) -> Result<(), CompactFiltersError>;
+    fn pop_cf_filter_resp(&self) -> Result<CFilter, CompactFiltersError>;
+}
+
+impl CompactFiltersPeer for Peer {
+    fn get_cf_checkpt(
+        &self,
+        filter_type: u8,
+        stop_hash: BlockHash,
+    ) -> Result<CFCheckpt, CompactFiltersError> {
+        self.send(NetworkMessage::GetCFCheckpt(GetCFCheckpt {
+            filter_type,
+            stop_hash,
+        }))?;
+
+        let response = self
+            .recv("cfcheckpt", Some(Duration::from_secs(TIMEOUT_SECS)))?
+            .ok_or(CompactFiltersError::Timeout)?;
+        let response = match response {
+            NetworkMessage::CFCheckpt(response) => response,
+            _ => return Err(CompactFiltersError::InvalidResponse),
+        };
+
+        if response.filter_type != filter_type {
+            return Err(CompactFiltersError::InvalidResponse);
+        }
+
+        Ok(response)
+    }
+
+    fn get_cf_headers(
+        &self,
+        filter_type: u8,
+        start_height: u32,
+        stop_hash: BlockHash,
+    ) -> Result<CFHeaders, CompactFiltersError> {
+        self.send(NetworkMessage::GetCFHeaders(GetCFHeaders {
+            filter_type,
+            start_height,
+            stop_hash,
+        }))?;
+
+        let response = self
+            .recv("cfheaders", Some(Duration::from_secs(TIMEOUT_SECS)))?
+            .ok_or(CompactFiltersError::Timeout)?;
+        let response = match response {
+            NetworkMessage::CFHeaders(response) => response,
+            _ => return Err(CompactFiltersError::InvalidResponse),
+        };
+
+        if response.filter_type != filter_type {
+            return Err(CompactFiltersError::InvalidResponse);
+        }
+
+        Ok(response)
+    }
+
+    fn pop_cf_filter_resp(&self) -> Result<CFilter, CompactFiltersError> {
+        let response = self
+            .recv("cfilter", Some(Duration::from_secs(TIMEOUT_SECS)))?
+            .ok_or(CompactFiltersError::Timeout)?;
+        let response = match response {
+            NetworkMessage::CFilter(response) => response,
+            _ => return Err(CompactFiltersError::InvalidResponse),
+        };
+
+        Ok(response)
+    }
+
+    fn get_cf_filters(
+        &self,
+        filter_type: u8,
+        start_height: u32,
+        stop_hash: BlockHash,
+    ) -> Result<(), CompactFiltersError> {
+        self.send(NetworkMessage::GetCFilters(GetCFilters {
+            filter_type,
+            start_height,
+            stop_hash,
+        }))?;
+
+        Ok(())
+    }
+}
+
+pub trait InvPeer {
+    fn get_block(&self, block_hash: BlockHash) -> Result<Option<Block>, CompactFiltersError>;
+    fn ask_for_mempool(&self) -> Result<(), CompactFiltersError>;
+    fn broadcast_tx(&self, tx: Transaction) -> Result<(), CompactFiltersError>;
+}
+
+impl InvPeer for Peer {
+    fn get_block(&self, block_hash: BlockHash) -> Result<Option<Block>, CompactFiltersError> {
+        self.send(NetworkMessage::GetData(vec![Inventory::WitnessBlock(
+            block_hash,
+        )]))?;
+
+        match self.recv("block", Some(Duration::from_secs(TIMEOUT_SECS)))? {
+            None => Ok(None),
+            Some(NetworkMessage::Block(response)) => Ok(Some(response)),
+            _ => Err(CompactFiltersError::InvalidResponse),
+        }
+    }
+
+    fn ask_for_mempool(&self) -> Result<(), CompactFiltersError> {
+        self.send(NetworkMessage::MemPool)?;
+        let inv = match self.recv("inv", Some(Duration::from_secs(5)))? {
+            None => return Ok(()), // empty mempool
+            Some(NetworkMessage::Inv(inv)) => inv,
+            _ => return Err(CompactFiltersError::InvalidResponse),
+        };
+
+        let getdata = inv
+            .iter()
+            .cloned()
+            .filter(|item| match item {
+                Inventory::Transaction(txid) if !self.mempool.has_tx(txid) => true,
+                _ => false,
+            })
+            .collect::<Vec<_>>();
+        let num_txs = getdata.len();
+        self.send(NetworkMessage::GetData(getdata))?;
+
+        for _ in 0..num_txs {
+            let tx = self
+                .recv("tx", Some(Duration::from_secs(TIMEOUT_SECS)))?
+                .ok_or(CompactFiltersError::Timeout)?;
+            let tx = match tx {
+                NetworkMessage::Tx(tx) => tx,
+                _ => return Err(CompactFiltersError::InvalidResponse),
+            };
+
+            self.mempool.add_tx(tx);
+        }
+
+        Ok(())
+    }
+
+    fn broadcast_tx(&self, tx: Transaction) -> Result<(), CompactFiltersError> {
+        self.mempool.add_tx(tx.clone());
+        self.send(NetworkMessage::Tx(tx))?;
+
+        Ok(())
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/store.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/store.rs.html new file mode 100644 index 0000000000..35d649a23b --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/store.rs.html @@ -0,0 +1,1814 @@ +store.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+use std::convert::TryInto;
+use std::fmt;
+use std::io::{Read, Write};
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::sync::Arc;
+use std::sync::RwLock;
+
+use rand::distributions::Alphanumeric;
+use rand::{thread_rng, Rng};
+
+use rocksdb::{Direction, IteratorMode, ReadOptions, WriteBatch, DB};
+
+use bitcoin::consensus::{deserialize, encode::VarInt, serialize, Decodable, Encodable};
+use bitcoin::hash_types::FilterHash;
+use bitcoin::hashes::hex::FromHex;
+use bitcoin::hashes::{sha256d, Hash};
+use bitcoin::util::bip158::BlockFilter;
+use bitcoin::util::uint::Uint256;
+use bitcoin::Block;
+use bitcoin::BlockHash;
+use bitcoin::BlockHeader;
+use bitcoin::Network;
+
+use super::CompactFiltersError;
+
+lazy_static! {
+    static ref MAINNET_GENESIS: Block = deserialize(&Vec::<u8>::from_hex("0100000000000000000000000000000000000000000000000000000000000000000000003BA3EDFD7A7B12B27AC72C3E67768F617FC81BC3888A51323A9FB8AA4B1E5E4A29AB5F49FFFF001D1DAC2B7C0101000000010000000000000000000000000000000000000000000000000000000000000000FFFFFFFF4D04FFFF001D0104455468652054696D65732030332F4A616E2F32303039204368616E63656C6C6F72206F6E206272696E6B206F66207365636F6E64206261696C6F757420666F722062616E6B73FFFFFFFF0100F2052A01000000434104678AFDB0FE5548271967F1A67130B7105CD6A828E03909A67962E0EA1F61DEB649F6BC3F4CEF38C4F35504E51EC112DE5C384DF7BA0B8D578A4C702B6BF11D5FAC00000000").unwrap()).unwrap();
+    static ref TESTNET_GENESIS: Block = deserialize(&Vec::<u8>::from_hex("0100000000000000000000000000000000000000000000000000000000000000000000003BA3EDFD7A7B12B27AC72C3E67768F617FC81BC3888A51323A9FB8AA4B1E5E4ADAE5494DFFFF001D1AA4AE180101000000010000000000000000000000000000000000000000000000000000000000000000FFFFFFFF4D04FFFF001D0104455468652054696D65732030332F4A616E2F32303039204368616E63656C6C6F72206F6E206272696E6B206F66207365636F6E64206261696C6F757420666F722062616E6B73FFFFFFFF0100F2052A01000000434104678AFDB0FE5548271967F1A67130B7105CD6A828E03909A67962E0EA1F61DEB649F6BC3F4CEF38C4F35504E51EC112DE5C384DF7BA0B8D578A4C702B6BF11D5FAC00000000").unwrap()).unwrap();
+    static ref REGTEST_GENESIS: Block = deserialize(&Vec::<u8>::from_hex("0100000000000000000000000000000000000000000000000000000000000000000000003BA3EDFD7A7B12B27AC72C3E67768F617FC81BC3888A51323A9FB8AA4B1E5E4ADAE5494DFFFF7F20020000000101000000010000000000000000000000000000000000000000000000000000000000000000FFFFFFFF4D04FFFF001D0104455468652054696D65732030332F4A616E2F32303039204368616E63656C6C6F72206F6E206272696E6B206F66207365636F6E64206261696C6F757420666F722062616E6B73FFFFFFFF0100F2052A01000000434104678AFDB0FE5548271967F1A67130B7105CD6A828E03909A67962E0EA1F61DEB649F6BC3F4CEF38C4F35504E51EC112DE5C384DF7BA0B8D578A4C702B6BF11D5FAC00000000").unwrap()).unwrap();
+}
+
+pub trait StoreType: Default + fmt::Debug {}
+
+#[derive(Default, Debug)]
+pub struct Full;
+impl StoreType for Full {}
+#[derive(Default, Debug)]
+pub struct Snapshot;
+impl StoreType for Snapshot {}
+
+pub enum StoreEntry {
+    BlockHeader(Option<usize>),
+    Block(Option<usize>),
+    BlockHeaderIndex(Option<BlockHash>),
+    CFilterTable((u8, Option<usize>)),
+}
+
+impl StoreEntry {
+    pub fn get_prefix(&self) -> Vec<u8> {
+        match self {
+            StoreEntry::BlockHeader(_) => b"z",
+            StoreEntry::Block(_) => b"x",
+            StoreEntry::BlockHeaderIndex(_) => b"i",
+            StoreEntry::CFilterTable(_) => b"t",
+        }
+        .to_vec()
+    }
+
+    pub fn get_key(&self) -> Vec<u8> {
+        let mut prefix = self.get_prefix();
+        match self {
+            StoreEntry::BlockHeader(Some(height)) => {
+                prefix.extend_from_slice(&height.to_be_bytes())
+            }
+            StoreEntry::Block(Some(height)) => prefix.extend_from_slice(&height.to_be_bytes()),
+            StoreEntry::BlockHeaderIndex(Some(hash)) => {
+                prefix.extend_from_slice(&hash.into_inner())
+            }
+            StoreEntry::CFilterTable((filter_type, bundle_index)) => {
+                prefix.push(*filter_type);
+                if let Some(bundle_index) = bundle_index {
+                    prefix.extend_from_slice(&bundle_index.to_be_bytes());
+                }
+            }
+            _ => {}
+        }
+
+        prefix
+    }
+}
+
+pub trait SerializeDb: Sized {
+    fn serialize(&self) -> Vec<u8>;
+    fn deserialize(data: &[u8]) -> Result<Self, CompactFiltersError>;
+}
+
+impl<T> SerializeDb for T
+where
+    T: Encodable + Decodable,
+{
+    fn serialize(&self) -> Vec<u8> {
+        serialize(self)
+    }
+
+    fn deserialize(data: &[u8]) -> Result<Self, CompactFiltersError> {
+        Ok(deserialize(data).map_err(|_| CompactFiltersError::DataCorruption)?)
+    }
+}
+
+impl Encodable for FilterHeader {
+    fn consensus_encode<W: Write>(
+        &self,
+        mut e: W,
+    ) -> Result<usize, bitcoin::consensus::encode::Error> {
+        let mut written = self.prev_header_hash.consensus_encode(&mut e)?;
+        written += self.filter_hash.consensus_encode(&mut e)?;
+        Ok(written)
+    }
+}
+
+impl Decodable for FilterHeader {
+    fn consensus_decode<D: Read>(mut d: D) -> Result<Self, bitcoin::consensus::encode::Error> {
+        let prev_header_hash = FilterHeaderHash::consensus_decode(&mut d)?;
+        let filter_hash = FilterHash::consensus_decode(&mut d)?;
+
+        Ok(FilterHeader {
+            prev_header_hash,
+            filter_hash,
+        })
+    }
+}
+
+impl Encodable for BundleStatus {
+    fn consensus_encode<W: Write>(
+        &self,
+        mut e: W,
+    ) -> Result<usize, bitcoin::consensus::encode::Error> {
+        let mut written = 0;
+
+        match self {
+            BundleStatus::Init => {
+                written += 0x00u8.consensus_encode(&mut e)?;
+            }
+            BundleStatus::CFHeaders { cf_headers } => {
+                written += 0x01u8.consensus_encode(&mut e)?;
+                written += VarInt(cf_headers.len() as u64).consensus_encode(&mut e)?;
+                for header in cf_headers {
+                    written += header.consensus_encode(&mut e)?;
+                }
+            }
+            BundleStatus::CFilters { cf_filters } => {
+                written += 0x02u8.consensus_encode(&mut e)?;
+                written += VarInt(cf_filters.len() as u64).consensus_encode(&mut e)?;
+                for filter in cf_filters {
+                    written += filter.consensus_encode(&mut e)?;
+                }
+            }
+            BundleStatus::Processed { cf_filters } => {
+                written += 0x03u8.consensus_encode(&mut e)?;
+                written += VarInt(cf_filters.len() as u64).consensus_encode(&mut e)?;
+                for filter in cf_filters {
+                    written += filter.consensus_encode(&mut e)?;
+                }
+            }
+            BundleStatus::Pruned => {
+                written += 0x04u8.consensus_encode(&mut e)?;
+            }
+            BundleStatus::Tip { cf_filters } => {
+                written += 0x05u8.consensus_encode(&mut e)?;
+                written += VarInt(cf_filters.len() as u64).consensus_encode(&mut e)?;
+                for filter in cf_filters {
+                    written += filter.consensus_encode(&mut e)?;
+                }
+            }
+        }
+
+        Ok(written)
+    }
+}
+
+impl Decodable for BundleStatus {
+    fn consensus_decode<D: Read>(mut d: D) -> Result<Self, bitcoin::consensus::encode::Error> {
+        let byte_type = u8::consensus_decode(&mut d)?;
+        match byte_type {
+            0x00 => Ok(BundleStatus::Init),
+            0x01 => {
+                let num = VarInt::consensus_decode(&mut d)?;
+                let num = num.0 as usize;
+
+                let mut cf_headers = Vec::with_capacity(num);
+                for _ in 0..num {
+                    cf_headers.push(FilterHeader::consensus_decode(&mut d)?);
+                }
+
+                Ok(BundleStatus::CFHeaders { cf_headers })
+            }
+            0x02 => {
+                let num = VarInt::consensus_decode(&mut d)?;
+                let num = num.0 as usize;
+
+                let mut cf_filters = Vec::with_capacity(num);
+                for _ in 0..num {
+                    cf_filters.push(Vec::<u8>::consensus_decode(&mut d)?);
+                }
+
+                Ok(BundleStatus::CFilters { cf_filters })
+            }
+            0x03 => {
+                let num = VarInt::consensus_decode(&mut d)?;
+                let num = num.0 as usize;
+
+                let mut cf_filters = Vec::with_capacity(num);
+                for _ in 0..num {
+                    cf_filters.push(Vec::<u8>::consensus_decode(&mut d)?);
+                }
+
+                Ok(BundleStatus::Processed { cf_filters })
+            }
+            0x04 => Ok(BundleStatus::Pruned),
+            0x05 => {
+                let num = VarInt::consensus_decode(&mut d)?;
+                let num = num.0 as usize;
+
+                let mut cf_filters = Vec::with_capacity(num);
+                for _ in 0..num {
+                    cf_filters.push(Vec::<u8>::consensus_decode(&mut d)?);
+                }
+
+                Ok(BundleStatus::Tip { cf_filters })
+            }
+            _ => Err(bitcoin::consensus::encode::Error::ParseFailed(
+                "Invalid byte type",
+            )),
+        }
+    }
+}
+
+pub struct ChainStore<T: StoreType> {
+    store: Arc<RwLock<DB>>,
+    cf_name: String,
+    min_height: usize,
+    network: Network,
+    phantom: PhantomData<T>,
+}
+
+impl ChainStore<Full> {
+    pub fn new(store: DB, network: Network) -> Result<Self, CompactFiltersError> {
+        let genesis = match network {
+            Network::Bitcoin => MAINNET_GENESIS.deref(),
+            Network::Testnet => TESTNET_GENESIS.deref(),
+            Network::Regtest => REGTEST_GENESIS.deref(),
+        };
+
+        let cf_name = "default".to_string();
+        let cf_handle = store.cf_handle(&cf_name).unwrap();
+
+        let genesis_key = StoreEntry::BlockHeader(Some(0)).get_key();
+
+        if store.get_pinned_cf(cf_handle, &genesis_key)?.is_none() {
+            let mut batch = WriteBatch::default();
+            batch.put_cf(
+                cf_handle,
+                genesis_key,
+                (genesis.header, genesis.header.work()).serialize(),
+            );
+            batch.put_cf(
+                cf_handle,
+                StoreEntry::BlockHeaderIndex(Some(genesis.block_hash())).get_key(),
+                &0usize.to_be_bytes(),
+            );
+            store.write(batch)?;
+        }
+
+        Ok(ChainStore {
+            store: Arc::new(RwLock::new(store)),
+            cf_name,
+            min_height: 0,
+            network,
+            phantom: PhantomData,
+        })
+    }
+
+    pub fn get_locators(&self) -> Result<Vec<(BlockHash, usize)>, CompactFiltersError> {
+        let mut step = 1;
+        let mut index = self.get_height()?;
+        let mut answer = Vec::new();
+
+        let store_read = self.store.read().unwrap();
+        let cf_handle = store_read.cf_handle(&self.cf_name).unwrap();
+
+        loop {
+            if answer.len() > 10 {
+                step *= 2;
+            }
+
+            let (header, _): (BlockHeader, Uint256) = SerializeDb::deserialize(
+                &store_read
+                    .get_pinned_cf(cf_handle, StoreEntry::BlockHeader(Some(index)).get_key())?
+                    .unwrap(),
+            )?;
+            answer.push((header.block_hash(), index));
+
+            if let Some(new_index) = index.checked_sub(step) {
+                index = new_index;
+            } else {
+                break;
+            }
+        }
+
+        Ok(answer)
+    }
+
+    pub fn start_snapshot(&self, from: usize) -> Result<ChainStore<Snapshot>, CompactFiltersError> {
+        let new_cf_name: String = thread_rng().sample_iter(&Alphanumeric).take(16).collect();
+        let new_cf_name = format!("_headers:{}", new_cf_name);
+
+        let mut write_store = self.store.write().unwrap();
+
+        write_store.create_cf(&new_cf_name, &Default::default())?;
+
+        let cf_handle = write_store.cf_handle(&self.cf_name).unwrap();
+        let new_cf_handle = write_store.cf_handle(&new_cf_name).unwrap();
+
+        let (header, work): (BlockHeader, Uint256) = SerializeDb::deserialize(
+            &write_store
+                .get_pinned_cf(cf_handle, StoreEntry::BlockHeader(Some(from)).get_key())?
+                .ok_or(CompactFiltersError::DataCorruption)?,
+        )?;
+
+        let mut batch = WriteBatch::default();
+        batch.put_cf(
+            new_cf_handle,
+            StoreEntry::BlockHeaderIndex(Some(header.block_hash())).get_key(),
+            &from.to_be_bytes(),
+        );
+        batch.put_cf(
+            new_cf_handle,
+            StoreEntry::BlockHeader(Some(from)).get_key(),
+            (header, work).serialize(),
+        );
+        write_store.write(batch)?;
+
+        let store = Arc::clone(&self.store);
+        Ok(ChainStore {
+            store,
+            cf_name: new_cf_name,
+            min_height: from,
+            network: self.network,
+            phantom: PhantomData,
+        })
+    }
+
+    pub fn recover_snapshot(&self, cf_name: &str) -> Result<(), CompactFiltersError> {
+        let mut write_store = self.store.write().unwrap();
+        let snapshot_cf_handle = write_store.cf_handle(cf_name).unwrap();
+
+        let prefix = StoreEntry::BlockHeader(None).get_key();
+        let mut iterator = write_store.prefix_iterator_cf(snapshot_cf_handle, prefix);
+
+        let min_height = match iterator
+            .next()
+            .and_then(|(k, _)| k[1..].try_into().ok())
+            .map(|bytes| usize::from_be_bytes(bytes))
+        {
+            None => {
+                std::mem::drop(iterator);
+                write_store.drop_cf(cf_name).ok();
+
+                return Ok(());
+            }
+            Some(x) => x,
+        };
+        std::mem::drop(iterator);
+        std::mem::drop(write_store);
+
+        let snapshot = ChainStore {
+            store: Arc::clone(&self.store),
+            cf_name: cf_name.into(),
+            min_height,
+            network: self.network,
+            phantom: PhantomData,
+        };
+        if snapshot.work()? > self.work()? {
+            self.apply_snapshot(snapshot)?;
+        }
+
+        Ok(())
+    }
+
+    pub fn apply_snapshot(
+        &self,
+        snaphost: ChainStore<Snapshot>,
+    ) -> Result<(), CompactFiltersError> {
+        let mut batch = WriteBatch::default();
+
+        let read_store = self.store.read().unwrap();
+        let cf_handle = read_store.cf_handle(&self.cf_name).unwrap();
+        let snapshot_cf_handle = read_store.cf_handle(&snaphost.cf_name).unwrap();
+
+        let from_key = StoreEntry::BlockHeader(Some(snaphost.min_height)).get_key();
+        let to_key = StoreEntry::BlockHeader(Some(usize::MAX)).get_key();
+
+        let mut opts = ReadOptions::default();
+        opts.set_iterate_upper_bound(to_key.clone());
+
+        log::debug!("Removing items");
+        batch.delete_range_cf(cf_handle, &from_key, &to_key);
+        for (_, v) in read_store.iterator_cf_opt(
+            cf_handle,
+            opts,
+            IteratorMode::From(&from_key, Direction::Forward),
+        ) {
+            let (header, _): (BlockHeader, Uint256) = SerializeDb::deserialize(&v)?;
+
+            batch.delete_cf(
+                cf_handle,
+                StoreEntry::BlockHeaderIndex(Some(header.block_hash())).get_key(),
+            );
+        }
+
+        // Delete full blocks overriden by snapshot
+        let from_key = StoreEntry::Block(Some(snaphost.min_height)).get_key();
+        let to_key = StoreEntry::Block(Some(usize::MAX)).get_key();
+        batch.delete_range(&from_key, &to_key);
+
+        log::debug!("Copying over new items");
+        for (k, v) in read_store.iterator_cf(snapshot_cf_handle, IteratorMode::Start) {
+            batch.put_cf(cf_handle, k, v);
+        }
+
+        read_store.write(batch)?;
+
+        std::mem::drop(snapshot_cf_handle);
+        std::mem::drop(cf_handle);
+        std::mem::drop(read_store);
+
+        self.store.write().unwrap().drop_cf(&snaphost.cf_name)?;
+
+        Ok(())
+    }
+
+    pub fn get_height_for(
+        &self,
+        block_hash: &BlockHash,
+    ) -> Result<Option<usize>, CompactFiltersError> {
+        let read_store = self.store.read().unwrap();
+        let cf_handle = read_store.cf_handle(&self.cf_name).unwrap();
+
+        let key = StoreEntry::BlockHeaderIndex(Some(block_hash.clone())).get_key();
+        let data = read_store.get_pinned_cf(cf_handle, key)?;
+        Ok(data
+            .map(|data| {
+                Ok::<_, CompactFiltersError>(usize::from_be_bytes(
+                    data.as_ref()
+                        .try_into()
+                        .map_err(|_| CompactFiltersError::DataCorruption)?,
+                ))
+            })
+            .transpose()?)
+    }
+
+    pub fn get_block_hash(&self, height: usize) -> Result<Option<BlockHash>, CompactFiltersError> {
+        let read_store = self.store.read().unwrap();
+        let cf_handle = read_store.cf_handle(&self.cf_name).unwrap();
+
+        let key = StoreEntry::BlockHeader(Some(height)).get_key();
+        let data = read_store.get_pinned_cf(cf_handle, key)?;
+        Ok(data
+            .map(|data| {
+                let (header, _): (BlockHeader, Uint256) =
+                    deserialize(&data).map_err(|_| CompactFiltersError::DataCorruption)?;
+                Ok::<_, CompactFiltersError>(header.block_hash())
+            })
+            .transpose()?)
+    }
+
+    pub fn save_full_block(&self, block: &Block, height: usize) -> Result<(), CompactFiltersError> {
+        let key = StoreEntry::Block(Some(height)).get_key();
+        self.store.read().unwrap().put(key, block.serialize())?;
+
+        Ok(())
+    }
+
+    pub fn get_full_block(&self, height: usize) -> Result<Option<Block>, CompactFiltersError> {
+        let read_store = self.store.read().unwrap();
+
+        let key = StoreEntry::Block(Some(height)).get_key();
+        let opt_block = read_store.get_pinned(key)?;
+
+        Ok(opt_block
+            .map(|data| deserialize(&data))
+            .transpose()
+            .map_err(|_| CompactFiltersError::DataCorruption)?)
+    }
+
+    pub fn delete_blocks_until(&self, height: usize) -> Result<(), CompactFiltersError> {
+        let from_key = StoreEntry::Block(Some(0)).get_key();
+        let to_key = StoreEntry::Block(Some(height)).get_key();
+
+        let mut batch = WriteBatch::default();
+        batch.delete_range(&from_key, &to_key);
+
+        self.store.read().unwrap().write(batch)?;
+
+        Ok(())
+    }
+
+    pub fn iter_full_blocks(&self) -> Result<Vec<(usize, Block)>, CompactFiltersError> {
+        let read_store = self.store.read().unwrap();
+
+        let prefix = StoreEntry::Block(None).get_key();
+
+        let iterator = read_store.prefix_iterator(&prefix);
+        // FIXME: we have to filter manually because rocksdb sometimes returns stuff that doesn't
+        // have the right prefix
+        iterator
+            .filter(|(k, _)| k.starts_with(&prefix))
+            .map(|(k, v)| {
+                let height: usize = usize::from_be_bytes(
+                    k[1..]
+                        .try_into()
+                        .map_err(|_| CompactFiltersError::DataCorruption)?,
+                );
+                let block = SerializeDb::deserialize(&v)?;
+
+                Ok((height, block))
+            })
+            .collect::<Result<_, _>>()
+    }
+}
+
+impl<T: StoreType> ChainStore<T> {
+    pub fn work(&self) -> Result<Uint256, CompactFiltersError> {
+        let read_store = self.store.read().unwrap();
+        let cf_handle = read_store.cf_handle(&self.cf_name).unwrap();
+
+        let prefix = StoreEntry::BlockHeader(None).get_key();
+        let iterator = read_store.prefix_iterator_cf(cf_handle, prefix);
+
+        Ok(iterator
+            .last()
+            .map(|(_, v)| -> Result<_, CompactFiltersError> {
+                let (_, work): (BlockHeader, Uint256) = SerializeDb::deserialize(&v)?;
+
+                Ok(work)
+            })
+            .transpose()?
+            .unwrap_or_default())
+    }
+
+    pub fn get_height(&self) -> Result<usize, CompactFiltersError> {
+        let read_store = self.store.read().unwrap();
+        let cf_handle = read_store.cf_handle(&self.cf_name).unwrap();
+
+        let prefix = StoreEntry::BlockHeader(None).get_key();
+        let iterator = read_store.prefix_iterator_cf(cf_handle, prefix);
+
+        Ok(iterator
+            .last()
+            .map(|(k, _)| -> Result<_, CompactFiltersError> {
+                let height = usize::from_be_bytes(
+                    k[1..]
+                        .try_into()
+                        .map_err(|_| CompactFiltersError::DataCorruption)?,
+                );
+
+                Ok(height)
+            })
+            .transpose()?
+            .unwrap_or_default())
+    }
+
+    pub fn get_tip_hash(&self) -> Result<Option<BlockHash>, CompactFiltersError> {
+        let read_store = self.store.read().unwrap();
+        let cf_handle = read_store.cf_handle(&self.cf_name).unwrap();
+
+        let prefix = StoreEntry::BlockHeader(None).get_key();
+        let iterator = read_store.prefix_iterator_cf(cf_handle, prefix);
+
+        Ok(iterator
+            .last()
+            .map(|(_, v)| -> Result<_, CompactFiltersError> {
+                let (header, _): (BlockHeader, Uint256) = SerializeDb::deserialize(&v)?;
+
+                Ok(header.block_hash())
+            })
+            .transpose()?)
+    }
+
+    pub fn apply(
+        &mut self,
+        from: usize,
+        headers: Vec<BlockHeader>,
+    ) -> Result<BlockHash, CompactFiltersError> {
+        let mut batch = WriteBatch::default();
+
+        let read_store = self.store.read().unwrap();
+        let cf_handle = read_store.cf_handle(&self.cf_name).unwrap();
+
+        let (mut last_hash, mut accumulated_work) = read_store
+            .get_pinned_cf(cf_handle, StoreEntry::BlockHeader(Some(from)).get_key())?
+            .map(|result| {
+                let (header, work): (BlockHeader, Uint256) = SerializeDb::deserialize(&result)?;
+                Ok::<_, CompactFiltersError>((header.block_hash(), work))
+            })
+            .transpose()?
+            .ok_or(CompactFiltersError::DataCorruption)?;
+
+        for (index, header) in headers.into_iter().enumerate() {
+            if header.prev_blockhash != last_hash {
+                return Err(CompactFiltersError::InvalidHeaders);
+            }
+
+            last_hash = header.block_hash();
+            accumulated_work = accumulated_work + header.work();
+
+            let height = from + index + 1;
+            batch.put_cf(
+                cf_handle,
+                StoreEntry::BlockHeaderIndex(Some(header.block_hash())).get_key(),
+                &(height).to_be_bytes(),
+            );
+            batch.put_cf(
+                cf_handle,
+                StoreEntry::BlockHeader(Some(height)).get_key(),
+                (header, accumulated_work).serialize(),
+            );
+        }
+
+        std::mem::drop(cf_handle);
+        std::mem::drop(read_store);
+
+        self.store.write().unwrap().write(batch)?;
+        Ok(last_hash)
+    }
+}
+
+impl<T: StoreType> fmt::Debug for ChainStore<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct(&format!("ChainStore<{:?}>", T::default()))
+            .field("cf_name", &self.cf_name)
+            .field("min_height", &self.min_height)
+            .field("network", &self.network)
+            .field("headers_height", &self.get_height())
+            .field("tip_hash", &self.get_tip_hash())
+            .finish()
+    }
+}
+
+pub type FilterHeaderHash = FilterHash;
+
+#[derive(Debug, Clone)]
+pub struct FilterHeader {
+    prev_header_hash: FilterHeaderHash,
+    filter_hash: FilterHash,
+}
+
+impl FilterHeader {
+    fn header_hash(&self) -> FilterHeaderHash {
+        let mut hash_data = self.filter_hash.into_inner().to_vec();
+        hash_data.extend_from_slice(&self.prev_header_hash);
+        sha256d::Hash::hash(&hash_data).into()
+    }
+}
+
+pub enum BundleStatus {
+    Init,
+    CFHeaders { cf_headers: Vec<FilterHeader> },
+    CFilters { cf_filters: Vec<Vec<u8>> },
+    Processed { cf_filters: Vec<Vec<u8>> },
+    Tip { cf_filters: Vec<Vec<u8>> },
+    Pruned,
+}
+
+pub struct CFStore {
+    store: Arc<RwLock<DB>>,
+    filter_type: u8,
+}
+
+type BundleEntry = (BundleStatus, FilterHeaderHash);
+
+impl CFStore {
+    pub fn new(
+        headers_store: &ChainStore<Full>,
+        filter_type: u8,
+    ) -> Result<Self, CompactFiltersError> {
+        let cf_store = CFStore {
+            store: Arc::clone(&headers_store.store),
+            filter_type,
+        };
+
+        let genesis = match headers_store.network {
+            Network::Bitcoin => MAINNET_GENESIS.deref(),
+            Network::Testnet => TESTNET_GENESIS.deref(),
+            Network::Regtest => REGTEST_GENESIS.deref(),
+        };
+
+        let filter = BlockFilter::new_script_filter(genesis, |utxo| {
+            Err(bitcoin::util::bip158::Error::UtxoMissing(*utxo))
+        })?;
+        let first_key = StoreEntry::CFilterTable((filter_type, Some(0))).get_key();
+
+        // Add the genesis' filter
+        {
+            let read_store = cf_store.store.read().unwrap();
+            if read_store.get_pinned(&first_key)?.is_none() {
+                read_store.put(
+                    &first_key,
+                    (BundleStatus::Init, filter.filter_id(&FilterHash::default())).serialize(),
+                )?;
+            }
+        }
+
+        Ok(cf_store)
+    }
+
+    pub fn get_filter_type(&self) -> u8 {
+        self.filter_type
+    }
+
+    pub fn get_bundles(&self) -> Result<Vec<BundleEntry>, CompactFiltersError> {
+        let read_store = self.store.read().unwrap();
+
+        let prefix = StoreEntry::CFilterTable((self.filter_type, None)).get_key();
+        let iterator = read_store.prefix_iterator(&prefix);
+
+        // FIXME: we have to filter manually because rocksdb sometimes returns stuff that doesn't
+        // have the right prefix
+        iterator
+            .filter(|(k, _)| k.starts_with(&prefix))
+            .map(|(_, data)| BundleEntry::deserialize(&data))
+            .collect::<Result<_, _>>()
+    }
+
+    pub fn get_checkpoints(&self) -> Result<Vec<FilterHash>, CompactFiltersError> {
+        let read_store = self.store.read().unwrap();
+
+        let prefix = StoreEntry::CFilterTable((self.filter_type, None)).get_key();
+        let iterator = read_store.prefix_iterator(&prefix);
+
+        // FIXME: we have to filter manually because rocksdb sometimes returns stuff that doesn't
+        // have the right prefix
+        Ok(iterator
+            .filter(|(k, _)| k.starts_with(&prefix))
+            .skip(1)
+            .map(|(_, data)| Ok::<_, CompactFiltersError>(BundleEntry::deserialize(&data)?.1))
+            .collect::<Result<_, _>>()?)
+    }
+
+    pub fn replace_checkpoints(
+        &self,
+        checkpoints: Vec<FilterHash>,
+    ) -> Result<(), CompactFiltersError> {
+        let current_checkpoints = self.get_checkpoints()?;
+
+        let mut equal_bundles = 0;
+        for (index, (our, their)) in current_checkpoints
+            .iter()
+            .zip(checkpoints.iter())
+            .enumerate()
+        {
+            equal_bundles = index;
+
+            if our != their {
+                break;
+            }
+        }
+
+        let read_store = self.store.read().unwrap();
+        let mut batch = WriteBatch::default();
+
+        for (index, filter_hash) in checkpoints.iter().enumerate().skip(equal_bundles) {
+            let key = StoreEntry::CFilterTable((self.filter_type, Some(index + 1))).get_key(); // +1 to skip the genesis' filter
+
+            if let Some((BundleStatus::Tip { .. }, _)) = read_store
+                .get_pinned(&key)?
+                .map(|data| BundleEntry::deserialize(&data))
+                .transpose()?
+            {
+                println!("Keeping bundle #{} as Tip", index);
+            } else {
+                batch.put(&key, (BundleStatus::Init, *filter_hash).serialize());
+            }
+        }
+
+        read_store.write(batch)?;
+
+        Ok(())
+    }
+
+    pub fn advance_to_cf_headers(
+        &self,
+        bundle: usize,
+        checkpoint_hash: FilterHeaderHash,
+        filter_headers: Vec<FilterHash>,
+    ) -> Result<BundleStatus, CompactFiltersError> {
+        let mut last_hash = checkpoint_hash;
+        let cf_headers = filter_headers
+            .into_iter()
+            .map(|filter_hash| {
+                let filter_header = FilterHeader {
+                    prev_header_hash: last_hash,
+                    filter_hash,
+                };
+                last_hash = filter_header.header_hash();
+
+                filter_header
+            })
+            .collect();
+
+        let read_store = self.store.read().unwrap();
+
+        let next_key = StoreEntry::CFilterTable((self.filter_type, Some(bundle + 1))).get_key(); // +1 to skip the genesis' filter
+        if let Some((_, next_checkpoint)) = read_store
+            .get_pinned(&next_key)?
+            .map(|data| BundleEntry::deserialize(&data))
+            .transpose()?
+        {
+            // check connection with the next bundle if present
+            if last_hash != next_checkpoint {
+                return Err(CompactFiltersError::InvalidFilterHeader);
+            }
+        }
+
+        let key = StoreEntry::CFilterTable((self.filter_type, Some(bundle))).get_key();
+        let value = (BundleStatus::CFHeaders { cf_headers }, checkpoint_hash);
+
+        read_store.put(key, value.serialize())?;
+
+        Ok(value.0)
+    }
+
+    pub fn advance_to_cf_filters(
+        &self,
+        bundle: usize,
+        checkpoint_hash: FilterHeaderHash,
+        headers: Vec<FilterHeader>,
+        filters: Vec<(usize, Vec<u8>)>,
+    ) -> Result<BundleStatus, CompactFiltersError> {
+        let cf_filters = filters
+            .into_iter()
+            .zip(headers.iter())
+            .map(|((_, filter_content), header)| {
+                if header.filter_hash != sha256d::Hash::hash(&filter_content).into() {
+                    return Err(CompactFiltersError::InvalidFilter);
+                }
+
+                Ok::<_, CompactFiltersError>(filter_content)
+            })
+            .collect::<Result<_, _>>()?;
+
+        let key = StoreEntry::CFilterTable((self.filter_type, Some(bundle))).get_key();
+        let value = (BundleStatus::CFilters { cf_filters }, checkpoint_hash);
+
+        let read_store = self.store.read().unwrap();
+        read_store.put(key, value.serialize())?;
+
+        Ok(value.0)
+    }
+
+    pub fn prune_filters(
+        &self,
+        bundle: usize,
+        checkpoint_hash: FilterHeaderHash,
+    ) -> Result<BundleStatus, CompactFiltersError> {
+        let key = StoreEntry::CFilterTable((self.filter_type, Some(bundle))).get_key();
+        let value = (BundleStatus::Pruned, checkpoint_hash);
+
+        let read_store = self.store.read().unwrap();
+        read_store.put(key, value.serialize())?;
+
+        Ok(value.0)
+    }
+
+    pub fn mark_as_tip(
+        &self,
+        bundle: usize,
+        cf_filters: Vec<Vec<u8>>,
+        checkpoint_hash: FilterHeaderHash,
+    ) -> Result<BundleStatus, CompactFiltersError> {
+        let key = StoreEntry::CFilterTable((self.filter_type, Some(bundle))).get_key();
+        let value = (BundleStatus::Tip { cf_filters }, checkpoint_hash);
+
+        let read_store = self.store.read().unwrap();
+        read_store.put(key, value.serialize())?;
+
+        Ok(value.0)
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/sync.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/sync.rs.html new file mode 100644 index 0000000000..3ac0bf5529 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/compact_filters/sync.rs.html @@ -0,0 +1,632 @@ +sync.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+use std::collections::{BTreeMap, HashMap, VecDeque};
+use std::sync::{Arc, Mutex};
+use std::time::Duration;
+
+use bitcoin::hash_types::{BlockHash, FilterHash};
+use bitcoin::network::message::NetworkMessage;
+use bitcoin::network::message_blockdata::GetHeadersMessage;
+use bitcoin::util::bip158::BlockFilter;
+
+use super::peer::*;
+use super::store::*;
+use super::CompactFiltersError;
+use crate::error::Error;
+
+pub(crate) const BURIED_CONFIRMATIONS: usize = 100;
+
+pub struct CFSync {
+    headers_store: Arc<ChainStore<Full>>,
+    cf_store: Arc<CFStore>,
+    skip_blocks: usize,
+    bundles: Mutex<VecDeque<(BundleStatus, FilterHash, usize)>>,
+}
+
+impl CFSync {
+    pub fn new(
+        headers_store: Arc<ChainStore<Full>>,
+        skip_blocks: usize,
+        filter_type: u8,
+    ) -> Result<Self, CompactFiltersError> {
+        let cf_store = Arc::new(CFStore::new(&headers_store, filter_type)?);
+
+        Ok(CFSync {
+            headers_store,
+            cf_store,
+            skip_blocks,
+            bundles: Mutex::new(VecDeque::new()),
+        })
+    }
+
+    pub fn pruned_bundles(&self) -> Result<usize, CompactFiltersError> {
+        Ok(self
+            .cf_store
+            .get_bundles()?
+            .into_iter()
+            .skip(self.skip_blocks / 1000)
+            .fold(0, |acc, (status, _)| match status {
+                BundleStatus::Pruned => acc + 1,
+                _ => acc,
+            }))
+    }
+
+    pub fn prepare_sync(&self, peer: Arc<Peer>) -> Result<(), CompactFiltersError> {
+        let mut bundles_lock = self.bundles.lock().unwrap();
+
+        let resp = peer.get_cf_checkpt(
+            self.cf_store.get_filter_type(),
+            self.headers_store.get_tip_hash()?.unwrap(),
+        )?;
+        self.cf_store.replace_checkpoints(resp.filter_headers)?;
+
+        bundles_lock.clear();
+        for (index, (status, checkpoint)) in self.cf_store.get_bundles()?.into_iter().enumerate() {
+            bundles_lock.push_back((status, checkpoint, index));
+        }
+
+        Ok(())
+    }
+
+    pub fn capture_thread_for_sync<F, Q>(
+        &self,
+        peer: Arc<Peer>,
+        process: F,
+        completed_bundle: Q,
+    ) -> Result<(), CompactFiltersError>
+    where
+        F: Fn(&BlockHash, &BlockFilter) -> Result<bool, CompactFiltersError>,
+        Q: Fn(usize) -> Result<(), Error>,
+    {
+        let current_height = self.headers_store.get_height()?; // TODO: we should update it in case headers_store is also updated
+
+        loop {
+            let (mut status, checkpoint, index) = match self.bundles.lock().unwrap().pop_front() {
+                None => break,
+                Some(x) => x,
+            };
+
+            log::debug!(
+                "Processing bundle #{} - height {} to {}",
+                index,
+                index * 1000 + 1,
+                (index + 1) * 1000
+            );
+
+            let process_received_filters =
+                |expected_filters| -> Result<BTreeMap<usize, Vec<u8>>, CompactFiltersError> {
+                    let mut filters_map = BTreeMap::new();
+                    for _ in 0..expected_filters {
+                        let filter = peer.pop_cf_filter_resp()?;
+                        if filter.filter_type != self.cf_store.get_filter_type() {
+                            return Err(CompactFiltersError::InvalidResponse);
+                        }
+
+                        match self.headers_store.get_height_for(&filter.block_hash)? {
+                            Some(height) => filters_map.insert(height, filter.filter),
+                            None => return Err(CompactFiltersError::InvalidFilter),
+                        };
+                    }
+
+                    Ok(filters_map)
+                };
+
+            let start_height = index * 1000 + 1;
+            let mut already_processed = 0;
+
+            if start_height < self.skip_blocks {
+                status = self.cf_store.prune_filters(index, checkpoint)?;
+            }
+
+            let stop_height = std::cmp::min(current_height, start_height + 999);
+            let stop_hash = self.headers_store.get_block_hash(stop_height)?.unwrap();
+
+            if let BundleStatus::Init = status {
+                log::trace!("status: Init");
+
+                let resp = peer.get_cf_headers(0x00, start_height as u32, stop_hash)?;
+
+                assert!(resp.previous_filter == checkpoint);
+                status =
+                    self.cf_store
+                        .advance_to_cf_headers(index, checkpoint, resp.filter_hashes)?;
+            }
+            if let BundleStatus::Tip { cf_filters } = status {
+                log::trace!("status: Tip (beginning) ");
+
+                already_processed = cf_filters.len();
+                let headers_resp = peer.get_cf_headers(0x00, start_height as u32, stop_hash)?;
+
+                let cf_headers = match self.cf_store.advance_to_cf_headers(
+                    index,
+                    checkpoint,
+                    headers_resp.filter_hashes,
+                )? {
+                    BundleStatus::CFHeaders { cf_headers } => cf_headers,
+                    _ => return Err(CompactFiltersError::InvalidResponse),
+                };
+
+                peer.get_cf_filters(
+                    self.cf_store.get_filter_type(),
+                    (start_height + cf_filters.len()) as u32,
+                    stop_hash,
+                )?;
+                let expected_filters = stop_height - start_height + 1 - cf_filters.len();
+                let filters_map = process_received_filters(expected_filters)?;
+                let filters = cf_filters
+                    .into_iter()
+                    .enumerate()
+                    .chain(filters_map.into_iter())
+                    .collect();
+                status = self
+                    .cf_store
+                    .advance_to_cf_filters(index, checkpoint, cf_headers, filters)?;
+            }
+            if let BundleStatus::CFHeaders { cf_headers } = status {
+                log::trace!("status: CFHeaders");
+
+                peer.get_cf_filters(
+                    self.cf_store.get_filter_type(),
+                    start_height as u32,
+                    stop_hash,
+                )?;
+                let expected_filters = stop_height - start_height + 1;
+                let filters_map = process_received_filters(expected_filters)?;
+                status = self.cf_store.advance_to_cf_filters(
+                    index,
+                    checkpoint,
+                    cf_headers,
+                    filters_map.into_iter().collect(),
+                )?;
+            }
+            if let BundleStatus::CFilters { cf_filters } = status {
+                log::trace!("status: CFilters");
+
+                let last_sync_buried_height = (start_height + already_processed)
+                    .checked_sub(BURIED_CONFIRMATIONS)
+                    .unwrap_or(0);
+
+                for (filter_index, filter) in cf_filters.iter().enumerate() {
+                    let height = filter_index + start_height;
+
+                    // do not download blocks that were already "buried" since the last sync
+                    if height < last_sync_buried_height {
+                        continue;
+                    }
+
+                    let block_hash = self.headers_store.get_block_hash(height)?.unwrap();
+
+                    // TODO: also download random blocks?
+                    if process(&block_hash, &BlockFilter::new(&filter))? {
+                        log::debug!("Downloading block {}", block_hash);
+
+                        let block = peer
+                            .get_block(block_hash)?
+                            .ok_or(CompactFiltersError::MissingBlock)?;
+                        self.headers_store.save_full_block(&block, height)?;
+                    }
+                }
+
+                status = BundleStatus::Processed { cf_filters };
+            }
+            if let BundleStatus::Processed { cf_filters } = status {
+                log::trace!("status: Processed");
+
+                if current_height - stop_height > 1000 {
+                    status = self.cf_store.prune_filters(index, checkpoint)?;
+                } else {
+                    status = self.cf_store.mark_as_tip(index, cf_filters, checkpoint)?;
+                }
+
+                completed_bundle(index)?;
+            }
+            if let BundleStatus::Pruned = status {
+                log::trace!("status: Pruned");
+            }
+            if let BundleStatus::Tip { .. } = status {
+                log::trace!("status: Tip");
+            }
+        }
+
+        Ok(())
+    }
+}
+
+pub fn sync_headers<F>(
+    peer: Arc<Peer>,
+    store: Arc<ChainStore<Full>>,
+    sync_fn: F,
+) -> Result<Option<ChainStore<Snapshot>>, CompactFiltersError>
+where
+    F: Fn(usize) -> Result<(), Error>,
+{
+    let locators = store.get_locators()?;
+    let locators_vec = locators.iter().map(|(hash, _)| hash).cloned().collect();
+    let locators_map: HashMap<_, _> = locators.into_iter().collect();
+
+    peer.send(NetworkMessage::GetHeaders(GetHeadersMessage::new(
+        locators_vec,
+        Default::default(),
+    )))?;
+    let (mut snapshot, mut last_hash) = if let NetworkMessage::Headers(headers) = peer
+        .recv("headers", Some(Duration::from_secs(TIMEOUT_SECS)))?
+        .ok_or(CompactFiltersError::Timeout)?
+    {
+        if headers.is_empty() {
+            return Ok(None);
+        }
+
+        match locators_map.get(&headers[0].prev_blockhash) {
+            None => return Err(CompactFiltersError::InvalidHeaders),
+            Some(from) => (
+                store.start_snapshot(*from)?,
+                headers[0].prev_blockhash.clone(),
+            ),
+        }
+    } else {
+        return Err(CompactFiltersError::InvalidResponse);
+    };
+
+    let mut sync_height = store.get_height()?;
+    while sync_height < peer.get_version().start_height as usize {
+        peer.send(NetworkMessage::GetHeaders(GetHeadersMessage::new(
+            vec![last_hash],
+            Default::default(),
+        )))?;
+        if let NetworkMessage::Headers(headers) = peer
+            .recv("headers", Some(Duration::from_secs(TIMEOUT_SECS)))?
+            .ok_or(CompactFiltersError::Timeout)?
+        {
+            let batch_len = headers.len();
+            last_hash = snapshot.apply(sync_height, headers)?;
+
+            sync_height += batch_len;
+            sync_fn(sync_height)?;
+        } else {
+            return Err(CompactFiltersError::InvalidResponse);
+        }
+    }
+
+    Ok(Some(snapshot))
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/electrum.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/electrum.rs.html new file mode 100644 index 0000000000..e40065bc4e --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/electrum.rs.html @@ -0,0 +1,386 @@ +electrum.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Electrum
+//!
+//! This module defines a [`Blockchain`] struct that wraps an [`electrum_client::Client`]
+//! and implements the logic required to populate the wallet's [database](crate::database::Database) by
+//! querying the inner client.
+//!
+//! ## Example
+//!
+//! ```no_run
+//! # use bdk::blockchain::electrum::ElectrumBlockchain;
+//! let client = electrum_client::Client::new("ssl://electrum.blockstream.info:50002")?;
+//! let blockchain = ElectrumBlockchain::from(client);
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use std::collections::HashSet;
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+
+use bitcoin::{BlockHeader, Script, Transaction, Txid};
+
+use electrum_client::{Client, ConfigBuilder, ElectrumApi, Socks5Config};
+
+use self::utils::{ELSGetHistoryRes, ElectrumLikeSync};
+use super::*;
+use crate::database::BatchDatabase;
+use crate::error::Error;
+use crate::FeeRate;
+
+/// Wrapper over an Electrum Client that implements the required blockchain traits
+///
+/// ## Example
+/// See the [`blockchain::electrum`](crate::blockchain::electrum) module for a usage example.
+pub struct ElectrumBlockchain(Client);
+
+#[cfg(test)]
+#[cfg(feature = "test-electrum")]
+#[bdk_blockchain_tests(crate)]
+fn local_electrs() -> ElectrumBlockchain {
+    ElectrumBlockchain::from(Client::new(&testutils::get_electrum_url()).unwrap())
+}
+
+impl std::convert::From<Client> for ElectrumBlockchain {
+    fn from(client: Client) -> Self {
+        ElectrumBlockchain(client)
+    }
+}
+
+impl Blockchain for ElectrumBlockchain {
+    fn get_capabilities(&self) -> HashSet<Capability> {
+        vec![
+            Capability::FullHistory,
+            Capability::GetAnyTx,
+            Capability::AccurateFees,
+        ]
+        .into_iter()
+        .collect()
+    }
+
+    fn setup<D: BatchDatabase, P: Progress>(
+        &self,
+        stop_gap: Option<usize>,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        self.0
+            .electrum_like_setup(stop_gap, database, progress_update)
+    }
+
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.0.transaction_get(txid).map(Option::Some)?)
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        Ok(self.0.transaction_broadcast(tx).map(|_| ())?)
+    }
+
+    fn get_height(&self) -> Result<u32, Error> {
+        // TODO: unsubscribe when added to the client, or is there a better call to use here?
+
+        Ok(self
+            .0
+            .block_headers_subscribe()
+            .map(|data| data.height as u32)?)
+    }
+
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        Ok(FeeRate::from_btc_per_kvb(
+            self.0.estimate_fee(target)? as f32
+        ))
+    }
+}
+
+impl ElectrumLikeSync for Client {
+    fn els_batch_script_get_history<'s, I: IntoIterator<Item = &'s Script> + Clone>(
+        &self,
+        scripts: I,
+    ) -> Result<Vec<Vec<ELSGetHistoryRes>>, Error> {
+        self.batch_script_get_history(scripts)
+            .map(|v| {
+                v.into_iter()
+                    .map(|v| {
+                        v.into_iter()
+                            .map(
+                                |electrum_client::GetHistoryRes {
+                                     height, tx_hash, ..
+                                 }| ELSGetHistoryRes {
+                                    height,
+                                    tx_hash,
+                                },
+                            )
+                            .collect()
+                    })
+                    .collect()
+            })
+            .map_err(Error::Electrum)
+    }
+
+    fn els_batch_transaction_get<'s, I: IntoIterator<Item = &'s Txid> + Clone>(
+        &self,
+        txids: I,
+    ) -> Result<Vec<Transaction>, Error> {
+        self.batch_transaction_get(txids).map_err(Error::Electrum)
+    }
+
+    fn els_batch_block_header<I: IntoIterator<Item = u32> + Clone>(
+        &self,
+        heights: I,
+    ) -> Result<Vec<BlockHeader>, Error> {
+        self.batch_block_header(heights).map_err(Error::Electrum)
+    }
+}
+
+/// Configuration for an [`ElectrumBlockchain`]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct ElectrumBlockchainConfig {
+    /// URL of the Electrum server (such as ElectrumX, Esplora, BWT) may start with `ssl://` or `tcp://` and include a port
+    ///
+    /// eg. `ssl://electrum.blockstream.info:60002`
+    pub url: String,
+    /// URL of the socks5 proxy server or a Tor service
+    pub socks5: Option<String>,
+    /// Request retry count
+    pub retry: u8,
+    /// Request timeout (seconds)
+    pub timeout: u8,
+}
+
+impl ConfigurableBlockchain for ElectrumBlockchain {
+    type Config = ElectrumBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        let socks5 = config.socks5.as_ref().map(Socks5Config::new);
+        let electrum_config = ConfigBuilder::new()
+            .retry(config.retry)
+            .socks5(socks5)?
+            .timeout(config.timeout)?
+            .build();
+
+        Ok(ElectrumBlockchain(Client::from_config(
+            config.url.as_str(),
+            electrum_config,
+        )?))
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/esplora.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/esplora.rs.html new file mode 100644 index 0000000000..df6abccb0d --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/esplora.rs.html @@ -0,0 +1,864 @@ +esplora.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Esplora
+//!
+//! This module defines a [`Blockchain`] struct that can query an Esplora backend
+//! populate the wallet's [database](crate::database::Database) by
+//!
+//! ## Example
+//!
+//! ```no_run
+//! # use bdk::blockchain::esplora::EsploraBlockchain;
+//! let blockchain = EsploraBlockchain::new("https://blockstream.info/testnet/api", None);
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use std::collections::{HashMap, HashSet};
+use std::fmt;
+
+use futures::stream::{self, FuturesOrdered, StreamExt, TryStreamExt};
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+
+use serde::Deserialize;
+
+use reqwest::{Client, StatusCode};
+
+use bitcoin::consensus::{self, deserialize, serialize};
+use bitcoin::hashes::hex::{FromHex, ToHex};
+use bitcoin::hashes::{sha256, Hash};
+use bitcoin::{BlockHash, BlockHeader, Script, Transaction, Txid};
+
+use self::utils::{ELSGetHistoryRes, ElectrumLikeSync};
+use super::*;
+use crate::database::BatchDatabase;
+use crate::error::Error;
+use crate::wallet::utils::ChunksIterator;
+use crate::FeeRate;
+
+const DEFAULT_CONCURRENT_REQUESTS: u8 = 4;
+
+#[derive(Debug)]
+struct UrlClient {
+    url: String,
+    // We use the async client instead of the blocking one because it automatically uses `fetch`
+    // when the target platform is wasm32.
+    client: Client,
+    concurrency: u8,
+}
+
+/// Structure that implements the logic to sync with Esplora
+///
+/// ## Example
+/// See the [`blockchain::esplora`](crate::blockchain::esplora) module for a usage example.
+#[derive(Debug)]
+pub struct EsploraBlockchain(UrlClient);
+
+impl std::convert::From<UrlClient> for EsploraBlockchain {
+    fn from(url_client: UrlClient) -> Self {
+        EsploraBlockchain(url_client)
+    }
+}
+
+impl EsploraBlockchain {
+    /// Create a new instance of the client from a base URL
+    pub fn new(base_url: &str, concurrency: Option<u8>) -> Self {
+        EsploraBlockchain(UrlClient {
+            url: base_url.to_string(),
+            client: Client::new(),
+            concurrency: concurrency.unwrap_or(DEFAULT_CONCURRENT_REQUESTS),
+        })
+    }
+}
+
+#[maybe_async]
+impl Blockchain for EsploraBlockchain {
+    fn get_capabilities(&self) -> HashSet<Capability> {
+        vec![
+            Capability::FullHistory,
+            Capability::GetAnyTx,
+            Capability::AccurateFees,
+        ]
+        .into_iter()
+        .collect()
+    }
+
+    fn setup<D: BatchDatabase, P: Progress>(
+        &self,
+        stop_gap: Option<usize>,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(self
+            .0
+            .electrum_like_setup(stop_gap, database, progress_update))
+    }
+
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(await_or_block!(self.0._get_tx(txid))?)
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        Ok(await_or_block!(self.0._broadcast(tx))?)
+    }
+
+    fn get_height(&self) -> Result<u32, Error> {
+        Ok(await_or_block!(self.0._get_height())?)
+    }
+
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        let estimates = await_or_block!(self.0._get_fee_estimates())?;
+
+        let fee_val = estimates
+            .into_iter()
+            .map(|(k, v)| Ok::<_, std::num::ParseIntError>((k.parse::<usize>()?, v)))
+            .collect::<Result<Vec<_>, _>>()
+            .map_err(|e| Error::Generic(e.to_string()))?
+            .into_iter()
+            .take_while(|(k, _)| k <= &target)
+            .map(|(_, v)| v)
+            .last()
+            .unwrap_or(1.0);
+
+        Ok(FeeRate::from_sat_per_vb(fee_val as f32))
+    }
+}
+
+impl UrlClient {
+    fn script_to_scripthash(script: &Script) -> String {
+        sha256::Hash::hash(script.as_bytes()).into_inner().to_hex()
+    }
+
+    async fn _get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, EsploraError> {
+        let resp = self
+            .client
+            .get(&format!("{}/tx/{}/raw", self.url, txid))
+            .send()
+            .await?;
+
+        if let StatusCode::NOT_FOUND = resp.status() {
+            return Ok(None);
+        }
+
+        Ok(Some(deserialize(&resp.error_for_status()?.bytes().await?)?))
+    }
+
+    async fn _get_tx_no_opt(&self, txid: &Txid) -> Result<Transaction, EsploraError> {
+        match self._get_tx(txid).await {
+            Ok(Some(tx)) => Ok(tx),
+            Ok(None) => Err(EsploraError::TransactionNotFound(*txid)),
+            Err(e) => Err(e),
+        }
+    }
+
+    async fn _get_header(&self, block_height: u32) -> Result<BlockHeader, EsploraError> {
+        let resp = self
+            .client
+            .get(&format!("{}/block-height/{}", self.url, block_height))
+            .send()
+            .await?;
+
+        if let StatusCode::NOT_FOUND = resp.status() {
+            return Err(EsploraError::HeaderHeightNotFound(block_height));
+        }
+        let bytes = resp.bytes().await?;
+        let hash = std::str::from_utf8(&bytes)
+            .map_err(|_| EsploraError::HeaderHeightNotFound(block_height))?;
+
+        let resp = self
+            .client
+            .get(&format!("{}/block/{}/header", self.url, hash))
+            .send()
+            .await?;
+
+        let header = deserialize(&Vec::from_hex(&resp.text().await?)?)?;
+
+        Ok(header)
+    }
+
+    async fn _broadcast(&self, transaction: &Transaction) -> Result<(), EsploraError> {
+        self.client
+            .post(&format!("{}/tx", self.url))
+            .body(serialize(transaction).to_hex())
+            .send()
+            .await?
+            .error_for_status()?;
+
+        Ok(())
+    }
+
+    async fn _get_height(&self) -> Result<u32, EsploraError> {
+        let req = self
+            .client
+            .get(&format!("{}/blocks/tip/height", self.url))
+            .send()
+            .await?;
+
+        Ok(req.error_for_status()?.text().await?.parse()?)
+    }
+
+    async fn _script_get_history(
+        &self,
+        script: &Script,
+    ) -> Result<Vec<ELSGetHistoryRes>, EsploraError> {
+        let mut result = Vec::new();
+        let scripthash = Self::script_to_scripthash(script);
+
+        // Add the unconfirmed transactions first
+        result.extend(
+            self.client
+                .get(&format!(
+                    "{}/scripthash/{}/txs/mempool",
+                    self.url, scripthash
+                ))
+                .send()
+                .await?
+                .error_for_status()?
+                .json::<Vec<EsploraGetHistory>>()
+                .await?
+                .into_iter()
+                .map(|x| ELSGetHistoryRes {
+                    tx_hash: x.txid,
+                    height: x.status.block_height.unwrap_or(0) as i32,
+                }),
+        );
+
+        debug!(
+            "Found {} mempool txs for {} - {:?}",
+            result.len(),
+            scripthash,
+            script
+        );
+
+        // Then go through all the pages of confirmed transactions
+        let mut last_txid = String::new();
+        loop {
+            let response = self
+                .client
+                .get(&format!(
+                    "{}/scripthash/{}/txs/chain/{}",
+                    self.url, scripthash, last_txid
+                ))
+                .send()
+                .await?
+                .error_for_status()?
+                .json::<Vec<EsploraGetHistory>>()
+                .await?;
+            let len = response.len();
+            if let Some(elem) = response.last() {
+                last_txid = elem.txid.to_hex();
+            }
+
+            debug!("... adding {} confirmed transactions", len);
+
+            result.extend(response.into_iter().map(|x| ELSGetHistoryRes {
+                tx_hash: x.txid,
+                height: x.status.block_height.unwrap_or(0) as i32,
+            }));
+
+            if len < 25 {
+                break;
+            }
+        }
+
+        Ok(result)
+    }
+
+    async fn _get_fee_estimates(&self) -> Result<HashMap<String, f64>, EsploraError> {
+        Ok(self
+            .client
+            .get(&format!("{}/fee-estimates", self.url,))
+            .send()
+            .await?
+            .error_for_status()?
+            .json::<HashMap<String, f64>>()
+            .await?)
+    }
+}
+
+#[maybe_async]
+impl ElectrumLikeSync for UrlClient {
+    fn els_batch_script_get_history<'s, I: IntoIterator<Item = &'s Script>>(
+        &self,
+        scripts: I,
+    ) -> Result<Vec<Vec<ELSGetHistoryRes>>, Error> {
+        let future = async {
+            let mut results = vec![];
+            for chunk in ChunksIterator::new(scripts.into_iter(), self.concurrency as usize) {
+                let mut futs = FuturesOrdered::new();
+                for script in chunk {
+                    futs.push(self._script_get_history(&script));
+                }
+                let partial_results: Vec<Vec<ELSGetHistoryRes>> = futs.try_collect().await?;
+                results.extend(partial_results);
+            }
+            Ok(stream::iter(results).collect().await)
+        };
+
+        await_or_block!(future)
+    }
+
+    fn els_batch_transaction_get<'s, I: IntoIterator<Item = &'s Txid>>(
+        &self,
+        txids: I,
+    ) -> Result<Vec<Transaction>, Error> {
+        let future = async {
+            let mut results = vec![];
+            for chunk in ChunksIterator::new(txids.into_iter(), self.concurrency as usize) {
+                let mut futs = FuturesOrdered::new();
+                for txid in chunk {
+                    futs.push(self._get_tx_no_opt(&txid));
+                }
+                let partial_results: Vec<Transaction> = futs.try_collect().await?;
+                results.extend(partial_results);
+            }
+            Ok(stream::iter(results).collect().await)
+        };
+
+        await_or_block!(future)
+    }
+
+    fn els_batch_block_header<I: IntoIterator<Item = u32>>(
+        &self,
+        heights: I,
+    ) -> Result<Vec<BlockHeader>, Error> {
+        let future = async {
+            let mut results = vec![];
+            for chunk in ChunksIterator::new(heights.into_iter(), self.concurrency as usize) {
+                let mut futs = FuturesOrdered::new();
+                for height in chunk {
+                    futs.push(self._get_header(height));
+                }
+                let partial_results: Vec<BlockHeader> = futs.try_collect().await?;
+                results.extend(partial_results);
+            }
+            Ok(stream::iter(results).collect().await)
+        };
+
+        await_or_block!(future)
+    }
+}
+
+#[derive(Deserialize)]
+struct EsploraGetHistoryStatus {
+    block_height: Option<usize>,
+}
+
+#[derive(Deserialize)]
+struct EsploraGetHistory {
+    txid: Txid,
+    status: EsploraGetHistoryStatus,
+}
+
+/// Configuration for an [`EsploraBlockchain`]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct EsploraBlockchainConfig {
+    /// Base URL of the esplora service
+    ///
+    /// eg. `https://blockstream.info/api/`
+    pub base_url: String,
+    /// Number of parallel requests sent to the esplora service (default: 4)
+    pub concurrency: Option<u8>,
+}
+
+impl ConfigurableBlockchain for EsploraBlockchain {
+    type Config = EsploraBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        Ok(EsploraBlockchain::new(
+            config.base_url.as_str(),
+            config.concurrency,
+        ))
+    }
+}
+
+/// Errors that can happen during a sync with [`EsploraBlockchain`]
+#[derive(Debug)]
+pub enum EsploraError {
+    /// Error with the HTTP call
+    Reqwest(reqwest::Error),
+    /// Invalid number returned
+    Parsing(std::num::ParseIntError),
+    /// Invalid Bitcoin data returned
+    BitcoinEncoding(bitcoin::consensus::encode::Error),
+    /// Invalid Hex data returned
+    Hex(bitcoin::hashes::hex::Error),
+
+    /// Transaction not found
+    TransactionNotFound(Txid),
+    /// Header height not found
+    HeaderHeightNotFound(u32),
+    /// Header hash not found
+    HeaderHashNotFound(BlockHash),
+}
+
+impl fmt::Display for EsploraError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl std::error::Error for EsploraError {}
+
+impl_error!(reqwest::Error, Reqwest, EsploraError);
+impl_error!(std::num::ParseIntError, Parsing, EsploraError);
+impl_error!(consensus::encode::Error, BitcoinEncoding, EsploraError);
+impl_error!(bitcoin::hashes::hex::Error, Hex, EsploraError);
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/mod.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/mod.rs.html new file mode 100644 index 0000000000..75931fe4bf --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/mod.rs.html @@ -0,0 +1,554 @@ +mod.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Blockchain backends
+//!
+//! This module provides the implementation of a few commonly-used backends like
+//! [Electrum](crate::blockchain::electrum), [Esplora](crate::blockchain::esplora) and
+//! [Compact Filters/Neutrino](crate::blockchain::compact_filters), along with a generalized trait
+//! [`Blockchain`] that can be implemented to build customized backends.
+
+use std::collections::HashSet;
+use std::ops::Deref;
+use std::sync::mpsc::{channel, Receiver, Sender};
+use std::sync::Arc;
+
+use bitcoin::{Transaction, Txid};
+
+use crate::database::BatchDatabase;
+use crate::error::Error;
+use crate::FeeRate;
+
+#[cfg(any(feature = "electrum", feature = "esplora"))]
+pub(crate) mod utils;
+
+#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))]
+pub mod any;
+#[cfg(any(feature = "electrum", feature = "esplora", feature = "compact_filters"))]
+pub use any::{AnyBlockchain, AnyBlockchainConfig};
+
+#[cfg(feature = "electrum")]
+#[cfg_attr(docsrs, doc(cfg(feature = "electrum")))]
+pub mod electrum;
+#[cfg(feature = "electrum")]
+pub use self::electrum::ElectrumBlockchain;
+#[cfg(feature = "electrum")]
+pub use self::electrum::ElectrumBlockchainConfig;
+
+#[cfg(feature = "esplora")]
+#[cfg_attr(docsrs, doc(cfg(feature = "esplora")))]
+pub mod esplora;
+#[cfg(feature = "esplora")]
+pub use self::esplora::EsploraBlockchain;
+
+#[cfg(feature = "compact_filters")]
+#[cfg_attr(docsrs, doc(cfg(feature = "compact_filters")))]
+pub mod compact_filters;
+#[cfg(feature = "compact_filters")]
+pub use self::compact_filters::CompactFiltersBlockchain;
+
+/// Capabilities that can be supported by a [`Blockchain`] backend
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Capability {
+    /// Can recover the full history of a wallet and not only the set of currently spendable UTXOs
+    FullHistory,
+    /// Can fetch any historical transaction given its txid
+    GetAnyTx,
+    /// Can compute accurate fees for the transactions found during sync
+    AccurateFees,
+}
+
+/// Marker trait for a blockchain backend
+///
+/// This is a marker trait for blockchain types. It is automatically implemented for types that
+/// implement [`Blockchain`], so as a user of the library you won't have to implement this
+/// manually.
+///
+/// Users of the library will probably never have to implement this trait manually, but they
+/// could still need to import it to define types and structs with generics;
+/// Implementing only the marker trait is pointless, since [`OfflineBlockchain`]
+/// already does that, and whenever [`Blockchain`] is implemented, the marker trait is also
+/// automatically implemented by the library.
+pub trait BlockchainMarker {}
+
+/// The [`BlockchainMarker`] marker trait is automatically implemented for [`Blockchain`] types
+impl<T: Blockchain> BlockchainMarker for T {}
+
+/// Type that only implements [`BlockchainMarker`] and is always "offline"
+pub struct OfflineBlockchain;
+impl BlockchainMarker for OfflineBlockchain {}
+
+/// Trait that defines the actions that must be supported by a blockchain backend
+#[maybe_async]
+pub trait Blockchain: BlockchainMarker {
+    /// Return the set of [`Capability`] supported by this backend
+    fn get_capabilities(&self) -> HashSet<Capability>;
+
+    /// Setup the backend and populate the internal database for the first time
+    ///
+    /// This method is the equivalent of [`Blockchain::sync`], but it's guaranteed to only be
+    /// called once, at the first [`Wallet::sync`](crate::wallet::Wallet::sync).
+    ///
+    /// The rationale behind the distinction between `sync` and `setup` is that some custom backends
+    /// might need to perform specific actions only the first time they are synced.
+    ///
+    /// For types that do not have that distinction, only this method can be implemented, since
+    /// [`Blockchain::sync`] defaults to calling this internally if not overridden.
+    fn setup<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        stop_gap: Option<usize>,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error>;
+    /// Populate the internal database with transactions and UTXOs
+    ///
+    /// If not overridden, it defaults to calling [`Blockchain::setup`] internally.
+    ///
+    /// This method should implement the logic required to iterate over the list of the wallet's
+    /// script_pubkeys using [`Database::iter_script_pubkeys`] and look for relevant transactions
+    /// in the blockchain to populate the database with [`BatchOperations::set_tx`] and
+    /// [`BatchOperations::set_utxo`].
+    ///
+    /// This method should also take care of removing UTXOs that are seen as spent in the
+    /// blockchain, using [`BatchOperations::del_utxo`].
+    ///
+    /// The `progress_update` object can be used to give the caller updates about the progress by using
+    /// [`Progress::update`].
+    ///
+    /// [`Database::iter_script_pubkeys`]: crate::database::Database::iter_script_pubkeys
+    /// [`BatchOperations::set_tx`]: crate::database::BatchOperations::set_tx
+    /// [`BatchOperations::set_utxo`]: crate::database::BatchOperations::set_utxo
+    /// [`BatchOperations::del_utxo`]: crate::database::BatchOperations::del_utxo
+    fn sync<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        stop_gap: Option<usize>,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(self.setup(stop_gap, database, progress_update))
+    }
+
+    /// Fetch a transaction from the blockchain given its txid
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>;
+    /// Broadcast a transaction
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error>;
+
+    /// Return the current height
+    fn get_height(&self) -> Result<u32, Error>;
+    /// Estimate the fee rate required to confirm a transaction in a given `target` of blocks
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error>;
+}
+
+/// Trait for [`Blockchain`] types that can be created given a configuration
+pub trait ConfigurableBlockchain: Blockchain + Sized {
+    /// Type that contains the configuration
+    type Config: std::fmt::Debug;
+
+    /// Create a new instance given a configuration
+    fn from_config(config: &Self::Config) -> Result<Self, Error>;
+}
+
+/// Data sent with a progress update over a [`channel`]
+pub type ProgressData = (f32, Option<String>);
+
+/// Trait for types that can receive and process progress updates during [`Blockchain::sync`] and
+/// [`Blockchain::setup`]
+pub trait Progress: Send {
+    /// Send a new progress update
+    ///
+    /// The `progress` value should be in the range 0.0 - 100.0, and the `message` value is an
+    /// optional text message that can be displayed to the user.
+    fn update(&self, progress: f32, message: Option<String>) -> Result<(), Error>;
+}
+
+/// Shortcut to create a [`channel`] (pair of [`Sender`] and [`Receiver`]) that can transport [`ProgressData`]
+pub fn progress() -> (Sender<ProgressData>, Receiver<ProgressData>) {
+    channel()
+}
+
+impl Progress for Sender<ProgressData> {
+    fn update(&self, progress: f32, message: Option<String>) -> Result<(), Error> {
+        if progress < 0.0 || progress > 100.0 {
+            return Err(Error::InvalidProgressValue(progress));
+        }
+
+        self.send((progress, message))
+            .map_err(|_| Error::ProgressUpdateError)
+    }
+}
+
+/// Type that implements [`Progress`] and drops every update received
+#[derive(Clone)]
+pub struct NoopProgress;
+
+/// Create a new instance of [`NoopProgress`]
+pub fn noop_progress() -> NoopProgress {
+    NoopProgress
+}
+
+impl Progress for NoopProgress {
+    fn update(&self, _progress: f32, _message: Option<String>) -> Result<(), Error> {
+        Ok(())
+    }
+}
+
+/// Type that implements [`Progress`] and logs at level `INFO` every update received
+#[derive(Clone)]
+pub struct LogProgress;
+
+/// Create a nwe instance of [`LogProgress`]
+pub fn log_progress() -> LogProgress {
+    LogProgress
+}
+
+impl Progress for LogProgress {
+    fn update(&self, progress: f32, message: Option<String>) -> Result<(), Error> {
+        log::info!(
+            "Sync {:.3}%: `{}`",
+            progress,
+            message.unwrap_or_else(|| "".into())
+        );
+
+        Ok(())
+    }
+}
+
+#[maybe_async]
+impl<T: Blockchain> Blockchain for Arc<T> {
+    fn get_capabilities(&self) -> HashSet<Capability> {
+        maybe_await!(self.deref().get_capabilities())
+    }
+
+    fn setup<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        stop_gap: Option<usize>,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(self.deref().setup(stop_gap, database, progress_update))
+    }
+
+    fn sync<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        stop_gap: Option<usize>,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(self.deref().sync(stop_gap, database, progress_update))
+    }
+
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        maybe_await!(self.deref().get_tx(txid))
+    }
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        maybe_await!(self.deref().broadcast(tx))
+    }
+
+    fn get_height(&self) -> Result<u32, Error> {
+        maybe_await!(self.deref().get_height())
+    }
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        maybe_await!(self.deref().estimate_fee(target))
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/utils.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/utils.rs.html new file mode 100644 index 0000000000..8cbfbf4840 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/blockchain/utils.rs.html @@ -0,0 +1,800 @@ +utils.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+use std::collections::{HashMap, HashSet};
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+use rand::seq::SliceRandom;
+use rand::thread_rng;
+
+use bitcoin::{BlockHeader, OutPoint, Script, Transaction, Txid};
+
+use super::*;
+use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
+use crate::error::Error;
+use crate::types::{KeychainKind, TransactionDetails, UTXO};
+use crate::wallet::time::Instant;
+use crate::wallet::utils::ChunksIterator;
+
+#[derive(Debug)]
+pub struct ELSGetHistoryRes {
+    pub height: i32,
+    pub tx_hash: Txid,
+}
+
+/// Implements the synchronization logic for an Electrum-like client.
+#[maybe_async]
+pub trait ElectrumLikeSync {
+    fn els_batch_script_get_history<'s, I: IntoIterator<Item = &'s Script> + Clone>(
+        &self,
+        scripts: I,
+    ) -> Result<Vec<Vec<ELSGetHistoryRes>>, Error>;
+
+    fn els_batch_transaction_get<'s, I: IntoIterator<Item = &'s Txid> + Clone>(
+        &self,
+        txids: I,
+    ) -> Result<Vec<Transaction>, Error>;
+
+    fn els_batch_block_header<I: IntoIterator<Item = u32> + Clone>(
+        &self,
+        heights: I,
+    ) -> Result<Vec<BlockHeader>, Error>;
+
+    // Provided methods down here...
+
+    fn electrum_like_setup<D: BatchDatabase, P: Progress>(
+        &self,
+        stop_gap: Option<usize>,
+        db: &mut D,
+        _progress_update: P,
+    ) -> Result<(), Error> {
+        // TODO: progress
+        let start = Instant::new();
+        debug!("start setup");
+
+        let stop_gap = stop_gap.unwrap_or(20);
+        let chunk_size = stop_gap;
+
+        let mut history_txs_id = HashSet::new();
+        let mut txid_height = HashMap::new();
+        let mut max_indexes = HashMap::new();
+
+        let mut wallet_chains = vec![KeychainKind::Internal, KeychainKind::External];
+        // shuffling improve privacy, the server doesn't know my first request is from my internal or external addresses
+        wallet_chains.shuffle(&mut thread_rng());
+        // download history of our internal and external script_pubkeys
+        for keychain in wallet_chains.iter() {
+            let script_iter = db.iter_script_pubkeys(Some(*keychain))?.into_iter();
+
+            for (i, chunk) in ChunksIterator::new(script_iter, stop_gap).enumerate() {
+                // TODO if i == last, should create another chunk of addresses in db
+                let call_result: Vec<Vec<ELSGetHistoryRes>> =
+                    maybe_await!(self.els_batch_script_get_history(chunk.iter()))?;
+                let max_index = call_result
+                    .iter()
+                    .enumerate()
+                    .filter_map(|(i, v)| v.first().map(|_| i as u32))
+                    .max();
+                if let Some(max) = max_index {
+                    max_indexes.insert(keychain, max + (i * chunk_size) as u32);
+                }
+                let flattened: Vec<ELSGetHistoryRes> = call_result.into_iter().flatten().collect();
+                debug!("#{} of {:?} results:{}", i, keychain, flattened.len());
+                if flattened.is_empty() {
+                    // Didn't find anything in the last `stop_gap` script_pubkeys, breaking
+                    break;
+                }
+
+                for el in flattened {
+                    // el.height = -1 means unconfirmed with unconfirmed parents
+                    // el.height =  0 means unconfirmed with confirmed parents
+                    // but we treat those tx the same
+                    if el.height <= 0 {
+                        txid_height.insert(el.tx_hash, None);
+                    } else {
+                        txid_height.insert(el.tx_hash, Some(el.height as u32));
+                    }
+                    history_txs_id.insert(el.tx_hash);
+                }
+            }
+        }
+
+        // saving max indexes
+        info!("max indexes are: {:?}", max_indexes);
+        for keychain in wallet_chains.iter() {
+            if let Some(index) = max_indexes.get(keychain) {
+                db.set_last_index(*keychain, *index)?;
+            }
+        }
+
+        // get db status
+        let txs_details_in_db: HashMap<Txid, TransactionDetails> = db
+            .iter_txs(false)?
+            .into_iter()
+            .map(|tx| (tx.txid, tx))
+            .collect();
+        let txs_raw_in_db: HashMap<Txid, Transaction> = db
+            .iter_raw_txs()?
+            .into_iter()
+            .map(|tx| (tx.txid(), tx))
+            .collect();
+        let utxos_deps = utxos_deps(db, &txs_raw_in_db)?;
+
+        // download new txs and headers
+        let new_txs = maybe_await!(self.download_and_save_needed_raw_txs(
+            &history_txs_id,
+            &txs_raw_in_db,
+            chunk_size,
+            db
+        ))?;
+        let new_timestamps = maybe_await!(self.download_needed_headers(
+            &txid_height,
+            &txs_details_in_db,
+            chunk_size
+        ))?;
+
+        let mut batch = db.begin_batch();
+
+        // save any tx details not in db but in history_txs_id or with different height/timestamp
+        for txid in history_txs_id.iter() {
+            let height = txid_height.get(txid).cloned().flatten();
+            let timestamp = *new_timestamps.get(txid).unwrap_or(&0u64);
+            if let Some(tx_details) = txs_details_in_db.get(txid) {
+                // check if height matches, otherwise updates it
+                if tx_details.height != height {
+                    let mut new_tx_details = tx_details.clone();
+                    new_tx_details.height = height;
+                    new_tx_details.timestamp = timestamp;
+                    batch.set_tx(&new_tx_details)?;
+                }
+            } else {
+                save_transaction_details_and_utxos(
+                    &txid,
+                    db,
+                    timestamp,
+                    height,
+                    &mut batch,
+                    &utxos_deps,
+                )?;
+            }
+        }
+
+        // remove any tx details in db but not in history_txs_id
+        for txid in txs_details_in_db.keys() {
+            if !history_txs_id.contains(txid) {
+                batch.del_tx(&txid, false)?;
+            }
+        }
+
+        // remove any spent utxo
+        for new_tx in new_txs.iter() {
+            for input in new_tx.input.iter() {
+                batch.del_utxo(&input.previous_output)?;
+            }
+        }
+
+        db.commit_batch(batch)?;
+        info!("finish setup, elapsed {:?}ms", start.elapsed().as_millis());
+
+        Ok(())
+    }
+
+    /// download txs identified by `history_txs_id` and theirs previous outputs if not already present in db
+    fn download_and_save_needed_raw_txs<D: BatchDatabase>(
+        &self,
+        history_txs_id: &HashSet<Txid>,
+        txs_raw_in_db: &HashMap<Txid, Transaction>,
+        chunk_size: usize,
+        db: &mut D,
+    ) -> Result<Vec<Transaction>, Error> {
+        let mut txs_downloaded = vec![];
+        let txids_raw_in_db: HashSet<Txid> = txs_raw_in_db.keys().cloned().collect();
+        let txids_to_download: Vec<&Txid> = history_txs_id.difference(&txids_raw_in_db).collect();
+        if !txids_to_download.is_empty() {
+            info!("got {} txs to download", txids_to_download.len());
+            txs_downloaded.extend(maybe_await!(self.download_and_save_in_chunks(
+                txids_to_download,
+                chunk_size,
+                db,
+            ))?);
+            let mut prev_txids = HashSet::new();
+            let mut txids_downloaded = HashSet::new();
+            for tx in txs_downloaded.iter() {
+                txids_downloaded.insert(tx.txid());
+                // add every previous input tx, but skip coinbase
+                for input in tx.input.iter().filter(|i| !i.previous_output.is_null()) {
+                    prev_txids.insert(input.previous_output.txid);
+                }
+            }
+            let already_present: HashSet<Txid> =
+                txids_downloaded.union(&txids_raw_in_db).cloned().collect();
+            let prev_txs_to_download: Vec<&Txid> =
+                prev_txids.difference(&already_present).collect();
+            info!("{} previous txs to download", prev_txs_to_download.len());
+            txs_downloaded.extend(maybe_await!(self.download_and_save_in_chunks(
+                prev_txs_to_download,
+                chunk_size,
+                db,
+            ))?);
+        }
+
+        Ok(txs_downloaded)
+    }
+
+    /// download headers at heights in `txid_height` if tx details not already present, returns a map Txid -> timestamp
+    fn download_needed_headers(
+        &self,
+        txid_height: &HashMap<Txid, Option<u32>>,
+        txs_details_in_db: &HashMap<Txid, TransactionDetails>,
+        chunk_size: usize,
+    ) -> Result<HashMap<Txid, u64>, Error> {
+        let mut txid_timestamp = HashMap::new();
+        let needed_txid_height: HashMap<&Txid, u32> = txid_height
+            .iter()
+            .filter(|(t, _)| txs_details_in_db.get(*t).is_none())
+            .filter_map(|(t, o)| o.map(|h| (t, h)))
+            .collect();
+        let needed_heights: HashSet<u32> = needed_txid_height.values().cloned().collect();
+        if !needed_heights.is_empty() {
+            info!("{} headers to download for timestamp", needed_heights.len());
+            let mut height_timestamp: HashMap<u32, u64> = HashMap::new();
+            for chunk in ChunksIterator::new(needed_heights.into_iter(), chunk_size) {
+                let call_result: Vec<BlockHeader> =
+                    maybe_await!(self.els_batch_block_header(chunk.clone()))?;
+                height_timestamp.extend(
+                    chunk
+                        .into_iter()
+                        .zip(call_result.iter().map(|h| h.time as u64)),
+                );
+            }
+            for (txid, height) in needed_txid_height {
+                let timestamp = height_timestamp
+                    .get(&height)
+                    .ok_or_else(|| Error::Generic("timestamp missing".to_string()))?;
+                txid_timestamp.insert(*txid, *timestamp);
+            }
+        }
+
+        Ok(txid_timestamp)
+    }
+
+    fn download_and_save_in_chunks<D: BatchDatabase>(
+        &self,
+        to_download: Vec<&Txid>,
+        chunk_size: usize,
+        db: &mut D,
+    ) -> Result<Vec<Transaction>, Error> {
+        let mut txs_downloaded = vec![];
+        for chunk in ChunksIterator::new(to_download.into_iter(), chunk_size) {
+            let call_result: Vec<Transaction> =
+                maybe_await!(self.els_batch_transaction_get(chunk))?;
+            let mut batch = db.begin_batch();
+            for new_tx in call_result.iter() {
+                batch.set_raw_tx(new_tx)?;
+            }
+            db.commit_batch(batch)?;
+            txs_downloaded.extend(call_result);
+        }
+
+        Ok(txs_downloaded)
+    }
+}
+
+fn save_transaction_details_and_utxos<D: BatchDatabase>(
+    txid: &Txid,
+    db: &mut D,
+    timestamp: u64,
+    height: Option<u32>,
+    updates: &mut dyn BatchOperations,
+    utxo_deps: &HashMap<OutPoint, OutPoint>,
+) -> Result<(), Error> {
+    let tx = db.get_raw_tx(txid)?.ok_or(Error::TransactionNotFound)?;
+
+    let mut incoming: u64 = 0;
+    let mut outgoing: u64 = 0;
+
+    let mut inputs_sum: u64 = 0;
+    let mut outputs_sum: u64 = 0;
+
+    // look for our own inputs
+    for input in tx.input.iter() {
+        // skip coinbase inputs
+        if input.previous_output.is_null() {
+            continue;
+        }
+
+        // We already downloaded all previous output txs in the previous step
+        if let Some(previous_output) = db.get_previous_output(&input.previous_output)? {
+            inputs_sum += previous_output.value;
+
+            if db.is_mine(&previous_output.script_pubkey)? {
+                outgoing += previous_output.value;
+            }
+        } else {
+            // The input is not ours, but we still need to count it for the fees
+            let tx = db
+                .get_raw_tx(&input.previous_output.txid)?
+                .ok_or(Error::TransactionNotFound)?;
+            inputs_sum += tx.output[input.previous_output.vout as usize].value;
+        }
+
+        // removes conflicting UTXO if any (generated from same inputs, like for example RBF)
+        if let Some(outpoint) = utxo_deps.get(&input.previous_output) {
+            updates.del_utxo(&outpoint)?;
+        }
+    }
+
+    for (i, output) in tx.output.iter().enumerate() {
+        // to compute the fees later
+        outputs_sum += output.value;
+
+        // this output is ours, we have a path to derive it
+        if let Some((keychain, _child)) = db.get_path_from_script_pubkey(&output.script_pubkey)? {
+            debug!("{} output #{} is mine, adding utxo", txid, i);
+            updates.set_utxo(&UTXO {
+                outpoint: OutPoint::new(tx.txid(), i as u32),
+                txout: output.clone(),
+                keychain,
+            })?;
+
+            incoming += output.value;
+        }
+    }
+
+    let tx_details = TransactionDetails {
+        txid: tx.txid(),
+        transaction: Some(tx),
+        received: incoming,
+        sent: outgoing,
+        height,
+        timestamp,
+        fees: inputs_sum.saturating_sub(outputs_sum), /* if the tx is a coinbase, fees would be negative */
+    };
+    updates.set_tx(&tx_details)?;
+
+    Ok(())
+}
+
+/// returns utxo dependency as the inputs needed for the utxo to exist
+/// `tx_raw_in_db` must contains utxo's generating txs or errors witt [crate::Error::TransactionNotFound]
+fn utxos_deps<D: BatchDatabase>(
+    db: &mut D,
+    tx_raw_in_db: &HashMap<Txid, Transaction>,
+) -> Result<HashMap<OutPoint, OutPoint>, Error> {
+    let utxos = db.iter_utxos()?;
+    let mut utxos_deps = HashMap::new();
+    for utxo in utxos {
+        let from_tx = tx_raw_in_db
+            .get(&utxo.outpoint.txid)
+            .ok_or(Error::TransactionNotFound)?;
+        for input in from_tx.input.iter() {
+            utxos_deps.insert(input.previous_output, utxo.outpoint);
+        }
+    }
+    Ok(utxos_deps)
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/any.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/any.rs.html new file mode 100644 index 0000000000..55b9fbcc5f --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/any.rs.html @@ -0,0 +1,782 @@ +any.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Runtime-checked database types
+//!
+//! This module provides the implementation of [`AnyDatabase`] which allows switching the
+//! inner [`Database`] type at runtime.
+//!
+//! ## Example
+//!
+//! In this example, `wallet_memory` and `wallet_sled` have the same type of `Wallet<OfflineBlockchain, AnyDatabase>`.
+//!
+//! ```no_run
+//! # use bitcoin::Network;
+//! # use bdk::database::{AnyDatabase, MemoryDatabase};
+//! # use bdk::{Wallet, OfflineWallet};
+//! let memory = MemoryDatabase::default().into();
+//! let wallet_memory: OfflineWallet<AnyDatabase> =
+//!     Wallet::new_offline("...", None, Network::Testnet, memory)?;
+//!
+//! # #[cfg(feature = "key-value-db")]
+//! # {
+//! let sled = sled::open("my-database")?.open_tree("default_tree")?.into();
+//! let wallet_sled: OfflineWallet<AnyDatabase> =
+//!     Wallet::new_offline("...", None, Network::Testnet, sled)?;
+//! # }
+//! # Ok::<(), bdk::Error>(())
+//! ```
+//!
+//! When paired with the use of [`ConfigurableDatabase`], it allows creating wallets with any
+//! database supported using a single line of code:
+//!
+//! ```no_run
+//! # use bitcoin::Network;
+//! # use bdk::database::*;
+//! # use bdk::{Wallet, OfflineWallet};
+//! let config = serde_json::from_str("...")?;
+//! let database = AnyDatabase::from_config(&config)?;
+//! let wallet: OfflineWallet<_> = Wallet::new_offline("...", None, Network::Testnet, database)?;
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use super::*;
+
+macro_rules! impl_from {
+    ( $from:ty, $to:ty, $variant:ident, $( $cfg:tt )* ) => {
+        $( $cfg )*
+        impl From<$from> for $to {
+            fn from(inner: $from) -> Self {
+                <$to>::$variant(inner)
+            }
+        }
+    };
+}
+
+macro_rules! impl_inner_method {
+    ( $enum_name:ident, $self:expr, $name:ident $(, $args:expr)* ) => {
+        match $self {
+            $enum_name::Memory(inner) => inner.$name( $($args, )* ),
+            #[cfg(feature = "key-value-db")]
+            $enum_name::Sled(inner) => inner.$name( $($args, )* ),
+        }
+    }
+}
+
+/// Type that can contain any of the [`Database`] types defined by the library
+///
+/// It allows switching database type at runtime.
+///
+/// See [this module](crate::database::any)'s documentation for a usage example.
+#[derive(Debug)]
+pub enum AnyDatabase {
+    /// In-memory ephemeral database
+    Memory(memory::MemoryDatabase),
+    #[cfg(feature = "key-value-db")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "key-value-db")))]
+    /// Simple key-value embedded database based on [`sled`]
+    Sled(sled::Tree),
+}
+
+impl_from!(memory::MemoryDatabase, AnyDatabase, Memory,);
+impl_from!(sled::Tree, AnyDatabase, Sled, #[cfg(feature = "key-value-db")]);
+
+/// Type that contains any of the [`BatchDatabase::Batch`] types defined by the library
+pub enum AnyBatch {
+    /// In-memory ephemeral database
+    Memory(<memory::MemoryDatabase as BatchDatabase>::Batch),
+    #[cfg(feature = "key-value-db")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "key-value-db")))]
+    /// Simple key-value embedded database based on [`sled`]
+    Sled(<sled::Tree as BatchDatabase>::Batch),
+}
+
+impl_from!(
+    <memory::MemoryDatabase as BatchDatabase>::Batch,
+    AnyBatch,
+    Memory,
+);
+impl_from!(<sled::Tree as BatchDatabase>::Batch, AnyBatch, Sled, #[cfg(feature = "key-value-db")]);
+
+impl BatchOperations for AnyDatabase {
+    fn set_script_pubkey(
+        &mut self,
+        script: &Script,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<(), Error> {
+        impl_inner_method!(
+            AnyDatabase,
+            self,
+            set_script_pubkey,
+            script,
+            keychain,
+            child
+        )
+    }
+    fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error> {
+        impl_inner_method!(AnyDatabase, self, set_utxo, utxo)
+    }
+    fn set_raw_tx(&mut self, transaction: &Transaction) -> Result<(), Error> {
+        impl_inner_method!(AnyDatabase, self, set_raw_tx, transaction)
+    }
+    fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error> {
+        impl_inner_method!(AnyDatabase, self, set_tx, transaction)
+    }
+    fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> {
+        impl_inner_method!(AnyDatabase, self, set_last_index, keychain, value)
+    }
+
+    fn del_script_pubkey_from_path(
+        &mut self,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<Option<Script>, Error> {
+        impl_inner_method!(
+            AnyDatabase,
+            self,
+            del_script_pubkey_from_path,
+            keychain,
+            child
+        )
+    }
+    fn del_path_from_script_pubkey(
+        &mut self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error> {
+        impl_inner_method!(AnyDatabase, self, del_path_from_script_pubkey, script)
+    }
+    fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
+        impl_inner_method!(AnyDatabase, self, del_utxo, outpoint)
+    }
+    fn del_raw_tx(&mut self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        impl_inner_method!(AnyDatabase, self, del_raw_tx, txid)
+    }
+    fn del_tx(
+        &mut self,
+        txid: &Txid,
+        include_raw: bool,
+    ) -> Result<Option<TransactionDetails>, Error> {
+        impl_inner_method!(AnyDatabase, self, del_tx, txid, include_raw)
+    }
+    fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
+        impl_inner_method!(AnyDatabase, self, del_last_index, keychain)
+    }
+}
+
+impl Database for AnyDatabase {
+    fn check_descriptor_checksum<B: AsRef<[u8]>>(
+        &mut self,
+        keychain: KeychainKind,
+        bytes: B,
+    ) -> Result<(), Error> {
+        impl_inner_method!(
+            AnyDatabase,
+            self,
+            check_descriptor_checksum,
+            keychain,
+            bytes
+        )
+    }
+
+    fn iter_script_pubkeys(&self, keychain: Option<KeychainKind>) -> Result<Vec<Script>, Error> {
+        impl_inner_method!(AnyDatabase, self, iter_script_pubkeys, keychain)
+    }
+    fn iter_utxos(&self) -> Result<Vec<UTXO>, Error> {
+        impl_inner_method!(AnyDatabase, self, iter_utxos)
+    }
+    fn iter_raw_txs(&self) -> Result<Vec<Transaction>, Error> {
+        impl_inner_method!(AnyDatabase, self, iter_raw_txs)
+    }
+    fn iter_txs(&self, include_raw: bool) -> Result<Vec<TransactionDetails>, Error> {
+        impl_inner_method!(AnyDatabase, self, iter_txs, include_raw)
+    }
+
+    fn get_script_pubkey_from_path(
+        &self,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<Option<Script>, Error> {
+        impl_inner_method!(
+            AnyDatabase,
+            self,
+            get_script_pubkey_from_path,
+            keychain,
+            child
+        )
+    }
+    fn get_path_from_script_pubkey(
+        &self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error> {
+        impl_inner_method!(AnyDatabase, self, get_path_from_script_pubkey, script)
+    }
+    fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
+        impl_inner_method!(AnyDatabase, self, get_utxo, outpoint)
+    }
+    fn get_raw_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        impl_inner_method!(AnyDatabase, self, get_raw_tx, txid)
+    }
+    fn get_tx(&self, txid: &Txid, include_raw: bool) -> Result<Option<TransactionDetails>, Error> {
+        impl_inner_method!(AnyDatabase, self, get_tx, txid, include_raw)
+    }
+    fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
+        impl_inner_method!(AnyDatabase, self, get_last_index, keychain)
+    }
+
+    fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> {
+        impl_inner_method!(AnyDatabase, self, increment_last_index, keychain)
+    }
+}
+
+impl BatchOperations for AnyBatch {
+    fn set_script_pubkey(
+        &mut self,
+        script: &Script,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<(), Error> {
+        impl_inner_method!(AnyBatch, self, set_script_pubkey, script, keychain, child)
+    }
+    fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error> {
+        impl_inner_method!(AnyBatch, self, set_utxo, utxo)
+    }
+    fn set_raw_tx(&mut self, transaction: &Transaction) -> Result<(), Error> {
+        impl_inner_method!(AnyBatch, self, set_raw_tx, transaction)
+    }
+    fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error> {
+        impl_inner_method!(AnyBatch, self, set_tx, transaction)
+    }
+    fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> {
+        impl_inner_method!(AnyBatch, self, set_last_index, keychain, value)
+    }
+
+    fn del_script_pubkey_from_path(
+        &mut self,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<Option<Script>, Error> {
+        impl_inner_method!(AnyBatch, self, del_script_pubkey_from_path, keychain, child)
+    }
+    fn del_path_from_script_pubkey(
+        &mut self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error> {
+        impl_inner_method!(AnyBatch, self, del_path_from_script_pubkey, script)
+    }
+    fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
+        impl_inner_method!(AnyBatch, self, del_utxo, outpoint)
+    }
+    fn del_raw_tx(&mut self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        impl_inner_method!(AnyBatch, self, del_raw_tx, txid)
+    }
+    fn del_tx(
+        &mut self,
+        txid: &Txid,
+        include_raw: bool,
+    ) -> Result<Option<TransactionDetails>, Error> {
+        impl_inner_method!(AnyBatch, self, del_tx, txid, include_raw)
+    }
+    fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
+        impl_inner_method!(AnyBatch, self, del_last_index, keychain)
+    }
+}
+
+impl BatchDatabase for AnyDatabase {
+    type Batch = AnyBatch;
+
+    fn begin_batch(&self) -> Self::Batch {
+        match self {
+            AnyDatabase::Memory(inner) => inner.begin_batch().into(),
+            #[cfg(feature = "key-value-db")]
+            AnyDatabase::Sled(inner) => inner.begin_batch().into(),
+        }
+    }
+    fn commit_batch(&mut self, batch: Self::Batch) -> Result<(), Error> {
+        // TODO: refactor once `move_ref_pattern` is stable
+        #[allow(irrefutable_let_patterns)]
+        match self {
+            AnyDatabase::Memory(db) => {
+                if let AnyBatch::Memory(batch) = batch {
+                    db.commit_batch(batch)
+                } else {
+                    unimplemented!()
+                }
+            }
+            #[cfg(feature = "key-value-db")]
+            AnyDatabase::Sled(db) => {
+                if let AnyBatch::Sled(batch) = batch {
+                    db.commit_batch(batch)
+                } else {
+                    unimplemented!()
+                }
+            }
+        }
+    }
+}
+
+/// Configuration type for a [`sled::Tree`] database
+#[cfg(feature = "key-value-db")]
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
+pub struct SledDbConfiguration {
+    /// Main directory of the db
+    pub path: String,
+    /// Name of the database tree, a separated namespace for the data
+    pub tree_name: String,
+}
+
+#[cfg(feature = "key-value-db")]
+impl ConfigurableDatabase for sled::Tree {
+    type Config = SledDbConfiguration;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        Ok(sled::open(&config.path)?.open_tree(&config.tree_name)?)
+    }
+}
+
+/// Type that can contain any of the database configurations defined by the library
+///
+/// This allows storing a single configuration that can be loaded into an [`AnyDatabase`]
+/// instance. Wallets that plan to offer users the ability to switch blockchain backend at runtime
+/// will find this particularly useful.
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
+pub enum AnyDatabaseConfig {
+    /// Memory database has no config
+    Memory(()),
+    #[cfg(feature = "key-value-db")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "key-value-db")))]
+    /// Simple key-value embedded database based on [`sled`]
+    Sled(SledDbConfiguration),
+}
+
+impl ConfigurableDatabase for AnyDatabase {
+    type Config = AnyDatabaseConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        Ok(match config {
+            AnyDatabaseConfig::Memory(inner) => {
+                AnyDatabase::Memory(memory::MemoryDatabase::from_config(inner)?)
+            }
+            #[cfg(feature = "key-value-db")]
+            AnyDatabaseConfig::Sled(inner) => AnyDatabase::Sled(sled::Tree::from_config(inner)?),
+        })
+    }
+}
+
+impl_from!((), AnyDatabaseConfig, Memory,);
+impl_from!(SledDbConfiguration, AnyDatabaseConfig, Sled, #[cfg(feature = "key-value-db")]);
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/keyvalue.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/keyvalue.rs.html new file mode 100644 index 0000000000..200aeebca1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/keyvalue.rs.html @@ -0,0 +1,968 @@ +keyvalue.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+use std::convert::TryInto;
+
+use sled::{Batch, Tree};
+
+use bitcoin::consensus::encode::{deserialize, serialize};
+use bitcoin::hash_types::Txid;
+use bitcoin::{OutPoint, Script, Transaction};
+
+use crate::database::memory::MapKey;
+use crate::database::{BatchDatabase, BatchOperations, Database};
+use crate::error::Error;
+use crate::types::*;
+
+macro_rules! impl_batch_operations {
+    ( { $($after_insert:tt)* }, $process_delete:ident ) => {
+        fn set_script_pubkey(&mut self, script: &Script, keychain: KeychainKind, path: u32) -> Result<(), Error> {
+            let key = MapKey::Path((Some(keychain), Some(path))).as_map_key();
+            self.insert(key, serialize(script))$($after_insert)*;
+
+            let key = MapKey::Script(Some(script)).as_map_key();
+            let value = json!({
+                "t": keychain,
+                "p": path,
+            });
+            self.insert(key, serde_json::to_vec(&value)?)$($after_insert)*;
+
+            Ok(())
+        }
+
+        fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error> {
+            let key = MapKey::UTXO(Some(&utxo.outpoint)).as_map_key();
+            let value = json!({
+                "t": utxo.txout,
+                "i": utxo.keychain,
+            });
+            self.insert(key, serde_json::to_vec(&value)?)$($after_insert)*;
+
+            Ok(())
+        }
+
+        fn set_raw_tx(&mut self, transaction: &Transaction) -> Result<(), Error> {
+            let key = MapKey::RawTx(Some(&transaction.txid())).as_map_key();
+            let value = serialize(transaction);
+            self.insert(key, value)$($after_insert)*;
+
+            Ok(())
+        }
+
+        fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error> {
+            let key = MapKey::Transaction(Some(&transaction.txid)).as_map_key();
+
+            // remove the raw tx from the serialized version
+            let mut value = serde_json::to_value(transaction)?;
+            value["transaction"] = serde_json::Value::Null;
+            let value = serde_json::to_vec(&value)?;
+
+            self.insert(key, value)$($after_insert)*;
+
+            // insert the raw_tx if present
+            if let Some(ref tx) = transaction.transaction {
+                self.set_raw_tx(tx)?;
+            }
+
+            Ok(())
+        }
+
+        fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> {
+            let key = MapKey::LastIndex(keychain).as_map_key();
+            self.insert(key, &value.to_be_bytes())$($after_insert)*;
+
+            Ok(())
+        }
+
+        fn del_script_pubkey_from_path(&mut self, keychain: KeychainKind, path: u32) -> Result<Option<Script>, Error> {
+            let key = MapKey::Path((Some(keychain), Some(path))).as_map_key();
+            let res = self.remove(key);
+            let res = $process_delete!(res);
+
+            Ok(res.map_or(Ok(None), |x| Some(deserialize(&x)).transpose())?)
+        }
+
+        fn del_path_from_script_pubkey(&mut self, script: &Script) -> Result<Option<(KeychainKind, u32)>, Error> {
+            let key = MapKey::Script(Some(script)).as_map_key();
+            let res = self.remove(key);
+            let res = $process_delete!(res);
+
+            match res {
+                None => Ok(None),
+                Some(b) => {
+                    let mut val: serde_json::Value = serde_json::from_slice(&b)?;
+                    let st = serde_json::from_value(val["t"].take())?;
+                    let path = serde_json::from_value(val["p"].take())?;
+
+                    Ok(Some((st, path)))
+                }
+            }
+        }
+
+        fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
+            let key = MapKey::UTXO(Some(outpoint)).as_map_key();
+            let res = self.remove(key);
+            let res = $process_delete!(res);
+
+            match res {
+                None => Ok(None),
+                Some(b) => {
+                    let mut val: serde_json::Value = serde_json::from_slice(&b)?;
+                    let txout = serde_json::from_value(val["t"].take())?;
+                    let keychain = serde_json::from_value(val["i"].take())?;
+
+                    Ok(Some(UTXO { outpoint: outpoint.clone(), txout, keychain }))
+                }
+            }
+        }
+
+        fn del_raw_tx(&mut self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+            let key = MapKey::RawTx(Some(txid)).as_map_key();
+            let res = self.remove(key);
+            let res = $process_delete!(res);
+
+            Ok(res.map_or(Ok(None), |x| Some(deserialize(&x)).transpose())?)
+        }
+
+        fn del_tx(&mut self, txid: &Txid, include_raw: bool) -> Result<Option<TransactionDetails>, Error> {
+            let raw_tx = if include_raw {
+                self.del_raw_tx(txid)?
+            } else {
+                None
+            };
+
+            let key = MapKey::Transaction(Some(txid)).as_map_key();
+            let res = self.remove(key);
+            let res = $process_delete!(res);
+
+            match res {
+                None => Ok(None),
+                Some(b) => {
+                    let mut val: TransactionDetails = serde_json::from_slice(&b)?;
+                    val.transaction = raw_tx;
+
+                    Ok(Some(val))
+                }
+            }
+        }
+
+        fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
+            let key = MapKey::LastIndex(keychain).as_map_key();
+            let res = self.remove(key);
+            let res = $process_delete!(res);
+
+            match res {
+                None => Ok(None),
+                Some(b) => {
+                    let array: [u8; 4] = b.as_ref().try_into().map_err(|_| Error::InvalidU32Bytes(b.to_vec()))?;
+                    let val = u32::from_be_bytes(array);
+                    Ok(Some(val))
+                }
+            }
+        }
+    }
+}
+
+macro_rules! process_delete_tree {
+    ($res:expr) => {
+        $res?
+    };
+}
+impl BatchOperations for Tree {
+    impl_batch_operations!({?}, process_delete_tree);
+}
+
+macro_rules! process_delete_batch {
+    ($res:expr) => {
+        None as Option<sled::IVec>
+    };
+}
+#[allow(unused_variables)]
+impl BatchOperations for Batch {
+    impl_batch_operations!({}, process_delete_batch);
+}
+
+impl Database for Tree {
+    fn check_descriptor_checksum<B: AsRef<[u8]>>(
+        &mut self,
+        keychain: KeychainKind,
+        bytes: B,
+    ) -> Result<(), Error> {
+        let key = MapKey::DescriptorChecksum(keychain).as_map_key();
+
+        let prev = self.get(&key)?.map(|x| x.to_vec());
+        if let Some(val) = prev {
+            if val == bytes.as_ref() {
+                Ok(())
+            } else {
+                Err(Error::ChecksumMismatch)
+            }
+        } else {
+            self.insert(&key, bytes.as_ref())?;
+            Ok(())
+        }
+    }
+
+    fn iter_script_pubkeys(&self, keychain: Option<KeychainKind>) -> Result<Vec<Script>, Error> {
+        let key = MapKey::Path((keychain, None)).as_map_key();
+        self.scan_prefix(key)
+            .map(|x| -> Result<_, Error> {
+                let (_, v) = x?;
+                Ok(deserialize(&v)?)
+            })
+            .collect()
+    }
+
+    fn iter_utxos(&self) -> Result<Vec<UTXO>, Error> {
+        let key = MapKey::UTXO(None).as_map_key();
+        self.scan_prefix(key)
+            .map(|x| -> Result<_, Error> {
+                let (k, v) = x?;
+                let outpoint = deserialize(&k[1..])?;
+
+                let mut val: serde_json::Value = serde_json::from_slice(&v)?;
+                let txout = serde_json::from_value(val["t"].take())?;
+                let keychain = serde_json::from_value(val["i"].take())?;
+
+                Ok(UTXO {
+                    outpoint,
+                    txout,
+                    keychain,
+                })
+            })
+            .collect()
+    }
+
+    fn iter_raw_txs(&self) -> Result<Vec<Transaction>, Error> {
+        let key = MapKey::RawTx(None).as_map_key();
+        self.scan_prefix(key)
+            .map(|x| -> Result<_, Error> {
+                let (_, v) = x?;
+                Ok(deserialize(&v)?)
+            })
+            .collect()
+    }
+
+    fn iter_txs(&self, include_raw: bool) -> Result<Vec<TransactionDetails>, Error> {
+        let key = MapKey::Transaction(None).as_map_key();
+        self.scan_prefix(key)
+            .map(|x| -> Result<_, Error> {
+                let (k, v) = x?;
+                let mut txdetails: TransactionDetails = serde_json::from_slice(&v)?;
+                if include_raw {
+                    let txid = deserialize(&k[1..])?;
+                    txdetails.transaction = self.get_raw_tx(&txid)?;
+                }
+
+                Ok(txdetails)
+            })
+            .collect()
+    }
+
+    fn get_script_pubkey_from_path(
+        &self,
+        keychain: KeychainKind,
+        path: u32,
+    ) -> Result<Option<Script>, Error> {
+        let key = MapKey::Path((Some(keychain), Some(path))).as_map_key();
+        Ok(self.get(key)?.map(|b| deserialize(&b)).transpose()?)
+    }
+
+    fn get_path_from_script_pubkey(
+        &self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error> {
+        let key = MapKey::Script(Some(script)).as_map_key();
+        self.get(key)?
+            .map(|b| -> Result<_, Error> {
+                let mut val: serde_json::Value = serde_json::from_slice(&b)?;
+                let st = serde_json::from_value(val["t"].take())?;
+                let path = serde_json::from_value(val["p"].take())?;
+
+                Ok((st, path))
+            })
+            .transpose()
+    }
+
+    fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
+        let key = MapKey::UTXO(Some(outpoint)).as_map_key();
+        self.get(key)?
+            .map(|b| -> Result<_, Error> {
+                let mut val: serde_json::Value = serde_json::from_slice(&b)?;
+                let txout = serde_json::from_value(val["t"].take())?;
+                let keychain = serde_json::from_value(val["i"].take())?;
+
+                Ok(UTXO {
+                    outpoint: *outpoint,
+                    txout,
+                    keychain,
+                })
+            })
+            .transpose()
+    }
+
+    fn get_raw_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        let key = MapKey::RawTx(Some(txid)).as_map_key();
+        Ok(self.get(key)?.map(|b| deserialize(&b)).transpose()?)
+    }
+
+    fn get_tx(&self, txid: &Txid, include_raw: bool) -> Result<Option<TransactionDetails>, Error> {
+        let key = MapKey::Transaction(Some(txid)).as_map_key();
+        self.get(key)?
+            .map(|b| -> Result<_, Error> {
+                let mut txdetails: TransactionDetails = serde_json::from_slice(&b)?;
+                if include_raw {
+                    txdetails.transaction = self.get_raw_tx(&txid)?;
+                }
+
+                Ok(txdetails)
+            })
+            .transpose()
+    }
+
+    fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
+        let key = MapKey::LastIndex(keychain).as_map_key();
+        self.get(key)?
+            .map(|b| -> Result<_, Error> {
+                let array: [u8; 4] = b
+                    .as_ref()
+                    .try_into()
+                    .map_err(|_| Error::InvalidU32Bytes(b.to_vec()))?;
+                let val = u32::from_be_bytes(array);
+                Ok(val)
+            })
+            .transpose()
+    }
+
+    // inserts 0 if not present
+    fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> {
+        let key = MapKey::LastIndex(keychain).as_map_key();
+        self.update_and_fetch(key, |prev| {
+            let new = match prev {
+                Some(b) => {
+                    let array: [u8; 4] = b.try_into().unwrap_or([0; 4]);
+                    let val = u32::from_be_bytes(array);
+
+                    val + 1
+                }
+                None => 0,
+            };
+
+            Some(new.to_be_bytes().to_vec())
+        })?
+        .map_or(Ok(0), |b| -> Result<_, Error> {
+            let array: [u8; 4] = b
+                .as_ref()
+                .try_into()
+                .map_err(|_| Error::InvalidU32Bytes(b.to_vec()))?;
+            let val = u32::from_be_bytes(array);
+            Ok(val)
+        })
+    }
+}
+
+impl BatchDatabase for Tree {
+    type Batch = sled::Batch;
+
+    fn begin_batch(&self) -> Self::Batch {
+        sled::Batch::default()
+    }
+
+    fn commit_batch(&mut self, batch: Self::Batch) -> Result<(), Error> {
+        Ok(self.apply_batch(batch)?)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::sync::{Arc, Condvar, Mutex, Once};
+    use std::time::{SystemTime, UNIX_EPOCH};
+
+    use sled::{Db, Tree};
+
+    static mut COUNT: usize = 0;
+
+    lazy_static! {
+        static ref DB: Arc<(Mutex<Option<Db>>, Condvar)> =
+            Arc::new((Mutex::new(None), Condvar::new()));
+        static ref INIT: Once = Once::new();
+    }
+
+    fn get_tree() -> Tree {
+        unsafe {
+            let cloned = DB.clone();
+            let (mutex, cvar) = &*cloned;
+
+            INIT.call_once(|| {
+                let mut db = mutex.lock().unwrap();
+
+                let time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
+                let mut dir = std::env::temp_dir();
+                dir.push(format!("mbw_{}", time.as_nanos()));
+
+                *db = Some(sled::open(dir).unwrap());
+                cvar.notify_all();
+            });
+
+            let mut db = mutex.lock().unwrap();
+            while !db.is_some() {
+                db = cvar.wait(db).unwrap();
+            }
+
+            COUNT += 1;
+
+            db.as_ref()
+                .unwrap()
+                .open_tree(format!("tree_{}", COUNT))
+                .unwrap()
+        }
+    }
+
+    #[test]
+    fn test_script_pubkey() {
+        crate::database::test::test_script_pubkey(get_tree());
+    }
+
+    #[test]
+    fn test_batch_script_pubkey() {
+        crate::database::test::test_batch_script_pubkey(get_tree());
+    }
+
+    #[test]
+    fn test_iter_script_pubkey() {
+        crate::database::test::test_iter_script_pubkey(get_tree());
+    }
+
+    #[test]
+    fn test_del_script_pubkey() {
+        crate::database::test::test_del_script_pubkey(get_tree());
+    }
+
+    #[test]
+    fn test_utxo() {
+        crate::database::test::test_utxo(get_tree());
+    }
+
+    #[test]
+    fn test_raw_tx() {
+        crate::database::test::test_raw_tx(get_tree());
+    }
+
+    #[test]
+    fn test_tx() {
+        crate::database::test::test_tx(get_tree());
+    }
+
+    #[test]
+    fn test_last_index() {
+        crate::database::test::test_last_index(get_tree());
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/memory.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/memory.rs.html new file mode 100644 index 0000000000..350db935c6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/memory.rs.html @@ -0,0 +1,1138 @@ +memory.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! In-memory ephemeral database
+//!
+//! This module defines an in-memory database type called [`MemoryDatabase`] that is based on a
+//! [`BTreeMap`].
+
+use std::collections::BTreeMap;
+use std::ops::Bound::{Excluded, Included};
+
+use bitcoin::consensus::encode::{deserialize, serialize};
+use bitcoin::hash_types::Txid;
+use bitcoin::{OutPoint, Script, Transaction};
+
+use crate::database::{BatchDatabase, BatchOperations, ConfigurableDatabase, Database};
+use crate::error::Error;
+use crate::types::*;
+
+// path -> script       p{i,e}<path> -> script
+// script -> path       s<script> -> {i,e}<path>
+// outpoint             u<outpoint> -> txout
+// rawtx                r<txid> -> tx
+// transactions         t<txid> -> tx details
+// deriv indexes        c{i,e} -> u32
+// descriptor checksum  d{i,e} -> vec<u8>
+
+pub(crate) enum MapKey<'a> {
+    Path((Option<KeychainKind>, Option<u32>)),
+    Script(Option<&'a Script>),
+    UTXO(Option<&'a OutPoint>),
+    RawTx(Option<&'a Txid>),
+    Transaction(Option<&'a Txid>),
+    LastIndex(KeychainKind),
+    DescriptorChecksum(KeychainKind),
+}
+
+impl MapKey<'_> {
+    fn as_prefix(&self) -> Vec<u8> {
+        match self {
+            MapKey::Path((st, _)) => {
+                let mut v = b"p".to_vec();
+                if let Some(st) = st {
+                    v.push(st.as_byte());
+                }
+                v
+            }
+            MapKey::Script(_) => b"s".to_vec(),
+            MapKey::UTXO(_) => b"u".to_vec(),
+            MapKey::RawTx(_) => b"r".to_vec(),
+            MapKey::Transaction(_) => b"t".to_vec(),
+            MapKey::LastIndex(st) => [b"c", st.as_ref()].concat(),
+            MapKey::DescriptorChecksum(st) => [b"d", st.as_ref()].concat(),
+        }
+    }
+
+    fn serialize_content(&self) -> Vec<u8> {
+        match self {
+            MapKey::Path((_, Some(child))) => child.to_be_bytes().to_vec(),
+            MapKey::Script(Some(s)) => serialize(*s),
+            MapKey::UTXO(Some(s)) => serialize(*s),
+            MapKey::RawTx(Some(s)) => serialize(*s),
+            MapKey::Transaction(Some(s)) => serialize(*s),
+            _ => vec![],
+        }
+    }
+
+    pub fn as_map_key(&self) -> Vec<u8> {
+        let mut v = self.as_prefix();
+        v.extend_from_slice(&self.serialize_content());
+
+        v
+    }
+}
+
+fn after(key: &[u8]) -> Vec<u8> {
+    let mut key = key.to_owned();
+    let mut idx = key.len();
+    while idx > 0 {
+        if key[idx - 1] == 0xFF {
+            idx -= 1;
+            continue;
+        } else {
+            key[idx - 1] += 1;
+            break;
+        }
+    }
+
+    key
+}
+
+/// In-memory ephemeral database
+///
+/// This database can be used as a temporary storage for wallets that are not kept permanently on
+/// a device, or on platforms that don't provide a filesystem, like `wasm32`.
+///
+/// Once it's dropped its content will be lost.
+///
+/// If you are looking for a permanent storage solution, you can try with the default key-value
+/// database called [`sled`]. See the [`database`] module documentation for more defailts.
+///
+/// [`database`]: crate::database
+#[derive(Debug, Default)]
+pub struct MemoryDatabase {
+    map: BTreeMap<Vec<u8>, Box<dyn std::any::Any>>,
+    deleted_keys: Vec<Vec<u8>>,
+}
+
+impl MemoryDatabase {
+    /// Create a new empty database
+    pub fn new() -> Self {
+        MemoryDatabase {
+            map: BTreeMap::new(),
+            deleted_keys: Vec::new(),
+        }
+    }
+}
+
+impl BatchOperations for MemoryDatabase {
+    fn set_script_pubkey(
+        &mut self,
+        script: &Script,
+        keychain: KeychainKind,
+        path: u32,
+    ) -> Result<(), Error> {
+        let key = MapKey::Path((Some(keychain), Some(path))).as_map_key();
+        self.map.insert(key, Box::new(script.clone()));
+
+        let key = MapKey::Script(Some(script)).as_map_key();
+        let value = json!({
+            "t": keychain,
+            "p": path,
+        });
+        self.map.insert(key, Box::new(value));
+
+        Ok(())
+    }
+
+    fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error> {
+        let key = MapKey::UTXO(Some(&utxo.outpoint)).as_map_key();
+        self.map
+            .insert(key, Box::new((utxo.txout.clone(), utxo.keychain)));
+
+        Ok(())
+    }
+    fn set_raw_tx(&mut self, transaction: &Transaction) -> Result<(), Error> {
+        let key = MapKey::RawTx(Some(&transaction.txid())).as_map_key();
+        self.map.insert(key, Box::new(transaction.clone()));
+
+        Ok(())
+    }
+    fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error> {
+        let key = MapKey::Transaction(Some(&transaction.txid)).as_map_key();
+
+        // insert the raw_tx if present
+        if let Some(ref tx) = transaction.transaction {
+            self.set_raw_tx(tx)?;
+        }
+
+        // remove the raw tx from the serialized version
+        let mut transaction = transaction.clone();
+        transaction.transaction = None;
+
+        self.map.insert(key, Box::new(transaction));
+
+        Ok(())
+    }
+    fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> {
+        let key = MapKey::LastIndex(keychain).as_map_key();
+        self.map.insert(key, Box::new(value));
+
+        Ok(())
+    }
+
+    fn del_script_pubkey_from_path(
+        &mut self,
+        keychain: KeychainKind,
+        path: u32,
+    ) -> Result<Option<Script>, Error> {
+        let key = MapKey::Path((Some(keychain), Some(path))).as_map_key();
+        let res = self.map.remove(&key);
+        self.deleted_keys.push(key);
+
+        Ok(res.map(|x| x.downcast_ref().cloned().unwrap()))
+    }
+    fn del_path_from_script_pubkey(
+        &mut self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error> {
+        let key = MapKey::Script(Some(script)).as_map_key();
+        let res = self.map.remove(&key);
+        self.deleted_keys.push(key);
+
+        match res {
+            None => Ok(None),
+            Some(b) => {
+                let mut val: serde_json::Value = b.downcast_ref().cloned().unwrap();
+                let st = serde_json::from_value(val["t"].take())?;
+                let path = serde_json::from_value(val["p"].take())?;
+
+                Ok(Some((st, path)))
+            }
+        }
+    }
+    fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
+        let key = MapKey::UTXO(Some(outpoint)).as_map_key();
+        let res = self.map.remove(&key);
+        self.deleted_keys.push(key);
+
+        match res {
+            None => Ok(None),
+            Some(b) => {
+                let (txout, keychain) = b.downcast_ref().cloned().unwrap();
+                Ok(Some(UTXO {
+                    outpoint: *outpoint,
+                    txout,
+                    keychain,
+                }))
+            }
+        }
+    }
+    fn del_raw_tx(&mut self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        let key = MapKey::RawTx(Some(txid)).as_map_key();
+        let res = self.map.remove(&key);
+        self.deleted_keys.push(key);
+
+        Ok(res.map(|x| x.downcast_ref().cloned().unwrap()))
+    }
+    fn del_tx(
+        &mut self,
+        txid: &Txid,
+        include_raw: bool,
+    ) -> Result<Option<TransactionDetails>, Error> {
+        let raw_tx = if include_raw {
+            self.del_raw_tx(txid)?
+        } else {
+            None
+        };
+
+        let key = MapKey::Transaction(Some(txid)).as_map_key();
+        let res = self.map.remove(&key);
+        self.deleted_keys.push(key);
+
+        match res {
+            None => Ok(None),
+            Some(b) => {
+                let mut val: TransactionDetails = b.downcast_ref().cloned().unwrap();
+                val.transaction = raw_tx;
+
+                Ok(Some(val))
+            }
+        }
+    }
+    fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
+        let key = MapKey::LastIndex(keychain).as_map_key();
+        let res = self.map.remove(&key);
+        self.deleted_keys.push(key);
+
+        match res {
+            None => Ok(None),
+            Some(b) => Ok(Some(*b.downcast_ref().unwrap())),
+        }
+    }
+}
+
+impl Database for MemoryDatabase {
+    fn check_descriptor_checksum<B: AsRef<[u8]>>(
+        &mut self,
+        keychain: KeychainKind,
+        bytes: B,
+    ) -> Result<(), Error> {
+        let key = MapKey::DescriptorChecksum(keychain).as_map_key();
+
+        let prev = self
+            .map
+            .get(&key)
+            .map(|x| x.downcast_ref::<Vec<u8>>().unwrap());
+        if let Some(val) = prev {
+            if val == &bytes.as_ref().to_vec() {
+                Ok(())
+            } else {
+                Err(Error::ChecksumMismatch)
+            }
+        } else {
+            self.map.insert(key, Box::new(bytes.as_ref().to_vec()));
+            Ok(())
+        }
+    }
+
+    fn iter_script_pubkeys(&self, keychain: Option<KeychainKind>) -> Result<Vec<Script>, Error> {
+        let key = MapKey::Path((keychain, None)).as_map_key();
+        self.map
+            .range::<Vec<u8>, _>((Included(&key), Excluded(&after(&key))))
+            .map(|(_, v)| Ok(v.downcast_ref().cloned().unwrap()))
+            .collect()
+    }
+
+    fn iter_utxos(&self) -> Result<Vec<UTXO>, Error> {
+        let key = MapKey::UTXO(None).as_map_key();
+        self.map
+            .range::<Vec<u8>, _>((Included(&key), Excluded(&after(&key))))
+            .map(|(k, v)| {
+                let outpoint = deserialize(&k[1..]).unwrap();
+                let (txout, keychain) = v.downcast_ref().cloned().unwrap();
+                Ok(UTXO {
+                    outpoint,
+                    txout,
+                    keychain,
+                })
+            })
+            .collect()
+    }
+
+    fn iter_raw_txs(&self) -> Result<Vec<Transaction>, Error> {
+        let key = MapKey::RawTx(None).as_map_key();
+        self.map
+            .range::<Vec<u8>, _>((Included(&key), Excluded(&after(&key))))
+            .map(|(_, v)| Ok(v.downcast_ref().cloned().unwrap()))
+            .collect()
+    }
+
+    fn iter_txs(&self, include_raw: bool) -> Result<Vec<TransactionDetails>, Error> {
+        let key = MapKey::Transaction(None).as_map_key();
+        self.map
+            .range::<Vec<u8>, _>((Included(&key), Excluded(&after(&key))))
+            .map(|(k, v)| {
+                let mut txdetails: TransactionDetails = v.downcast_ref().cloned().unwrap();
+                if include_raw {
+                    let txid = deserialize(&k[1..])?;
+                    txdetails.transaction = self.get_raw_tx(&txid)?;
+                }
+
+                Ok(txdetails)
+            })
+            .collect()
+    }
+
+    fn get_script_pubkey_from_path(
+        &self,
+        keychain: KeychainKind,
+        path: u32,
+    ) -> Result<Option<Script>, Error> {
+        let key = MapKey::Path((Some(keychain), Some(path))).as_map_key();
+        Ok(self
+            .map
+            .get(&key)
+            .map(|b| b.downcast_ref().cloned().unwrap()))
+    }
+
+    fn get_path_from_script_pubkey(
+        &self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error> {
+        let key = MapKey::Script(Some(script)).as_map_key();
+        Ok(self.map.get(&key).map(|b| {
+            let mut val: serde_json::Value = b.downcast_ref().cloned().unwrap();
+            let st = serde_json::from_value(val["t"].take()).unwrap();
+            let path = serde_json::from_value(val["p"].take()).unwrap();
+
+            (st, path)
+        }))
+    }
+
+    fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
+        let key = MapKey::UTXO(Some(outpoint)).as_map_key();
+        Ok(self.map.get(&key).map(|b| {
+            let (txout, keychain) = b.downcast_ref().cloned().unwrap();
+            UTXO {
+                outpoint: *outpoint,
+                txout,
+                keychain,
+            }
+        }))
+    }
+
+    fn get_raw_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        let key = MapKey::RawTx(Some(txid)).as_map_key();
+        Ok(self
+            .map
+            .get(&key)
+            .map(|b| b.downcast_ref().cloned().unwrap()))
+    }
+
+    fn get_tx(&self, txid: &Txid, include_raw: bool) -> Result<Option<TransactionDetails>, Error> {
+        let key = MapKey::Transaction(Some(txid)).as_map_key();
+        Ok(self.map.get(&key).map(|b| {
+            let mut txdetails: TransactionDetails = b.downcast_ref().cloned().unwrap();
+            if include_raw {
+                txdetails.transaction = self.get_raw_tx(&txid).unwrap();
+            }
+
+            txdetails
+        }))
+    }
+
+    fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
+        let key = MapKey::LastIndex(keychain).as_map_key();
+        Ok(self.map.get(&key).map(|b| *b.downcast_ref().unwrap()))
+    }
+
+    // inserts 0 if not present
+    fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> {
+        let key = MapKey::LastIndex(keychain).as_map_key();
+        let value = self
+            .map
+            .entry(key)
+            .and_modify(|x| *x.downcast_mut::<u32>().unwrap() += 1)
+            .or_insert_with(|| Box::<u32>::new(0))
+            .downcast_mut()
+            .unwrap();
+
+        Ok(*value)
+    }
+}
+
+impl BatchDatabase for MemoryDatabase {
+    type Batch = Self;
+
+    fn begin_batch(&self) -> Self::Batch {
+        MemoryDatabase::new()
+    }
+
+    fn commit_batch(&mut self, mut batch: Self::Batch) -> Result<(), Error> {
+        for key in batch.deleted_keys {
+            self.map.remove(&key);
+        }
+        self.map.append(&mut batch.map);
+        Ok(())
+    }
+}
+
+impl ConfigurableDatabase for MemoryDatabase {
+    type Config = ();
+
+    fn from_config(_config: &Self::Config) -> Result<Self, Error> {
+        Ok(MemoryDatabase::default())
+    }
+}
+
+#[cfg(test)]
+impl MemoryDatabase {
+    // Artificially insert a tx in the database, as if we had found it with a `sync`
+    pub fn received_tx(
+        &mut self,
+        tx_meta: testutils::TestIncomingTx,
+        current_height: Option<u32>,
+    ) -> bitcoin::Txid {
+        use std::str::FromStr;
+
+        let tx = Transaction {
+            version: 1,
+            lock_time: 0,
+            input: vec![],
+            output: tx_meta
+                .output
+                .iter()
+                .map(|out_meta| bitcoin::TxOut {
+                    value: out_meta.value,
+                    script_pubkey: bitcoin::Address::from_str(&out_meta.to_address)
+                        .unwrap()
+                        .script_pubkey(),
+                })
+                .collect(),
+        };
+
+        let txid = tx.txid();
+        let height = tx_meta
+            .min_confirmations
+            .map(|conf| current_height.unwrap().checked_sub(conf as u32).unwrap());
+
+        let tx_details = TransactionDetails {
+            transaction: Some(tx.clone()),
+            txid,
+            timestamp: 0,
+            height,
+            received: 0,
+            sent: 0,
+            fees: 0,
+        };
+
+        self.set_tx(&tx_details).unwrap();
+        for (vout, out) in tx.output.iter().enumerate() {
+            self.set_utxo(&UTXO {
+                txout: out.clone(),
+                outpoint: OutPoint {
+                    txid,
+                    vout: vout as u32,
+                },
+                keychain: KeychainKind::External,
+            })
+            .unwrap();
+        }
+
+        txid
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::MemoryDatabase;
+
+    fn get_tree() -> MemoryDatabase {
+        MemoryDatabase::new()
+    }
+
+    #[test]
+    fn test_script_pubkey() {
+        crate::database::test::test_script_pubkey(get_tree());
+    }
+
+    #[test]
+    fn test_batch_script_pubkey() {
+        crate::database::test::test_batch_script_pubkey(get_tree());
+    }
+
+    #[test]
+    fn test_iter_script_pubkey() {
+        crate::database::test::test_iter_script_pubkey(get_tree());
+    }
+
+    #[test]
+    fn test_del_script_pubkey() {
+        crate::database::test::test_del_script_pubkey(get_tree());
+    }
+
+    #[test]
+    fn test_utxo() {
+        crate::database::test::test_utxo(get_tree());
+    }
+
+    #[test]
+    fn test_raw_tx() {
+        crate::database::test::test_raw_tx(get_tree());
+    }
+
+    #[test]
+    fn test_tx() {
+        crate::database::test::test_tx(get_tree());
+    }
+
+    #[test]
+    fn test_last_index() {
+        crate::database::test::test_last_index(get_tree());
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/mod.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/mod.rs.html new file mode 100644 index 0000000000..864f1cb872 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/database/mod.rs.html @@ -0,0 +1,772 @@ +mod.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Database types
+//!
+//! This module provides the implementation of some defaults database types, along with traits that
+//! can be implemented externally to let [`Wallet`]s use customized databases.
+//!
+//! It's important to note that the databases defined here only contains "blockchain-related" data.
+//! They can be seen more as a cache than a critical piece of storage that contains secrets and
+//! keys.
+//!
+//! The currently recommended database is [`sled`], which is a pretty simple key-value embedded
+//! database written in Rust. If the `key-value-db` feature is enabled (which by default is),
+//! this library automatically implements all the required traits for [`sled::Tree`].
+//!
+//! [`Wallet`]: crate::wallet::Wallet
+
+use bitcoin::hash_types::Txid;
+use bitcoin::{OutPoint, Script, Transaction, TxOut};
+
+use crate::error::Error;
+use crate::types::*;
+
+pub mod any;
+pub use any::{AnyDatabase, AnyDatabaseConfig};
+
+#[cfg(feature = "key-value-db")]
+pub(crate) mod keyvalue;
+
+pub mod memory;
+pub use memory::MemoryDatabase;
+
+/// Trait for operations that can be batched
+///
+/// This trait defines the list of operations that must be implemented on the [`Database`] type and
+/// the [`BatchDatabase::Batch`] type.
+pub trait BatchOperations {
+    /// Store a script_pubkey along with its keychain and child number.
+    fn set_script_pubkey(
+        &mut self,
+        script: &Script,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<(), Error>;
+    /// Store a [`UTXO`]
+    fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error>;
+    /// Store a raw transaction
+    fn set_raw_tx(&mut self, transaction: &Transaction) -> Result<(), Error>;
+    /// Store the metadata of a transaction
+    fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error>;
+    /// Store the last derivation index for a given keychain.
+    fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error>;
+
+    /// Delete a script_pubkey given the keychain and its child number.
+    fn del_script_pubkey_from_path(
+        &mut self,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<Option<Script>, Error>;
+    /// Delete the data related to a specific script_pubkey, meaning the keychain and the child
+    /// number.
+    fn del_path_from_script_pubkey(
+        &mut self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error>;
+    /// Delete a [`UTXO`] given its [`OutPoint`]
+    fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error>;
+    /// Delete a raw transaction given its [`Txid`]
+    fn del_raw_tx(&mut self, txid: &Txid) -> Result<Option<Transaction>, Error>;
+    /// Delete the metadata of a transaction and optionally the raw transaction itself
+    fn del_tx(
+        &mut self,
+        txid: &Txid,
+        include_raw: bool,
+    ) -> Result<Option<TransactionDetails>, Error>;
+    /// Delete the last derivation index for a keychain.
+    fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error>;
+}
+
+/// Trait for reading data from a database
+///
+/// This traits defines the operations that can be used to read data out of a database
+pub trait Database: BatchOperations {
+    /// Read and checks the descriptor checksum for a given keychain.
+    ///
+    /// Should return [`Error::ChecksumMismatch`](crate::error::Error::ChecksumMismatch) if the
+    /// checksum doesn't match. If there's no checksum in the database, simply store it for the
+    /// next time.
+    fn check_descriptor_checksum<B: AsRef<[u8]>>(
+        &mut self,
+        keychain: KeychainKind,
+        bytes: B,
+    ) -> Result<(), Error>;
+
+    /// Return the list of script_pubkeys
+    fn iter_script_pubkeys(&self, keychain: Option<KeychainKind>) -> Result<Vec<Script>, Error>;
+    /// Return the list of [`UTXO`]s
+    fn iter_utxos(&self) -> Result<Vec<UTXO>, Error>;
+    /// Return the list of raw transactions
+    fn iter_raw_txs(&self) -> Result<Vec<Transaction>, Error>;
+    /// Return the list of transactions metadata
+    fn iter_txs(&self, include_raw: bool) -> Result<Vec<TransactionDetails>, Error>;
+
+    /// Fetch a script_pubkey given the child number of a keychain.
+    fn get_script_pubkey_from_path(
+        &self,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<Option<Script>, Error>;
+    /// Fetch the keychain and child number of a given script_pubkey
+    fn get_path_from_script_pubkey(
+        &self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error>;
+    /// Fetch a [`UTXO`] given its [`OutPoint`]
+    fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error>;
+    /// Fetch a raw transaction given its [`Txid`]
+    fn get_raw_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>;
+    /// Fetch the transaction metadata and optionally also the raw transaction
+    fn get_tx(&self, txid: &Txid, include_raw: bool) -> Result<Option<TransactionDetails>, Error>;
+    /// Return the last defivation index for a keychain.
+    fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error>;
+
+    /// Increment the last derivation index for a keychain and return it
+    ///
+    /// It should insert and return `0` if not present in the database
+    fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error>;
+}
+
+/// Trait for a database that supports batch operations
+///
+/// This trait defines the methods to start and apply a batch of operations.
+pub trait BatchDatabase: Database {
+    /// Container for the operations
+    type Batch: BatchOperations;
+
+    /// Create a new batch container
+    fn begin_batch(&self) -> Self::Batch;
+    /// Consume and apply a batch of operations
+    fn commit_batch(&mut self, batch: Self::Batch) -> Result<(), Error>;
+}
+
+/// Trait for [`Database`] types that can be created given a configuration
+pub trait ConfigurableDatabase: Database + Sized {
+    /// Type that contains the configuration
+    type Config: std::fmt::Debug;
+
+    /// Create a new instance given a configuration
+    fn from_config(config: &Self::Config) -> Result<Self, Error>;
+}
+
+pub(crate) trait DatabaseUtils: Database {
+    fn is_mine(&self, script: &Script) -> Result<bool, Error> {
+        self.get_path_from_script_pubkey(script)
+            .map(|o| o.is_some())
+    }
+
+    fn get_raw_tx_or<F>(&self, txid: &Txid, f: F) -> Result<Option<Transaction>, Error>
+    where
+        F: FnOnce() -> Result<Option<Transaction>, Error>,
+    {
+        self.get_tx(txid, true)?
+            .map(|t| t.transaction)
+            .flatten()
+            .map_or_else(f, |t| Ok(Some(t)))
+    }
+
+    fn get_previous_output(&self, outpoint: &OutPoint) -> Result<Option<TxOut>, Error> {
+        self.get_raw_tx(&outpoint.txid)?
+            .map(|previous_tx| {
+                if outpoint.vout as usize >= previous_tx.output.len() {
+                    Err(Error::InvalidOutpoint(*outpoint))
+                } else {
+                    Ok(previous_tx.output[outpoint.vout as usize].clone())
+                }
+            })
+            .transpose()
+    }
+}
+
+impl<T: Database> DatabaseUtils for T {}
+
+#[cfg(test)]
+pub mod test {
+    use std::str::FromStr;
+
+    use bitcoin::consensus::encode::deserialize;
+    use bitcoin::hashes::hex::*;
+    use bitcoin::*;
+
+    use super::*;
+
+    pub fn test_script_pubkey<D: Database>(mut tree: D) {
+        let script = Script::from(
+            Vec::<u8>::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap(),
+        );
+        let path = 42;
+        let keychain = KeychainKind::External;
+
+        tree.set_script_pubkey(&script, keychain, path).unwrap();
+
+        assert_eq!(
+            tree.get_script_pubkey_from_path(keychain, path).unwrap(),
+            Some(script.clone())
+        );
+        assert_eq!(
+            tree.get_path_from_script_pubkey(&script).unwrap(),
+            Some((keychain, path.clone()))
+        );
+    }
+
+    pub fn test_batch_script_pubkey<D: BatchDatabase>(mut tree: D) {
+        let mut batch = tree.begin_batch();
+
+        let script = Script::from(
+            Vec::<u8>::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap(),
+        );
+        let path = 42;
+        let keychain = KeychainKind::External;
+
+        batch.set_script_pubkey(&script, keychain, path).unwrap();
+
+        assert_eq!(
+            tree.get_script_pubkey_from_path(keychain, path).unwrap(),
+            None
+        );
+        assert_eq!(tree.get_path_from_script_pubkey(&script).unwrap(), None);
+
+        tree.commit_batch(batch).unwrap();
+
+        assert_eq!(
+            tree.get_script_pubkey_from_path(keychain, path).unwrap(),
+            Some(script.clone())
+        );
+        assert_eq!(
+            tree.get_path_from_script_pubkey(&script).unwrap(),
+            Some((keychain, path.clone()))
+        );
+    }
+
+    pub fn test_iter_script_pubkey<D: Database>(mut tree: D) {
+        let script = Script::from(
+            Vec::<u8>::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap(),
+        );
+        let path = 42;
+        let keychain = KeychainKind::External;
+
+        tree.set_script_pubkey(&script, keychain, path).unwrap();
+
+        assert_eq!(tree.iter_script_pubkeys(None).unwrap().len(), 1);
+    }
+
+    pub fn test_del_script_pubkey<D: Database>(mut tree: D) {
+        let script = Script::from(
+            Vec::<u8>::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap(),
+        );
+        let path = 42;
+        let keychain = KeychainKind::External;
+
+        tree.set_script_pubkey(&script, keychain, path).unwrap();
+        assert_eq!(tree.iter_script_pubkeys(None).unwrap().len(), 1);
+
+        tree.del_script_pubkey_from_path(keychain, path).unwrap();
+        assert_eq!(tree.iter_script_pubkeys(None).unwrap().len(), 0);
+    }
+
+    pub fn test_utxo<D: Database>(mut tree: D) {
+        let outpoint = OutPoint::from_str(
+            "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:0",
+        )
+        .unwrap();
+        let script = Script::from(
+            Vec::<u8>::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap(),
+        );
+        let txout = TxOut {
+            value: 133742,
+            script_pubkey: script,
+        };
+        let utxo = UTXO {
+            txout,
+            outpoint,
+            keychain: KeychainKind::External,
+        };
+
+        tree.set_utxo(&utxo).unwrap();
+
+        assert_eq!(tree.get_utxo(&outpoint).unwrap(), Some(utxo));
+    }
+
+    pub fn test_raw_tx<D: Database>(mut tree: D) {
+        let hex_tx = Vec::<u8>::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
+        let tx: Transaction = deserialize(&hex_tx).unwrap();
+
+        tree.set_raw_tx(&tx).unwrap();
+
+        let txid = tx.txid();
+
+        assert_eq!(tree.get_raw_tx(&txid).unwrap(), Some(tx));
+    }
+
+    pub fn test_tx<D: Database>(mut tree: D) {
+        let hex_tx = Vec::<u8>::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
+        let tx: Transaction = deserialize(&hex_tx).unwrap();
+        let txid = tx.txid();
+        let mut tx_details = TransactionDetails {
+            transaction: Some(tx),
+            txid,
+            timestamp: 123456,
+            received: 1337,
+            sent: 420420,
+            fees: 140,
+            height: Some(1000),
+        };
+
+        tree.set_tx(&tx_details).unwrap();
+
+        // get with raw tx too
+        assert_eq!(
+            tree.get_tx(&tx_details.txid, true).unwrap(),
+            Some(tx_details.clone())
+        );
+        // get only raw_tx
+        assert_eq!(
+            tree.get_raw_tx(&tx_details.txid).unwrap(),
+            tx_details.transaction
+        );
+
+        // now get without raw_tx
+        tx_details.transaction = None;
+        assert_eq!(
+            tree.get_tx(&tx_details.txid, false).unwrap(),
+            Some(tx_details)
+        );
+    }
+
+    pub fn test_last_index<D: Database>(mut tree: D) {
+        tree.set_last_index(KeychainKind::External, 1337).unwrap();
+
+        assert_eq!(
+            tree.get_last_index(KeychainKind::External).unwrap(),
+            Some(1337)
+        );
+        assert_eq!(tree.get_last_index(KeychainKind::Internal).unwrap(), None);
+
+        let res = tree.increment_last_index(KeychainKind::External).unwrap();
+        assert_eq!(res, 1338);
+        let res = tree.increment_last_index(KeychainKind::Internal).unwrap();
+        assert_eq!(res, 0);
+
+        assert_eq!(
+            tree.get_last_index(KeychainKind::External).unwrap(),
+            Some(1338)
+        );
+        assert_eq!(
+            tree.get_last_index(KeychainKind::Internal).unwrap(),
+            Some(0)
+        );
+    }
+
+    // TODO: more tests...
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/checksum.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/checksum.rs.html new file mode 100644 index 0000000000..d1a56388f4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/checksum.rs.html @@ -0,0 +1,258 @@ +checksum.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Descriptor checksum
+//!
+//! This module contains a re-implementation of the function used by Bitcoin Core to calculate the
+//! checksum of a descriptor
+
+use std::iter::FromIterator;
+
+use crate::descriptor::Error;
+
+const INPUT_CHARSET: &str =  "0123456789()[],'/*abcdefgh@:$%{}IJKLMNOPQRSTUVWXYZ&+-.;<=>?!^_|~ijklmnopqrstuvwxyzABCDEFGH`#\"\\ ";
+const CHECKSUM_CHARSET: &str = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
+
+fn poly_mod(mut c: u64, val: u64) -> u64 {
+    let c0 = c >> 35;
+    c = ((c & 0x7ffffffff) << 5) ^ val;
+    if c0 & 1 > 0 {
+        c ^= 0xf5dee51989
+    };
+    if c0 & 2 > 0 {
+        c ^= 0xa9fdca3312
+    };
+    if c0 & 4 > 0 {
+        c ^= 0x1bab10e32d
+    };
+    if c0 & 8 > 0 {
+        c ^= 0x3706b1677a
+    };
+    if c0 & 16 > 0 {
+        c ^= 0x644d626ffd
+    };
+
+    c
+}
+
+/// Compute the checksum of a descriptor
+pub fn get_checksum(desc: &str) -> Result<String, Error> {
+    let mut c = 1;
+    let mut cls = 0;
+    let mut clscount = 0;
+    for ch in desc.chars() {
+        let pos = INPUT_CHARSET
+            .find(ch)
+            .ok_or(Error::InvalidDescriptorCharacter(ch))? as u64;
+        c = poly_mod(c, pos & 31);
+        cls = cls * 3 + (pos >> 5);
+        clscount += 1;
+        if clscount == 3 {
+            c = poly_mod(c, cls);
+            cls = 0;
+            clscount = 0;
+        }
+    }
+    if clscount > 0 {
+        c = poly_mod(c, cls);
+    }
+    (0..8).for_each(|_| c = poly_mod(c, 0));
+    c ^= 1;
+
+    let mut chars = Vec::with_capacity(8);
+    for j in 0..8 {
+        chars.push(
+            CHECKSUM_CHARSET
+                .chars()
+                .nth(((c >> (5 * (7 - j))) & 31) as usize)
+                .unwrap(),
+        );
+    }
+
+    Ok(String::from_iter(chars))
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::descriptor::get_checksum;
+
+    // test get_checksum() function; it should return the same value as Bitcoin Core
+    #[test]
+    fn test_get_checksum() {
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)";
+        assert_eq!(get_checksum(desc).unwrap(), "tqz0nc62");
+
+        let desc = "pkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/44'/1'/0'/0/*)";
+        assert_eq!(get_checksum(desc).unwrap(), "lasegmfs");
+    }
+
+    #[test]
+    fn test_get_checksum_invalid_character() {
+        let sparkle_heart = vec![240, 159, 146, 150];
+        let sparkle_heart = std::str::from_utf8(&sparkle_heart)
+            .unwrap()
+            .chars()
+            .next()
+            .unwrap();
+        let invalid_desc = format!("wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcL{}fjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)", sparkle_heart);
+
+        assert!(matches!(
+            get_checksum(&invalid_desc).err(),
+            Some(Error::InvalidDescriptorCharacter(invalid_char)) if invalid_char == sparkle_heart
+        ));
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/dsl.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/dsl.rs.html new file mode 100644 index 0000000000..418ef8e3ab --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/dsl.rs.html @@ -0,0 +1,1630 @@ +dsl.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Descriptors DSL
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_top_level_sh {
+    // disallow `sortedmulti` in `bare()`
+    ( Bare, Bare, sortedmulti $( $inner:tt )* ) => {
+        compile_error!("`bare()` descriptors can't contain any `sortedmulti` operands");
+    };
+    ( Bare, Bare, sortedmulti_vec $( $inner:tt )* ) => {
+        compile_error!("`bare()` descriptors can't contain any `sortedmulti_vec` operands");
+    };
+
+    ( $descriptor_variant:ident, $sortedmulti_variant:ident, sortedmulti $( $inner:tt )* ) => {
+        $crate::impl_sortedmulti!(sortedmulti $( $inner )*)
+            .and_then(|(inner, key_map, valid_networks)| Ok(($crate::miniscript::Descriptor::$sortedmulti_variant(inner), key_map, valid_networks)))
+    };
+    ( $descriptor_variant:ident, $sortedmulti_variant:ident, sortedmulti_vec $( $inner:tt )* ) => {
+        $crate::impl_sortedmulti!(sortedmulti_vec $( $inner )*)
+            .and_then(|(inner, key_map, valid_networks)| Ok(($crate::miniscript::Descriptor::$sortedmulti_variant(inner), key_map, valid_networks)))
+    };
+
+    ( $descriptor_variant:ident, $sortedmulti_variant:ident, $( $minisc:tt )* ) => {
+        $crate::fragment!($( $minisc )*)
+            .map(|(minisc, keymap, networks)|($crate::miniscript::Descriptor::<$crate::miniscript::descriptor::DescriptorPublicKey>::$descriptor_variant(minisc), keymap, networks))
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_top_level_pk {
+    ( $descriptor_variant:ident, $ctx:ty, $key:expr ) => {{
+        #[allow(unused_imports)]
+        use $crate::keys::{DescriptorKey, ToDescriptorKey};
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+
+        $key.to_descriptor_key()
+            .and_then(|key: DescriptorKey<$ctx>| key.extract(&secp))
+            .map(|(pk, key_map, valid_networks)| {
+                (
+                    $crate::miniscript::Descriptor::<
+                        $crate::miniscript::descriptor::DescriptorPublicKey,
+                    >::$descriptor_variant(pk),
+                    key_map,
+                    valid_networks,
+                )
+            })
+    }};
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_modifier {
+    ( $terminal_variant:ident, $( $inner:tt )* ) => {
+        $crate::fragment!($( $inner )*)
+            .map_err(|e| -> $crate::Error { e.into() })
+            .and_then(|(minisc, keymap, networks)| Ok(($crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(std::sync::Arc::new(minisc)))?, keymap, networks)))
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_leaf_opcode {
+    ( $terminal_variant:ident ) => {
+        $crate::miniscript::Miniscript::from_ast(
+            $crate::miniscript::miniscript::decode::Terminal::$terminal_variant,
+        )
+        .map_err($crate::Error::Miniscript)
+        .map(|minisc| {
+            (
+                minisc,
+                $crate::miniscript::descriptor::KeyMap::default(),
+                $crate::keys::any_network(),
+            )
+        })
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_leaf_opcode_value {
+    ( $terminal_variant:ident, $value:expr ) => {
+        $crate::miniscript::Miniscript::from_ast(
+            $crate::miniscript::miniscript::decode::Terminal::$terminal_variant($value),
+        )
+        .map_err($crate::Error::Miniscript)
+        .map(|minisc| {
+            (
+                minisc,
+                $crate::miniscript::descriptor::KeyMap::default(),
+                $crate::keys::any_network(),
+            )
+        })
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_leaf_opcode_value_two {
+    ( $terminal_variant:ident, $one:expr, $two:expr ) => {
+        $crate::miniscript::Miniscript::from_ast(
+            $crate::miniscript::miniscript::decode::Terminal::$terminal_variant($one, $two),
+        )
+        .map_err($crate::Error::Miniscript)
+        .map(|minisc| {
+            (
+                minisc,
+                $crate::miniscript::descriptor::KeyMap::default(),
+                $crate::keys::any_network(),
+            )
+        })
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_node_opcode_two {
+    ( $terminal_variant:ident, ( $( $a:tt )* ), ( $( $b:tt )* ) ) => {
+        $crate::fragment!($( $a )*)
+            .and_then(|a| Ok((a, $crate::fragment!($( $b )*)?)))
+            .and_then(|((a_minisc, mut a_keymap, a_networks), (b_minisc, b_keymap, b_networks))| {
+                // join key_maps
+                a_keymap.extend(b_keymap.into_iter());
+
+                Ok(($crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
+                    std::sync::Arc::new(a_minisc),
+                    std::sync::Arc::new(b_minisc),
+                ))?, a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks)))
+            })
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_node_opcode_three {
+    ( $terminal_variant:ident, ( $( $a:tt )* ), ( $( $b:tt )* ), ( $( $c:tt )* ) ) => {
+        $crate::fragment!($( $a )*)
+            .and_then(|a| Ok((a, $crate::fragment!($( $b )*)?, $crate::fragment!($( $c )*)?)))
+            .and_then(|((a_minisc, mut a_keymap, a_networks), (b_minisc, b_keymap, b_networks), (c_minisc, c_keymap, c_networks))| {
+                // join key_maps
+                a_keymap.extend(b_keymap.into_iter());
+                a_keymap.extend(c_keymap.into_iter());
+
+                let networks = $crate::keys::merge_networks(&a_networks, &b_networks);
+                let networks = $crate::keys::merge_networks(&networks, &c_networks);
+
+                Ok(($crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
+                    std::sync::Arc::new(a_minisc),
+                    std::sync::Arc::new(b_minisc),
+                    std::sync::Arc::new(c_minisc),
+                ))?, a_keymap, networks))
+            })
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_sortedmulti {
+    ( sortedmulti_vec $thresh:expr, $keys:expr ) => ({
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+        $crate::keys::make_sortedmulti_inner($thresh, $keys, &secp)
+    });
+    ( sortedmulti $thresh:expr $(, $key:expr )+ ) => ({
+        use $crate::keys::ToDescriptorKey;
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+
+        let mut keys = vec![];
+        $(
+            keys.push($key.to_descriptor_key());
+        )*
+
+        keys.into_iter().collect::<Result<Vec<_>, _>>()
+            .and_then(|keys| $crate::keys::make_sortedmulti_inner($thresh, keys, &secp))
+    });
+
+}
+
+/// Macro to write full descriptors with code
+///
+/// This macro expands to a `Result` of
+/// [`DescriptorTemplateOut`](super::template::DescriptorTemplateOut) and [`Error`](crate::Error)
+///
+/// ## Example
+///
+/// Signature plus timelock, equivalent to: `sh(wsh(and_v(v:pk(...), older(...))))`
+///
+/// ```
+/// # use std::str::FromStr;
+/// let my_key = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?;
+/// let my_timelock = 50;
+/// let (my_descriptor, my_keys_map, networks) = bdk::descriptor!(sh ( wsh ( and_v (+v pk my_key), ( older my_timelock ))))?;
+/// # Ok::<(), Box<dyn std::error::Error>>(())
+/// ```
+///
+/// -------
+///
+/// 2-of-3 that becomes a 1-of-3 after a timelock has expired. Both `descriptor_a` and `descriptor_b` are equivalent: the first
+/// syntax is more suitable for a fixed number of items known at compile time, while the other accepts a
+/// [`Vec`] of items, which makes it more suitable for writing dynamic descriptors.
+///
+/// They both produce the descriptor: `wsh(thresh(2,pk(...),s:pk(...),sdv:older(...)))`
+///
+/// ```
+/// # use std::str::FromStr;
+/// let my_key_1 = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?;
+/// let my_key_2 = bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
+/// let my_timelock = 50;
+///
+/// let (descriptor_a, key_map_a, networks) = bdk::descriptor! {
+///     wsh (
+///         thresh 2, (pk my_key_1), (+s pk my_key_2), (+s+d+v older my_timelock)
+///     )
+/// }?;
+///
+/// let b_items = vec![
+///     bdk::fragment!(pk my_key_1)?,
+///     bdk::fragment!(+s pk my_key_2)?,
+///     bdk::fragment!(+s+d+v older my_timelock)?,
+/// ];
+/// let (descriptor_b, mut key_map_b, networks) = bdk::descriptor!( wsh ( thresh_vec 2, b_items ) )?;
+///
+/// assert_eq!(descriptor_a, descriptor_b);
+/// assert_eq!(key_map_a.len(), key_map_b.len());
+/// # Ok::<(), Box<dyn std::error::Error>>(())
+/// ```
+///
+/// ------
+///
+/// Simple 2-of-2 multi-signature, equivalent to: `wsh(multi(2, ...))`
+///
+/// ```
+/// # use std::str::FromStr;
+/// let my_key_1 = bitcoin::PublicKey::from_str(
+///     "02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c",
+/// )?;
+/// let my_key_2 =
+///     bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
+///
+/// let (descriptor, key_map, networks) = bdk::descriptor! {
+///     wsh (
+///         multi 2, my_key_1, my_key_2
+///     )
+/// }?;
+/// # Ok::<(), Box<dyn std::error::Error>>(())
+/// ```
+///
+/// ------
+///
+/// Native-Segwit single-sig, equivalent to: `wpkh(...)`
+///
+/// ```
+/// let my_key =
+///     bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
+///
+/// let (descriptor, key_map, networks) = bdk::descriptor!(wpkh(my_key))?;
+/// # Ok::<(), Box<dyn std::error::Error>>(())
+/// ```
+#[macro_export]
+macro_rules! descriptor {
+    ( bare ( $( $minisc:tt )* ) ) => ({
+        $crate::impl_top_level_sh!(Bare, Bare, $( $minisc )*)
+    });
+    ( sh ( wsh ( $( $minisc:tt )* ) ) ) => ({
+        $crate::descriptor!(shwsh ($( $minisc )*))
+    });
+    ( shwsh ( $( $minisc:tt )* ) ) => ({
+        $crate::impl_top_level_sh!(ShWsh, ShWshSortedMulti, $( $minisc )*)
+    });
+    ( pk $key:expr ) => ({
+        $crate::impl_top_level_pk!(Pk, $crate::miniscript::Legacy, $key)
+    });
+    ( pkh $key:expr ) => ({
+        $crate::impl_top_level_pk!(Pkh,$crate::miniscript::Legacy, $key)
+    });
+    ( wpkh $key:expr ) => ({
+        $crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key)
+    });
+    ( sh ( wpkh ( $key:expr ) ) ) => ({
+        $crate::descriptor!(shwpkh ( $key ))
+    });
+    ( shwpkh ( $key:expr ) ) => ({
+        $crate::impl_top_level_pk!(ShWpkh, $crate::miniscript::Segwitv0, $key)
+    });
+    ( sh ( $( $minisc:tt )* ) ) => ({
+        $crate::impl_top_level_sh!(Sh, ShSortedMulti, $( $minisc )*)
+    });
+    ( wsh ( $( $minisc:tt )* ) ) => ({
+        $crate::impl_top_level_sh!(Wsh, WshSortedMulti, $( $minisc )*)
+    });
+}
+
+/// Macro to write descriptor fragments with code
+///
+/// This macro will be expanded to an object of type `Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), Error>`. It allows writing
+/// fragments of larger descriptors that can be pieced together using `fragment!(thresh_vec ...)`.
+#[macro_export]
+macro_rules! fragment {
+    // Modifiers
+    ( +a $( $inner:tt )* ) => ({
+        $crate::impl_modifier!(Alt, $( $inner )*)
+    });
+    ( +s $( $inner:tt )* ) => ({
+        $crate::impl_modifier!(Swap, $( $inner )*)
+    });
+    ( +c $( $inner:tt )* ) => ({
+        $crate::impl_modifier!(Check, $( $inner )*)
+    });
+    ( +d $( $inner:tt )* ) => ({
+        $crate::impl_modifier!(DupIf, $( $inner )*)
+    });
+    ( +v $( $inner:tt )* ) => ({
+        $crate::impl_modifier!(Verify, $( $inner )*)
+    });
+    ( +j $( $inner:tt )* ) => ({
+        $crate::impl_modifier!(NonZero, $( $inner )*)
+    });
+    ( +n $( $inner:tt )* ) => ({
+        $crate::impl_modifier!(ZeroNotEqual, $( $inner )*)
+    });
+    ( +t $( $inner:tt )* ) => ({
+        $crate::fragment!(and_v ( $( $inner )* ), ( true ) )
+    });
+    ( +l $( $inner:tt )* ) => ({
+        $crate::fragment!(or_i ( false ), ( $( $inner )* ) )
+    });
+    ( +u $( $inner:tt )* ) => ({
+        $crate::fragment!(or_i ( $( $inner )* ), ( false ) )
+    });
+
+    // Miniscript
+    ( true ) => ({
+        $crate::impl_leaf_opcode!(True)
+    });
+    ( false ) => ({
+        $crate::impl_leaf_opcode!(False)
+    });
+    ( pk_k $key:expr ) => ({
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+        $crate::keys::make_pk($key, &secp)
+    });
+    ( pk $key:expr ) => ({
+        $crate::fragment!(+c pk_k $key)
+    });
+    ( pk_h $key_hash:expr ) => ({
+        $crate::impl_leaf_opcode_value!(PkH, $key_hash)
+    });
+    ( after $value:expr ) => ({
+        $crate::impl_leaf_opcode_value!(After, $value)
+    });
+    ( older $value:expr ) => ({
+        $crate::impl_leaf_opcode_value!(Older, $value)
+    });
+    ( sha256 $hash:expr ) => ({
+        $crate::impl_leaf_opcode_value!(Sha256, $hash)
+    });
+    ( hash256 $hash:expr ) => ({
+        $crate::impl_leaf_opcode_value!(Hash256, $hash)
+    });
+    ( ripemd160 $hash:expr ) => ({
+        $crate::impl_leaf_opcode_value!(Ripemd160, $hash)
+    });
+    ( hash160 $hash:expr ) => ({
+        $crate::impl_leaf_opcode_value!(Hash160, $hash)
+    });
+    ( and_v ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(AndV, ( $( $a )* ), ( $( $b )* ))
+    });
+    ( and_b ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(AndB, ( $( $a )* ), ( $( $b )* ))
+    });
+    ( and_or ( $( $a:tt )* ), ( $( $b:tt )* ), ( $( $c:tt )* ) ) => ({
+        $crate::impl_node_opcode_three!(AndOr, ( $( $a )* ), ( $( $b )* ), ( $( $c )* ))
+    });
+    ( or_b ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrB, ( $( $a )* ), ( $( $b )* ))
+    });
+    ( or_d ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrD, ( $( $a )* ), ( $( $b )* ))
+    });
+    ( or_c ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrC, ( $( $a )* ), ( $( $b )* ))
+    });
+    ( or_i ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrI, ( $( $a )* ), ( $( $b )* ))
+    });
+    ( thresh_vec $thresh:expr, $items:expr ) => ({
+        use $crate::miniscript::descriptor::KeyMap;
+
+        let (items, key_maps_networks): (Vec<_>, Vec<_>) = $items.into_iter().map(|(a, b, c)| (a, (b, c))).unzip();
+        let items = items.into_iter().map(std::sync::Arc::new).collect();
+
+        let (key_maps, valid_networks) = key_maps_networks.into_iter().fold((KeyMap::default(), $crate::keys::any_network()), |(mut keys_acc, net_acc), (key, net)| {
+            keys_acc.extend(key.into_iter());
+            let net_acc = $crate::keys::merge_networks(&net_acc, &net);
+
+            (keys_acc, net_acc)
+        });
+
+        $crate::impl_leaf_opcode_value_two!(Thresh, $thresh, items)
+            .map(|(minisc, _, _)| (minisc, key_maps, valid_networks))
+    });
+    ( thresh $thresh:expr $(, ( $( $item:tt )* ) )+ ) => ({
+        let mut items = vec![];
+        $(
+            items.push($crate::fragment!($( $item )*));
+        )*
+
+        items.into_iter().collect::<Result<Vec<_>, _>>()
+            .and_then(|items| $crate::fragment!(thresh_vec $thresh, items))
+    });
+    ( multi_vec $thresh:expr, $keys:expr ) => ({
+        $crate::keys::make_multi($thresh, $keys)
+    });
+    ( multi $thresh:expr $(, $key:expr )+ ) => ({
+        use $crate::keys::ToDescriptorKey;
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+
+        let mut keys = vec![];
+        $(
+            keys.push($key.to_descriptor_key());
+        )*
+
+        keys.into_iter().collect::<Result<Vec<_>, _>>()
+            .and_then(|keys| $crate::keys::make_multi($thresh, keys, &secp))
+    });
+
+    // `sortedmulti()` is handled separately
+    ( sortedmulti $( $inner:tt )* ) => ({
+        compile_error!("`sortedmulti` can only be used as the root operand of a descriptor");
+    });
+    ( sortedmulti_vec $( $inner:tt )* ) => ({
+        compile_error!("`sortedmulti_vec` can only be used as the root operand of a descriptor");
+    });
+}
+
+#[cfg(test)]
+mod test {
+    use bitcoin::hashes::hex::ToHex;
+    use bitcoin::secp256k1::Secp256k1;
+    use miniscript::descriptor::{DescriptorPublicKey, DescriptorPublicKeyCtx, KeyMap};
+    use miniscript::{Descriptor, Legacy, Segwitv0};
+
+    use std::str::FromStr;
+
+    use crate::descriptor::DescriptorMeta;
+    use crate::keys::{DescriptorKey, KeyError, ToDescriptorKey, ValidNetworks};
+    use bitcoin::network::constants::Network::{Bitcoin, Regtest, Testnet};
+    use bitcoin::util::bip32;
+    use bitcoin::util::bip32::ChildNumber;
+
+    // test the descriptor!() macro
+
+    // verify descriptor generates expected script(s) (if bare or pk) or address(es)
+    fn check(
+        desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError>,
+        is_witness: bool,
+        is_fixed: bool,
+        expected: &[&str],
+    ) {
+        let secp = Secp256k1::new();
+        let deriv_ctx = DescriptorPublicKeyCtx::new(&secp, ChildNumber::Normal { index: 0 });
+
+        let (desc, _key_map, _networks) = desc.unwrap();
+        assert_eq!(desc.is_witness(), is_witness);
+        assert_eq!(desc.is_fixed(), is_fixed);
+        for i in 0..expected.len() {
+            let index = i as u32;
+            let child_desc = if desc.is_fixed() {
+                desc.clone()
+            } else {
+                desc.derive(ChildNumber::from_normal_idx(index).unwrap())
+            };
+            let address = child_desc.address(Regtest, deriv_ctx);
+            if let Some(address) = address {
+                assert_eq!(address.to_string(), *expected.get(i).unwrap());
+            } else {
+                let script = child_desc.script_pubkey(deriv_ctx);
+                assert_eq!(script.to_hex().as_str(), *expected.get(i).unwrap());
+            }
+        }
+    }
+
+    // - at least one of each "type" of operator; ie. one modifier, one leaf_opcode, one leaf_opcode_value, etc.
+    // - mixing up key types that implement ToDescriptorKey in multi() or thresh()
+
+    // expected script for pk and bare manually created
+    // expected addresses created with `bitcoin-cli getdescriptorinfo` (for hash) and `bitcoin-cli deriveaddresses`
+
+    #[test]
+    fn test_fixed_legacy_descriptors() {
+        let pubkey1 = bitcoin::PublicKey::from_str(
+            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
+        )
+        .unwrap();
+        let pubkey2 = bitcoin::PublicKey::from_str(
+            "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
+        )
+        .unwrap();
+
+        check(
+            descriptor!(bare(multi 1,pubkey1,pubkey2)),
+            false,
+            true,
+            &["512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd21032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af52ae"],
+        );
+        check(
+            descriptor!(pk(pubkey1)),
+            false,
+            true,
+            &["2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"],
+        );
+        check(
+            descriptor!(pkh(pubkey1)),
+            false,
+            true,
+            &["muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi"],
+        );
+        check(
+            descriptor!(sh(multi 1,pubkey1,pubkey2)),
+            false,
+            true,
+            &["2MymURoV1bzuMnWMGiXzyomDkeuxXY7Suey"],
+        );
+    }
+
+    #[test]
+    fn test_fixed_segwitv0_descriptors() {
+        let pubkey1 = bitcoin::PublicKey::from_str(
+            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
+        )
+        .unwrap();
+        let pubkey2 = bitcoin::PublicKey::from_str(
+            "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
+        )
+        .unwrap();
+
+        check(
+            descriptor!(wpkh(pubkey1)),
+            true,
+            true,
+            &["bcrt1qngw83fg8dz0k749cg7k3emc7v98wy0c7azaa6h"],
+        );
+        check(
+            descriptor!(sh(wpkh(pubkey1))),
+            true,
+            true,
+            &["2N5LiC3CqzxDamRTPG1kiNv1FpNJQ7x28sb"],
+        );
+        check(
+            descriptor!(wsh(multi 1,pubkey1,pubkey2)),
+            true,
+            true,
+            &["bcrt1qgw8jvv2hsrvjfa6q66rk6har7d32lrqm5unnf5cl63q9phxfvgps5fyfqe"],
+        );
+        check(
+            descriptor!(sh(wsh(multi 1,pubkey1,pubkey2))),
+            true,
+            true,
+            &["2NCidRJysy7apkmE6JF5mLLaJFkrN3Ub9iy"],
+        );
+    }
+
+    #[test]
+    fn test_bip32_legacy_descriptors() {
+        let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+
+        let path = bip32::DerivationPath::from_str("m/0").unwrap();
+        let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap();
+        check(
+            descriptor!(pk(desc_key)),
+            false,
+            false,
+            &[
+                "2102363ad03c10024e1b597a5b01b9982807fb638e00b06f3b2d4a89707de3b93c37ac",
+                "2102063a21fd780df370ed2fc8c4b86aa5ea642630609c203009df631feb7b480dd2ac",
+                "2102ba2685ad1fa5891cb100f1656b2ce3801822ccb9bac0336734a6f8c1b93ebbc0ac",
+            ],
+        );
+
+        let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap();
+        check(
+            descriptor!(pkh(desc_key)),
+            false,
+            false,
+            &[
+                "muvBdsVpJxpFuTHMKA47htJPdCvdt4F9DP",
+                "mxQSHK7DL2t1DN3xFxov1janCoXSSkrSPj",
+                "mfz43r15GiWo4nizmyzMNubsnkDpByFFAn",
+            ],
+        );
+
+        let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap();
+        let desc_key1 = (xprv, path).to_descriptor_key().unwrap();
+        let desc_key2 = (xprv, path2).to_descriptor_key().unwrap();
+
+        check(
+            descriptor!(sh(multi 1,desc_key1,desc_key2)),
+            false,
+            false,
+            &[
+                "2MtMDXsfwefZkEEhVViEPidvcKRUtJamJJ8",
+                "2MwAUZ1NYyWjhVvGTethFL6n7nZhS8WE6At",
+                "2MuT6Bj66HLwZd7s4SoD8XbK4GwriKEA6Gr",
+            ],
+        );
+    }
+
+    #[test]
+    fn test_bip32_segwitv0_descriptors() {
+        let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+
+        let path = bip32::DerivationPath::from_str("m/0").unwrap();
+        let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap();
+        check(
+            descriptor!(wpkh(desc_key)),
+            true,
+            false,
+            &[
+                "bcrt1qnhm8w9fhc8cxzgqsmqdf9fyjccyvc0gltnymu0",
+                "bcrt1qhylfd55rn75w9fj06zspctad5w4hz33rf0ttad",
+                "bcrt1qq5sq3a6k9av9d8cne0k9wcldy4nqey5yt6889r",
+            ],
+        );
+
+        let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap();
+        check(
+            descriptor!(sh(wpkh(desc_key))),
+            true,
+            false,
+            &[
+                "2MxvjQCaLqZ5QxZ7XotZDQ63hZw3NPss763",
+                "2NDUoevN4QMzhvHDMGhKuiT2fN9HXbFRMwn",
+                "2NF4BEAY2jF1Fu8vqfN3NVKoFtom77pUxrx",
+            ],
+        );
+
+        let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap();
+        let desc_key1 = (xprv, path.clone()).to_descriptor_key().unwrap();
+        let desc_key2 = (xprv, path2.clone()).to_descriptor_key().unwrap();
+        check(
+            descriptor!(wsh(multi 1,desc_key1,desc_key2)),
+            true,
+            false,
+            &[
+                "bcrt1qfxv8mxmlv5sz8q2mnuyaqdfe9jr4vvmx0csjhn092p6f4qfygfkq2hng49",
+                "bcrt1qerj85g243e6jlcdxpmn9spk0gefcwvu7nw7ee059d5ydzpdhkm2qwfkf5k",
+                "bcrt1qxkl2qss3k58q9ktc8e89pwr4gnptfpw4hju4xstxcjc0hkcae3jstluty7",
+            ],
+        );
+
+        let desc_key1 = (xprv, path).to_descriptor_key().unwrap();
+        let desc_key2 = (xprv, path2).to_descriptor_key().unwrap();
+        check(
+            descriptor!(sh(wsh(multi 1,desc_key1,desc_key2))),
+            true,
+            false,
+            &[
+                "2NFCtXvx9q4ci2kvKub17iSTgvRXGctCGhz",
+                "2NB2PrFPv5NxWCpygas8tPrGJG2ZFgeuwJw",
+                "2N79ZAGo5cMi5Jt7Wo9L5YmF5GkEw7sjWdC",
+            ],
+        );
+    }
+
+    #[test]
+    fn test_dsl_sortedmulti() {
+        let key_1 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+        let path_1 = bip32::DerivationPath::from_str("m/0").unwrap();
+
+        let key_2 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
+        let path_2 = bip32::DerivationPath::from_str("m/1").unwrap();
+
+        let desc_key1 = (key_1, path_1);
+        let desc_key2 = (key_2, path_2);
+
+        check(
+            descriptor!(sh(sortedmulti 1, desc_key1.clone(), desc_key2.clone())),
+            false,
+            false,
+            &[
+                "2MsxzPEJDBzpGffJXPaDpfXZAUNnZhaMh2N",
+                "2My3x3DLPK3UbGWGpxrXr1RnbD8MNC4FpgS",
+                "2NByEuiQT7YLqHCTNxL5KwYjvtuCYcXNBSC",
+                "2N1TGbP81kj2VUKTSWgrwxoMfuWjvfUdyu7",
+                "2N3Bomq2fpAcLRNfZnD3bCWK9quan28CxCR",
+                "2N9nrZaEzEFDqEAU9RPvDnXGT6AVwBDKAQb",
+            ],
+        );
+
+        check(
+            descriptor!(sh(wsh(sortedmulti 1, desc_key1.clone(), desc_key2.clone()))),
+            true,
+            false,
+            &[
+                "2NCogc5YyM4N6ruv1hUa7WLMW1BPeCK7N9B",
+                "2N6mkSAKi1V2oaBXby7XHdvBMKEDRQcFpNe",
+                "2NFmTSttm9v6bXeoWaBvpMcgfPQcZhNn3Eh",
+                "2Mvib87RBPUHXNEpX5S5Kv1qqrhBfgBGsJM",
+                "2MtMv5mcK2EjcLsH8Txpx2JxLLzHr4ttczL",
+                "2MsWCB56rb4T6yPv8QudZGHERTwNgesE4f6",
+            ],
+        );
+
+        check(
+            descriptor!(wsh(sortedmulti_vec 1, vec![desc_key1, desc_key2])),
+            true,
+            false,
+            &[
+                "bcrt1qcvq0lg8q7a47ytrd7zk5y7uls7mulrenjgvflwylpppgwf8029es4vhpnj",
+                "bcrt1q80yn8sdt6l7pjvkz25lglyaqctlmsq9ugk80rmxt8yu0npdsj97sc7l4de",
+                "bcrt1qrvf6024v9s50qhffe3t2fr2q9ckdhx2g6jz32chm2pp24ymgtr5qfrdmct",
+                "bcrt1q6srfmra0ynypym35c7jvsxt2u4yrugeajq95kg2ps7lk6h2gaunsq9lzxn",
+                "bcrt1qhl8rrzzcdpu7tcup3lcg7tge52sqvwy5fcv4k78v6kxtwmqf3v6qpvyjza",
+                "bcrt1ql2elz9mhm9ll27ddpewhxs732xyl2fk2kpkqz9gdyh33wgcun4vstrd49k",
+            ],
+        );
+    }
+
+    // - verify the valid_networks returned is correctly computed based on the keys present in the descriptor
+    #[test]
+    fn test_valid_networks() {
+        let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+        let path = bip32::DerivationPath::from_str("m/0").unwrap();
+        let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap();
+
+        let (_desc, _key_map, valid_networks) = descriptor!(pkh(desc_key)).unwrap();
+        assert_eq!(valid_networks, [Testnet, Regtest].iter().cloned().collect());
+
+        let xprv = bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap();
+        let path = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap();
+        let desc_key = (xprv, path.clone()).to_descriptor_key().unwrap();
+
+        let (_desc, _key_map, valid_networks) = descriptor!(wpkh(desc_key)).unwrap();
+        assert_eq!(valid_networks, [Bitcoin].iter().cloned().collect());
+    }
+
+    // - verify the key_maps are correctly merged together
+    #[test]
+    fn test_key_maps_merged() {
+        let secp = Secp256k1::new();
+
+        let xprv1 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+        let path1 = bip32::DerivationPath::from_str("m/0").unwrap();
+        let desc_key1 = (xprv1, path1.clone()).to_descriptor_key().unwrap();
+
+        let xprv2 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
+        let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap();
+        let desc_key2 = (xprv2, path2.clone()).to_descriptor_key().unwrap();
+
+        let xprv3 = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf").unwrap();
+        let path3 = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap();
+        let desc_key3 = (xprv3, path3.clone()).to_descriptor_key().unwrap();
+
+        let (_desc, key_map, _valid_networks) =
+            descriptor!(sh(wsh(multi 2,desc_key1,desc_key2,desc_key3))).unwrap();
+        assert_eq!(key_map.len(), 3);
+
+        let desc_key1: DescriptorKey<Segwitv0> =
+            (xprv1, path1.clone()).to_descriptor_key().unwrap();
+        let desc_key2: DescriptorKey<Segwitv0> =
+            (xprv2, path2.clone()).to_descriptor_key().unwrap();
+        let desc_key3: DescriptorKey<Segwitv0> =
+            (xprv3, path3.clone()).to_descriptor_key().unwrap();
+
+        let (key1, _key_map, _valid_networks) = desc_key1.extract(&secp).unwrap();
+        let (key2, _key_map, _valid_networks) = desc_key2.extract(&secp).unwrap();
+        let (key3, _key_map, _valid_networks) = desc_key3.extract(&secp).unwrap();
+        assert_eq!(key_map.get(&key1).unwrap().to_string(), "tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/0/*");
+        assert_eq!(key_map.get(&key2).unwrap().to_string(), "tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF/2147483647'/0/*");
+        assert_eq!(key_map.get(&key3).unwrap().to_string(), "tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf/10/20/30/40/*");
+    }
+
+    // - verify the ScriptContext is correctly validated (i.e. passing a type that only impl ToDescriptorKey<Segwitv0> to a pkh() descriptor should throw a compilation error
+    #[test]
+    fn test_script_context_validation() {
+        // this compiles
+        let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+        let path = bip32::DerivationPath::from_str("m/0").unwrap();
+        let desc_key: DescriptorKey<Legacy> = (xprv, path.clone()).to_descriptor_key().unwrap();
+
+        let (desc, _key_map, _valid_networks) = descriptor!(pkh(desc_key)).unwrap();
+        assert_eq!(desc.to_string(), "pkh(tpubD6NzVbkrYhZ4WR7a4vY1VT3khMJMeAxVsfq9TBJyJWrNk247zCJtV7AWf6UJP7rAVsn8NNKdJi3gFyKPTmWZS9iukb91xbn2HbFSMQm2igY/0/*)");
+
+        // as expected this does not compile due to invalid context
+        //let desc_key:DescriptorKey<Segwitv0> = (xprv, path.clone()).to_descriptor_key().unwrap();
+        //let (desc, _key_map, _valid_networks) = descriptor!(pkh(desc_key)).unwrap();
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/error.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/error.rs.html new file mode 100644 index 0000000000..2472440c46 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/error.rs.html @@ -0,0 +1,176 @@ +error.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Descriptor errors
+
+/// Errors related to the parsing and usage of descriptors
+#[derive(Debug)]
+pub enum Error {
+    //InternalError,
+    //InvalidPrefix(Vec<u8>),
+    //HardenedDerivationOnXpub,
+    //MalformedInput,
+    /// Invalid HD Key path, such as having a wildcard but a length != 1
+    InvalidHDKeyPath,
+
+    //KeyParsingError(String),
+    /// Error thrown while working with [`keys`](crate::keys)
+    Key(crate::keys::KeyError),
+    /// Error while extracting and manipulating policies
+    Policy(crate::descriptor::policy::PolicyError),
+
+    //InputIndexDoesntExist,
+    //MissingPublicKey,
+    //MissingDetails,
+    /// Invalid character found in the descriptor checksum
+    InvalidDescriptorCharacter(char),
+
+    //CantDeriveWithMiniscript,
+    /// BIP32 error
+    BIP32(bitcoin::util::bip32::Error),
+    /// Error during base58 decoding
+    Base58(bitcoin::util::base58::Error),
+    /// Key-related error
+    PK(bitcoin::util::key::Error),
+    /// Miniscript error
+    Miniscript(miniscript::Error),
+    /// Hex decoding error
+    Hex(bitcoin::hashes::hex::Error),
+}
+
+impl From<crate::keys::KeyError> for Error {
+    fn from(key_error: crate::keys::KeyError) -> Error {
+        match key_error {
+            crate::keys::KeyError::Miniscript(inner) => Error::Miniscript(inner),
+            crate::keys::KeyError::BIP32(inner) => Error::BIP32(inner),
+            e => Error::Key(e),
+        }
+    }
+}
+
+impl std::fmt::Display for Error {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl std::error::Error for Error {}
+
+impl_error!(bitcoin::util::bip32::Error, BIP32);
+impl_error!(bitcoin::util::base58::Error, Base58);
+impl_error!(bitcoin::util::key::Error, PK);
+impl_error!(miniscript::Error, Miniscript);
+impl_error!(bitcoin::hashes::hex::Error, Hex);
+impl_error!(crate::descriptor::policy::PolicyError, Policy);
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/mod.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/mod.rs.html new file mode 100644 index 0000000000..22803d1c76 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/mod.rs.html @@ -0,0 +1,1560 @@ +mod.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Descriptors
+//!
+//! This module contains generic utilities to work with descriptors, plus some re-exported types
+//! from [`miniscript`].
+
+use std::collections::{BTreeMap, HashMap};
+use std::fmt;
+
+use bitcoin::secp256k1::Secp256k1;
+use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint, KeySource};
+use bitcoin::util::psbt;
+use bitcoin::{Network, PublicKey, Script, TxOut};
+
+use miniscript::descriptor::{DescriptorPublicKey, DescriptorXKey, InnerXKey};
+pub use miniscript::{
+    descriptor::KeyMap, Descriptor, Legacy, Miniscript, MiniscriptKey, ScriptContext, Segwitv0,
+    Terminal, ToPublicKey,
+};
+
+pub mod checksum;
+mod dsl;
+pub mod error;
+pub mod policy;
+pub mod template;
+
+pub use self::checksum::get_checksum;
+use self::error::Error;
+pub use self::policy::Policy;
+use self::template::DescriptorTemplateOut;
+use crate::keys::{KeyError, ToDescriptorKey};
+use crate::wallet::signer::SignersContainer;
+use crate::wallet::utils::{descriptor_to_pk_ctx, SecpCtx};
+
+/// Alias for a [`Descriptor`] that can contain extended keys using [`DescriptorPublicKey`]
+pub type ExtendedDescriptor = Descriptor<DescriptorPublicKey>;
+
+/// Alias for the type of maps that represent derivation paths in a [`psbt::Input`] or
+/// [`psbt::Output`]
+///
+/// [`psbt::Input`]: bitcoin::util::psbt::Input
+/// [`psbt::Output`]: bitcoin::util::psbt::Output
+pub type HDKeyPaths = BTreeMap<PublicKey, KeySource>;
+
+/// Trait for types which can be converted into an [`ExtendedDescriptor`] and a [`KeyMap`] usable by a wallet in a specific [`Network`]
+pub trait ToWalletDescriptor {
+    /// Convert to wallet descriptor
+    fn to_wallet_descriptor(
+        self,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), KeyError>;
+}
+
+impl ToWalletDescriptor for &str {
+    fn to_wallet_descriptor(
+        self,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+        let descriptor = if self.contains('#') {
+            let parts: Vec<&str> = self.splitn(2, '#').collect();
+            if !get_checksum(parts[0])
+                .ok()
+                .map(|computed| computed == parts[1])
+                .unwrap_or(false)
+            {
+                return Err(KeyError::InvalidChecksum);
+            }
+
+            parts[0]
+        } else {
+            self
+        };
+
+        ExtendedDescriptor::parse_descriptor(descriptor)?.to_wallet_descriptor(network)
+    }
+}
+
+impl ToWalletDescriptor for &String {
+    fn to_wallet_descriptor(
+        self,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+        self.as_str().to_wallet_descriptor(network)
+    }
+}
+
+impl ToWalletDescriptor for ExtendedDescriptor {
+    fn to_wallet_descriptor(
+        self,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+        (self, KeyMap::default()).to_wallet_descriptor(network)
+    }
+}
+
+impl ToWalletDescriptor for (ExtendedDescriptor, KeyMap) {
+    fn to_wallet_descriptor(
+        self,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+        use crate::keys::DescriptorKey;
+
+        let secp = Secp256k1::new();
+
+        let check_key = |pk: &DescriptorPublicKey| {
+            let (pk, _, networks) = if self.0.is_witness() {
+                let desciptor_key: DescriptorKey<miniscript::Segwitv0> =
+                    pk.clone().to_descriptor_key()?;
+                desciptor_key.extract(&secp)?
+            } else {
+                let desciptor_key: DescriptorKey<miniscript::Legacy> =
+                    pk.clone().to_descriptor_key()?;
+                desciptor_key.extract(&secp)?
+            };
+
+            if networks.contains(&network) {
+                Ok(pk)
+            } else {
+                Err(KeyError::InvalidNetwork)
+            }
+        };
+
+        // check the network for the keys
+        let translated = self.0.translate_pk(check_key, check_key)?;
+
+        Ok((translated, self.1))
+    }
+}
+
+impl ToWalletDescriptor for DescriptorTemplateOut {
+    fn to_wallet_descriptor(
+        self,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+        let valid_networks = &self.2;
+
+        let fix_key = |pk: &DescriptorPublicKey| {
+            if valid_networks.contains(&network) {
+                // workaround for xpubs generated by other key types, like bip39: since when the
+                // conversion is made one network has to be chosen, what we generally choose
+                // "mainnet", but then override the set of valid networks to specify that all of
+                // them are valid. here we reset the network to make sure the wallet struct gets a
+                // descriptor with the right network everywhere.
+                let pk = match pk {
+                    DescriptorPublicKey::XPub(ref xpub) => {
+                        let mut xpub = xpub.clone();
+                        xpub.xkey.network = network;
+
+                        DescriptorPublicKey::XPub(xpub)
+                    }
+                    other => other.clone(),
+                };
+
+                Ok(pk)
+            } else {
+                Err(KeyError::InvalidNetwork)
+            }
+        };
+
+        // fixup the network for keys that need it
+        let translated = self.0.translate_pk(fix_key, fix_key)?;
+
+        Ok((translated, self.1))
+    }
+}
+
+/// Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`]
+pub trait ExtractPolicy {
+    /// Extract the spending [`policy`]
+    fn extract_policy(
+        &self,
+        signers: &SignersContainer,
+        secp: &SecpCtx,
+    ) -> Result<Option<Policy>, Error>;
+}
+
+pub(crate) trait XKeyUtils {
+    fn full_path(&self, append: &[ChildNumber]) -> DerivationPath;
+    fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint;
+}
+
+impl<K: InnerXKey> XKeyUtils for DescriptorXKey<K> {
+    fn full_path(&self, append: &[ChildNumber]) -> DerivationPath {
+        let full_path = match self.origin {
+            Some((_, ref path)) => path
+                .into_iter()
+                .chain(self.derivation_path.into_iter())
+                .cloned()
+                .collect(),
+            None => self.derivation_path.clone(),
+        };
+
+        if self.is_wildcard {
+            full_path
+                .into_iter()
+                .chain(append.iter())
+                .cloned()
+                .collect()
+        } else {
+            full_path
+        }
+    }
+
+    fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint {
+        match self.origin {
+            Some((fingerprint, _)) => fingerprint,
+            None => self.xkey.xkey_fingerprint(secp),
+        }
+    }
+}
+
+pub(crate) trait DescriptorMeta: Sized {
+    fn is_witness(&self) -> bool;
+    fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, Error>;
+    fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, Error>;
+    fn is_fixed(&self) -> bool;
+    fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths, secp: &SecpCtx) -> Option<Self>;
+    fn derive_from_psbt_input(
+        &self,
+        psbt_input: &psbt::Input,
+        utxo: Option<TxOut>,
+        secp: &SecpCtx,
+    ) -> Option<Self>;
+}
+
+pub(crate) trait DescriptorScripts {
+    fn psbt_redeem_script(&self, secp: &SecpCtx) -> Option<Script>;
+    fn psbt_witness_script(&self, secp: &SecpCtx) -> Option<Script>;
+}
+
+impl DescriptorScripts for Descriptor<DescriptorPublicKey> {
+    fn psbt_redeem_script(&self, secp: &SecpCtx) -> Option<Script> {
+        let deriv_ctx = descriptor_to_pk_ctx(secp);
+
+        match self {
+            Descriptor::ShWpkh(_) => Some(self.witness_script(deriv_ctx)),
+            Descriptor::ShWsh(ref script) => Some(script.encode(deriv_ctx).to_v0_p2wsh()),
+            Descriptor::Sh(ref script) => Some(script.encode(deriv_ctx)),
+            Descriptor::Bare(ref script) => Some(script.encode(deriv_ctx)),
+            Descriptor::ShSortedMulti(ref keys) => Some(keys.encode(deriv_ctx)),
+            _ => None,
+        }
+    }
+
+    fn psbt_witness_script(&self, secp: &SecpCtx) -> Option<Script> {
+        let deriv_ctx = descriptor_to_pk_ctx(secp);
+
+        match self {
+            Descriptor::Wsh(ref script) => Some(script.encode(deriv_ctx)),
+            Descriptor::ShWsh(ref script) => Some(script.encode(deriv_ctx)),
+            Descriptor::WshSortedMulti(ref keys) | Descriptor::ShWshSortedMulti(ref keys) => {
+                Some(keys.encode(deriv_ctx))
+            }
+            _ => None,
+        }
+    }
+}
+
+impl DescriptorMeta for Descriptor<DescriptorPublicKey> {
+    fn is_witness(&self) -> bool {
+        match self {
+            Descriptor::Bare(_)
+            | Descriptor::Pk(_)
+            | Descriptor::Pkh(_)
+            | Descriptor::Sh(_)
+            | Descriptor::ShSortedMulti(_) => false,
+            Descriptor::Wpkh(_)
+            | Descriptor::ShWpkh(_)
+            | Descriptor::Wsh(_)
+            | Descriptor::ShWsh(_)
+            | Descriptor::ShWshSortedMulti(_)
+            | Descriptor::WshSortedMulti(_) => true,
+        }
+    }
+
+    fn get_hd_keypaths(&self, index: u32, secp: &SecpCtx) -> Result<HDKeyPaths, Error> {
+        let translate_key = |key: &DescriptorPublicKey,
+                             index: u32,
+                             paths: &mut HDKeyPaths|
+         -> Result<DummyKey, Error> {
+            match key {
+                DescriptorPublicKey::SinglePub(_) => {}
+                DescriptorPublicKey::XPub(xpub) => {
+                    let derive_path = if xpub.is_wildcard {
+                        xpub.derivation_path
+                            .into_iter()
+                            .chain([ChildNumber::from_normal_idx(index)?].iter())
+                            .cloned()
+                            .collect()
+                    } else {
+                        xpub.derivation_path.clone()
+                    };
+                    let derived_pubkey = xpub
+                        .xkey
+                        .derive_pub(&Secp256k1::verification_only(), &derive_path)?;
+
+                    paths.insert(
+                        derived_pubkey.public_key,
+                        (
+                            xpub.root_fingerprint(secp),
+                            xpub.full_path(&[ChildNumber::from_normal_idx(index)?]),
+                        ),
+                    );
+                }
+            }
+
+            Ok(DummyKey::default())
+        };
+
+        let mut answer_pk = BTreeMap::new();
+        let mut answer_pkh = BTreeMap::new();
+
+        self.translate_pk(
+            |pk| translate_key(pk, index, &mut answer_pk),
+            |pkh| translate_key(pkh, index, &mut answer_pkh),
+        )?;
+
+        answer_pk.append(&mut answer_pkh);
+
+        Ok(answer_pk)
+    }
+
+    fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, Error> {
+        let get_key = |key: &DescriptorPublicKey,
+                       keys: &mut Vec<DescriptorXKey<ExtendedPubKey>>|
+         -> Result<DummyKey, Error> {
+            if let DescriptorPublicKey::XPub(xpub) = key {
+                keys.push(xpub.clone())
+            }
+
+            Ok(DummyKey::default())
+        };
+
+        let mut answer_pk = Vec::new();
+        let mut answer_pkh = Vec::new();
+
+        self.translate_pk(
+            |pk| get_key(pk, &mut answer_pk),
+            |pkh| get_key(pkh, &mut answer_pkh),
+        )?;
+
+        answer_pk.append(&mut answer_pkh);
+
+        Ok(answer_pk)
+    }
+
+    fn is_fixed(&self) -> bool {
+        fn check_key(key: &DescriptorPublicKey, flag: &mut bool) -> Result<DummyKey, Error> {
+            match key {
+                DescriptorPublicKey::SinglePub(_) => {}
+                DescriptorPublicKey::XPub(xpub) => {
+                    if xpub.is_wildcard {
+                        *flag = true;
+                    }
+                }
+            }
+
+            Ok(DummyKey::default())
+        }
+
+        let mut found_wildcard_pk = false;
+        let mut found_wildcard_pkh = false;
+
+        self.translate_pk(
+            |pk| check_key(pk, &mut found_wildcard_pk),
+            |pkh| check_key(pkh, &mut found_wildcard_pkh),
+        )
+        .unwrap();
+
+        !found_wildcard_pk && !found_wildcard_pkh
+    }
+
+    fn derive_from_hd_keypaths(&self, hd_keypaths: &HDKeyPaths, secp: &SecpCtx) -> Option<Self> {
+        let try_key = |key: &DescriptorPublicKey,
+                       index: &HashMap<Fingerprint, DerivationPath>,
+                       found_path: &mut Option<ChildNumber>|
+         -> Result<DummyKey, Error> {
+            if found_path.is_some() {
+                // already found a matching path, we are done
+                return Ok(DummyKey::default());
+            }
+
+            if let DescriptorPublicKey::XPub(xpub) = key {
+                // Check if the key matches one entry in our `index`. If it does, `matches()` will
+                // return the "prefix" that matched, so we remove that prefix from the full path
+                // found in `index` and save it in `derive_path`. We expect this to be a derivation
+                // path of length 1 if the key `is_wildcard` and an empty path otherwise.
+                let root_fingerprint = xpub.root_fingerprint(secp);
+                let derivation_path: Option<Vec<ChildNumber>> = index
+                    .get_key_value(&root_fingerprint)
+                    .and_then(|(fingerprint, path)| {
+                        xpub.matches(&(*fingerprint, path.clone()), secp)
+                    })
+                    .map(|prefix| {
+                        index
+                            .get(&xpub.root_fingerprint(secp))
+                            .unwrap()
+                            .into_iter()
+                            .skip(prefix.into_iter().count())
+                            .cloned()
+                            .collect()
+                    });
+
+                match derivation_path {
+                    Some(path) if xpub.is_wildcard && path.len() == 1 => {
+                        *found_path = Some(path[0])
+                    }
+                    Some(path) if !xpub.is_wildcard && path.is_empty() => {
+                        *found_path = Some(ChildNumber::Normal { index: 0 })
+                    }
+                    Some(_) => return Err(Error::InvalidHDKeyPath),
+                    _ => {}
+                }
+            }
+
+            Ok(DummyKey::default())
+        };
+
+        let index: HashMap<_, _> = hd_keypaths.values().cloned().collect();
+
+        let mut found_path_pk = None;
+        let mut found_path_pkh = None;
+
+        if self
+            .translate_pk(
+                |pk| try_key(pk, &index, &mut found_path_pk),
+                |pkh| try_key(pkh, &index, &mut found_path_pkh),
+            )
+            .is_err()
+        {
+            return None;
+        }
+
+        // if we have found a path for both `found_path_pk` and `found_path_pkh` but they are
+        // different we consider this an error and return None. we only return a path either if
+        // they are equal or if only one of them is Some(_)
+        let merged_path = match (found_path_pk, found_path_pkh) {
+            (Some(a), Some(b)) if a != b => return None,
+            (a, b) => a.or(b),
+        };
+
+        merged_path.map(|path| self.derive(path))
+    }
+
+    fn derive_from_psbt_input(
+        &self,
+        psbt_input: &psbt::Input,
+        utxo: Option<TxOut>,
+        secp: &SecpCtx,
+    ) -> Option<Self> {
+        if let Some(derived) = self.derive_from_hd_keypaths(&psbt_input.hd_keypaths, secp) {
+            return Some(derived);
+        } else if !self.is_fixed() {
+            // If the descriptor is not fixed we can't brute-force the derivation address, so just
+            // exit here
+            return None;
+        }
+
+        let deriv_ctx = descriptor_to_pk_ctx(secp);
+        match self {
+            Descriptor::Pk(_)
+            | Descriptor::Pkh(_)
+            | Descriptor::Wpkh(_)
+            | Descriptor::ShWpkh(_)
+                if utxo.is_some()
+                    && self.script_pubkey(deriv_ctx) == utxo.as_ref().unwrap().script_pubkey =>
+            {
+                Some(self.clone())
+            }
+            Descriptor::Bare(ms)
+                if psbt_input.redeem_script.is_some()
+                    && &ms.encode(deriv_ctx) == psbt_input.redeem_script.as_ref().unwrap() =>
+            {
+                Some(self.clone())
+            }
+            Descriptor::Sh(ms)
+                if psbt_input.redeem_script.is_some()
+                    && &ms.encode(deriv_ctx) == psbt_input.redeem_script.as_ref().unwrap() =>
+            {
+                Some(self.clone())
+            }
+            Descriptor::Wsh(ms) | Descriptor::ShWsh(ms)
+                if psbt_input.witness_script.is_some()
+                    && &ms.encode(deriv_ctx) == psbt_input.witness_script.as_ref().unwrap() =>
+            {
+                Some(self.clone())
+            }
+            Descriptor::ShSortedMulti(keys)
+                if psbt_input.redeem_script.is_some()
+                    && &keys.encode(deriv_ctx) == psbt_input.redeem_script.as_ref().unwrap() =>
+            {
+                Some(self.clone())
+            }
+            Descriptor::WshSortedMulti(keys) | Descriptor::ShWshSortedMulti(keys)
+                if psbt_input.witness_script.is_some()
+                    && &keys.encode(deriv_ctx) == psbt_input.witness_script.as_ref().unwrap() =>
+            {
+                Some(self.clone())
+            }
+            _ => None,
+        }
+    }
+}
+
+#[derive(Debug, Clone, Hash, PartialEq, PartialOrd, Eq, Ord, Default)]
+struct DummyKey();
+
+impl fmt::Display for DummyKey {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "DummyKey")
+    }
+}
+
+impl std::str::FromStr for DummyKey {
+    type Err = ();
+
+    fn from_str(_: &str) -> Result<Self, Self::Err> {
+        Ok(DummyKey::default())
+    }
+}
+
+impl miniscript::MiniscriptKey for DummyKey {
+    type Hash = DummyKey;
+
+    fn to_pubkeyhash(&self) -> DummyKey {
+        DummyKey::default()
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::str::FromStr;
+
+    use bitcoin::consensus::encode::deserialize;
+    use bitcoin::hashes::hex::FromHex;
+    use bitcoin::secp256k1::Secp256k1;
+    use bitcoin::util::{bip32, psbt};
+
+    use super::*;
+    use crate::psbt::PSBTUtils;
+
+    #[test]
+    fn test_derive_from_psbt_input_wpkh_wif() {
+        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
+            "wpkh(02b4632d08485ff1df2db55b9dafd23347d1c47a457072a1e87be26896549a8737)",
+        )
+        .unwrap();
+        let psbt: psbt::PartiallySignedTransaction = deserialize(
+            &Vec::<u8>::from_hex(
+                "70736274ff010052010000000162307be8e431fbaff807cdf9cdc3fde44d7402\
+                 11bc8342c31ffd6ec11fe35bcc0100000000ffffffff01328601000000000016\
+                 001493ce48570b55c42c2af816aeaba06cfee1224fae000000000001011fa086\
+                 01000000000016001493ce48570b55c42c2af816aeaba06cfee1224fae010304\
+                 010000000000",
+            )
+            .unwrap(),
+        )
+        .unwrap();
+
+        assert!(descriptor
+            .derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
+            .is_some());
+    }
+
+    #[test]
+    fn test_derive_from_psbt_input_pkh_tpub() {
+        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
+            "pkh([0f056943/44h/0h/0h]tpubDDpWvmUrPZrhSPmUzCMBHffvC3HyMAPnWDSAQNBTnj1iZeJa7BZQEttFiP4DS4GCcXQHezdXhn86Hj6LHX5EDstXPWrMaSneRWM8yUf6NFd/10/*)",
+        )
+        .unwrap();
+        let psbt: psbt::PartiallySignedTransaction = deserialize(
+            &Vec::<u8>::from_hex(
+                "70736274ff010053010000000145843b86be54a3cd8c9e38444e1162676c00df\
+                 e7964122a70df491ea12fd67090100000000ffffffff01c19598000000000017\
+                 a91432bb94283282f72b2e034709e348c44d5a4db0ef8700000000000100f902\
+                 0000000001010167e99c0eb67640f3a1b6805f2d8be8238c947f8aaf49eb0a9c\
+                 bee6a42c984200000000171600142b29a22019cca05b9c2b2d283a4c4489e1cf\
+                 9f8ffeffffff02a01dced06100000017a914e2abf033cadbd74f0f4c74946201\
+                 decd20d5c43c8780969800000000001976a9148b0fce5fb1264e599a65387313\
+                 3c95478b902eb288ac02473044022015d9211576163fa5b001e84dfa3d44efd9\
+                 86b8f3a0d3d2174369288b2b750906022048dacc0e5d73ae42512fd2b97e2071\
+                 a8d0bce443b390b1fe0b8128fe70ec919e01210232dad1c5a67dcb0116d407e2\
+                 52584228ab7ec00e8b9779d0c3ffe8114fc1a7d2c80600000103040100000022\
+                 0603433b83583f8c4879b329dd08bbc7da935e4cc02f637ff746e05f0466ffb2\
+                 a6a2180f0569432c00008000000080000000800a000000000000000000",
+            )
+            .unwrap(),
+        )
+        .unwrap();
+
+        assert!(descriptor
+            .derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
+            .is_some());
+    }
+
+    #[test]
+    fn test_derive_from_psbt_input_wsh() {
+        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
+            "wsh(and_v(v:pk(03b6633fef2397a0a9de9d7b6f23aef8368a6e362b0581f0f0af70d5ecfd254b14),older(6)))",
+        )
+        .unwrap();
+        let psbt: psbt::PartiallySignedTransaction = deserialize(
+            &Vec::<u8>::from_hex(
+                "70736274ff01005302000000011c8116eea34408ab6529223c9a176606742207\
+                 67a1ff1d46a6e3c4a88243ea6e01000000000600000001109698000000000017\
+                 a914ad105f61102e0d01d7af40d06d6a5c3ae2f7fde387000000000001012b80\
+                 969800000000002200203ca72f106a72234754890ca7640c43f65d2174e44d33\
+                 336030f9059345091044010304010000000105252103b6633fef2397a0a9de9d\
+                 7b6f23aef8368a6e362b0581f0f0af70d5ecfd254b14ad56b20000",
+            )
+            .unwrap(),
+        )
+        .unwrap();
+
+        assert!(descriptor
+            .derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
+            .is_some());
+    }
+
+    #[test]
+    fn test_derive_from_psbt_input_sh() {
+        let descriptor = Descriptor::<DescriptorPublicKey>::from_str(
+            "sh(and_v(v:pk(021403881a5587297818fcaf17d239cefca22fce84a45b3b1d23e836c4af671dbb),after(630000)))",
+        )
+        .unwrap();
+        let psbt: psbt::PartiallySignedTransaction = deserialize(
+            &Vec::<u8>::from_hex(
+                "70736274ff0100530100000001bc8c13df445dfadcc42afa6dc841f85d22b01d\
+                 a6270ebf981740f4b7b1d800390000000000feffffff01ba9598000000000017\
+                 a91457b148ba4d3e5fa8608a8657875124e3d1c9390887f09c0900000100e002\
+                 0000000001016ba1bbe05cc93574a0d611ec7d93ad0ab6685b28d0cd80e8a82d\
+                 debb326643c90100000000feffffff02809698000000000017a914d9a6e8c455\
+                 8e16c8253afe53ce37ad61cf4c38c487403504cf6100000017a9144044fb6e0b\
+                 757dfc1b34886b6a95aef4d3db137e870247304402202a9b72d939bcde8ba2a1\
+                 e0980597e47af4f5c152a78499143c3d0a78ac2286a602207a45b1df9e93b8c9\
+                 6f09f5c025fe3e413ca4b905fe65ee55d32a3276439a9b8f012102dc1fcc2636\
+                 4da1aa718f03d8d9bd6f2ff410ed2cf1245a168aa3bcc995ac18e0a806000001\
+                 03040100000001042821021403881a5587297818fcaf17d239cefca22fce84a4\
+                 5b3b1d23e836c4af671dbbad03f09c09b10000",
+            )
+            .unwrap(),
+        )
+        .unwrap();
+
+        assert!(descriptor
+            .derive_from_psbt_input(&psbt.inputs[0], psbt.get_utxo_for(0), &Secp256k1::new())
+            .is_some());
+    }
+
+    #[test]
+    fn test_to_wallet_descriptor_fixup_networks() {
+        use crate::keys::{any_network, ToDescriptorKey};
+
+        let xpub = bip32::ExtendedPubKey::from_str("xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL").unwrap();
+        let path = bip32::DerivationPath::from_str("m/0").unwrap();
+
+        // here `to_descriptor_key` will set the valid networks for the key to only mainnet, since
+        // we are using an "xpub"
+        let key = (xpub, path).to_descriptor_key().unwrap();
+        // override it with any. this happens in some key conversions, like bip39
+        let key = key.override_valid_networks(any_network());
+
+        // make a descriptor out of it
+        let desc = crate::descriptor!(wpkh(key)).unwrap();
+        // this should conver the key that supports "any_network" to the right network (testnet)
+        let (wallet_desc, _) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+
+        assert_eq!(wallet_desc.to_string(), "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)");
+    }
+
+    // test ToWalletDescriptor trait from &str with and without checksum appended
+    #[test]
+    fn test_descriptor_from_str_with_checksum() {
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#tqz0nc62"
+            .to_wallet_descriptor(Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
+            .to_wallet_descriptor(Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)#67ju93jw"
+            .to_wallet_descriptor(Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
+            .to_wallet_descriptor(Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw"
+            .to_wallet_descriptor(Network::Testnet);
+        assert!(matches!(desc.err(), Some(KeyError::InvalidChecksum)));
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw"
+            .to_wallet_descriptor(Network::Testnet);
+        assert!(matches!(desc.err(), Some(KeyError::InvalidChecksum)));
+    }
+
+    // test ToWalletDescriptor trait from &str with keys from right and wrong network
+    #[test]
+    fn test_descriptor_from_str_with_keys_network() {
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
+            .to_wallet_descriptor(Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
+            .to_wallet_descriptor(Network::Regtest);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
+            .to_wallet_descriptor(Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
+            .to_wallet_descriptor(Network::Regtest);
+        assert!(desc.is_ok());
+
+        let desc = "sh(wpkh(02864bb4ad00cefa806098a69e192bbda937494e69eb452b87bb3f20f6283baedb))"
+            .to_wallet_descriptor(Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "sh(wpkh(02864bb4ad00cefa806098a69e192bbda937494e69eb452b87bb3f20f6283baedb))"
+            .to_wallet_descriptor(Network::Bitcoin);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
+            .to_wallet_descriptor(Network::Bitcoin);
+        assert!(matches!(desc.err(), Some(KeyError::InvalidNetwork)));
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
+            .to_wallet_descriptor(Network::Bitcoin);
+        assert!(matches!(desc.err(), Some(KeyError::InvalidNetwork)));
+    }
+
+    // test ToWalletDescriptor trait from the output of the descriptor!() macro
+    #[test]
+    fn test_descriptor_from_str_from_output_of_macro() {
+        let tpub = bip32::ExtendedPubKey::from_str("tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK").unwrap();
+        let path = bip32::DerivationPath::from_str("m/1/2").unwrap();
+        let key = (tpub, path).to_descriptor_key().unwrap();
+
+        // make a descriptor out of it
+        let desc = crate::descriptor!(wpkh(key)).unwrap();
+
+        let (wallet_desc, _) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+        let wallet_desc_str = wallet_desc.to_string();
+        assert_eq!(wallet_desc_str, "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)");
+
+        let (wallet_desc2, _) = wallet_desc_str
+            .to_wallet_descriptor(Network::Testnet)
+            .unwrap();
+        assert_eq!(wallet_desc, wallet_desc2)
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/policy.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/policy.rs.html new file mode 100644 index 0000000000..ea8a2c70d1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/policy.rs.html @@ -0,0 +1,2462 @@ +policy.rs - source + +
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Descriptor policy
+//!
+//! This module implements the logic to extract and represent the spending policies of a descriptor
+//! in a more human-readable format.
+//!
+//! This is an **EXPERIMENTAL** feature, API and other major changes are expected.
+//!
+//! ## Example
+//!
+//! ```
+//! # use std::sync::Arc;
+//! # use bdk::descriptor::*;
+//! # use bdk::bitcoin::secp256k1::Secp256k1;
+//! let secp = Secp256k1::new();
+//! let desc = "wsh(and_v(v:pk(cV3oCth6zxZ1UVsHLnGothsWNsaoxRhC6aeNi5VbSdFpwUkgkEci),or_d(pk(cVMTy7uebJgvFaSBwcgvwk8qn8xSLc97dKow4MBetjrrahZoimm2),older(12960))))";
+//!
+//! let (extended_desc, key_map) = ExtendedDescriptor::parse_descriptor(desc)?;
+//! println!("{:?}", extended_desc);
+//!
+//! let signers = Arc::new(key_map.into());
+//! let policy = extended_desc.extract_policy(&signers, &secp)?;
+//! println!("policy: {}", serde_json::to_string(&policy)?);
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use std::cmp::{max, Ordering};
+use std::collections::{BTreeMap, HashSet, VecDeque};
+use std::fmt;
+
+use serde::ser::SerializeMap;
+use serde::{Serialize, Serializer};
+
+use bitcoin::hashes::*;
+use bitcoin::util::bip32::Fingerprint;
+use bitcoin::PublicKey;
+
+use miniscript::descriptor::{DescriptorPublicKey, SortedMultiVec};
+use miniscript::{Descriptor, Miniscript, MiniscriptKey, ScriptContext, Terminal, ToPublicKey};
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+
+use crate::descriptor::ExtractPolicy;
+use crate::wallet::signer::{SignerId, SignersContainer};
+use crate::wallet::utils::{self, descriptor_to_pk_ctx, SecpCtx};
+
+use super::checksum::get_checksum;
+use super::error::Error;
+use super::XKeyUtils;
+
+/// Raw public key or extended key fingerprint
+#[derive(Debug, Clone, Default, Serialize)]
+pub struct PKOrF {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pubkey: Option<PublicKey>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pubkey_hash: Option<hash160::Hash>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    fingerprint: Option<Fingerprint>,
+}
+
+impl PKOrF {
+    fn from_key(k: &DescriptorPublicKey, secp: &SecpCtx) -> Self {
+        match k {
+            DescriptorPublicKey::SinglePub(pubkey) => PKOrF {
+                pubkey: Some(pubkey.key),
+                ..Default::default()
+            },
+            DescriptorPublicKey::XPub(xpub) => PKOrF {
+                fingerprint: Some(xpub.root_fingerprint(secp)),
+                ..Default::default()
+            },
+        }
+    }
+
+    fn from_key_hash(k: hash160::Hash) -> Self {
+        PKOrF {
+            pubkey_hash: Some(k),
+            ..Default::default()
+        }
+    }
+}
+
+/// An item that needs to be satisfied
+#[derive(Debug, Clone, Serialize)]
+#[serde(tag = "type", rename_all = "UPPERCASE")]
+pub enum SatisfiableItem {
+    // Leaves
+    /// Signature for a raw public key
+    Signature(PKOrF),
+    /// Signature for an extended key fingerprint
+    SignatureKey(PKOrF),
+    /// SHA256 preimage hash
+    SHA256Preimage {
+        /// The digest value
+        hash: sha256::Hash,
+    },
+    /// Double SHA256 preimage hash
+    HASH256Preimage {
+        /// The digest value
+        hash: sha256d::Hash,
+    },
+    /// RIPEMD160 preimage hash
+    RIPEMD160Preimage {
+        /// The digest value
+        hash: ripemd160::Hash,
+    },
+    /// SHA256 then RIPEMD160 preimage hash
+    HASH160Preimage {
+        /// The digest value
+        hash: hash160::Hash,
+    },
+    /// Absolute timeclock timestamp
+    AbsoluteTimelock {
+        /// The timestamp value
+        value: u32,
+    },
+    /// Relative timelock locktime
+    RelativeTimelock {
+        /// The locktime value
+        value: u32,
+    },
+    /// Multi-signature public keys with threshold count
+    Multisig {
+        /// The raw public key or extended key fingerprint
+        keys: Vec<PKOrF>,
+        /// The required threshold count
+        threshold: usize,
+    },
+
+    // Complex item
+    /// Threshold items with threshold count
+    Thresh {
+        /// The policy items
+        items: Vec<Policy>,
+        /// The required threshold count
+        threshold: usize,
+    },
+}
+
+impl SatisfiableItem {
+    /// Returns whether the [`SatisfiableItem`] is a leaf item
+    pub fn is_leaf(&self) -> bool {
+        !matches!(self,
+        SatisfiableItem::Thresh {
+            items: _,
+            threshold: _,
+        })
+    }
+
+    /// Returns a unique id for the [`SatisfiableItem`]
+    pub fn id(&self) -> String {
+        get_checksum(&serde_json::to_string(self).expect("Failed to serialize a SatisfiableItem"))
+            .expect("Failed to compute a SatisfiableItem id")
+    }
+}
+
+fn combinations(vec: &[usize], size: usize) -> Vec<Vec<usize>> {
+    assert!(vec.len() >= size);
+
+    let mut answer = Vec::new();
+
+    let mut queue = VecDeque::new();
+    for (index, val) in vec.iter().enumerate() {
+        let mut new_vec = Vec::with_capacity(size);
+        new_vec.push(*val);
+        queue.push_back((index, new_vec));
+    }
+
+    while let Some((index, vals)) = queue.pop_front() {
+        if vals.len() >= size {
+            answer.push(vals);
+        } else {
+            for (new_index, val) in vec.iter().skip(index + 1).enumerate() {
+                let mut cloned = vals.clone();
+                cloned.push(*val);
+                queue.push_front((new_index, cloned));
+            }
+        }
+    }
+
+    answer
+}
+
+fn mix<T: Clone>(vec: Vec<Vec<T>>) -> Vec<Vec<T>> {
+    if vec.is_empty() || vec.iter().any(Vec::is_empty) {
+        return vec![];
+    }
+
+    let mut answer = Vec::new();
+    let size = vec.len();
+
+    let mut queue = VecDeque::new();
+    for i in &vec[0] {
+        let mut new_vec = Vec::with_capacity(size);
+        new_vec.push(i.clone());
+        queue.push_back(new_vec);
+    }
+
+    while let Some(vals) = queue.pop_front() {
+        if vals.len() >= size {
+            answer.push(vals);
+        } else {
+            let level = vals.len();
+            for i in &vec[level] {
+                let mut cloned = vals.clone();
+                cloned.push(i.clone());
+                queue.push_front(cloned);
+            }
+        }
+    }
+
+    answer
+}
+
+/// Type for a map of sets of [`Condition`] items keyed by each set's index
+pub type ConditionMap = BTreeMap<usize, HashSet<Condition>>;
+/// Type for a map of folded sets of [`Condition`] items keyed by a vector of the combined set's indexes
+pub type FoldedConditionMap = BTreeMap<Vec<usize>, HashSet<Condition>>;
+
+fn serialize_folded_cond_map<S>(
+    input_map: &FoldedConditionMap,
+    serializer: S,
+) -> Result<S::Ok, S::Error>
+where
+    S: Serializer,
+{
+    let mut map = serializer.serialize_map(Some(input_map.len()))?;
+    for (k, v) in input_map {
+        let k_string = format!("{:?}", k);
+        map.serialize_entry(&k_string, v)?;
+    }
+    map.end()
+}
+
+/// Represent if and how much a policy item is satisfied by the wallet's descriptor
+#[derive(Debug, Clone, Serialize)]
+#[serde(tag = "type", rename_all = "UPPERCASE")]
+pub enum Satisfaction {
+    /// Only a partial satisfaction of some kind of threshold policy
+    Partial {
+        /// Total number of items
+        n: usize,
+        /// Threshold
+        m: usize,
+        /// The items that can be satisfied by the descriptor
+        items: Vec<usize>,
+        #[serde(skip_serializing_if = "Option::is_none")]
+        /// Whether the items are sorted in lexicographic order (used by `sortedmulti`)
+        sorted: Option<bool>,
+        #[serde(skip_serializing_if = "BTreeMap::is_empty")]
+        /// Extra conditions that also need to be satisfied
+        conditions: ConditionMap,
+    },
+    /// Can reach the threshold of some kind of threshold policy
+    PartialComplete {
+        /// Total number of items
+        n: usize,
+        /// Threshold
+        m: usize,
+        /// The items that can be satisfied by the descriptor
+        items: Vec<usize>,
+        #[serde(skip_serializing_if = "Option::is_none")]
+        /// Whether the items are sorted in lexicographic order (used by `sortedmulti`)
+        sorted: Option<bool>,
+        #[serde(
+            serialize_with = "serialize_folded_cond_map",
+            skip_serializing_if = "BTreeMap::is_empty"
+        )]
+        /// Extra conditions that also need to be satisfied
+        conditions: FoldedConditionMap,
+    },
+
+    /// Can satisfy the policy item
+    Complete {
+        /// Extra conditions that also need to be satisfied
+        condition: Condition,
+    },
+    /// Cannot satisfy or contribute to the policy item
+    None,
+}
+
+impl Satisfaction {
+    /// Returns whether the [`Satisfaction`] is a leaf item
+    pub fn is_leaf(&self) -> bool {
+        match self {
+            Satisfaction::None | Satisfaction::Complete { .. } => true,
+            Satisfaction::PartialComplete { .. } | Satisfaction::Partial { .. } => false,
+        }
+    }
+
+    // add `inner` as one of self's partial items. this only makes sense on partials
+    fn add(&mut self, inner: &Satisfaction, inner_index: usize) -> Result<(), PolicyError> {
+        match self {
+            Satisfaction::None | Satisfaction::Complete { .. } => Err(PolicyError::AddOnLeaf),
+            Satisfaction::PartialComplete { .. } => Err(PolicyError::AddOnPartialComplete),
+            Satisfaction::Partial {
+                n,
+                ref mut conditions,
+                ref mut items,
+                ..
+            } => {
+                if inner_index >= *n || items.contains(&inner_index) {
+                    return Err(PolicyError::IndexOutOfRange(inner_index));
+                }
+
+                match inner {
+                    // not relevant if not completed yet
+                    Satisfaction::None | Satisfaction::Partial { .. } => return Ok(()),
+                    Satisfaction::Complete { condition } => {
+                        items.push(inner_index);
+                        conditions.insert(inner_index, vec![*condition].into_iter().collect());
+                    }
+                    Satisfaction::PartialComplete {
+                        conditions: other_conditions,
+                        ..
+                    } => {
+                        items.push(inner_index);
+                        let conditions_set = other_conditions
+                            .values()
+                            .fold(HashSet::new(), |set, i| set.union(&i).cloned().collect());
+                        conditions.insert(inner_index, conditions_set);
+                    }
+                }
+
+                Ok(())
+            }
+        }
+    }
+
+    fn finalize(&mut self) -> Result<(), PolicyError> {
+        // if partial try to bump it to a partialcomplete
+        if let Satisfaction::Partial {
+            n,
+            m,
+            items,
+            conditions,
+            sorted,
+        } = self
+        {
+            if items.len() >= *m {
+                let mut map = BTreeMap::new();
+                let indexes = combinations(items, *m);
+                // `indexes` at this point is a Vec<Vec<usize>>, with the "n choose k" of items (m of n)
+                indexes
+                    .into_iter()
+                    // .inspect(|x| println!("--- orig --- {:?}", x))
+                    // we map each of the combinations of elements into a tuple of ([choosen items], [conditions]). unfortunately, those items have potentially more than one
+                    // condition (think about ORs), so we also use `mix` to expand those, i.e. [[0], [1, 2]] becomes [[0, 1], [0, 2]]. This is necessary to make sure that we
+                    // consider every possibile options and check whether or not they are compatible.
+                    .map(|i_vec| {
+                        mix(i_vec
+                            .iter()
+                            .map(|i| {
+                                conditions
+                                    .get(i)
+                                    .map(|set| set.clone().into_iter().collect())
+                                    .unwrap_or_default()
+                            })
+                            .collect())
+                        .into_iter()
+                        .map(|x| (i_vec.clone(), x))
+                        .collect::<Vec<(Vec<usize>, Vec<Condition>)>>()
+                    })
+                    // .inspect(|x: &Vec<(Vec<usize>, Vec<Condition>)>| println!("fetch {:?}", x))
+                    // since the previous step can turn one item of the iterator into multiple ones, we call flatten to expand them out
+                    .flatten()
+                    // .inspect(|x| println!("flat {:?}", x))
+                    // try to fold all the conditions for this specific combination of indexes/options. if they are not compatible, try_fold will be Err
+                    .map(|(key, val)| {
+                        (
+                            key,
+                            val.into_iter()
+                                .try_fold(Condition::default(), |acc, v| acc.merge(&v)),
+                        )
+                    })
+                    // .inspect(|x| println!("try_fold {:?}", x))
+                    // filter out all the incompatible combinations
+                    .filter(|(_, val)| val.is_ok())
+                    // .inspect(|x| println!("filter {:?}", x))
+                    // push them into the map
+                    .for_each(|(key, val)| {
+                        map.entry(key)
+                            .or_insert_with(HashSet::new)
+                            .insert(val.unwrap());
+                    });
+                // TODO: if the map is empty, the conditions are not compatible, return an error?
+                *self = Satisfaction::PartialComplete {
+                    n: *n,
+                    m: *m,
+                    items: items.clone(),
+                    conditions: map,
+                    sorted: *sorted,
+                };
+            }
+        }
+
+        Ok(())
+    }
+}
+
+impl From<bool> for Satisfaction {
+    fn from(other: bool) -> Self {
+        if other {
+            Satisfaction::Complete {
+                condition: Default::default(),
+            }
+        } else {
+            Satisfaction::None
+        }
+    }
+}
+
+/// Descriptor spending policy
+#[derive(Debug, Clone, Serialize)]
+pub struct Policy {
+    /// Identifier for this policy node
+    pub id: String,
+
+    /// Type of this policy node
+    #[serde(flatten)]
+    pub item: SatisfiableItem,
+    /// How a much given PSBT already satisfies this polcy node **(currently unused)**
+    pub satisfaction: Satisfaction,
+    /// How the wallet's descriptor can satisfy this policy node
+    pub contribution: Satisfaction,
+}
+
+/// An extra condition that must be satisfied but that is out of control of the user
+#[derive(Hash, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize)]
+pub struct Condition {
+    /// Optional CheckSequenceVerify condition
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub csv: Option<u32>,
+    /// Optional timelock condition
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub timelock: Option<u32>,
+}
+
+impl Condition {
+    fn merge_nlocktime(a: u32, b: u32) -> Result<u32, PolicyError> {
+        if (a < utils::BLOCKS_TIMELOCK_THRESHOLD) != (b < utils::BLOCKS_TIMELOCK_THRESHOLD) {
+            Err(PolicyError::MixedTimelockUnits)
+        } else {
+            Ok(max(a, b))
+        }
+    }
+
+    fn merge_nsequence(a: u32, b: u32) -> Result<u32, PolicyError> {
+        let mask = utils::SEQUENCE_LOCKTIME_TYPE_FLAG | utils::SEQUENCE_LOCKTIME_MASK;
+
+        let a = a & mask;
+        let b = b & mask;
+
+        if (a < utils::SEQUENCE_LOCKTIME_TYPE_FLAG) != (b < utils::SEQUENCE_LOCKTIME_TYPE_FLAG) {
+            Err(PolicyError::MixedTimelockUnits)
+        } else {
+            Ok(max(a, b))
+        }
+    }
+
+    pub(crate) fn merge(mut self, other: &Condition) -> Result<Self, PolicyError> {
+        match (self.csv, other.csv) {
+            (Some(a), Some(b)) => self.csv = Some(Self::merge_nsequence(a, b)?),
+            (None, any) => self.csv = any,
+            _ => {}
+        }
+
+        match (self.timelock, other.timelock) {
+            (Some(a), Some(b)) => self.timelock = Some(Self::merge_nlocktime(a, b)?),
+            (None, any) => self.timelock = any,
+            _ => {}
+        }
+
+        Ok(self)
+    }
+
+    /// Returns `true` if there are no extra conditions to verify
+    pub fn is_null(&self) -> bool {
+        self.csv.is_none() && self.timelock.is_none()
+    }
+}
+
+/// Errors that can happen while extracting and manipulating policies
+#[derive(Debug)]
+pub enum PolicyError {
+    /// Not enough items are selected to satisfy a [`SatisfiableItem::Thresh`]
+    NotEnoughItemsSelected(String),
+    /// Too many items are selected to satisfy a [`SatisfiableItem::Thresh`]
+    TooManyItemsSelected(String),
+    /// Index out of range for an item to satisfy a [`SatisfiableItem::Thresh`]
+    IndexOutOfRange(usize),
+    /// Can not add to an item that is [`Satisfaction::None`] or [`Satisfaction::Complete`]
+    AddOnLeaf,
+    /// Can not add to an item that is [`Satisfaction::PartialComplete`]
+    AddOnPartialComplete,
+    /// Can not merge CSV or timelock values unless both are less than or both are equal or greater than 500_000_000
+    MixedTimelockUnits,
+    /// Incompatible conditions (not currently used)
+    IncompatibleConditions,
+}
+
+impl fmt::Display for PolicyError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl std::error::Error for PolicyError {}
+
+impl Policy {
+    fn new(item: SatisfiableItem) -> Self {
+        Policy {
+            id: item.id(),
+            item,
+            satisfaction: Satisfaction::None,
+            contribution: Satisfaction::None,
+        }
+    }
+
+    fn make_and(a: Option<Policy>, b: Option<Policy>) -> Result<Option<Policy>, PolicyError> {
+        match (a, b) {
+            (None, None) => Ok(None),
+            (Some(x), None) | (None, Some(x)) => Ok(Some(x)),
+            (Some(a), Some(b)) => Self::make_thresh(vec![a, b], 2),
+        }
+    }
+
+    fn make_or(a: Option<Policy>, b: Option<Policy>) -> Result<Option<Policy>, PolicyError> {
+        match (a, b) {
+            (None, None) => Ok(None),
+            (Some(x), None) | (None, Some(x)) => Ok(Some(x)),
+            (Some(a), Some(b)) => Self::make_thresh(vec![a, b], 1),
+        }
+    }
+
+    fn make_thresh(items: Vec<Policy>, threshold: usize) -> Result<Option<Policy>, PolicyError> {
+        if threshold == 0 {
+            return Ok(None);
+        }
+
+        let mut contribution = Satisfaction::Partial {
+            n: items.len(),
+            m: threshold,
+            items: vec![],
+            conditions: Default::default(),
+            sorted: None,
+        };
+        for (index, item) in items.iter().enumerate() {
+            contribution.add(&item.contribution, index)?;
+        }
+        contribution.finalize()?;
+
+        let mut policy: Policy = SatisfiableItem::Thresh { items, threshold }.into();
+        policy.contribution = contribution;
+
+        Ok(Some(policy))
+    }
+
+    fn make_multisig(
+        keys: &[DescriptorPublicKey],
+        signers: &SignersContainer,
+        threshold: usize,
+        sorted: bool,
+        secp: &SecpCtx,
+    ) -> Result<Option<Policy>, PolicyError> {
+        if threshold == 0 {
+            return Ok(None);
+        }
+
+        let parsed_keys = keys.iter().map(|k| PKOrF::from_key(k, secp)).collect();
+
+        let mut contribution = Satisfaction::Partial {
+            n: keys.len(),
+            m: threshold,
+            items: vec![],
+            conditions: Default::default(),
+            sorted: Some(sorted),
+        };
+        for (index, key) in keys.iter().enumerate() {
+            if signers.find(signer_id(key, secp)).is_some() {
+                contribution.add(
+                    &Satisfaction::Complete {
+                        condition: Default::default(),
+                    },
+                    index,
+                )?;
+            }
+        }
+        contribution.finalize()?;
+
+        let mut policy: Policy = SatisfiableItem::Multisig {
+            keys: parsed_keys,
+            threshold,
+        }
+        .into();
+        policy.contribution = contribution;
+
+        Ok(Some(policy))
+    }
+
+    /// Return whether or not a specific path in the policy tree is required to unambiguously
+    /// create a transaction
+    ///
+    /// What this means is that for some spending policies the user should select which paths in
+    /// the tree it intends to satisfy while signing, because the transaction must be created differently based
+    /// on that.
+    pub fn requires_path(&self) -> bool {
+        self.get_condition(&BTreeMap::new()).is_err()
+    }
+
+    /// Return the conditions that are set by the spending policy for a given path in the
+    /// policy tree
+    pub fn get_condition(
+        &self,
+        path: &BTreeMap<String, Vec<usize>>,
+    ) -> Result<Condition, PolicyError> {
+        // if items.len() == threshold, selected can be omitted and we take all of them by default
+        let default = match &self.item {
+            SatisfiableItem::Thresh { items, threshold } if items.len() == *threshold => {
+                (0..*threshold).collect()
+            }
+            _ => vec![],
+        };
+        let selected = match path.get(&self.id) {
+            _ if !default.is_empty() => &default,
+            Some(arr) => arr,
+            _ => &default,
+        };
+
+        match &self.item {
+            SatisfiableItem::Thresh { items, threshold } => {
+                let mapped_req = items
+                    .iter()
+                    .map(|i| i.get_condition(path))
+                    .collect::<Result<Vec<_>, _>>()?;
+
+                // if all the requirements are null we don't care about `selected` because there
+                // are no requirements
+                if mapped_req.iter().all(Condition::is_null) {
+                    return Ok(Condition::default());
+                }
+
+                // if we have something, make sure we have enough items. note that the user can set
+                // an empty value for this step in case of n-of-n, because `selected` is set to all
+                // the elements above
+                match selected.len().cmp(threshold) {
+                    Ordering::Less => {
+                        return Err(PolicyError::NotEnoughItemsSelected(self.id.clone()))
+                    }
+                    Ordering::Greater => {
+                        return Err(PolicyError::TooManyItemsSelected(self.id.clone()))
+                    }
+                    Ordering::Equal => (),
+                }
+
+                // check the selected items, see if there are conflicting requirements
+                let mut requirements = Condition::default();
+                for item_index in selected {
+                    requirements = requirements.merge(
+                        mapped_req
+                            .get(*item_index)
+                            .ok_or(PolicyError::IndexOutOfRange(*item_index))?,
+                    )?;
+                }
+
+                Ok(requirements)
+            }
+            _ if !selected.is_empty() => Err(PolicyError::TooManyItemsSelected(self.id.clone())),
+            SatisfiableItem::AbsoluteTimelock { value } => Ok(Condition {
+                csv: None,
+                timelock: Some(*value),
+            }),
+            SatisfiableItem::RelativeTimelock { value } => Ok(Condition {
+                csv: Some(*value),
+                timelock: None,
+            }),
+            _ => Ok(Condition::default()),
+        }
+    }
+}
+
+impl From<SatisfiableItem> for Policy {
+    fn from(other: SatisfiableItem) -> Self {
+        Self::new(other)
+    }
+}
+
+fn signer_id(key: &DescriptorPublicKey, secp: &SecpCtx) -> SignerId {
+    match key {
+        DescriptorPublicKey::SinglePub(pubkey) => pubkey.key.to_pubkeyhash().into(),
+        DescriptorPublicKey::XPub(xpub) => xpub.root_fingerprint(secp).into(),
+    }
+}
+
+fn signature(key: &DescriptorPublicKey, signers: &SignersContainer, secp: &SecpCtx) -> Policy {
+    let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key(key, secp)).into();
+
+    policy.contribution = if signers.find(signer_id(key, secp)).is_some() {
+        Satisfaction::Complete {
+            condition: Default::default(),
+        }
+    } else {
+        Satisfaction::None
+    };
+
+    policy
+}
+
+fn signature_key(
+    key: &<DescriptorPublicKey as MiniscriptKey>::Hash,
+    signers: &SignersContainer,
+    secp: &SecpCtx,
+) -> Policy {
+    let deriv_ctx = descriptor_to_pk_ctx(secp);
+    let key_hash = key.to_public_key(deriv_ctx).to_pubkeyhash();
+    let mut policy: Policy = SatisfiableItem::Signature(PKOrF::from_key_hash(key_hash)).into();
+
+    if signers.find(SignerId::PkHash(key_hash)).is_some() {
+        policy.contribution = Satisfaction::Complete {
+            condition: Default::default(),
+        }
+    }
+
+    policy
+}
+
+impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx> {
+    fn extract_policy(
+        &self,
+        signers: &SignersContainer,
+        secp: &SecpCtx,
+    ) -> Result<Option<Policy>, Error> {
+        Ok(match &self.node {
+            // Leaves
+            Terminal::True | Terminal::False => None,
+            Terminal::PkK(pubkey) => Some(signature(pubkey, signers, secp)),
+            Terminal::PkH(pubkey_hash) => Some(signature_key(pubkey_hash, signers, secp)),
+            Terminal::After(value) => {
+                let mut policy: Policy = SatisfiableItem::AbsoluteTimelock { value: *value }.into();
+                policy.contribution = Satisfaction::Complete {
+                    condition: Condition {
+                        timelock: Some(*value),
+                        csv: None,
+                    },
+                };
+
+                Some(policy)
+            }
+            Terminal::Older(value) => {
+                let mut policy: Policy = SatisfiableItem::RelativeTimelock { value: *value }.into();
+                policy.contribution = Satisfaction::Complete {
+                    condition: Condition {
+                        timelock: None,
+                        csv: Some(*value),
+                    },
+                };
+
+                Some(policy)
+            }
+            Terminal::Sha256(hash) => Some(SatisfiableItem::SHA256Preimage { hash: *hash }.into()),
+            Terminal::Hash256(hash) => {
+                Some(SatisfiableItem::HASH256Preimage { hash: *hash }.into())
+            }
+            Terminal::Ripemd160(hash) => {
+                Some(SatisfiableItem::RIPEMD160Preimage { hash: *hash }.into())
+            }
+            Terminal::Hash160(hash) => {
+                Some(SatisfiableItem::HASH160Preimage { hash: *hash }.into())
+            }
+            Terminal::Multi(k, pks) => Policy::make_multisig(pks, signers, *k, false, secp)?,
+            // Identities
+            Terminal::Alt(inner)
+            | Terminal::Swap(inner)
+            | Terminal::Check(inner)
+            | Terminal::DupIf(inner)
+            | Terminal::Verify(inner)
+            | Terminal::NonZero(inner)
+            | Terminal::ZeroNotEqual(inner) => inner.extract_policy(signers, secp)?,
+            // Complex policies
+            Terminal::AndV(a, b) | Terminal::AndB(a, b) => Policy::make_and(
+                a.extract_policy(signers, secp)?,
+                b.extract_policy(signers, secp)?,
+            )?,
+            Terminal::AndOr(x, y, z) => Policy::make_or(
+                Policy::make_and(
+                    x.extract_policy(signers, secp)?,
+                    y.extract_policy(signers, secp)?,
+                )?,
+                z.extract_policy(signers, secp)?,
+            )?,
+            Terminal::OrB(a, b)
+            | Terminal::OrD(a, b)
+            | Terminal::OrC(a, b)
+            | Terminal::OrI(a, b) => Policy::make_or(
+                a.extract_policy(signers, secp)?,
+                b.extract_policy(signers, secp)?,
+            )?,
+            Terminal::Thresh(k, nodes) => {
+                let mut threshold = *k;
+                let mapped: Vec<_> = nodes
+                    .iter()
+                    .map(|n| n.extract_policy(signers, secp))
+                    .collect::<Result<Vec<_>, _>>()?
+                    .into_iter()
+                    .filter_map(|x| x)
+                    .collect();
+
+                if mapped.len() < nodes.len() {
+                    threshold = match threshold.checked_sub(nodes.len() - mapped.len()) {
+                        None => return Ok(None),
+                        Some(x) => x,
+                    };
+                }
+
+                Policy::make_thresh(mapped, threshold)?
+            }
+        })
+    }
+}
+
+impl ExtractPolicy for Descriptor<DescriptorPublicKey> {
+    fn extract_policy(
+        &self,
+        signers: &SignersContainer,
+        secp: &SecpCtx,
+    ) -> Result<Option<Policy>, Error> {
+        fn make_sortedmulti<Ctx: ScriptContext>(
+            keys: &SortedMultiVec<DescriptorPublicKey, Ctx>,
+            signers: &SignersContainer,
+            secp: &SecpCtx,
+        ) -> Result<Option<Policy>, Error> {
+            Ok(Policy::make_multisig(
+                keys.pks.as_ref(),
+                signers,
+                keys.k,
+                true,
+                secp,
+            )?)
+        }
+
+        match self {
+            Descriptor::Pk(pubkey)
+            | Descriptor::Pkh(pubkey)
+            | Descriptor::Wpkh(pubkey)
+            | Descriptor::ShWpkh(pubkey) => Ok(Some(signature(pubkey, signers, secp))),
+            Descriptor::Bare(inner) => Ok(inner.extract_policy(signers, secp)?),
+            Descriptor::Sh(inner) => Ok(inner.extract_policy(signers, secp)?),
+            Descriptor::Wsh(inner) | Descriptor::ShWsh(inner) => {
+                Ok(inner.extract_policy(signers, secp)?)
+            }
+
+            // `sortedmulti()` is handled separately
+            Descriptor::ShSortedMulti(keys) => make_sortedmulti(&keys, signers, secp),
+            Descriptor::ShWshSortedMulti(keys) | Descriptor::WshSortedMulti(keys) => {
+                make_sortedmulti(&keys, signers, secp)
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+
+    use crate::descriptor;
+    use crate::descriptor::{ExtractPolicy, ToWalletDescriptor};
+
+    use super::*;
+    use crate::descriptor::policy::SatisfiableItem::{Multisig, Signature, Thresh};
+    use crate::keys::{DescriptorKey, ToDescriptorKey};
+    use crate::wallet::signer::SignersContainer;
+    use bitcoin::secp256k1::{All, Secp256k1};
+    use bitcoin::util::bip32;
+    use bitcoin::util::bip32::ChildNumber;
+    use bitcoin::Network;
+    use std::str::FromStr;
+    use std::sync::Arc;
+
+    const TPRV0_STR:&str = "tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf";
+    const TPRV1_STR:&str = "tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N";
+
+    const PATH: &str = "m/44'/1'/0'/0";
+
+    fn setup_keys<Ctx: ScriptContext>(
+        tprv: &str,
+    ) -> (DescriptorKey<Ctx>, DescriptorKey<Ctx>, Fingerprint) {
+        let secp: Secp256k1<All> = Secp256k1::new();
+        let path = bip32::DerivationPath::from_str(PATH).unwrap();
+        let tprv = bip32::ExtendedPrivKey::from_str(tprv).unwrap();
+        let tpub = bip32::ExtendedPubKey::from_private(&secp, &tprv);
+        let fingerprint = tprv.fingerprint(&secp);
+        let prvkey = (tprv, path.clone()).to_descriptor_key().unwrap();
+        let pubkey = (tpub, path).to_descriptor_key().unwrap();
+
+        (prvkey, pubkey, fingerprint)
+    }
+
+    // test ExtractPolicy trait for simple descriptors; wpkh(), sh(multi())
+
+    #[test]
+    fn test_extract_policy_for_wpkh() {
+        let (prvkey, pubkey, fingerprint) = setup_keys(TPRV0_STR);
+        let desc = descriptor!(wpkh(pubkey)).unwrap();
+        let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, &Secp256k1::new())
+            .unwrap()
+            .unwrap();
+
+        assert!(
+            matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint)
+        );
+        assert!(matches!(&policy.contribution, Satisfaction::None));
+
+        let desc = descriptor!(wpkh(prvkey)).unwrap();
+        let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, &Secp256k1::new())
+            .unwrap()
+            .unwrap();
+
+        assert!(
+            matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint)
+        );
+        assert!(
+            matches!(&policy.contribution, Satisfaction::Complete {condition} if condition.csv == None && condition.timelock == None)
+        );
+    }
+
+    // 2 pub keys descriptor, required 2 prv keys
+    // #[test]
+    // fn test_extract_policy_for_sh_multi_partial_0of2() {
+    //     let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR);
+    //     let (_prvkey1, pubkey1, fingerprint1) = setup_keys(TPRV1_STR);
+    //     let desc = descriptor!(sh(multi 2, pubkey0, pubkey1)).unwrap();
+    //     let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+    //     let signers_container = Arc::new(SignersContainer::from(keymap));
+    //     let policy = wallet_desc
+    //         .extract_policy(signers_container)
+    //         .unwrap()
+    //         .unwrap();
+    //
+    //     assert!(
+    //         matches!(&policy.item, Multisig { keys, threshold } if threshold == &2
+    //         && &keys[0].fingerprint.unwrap() == &fingerprint0
+    //         && &keys[1].fingerprint.unwrap() == &fingerprint1)
+    //     );
+    //
+    //     // TODO should this be "Satisfaction::None" since we have no prv keys?
+    //     // TODO should items and conditions not be empty?
+    //     assert!(
+    //         matches!(&policy.contribution, Satisfaction::Partial { n, m, items, conditions} if n == &2
+    //         && m == &2
+    //         && items.is_empty()
+    //         && conditions.is_empty()
+    //         )
+    //     );
+    // }
+
+    // 1 prv and 1 pub key descriptor, required 2 prv keys
+    // #[test]
+    // fn test_extract_policy_for_sh_multi_partial_1of2() {
+    //     let (prvkey0, _pubkey0, fingerprint0) = setup_keys(TPRV0_STR);
+    //     let (_prvkey1, pubkey1, fingerprint1) = setup_keys(TPRV1_STR);
+    //     let desc = descriptor!(sh(multi 2, prvkey0, pubkey1)).unwrap();
+    //     let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+    //     let signers_container = Arc::new(SignersContainer::from(keymap));
+    //     let policy = wallet_desc
+    //         .extract_policy(signers_container)
+    //         .unwrap()
+    //         .unwrap();
+    //
+    //     assert!(
+    //         matches!(&policy.item, Multisig { keys, threshold } if threshold == &2
+    //         && &keys[0].fingerprint.unwrap() == &fingerprint0
+    //         && &keys[1].fingerprint.unwrap() == &fingerprint1)
+    //     );
+    //
+    //     // TODO should this be "Satisfaction::Partial" since we have only one of two prv keys?
+    //     assert!(
+    //         matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions} if n == &2
+    //          && m == &2
+    //          && items.len() == 2
+    //          && conditions.contains_key(&vec![0,1])
+    //         )
+    //     );
+    // }
+
+    // 1 prv and 1 pub key descriptor, required 1 prv keys
+    #[test]
+    #[ignore] // see https://github.com/bitcoindevkit/bdk/issues/225
+    fn test_extract_policy_for_sh_multi_complete_1of2() {
+        let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR);
+        let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR);
+        let desc = descriptor!(sh(multi 1, pubkey0, prvkey1)).unwrap();
+        let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, &Secp256k1::new())
+            .unwrap()
+            .unwrap();
+
+        assert!(
+            matches!(&policy.item, Multisig { keys, threshold } if threshold == &1
+            && &keys[0].fingerprint.unwrap() == &fingerprint0
+            && &keys[1].fingerprint.unwrap() == &fingerprint1)
+        );
+        assert!(
+            matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &2
+             && m == &1
+             && items.len() == 2
+             && conditions.contains_key(&vec![0])
+             && conditions.contains_key(&vec![1])
+            )
+        );
+    }
+
+    // 2 prv keys descriptor, required 2 prv keys
+    #[test]
+    fn test_extract_policy_for_sh_multi_complete_2of2() {
+        let (prvkey0, _pubkey0, fingerprint0) = setup_keys(TPRV0_STR);
+        let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR);
+        let desc = descriptor!(sh(multi 2, prvkey0, prvkey1)).unwrap();
+        let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, &Secp256k1::new())
+            .unwrap()
+            .unwrap();
+
+        assert!(
+            matches!(&policy.item, Multisig { keys, threshold } if threshold == &2
+            && &keys[0].fingerprint.unwrap() == &fingerprint0
+            && &keys[1].fingerprint.unwrap() == &fingerprint1)
+        );
+
+        assert!(
+            matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &2
+             && m == &2
+             && items.len() == 2
+             && conditions.contains_key(&vec![0,1])
+            )
+        );
+    }
+
+    // test ExtractPolicy trait with extended and single keys
+
+    #[test]
+    fn test_extract_policy_for_single_wpkh() {
+        let (prvkey, pubkey, fingerprint) = setup_keys(TPRV0_STR);
+        let desc = descriptor!(wpkh(pubkey)).unwrap();
+        let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+        let single_key = wallet_desc.derive(ChildNumber::from_normal_idx(0).unwrap());
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = single_key
+            .extract_policy(&signers_container, &Secp256k1::new())
+            .unwrap()
+            .unwrap();
+
+        assert!(
+            matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint)
+        );
+        assert!(matches!(&policy.contribution, Satisfaction::None));
+
+        let desc = descriptor!(wpkh(prvkey)).unwrap();
+        let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+        let single_key = wallet_desc.derive(ChildNumber::from_normal_idx(0).unwrap());
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = single_key
+            .extract_policy(&signers_container, &Secp256k1::new())
+            .unwrap()
+            .unwrap();
+
+        assert!(
+            matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint)
+        );
+        assert!(
+            matches!(&policy.contribution, Satisfaction::Complete {condition} if condition.csv == None && condition.timelock == None)
+        );
+    }
+
+    // single key, 1 prv and 1 pub key descriptor, required 1 prv keys
+    #[test]
+    #[ignore] // see https://github.com/bitcoindevkit/bdk/issues/225
+    fn test_extract_policy_for_single_wsh_multi_complete_1of2() {
+        let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR);
+        let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR);
+        let desc = descriptor!(sh(multi 1, pubkey0, prvkey1)).unwrap();
+        let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+        let single_key = wallet_desc.derive(ChildNumber::from_normal_idx(0).unwrap());
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = single_key
+            .extract_policy(&signers_container, &Secp256k1::new())
+            .unwrap()
+            .unwrap();
+
+        assert!(
+            matches!(&policy.item, Multisig { keys, threshold } if threshold == &1
+            && &keys[0].fingerprint.unwrap() == &fingerprint0
+            && &keys[1].fingerprint.unwrap() == &fingerprint1)
+        );
+        assert!(
+            matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &2
+             && m == &1
+             && items.len() == 2
+             && conditions.contains_key(&vec![0])
+             && conditions.contains_key(&vec![1])
+            )
+        );
+    }
+
+    // test ExtractPolicy trait with descriptors containing timelocks in a thresh()
+
+    #[test]
+    #[ignore] // see https://github.com/bitcoindevkit/bdk/issues/225
+    fn test_extract_policy_for_wsh_multi_timelock() {
+        let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR);
+        let (_prvkey1, pubkey1, _fingerprint1) = setup_keys(TPRV1_STR);
+        let sequence = 50;
+        let desc = descriptor!(wsh (
+            thresh 2, (pk prvkey0), (+s pk pubkey1), (+s+d+v older sequence)
+        ))
+        .unwrap();
+
+        let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, &Secp256k1::new())
+            .unwrap()
+            .unwrap();
+
+        assert!(
+            matches!(&policy.item, Thresh { items, threshold } if items.len() == 3 && threshold == &2)
+        );
+
+        assert!(
+            matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &3
+             && m == &2
+             && items.len() == 3
+             && conditions.get(&vec![0,1]).unwrap().iter().next().unwrap().csv.is_none()
+             && conditions.get(&vec![0,2]).unwrap().iter().next().unwrap().csv == Some(sequence)
+             && conditions.get(&vec![1,2]).unwrap().iter().next().unwrap().csv == Some(sequence)
+            )
+        );
+    }
+
+    // - mixed timelocks should fail
+
+    // #[test]
+    // fn test_extract_policy_for_wsh_mixed_timelocks() {
+    //     let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR);
+    //     let locktime_threshold = 500000000; // if less than this means block number, else block time in seconds
+    //     let locktime_blocks = 100;
+    //     let locktime_seconds = locktime_blocks + locktime_threshold;
+    //     let desc = descriptor!(sh (and_v (+v pk prvkey0), (and_v (+v after locktime_seconds), (after locktime_blocks)))).unwrap();
+    //     let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+    //     let signers_container = Arc::new(SignersContainer::from(keymap));
+    //     let policy = wallet_desc
+    //         .extract_policy(signers_container)
+    //         .unwrap()
+    //         .unwrap();
+    //
+    //     println!("desc policy = {:?}", policy); // TODO remove
+    //
+    //     // TODO how should this fail with mixed timelocks?
+    // }
+
+    // - multiple timelocks of the same type should be correctly merged together
+
+    // #[test]
+    // fn test_extract_policy_for_multiple_same_timelocks() {
+    //     let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR);
+    //     let locktime_blocks0 = 100;
+    //     let locktime_blocks1 = 200;
+    //     let desc = descriptor!(sh (and_v (+v pk prvkey0), (and_v (+v after locktime_blocks0), (after locktime_blocks1)))).unwrap();
+    //     let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+    //     let signers_container = Arc::new(SignersContainer::from(keymap));
+    //     let policy = wallet_desc
+    //         .extract_policy(signers_container)
+    //         .unwrap()
+    //         .unwrap();
+    //
+    //     println!("desc policy = {:?}", policy); // TODO remove
+    //
+    //     // TODO how should this merge timelocks?
+    //
+    //     let (prvkey1, _pubkey1, _fingerprint1) = setup_keys(TPRV0_STR);
+    //     let locktime_seconds0 = 500000100;
+    //     let locktime_seconds1 = 500000200;
+    //     let desc = descriptor!(sh (and_v (+v pk prvkey1), (and_v (+v after locktime_seconds0), (after locktime_seconds1)))).unwrap();
+    //     let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+    //     let signers_container = Arc::new(SignersContainer::from(keymap));
+    //     let policy = wallet_desc
+    //         .extract_policy(signers_container)
+    //         .unwrap()
+    //         .unwrap();
+    //
+    //     println!("desc policy = {:?}", policy); // TODO remove
+    //
+    //     // TODO how should this merge timelocks?
+    // }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/template.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/template.rs.html new file mode 100644 index 0000000000..751445aba5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/descriptor/template.rs.html @@ -0,0 +1,1460 @@ +template.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Descriptor templates
+//!
+//! This module contains the definition of various common script templates that are ready to be
+//! used. See the documentation of each template for an example.
+
+use bitcoin::util::bip32;
+use bitcoin::Network;
+
+use miniscript::{Legacy, Segwitv0};
+
+use super::{ExtendedDescriptor, KeyMap, ToWalletDescriptor};
+use crate::keys::{DerivableKey, KeyError, ToDescriptorKey, ValidNetworks};
+use crate::{descriptor, KeychainKind};
+
+/// Type alias for the return type of [`DescriptorTemplate`], [`descriptor!`](crate::descriptor!) and others
+pub type DescriptorTemplateOut = (ExtendedDescriptor, KeyMap, ValidNetworks);
+
+/// Trait for descriptor templates that can be built into a full descriptor
+///
+/// Since [`ToWalletDescriptor`] is implemented for any [`DescriptorTemplate`], they can also be
+/// passed directly to the [`Wallet`](crate::Wallet) constructor.
+///
+/// ## Example
+///
+/// ```
+/// use bdk::keys::{KeyError, ToDescriptorKey};
+/// use bdk::miniscript::Legacy;
+/// use bdk::template::{DescriptorTemplate, DescriptorTemplateOut};
+///
+/// struct MyP2PKH<K: ToDescriptorKey<Legacy>>(K);
+///
+/// impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for MyP2PKH<K> {
+///     fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+///         Ok(bdk::descriptor!(pkh(self.0))?)
+///     }
+/// }
+/// ```
+pub trait DescriptorTemplate {
+    /// Build the complete descriptor
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError>;
+}
+
+/// Turns a [`DescriptorTemplate`] into a valid wallet descriptor by calling its
+/// [`build`](DescriptorTemplate::build) method
+impl<T: DescriptorTemplate> ToWalletDescriptor for T {
+    fn to_wallet_descriptor(
+        self,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), KeyError> {
+        Ok(self.build()?.to_wallet_descriptor(network)?)
+    }
+}
+
+/// P2PKH template. Expands to a descriptor `pkh(key)`
+///
+/// ## Example
+///
+/// ```
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet, OfflineWallet};
+/// # use bdk::database::MemoryDatabase;
+/// use bdk::template::P2PKH;
+///
+/// let key =
+///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+/// let wallet: OfflineWallet<_> = Wallet::new_offline(
+///     P2PKH(key),
+///     None,
+///     Network::Testnet,
+///     MemoryDatabase::default(),
+/// )?;
+///
+/// assert_eq!(
+///     wallet.get_new_address()?.to_string(),
+///     "mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT"
+/// );
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct P2PKH<K: ToDescriptorKey<Legacy>>(pub K);
+
+impl<K: ToDescriptorKey<Legacy>> DescriptorTemplate for P2PKH<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(descriptor!(pkh(self.0))?)
+    }
+}
+
+/// P2WPKH-P2SH template. Expands to a descriptor `sh(wpkh(key))`
+///
+/// ## Example
+///
+/// ```
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet, OfflineWallet};
+/// # use bdk::database::MemoryDatabase;
+/// use bdk::template::P2WPKH_P2SH;
+///
+/// let key =
+///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+/// let wallet: OfflineWallet<_> = Wallet::new_offline(
+///     P2WPKH_P2SH(key),
+///     None,
+///     Network::Testnet,
+///     MemoryDatabase::default(),
+/// )?;
+///
+/// assert_eq!(
+///     wallet.get_new_address()?.to_string(),
+///     "2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5"
+/// );
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+#[allow(non_camel_case_types)]
+pub struct P2WPKH_P2SH<K: ToDescriptorKey<Segwitv0>>(pub K);
+
+impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH_P2SH<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(descriptor!(sh(wpkh(self.0)))?)
+    }
+}
+
+/// P2WPKH template. Expands to a descriptor `wpkh(key)`
+///
+/// ## Example
+///
+/// ```
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet, OfflineWallet};
+/// # use bdk::database::MemoryDatabase;
+/// use bdk::template::P2WPKH;
+///
+/// let key =
+///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+/// let wallet: OfflineWallet<_> = Wallet::new_offline(
+///     P2WPKH(key),
+///     None,
+///     Network::Testnet,
+///     MemoryDatabase::default(),
+/// )?;
+///
+/// assert_eq!(
+///     wallet.get_new_address()?.to_string(),
+///     "tb1q4525hmgw265tl3drrl8jjta7ayffu6jf68ltjd"
+/// );
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct P2WPKH<K: ToDescriptorKey<Segwitv0>>(pub K);
+
+impl<K: ToDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(descriptor!(wpkh(self.0))?)
+    }
+}
+
+/// BIP44 template. Expands to `pkh(key/44'/0'/0'/{0,1}/*)`
+///
+/// Since there are hardened derivation steps, this template requires a private derivable key (generally a `xprv`/`tprv`).
+///
+/// See [`BIP44Public`] for a template that can work with a `xpub`/`tpub`.
+///
+/// ## Example
+///
+/// ```
+/// # use std::str::FromStr;
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// use bdk::template::BIP44;
+///
+/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let wallet: OfflineWallet<_> = Wallet::new_offline(
+///     BIP44(key.clone(), KeychainKind::External),
+///     Some(BIP44(key, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_new_address()?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)");
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct BIP44<K: DerivableKey<Legacy>>(pub K, pub KeychainKind);
+
+impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(P2PKH(legacy::make_bipxx_private(44, self.0, self.1)?).build()?)
+    }
+}
+
+/// BIP44 public template. Expands to `pkh(key/{0,1}/*)`
+///
+/// This assumes that the key used has already been derived with `m/44'/0'/0'`.
+///
+/// This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
+///
+/// See [`BIP44`] for a template that does the full derivation, but requires private data
+/// for the key.
+///
+/// ## Example
+///
+/// ```
+/// # use std::str::FromStr;
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// use bdk::template::BIP44Public;
+///
+/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
+/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let wallet: OfflineWallet<_> = Wallet::new_offline(
+///     BIP44Public(key.clone(), fingerprint, KeychainKind::External),
+///     Some(BIP44Public(key, fingerprint, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_new_address()?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)");
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct BIP44Public<K: DerivableKey<Legacy>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
+
+impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44Public<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(P2PKH(legacy::make_bipxx_public(44, self.0, self.1, self.2)?).build()?)
+    }
+}
+
+/// BIP49 template. Expands to `sh(wpkh(key/49'/0'/0'/{0,1}/*))`
+///
+/// Since there are hardened derivation steps, this template requires a private derivable key (generally a `xprv`/`tprv`).
+///
+/// See [`BIP49Public`] for a template that can work with a `xpub`/`tpub`.
+///
+/// ## Example
+///
+/// ```
+/// # use std::str::FromStr;
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// use bdk::template::BIP49;
+///
+/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let wallet: OfflineWallet<_> = Wallet::new_offline(
+///     BIP49(key.clone(), KeychainKind::External),
+///     Some(BIP49(key, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_new_address()?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))");
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct BIP49<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
+
+impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(P2WPKH_P2SH(segwit_v0::make_bipxx_private(49, self.0, self.1)?).build()?)
+    }
+}
+
+/// BIP49 public template. Expands to `sh(wpkh(key/{0,1}/*))`
+///
+/// This assumes that the key used has already been derived with `m/49'/0'/0'`.
+///
+/// This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
+///
+/// See [`BIP49`] for a template that does the full derivation, but requires private data
+/// for the key.
+///
+/// ## Example
+///
+/// ```
+/// # use std::str::FromStr;
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// use bdk::template::BIP49Public;
+///
+/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
+/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let wallet: OfflineWallet<_> = Wallet::new_offline(
+///     BIP49Public(key.clone(), fingerprint, KeychainKind::External),
+///     Some(BIP49Public(key, fingerprint, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_new_address()?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))");
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct BIP49Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
+
+impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49Public<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(P2WPKH_P2SH(segwit_v0::make_bipxx_public(49, self.0, self.1, self.2)?).build()?)
+    }
+}
+
+/// BIP84 template. Expands to `wpkh(key/84'/0'/0'/{0,1}/*)`
+///
+/// Since there are hardened derivation steps, this template requires a private derivable key (generally a `xprv`/`tprv`).
+///
+/// See [`BIP84Public`] for a template that can work with a `xpub`/`tpub`.
+///
+/// ## Example
+///
+/// ```
+/// # use std::str::FromStr;
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// use bdk::template::BIP84;
+///
+/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let wallet: OfflineWallet<_> = Wallet::new_offline(
+///     BIP84(key.clone(), KeychainKind::External),
+///     Some(BIP84(key, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_new_address()?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)");
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct BIP84<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
+
+impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(P2WPKH(segwit_v0::make_bipxx_private(84, self.0, self.1)?).build()?)
+    }
+}
+
+/// BIP84 public template. Expands to `wpkh(key/{0,1}/*)`
+///
+/// This assumes that the key used has already been derived with `m/84'/0'/0'`.
+///
+/// This template requires the parent fingerprint to populate correctly the metadata of PSBTs.
+///
+/// See [`BIP84`] for a template that does the full derivation, but requires private data
+/// for the key.
+///
+/// ## Example
+///
+/// ```
+/// # use std::str::FromStr;
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet, OfflineWallet, KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// use bdk::template::BIP84Public;
+///
+/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
+/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let wallet: OfflineWallet<_> = Wallet::new_offline(
+///     BIP84Public(key.clone(), fingerprint, KeychainKind::External),
+///     Some(BIP84Public(key, fingerprint, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_new_address()?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)");
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct BIP84Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint, pub KeychainKind);
+
+impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84Public<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, KeyError> {
+        Ok(P2WPKH(segwit_v0::make_bipxx_public(84, self.0, self.1, self.2)?).build()?)
+    }
+}
+
+macro_rules! expand_make_bipxx {
+    ( $mod_name:ident, $ctx:ty ) => {
+        mod $mod_name {
+            use super::*;
+
+            pub(super) fn make_bipxx_private<K: DerivableKey<$ctx>>(
+                bip: u32,
+                key: K,
+                keychain: KeychainKind,
+            ) -> Result<impl ToDescriptorKey<$ctx>, KeyError> {
+                let mut derivation_path = Vec::with_capacity(4);
+                derivation_path.push(bip32::ChildNumber::from_hardened_idx(bip)?);
+                derivation_path.push(bip32::ChildNumber::from_hardened_idx(0)?);
+                derivation_path.push(bip32::ChildNumber::from_hardened_idx(0)?);
+
+                match keychain {
+                    KeychainKind::External => {
+                        derivation_path.push(bip32::ChildNumber::from_normal_idx(0)?)
+                    }
+                    KeychainKind::Internal => {
+                        derivation_path.push(bip32::ChildNumber::from_normal_idx(1)?)
+                    }
+                };
+
+                let derivation_path: bip32::DerivationPath = derivation_path.into();
+
+                Ok((key, derivation_path))
+            }
+            pub(super) fn make_bipxx_public<K: DerivableKey<$ctx>>(
+                bip: u32,
+                key: K,
+                parent_fingerprint: bip32::Fingerprint,
+                keychain: KeychainKind,
+            ) -> Result<impl ToDescriptorKey<$ctx>, KeyError> {
+                let derivation_path: bip32::DerivationPath = match keychain {
+                    KeychainKind::External => vec![bip32::ChildNumber::from_normal_idx(0)?].into(),
+                    KeychainKind::Internal => vec![bip32::ChildNumber::from_normal_idx(1)?].into(),
+                };
+
+                let mut source_path = Vec::with_capacity(3);
+                source_path.push(bip32::ChildNumber::from_hardened_idx(bip)?);
+                source_path.push(bip32::ChildNumber::from_hardened_idx(0)?);
+                source_path.push(bip32::ChildNumber::from_hardened_idx(0)?);
+                let source_path: bip32::DerivationPath = source_path.into();
+
+                Ok((key, (parent_fingerprint, source_path), derivation_path))
+            }
+        }
+    };
+}
+
+expand_make_bipxx!(legacy, Legacy);
+expand_make_bipxx!(segwit_v0, Segwitv0);
+
+#[cfg(test)]
+mod test {
+    // test existing descriptor templates, make sure they are expanded to the right descriptors
+
+    use super::*;
+    use crate::descriptor::DescriptorMeta;
+    use crate::keys::{KeyError, ValidNetworks};
+    use bitcoin::hashes::core::str::FromStr;
+    use bitcoin::network::constants::Network::Regtest;
+    use bitcoin::secp256k1::Secp256k1;
+    use bitcoin::util::bip32::ChildNumber;
+    use miniscript::descriptor::{DescriptorPublicKey, DescriptorPublicKeyCtx, KeyMap};
+    use miniscript::Descriptor;
+
+    // verify template descriptor generates expected address(es)
+    fn check(
+        desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError>,
+        is_witness: bool,
+        is_fixed: bool,
+        expected: &[&str],
+    ) {
+        let secp = Secp256k1::new();
+        let deriv_ctx =
+            DescriptorPublicKeyCtx::new(&secp, ChildNumber::from_normal_idx(0).unwrap());
+
+        let (desc, _key_map, _networks) = desc.unwrap();
+        assert_eq!(desc.is_witness(), is_witness);
+        assert_eq!(desc.is_fixed(), is_fixed);
+        for i in 0..expected.len() {
+            let index = i as u32;
+            let child_desc = if desc.is_fixed() {
+                desc.clone()
+            } else {
+                desc.derive(ChildNumber::from_normal_idx(index).unwrap())
+            };
+            let address = child_desc.address(Regtest, deriv_ctx).unwrap();
+            assert_eq!(address.to_string(), *expected.get(i).unwrap());
+        }
+    }
+
+    // P2PKH
+    #[test]
+    fn test_p2ph_template() {
+        let prvkey =
+            bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")
+                .unwrap();
+        check(
+            P2PKH(prvkey).build(),
+            false,
+            true,
+            &["mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT"],
+        );
+
+        let pubkey = bitcoin::PublicKey::from_str(
+            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
+        )
+        .unwrap();
+        check(
+            P2PKH(pubkey).build(),
+            false,
+            true,
+            &["muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi"],
+        );
+    }
+
+    // P2WPKH-P2SH `sh(wpkh(key))`
+    #[test]
+    fn test_p2wphp2sh_template() {
+        let prvkey =
+            bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")
+                .unwrap();
+        check(
+            P2WPKH_P2SH(prvkey).build(),
+            true,
+            true,
+            &["2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5"],
+        );
+
+        let pubkey = bitcoin::PublicKey::from_str(
+            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
+        )
+        .unwrap();
+        check(
+            P2WPKH_P2SH(pubkey).build(),
+            true,
+            true,
+            &["2N5LiC3CqzxDamRTPG1kiNv1FpNJQ7x28sb"],
+        );
+    }
+
+    // P2WPKH `wpkh(key)`
+    #[test]
+    fn test_p2wph_template() {
+        let prvkey =
+            bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")
+                .unwrap();
+        check(
+            P2WPKH(prvkey).build(),
+            true,
+            true,
+            &["bcrt1q4525hmgw265tl3drrl8jjta7ayffu6jfcwxx9y"],
+        );
+
+        let pubkey = bitcoin::PublicKey::from_str(
+            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
+        )
+        .unwrap();
+        check(
+            P2WPKH(pubkey).build(),
+            true,
+            true,
+            &["bcrt1qngw83fg8dz0k749cg7k3emc7v98wy0c7azaa6h"],
+        );
+    }
+
+    // BIP44 `pkh(key/44'/0'/0'/{0,1}/*)`
+    #[test]
+    fn test_bip44_template() {
+        let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+        check(
+            BIP44(prvkey, KeychainKind::External).build(),
+            false,
+            false,
+            &[
+                "n453VtnjDHPyDt2fDstKSu7A3YCJoHZ5g5",
+                "mvfrrumXgTtwFPWDNUecBBgzuMXhYM7KRP",
+                "mzYvhRAuQqbdSKMVVzXNYyqihgNdRadAUQ",
+            ],
+        );
+        check(
+            BIP44(prvkey, KeychainKind::Internal).build(),
+            false,
+            false,
+            &[
+                "muHF98X9KxEzdKrnFAX85KeHv96eXopaip",
+                "n4hpyLJE5ub6B5Bymv4eqFxS5KjrewSmYR",
+                "mgvkdv1ffmsXd2B1sRKQ5dByK3SzpG42rA",
+            ],
+        );
+    }
+
+    // BIP44 public `pkh(key/{0,1}/*)`
+    #[test]
+    fn test_bip44_public_template() {
+        let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU").unwrap();
+        let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap();
+        check(
+            BIP44Public(pubkey, fingerprint, KeychainKind::External).build(),
+            false,
+            false,
+            &[
+                "miNG7dJTzJqNbFS19svRdTCisC65dsubtR",
+                "n2UqaDbCjWSFJvpC84m3FjUk5UaeibCzYg",
+                "muCPpS6Ue7nkzeJMWDViw7Lkwr92Yc4K8g",
+            ],
+        );
+        check(
+            BIP44Public(pubkey, fingerprint, KeychainKind::Internal).build(),
+            false,
+            false,
+            &[
+                "moDr3vJ8wpt5nNxSK55MPq797nXJb2Ru9H",
+                "ms7A1Yt4uTezT2XkefW12AvLoko8WfNJMG",
+                "mhYiyat2rtEnV77cFfQsW32y1m2ceCGHPo",
+            ],
+        );
+    }
+
+    // BIP49 `sh(wpkh(key/49'/0'/0'/{0,1}/*))`
+    #[test]
+    fn test_bip49_template() {
+        let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+        check(
+            BIP49(prvkey, KeychainKind::External).build(),
+            true,
+            false,
+            &[
+                "2N9bCAJXGm168MjVwpkBdNt6ucka3PKVoUV",
+                "2NDckYkqrYyDMtttEav5hB3Bfw9EGAW5HtS",
+                "2NAFTVtksF9T4a97M7nyCjwUBD24QevZ5Z4",
+            ],
+        );
+        check(
+            BIP49(prvkey, KeychainKind::Internal).build(),
+            true,
+            false,
+            &[
+                "2NB3pA8PnzJLGV8YEKNDFpbViZv3Bm1K6CG",
+                "2NBiX2Wzxngb5rPiWpUiJQ2uLVB4HBjFD4p",
+                "2NA8ek4CdQ6aMkveYF6AYuEYNrftB47QGTn",
+            ],
+        );
+    }
+
+    // BIP49 public `sh(wpkh(key/{0,1}/*))`
+    #[test]
+    fn test_bip49_public_template() {
+        let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L").unwrap();
+        let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap();
+        check(
+            BIP49Public(pubkey, fingerprint, KeychainKind::External).build(),
+            true,
+            false,
+            &[
+                "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt",
+                "2NCTQfJ1sZa3wQ3pPseYRHbaNEpC3AquEfX",
+                "2MveFxAuC8BYPzTybx7FxSzW8HSd8ATT4z7",
+            ],
+        );
+        check(
+            BIP49Public(pubkey, fingerprint, KeychainKind::Internal).build(),
+            true,
+            false,
+            &[
+                "2NF2vttKibwyxigxtx95Zw8K7JhDbo5zPVJ",
+                "2Mtmyd8taksxNVWCJ4wVvaiss7QPZGcAJuH",
+                "2NBs3CTVYPr1HCzjB4YFsnWCPCtNg8uMEfp",
+            ],
+        );
+    }
+
+    // BIP84 `wpkh(key/84'/0'/0'/{0,1}/*)`
+    #[test]
+    fn test_bip84_template() {
+        let prvkey = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
+        check(
+            BIP84(prvkey, KeychainKind::External).build(),
+            true,
+            false,
+            &[
+                "bcrt1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvwtjf8s",
+                "bcrt1qx0v6zgfwe50m4kqc58cqzcyem7ay2sfl3gvqhp",
+                "bcrt1q4h7fq9zhxst6e69p3n882nfj649l7w9g3zccfp",
+            ],
+        );
+        check(
+            BIP84(prvkey, KeychainKind::Internal).build(),
+            true,
+            false,
+            &[
+                "bcrt1qtrwtz00wxl69e5xex7amy4xzlxkaefg3gfdkxa",
+                "bcrt1qqqasfhxpkkf7zrxqnkr2sfhn74dgsrc3e3ky45",
+                "bcrt1qpks7n0gq74hsgsz3phn5vuazjjq0f5eqhsgyce",
+            ],
+        );
+    }
+
+    // BIP84 public `wpkh(key/{0,1}/*)`
+    #[test]
+    fn test_bip84_public_template() {
+        let pubkey = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q").unwrap();
+        let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f").unwrap();
+        check(
+            BIP84Public(pubkey, fingerprint, KeychainKind::External).build(),
+            true,
+            false,
+            &[
+                "bcrt1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2prcdvd0h",
+                "bcrt1q3lncdlwq3lgcaaeyruynjnlccr0ve0kakh6ana",
+                "bcrt1qt9800y6xl3922jy3uyl0z33jh5wfpycyhcylr9",
+            ],
+        );
+        check(
+            BIP84Public(pubkey, fingerprint, KeychainKind::Internal).build(),
+            true,
+            false,
+            &[
+                "bcrt1qm6wqukenh7guu792lj2njgw9n78cmwsy8xy3z2",
+                "bcrt1q694twxtjn4nnrvnyvra769j0a23rllj5c6cgwp",
+                "bcrt1qhlac3c5ranv5w5emlnqs7wxhkxt8maelylcarp",
+            ],
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/error.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/error.rs.html new file mode 100644 index 0000000000..cd048a7951 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/error.rs.html @@ -0,0 +1,414 @@ +error.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+use std::fmt;
+
+use crate::{descriptor, wallet, wallet::address_validator};
+use bitcoin::OutPoint;
+
+/// Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet)
+#[derive(Debug)]
+pub enum Error {
+    /// Wrong number of bytes found when trying to convert to u32
+    InvalidU32Bytes(Vec<u8>),
+    /// Generic error
+    Generic(String),
+    /// This error is thrown when trying to convert Bare and Public key script to address
+    ScriptDoesntHaveAddressForm,
+    /// Found multiple outputs when `single_recipient` option has been specified
+    SingleRecipientMultipleOutputs,
+    /// `single_recipient` option is selected but neither `drain_wallet` nor `manually_selected_only` are
+    SingleRecipientNoInputs,
+    /// Cannot build a tx without recipients
+    NoRecipients,
+    /// `manually_selected_only` option is selected but no utxo has been passed
+    NoUtxosSelected,
+    /// Output created is under the dust limit, 546 satoshis
+    OutputBelowDustLimit(usize),
+    /// Wallet's UTXO set is not enough to cover recipient's requested plus fee
+    InsufficientFunds,
+    /// Branch and bound coin selection possible attempts with sufficiently big UTXO set could grow
+    /// exponentially, thus a limit is set, and when hit, this error is thrown
+    BnBTotalTriesExceeded,
+    /// Branch and bound coin selection tries to avoid needing a change by finding the right inputs for
+    /// the desired outputs plus fee, if there is not such combination this error is thrown
+    BnBNoExactMatch,
+    /// Happens when trying to spend an UTXO that is not in the internal database
+    UnknownUTXO,
+    /// Thrown when a tx is not found in the internal database
+    TransactionNotFound,
+    /// Happens when trying to bump a transaction that is already confirmed
+    TransactionConfirmed,
+    /// Trying to replace a tx that has a sequence >= `0xFFFFFFFE`
+    IrreplaceableTransaction,
+    /// When bumping a tx the fee rate requested is lower than required
+    FeeRateTooLow {
+        /// Required fee rate (satoshi/vbyte)
+        required: crate::types::FeeRate,
+    },
+    /// When bumping a tx the absolute fee requested is lower than replaced tx absolute fee
+    FeeTooLow {
+        /// Required fee absolute value (satoshi)
+        required: u64,
+    },
+    /// In order to use the [`TxBuilder::add_global_xpubs`] option every extended
+    /// key in the descriptor must either be a master key itself (having depth = 0) or have an
+    /// explicit origin provided
+    ///
+    /// [`TxBuilder::add_global_xpubs`]: crate::wallet::tx_builder::TxBuilder::add_global_xpubs
+    MissingKeyOrigin(String),
+    /// Error while working with [`keys`](crate::keys)
+    Key(crate::keys::KeyError),
+    /// Descriptor checksum mismatch
+    ChecksumMismatch,
+    /// Spending policy is not compatible with this [`KeychainKind`](crate::types::KeychainKind)
+    SpendingPolicyRequired(crate::types::KeychainKind),
+    /// Error while extracting and manipulating policies
+    InvalidPolicyPathError(crate::descriptor::policy::PolicyError),
+    /// Signing error
+    Signer(crate::wallet::signer::SignerError),
+
+    // Blockchain interface errors
+    /// Thrown when trying to call a method that requires a network connection, [`Wallet::sync`](crate::Wallet::sync) and [`Wallet::broadcast`](crate::Wallet::broadcast)
+    /// This error is thrown when creating the Client for the first time, while recovery attempts are tried
+    /// during the sync
+    OfflineClient,
+    /// Progress value must be between `0.0` (included) and `100.0` (included)
+    InvalidProgressValue(f32),
+    /// Progress update error (maybe the channel has been closed)
+    ProgressUpdateError,
+    /// Requested outpoint doesn't exist in the tx (vout greater than available outputs)
+    InvalidOutpoint(OutPoint),
+
+    /// Error related to the parsing and usage of descriptors
+    Descriptor(crate::descriptor::error::Error),
+    /// Error that can be returned to fail the validation of an address
+    AddressValidator(crate::wallet::address_validator::AddressValidatorError),
+    /// Encoding error
+    Encode(bitcoin::consensus::encode::Error),
+    /// Miniscript error
+    Miniscript(miniscript::Error),
+    /// BIP32 error
+    BIP32(bitcoin::util::bip32::Error),
+    /// An ECDSA error
+    Secp256k1(bitcoin::secp256k1::Error),
+    /// Error serializing or deserializing JSON data
+    JSON(serde_json::Error),
+    /// Hex decoding error
+    Hex(bitcoin::hashes::hex::Error),
+    /// Partially signed bitcoin transaction error
+    PSBT(bitcoin::util::psbt::Error),
+
+    //KeyMismatch(bitcoin::secp256k1::PublicKey, bitcoin::secp256k1::PublicKey),
+    //MissingInputUTXO(usize),
+    //InvalidAddressNetwork(Address),
+    //DifferentTransactions,
+    //DifferentDescriptorStructure,
+    //Uncapable(crate::blockchain::Capability),
+    //MissingCachedAddresses,
+    #[cfg(feature = "electrum")]
+    /// Electrum client error
+    Electrum(electrum_client::Error),
+    #[cfg(feature = "esplora")]
+    /// Esplora client error
+    Esplora(crate::blockchain::esplora::EsploraError),
+    #[cfg(feature = "compact_filters")]
+    /// Compact filters client error)
+    CompactFilters(crate::blockchain::compact_filters::CompactFiltersError),
+    #[cfg(feature = "key-value-db")]
+    /// Sled database error
+    Sled(sled::Error),
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl std::error::Error for Error {}
+
+macro_rules! impl_error {
+    ( $from:ty, $to:ident ) => {
+        impl_error!($from, $to, Error);
+    };
+    ( $from:ty, $to:ident, $impl_for:ty ) => {
+        impl std::convert::From<$from> for $impl_for {
+            fn from(err: $from) -> Self {
+                <$impl_for>::$to(err)
+            }
+        }
+    };
+}
+
+impl_error!(descriptor::error::Error, Descriptor);
+impl_error!(address_validator::AddressValidatorError, AddressValidator);
+impl_error!(descriptor::policy::PolicyError, InvalidPolicyPathError);
+impl_error!(wallet::signer::SignerError, Signer);
+
+impl From<crate::keys::KeyError> for Error {
+    fn from(key_error: crate::keys::KeyError) -> Error {
+        match key_error {
+            crate::keys::KeyError::Miniscript(inner) => Error::Miniscript(inner),
+            crate::keys::KeyError::BIP32(inner) => Error::BIP32(inner),
+            crate::keys::KeyError::InvalidChecksum => Error::ChecksumMismatch,
+            e => Error::Key(e),
+        }
+    }
+}
+
+impl_error!(bitcoin::consensus::encode::Error, Encode);
+impl_error!(miniscript::Error, Miniscript);
+impl_error!(bitcoin::util::bip32::Error, BIP32);
+impl_error!(bitcoin::secp256k1::Error, Secp256k1);
+impl_error!(serde_json::Error, JSON);
+impl_error!(bitcoin::hashes::hex::Error, Hex);
+impl_error!(bitcoin::util::psbt::Error, PSBT);
+
+#[cfg(feature = "electrum")]
+impl_error!(electrum_client::Error, Electrum);
+#[cfg(feature = "esplora")]
+impl_error!(crate::blockchain::esplora::EsploraError, Esplora);
+#[cfg(feature = "key-value-db")]
+impl_error!(sled::Error, Sled);
+
+#[cfg(feature = "compact_filters")]
+impl From<crate::blockchain::compact_filters::CompactFiltersError> for Error {
+    fn from(other: crate::blockchain::compact_filters::CompactFiltersError) -> Self {
+        match other {
+            crate::blockchain::compact_filters::CompactFiltersError::Global(e) => *e,
+            err @ _ => Error::CompactFilters(err),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/keys/bip39.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/keys/bip39.rs.html new file mode 100644 index 0000000000..b7bd41a2f9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/keys/bip39.rs.html @@ -0,0 +1,352 @@ +bip39.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! BIP-0039
+
+// TODO: maybe write our own implementation of bip39? Seems stupid to have an extra dependency for
+// something that should be fairly simple to re-implement.
+
+use bitcoin::util::bip32;
+use bitcoin::Network;
+
+use miniscript::ScriptContext;
+
+use bip39::{Language, Mnemonic, MnemonicType, Seed};
+
+use super::{any_network, DerivableKey, DescriptorKey, GeneratableKey, GeneratedKey, KeyError};
+
+/// Type for a BIP39 mnemonic with an optional passphrase
+pub type MnemonicWithPassphrase = (Mnemonic, Option<String>);
+
+#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for Seed {
+    fn add_metadata(
+        self,
+        source: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let xprv = bip32::ExtendedPrivKey::new_master(Network::Bitcoin, &self.as_bytes())?;
+        let descriptor_key = xprv.add_metadata(source, derivation_path)?;
+
+        // here we must choose one network to build the xpub, but since the bip39 standard doesn't
+        // encode the network, the xpub we create is actually valid everywhere. so we override the
+        // valid networks with `any_network()`.
+        Ok(descriptor_key.override_valid_networks(any_network()))
+    }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for MnemonicWithPassphrase {
+    fn add_metadata(
+        self,
+        source: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let (mnemonic, passphrase) = self;
+        let seed = Seed::new(&mnemonic, passphrase.as_deref().unwrap_or(""));
+        seed.add_metadata(source, derivation_path)
+    }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for Mnemonic {
+    fn add_metadata(
+        self,
+        source: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        (self, None).add_metadata(source, derivation_path)
+    }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
+impl<Ctx: ScriptContext> GeneratableKey<Ctx> for Mnemonic {
+    type Entropy = [u8; 32];
+
+    type Options = (MnemonicType, Language);
+    type Error = Option<bip39::ErrorKind>;
+
+    fn generate_with_entropy(
+        (mnemonic_type, language): Self::Options,
+        entropy: Self::Entropy,
+    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
+        let entropy = &entropy.as_ref()[..(mnemonic_type.entropy_bits() / 8)];
+        let mnemonic = Mnemonic::from_entropy(entropy, language).map_err(|e| e.downcast().ok())?;
+
+        Ok(GeneratedKey::new(mnemonic, any_network()))
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::str::FromStr;
+
+    use bitcoin::util::bip32;
+
+    use bip39::{Language, Mnemonic, MnemonicType};
+
+    use crate::keys::{any_network, GeneratableKey, GeneratedKey};
+
+    #[test]
+    fn test_keys_bip39_mnemonic() {
+        let mnemonic =
+            "aim bunker wash balance finish force paper analyst cabin spoon stable organ";
+        let mnemonic = Mnemonic::from_phrase(mnemonic, Language::English).unwrap();
+        let path = bip32::DerivationPath::from_str("m/44'/0'/0'/0").unwrap();
+
+        let key = (mnemonic, path);
+        let (desc, keys, networks) = crate::descriptor!(wpkh(key)).unwrap();
+        assert_eq!(desc.to_string(), "wpkh([be83839f/44'/0'/0']xpub6DCQ1YcqvZtSwGWMrwHELPehjWV3f2MGZ69yBADTxFEUAoLwb5Mp5GniQK6tTp3AgbngVz9zEFbBJUPVnkG7LFYt8QMTfbrNqs6FNEwAPKA/0/*)");
+        assert_eq!(keys.len(), 1);
+        assert_eq!(networks.len(), 3);
+    }
+
+    #[test]
+    fn test_keys_bip39_mnemonic_passphrase() {
+        let mnemonic =
+            "aim bunker wash balance finish force paper analyst cabin spoon stable organ";
+        let mnemonic = Mnemonic::from_phrase(mnemonic, Language::English).unwrap();
+        let path = bip32::DerivationPath::from_str("m/44'/0'/0'/0").unwrap();
+
+        let key = ((mnemonic, Some("passphrase".into())), path);
+        let (desc, keys, networks) = crate::descriptor!(wpkh(key)).unwrap();
+        assert_eq!(desc.to_string(), "wpkh([8f6cb80c/44'/0'/0']xpub6DWYS8bbihFevy29M4cbw4ZR3P5E12jB8R88gBDWCTCNpYiDHhYWNywrCF9VZQYagzPmsZpxXpytzSoxynyeFr4ZyzheVjnpLKuse4fiwZw/0/*)");
+        assert_eq!(keys.len(), 1);
+        assert_eq!(networks.len(), 3);
+    }
+
+    #[test]
+    fn test_keys_generate_bip39() {
+        let generated_mnemonic: GeneratedKey<_, miniscript::Segwitv0> =
+            Mnemonic::generate_with_entropy(
+                (MnemonicType::Words12, Language::English),
+                crate::keys::test::TEST_ENTROPY,
+            )
+            .unwrap();
+        assert_eq!(generated_mnemonic.valid_networks, any_network());
+        assert_eq!(
+            generated_mnemonic.to_string(),
+            "primary fetch primary fetch primary fetch primary fetch primary fetch primary fever"
+        );
+
+        let generated_mnemonic: GeneratedKey<_, miniscript::Segwitv0> =
+            Mnemonic::generate_with_entropy(
+                (MnemonicType::Words24, Language::English),
+                crate::keys::test::TEST_ENTROPY,
+            )
+            .unwrap();
+        assert_eq!(generated_mnemonic.valid_networks, any_network());
+        assert_eq!(generated_mnemonic.to_string(), "primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary fetch primary foster");
+    }
+
+    #[test]
+    fn test_keys_generate_bip39_random() {
+        let generated_mnemonic: GeneratedKey<_, miniscript::Segwitv0> =
+            Mnemonic::generate((MnemonicType::Words12, Language::English)).unwrap();
+        assert_eq!(generated_mnemonic.valid_networks, any_network());
+
+        let generated_mnemonic: GeneratedKey<_, miniscript::Segwitv0> =
+            Mnemonic::generate((MnemonicType::Words24, Language::English)).unwrap();
+        assert_eq!(generated_mnemonic.valid_networks, any_network());
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/keys/mod.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/keys/mod.rs.html new file mode 100644 index 0000000000..a18ef6494a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/keys/mod.rs.html @@ -0,0 +1,1482 @@ +mod.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Key formats
+
+use std::any::TypeId;
+use std::collections::HashSet;
+use std::marker::PhantomData;
+use std::ops::Deref;
+
+use bitcoin::secp256k1;
+
+use bitcoin::util::bip32;
+use bitcoin::{Network, PrivateKey, PublicKey};
+
+pub use miniscript::descriptor::{
+    DescriptorPublicKey, DescriptorSecretKey, DescriptorSinglePriv, DescriptorSinglePub,
+    SortedMultiVec,
+};
+use miniscript::descriptor::{DescriptorXKey, KeyMap};
+pub use miniscript::ScriptContext;
+use miniscript::{Miniscript, Terminal};
+
+use crate::wallet::utils::SecpCtx;
+
+#[cfg(feature = "keys-bip39")]
+#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
+pub mod bip39;
+
+/// Set of valid networks for a key
+pub type ValidNetworks = HashSet<Network>;
+
+/// Create a set containing mainnet, testnet and regtest
+pub fn any_network() -> ValidNetworks {
+    vec![Network::Bitcoin, Network::Testnet, Network::Regtest]
+        .into_iter()
+        .collect()
+}
+/// Create a set only containing mainnet
+pub fn mainnet_network() -> ValidNetworks {
+    vec![Network::Bitcoin].into_iter().collect()
+}
+/// Create a set containing testnet and regtest
+pub fn test_networks() -> ValidNetworks {
+    vec![Network::Testnet, Network::Regtest]
+        .into_iter()
+        .collect()
+}
+/// Compute the intersection of two sets
+pub fn merge_networks(a: &ValidNetworks, b: &ValidNetworks) -> ValidNetworks {
+    a.intersection(b).cloned().collect()
+}
+
+/// Container for public or secret keys
+#[derive(Debug)]
+pub enum DescriptorKey<Ctx: ScriptContext> {
+    #[doc(hidden)]
+    Public(DescriptorPublicKey, ValidNetworks, PhantomData<Ctx>),
+    #[doc(hidden)]
+    Secret(DescriptorSecretKey, ValidNetworks, PhantomData<Ctx>),
+}
+
+impl<Ctx: ScriptContext> DescriptorKey<Ctx> {
+    /// Create an instance given a public key and a set of valid networks
+    pub fn from_public(public: DescriptorPublicKey, networks: ValidNetworks) -> Self {
+        DescriptorKey::Public(public, networks, PhantomData)
+    }
+
+    /// Create an instance given a secret key and a set of valid networks
+    pub fn from_secret(secret: DescriptorSecretKey, networks: ValidNetworks) -> Self {
+        DescriptorKey::Secret(secret, networks, PhantomData)
+    }
+
+    /// Override the computed set of valid networks
+    pub fn override_valid_networks(self, networks: ValidNetworks) -> Self {
+        match self {
+            DescriptorKey::Public(key, _, _) => DescriptorKey::Public(key, networks, PhantomData),
+            DescriptorKey::Secret(key, _, _) => DescriptorKey::Secret(key, networks, PhantomData),
+        }
+    }
+
+    // This method is used internally by `bdk::fragment!` and `bdk::descriptor!`. It has to be
+    // public because it is effectively called by external crates, once the macros are expanded,
+    // but since it is not meant to be part of the public api we hide it from the docs.
+    #[doc(hidden)]
+    pub fn extract(
+        self,
+        secp: &SecpCtx,
+    ) -> Result<(DescriptorPublicKey, KeyMap, ValidNetworks), KeyError> {
+        match self {
+            DescriptorKey::Public(public, valid_networks, _) => {
+                Ok((public, KeyMap::default(), valid_networks))
+            }
+            DescriptorKey::Secret(secret, valid_networks, _) => {
+                let mut key_map = KeyMap::with_capacity(1);
+
+                let public = secret
+                    .as_public(secp)
+                    .map_err(|e| miniscript::Error::Unexpected(e.to_string()))?;
+                key_map.insert(public.clone(), secret);
+
+                Ok((public, key_map, valid_networks))
+            }
+        }
+    }
+}
+
+/// Enum representation of the known valid [`ScriptContext`]s
+#[derive(Debug, Eq, PartialEq, Copy, Clone)]
+pub enum ScriptContextEnum {
+    /// Legacy scripts
+    Legacy,
+    /// Segwitv0 scripts
+    Segwitv0,
+}
+
+impl ScriptContextEnum {
+    /// Returns whether the script context is [`ScriptContextEnum::Legacy`]
+    pub fn is_legacy(&self) -> bool {
+        self == &ScriptContextEnum::Legacy
+    }
+
+    /// Returns whether the script context is [`ScriptContextEnum::Segwitv0`]
+    pub fn is_segwit_v0(&self) -> bool {
+        self == &ScriptContextEnum::Segwitv0
+    }
+}
+
+/// Trait that adds extra useful methods to [`ScriptContext`]s
+pub trait ExtScriptContext: ScriptContext {
+    /// Returns the [`ScriptContext`] as a [`ScriptContextEnum`]
+    fn as_enum() -> ScriptContextEnum;
+
+    /// Returns whether the script context is [`Legacy`](miniscript::Legacy)
+    fn is_legacy() -> bool {
+        Self::as_enum().is_legacy()
+    }
+
+    /// Returns whether the script context is [`Segwitv0`](miniscript::Segwitv0)
+    fn is_segwit_v0() -> bool {
+        Self::as_enum().is_segwit_v0()
+    }
+}
+
+impl<Ctx: ScriptContext + 'static> ExtScriptContext for Ctx {
+    fn as_enum() -> ScriptContextEnum {
+        match TypeId::of::<Ctx>() {
+            t if t == TypeId::of::<miniscript::Legacy>() => ScriptContextEnum::Legacy,
+            t if t == TypeId::of::<miniscript::Segwitv0>() => ScriptContextEnum::Segwitv0,
+            _ => unimplemented!("Unknown ScriptContext type"),
+        }
+    }
+}
+
+/// Trait for objects that can be turned into a public or secret [`DescriptorKey`]
+///
+/// The generic type `Ctx` is used to define the context in which the key is valid: some key
+/// formats, like the mnemonics used by Electrum wallets, encode internally whether the wallet is
+/// legacy or segwit. Thus, trying to turn a valid legacy mnemonic into a `DescriptorKey`
+/// that would become part of a segwit descriptor should fail.
+///
+/// For key types that do care about this, the [`ExtScriptContext`] trait provides some useful
+/// methods that can be used to check at runtime which `Ctx` is being used.
+///
+/// For key types that can do this check statically (because they can only work within a
+/// single `Ctx`), the "specialized" trait can be implemented to make the compiler handle the type
+/// checking.
+///
+/// Keys also have control over the networks they support: constructing the return object with
+/// [`DescriptorKey::from_public`] or [`DescriptorKey::from_secret`] allows to specify a set of
+/// [`ValidNetworks`].
+///
+/// ## Examples
+///
+/// Key type valid in any context:
+///
+/// ```
+/// use bdk::bitcoin::PublicKey;
+///
+/// use bdk::keys::{DescriptorKey, KeyError, ScriptContext, ToDescriptorKey};
+///
+/// pub struct MyKeyType {
+///     pubkey: PublicKey,
+/// }
+///
+/// impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for MyKeyType {
+///     fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+///         self.pubkey.to_descriptor_key()
+///     }
+/// }
+/// ```
+///
+/// Key type that is only valid on mainnet:
+///
+/// ```
+/// use bdk::bitcoin::PublicKey;
+///
+/// use bdk::keys::{
+///     mainnet_network, DescriptorKey, DescriptorPublicKey, DescriptorSinglePub, KeyError,
+///     ScriptContext, ToDescriptorKey,
+/// };
+///
+/// pub struct MyKeyType {
+///     pubkey: PublicKey,
+/// }
+///
+/// impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for MyKeyType {
+///     fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+///         Ok(DescriptorKey::from_public(
+///             DescriptorPublicKey::SinglePub(DescriptorSinglePub {
+///                 origin: None,
+///                 key: self.pubkey,
+///             }),
+///             mainnet_network(),
+///         ))
+///     }
+/// }
+/// ```
+///
+/// Key type that internally encodes in which context it's valid. The context is checked at runtime:
+///
+/// ```
+/// use bdk::bitcoin::PublicKey;
+///
+/// use bdk::keys::{DescriptorKey, ExtScriptContext, KeyError, ScriptContext, ToDescriptorKey};
+///
+/// pub struct MyKeyType {
+///     is_legacy: bool,
+///     pubkey: PublicKey,
+/// }
+///
+/// impl<Ctx: ScriptContext + 'static> ToDescriptorKey<Ctx> for MyKeyType {
+///     fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+///         if Ctx::is_legacy() == self.is_legacy {
+///             self.pubkey.to_descriptor_key()
+///         } else {
+///             Err(KeyError::InvalidScriptContext)
+///         }
+///     }
+/// }
+/// ```
+///
+/// Key type that can only work within [`miniscript::Segwitv0`] context. Only the specialized version
+/// of the trait is implemented.
+///
+/// This example deliberately fails to compile, to demonstrate how the compiler can catch when keys
+/// are misused. In this case, the "segwit-only" key is used to build a `pkh()` descriptor, which
+/// makes the compiler (correctly) fail.
+///
+/// ```compile_fail
+/// use bdk::bitcoin::PublicKey;
+/// use std::str::FromStr;
+///
+/// use bdk::keys::{DescriptorKey, KeyError, ToDescriptorKey};
+///
+/// pub struct MySegwitOnlyKeyType {
+///     pubkey: PublicKey,
+/// }
+///
+/// impl ToDescriptorKey<bdk::miniscript::Segwitv0> for MySegwitOnlyKeyType {
+///     fn to_descriptor_key(self) -> Result<DescriptorKey<bdk::miniscript::Segwitv0>, KeyError> {
+///         self.pubkey.to_descriptor_key()
+///     }
+/// }
+///
+/// let key = MySegwitOnlyKeyType {
+///     pubkey: PublicKey::from_str("...")?,
+/// };
+/// let (descriptor, _, _) = bdk::descriptor!(pkh(key))?;
+/// //                                       ^^^^^ changing this to `wpkh` would make it compile
+///
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub trait ToDescriptorKey<Ctx: ScriptContext>: Sized {
+    /// Turn the key into a [`DescriptorKey`] within the requested [`ScriptContext`]
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError>;
+}
+
+/// Trait for keys that can be derived.
+///
+/// When extra metadata are provided, a [`DerivableKey`] can be transofrmed into a
+/// [`DescriptorKey`]: the trait [`ToDescriptorKey`] is automatically implemented
+/// for `(DerivableKey, DerivationPath)` and
+/// `(DerivableKey, KeySource, DerivationPath)` tuples.
+///
+/// For key types that don't encode any indication about the path to use (like bip39), it's
+/// generally recommended to implemented this trait instead of [`ToDescriptorKey`]. The same
+/// rules regarding script context and valid networks apply.
+///
+/// [`DerivationPath`]: (bip32::DerivationPath)
+pub trait DerivableKey<Ctx: ScriptContext> {
+    /// Add a extra metadata, consume `self` and turn it into a [`DescriptorKey`]
+    fn add_metadata(
+        self,
+        origin: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError>;
+}
+
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPubKey {
+    fn add_metadata(
+        self,
+        origin: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        DescriptorPublicKey::XPub(DescriptorXKey {
+            origin,
+            xkey: self,
+            derivation_path,
+            is_wildcard: true,
+        })
+        .to_descriptor_key()
+    }
+}
+
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPrivKey {
+    fn add_metadata(
+        self,
+        origin: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        DescriptorSecretKey::XPrv(DescriptorXKey {
+            origin,
+            xkey: self,
+            derivation_path,
+            is_wildcard: true,
+        })
+        .to_descriptor_key()
+    }
+}
+
+/// Output of a [`GeneratableKey`] key generation
+pub struct GeneratedKey<K, Ctx: ScriptContext> {
+    key: K,
+    valid_networks: ValidNetworks,
+    phantom: PhantomData<Ctx>,
+}
+
+impl<K, Ctx: ScriptContext> GeneratedKey<K, Ctx> {
+    fn new(key: K, valid_networks: ValidNetworks) -> Self {
+        GeneratedKey {
+            key,
+            valid_networks,
+            phantom: PhantomData,
+        }
+    }
+
+    /// Consumes `self` and returns the key
+    pub fn into_key(self) -> K {
+        self.key
+    }
+}
+
+impl<K, Ctx: ScriptContext> Deref for GeneratedKey<K, Ctx> {
+    type Target = K;
+
+    fn deref(&self) -> &Self::Target {
+        &self.key
+    }
+}
+
+// Make generated "derivable" keys themselves "derivable". Also make sure they are assigned the
+// right `valid_networks`.
+impl<Ctx, K> DerivableKey<Ctx> for GeneratedKey<K, Ctx>
+where
+    Ctx: ScriptContext,
+    K: DerivableKey<Ctx>,
+{
+    fn add_metadata(
+        self,
+        origin: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let descriptor_key = self.key.add_metadata(origin, derivation_path)?;
+        Ok(descriptor_key.override_valid_networks(self.valid_networks))
+    }
+}
+
+// Make generated keys directly usable in descriptors, and make sure they get assigned the right
+// `valid_networks`.
+impl<Ctx, K> ToDescriptorKey<Ctx> for GeneratedKey<K, Ctx>
+where
+    Ctx: ScriptContext,
+    K: ToDescriptorKey<Ctx>,
+{
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let desc_key = self.key.to_descriptor_key()?;
+        Ok(desc_key.override_valid_networks(self.valid_networks))
+    }
+}
+
+/// Trait for keys that can be generated
+///
+/// The same rules about [`ScriptContext`] and [`ValidNetworks`] from [`ToDescriptorKey`] apply.
+///
+/// This trait is particularly useful when combined with [`DerivableKey`]: if `Self`
+/// implements it, the returned [`GeneratedKey`] will also implement it. The same is true for
+/// [`ToDescriptorKey`]: the generated keys can be directly used in descriptors if `Self` is also
+/// [`ToDescriptorKey`].
+pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
+    /// Type specifying the amount of entropy required e.g. [u8;32]
+    type Entropy: AsMut<[u8]> + Default;
+
+    /// Extra options required by the `generate_with_entropy`
+    type Options;
+    /// Returned error in case of failure
+    type Error: std::fmt::Debug;
+
+    /// Generate a key given the extra options and the entropy
+    fn generate_with_entropy(
+        options: Self::Options,
+        entropy: Self::Entropy,
+    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error>;
+
+    /// Generate a key given the options with a random entropy
+    fn generate(options: Self::Options) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
+        use rand::{thread_rng, Rng};
+
+        let mut entropy = Self::Entropy::default();
+        thread_rng().fill(entropy.as_mut());
+        Self::generate_with_entropy(options, entropy)
+    }
+}
+
+/// Trait that allows generating a key with the default options
+///
+/// This trait is automatically implemented if the [`GeneratableKey::Options`] implements [`Default`].
+pub trait GeneratableDefaultOptions<Ctx>: GeneratableKey<Ctx>
+where
+    Ctx: ScriptContext,
+    <Self as GeneratableKey<Ctx>>::Options: Default,
+{
+    /// Generate a key with the default options and a given entropy
+    fn generate_with_entropy_default(
+        entropy: Self::Entropy,
+    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
+        Self::generate_with_entropy(Default::default(), entropy)
+    }
+
+    /// Generate a key with the default options and a random entropy
+    fn generate_default() -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
+        Self::generate(Default::default())
+    }
+}
+
+/// Automatic implementation of [`GeneratableDefaultOptions`] for [`GeneratableKey`]s where
+/// `Options` implements `Default`
+impl<Ctx, K> GeneratableDefaultOptions<Ctx> for K
+where
+    Ctx: ScriptContext,
+    K: GeneratableKey<Ctx>,
+    <K as GeneratableKey<Ctx>>::Options: Default,
+{
+}
+
+impl<Ctx: ScriptContext> GeneratableKey<Ctx> for bip32::ExtendedPrivKey {
+    type Entropy = [u8; 32];
+
+    type Options = ();
+    type Error = bip32::Error;
+
+    fn generate_with_entropy(
+        _: Self::Options,
+        entropy: Self::Entropy,
+    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
+        // pick a arbitrary network here, but say that we support all of them
+        let xprv = bip32::ExtendedPrivKey::new_master(Network::Bitcoin, entropy.as_ref())?;
+        Ok(GeneratedKey::new(xprv, any_network()))
+    }
+}
+
+/// Options for generating a [`PrivateKey`]
+///
+/// Defaults to creating compressed keys, which save on-chain bytes and fees
+#[derive(Debug, Copy, Clone)]
+pub struct PrivateKeyGenerateOptions {
+    /// Whether the generated key should be "compressed" or not
+    pub compressed: bool,
+}
+
+impl Default for PrivateKeyGenerateOptions {
+    fn default() -> Self {
+        PrivateKeyGenerateOptions { compressed: true }
+    }
+}
+
+impl<Ctx: ScriptContext> GeneratableKey<Ctx> for PrivateKey {
+    type Entropy = [u8; secp256k1::constants::SECRET_KEY_SIZE];
+
+    type Options = PrivateKeyGenerateOptions;
+    type Error = bip32::Error;
+
+    fn generate_with_entropy(
+        options: Self::Options,
+        entropy: Self::Entropy,
+    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> {
+        // pick a arbitrary network here, but say that we support all of them
+        let key = secp256k1::SecretKey::from_slice(&entropy)?;
+        let private_key = PrivateKey {
+            compressed: options.compressed,
+            network: Network::Bitcoin,
+            key,
+        };
+
+        Ok(GeneratedKey::new(private_key, any_network()))
+    }
+}
+
+impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> ToDescriptorKey<Ctx> for (T, bip32::DerivationPath) {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        self.0.add_metadata(None, self.1)
+    }
+}
+
+impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> ToDescriptorKey<Ctx>
+    for (T, bip32::KeySource, bip32::DerivationPath)
+{
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        self.0.add_metadata(Some(self.1), self.2)
+    }
+}
+
+fn expand_multi_keys<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
+    pks: Vec<Pk>,
+    secp: &SecpCtx,
+) -> Result<(Vec<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError> {
+    let (pks, key_maps_networks): (Vec<_>, Vec<_>) = pks
+        .into_iter()
+        .map(|key| Ok::<_, KeyError>(key.to_descriptor_key()?.extract(secp)?))
+        .collect::<Result<Vec<_>, _>>()?
+        .into_iter()
+        .map(|(a, b, c)| (a, (b, c)))
+        .unzip();
+
+    let (key_map, valid_networks) = key_maps_networks.into_iter().fold(
+        (KeyMap::default(), any_network()),
+        |(mut keys_acc, net_acc), (key, net)| {
+            keys_acc.extend(key.into_iter());
+            let net_acc = merge_networks(&net_acc, &net);
+
+            (keys_acc, net_acc)
+        },
+    );
+
+    Ok((pks, key_map, valid_networks))
+}
+
+// Used internally by `bdk::fragment!` to build `pk_k()` fragments
+#[doc(hidden)]
+pub fn make_pk<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
+    descriptor_key: Pk,
+    secp: &SecpCtx,
+) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), KeyError> {
+    let (key, key_map, valid_networks) = descriptor_key.to_descriptor_key()?.extract(secp)?;
+
+    Ok((
+        Miniscript::from_ast(Terminal::PkK(key))?,
+        key_map,
+        valid_networks,
+    ))
+}
+
+// Used internally by `bdk::fragment!` to build `multi()` fragments
+#[doc(hidden)]
+pub fn make_multi<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
+    thresh: usize,
+    pks: Vec<Pk>,
+    secp: &SecpCtx,
+) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), KeyError> {
+    let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
+
+    Ok((
+        Miniscript::from_ast(Terminal::Multi(thresh, pks))?,
+        key_map,
+        valid_networks,
+    ))
+}
+
+// Used internally by `bdk::descriptor!` to build `sortedmulti()` fragments
+#[doc(hidden)]
+pub fn make_sortedmulti_inner<Pk: ToDescriptorKey<Ctx>, Ctx: ScriptContext>(
+    thresh: usize,
+    pks: Vec<Pk>,
+    secp: &SecpCtx,
+) -> Result<
+    (
+        SortedMultiVec<DescriptorPublicKey, Ctx>,
+        KeyMap,
+        ValidNetworks,
+    ),
+    KeyError,
+> {
+    let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
+
+    Ok((SortedMultiVec::new(thresh, pks)?, key_map, valid_networks))
+}
+
+/// The "identity" conversion is used internally by some `bdk::fragment`s
+impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorKey<Ctx> {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        Ok(self)
+    }
+}
+
+impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorPublicKey {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let networks = match self {
+            DescriptorPublicKey::SinglePub(_) => any_network(),
+            DescriptorPublicKey::XPub(DescriptorXKey { xkey, .. })
+                if xkey.network == Network::Bitcoin =>
+            {
+                mainnet_network()
+            }
+            _ => test_networks(),
+        };
+
+        Ok(DescriptorKey::from_public(self, networks))
+    }
+}
+
+impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PublicKey {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        DescriptorPublicKey::SinglePub(DescriptorSinglePub {
+            key: self,
+            origin: None,
+        })
+        .to_descriptor_key()
+    }
+}
+
+impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for DescriptorSecretKey {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let networks = match &self {
+            DescriptorSecretKey::SinglePriv(sk) if sk.key.network == Network::Bitcoin => {
+                mainnet_network()
+            }
+            DescriptorSecretKey::XPrv(DescriptorXKey { xkey, .. })
+                if xkey.network == Network::Bitcoin =>
+            {
+                mainnet_network()
+            }
+            _ => test_networks(),
+        };
+
+        Ok(DescriptorKey::from_secret(self, networks))
+    }
+}
+
+impl<Ctx: ScriptContext> ToDescriptorKey<Ctx> for PrivateKey {
+    fn to_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        DescriptorSecretKey::SinglePriv(DescriptorSinglePriv {
+            key: self,
+            origin: None,
+        })
+        .to_descriptor_key()
+    }
+}
+
+/// Errors thrown while working with [`keys`](crate::keys)
+#[derive(Debug)]
+pub enum KeyError {
+    /// The key cannot exist in the given script context
+    InvalidScriptContext,
+    /// The key is not valid for the given network
+    InvalidNetwork,
+    /// The key has an invalid checksum
+    InvalidChecksum,
+
+    /// Custom error message
+    Message(String),
+
+    /// BIP32 error
+    BIP32(bitcoin::util::bip32::Error),
+    /// Miniscript error
+    Miniscript(miniscript::Error),
+}
+
+impl_error!(miniscript::Error, Miniscript, KeyError);
+impl_error!(bitcoin::util::bip32::Error, BIP32, KeyError);
+
+impl std::fmt::Display for KeyError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl std::error::Error for KeyError {}
+
+#[cfg(test)]
+pub mod test {
+    use bitcoin::util::bip32;
+
+    use super::*;
+
+    pub const TEST_ENTROPY: [u8; 32] = [0xAA; 32];
+
+    #[test]
+    fn test_keys_generate_xprv() {
+        let generated_xprv: GeneratedKey<_, miniscript::Segwitv0> =
+            bip32::ExtendedPrivKey::generate_with_entropy_default(TEST_ENTROPY).unwrap();
+
+        assert_eq!(generated_xprv.valid_networks, any_network());
+        assert_eq!(generated_xprv.to_string(), "xprv9s21ZrQH143K4Xr1cJyqTvuL2FWR8eicgY9boWqMBv8MDVUZ65AXHnzBrK1nyomu6wdcabRgmGTaAKawvhAno1V5FowGpTLVx3jxzE5uk3Q");
+    }
+
+    #[test]
+    fn test_keys_generate_wif() {
+        let generated_wif: GeneratedKey<_, miniscript::Segwitv0> =
+            bitcoin::PrivateKey::generate_with_entropy_default(TEST_ENTROPY).unwrap();
+
+        assert_eq!(generated_wif.valid_networks, any_network());
+        assert_eq!(
+            generated_wif.to_string(),
+            "L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch"
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/lib.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/lib.rs.html new file mode 100644 index 0000000000..41b65ad153 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/lib.rs.html @@ -0,0 +1,548 @@ +lib.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+// rustdoc will warn if there are missing docs
+#![warn(missing_docs)]
+// only enables the `doc_cfg` feature when
+// the `docsrs` configuration attribute is defined
+#![cfg_attr(docsrs, feature(doc_cfg))]
+// only enables the nightly `external_doc` feature when
+// `test-md-docs` is enabled
+#![cfg_attr(feature = "test-md-docs", feature(external_doc))]
+
+//! A modern, lightweight, descriptor-based wallet library written in Rust.
+//!
+//! # About
+//!
+//! The BDK library aims to be the core building block for Bitcoin wallets of any kind.
+//!
+//! * It uses [Miniscript](https://github.com/rust-bitcoin/rust-miniscript) to support descriptors with generalized conditions. This exact same library can be used to build
+//!   single-sig wallets, multisigs, timelocked contracts and more.
+//! * It supports multiple blockchain backends and databases, allowing developers to choose exactly what's right for their projects.
+//! * It is built to be cross-platform: the core logic works on desktop, mobile, and even WebAssembly.
+//! * It is very easy to extend: developers can implement customized logic for blockchain backends, databases, signers, coin selection, and more, without having to fork and modify this library.
+//!
+//! # A Tour of BDK
+//!
+//! BDK consists of a number of modules that provide a range of functionality
+//! essential for implementing descriptor based Bitcoin wallet applications in Rust. In this
+//! section, we will take a brief tour of BDK, summarizing the major APIs and
+//! their uses.
+//!
+//! The easiest way to get started is to add bdk to your dependencies with the default features.
+//! The default features include a simple key-value database ([`sled`](sled)) to cache
+//! blockchain data and an [electrum](https://docs.rs/electrum-client/) blockchain client to
+//! interact with the bitcoin P2P network.
+//!
+//! ```toml
+//! bdk = "0.2.0"
+//! ```
+//!
+//! ## Sync the balance of a descriptor
+//!
+//! ### Example
+//! ```ignore
+//! use bdk::Wallet;
+//! use bdk::database::MemoryDatabase;
+//! use bdk::blockchain::{noop_progress, ElectrumBlockchain};
+//!
+//! use bdk::electrum_client::Client;
+//!
+//! fn main() -> Result<(), bdk::Error> {
+//!     let client = Client::new("ssl://electrum.blockstream.info:60002")?;
+//!     let wallet = Wallet::new(
+//!         "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
+//!         Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
+//!         bitcoin::Network::Testnet,
+//!         MemoryDatabase::default(),
+//!         ElectrumBlockchain::from(client)
+//!     )?;
+//!
+//!     wallet.sync(noop_progress(), None)?;
+//!
+//!     println!("Descriptor balance: {} SAT", wallet.get_balance()?);
+//!
+//!     Ok(())
+//! }
+//! ```
+//!
+//! ## Generate a few addresses
+//!
+//! ### Example
+//! ```
+//! use bdk::{Wallet, OfflineWallet};
+//! use bdk::database::MemoryDatabase;
+//!
+//! fn main() -> Result<(), bdk::Error> {
+//!     let wallet: OfflineWallet<_> = Wallet::new_offline(
+//!         "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
+//!         Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
+//!         bitcoin::Network::Testnet,
+//!         MemoryDatabase::default(),
+//!     )?;
+//!
+//!     println!("Address #0: {}", wallet.get_new_address()?);
+//!     println!("Address #1: {}", wallet.get_new_address()?);
+//!     println!("Address #2: {}", wallet.get_new_address()?);
+//!
+//!     Ok(())
+//! }
+//! ```
+//!
+//! ## Create a transaction
+//!
+//! ### Example
+//! ```ignore
+//! use base64::decode;
+//! use bdk::{FeeRate, TxBuilder, Wallet};
+//! use bdk::database::MemoryDatabase;
+//! use bdk::blockchain::{noop_progress, ElectrumBlockchain};
+//!
+//! use bdk::electrum_client::Client;
+//!
+//! use bitcoin::consensus::serialize;
+//!
+//! fn main() -> Result<(), bdk::Error> {
+//!     let client = Client::new("ssl://electrum.blockstream.info:60002")?;
+//!     let wallet = Wallet::new(
+//!         "wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/0/*)",
+//!         Some("wpkh([c258d2e4/84h/1h/0h]tpubDDYkZojQFQjht8Tm4jsS3iuEmKjTiEGjG6KnuFNKKJb5A6ZUCUZKdvLdSDWofKi4ToRCwb9poe1XdqfUnP4jaJjCB2Zwv11ZLgSbnZSNecE/1/*)"),
+//!         bitcoin::Network::Testnet,
+//!         MemoryDatabase::default(),
+//!         ElectrumBlockchain::from(client)
+//!     )?;
+//!
+//!     wallet.sync(noop_progress(), None)?;
+//!
+//!     let send_to = wallet.get_new_address()?;
+//!     let (psbt, details) = wallet.create_tx(
+//!         TxBuilder::with_recipients(vec![(send_to.script_pubkey(), 50_000)])
+//!             .enable_rbf()
+//!             .do_not_spend_change()
+//!             .fee_rate(FeeRate::from_sat_per_vb(5.0))
+//!     )?;
+//!
+//!     println!("Transaction details: {:#?}", details);
+//!     println!("Unsigned PSBT: {}", base64::encode(&serialize(&psbt)));
+//!
+//!     Ok(())
+//! }
+//! ```
+//!
+//! ## Sign a transaction
+//!
+//! ### Example
+//! ```ignore
+//! use base64::decode;
+//! use bdk::{Wallet, OfflineWallet};
+//! use bdk::database::MemoryDatabase;
+//!
+//! use bitcoin::consensus::deserialize;
+//!
+//! fn main() -> Result<(), bdk::Error> {
+//!     let wallet: OfflineWallet<_> = Wallet::new_offline(
+//!         "wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/0/*)",
+//!         Some("wpkh([c258d2e4/84h/1h/0h]tprv8griRPhA7342zfRyB6CqeKF8CJDXYu5pgnj1cjL1u2ngKcJha5jjTRimG82ABzJQ4MQe71CV54xfn25BbhCNfEGGJZnxvCDQCd6JkbvxW6h/1/*)"),
+//!         bitcoin::Network::Testnet,
+//!         MemoryDatabase::default(),
+//!     )?;
+//!
+//!     let psbt = "...";
+//!     let psbt = deserialize(&base64::decode(psbt).unwrap())?;
+//!
+//!     let (signed_psbt, finalized) = wallet.sign(psbt, None)?;
+//!
+//!     Ok(())
+//! }
+//! ```
+//!
+//! # Feature flags
+//!
+//! BDK uses a set of [feature flags](https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section)
+//! to reduce the amount of compiled code by allowing projects to only enable the features they need.
+//! By default, BDK enables two internal features, `key-value-db` and `electrum`.
+//!
+//! If you are new to BDK we recommended that you use the default features which will enable
+//! basic descriptor wallet functionality. More advanced users can disable the `default` features
+//! (`--no-default-features`) and build the BDK library with only the features you need.
+
+//! Below is a list of the available feature flags and the additional functionality they provide.
+//!
+//! * `all-keys`: all features for working with bitcoin keys
+//! * `async-interface`: async functions in bdk traits
+//! * `cli-utils`: utilities for creating a command line interface wallet
+//! * `keys-bip39`: [BIP-39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki) mnemonic codes for generating deterministic keys
+//!
+//! ## Internal features
+//!
+//! These features do not expose any new API, but influence internal implementation aspects of
+//! BDK.
+//!
+//! * `compact_filters`: [`compact_filters`](crate::blockchain::compact_filters) client protocol for interacting with the bitcoin P2P network
+//! * `electrum`: [`electrum`](crate::blockchain::electrum) client protocol for interacting with electrum servers
+//! * `esplora`: [`esplora`](crate::blockchain::esplora) client protocol for interacting with blockstream [electrs](https://github.com/Blockstream/electrs) servers
+//! * `key-value-db`: key value [`database`](crate::database) based on [`sled`](crate::sled) for caching blockchain data
+
+pub extern crate bitcoin;
+extern crate log;
+pub extern crate miniscript;
+extern crate serde;
+#[macro_use]
+extern crate serde_json;
+
+#[cfg(feature = "keys-bip39")]
+extern crate bip39;
+
+#[cfg(any(target_arch = "wasm32", feature = "async-interface"))]
+#[macro_use]
+extern crate async_trait;
+#[macro_use]
+extern crate bdk_macros;
+
+#[cfg(feature = "compact_filters")]
+#[macro_use]
+extern crate lazy_static;
+
+#[cfg(feature = "electrum")]
+pub extern crate electrum_client;
+
+#[cfg(feature = "esplora")]
+pub extern crate reqwest;
+
+#[cfg(feature = "key-value-db")]
+pub extern crate sled;
+
+#[cfg(feature = "cli-utils")]
+pub mod cli;
+
+#[allow(unused_imports)]
+#[cfg(test)]
+#[macro_use]
+extern crate testutils;
+#[allow(unused_imports)]
+#[cfg(test)]
+#[macro_use]
+extern crate testutils_macros;
+#[allow(unused_imports)]
+#[cfg(test)]
+#[macro_use]
+extern crate serial_test;
+
+#[macro_use]
+pub(crate) mod error;
+pub mod blockchain;
+pub mod database;
+pub mod descriptor;
+#[cfg(feature = "test-md-docs")]
+mod doctest;
+pub mod keys;
+pub(crate) mod psbt;
+pub(crate) mod types;
+pub mod wallet;
+
+pub use descriptor::template;
+pub use descriptor::HDKeyPaths;
+pub use error::Error;
+pub use types::*;
+pub use wallet::address_validator;
+pub use wallet::signer;
+pub use wallet::tx_builder::TxBuilder;
+pub use wallet::{OfflineWallet, Wallet};
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/psbt/mod.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/psbt/mod.rs.html new file mode 100644 index 0000000000..27b1f86e57 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/psbt/mod.rs.html @@ -0,0 +1,110 @@ +mod.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+use bitcoin::util::psbt::PartiallySignedTransaction as PSBT;
+use bitcoin::TxOut;
+
+pub trait PSBTUtils {
+    fn get_utxo_for(&self, input_index: usize) -> Option<TxOut>;
+}
+
+impl PSBTUtils for PSBT {
+    fn get_utxo_for(&self, input_index: usize) -> Option<TxOut> {
+        let tx = &self.global.unsigned_tx;
+
+        if input_index >= tx.input.len() {
+            return None;
+        }
+
+        if let Some(input) = self.inputs.get(input_index) {
+            if let Some(wit_utxo) = &input.witness_utxo {
+                Some(wit_utxo.clone())
+            } else if let Some(in_tx) = &input.non_witness_utxo {
+                Some(in_tx.output[tx.input[input_index].previous_output.vout as usize].clone())
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/types.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/types.rs.html new file mode 100644 index 0000000000..4f731ccfd6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/types.rs.html @@ -0,0 +1,248 @@ +types.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+use std::convert::AsRef;
+
+use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut};
+use bitcoin::hash_types::Txid;
+
+use serde::{Deserialize, Serialize};
+
+/// Types of keychains
+#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum KeychainKind {
+    /// External
+    External = 0,
+    /// Internal, usually used for change outputs
+    Internal = 1,
+}
+
+impl KeychainKind {
+    /// Return [`KeychainKind`] as a byte
+    pub fn as_byte(&self) -> u8 {
+        match self {
+            KeychainKind::External => b'e',
+            KeychainKind::Internal => b'i',
+        }
+    }
+}
+
+impl AsRef<[u8]> for KeychainKind {
+    fn as_ref(&self) -> &[u8] {
+        match self {
+            KeychainKind::External => b"e",
+            KeychainKind::Internal => b"i",
+        }
+    }
+}
+
+/// Fee rate
+#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
+// Internally stored as satoshi/vbyte
+pub struct FeeRate(f32);
+
+impl FeeRate {
+    /// Create a new instance of [`FeeRate`] given a float fee rate in btc/kvbytes
+    pub fn from_btc_per_kvb(btc_per_kvb: f32) -> Self {
+        FeeRate(btc_per_kvb * 1e5)
+    }
+
+    /// Create a new instance of [`FeeRate`] given a float fee rate in satoshi/vbyte
+    pub fn from_sat_per_vb(sat_per_vb: f32) -> Self {
+        FeeRate(sat_per_vb)
+    }
+
+    /// Create a new [`FeeRate`] with the default min relay fee value
+    pub fn default_min_relay_fee() -> Self {
+        FeeRate(1.0)
+    }
+
+    /// Return the value as satoshi/vbyte
+    pub fn as_sat_vb(&self) -> f32 {
+        self.0
+    }
+}
+
+impl std::default::Default for FeeRate {
+    fn default() -> Self {
+        FeeRate::default_min_relay_fee()
+    }
+}
+
+/// A wallet unspent output
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
+pub struct UTXO {
+    /// Reference to a transaction output
+    pub outpoint: OutPoint,
+    /// Transaction output
+    pub txout: TxOut,
+    /// Type of keychain
+    pub keychain: KeychainKind,
+}
+
+/// A wallet transaction
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
+pub struct TransactionDetails {
+    /// Optional transaction
+    pub transaction: Option<Transaction>,
+    /// Transaction id
+    pub txid: Txid,
+    /// Timestamp
+    pub timestamp: u64,
+    /// Received value (sats)
+    pub received: u64,
+    /// Sent value (sats)
+    pub sent: u64,
+    /// Fee value (sats)
+    pub fees: u64,
+    /// Confirmed in block height, `None` means unconfirmed
+    pub height: Option<u32>,
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/address_validator.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/address_validator.rs.html new file mode 100644 index 0000000000..de52fb046b --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/address_validator.rs.html @@ -0,0 +1,340 @@ +address_validator.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Address validation callbacks
+//!
+//! The typical usage of those callbacks is for displaying the newly-generated address on a
+//! hardware wallet, so that the user can cross-check its correctness.
+//!
+//! More generally speaking though, these callbacks can also be used to "do something" every time
+//! an address is generated, without necessarily checking or validating it.
+//!
+//! An address validator can be attached to a [`Wallet`](super::Wallet) by using the
+//! [`Wallet::add_address_validator`](super::Wallet::add_address_validator) method, and
+//! whenever a new address is generated (either explicitly by the user with
+//! [`Wallet::get_new_address`](super::Wallet::get_new_address) or internally to create a change
+//! address) all the attached validators will be polled, in sequence. All of them must complete
+//! successfully to continue.
+//!
+//! ## Example
+//!
+//! ```
+//! # use std::sync::Arc;
+//! # use bitcoin::*;
+//! # use bdk::address_validator::*;
+//! # use bdk::database::*;
+//! # use bdk::*;
+//! struct PrintAddressAndContinue;
+//!
+//! impl AddressValidator for PrintAddressAndContinue {
+//!     fn validate(
+//!         &self,
+//!         keychain: KeychainKind,
+//!         hd_keypaths: &HDKeyPaths,
+//!         script: &Script
+//!     ) -> Result<(), AddressValidatorError> {
+//!         let address = Address::from_script(script, Network::Testnet)
+//!             .as_ref()
+//!             .map(Address::to_string)
+//!             .unwrap_or(script.to_string());
+//!         println!("New address of type {:?}: {}", keychain, address);
+//!         println!("HD keypaths: {:#?}", hd_keypaths);
+//!
+//!         Ok(())
+//!     }
+//! }
+//!
+//! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+//! let mut wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+//! wallet.add_address_validator(Arc::new(PrintAddressAndContinue));
+//!
+//! let address = wallet.get_new_address()?;
+//! println!("Address: {}", address);
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use std::fmt;
+
+use bitcoin::Script;
+
+use crate::descriptor::HDKeyPaths;
+use crate::types::KeychainKind;
+
+/// Errors that can be returned to fail the validation of an address
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum AddressValidatorError {
+    /// User rejected the address
+    UserRejected,
+    /// Network connection error
+    ConnectionError,
+    /// Network request timeout error
+    TimeoutError,
+    /// Invalid script
+    InvalidScript,
+    /// A custom error message
+    Message(String),
+}
+
+impl fmt::Display for AddressValidatorError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl std::error::Error for AddressValidatorError {}
+
+/// Trait to build address validators
+///
+/// All the address validators attached to a wallet with [`Wallet::add_address_validator`](super::Wallet::add_address_validator) will be polled
+/// every time an address (external or internal) is generated by the wallet. Errors returned in the
+/// validator will be propagated up to the original caller that triggered the address generation.
+///
+/// For a usage example see [this module](crate::address_validator)'s documentation.
+pub trait AddressValidator: Send + Sync {
+    /// Validate or inspect an address
+    fn validate(
+        &self,
+        keychain: KeychainKind,
+        hd_keypaths: &HDKeyPaths,
+        script: &Script,
+    ) -> Result<(), AddressValidatorError>;
+}
+
+#[cfg(test)]
+mod test {
+    use std::sync::Arc;
+
+    use super::*;
+    use crate::wallet::test::{get_funded_wallet, get_test_wpkh};
+    use crate::wallet::TxBuilder;
+
+    struct TestValidator;
+    impl AddressValidator for TestValidator {
+        fn validate(
+            &self,
+            _keychain: KeychainKind,
+            _hd_keypaths: &HDKeyPaths,
+            _script: &bitcoin::Script,
+        ) -> Result<(), AddressValidatorError> {
+            Err(AddressValidatorError::InvalidScript)
+        }
+    }
+
+    #[test]
+    #[should_panic(expected = "InvalidScript")]
+    fn test_address_validator_external() {
+        let (mut wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        wallet.add_address_validator(Arc::new(TestValidator));
+
+        wallet.get_new_address().unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "InvalidScript")]
+    fn test_address_validator_internal() {
+        let (mut wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        wallet.add_address_validator(Arc::new(TestValidator));
+
+        let addr = testutils!(@external descriptors, 10);
+        wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                25_000,
+            )]))
+            .unwrap();
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/coin_selection.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/coin_selection.rs.html new file mode 100644 index 0000000000..f52a1c8b9a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/coin_selection.rs.html @@ -0,0 +1,2000 @@ +coin_selection.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Coin selection
+//!
+//! This module provides the trait [`CoinSelectionAlgorithm`] that can be implemented to
+//! define custom coin selection algorithms.
+//!
+//! The coin selection algorithm is not globally part of a [`Wallet`](super::Wallet), instead it
+//! is selected whenever a [`Wallet::create_tx`](super::Wallet::create_tx) call is made, through
+//! the use of the [`TxBuilder`] structure, specifically with
+//! [`TxBuilder::coin_selection`](super::tx_builder::TxBuilder::coin_selection) method.
+//!
+//! The [`DefaultCoinSelectionAlgorithm`] selects the default coin selection algorithm that
+//! [`TxBuilder`] uses, if it's not explicitly overridden.
+//!
+//! [`TxBuilder`]: super::tx_builder::TxBuilder
+//!
+//! ## Example
+//!
+//! ```no_run
+//! # use std::str::FromStr;
+//! # use bitcoin::*;
+//! # use bdk::wallet::coin_selection::*;
+//! # use bdk::database::Database;
+//! # use bdk::*;
+//! # const TXIN_BASE_WEIGHT: usize = (32 + 4 + 4 + 1) * 4;
+//! #[derive(Debug)]
+//! struct AlwaysSpendEverything;
+//!
+//! impl<D: Database> CoinSelectionAlgorithm<D> for AlwaysSpendEverything {
+//!     fn coin_select(
+//!         &self,
+//!         database: &D,
+//!         required_utxos: Vec<(UTXO, usize)>,
+//!         optional_utxos: Vec<(UTXO, usize)>,
+//!         fee_rate: FeeRate,
+//!         amount_needed: u64,
+//!         fee_amount: f32,
+//!     ) -> Result<CoinSelectionResult, bdk::Error> {
+//!         let mut selected_amount = 0;
+//!         let mut additional_weight = 0;
+//!         let all_utxos_selected = required_utxos
+//!             .into_iter().chain(optional_utxos)
+//!             .scan((&mut selected_amount, &mut additional_weight), |(selected_amount, additional_weight), (utxo, weight)| {
+//!                 **selected_amount += utxo.txout.value;
+//!                 **additional_weight += TXIN_BASE_WEIGHT + weight;
+//!
+//!                 Some(utxo)
+//!             })
+//!             .collect::<Vec<_>>();
+//!         let additional_fees = additional_weight as f32 * fee_rate.as_sat_vb() / 4.0;
+//!
+//!         if (fee_amount + additional_fees).ceil() as u64 + amount_needed > selected_amount {
+//!             return Err(bdk::Error::InsufficientFunds);
+//!         }
+//!
+//!         Ok(CoinSelectionResult {
+//!             selected: all_utxos_selected,
+//!             selected_amount,
+//!             fee_amount: fee_amount + additional_fees,
+//!         })
+//!     }
+//! }
+//!
+//! # let wallet: OfflineWallet<_> = Wallet::new_offline("", None, Network::Testnet, bdk::database::MemoryDatabase::default())?;
+//! // create wallet, sync, ...
+//!
+//! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+//! let (psbt, details) = wallet.create_tx(
+//!     TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
+//!         .coin_selection(AlwaysSpendEverything),
+//! )?;
+//!
+//! // inspect, sign, broadcast, ...
+//!
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use crate::database::Database;
+use crate::error::Error;
+use crate::types::{FeeRate, UTXO};
+
+use rand::seq::SliceRandom;
+#[cfg(not(test))]
+use rand::thread_rng;
+#[cfg(test)]
+use rand::{rngs::StdRng, SeedableRng};
+
+/// Default coin selection algorithm used by [`TxBuilder`](super::tx_builder::TxBuilder) if not
+/// overridden
+#[cfg(not(test))]
+pub type DefaultCoinSelectionAlgorithm = BranchAndBoundCoinSelection;
+#[cfg(test)]
+pub type DefaultCoinSelectionAlgorithm = LargestFirstCoinSelection; // make the tests more predictable
+
+// Base weight of a Txin, not counting the weight needed for satisfying it.
+// prev_txid (32 bytes) + prev_vout (4 bytes) + sequence (4 bytes) + script_len (1 bytes)
+pub(crate) const TXIN_BASE_WEIGHT: usize = (32 + 4 + 4 + 1) * 4;
+
+/// Result of a successful coin selection
+#[derive(Debug)]
+pub struct CoinSelectionResult {
+    /// List of outputs selected for use as inputs
+    pub selected: Vec<UTXO>,
+    /// Sum of the selected inputs' value
+    pub selected_amount: u64,
+    /// Total fee amount in satoshi
+    pub fee_amount: f32,
+}
+
+/// Trait for generalized coin selection algorithms
+///
+/// This trait can be implemented to make the [`Wallet`](super::Wallet) use a customized coin
+/// selection algorithm when it creates transactions.
+///
+/// For an example see [this module](crate::wallet::coin_selection)'s documentation.
+pub trait CoinSelectionAlgorithm<D: Database>: std::fmt::Debug {
+    /// Perform the coin selection
+    ///
+    /// - `database`: a reference to the wallet's database that can be used to lookup additional
+    ///               details for a specific UTXO
+    /// - `required_utxos`: the utxos that must be spent regardless of `amount_needed` with their
+    ///                     weight cost
+    /// - `optional_utxos`: the remaining available utxos to satisfy `amount_needed` with their
+    ///                     weight cost
+    /// - `fee_rate`: fee rate to use
+    /// - `amount_needed`: the amount in satoshi to select
+    /// - `fee_amount`: the amount of fees in satoshi already accumulated from adding outputs and
+    ///                 the transaction's header
+    fn coin_select(
+        &self,
+        database: &D,
+        required_utxos: Vec<(UTXO, usize)>,
+        optional_utxos: Vec<(UTXO, usize)>,
+        fee_rate: FeeRate,
+        amount_needed: u64,
+        fee_amount: f32,
+    ) -> Result<CoinSelectionResult, Error>;
+}
+
+/// Simple and dumb coin selection
+///
+/// This coin selection algorithm sorts the available UTXOs by value and then picks them starting
+/// from the largest ones until the required amount is reached.
+#[derive(Debug, Default)]
+pub struct LargestFirstCoinSelection;
+
+impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection {
+    fn coin_select(
+        &self,
+        _database: &D,
+        required_utxos: Vec<(UTXO, usize)>,
+        mut optional_utxos: Vec<(UTXO, usize)>,
+        fee_rate: FeeRate,
+        amount_needed: u64,
+        mut fee_amount: f32,
+    ) -> Result<CoinSelectionResult, Error> {
+        let calc_fee_bytes = |wu| (wu as f32) * fee_rate.as_sat_vb() / 4.0;
+
+        log::debug!(
+            "amount_needed = `{}`, fee_amount = `{}`, fee_rate = `{:?}`",
+            amount_needed,
+            fee_amount,
+            fee_rate
+        );
+
+        // We put the "required UTXOs" first and make sure the optional UTXOs are sorted,
+        // initially smallest to largest, before being reversed with `.rev()`.
+        let utxos = {
+            optional_utxos.sort_unstable_by_key(|(utxo, _)| utxo.txout.value);
+            required_utxos
+                .into_iter()
+                .map(|utxo| (true, utxo))
+                .chain(optional_utxos.into_iter().rev().map(|utxo| (false, utxo)))
+        };
+
+        // Keep including inputs until we've got enough.
+        // Store the total input value in selected_amount and the total fee being paid in fee_amount
+        let mut selected_amount = 0;
+        let selected = utxos
+            .scan(
+                (&mut selected_amount, &mut fee_amount),
+                |(selected_amount, fee_amount), (must_use, (utxo, weight))| {
+                    if must_use || **selected_amount < amount_needed + (fee_amount.ceil() as u64) {
+                        **fee_amount += calc_fee_bytes(TXIN_BASE_WEIGHT + weight);
+                        **selected_amount += utxo.txout.value;
+
+                        log::debug!(
+                            "Selected {}, updated fee_amount = `{}`",
+                            utxo.outpoint,
+                            fee_amount
+                        );
+
+                        Some(utxo)
+                    } else {
+                        None
+                    }
+                },
+            )
+            .collect::<Vec<_>>();
+
+        if selected_amount < amount_needed + (fee_amount.ceil() as u64) {
+            return Err(Error::InsufficientFunds);
+        }
+
+        Ok(CoinSelectionResult {
+            selected,
+            fee_amount,
+            selected_amount,
+        })
+    }
+}
+
+#[derive(Debug, Clone)]
+// Adds fee information to an UTXO.
+struct OutputGroup {
+    utxo: UTXO,
+    // weight needed to satisfy the UTXO, as described in `Descriptor::max_satisfaction_weight`
+    satisfaction_weight: usize,
+    // Amount of fees for spending a certain utxo, calculated using a certain FeeRate
+    fee: f32,
+    // The effective value of the UTXO, i.e., the utxo value minus the fee for spending it
+    effective_value: i64,
+}
+
+impl OutputGroup {
+    fn new(utxo: UTXO, satisfaction_weight: usize, fee_rate: FeeRate) -> Self {
+        let fee = (TXIN_BASE_WEIGHT + satisfaction_weight) as f32 / 4.0 * fee_rate.as_sat_vb();
+        let effective_value = utxo.txout.value as i64 - fee.ceil() as i64;
+        OutputGroup {
+            utxo,
+            satisfaction_weight,
+            effective_value,
+            fee,
+        }
+    }
+}
+
+/// Branch and bound coin selection
+///
+/// Code adapted from Bitcoin Core's implementation and from Mark Erhardt Master's Thesis: <http://murch.one/wp-content/uploads/2016/11/erhardt2016coinselection.pdf>
+#[derive(Debug)]
+pub struct BranchAndBoundCoinSelection {
+    size_of_change: u64,
+}
+
+impl Default for BranchAndBoundCoinSelection {
+    fn default() -> Self {
+        Self {
+            // P2WPKH cost of change -> value (8 bytes) + script len (1 bytes) + script (22 bytes)
+            size_of_change: 8 + 1 + 22,
+        }
+    }
+}
+
+impl BranchAndBoundCoinSelection {
+    /// Create new instance with target size for change output
+    pub fn new(size_of_change: u64) -> Self {
+        Self { size_of_change }
+    }
+}
+
+const BNB_TOTAL_TRIES: usize = 100_000;
+
+impl<D: Database> CoinSelectionAlgorithm<D> for BranchAndBoundCoinSelection {
+    fn coin_select(
+        &self,
+        _database: &D,
+        required_utxos: Vec<(UTXO, usize)>,
+        optional_utxos: Vec<(UTXO, usize)>,
+        fee_rate: FeeRate,
+        amount_needed: u64,
+        fee_amount: f32,
+    ) -> Result<CoinSelectionResult, Error> {
+        // Mapping every (UTXO, usize) to an output group
+        let required_utxos: Vec<OutputGroup> = required_utxos
+            .into_iter()
+            .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+            .collect();
+
+        // Mapping every (UTXO, usize) to an output group.
+        // Filtering UTXOs with an effective_value < 0, as the fee paid for
+        // adding them is more than their value
+        let optional_utxos: Vec<OutputGroup> = optional_utxos
+            .into_iter()
+            .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+            .filter(|u| u.effective_value > 0)
+            .collect();
+
+        let curr_value = required_utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value as u64);
+
+        let curr_available_value = optional_utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value as u64);
+
+        let actual_target = fee_amount.ceil() as u64 + amount_needed;
+        let cost_of_change = self.size_of_change as f32 * fee_rate.as_sat_vb();
+
+        if curr_available_value + curr_value < actual_target {
+            return Err(Error::InsufficientFunds);
+        }
+
+        Ok(self
+            .bnb(
+                required_utxos.clone(),
+                optional_utxos.clone(),
+                curr_value,
+                curr_available_value,
+                actual_target,
+                fee_amount,
+                cost_of_change,
+            )
+            .unwrap_or_else(|_| {
+                self.single_random_draw(
+                    required_utxos,
+                    optional_utxos,
+                    curr_value,
+                    actual_target,
+                    fee_amount,
+                )
+            }))
+    }
+}
+
+impl BranchAndBoundCoinSelection {
+    // TODO: make this more Rust-onic :)
+    // (And perhpaps refactor with less arguments?)
+    #[allow(clippy::too_many_arguments)]
+    fn bnb(
+        &self,
+        required_utxos: Vec<OutputGroup>,
+        mut optional_utxos: Vec<OutputGroup>,
+        mut curr_value: u64,
+        mut curr_available_value: u64,
+        actual_target: u64,
+        fee_amount: f32,
+        cost_of_change: f32,
+    ) -> Result<CoinSelectionResult, Error> {
+        // current_selection[i] will contain true if we are using optional_utxos[i],
+        // false otherwise. Note that current_selection.len() could be less than
+        // optional_utxos.len(), it just means that we still haven't decided if we should keep
+        // certain optional_utxos or not.
+        let mut current_selection: Vec<bool> = Vec::with_capacity(optional_utxos.len());
+
+        // Sort the utxo_pool
+        optional_utxos.sort_unstable_by_key(|a| a.effective_value);
+        optional_utxos.reverse();
+
+        // Contains the best selection we found
+        let mut best_selection = Vec::new();
+        let mut best_selection_value = None;
+
+        // Depth First search loop for choosing the UTXOs
+        for _ in 0..BNB_TOTAL_TRIES {
+            // Conditions for starting a backtrack
+            let mut backtrack = false;
+            // Cannot possibly reach target with the amount remaining in the curr_available_value,
+            // or the selected value is out of range.
+            // Go back and try other branch
+            if curr_value + curr_available_value < actual_target
+                || curr_value > actual_target + cost_of_change as u64
+            {
+                backtrack = true;
+            } else if curr_value >= actual_target {
+                // Selected value is within range, there's no point in going forward. Start
+                // backtracking
+                backtrack = true;
+
+                // If we found a solution better than the previous one, or if there wasn't previous
+                // solution, update the best solution
+                if best_selection_value.is_none() || curr_value < best_selection_value.unwrap() {
+                    best_selection = current_selection.clone();
+                    best_selection_value = Some(curr_value);
+                }
+
+                // If we found a perfect match, break here
+                if curr_value == actual_target {
+                    break;
+                }
+            }
+
+            // Backtracking, moving backwards
+            if backtrack {
+                // Walk backwards to find the last included UTXO that still needs to have its omission branch traversed.
+                while let Some(false) = current_selection.last() {
+                    current_selection.pop();
+                    curr_available_value +=
+                        optional_utxos[current_selection.len()].effective_value as u64;
+                }
+
+                if current_selection.last_mut().is_none() {
+                    // We have walked back to the first utxo and no branch is untraversed. All solutions searched
+                    // If best selection is empty, then there's no exact match
+                    if best_selection.is_empty() {
+                        return Err(Error::BnBNoExactMatch);
+                    }
+                    break;
+                }
+
+                if let Some(c) = current_selection.last_mut() {
+                    // Output was included on previous iterations, try excluding now.
+                    *c = false;
+                }
+
+                let utxo = &optional_utxos[current_selection.len() - 1];
+                curr_value -= utxo.effective_value as u64;
+            } else {
+                // Moving forwards, continuing down this branch
+                let utxo = &optional_utxos[current_selection.len()];
+
+                // Remove this utxo from the curr_available_value utxo amount
+                curr_available_value -= utxo.effective_value as u64;
+
+                // Inclusion branch first (Largest First Exploration)
+                current_selection.push(true);
+                curr_value += utxo.effective_value as u64;
+            }
+        }
+
+        // Check for solution
+        if best_selection.is_empty() {
+            return Err(Error::BnBTotalTriesExceeded);
+        }
+
+        // Set output set
+        let selected_utxos = optional_utxos
+            .into_iter()
+            .zip(best_selection)
+            .filter_map(|(optional, is_in_best)| if is_in_best { Some(optional) } else { None })
+            .collect();
+
+        Ok(BranchAndBoundCoinSelection::calculate_cs_result(
+            selected_utxos,
+            required_utxos,
+            fee_amount,
+        ))
+    }
+
+    fn single_random_draw(
+        &self,
+        required_utxos: Vec<OutputGroup>,
+        mut optional_utxos: Vec<OutputGroup>,
+        curr_value: u64,
+        actual_target: u64,
+        fee_amount: f32,
+    ) -> CoinSelectionResult {
+        #[cfg(not(test))]
+        optional_utxos.shuffle(&mut thread_rng());
+        #[cfg(test)]
+        {
+            let seed = [0; 32];
+            let mut rng: StdRng = SeedableRng::from_seed(seed);
+            optional_utxos.shuffle(&mut rng);
+        }
+
+        let selected_utxos = optional_utxos
+            .into_iter()
+            .scan(curr_value, |curr_value, utxo| {
+                if *curr_value >= actual_target {
+                    None
+                } else {
+                    *curr_value += utxo.effective_value as u64;
+                    Some(utxo)
+                }
+            })
+            .collect::<Vec<_>>();
+
+        BranchAndBoundCoinSelection::calculate_cs_result(selected_utxos, required_utxos, fee_amount)
+    }
+
+    fn calculate_cs_result(
+        mut selected_utxos: Vec<OutputGroup>,
+        mut required_utxos: Vec<OutputGroup>,
+        mut fee_amount: f32,
+    ) -> CoinSelectionResult {
+        selected_utxos.append(&mut required_utxos);
+        fee_amount += selected_utxos.iter().map(|u| u.fee).sum::<f32>();
+        let selected = selected_utxos
+            .into_iter()
+            .map(|u| u.utxo)
+            .collect::<Vec<_>>();
+        let selected_amount = selected.iter().map(|u| u.txout.value).sum();
+
+        CoinSelectionResult {
+            selected,
+            fee_amount,
+            selected_amount,
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::str::FromStr;
+
+    use bitcoin::{OutPoint, Script, TxOut};
+
+    use super::*;
+    use crate::database::MemoryDatabase;
+    use crate::types::*;
+
+    use rand::rngs::StdRng;
+    use rand::seq::SliceRandom;
+    use rand::{Rng, SeedableRng};
+
+    const P2WPKH_WITNESS_SIZE: usize = 73 + 33 + 2;
+
+    fn get_test_utxos() -> Vec<(UTXO, usize)> {
+        vec![
+            (
+                UTXO {
+                    outpoint: OutPoint::from_str(
+                        "ebd9813ecebc57ff8f30797de7c205e3c7498ca950ea4341ee51a685ff2fa30a:0",
+                    )
+                    .unwrap(),
+                    txout: TxOut {
+                        value: 100_000,
+                        script_pubkey: Script::new(),
+                    },
+                    keychain: KeychainKind::External,
+                },
+                P2WPKH_WITNESS_SIZE,
+            ),
+            (
+                UTXO {
+                    outpoint: OutPoint::from_str(
+                        "65d92ddff6b6dc72c89624a6491997714b90f6004f928d875bc0fd53f264fa85:0",
+                    )
+                    .unwrap(),
+                    txout: TxOut {
+                        value: 200_000,
+                        script_pubkey: Script::new(),
+                    },
+                    keychain: KeychainKind::Internal,
+                },
+                P2WPKH_WITNESS_SIZE,
+            ),
+        ]
+    }
+
+    fn generate_random_utxos(rng: &mut StdRng, utxos_number: usize) -> Vec<(UTXO, usize)> {
+        let mut res = Vec::new();
+        for _ in 0..utxos_number {
+            res.push((
+                UTXO {
+                    outpoint: OutPoint::from_str(
+                        "ebd9813ecebc57ff8f30797de7c205e3c7498ca950ea4341ee51a685ff2fa30a:0",
+                    )
+                    .unwrap(),
+                    txout: TxOut {
+                        value: rng.gen_range(0, 200000000),
+                        script_pubkey: Script::new(),
+                    },
+                    keychain: KeychainKind::External,
+                },
+                P2WPKH_WITNESS_SIZE,
+            ));
+        }
+        res
+    }
+
+    fn generate_same_value_utxos(utxos_value: u64, utxos_number: usize) -> Vec<(UTXO, usize)> {
+        let utxo = (
+            UTXO {
+                outpoint: OutPoint::from_str(
+                    "ebd9813ecebc57ff8f30797de7c205e3c7498ca950ea4341ee51a685ff2fa30a:0",
+                )
+                .unwrap(),
+                txout: TxOut {
+                    value: utxos_value,
+                    script_pubkey: Script::new(),
+                },
+                keychain: KeychainKind::External,
+            },
+            P2WPKH_WITNESS_SIZE,
+        );
+        vec![utxo; utxos_number]
+    }
+
+    fn sum_random_utxos(mut rng: &mut StdRng, utxos: &mut Vec<(UTXO, usize)>) -> u64 {
+        let utxos_picked_len = rng.gen_range(2, utxos.len() / 2);
+        utxos.shuffle(&mut rng);
+        utxos[..utxos_picked_len]
+            .iter()
+            .fold(0, |acc, x| acc + x.0.txout.value)
+    }
+
+    #[test]
+    fn test_largest_first_coin_selection_success() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        let result = LargestFirstCoinSelection::default()
+            .coin_select(
+                &database,
+                utxos,
+                vec![],
+                FeeRate::from_sat_per_vb(1.0),
+                250_000,
+                50.0,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 2);
+        assert_eq!(result.selected_amount, 300_000);
+        assert_eq!(result.fee_amount, 186.0);
+    }
+
+    #[test]
+    fn test_largest_first_coin_selection_use_all() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        let result = LargestFirstCoinSelection::default()
+            .coin_select(
+                &database,
+                utxos,
+                vec![],
+                FeeRate::from_sat_per_vb(1.0),
+                20_000,
+                50.0,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 2);
+        assert_eq!(result.selected_amount, 300_000);
+        assert_eq!(result.fee_amount, 186.0);
+    }
+
+    #[test]
+    fn test_largest_first_coin_selection_use_only_necessary() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        let result = LargestFirstCoinSelection::default()
+            .coin_select(
+                &database,
+                vec![],
+                utxos,
+                FeeRate::from_sat_per_vb(1.0),
+                20_000,
+                50.0,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 1);
+        assert_eq!(result.selected_amount, 200_000);
+        assert_eq!(result.fee_amount, 118.0);
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_largest_first_coin_selection_insufficient_funds() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        LargestFirstCoinSelection::default()
+            .coin_select(
+                &database,
+                vec![],
+                utxos,
+                FeeRate::from_sat_per_vb(1.0),
+                500_000,
+                50.0,
+            )
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_largest_first_coin_selection_insufficient_funds_high_fees() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        LargestFirstCoinSelection::default()
+            .coin_select(
+                &database,
+                vec![],
+                utxos,
+                FeeRate::from_sat_per_vb(1000.0),
+                250_000,
+                50.0,
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_bnb_coin_selection_success() {
+        // In this case bnb won't find a suitable match and single random draw will
+        // select three outputs
+        let utxos = generate_same_value_utxos(100_000, 20);
+
+        let database = MemoryDatabase::default();
+
+        let result = BranchAndBoundCoinSelection::default()
+            .coin_select(
+                &database,
+                vec![],
+                utxos,
+                FeeRate::from_sat_per_vb(1.0),
+                250_000,
+                50.0,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 3);
+        assert_eq!(result.selected_amount, 300_000);
+        assert_eq!(result.fee_amount, 254.0);
+    }
+
+    #[test]
+    fn test_bnb_coin_selection_required_are_enough() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        let result = BranchAndBoundCoinSelection::default()
+            .coin_select(
+                &database,
+                utxos.clone(),
+                utxos,
+                FeeRate::from_sat_per_vb(1.0),
+                20_000,
+                50.0,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 2);
+        assert_eq!(result.selected_amount, 300_000);
+        assert_eq!(result.fee_amount, 186.0);
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_bnb_coin_selection_insufficient_funds() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        BranchAndBoundCoinSelection::default()
+            .coin_select(
+                &database,
+                vec![],
+                utxos,
+                FeeRate::from_sat_per_vb(1.0),
+                500_000,
+                50.0,
+            )
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_bnb_coin_selection_insufficient_funds_high_fees() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        BranchAndBoundCoinSelection::default()
+            .coin_select(
+                &database,
+                vec![],
+                utxos,
+                FeeRate::from_sat_per_vb(1000.0),
+                250_000,
+                50.0,
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_bnb_coin_selection_check_fee_rate() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        let result = BranchAndBoundCoinSelection::new(0)
+            .coin_select(
+                &database,
+                vec![],
+                utxos.clone(),
+                FeeRate::from_sat_per_vb(1.0),
+                99932, // first utxo's effective value
+                0.0,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 1);
+        assert_eq!(result.selected_amount, 100_000);
+        let input_size = (TXIN_BASE_WEIGHT as f32) / 4.0 + P2WPKH_WITNESS_SIZE as f32 / 4.0;
+        let epsilon = 0.5;
+        assert!((1.0 - (result.fee_amount / input_size)).abs() < epsilon);
+    }
+
+    #[test]
+    fn test_bnb_coin_selection_exact_match() {
+        let seed = [0; 32];
+        let mut rng: StdRng = SeedableRng::from_seed(seed);
+        let database = MemoryDatabase::default();
+
+        for _i in 0..200 {
+            let mut optional_utxos = generate_random_utxos(&mut rng, 16);
+            let target_amount = sum_random_utxos(&mut rng, &mut optional_utxos);
+            let result = BranchAndBoundCoinSelection::new(0)
+                .coin_select(
+                    &database,
+                    vec![],
+                    optional_utxos,
+                    FeeRate::from_sat_per_vb(0.0),
+                    target_amount,
+                    0.0,
+                )
+                .unwrap();
+            assert_eq!(result.selected_amount, target_amount);
+        }
+    }
+
+    #[test]
+    #[should_panic(expected = "BnBNoExactMatch")]
+    fn test_bnb_function_no_exact_match() {
+        let fee_rate = FeeRate::from_sat_per_vb(10.0);
+        let utxos: Vec<OutputGroup> = get_test_utxos()
+            .into_iter()
+            .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+            .collect();
+
+        let curr_available_value = utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value as u64);
+
+        let size_of_change = 31;
+        let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
+        BranchAndBoundCoinSelection::new(size_of_change)
+            .bnb(
+                vec![],
+                utxos,
+                0,
+                curr_available_value,
+                20_000,
+                50.0,
+                cost_of_change,
+            )
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "BnBTotalTriesExceeded")]
+    fn test_bnb_function_tries_exceeded() {
+        let fee_rate = FeeRate::from_sat_per_vb(10.0);
+        let utxos: Vec<OutputGroup> = generate_same_value_utxos(100_000, 100_000)
+            .into_iter()
+            .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+            .collect();
+
+        let curr_available_value = utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value as u64);
+
+        let size_of_change = 31;
+        let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
+
+        BranchAndBoundCoinSelection::new(size_of_change)
+            .bnb(
+                vec![],
+                utxos,
+                0,
+                curr_available_value,
+                20_000,
+                50.0,
+                cost_of_change,
+            )
+            .unwrap();
+    }
+
+    // The match won't be exact but still in the range
+    #[test]
+    fn test_bnb_function_almost_exact_match_with_fees() {
+        let fee_rate = FeeRate::from_sat_per_vb(1.0);
+        let size_of_change = 31;
+        let cost_of_change = size_of_change as f32 * fee_rate.as_sat_vb();
+        let fee_amount = 50.0;
+
+        let utxos: Vec<_> = generate_same_value_utxos(50_000, 10)
+            .into_iter()
+            .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+            .collect();
+
+        let curr_value = 0;
+
+        let curr_available_value = utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value as u64);
+
+        // 2*(value of 1 utxo)  - 2*(1 utxo fees with 1.0sat/vbyte fee rate) -
+        // cost_of_change + 5.
+        let target_amount = 2 * 50_000 - 2 * 67 - cost_of_change.ceil() as u64 + 5;
+
+        let result = BranchAndBoundCoinSelection::new(size_of_change)
+            .bnb(
+                vec![],
+                utxos,
+                curr_value,
+                curr_available_value,
+                target_amount,
+                fee_amount,
+                cost_of_change,
+            )
+            .unwrap();
+        assert_eq!(result.fee_amount, 186.0);
+        assert_eq!(result.selected_amount, 100_000);
+    }
+
+    // TODO: bnb() function should be optimized, and this test should be done with more utxos
+    #[test]
+    fn test_bnb_function_exact_match_more_utxos() {
+        let seed = [0; 32];
+        let mut rng: StdRng = SeedableRng::from_seed(seed);
+        let fee_rate = FeeRate::from_sat_per_vb(0.0);
+
+        for _ in 0..200 {
+            let optional_utxos: Vec<_> = generate_random_utxos(&mut rng, 40)
+                .into_iter()
+                .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+                .collect();
+
+            let curr_value = 0;
+
+            let curr_available_value = optional_utxos
+                .iter()
+                .fold(0, |acc, x| acc + x.effective_value as u64);
+
+            let target_amount = optional_utxos[3].effective_value as u64
+                + optional_utxos[23].effective_value as u64;
+
+            let result = BranchAndBoundCoinSelection::new(0)
+                .bnb(
+                    vec![],
+                    optional_utxos,
+                    curr_value,
+                    curr_available_value,
+                    target_amount,
+                    0.0,
+                    0.0,
+                )
+                .unwrap();
+            assert_eq!(result.selected_amount, target_amount);
+        }
+    }
+
+    #[test]
+    fn test_single_random_draw_function_success() {
+        let seed = [0; 32];
+        let mut rng: StdRng = SeedableRng::from_seed(seed);
+        let mut utxos = generate_random_utxos(&mut rng, 300);
+        let target_amount = sum_random_utxos(&mut rng, &mut utxos);
+
+        let fee_rate = FeeRate::from_sat_per_vb(1.0);
+        let utxos: Vec<OutputGroup> = utxos
+            .into_iter()
+            .map(|u| OutputGroup::new(u.0, u.1, fee_rate))
+            .collect();
+
+        let result = BranchAndBoundCoinSelection::default().single_random_draw(
+            vec![],
+            utxos,
+            0,
+            target_amount,
+            50.0,
+        );
+
+        assert!(result.selected_amount > target_amount);
+        assert_eq!(
+            result.fee_amount,
+            50.0 + result.selected.len() as f32 * 68.0
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/export.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/export.rs.html new file mode 100644 index 0000000000..1f0ffc2e91 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/export.rs.html @@ -0,0 +1,692 @@ +export.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Wallet export
+//!
+//! This modules implements the wallet export format used by [FullyNoded](https://github.com/Fonta1n3/FullyNoded/blob/10b7808c8b929b171cca537fb50522d015168ac9/Docs/Wallets/Wallet-Export-Spec.md).
+//!
+//! ## Examples
+//!
+//! ### Import from JSON
+//!
+//! ```
+//! # use std::str::FromStr;
+//! # use bitcoin::*;
+//! # use bdk::database::*;
+//! # use bdk::wallet::export::*;
+//! # use bdk::*;
+//! let import = r#"{
+//!     "descriptor": "wpkh([c258d2e4\/84h\/1h\/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe\/0\/*)",
+//!     "blockheight":1782088,
+//!     "label":"testnet"
+//! }"#;
+//!
+//! let import = WalletExport::from_str(import)?;
+//! let wallet: OfflineWallet<_> = Wallet::new_offline(
+//!     &import.descriptor(),
+//!     import.change_descriptor().as_ref(),
+//!     Network::Testnet,
+//!     MemoryDatabase::default(),
+//! )?;
+//! # Ok::<_, bdk::Error>(())
+//! ```
+//!
+//! ### Export a `Wallet`
+//! ```
+//! # use bitcoin::*;
+//! # use bdk::database::*;
+//! # use bdk::wallet::export::*;
+//! # use bdk::*;
+//! let wallet: OfflineWallet<_> = Wallet::new_offline(
+//!     "wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/0/*)",
+//!     Some("wpkh([c258d2e4/84h/1h/0h]tpubDD3ynpHgJQW8VvWRzQ5WFDCrs4jqVFGHB3vLC3r49XHJSqP8bHKdK4AriuUKLccK68zfzowx7YhmDN8SiSkgCDENUFx9qVw65YyqM78vyVe/1/*)"),
+//!     Network::Testnet,
+//!     MemoryDatabase::default()
+//! )?;
+//! let export = WalletExport::export_wallet(&wallet, "exported wallet", true)
+//!     .map_err(ToString::to_string)
+//!     .map_err(bdk::Error::Generic)?;
+//!
+//! println!("Exported: {}", export.to_string());
+//! # Ok::<_, bdk::Error>(())
+//! ```
+
+use std::str::FromStr;
+
+use serde::{Deserialize, Serialize};
+
+use miniscript::{Descriptor, DescriptorPublicKey, ScriptContext, Terminal};
+
+use crate::blockchain::BlockchainMarker;
+use crate::database::BatchDatabase;
+use crate::wallet::Wallet;
+
+/// Structure that contains the export of a wallet
+///
+/// For a usage example see [this module](crate::wallet::export)'s documentation.
+#[derive(Debug, Serialize, Deserialize)]
+pub struct WalletExport {
+    descriptor: String,
+    /// Earliest block to rescan when looking for the wallet's transactions
+    pub blockheight: u32,
+    /// Arbitrary label for the wallet
+    pub label: String,
+}
+
+impl ToString for WalletExport {
+    fn to_string(&self) -> String {
+        serde_json::to_string(self).unwrap()
+    }
+}
+
+impl FromStr for WalletExport {
+    type Err = serde_json::Error;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        serde_json::from_str(s)
+    }
+}
+
+impl WalletExport {
+    /// Export a wallet
+    ///
+    /// This function returns an error if it determines that the `wallet`'s descriptor(s) are not
+    /// supported by Bitcoin Core or don't follow the standard derivation paths defined by BIP44
+    /// and others.
+    ///
+    /// If `include_blockheight` is `true`, this function will look into the `wallet`'s database
+    /// for the oldest transaction it knows and use that as the earliest block to rescan.
+    ///
+    /// If the database is empty or `include_blockheight` is false, the `blockheight` field
+    /// returned will be `0`.
+    pub fn export_wallet<B: BlockchainMarker, D: BatchDatabase>(
+        wallet: &Wallet<B, D>,
+        label: &str,
+        include_blockheight: bool,
+    ) -> Result<Self, &'static str> {
+        let descriptor = wallet
+            .descriptor
+            .to_string_with_secret(&wallet.signers.as_key_map(wallet.secp_ctx()));
+        Self::is_compatible_with_core(&descriptor)?;
+
+        let blockheight = match wallet.database.borrow().iter_txs(false) {
+            _ if !include_blockheight => 0,
+            Err(_) => 0,
+            Ok(txs) => {
+                let mut heights = txs
+                    .into_iter()
+                    .map(|tx| tx.height.unwrap_or(0))
+                    .collect::<Vec<_>>();
+                heights.sort_unstable();
+
+                *heights.last().unwrap_or(&0)
+            }
+        };
+
+        let export = WalletExport {
+            descriptor,
+            label: label.into(),
+            blockheight,
+        };
+
+        let desc_to_string = |d: &Descriptor<DescriptorPublicKey>| {
+            d.to_string_with_secret(&wallet.change_signers.as_key_map(wallet.secp_ctx()))
+        };
+        if export.change_descriptor() != wallet.change_descriptor.as_ref().map(desc_to_string) {
+            return Err("Incompatible change descriptor");
+        }
+
+        Ok(export)
+    }
+
+    fn is_compatible_with_core(descriptor: &str) -> Result<(), &'static str> {
+        fn check_ms<Ctx: ScriptContext>(
+            terminal: Terminal<String, Ctx>,
+        ) -> Result<(), &'static str> {
+            if let Terminal::Multi(_, _) = terminal {
+                Ok(())
+            } else {
+                Err("The descriptor contains operators not supported by Bitcoin Core")
+            }
+        }
+
+        match Descriptor::<String>::from_str(descriptor).map_err(|_| "Invalid descriptor")? {
+            Descriptor::Pk(_)
+            | Descriptor::Pkh(_)
+            | Descriptor::Wpkh(_)
+            | Descriptor::ShWpkh(_) => Ok(()),
+            Descriptor::Sh(ms) => check_ms(ms.node),
+            Descriptor::Wsh(ms) | Descriptor::ShWsh(ms) => check_ms(ms.node),
+            _ => Err("The descriptor is not compatible with Bitcoin Core"),
+        }
+    }
+
+    /// Return the external descriptor
+    pub fn descriptor(&self) -> String {
+        self.descriptor.clone()
+    }
+
+    /// Return the internal descriptor, if present
+    pub fn change_descriptor(&self) -> Option<String> {
+        let replaced = self.descriptor.replace("/0/*", "/1/*");
+
+        if replaced != self.descriptor {
+            Some(replaced)
+        } else {
+            None
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::str::FromStr;
+
+    use bitcoin::{Network, Txid};
+
+    use super::*;
+    use crate::database::{memory::MemoryDatabase, BatchOperations};
+    use crate::types::TransactionDetails;
+    use crate::wallet::{OfflineWallet, Wallet};
+
+    fn get_test_db() -> MemoryDatabase {
+        let mut db = MemoryDatabase::new();
+        db.set_tx(&TransactionDetails {
+            transaction: None,
+            txid: Txid::from_str(
+                "4ddff1fa33af17f377f62b72357b43107c19110a8009b36fb832af505efed98a",
+            )
+            .unwrap(),
+            timestamp: 12345678,
+            received: 100_000,
+            sent: 0,
+            fees: 500,
+            height: Some(5000),
+        })
+        .unwrap();
+
+        db
+    }
+
+    #[test]
+    fn test_export_bip44() {
+        let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
+        let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";
+
+        let wallet: OfflineWallet<_> = Wallet::new_offline(
+            descriptor,
+            Some(change_descriptor),
+            Network::Bitcoin,
+            get_test_db(),
+        )
+        .unwrap();
+        let export = WalletExport::export_wallet(&wallet, "Test Label", true).unwrap();
+
+        assert_eq!(export.descriptor(), descriptor);
+        assert_eq!(export.change_descriptor(), Some(change_descriptor.into()));
+        assert_eq!(export.blockheight, 5000);
+        assert_eq!(export.label, "Test Label");
+    }
+
+    #[test]
+    #[should_panic(expected = "Incompatible change descriptor")]
+    fn test_export_no_change() {
+        // This wallet explicitly doesn't have a change descriptor. It should be impossible to
+        // export, because exporting this kind of external descriptor normally implies the
+        // existence of an internal descriptor
+
+        let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
+
+        let wallet: OfflineWallet<_> =
+            Wallet::new_offline(descriptor, None, Network::Bitcoin, get_test_db()).unwrap();
+        WalletExport::export_wallet(&wallet, "Test Label", true).unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "Incompatible change descriptor")]
+    fn test_export_incompatible_change() {
+        // This wallet has a change descriptor, but the derivation path is not in the "standard"
+        // bip44/49/etc format
+
+        let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
+        let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/50'/0'/1/*)";
+
+        let wallet: OfflineWallet<_> = Wallet::new_offline(
+            descriptor,
+            Some(change_descriptor),
+            Network::Bitcoin,
+            get_test_db(),
+        )
+        .unwrap();
+        WalletExport::export_wallet(&wallet, "Test Label", true).unwrap();
+    }
+
+    #[test]
+    fn test_export_multi() {
+        let descriptor = "wsh(multi(2,\
+                                [73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*,\
+                                [f9f62194/48'/0'/0'/2']tpubDDp3ZSH1yCwusRppH7zgSxq2t1VEUyXSeEp8E5aFS8m43MknUjiF1bSLo3CGWAxbDyhF1XowA5ukPzyJZjznYk3kYi6oe7QxtX2euvKWsk4/0/*,\
+                                [c98b1535/48'/0'/0'/2']tpubDCDi5W4sP6zSnzJeowy8rQDVhBdRARaPhK1axABi8V1661wEPeanpEXj4ZLAUEoikVtoWcyK26TKKJSecSfeKxwHCcRrge9k1ybuiL71z4a/0/*\
+                          ))";
+        let change_descriptor = "wsh(multi(2,\
+                                       [73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/1/*,\
+                                       [f9f62194/48'/0'/0'/2']tpubDDp3ZSH1yCwusRppH7zgSxq2t1VEUyXSeEp8E5aFS8m43MknUjiF1bSLo3CGWAxbDyhF1XowA5ukPzyJZjznYk3kYi6oe7QxtX2euvKWsk4/1/*,\
+                                       [c98b1535/48'/0'/0'/2']tpubDCDi5W4sP6zSnzJeowy8rQDVhBdRARaPhK1axABi8V1661wEPeanpEXj4ZLAUEoikVtoWcyK26TKKJSecSfeKxwHCcRrge9k1ybuiL71z4a/1/*\
+                                 ))";
+
+        let wallet: OfflineWallet<_> = Wallet::new_offline(
+            descriptor,
+            Some(change_descriptor),
+            Network::Testnet,
+            get_test_db(),
+        )
+        .unwrap();
+        let export = WalletExport::export_wallet(&wallet, "Test Label", true).unwrap();
+
+        assert_eq!(export.descriptor(), descriptor);
+        assert_eq!(export.change_descriptor(), Some(change_descriptor.into()));
+        assert_eq!(export.blockheight, 5000);
+        assert_eq!(export.label, "Test Label");
+    }
+
+    #[test]
+    fn test_export_to_json() {
+        let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
+        let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";
+
+        let wallet: OfflineWallet<_> = Wallet::new_offline(
+            descriptor,
+            Some(change_descriptor),
+            Network::Bitcoin,
+            get_test_db(),
+        )
+        .unwrap();
+        let export = WalletExport::export_wallet(&wallet, "Test Label", true).unwrap();
+
+        assert_eq!(export.to_string(), "{\"descriptor\":\"wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44\'/0\'/0\'/0/*)\",\"blockheight\":5000,\"label\":\"Test Label\"}");
+    }
+
+    #[test]
+    fn test_export_from_json() {
+        let descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/0/*)";
+        let change_descriptor = "wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44'/0'/0'/1/*)";
+
+        let import_str = "{\"descriptor\":\"wpkh(xprv9s21ZrQH143K4CTb63EaMxja1YiTnSEWKMbn23uoEnAzxjdUJRQkazCAtzxGm4LSoTSVTptoV9RbchnKPW9HxKtZumdyxyikZFDLhogJ5Uj/44\'/0\'/0\'/0/*)\",\"blockheight\":5000,\"label\":\"Test Label\"}";
+        let export = WalletExport::from_str(import_str).unwrap();
+
+        assert_eq!(export.descriptor(), descriptor);
+        assert_eq!(export.change_descriptor(), Some(change_descriptor.into()));
+        assert_eq!(export.blockheight, 5000);
+        assert_eq!(export.label, "Test Label");
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/mod.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/mod.rs.html new file mode 100644 index 0000000000..a6ebcf5de5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/mod.rs.html @@ -0,0 +1,6828 @@ +mod.rs - source + +
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+2328
+2329
+2330
+2331
+2332
+2333
+2334
+2335
+2336
+2337
+2338
+2339
+2340
+2341
+2342
+2343
+2344
+2345
+2346
+2347
+2348
+2349
+2350
+2351
+2352
+2353
+2354
+2355
+2356
+2357
+2358
+2359
+2360
+2361
+2362
+2363
+2364
+2365
+2366
+2367
+2368
+2369
+2370
+2371
+2372
+2373
+2374
+2375
+2376
+2377
+2378
+2379
+2380
+2381
+2382
+2383
+2384
+2385
+2386
+2387
+2388
+2389
+2390
+2391
+2392
+2393
+2394
+2395
+2396
+2397
+2398
+2399
+2400
+2401
+2402
+2403
+2404
+2405
+2406
+2407
+2408
+2409
+2410
+2411
+2412
+2413
+2414
+2415
+2416
+2417
+2418
+2419
+2420
+2421
+2422
+2423
+2424
+2425
+2426
+2427
+2428
+2429
+2430
+2431
+2432
+2433
+2434
+2435
+2436
+2437
+2438
+2439
+2440
+2441
+2442
+2443
+2444
+2445
+2446
+2447
+2448
+2449
+2450
+2451
+2452
+2453
+2454
+2455
+2456
+2457
+2458
+2459
+2460
+2461
+2462
+2463
+2464
+2465
+2466
+2467
+2468
+2469
+2470
+2471
+2472
+2473
+2474
+2475
+2476
+2477
+2478
+2479
+2480
+2481
+2482
+2483
+2484
+2485
+2486
+2487
+2488
+2489
+2490
+2491
+2492
+2493
+2494
+2495
+2496
+2497
+2498
+2499
+2500
+2501
+2502
+2503
+2504
+2505
+2506
+2507
+2508
+2509
+2510
+2511
+2512
+2513
+2514
+2515
+2516
+2517
+2518
+2519
+2520
+2521
+2522
+2523
+2524
+2525
+2526
+2527
+2528
+2529
+2530
+2531
+2532
+2533
+2534
+2535
+2536
+2537
+2538
+2539
+2540
+2541
+2542
+2543
+2544
+2545
+2546
+2547
+2548
+2549
+2550
+2551
+2552
+2553
+2554
+2555
+2556
+2557
+2558
+2559
+2560
+2561
+2562
+2563
+2564
+2565
+2566
+2567
+2568
+2569
+2570
+2571
+2572
+2573
+2574
+2575
+2576
+2577
+2578
+2579
+2580
+2581
+2582
+2583
+2584
+2585
+2586
+2587
+2588
+2589
+2590
+2591
+2592
+2593
+2594
+2595
+2596
+2597
+2598
+2599
+2600
+2601
+2602
+2603
+2604
+2605
+2606
+2607
+2608
+2609
+2610
+2611
+2612
+2613
+2614
+2615
+2616
+2617
+2618
+2619
+2620
+2621
+2622
+2623
+2624
+2625
+2626
+2627
+2628
+2629
+2630
+2631
+2632
+2633
+2634
+2635
+2636
+2637
+2638
+2639
+2640
+2641
+2642
+2643
+2644
+2645
+2646
+2647
+2648
+2649
+2650
+2651
+2652
+2653
+2654
+2655
+2656
+2657
+2658
+2659
+2660
+2661
+2662
+2663
+2664
+2665
+2666
+2667
+2668
+2669
+2670
+2671
+2672
+2673
+2674
+2675
+2676
+2677
+2678
+2679
+2680
+2681
+2682
+2683
+2684
+2685
+2686
+2687
+2688
+2689
+2690
+2691
+2692
+2693
+2694
+2695
+2696
+2697
+2698
+2699
+2700
+2701
+2702
+2703
+2704
+2705
+2706
+2707
+2708
+2709
+2710
+2711
+2712
+2713
+2714
+2715
+2716
+2717
+2718
+2719
+2720
+2721
+2722
+2723
+2724
+2725
+2726
+2727
+2728
+2729
+2730
+2731
+2732
+2733
+2734
+2735
+2736
+2737
+2738
+2739
+2740
+2741
+2742
+2743
+2744
+2745
+2746
+2747
+2748
+2749
+2750
+2751
+2752
+2753
+2754
+2755
+2756
+2757
+2758
+2759
+2760
+2761
+2762
+2763
+2764
+2765
+2766
+2767
+2768
+2769
+2770
+2771
+2772
+2773
+2774
+2775
+2776
+2777
+2778
+2779
+2780
+2781
+2782
+2783
+2784
+2785
+2786
+2787
+2788
+2789
+2790
+2791
+2792
+2793
+2794
+2795
+2796
+2797
+2798
+2799
+2800
+2801
+2802
+2803
+2804
+2805
+2806
+2807
+2808
+2809
+2810
+2811
+2812
+2813
+2814
+2815
+2816
+2817
+2818
+2819
+2820
+2821
+2822
+2823
+2824
+2825
+2826
+2827
+2828
+2829
+2830
+2831
+2832
+2833
+2834
+2835
+2836
+2837
+2838
+2839
+2840
+2841
+2842
+2843
+2844
+2845
+2846
+2847
+2848
+2849
+2850
+2851
+2852
+2853
+2854
+2855
+2856
+2857
+2858
+2859
+2860
+2861
+2862
+2863
+2864
+2865
+2866
+2867
+2868
+2869
+2870
+2871
+2872
+2873
+2874
+2875
+2876
+2877
+2878
+2879
+2880
+2881
+2882
+2883
+2884
+2885
+2886
+2887
+2888
+2889
+2890
+2891
+2892
+2893
+2894
+2895
+2896
+2897
+2898
+2899
+2900
+2901
+2902
+2903
+2904
+2905
+2906
+2907
+2908
+2909
+2910
+2911
+2912
+2913
+2914
+2915
+2916
+2917
+2918
+2919
+2920
+2921
+2922
+2923
+2924
+2925
+2926
+2927
+2928
+2929
+2930
+2931
+2932
+2933
+2934
+2935
+2936
+2937
+2938
+2939
+2940
+2941
+2942
+2943
+2944
+2945
+2946
+2947
+2948
+2949
+2950
+2951
+2952
+2953
+2954
+2955
+2956
+2957
+2958
+2959
+2960
+2961
+2962
+2963
+2964
+2965
+2966
+2967
+2968
+2969
+2970
+2971
+2972
+2973
+2974
+2975
+2976
+2977
+2978
+2979
+2980
+2981
+2982
+2983
+2984
+2985
+2986
+2987
+2988
+2989
+2990
+2991
+2992
+2993
+2994
+2995
+2996
+2997
+2998
+2999
+3000
+3001
+3002
+3003
+3004
+3005
+3006
+3007
+3008
+3009
+3010
+3011
+3012
+3013
+3014
+3015
+3016
+3017
+3018
+3019
+3020
+3021
+3022
+3023
+3024
+3025
+3026
+3027
+3028
+3029
+3030
+3031
+3032
+3033
+3034
+3035
+3036
+3037
+3038
+3039
+3040
+3041
+3042
+3043
+3044
+3045
+3046
+3047
+3048
+3049
+3050
+3051
+3052
+3053
+3054
+3055
+3056
+3057
+3058
+3059
+3060
+3061
+3062
+3063
+3064
+3065
+3066
+3067
+3068
+3069
+3070
+3071
+3072
+3073
+3074
+3075
+3076
+3077
+3078
+3079
+3080
+3081
+3082
+3083
+3084
+3085
+3086
+3087
+3088
+3089
+3090
+3091
+3092
+3093
+3094
+3095
+3096
+3097
+3098
+3099
+3100
+3101
+3102
+3103
+3104
+3105
+3106
+3107
+3108
+3109
+3110
+3111
+3112
+3113
+3114
+3115
+3116
+3117
+3118
+3119
+3120
+3121
+3122
+3123
+3124
+3125
+3126
+3127
+3128
+3129
+3130
+3131
+3132
+3133
+3134
+3135
+3136
+3137
+3138
+3139
+3140
+3141
+3142
+3143
+3144
+3145
+3146
+3147
+3148
+3149
+3150
+3151
+3152
+3153
+3154
+3155
+3156
+3157
+3158
+3159
+3160
+3161
+3162
+3163
+3164
+3165
+3166
+3167
+3168
+3169
+3170
+3171
+3172
+3173
+3174
+3175
+3176
+3177
+3178
+3179
+3180
+3181
+3182
+3183
+3184
+3185
+3186
+3187
+3188
+3189
+3190
+3191
+3192
+3193
+3194
+3195
+3196
+3197
+3198
+3199
+3200
+3201
+3202
+3203
+3204
+3205
+3206
+3207
+3208
+3209
+3210
+3211
+3212
+3213
+3214
+3215
+3216
+3217
+3218
+3219
+3220
+3221
+3222
+3223
+3224
+3225
+3226
+3227
+3228
+3229
+3230
+3231
+3232
+3233
+3234
+3235
+3236
+3237
+3238
+3239
+3240
+3241
+3242
+3243
+3244
+3245
+3246
+3247
+3248
+3249
+3250
+3251
+3252
+3253
+3254
+3255
+3256
+3257
+3258
+3259
+3260
+3261
+3262
+3263
+3264
+3265
+3266
+3267
+3268
+3269
+3270
+3271
+3272
+3273
+3274
+3275
+3276
+3277
+3278
+3279
+3280
+3281
+3282
+3283
+3284
+3285
+3286
+3287
+3288
+3289
+3290
+3291
+3292
+3293
+3294
+3295
+3296
+3297
+3298
+3299
+3300
+3301
+3302
+3303
+3304
+3305
+3306
+3307
+3308
+3309
+3310
+3311
+3312
+3313
+3314
+3315
+3316
+3317
+3318
+3319
+3320
+3321
+3322
+3323
+3324
+3325
+3326
+3327
+3328
+3329
+3330
+3331
+3332
+3333
+3334
+3335
+3336
+3337
+3338
+3339
+3340
+3341
+3342
+3343
+3344
+3345
+3346
+3347
+3348
+3349
+3350
+3351
+3352
+3353
+3354
+3355
+3356
+3357
+3358
+3359
+3360
+3361
+3362
+3363
+3364
+3365
+3366
+3367
+3368
+3369
+3370
+3371
+3372
+3373
+3374
+3375
+3376
+3377
+3378
+3379
+3380
+3381
+3382
+3383
+3384
+3385
+3386
+3387
+3388
+3389
+3390
+3391
+3392
+3393
+3394
+3395
+3396
+3397
+3398
+3399
+3400
+3401
+3402
+3403
+3404
+3405
+3406
+3407
+3408
+3409
+3410
+3411
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Wallet
+//!
+//! This module defines the [`Wallet`] structure.
+
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::collections::{BTreeMap, HashSet};
+use std::ops::{Deref, DerefMut};
+use std::sync::Arc;
+
+use bitcoin::secp256k1::Secp256k1;
+
+use bitcoin::consensus::encode::serialize;
+use bitcoin::util::base58;
+use bitcoin::util::bip32::ChildNumber;
+use bitcoin::util::psbt::raw::Key as PSBTKey;
+use bitcoin::util::psbt::PartiallySignedTransaction as PSBT;
+use bitcoin::{Address, Network, OutPoint, Script, Transaction, TxOut, Txid};
+
+use miniscript::psbt::PsbtInputSatisfier;
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+
+pub mod address_validator;
+pub mod coin_selection;
+pub mod export;
+pub mod signer;
+pub mod time;
+pub mod tx_builder;
+pub(crate) mod utils;
+
+pub use utils::IsDust;
+
+use address_validator::AddressValidator;
+use signer::{Signer, SignerId, SignerOrdering, SignersContainer};
+use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxBuilderContext};
+use utils::{check_nlocktime, check_nsequence_rbf, descriptor_to_pk_ctx, After, Older, SecpCtx};
+
+use crate::blockchain::{Blockchain, BlockchainMarker, OfflineBlockchain, Progress};
+use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
+use crate::descriptor::{
+    get_checksum, DescriptorMeta, DescriptorScripts, ExtendedDescriptor, ExtractPolicy, Policy,
+    ToWalletDescriptor, XKeyUtils,
+};
+use crate::error::Error;
+use crate::psbt::PSBTUtils;
+use crate::types::*;
+
+const CACHE_ADDR_BATCH_SIZE: u32 = 100;
+
+/// Type alias for a [`Wallet`] that uses [`OfflineBlockchain`]
+pub type OfflineWallet<D> = Wallet<OfflineBlockchain, D>;
+
+/// A Bitcoin wallet
+///
+/// A wallet takes descriptors, a [`database`](trait@crate::database::Database) and a
+/// [`blockchain`](trait@crate::blockchain::Blockchain) and implements the basic functions that a Bitcoin wallets
+/// needs to operate, like [generating addresses](Wallet::get_new_address), [returning the balance](Wallet::get_balance),
+/// [creating transactions](Wallet::create_tx), etc.
+///
+/// A wallet can be either "online" if the [`blockchain`](crate::blockchain) type provided
+/// implements [`Blockchain`], or "offline" [`OfflineBlockchain`] is used. Offline wallets only expose
+/// methods that don't need any interaction with the blockchain to work.
+pub struct Wallet<B, D> {
+    descriptor: ExtendedDescriptor,
+    change_descriptor: Option<ExtendedDescriptor>,
+
+    signers: Arc<SignersContainer>,
+    change_signers: Arc<SignersContainer>,
+
+    address_validators: Vec<Arc<dyn AddressValidator>>,
+
+    network: Network,
+
+    current_height: Option<u32>,
+
+    client: Option<B>,
+    database: RefCell<D>,
+
+    secp: SecpCtx,
+}
+
+// offline actions, always available
+impl<B, D> Wallet<B, D>
+where
+    B: BlockchainMarker,
+    D: BatchDatabase,
+{
+    /// Create a new "offline" wallet
+    pub fn new_offline<E: ToWalletDescriptor>(
+        descriptor: E,
+        change_descriptor: Option<E>,
+        network: Network,
+        mut database: D,
+    ) -> Result<Self, Error> {
+        let (descriptor, keymap) = descriptor.to_wallet_descriptor(network)?;
+        database.check_descriptor_checksum(
+            KeychainKind::External,
+            get_checksum(&descriptor.to_string())?.as_bytes(),
+        )?;
+        let signers = Arc::new(SignersContainer::from(keymap));
+        let (change_descriptor, change_signers) = match change_descriptor {
+            Some(desc) => {
+                let (change_descriptor, change_keymap) = desc.to_wallet_descriptor(network)?;
+                database.check_descriptor_checksum(
+                    KeychainKind::Internal,
+                    get_checksum(&change_descriptor.to_string())?.as_bytes(),
+                )?;
+
+                let change_signers = Arc::new(SignersContainer::from(change_keymap));
+                // if !parsed.same_structure(descriptor.as_ref()) {
+                //     return Err(Error::DifferentDescriptorStructure);
+                // }
+
+                (Some(change_descriptor), change_signers)
+            }
+            None => (None, Arc::new(SignersContainer::new())),
+        };
+
+        Ok(Wallet {
+            descriptor,
+            change_descriptor,
+            signers,
+            change_signers,
+            address_validators: Vec::new(),
+
+            network,
+
+            current_height: None,
+
+            client: None,
+            database: RefCell::new(database),
+
+            secp: Secp256k1::new(),
+        })
+    }
+
+    /// Return a newly generated address using the external descriptor
+    pub fn get_new_address(&self) -> Result<Address, Error> {
+        let index = self.fetch_and_increment_index(KeychainKind::External)?;
+        let deriv_ctx = descriptor_to_pk_ctx(&self.secp);
+
+        self.descriptor
+            .derive(ChildNumber::from_normal_idx(index)?)
+            .address(self.network, deriv_ctx)
+            .ok_or(Error::ScriptDoesntHaveAddressForm)
+    }
+
+    /// Return whether or not a `script` is part of this wallet (either internal or external)
+    pub fn is_mine(&self, script: &Script) -> Result<bool, Error> {
+        self.database.borrow().is_mine(script)
+    }
+
+    /// Return the list of unspent outputs of this wallet
+    ///
+    /// Note that this methods only operate on the internal database, which first needs to be
+    /// [`Wallet::sync`] manually.
+    pub fn list_unspent(&self) -> Result<Vec<UTXO>, Error> {
+        self.database.borrow().iter_utxos()
+    }
+
+    /// Return the list of transactions made and received by the wallet
+    ///
+    /// Optionally fill the [`TransactionDetails::transaction`] field with the raw transaction if
+    /// `include_raw` is `true`.
+    ///
+    /// Note that this methods only operate on the internal database, which first needs to be
+    /// [`Wallet::sync`] manually.
+    pub fn list_transactions(&self, include_raw: bool) -> Result<Vec<TransactionDetails>, Error> {
+        self.database.borrow().iter_txs(include_raw)
+    }
+
+    /// Return the balance, meaning the sum of this wallet's unspent outputs' values
+    ///
+    /// Note that this methods only operate on the internal database, which first needs to be
+    /// [`Wallet::sync`] manually.
+    pub fn get_balance(&self) -> Result<u64, Error> {
+        Ok(self
+            .list_unspent()?
+            .iter()
+            .fold(0, |sum, i| sum + i.txout.value))
+    }
+
+    /// Add an external signer
+    ///
+    /// See [the `signer` module](signer) for an example.
+    pub fn add_signer(
+        &mut self,
+        keychain: KeychainKind,
+        id: SignerId,
+        ordering: SignerOrdering,
+        signer: Arc<dyn Signer>,
+    ) {
+        let signers = match keychain {
+            KeychainKind::External => Arc::make_mut(&mut self.signers),
+            KeychainKind::Internal => Arc::make_mut(&mut self.change_signers),
+        };
+
+        signers.add_external(id, ordering, signer);
+    }
+
+    /// Add an address validator
+    ///
+    /// See [the `address_validator` module](address_validator) for an example.
+    pub fn add_address_validator(&mut self, validator: Arc<dyn AddressValidator>) {
+        self.address_validators.push(validator);
+    }
+
+    /// Create a new transaction following the options specified in the `builder`
+    ///
+    /// ## Example
+    ///
+    /// ```no_run
+    /// # use std::str::FromStr;
+    /// # use bitcoin::*;
+    /// # use bdk::*;
+    /// # use bdk::database::*;
+    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+    /// # let wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+    /// let (psbt, details) = wallet.create_tx(
+    ///     TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
+    /// )?;
+    /// // sign and broadcast ...
+    /// # Ok::<(), bdk::Error>(())
+    /// ```
+    pub fn create_tx<Cs: coin_selection::CoinSelectionAlgorithm<D>>(
+        &self,
+        builder: TxBuilder<D, Cs, CreateTx>,
+    ) -> Result<(PSBT, TransactionDetails), Error> {
+        let external_policy = self
+            .descriptor
+            .extract_policy(&self.signers, &self.secp)?
+            .unwrap();
+        let internal_policy = self
+            .change_descriptor
+            .as_ref()
+            .map(|desc| {
+                Ok::<_, Error>(
+                    desc.extract_policy(&self.change_signers, &self.secp)?
+                        .unwrap(),
+                )
+            })
+            .transpose()?;
+
+        // The policy allows spending external outputs, but it requires a policy path that hasn't been
+        // provided
+        if builder.change_policy != tx_builder::ChangeSpendPolicy::OnlyChange
+            && external_policy.requires_path()
+            && builder.external_policy_path.is_none()
+        {
+            return Err(Error::SpendingPolicyRequired(KeychainKind::External));
+        };
+        // Same for the internal_policy path, if present
+        if let Some(internal_policy) = &internal_policy {
+            if builder.change_policy != tx_builder::ChangeSpendPolicy::ChangeForbidden
+                && internal_policy.requires_path()
+                && builder.internal_policy_path.is_none()
+            {
+                return Err(Error::SpendingPolicyRequired(KeychainKind::Internal));
+            };
+        }
+
+        let external_requirements = external_policy.get_condition(
+            builder
+                .external_policy_path
+                .as_ref()
+                .unwrap_or(&BTreeMap::new()),
+        )?;
+        let internal_requirements = internal_policy
+            .map(|policy| {
+                Ok::<_, Error>(
+                    policy.get_condition(
+                        builder
+                            .internal_policy_path
+                            .as_ref()
+                            .unwrap_or(&BTreeMap::new()),
+                    )?,
+                )
+            })
+            .transpose()?;
+
+        let requirements = external_requirements
+            .clone()
+            .merge(&internal_requirements.unwrap_or_default())?;
+        debug!("Policy requirements: {:?}", requirements);
+
+        let version = match builder.version {
+            Some(tx_builder::Version(0)) => {
+                return Err(Error::Generic("Invalid version `0`".into()))
+            }
+            Some(tx_builder::Version(1)) if requirements.csv.is_some() => {
+                return Err(Error::Generic(
+                    "TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV"
+                        .into(),
+                ))
+            }
+            Some(tx_builder::Version(x)) => x,
+            None if requirements.csv.is_some() => 2,
+            _ => 1,
+        };
+
+        let lock_time = match builder.locktime {
+            // No nLockTime, default to 0
+            None => requirements.timelock.unwrap_or(0),
+            // Specific nLockTime required and we have no constraints, so just set to that value
+            Some(x) if requirements.timelock.is_none() => x,
+            // Specific nLockTime required and it's compatible with the constraints
+            Some(x) if check_nlocktime(x, requirements.timelock.unwrap()) => x,
+            // Invalid nLockTime required
+            Some(x) => return Err(Error::Generic(format!("TxBuilder requested timelock of `{}`, but at least `{}` is required to spend from this script", x, requirements.timelock.unwrap())))
+        };
+
+        let n_sequence = match (builder.rbf, requirements.csv) {
+            // No RBF or CSV but there's an nLockTime, so the nSequence cannot be final
+            (None, None) if lock_time != 0 => 0xFFFFFFFE,
+            // No RBF, CSV or nLockTime, make the transaction final
+            (None, None) => 0xFFFFFFFF,
+
+            // No RBF requested, use the value from CSV. Note that this value is by definition
+            // non-final, so even if a timelock is enabled this nSequence is fine, hence why we
+            // don't bother checking for it here. The same is true for all the other branches below
+            (None, Some(csv)) => csv,
+
+            // RBF with a specific value but that value is too high
+            (Some(tx_builder::RBFValue::Value(rbf)), _) if rbf >= 0xFFFFFFFE => {
+                return Err(Error::Generic(
+                    "Cannot enable RBF with a nSequence >= 0xFFFFFFFE".into(),
+                ))
+            }
+            // RBF with a specific value requested, but the value is incompatible with CSV
+            (Some(tx_builder::RBFValue::Value(rbf)), Some(csv))
+                if !check_nsequence_rbf(rbf, csv) =>
+            {
+                return Err(Error::Generic(format!(
+                    "Cannot enable RBF with nSequence `{}` given a required OP_CSV of `{}`",
+                    rbf, csv
+                )))
+            }
+
+            // RBF enabled with the default value with CSV also enabled. CSV takes precedence
+            (Some(tx_builder::RBFValue::Default), Some(csv)) => csv,
+            // Valid RBF, either default or with a specific value. We ignore the `CSV` value
+            // because we've already checked it before
+            (Some(rbf), _) => rbf.get_value(),
+        };
+
+        let mut tx = Transaction {
+            version,
+            lock_time,
+            input: vec![],
+            output: vec![],
+        };
+
+        let (fee_rate, mut fee_amount) = match builder
+            .fee_policy
+            .as_ref()
+            .unwrap_or(&FeePolicy::FeeRate(FeeRate::default()))
+        {
+            FeePolicy::FeeAmount(amount) => (FeeRate::from_sat_per_vb(0.0), *amount as f32),
+            FeePolicy::FeeRate(rate) => (*rate, 0.0),
+        };
+
+        // try not to move from `builder` because we still need to use it later.
+        let recipients = match &builder.single_recipient {
+            Some(recipient) => vec![(recipient, 0)],
+            None => builder.recipients.iter().map(|(r, v)| (r, *v)).collect(),
+        };
+        if builder.single_recipient.is_some()
+            && !builder.manually_selected_only
+            && !builder.drain_wallet
+        {
+            return Err(Error::SingleRecipientNoInputs);
+        }
+        if recipients.is_empty() {
+            return Err(Error::NoRecipients);
+        }
+
+        if builder.manually_selected_only && builder.utxos.is_empty() {
+            return Err(Error::NoUtxosSelected);
+        }
+
+        // we keep it as a float while we accumulate it, and only round it at the end
+        let mut outgoing: u64 = 0;
+        let mut received: u64 = 0;
+
+        let calc_fee_bytes = |wu| (wu as f32) * fee_rate.as_sat_vb() / 4.0;
+        fee_amount += calc_fee_bytes(tx.get_weight());
+
+        for (index, (script_pubkey, satoshi)) in recipients.into_iter().enumerate() {
+            let value = match builder.single_recipient {
+                Some(_) => 0,
+                None if satoshi.is_dust() => return Err(Error::OutputBelowDustLimit(index)),
+                None => satoshi,
+            };
+
+            if self.is_mine(script_pubkey)? {
+                received += value;
+            }
+
+            let new_out = TxOut {
+                script_pubkey: script_pubkey.clone(),
+                value,
+            };
+            fee_amount += calc_fee_bytes(serialize(&new_out).len() * 4);
+
+            tx.output.push(new_out);
+
+            outgoing += value;
+        }
+
+        if builder.change_policy != tx_builder::ChangeSpendPolicy::ChangeAllowed
+            && self.change_descriptor.is_none()
+        {
+            return Err(Error::Generic(
+                "The `change_policy` can be set only if the wallet has a change_descriptor".into(),
+            ));
+        }
+
+        let (required_utxos, optional_utxos) = self.preselect_utxos(
+            builder.change_policy,
+            &builder.unspendable,
+            &builder.utxos,
+            builder.drain_wallet,
+            builder.manually_selected_only,
+            false, // we don't mind using unconfirmed outputs here, hopefully coin selection will sort this out?
+        )?;
+
+        let coin_selection::CoinSelectionResult {
+            selected,
+            selected_amount,
+            mut fee_amount,
+        } = builder.coin_selection.coin_select(
+            self.database.borrow().deref(),
+            required_utxos,
+            optional_utxos,
+            fee_rate,
+            outgoing,
+            fee_amount,
+        )?;
+        tx.input = selected
+            .iter()
+            .map(|u| bitcoin::TxIn {
+                previous_output: u.outpoint,
+                script_sig: Script::default(),
+                sequence: n_sequence,
+                witness: vec![],
+            })
+            .collect();
+
+        // prepare the change output
+        let change_output = match builder.single_recipient {
+            Some(_) => None,
+            None => {
+                let change_script = self.get_change_address()?;
+                let change_output = TxOut {
+                    script_pubkey: change_script,
+                    value: 0,
+                };
+
+                // take the change into account for fees
+                fee_amount += calc_fee_bytes(serialize(&change_output).len() * 4);
+                Some(change_output)
+            }
+        };
+
+        let mut fee_amount = fee_amount.ceil() as u64;
+        let change_val = (selected_amount - outgoing).saturating_sub(fee_amount);
+
+        match change_output {
+            None if change_val.is_dust() => {
+                // single recipient, but the only output would be below dust limit
+                return Err(Error::InsufficientFunds); // TODO: or OutputBelowDustLimit?
+            }
+            Some(_) if change_val.is_dust() => {
+                // skip the change output because it's dust, this adds up to the fees
+                fee_amount += selected_amount - outgoing;
+            }
+            Some(mut change_output) => {
+                change_output.value = change_val;
+                received += change_val;
+
+                tx.output.push(change_output);
+            }
+            None => {
+                // there's only one output, send everything to it
+                tx.output[0].value = change_val;
+
+                // the single recipient is our address
+                if self.is_mine(&tx.output[0].script_pubkey)? {
+                    received = change_val;
+                }
+            }
+        }
+
+        // sort input/outputs according to the chosen algorithm
+        builder.ordering.sort_tx(&mut tx);
+
+        let txid = tx.txid();
+        let psbt = self.complete_transaction(tx, selected, builder)?;
+
+        let transaction_details = TransactionDetails {
+            transaction: None,
+            txid,
+            timestamp: time::get_timestamp(),
+            received,
+            sent: selected_amount,
+            fees: fee_amount,
+            height: None,
+        };
+
+        Ok((psbt, transaction_details))
+    }
+
+    /// Bump the fee of a transaction following the options specified in the `builder`
+    ///
+    /// Return an error if the transaction is already confirmed or doesn't explicitly signal RBF.
+    ///
+    /// **NOTE**: if the original transaction was made with [`TxBuilder::set_single_recipient`],
+    /// the [`TxBuilder::maintain_single_recipient`] flag should be enabled to correctly reduce the
+    /// only output's value in order to increase the fees.
+    ///
+    /// If the `builder` specifies some `utxos` that must be spent, they will be added to the
+    /// transaction regardless of whether they are necessary or not to cover additional fees.
+    ///
+    /// ## Example
+    ///
+    /// ```no_run
+    /// # use std::str::FromStr;
+    /// # use bitcoin::*;
+    /// # use bdk::*;
+    /// # use bdk::database::*;
+    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+    /// # let wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+    /// let txid = Txid::from_str("faff0a466b70f5d5f92bd757a92c1371d4838bdd5bc53a06764e2488e51ce8f8").unwrap();
+    /// let (psbt, details) = wallet.bump_fee(
+    ///     &txid,
+    ///     TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(5.0)),
+    /// )?;
+    /// // sign and broadcast ...
+    /// # Ok::<(), bdk::Error>(())
+    /// ```
+    // TODO: support for merging multiple transactions while bumping the fees
+    // TODO: option to force addition of an extra output? seems bad for privacy to update the
+    // change
+    pub fn bump_fee<Cs: coin_selection::CoinSelectionAlgorithm<D>>(
+        &self,
+        txid: &Txid,
+        builder: TxBuilder<D, Cs, BumpFee>,
+    ) -> Result<(PSBT, TransactionDetails), Error> {
+        let mut details = match self.database.borrow().get_tx(&txid, true)? {
+            None => return Err(Error::TransactionNotFound),
+            Some(tx) if tx.transaction.is_none() => return Err(Error::TransactionNotFound),
+            Some(tx) if tx.height.is_some() => return Err(Error::TransactionConfirmed),
+            Some(tx) => tx,
+        };
+        let mut tx = details.transaction.take().unwrap();
+        if !tx.input.iter().any(|txin| txin.sequence <= 0xFFFFFFFD) {
+            return Err(Error::IrreplaceableTransaction);
+        }
+
+        // the new tx must "pay for its bandwidth"
+        let vbytes = tx.get_weight() as f32 / 4.0;
+        let required_feerate = FeeRate::from_sat_per_vb(details.fees as f32 / vbytes + 1.0);
+
+        // find the index of the output that we can update. either the change or the only one if
+        // it's `single_recipient`
+        let updatable_output = match builder.single_recipient {
+            Some(_) if tx.output.len() != 1 => return Err(Error::SingleRecipientMultipleOutputs),
+            Some(_) => Some(0),
+            None => {
+                let mut change_output = None;
+                for (index, txout) in tx.output.iter().enumerate() {
+                    // look for an output that we know and that has the right KeychainKind. We use
+                    // `get_descriptor_for` to find what's the KeychainKind for `Internal`
+                    // addresses really is, because if there's no change_descriptor it's actually equal
+                    // to "External"
+                    let (_, change_type) = self.get_descriptor_for_keychain(KeychainKind::Internal);
+                    match self
+                        .database
+                        .borrow()
+                        .get_path_from_script_pubkey(&txout.script_pubkey)?
+                    {
+                        Some((keychain, _)) if keychain == change_type => {
+                            change_output = Some(index);
+                            break;
+                        }
+                        _ => {}
+                    }
+                }
+
+                change_output
+            }
+        };
+        let updatable_output = match updatable_output {
+            Some(updatable_output) => updatable_output,
+            None => {
+                // we need a change output, add one here and take into account the extra fees for it
+                let change_script = self.get_change_address()?;
+                let change_txout = TxOut {
+                    script_pubkey: change_script,
+                    value: 0,
+                };
+                tx.output.push(change_txout);
+
+                tx.output.len() - 1
+            }
+        };
+
+        // initially always remove the output we can change
+        let mut removed_updatable_output = tx.output.remove(updatable_output);
+        if self.is_mine(&removed_updatable_output.script_pubkey)? {
+            details.received -= removed_updatable_output.value;
+        }
+
+        let deriv_ctx = descriptor_to_pk_ctx(&self.secp);
+        let original_sequence = tx.input[0].sequence;
+
+        // remove the inputs from the tx and process them
+        let original_txin = tx.input.drain(..).collect::<Vec<_>>();
+        let mut original_utxos = original_txin
+            .iter()
+            .map(|txin| -> Result<(UTXO, usize), Error> {
+                let txout = self
+                    .database
+                    .borrow()
+                    .get_previous_output(&txin.previous_output)?
+                    .ok_or(Error::UnknownUTXO)?;
+
+                let (weight, keychain) = match self
+                    .database
+                    .borrow()
+                    .get_path_from_script_pubkey(&txout.script_pubkey)?
+                {
+                    Some((keychain, _)) => (
+                        self.get_descriptor_for_keychain(keychain)
+                            .0
+                            .max_satisfaction_weight(deriv_ctx)
+                            .unwrap(),
+                        keychain,
+                    ),
+                    None => {
+                        // estimate the weight based on the scriptsig/witness size present in the
+                        // original transaction
+                        let weight =
+                            serialize(&txin.script_sig).len() * 4 + serialize(&txin.witness).len();
+                        (weight, KeychainKind::External)
+                    }
+                };
+
+                let utxo = UTXO {
+                    outpoint: txin.previous_output,
+                    txout,
+                    keychain,
+                };
+
+                Ok((utxo, weight))
+            })
+            .collect::<Result<Vec<_>, _>>()?;
+
+        if builder.manually_selected_only && builder.utxos.is_empty() {
+            return Err(Error::NoUtxosSelected);
+        }
+
+        let builder_extra_utxos = builder
+            .utxos
+            .iter()
+            .filter(|utxo| {
+                !original_txin
+                    .iter()
+                    .any(|txin| &&txin.previous_output == utxo)
+            })
+            .cloned()
+            .collect::<Vec<_>>();
+
+        let (mut required_utxos, optional_utxos) = self.preselect_utxos(
+            builder.change_policy,
+            &builder.unspendable,
+            &builder_extra_utxos[..],
+            builder.drain_wallet,
+            builder.manually_selected_only,
+            true, // we only want confirmed transactions for RBF
+        )?;
+
+        required_utxos.append(&mut original_utxos);
+
+        let amount_needed = tx.output.iter().fold(0, |acc, out| acc + out.value);
+        let (new_feerate, initial_fee) = match builder
+            .fee_policy
+            .as_ref()
+            .unwrap_or(&FeePolicy::FeeRate(FeeRate::default()))
+        {
+            FeePolicy::FeeAmount(amount) => {
+                if *amount < details.fees {
+                    return Err(Error::FeeTooLow {
+                        required: details.fees,
+                    });
+                }
+                (FeeRate::from_sat_per_vb(0.0), *amount as f32)
+            }
+            FeePolicy::FeeRate(rate) => {
+                if *rate < required_feerate {
+                    return Err(Error::FeeRateTooLow {
+                        required: required_feerate,
+                    });
+                }
+                (*rate, tx.get_weight() as f32 / 4.0 * rate.as_sat_vb())
+            }
+        };
+
+        let coin_selection::CoinSelectionResult {
+            selected,
+            selected_amount,
+            fee_amount,
+        } = builder.coin_selection.coin_select(
+            self.database.borrow().deref(),
+            required_utxos,
+            optional_utxos,
+            new_feerate,
+            amount_needed,
+            initial_fee,
+        )?;
+
+        tx.input = selected
+            .iter()
+            .map(|u| bitcoin::TxIn {
+                previous_output: u.outpoint,
+                script_sig: Script::default(),
+                // TODO: use builder.n_sequence??
+                sequence: original_sequence,
+                witness: vec![],
+            })
+            .collect();
+
+        details.sent = selected_amount;
+
+        let mut fee_amount = fee_amount.ceil() as u64;
+        let removed_output_fee_cost = (serialize(&removed_updatable_output).len() as f32
+            * new_feerate.as_sat_vb())
+        .ceil() as u64;
+
+        let change_val = selected_amount - amount_needed - fee_amount;
+        let change_val_after_add = change_val.saturating_sub(removed_output_fee_cost);
+        match builder.single_recipient {
+            None if change_val_after_add.is_dust() => {
+                // skip the change output because it's dust, this adds up to the fees
+                fee_amount += change_val;
+            }
+            Some(_) if change_val_after_add.is_dust() => {
+                // single_recipient but the only output would be below dust limit
+                return Err(Error::InsufficientFunds); // TODO: or OutputBelowDustLimit?
+            }
+            None => {
+                removed_updatable_output.value = change_val_after_add;
+                fee_amount += removed_output_fee_cost;
+                details.received += change_val_after_add;
+
+                tx.output.push(removed_updatable_output);
+            }
+            Some(_) => {
+                removed_updatable_output.value = change_val_after_add;
+                fee_amount += removed_output_fee_cost;
+
+                // single recipient and it's our address
+                if self.is_mine(&removed_updatable_output.script_pubkey)? {
+                    details.received = change_val_after_add;
+                }
+
+                tx.output.push(removed_updatable_output);
+            }
+        }
+
+        // sort input/outputs according to the chosen algorithm
+        builder.ordering.sort_tx(&mut tx);
+
+        // TODO: check that we are not replacing more than 100 txs from mempool
+
+        details.txid = tx.txid();
+        details.fees = fee_amount;
+        details.timestamp = time::get_timestamp();
+
+        let psbt = self.complete_transaction(tx, selected, builder)?;
+
+        Ok((psbt, details))
+    }
+
+    /// Sign a transaction with all the wallet's signers, in the order specified by every signer's
+    /// [`SignerOrdering`]
+    ///
+    /// ## Example
+    ///
+    /// ```no_run
+    /// # use std::str::FromStr;
+    /// # use bitcoin::*;
+    /// # use bdk::*;
+    /// # use bdk::database::*;
+    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+    /// # let wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+    /// # let (psbt, _) = wallet.create_tx(TxBuilder::new())?;
+    /// let (signed_psbt, finalized) = wallet.sign(psbt, None)?;
+    /// # Ok::<(), bdk::Error>(())
+    pub fn sign(&self, mut psbt: PSBT, assume_height: Option<u32>) -> Result<(PSBT, bool), Error> {
+        // this helps us doing our job later
+        self.add_input_hd_keypaths(&mut psbt)?;
+
+        for signer in self
+            .signers
+            .signers()
+            .iter()
+            .chain(self.change_signers.signers().iter())
+        {
+            if signer.sign_whole_tx() {
+                signer.sign(&mut psbt, None, &self.secp)?;
+            } else {
+                for index in 0..psbt.inputs.len() {
+                    signer.sign(&mut psbt, Some(index), &self.secp)?;
+                }
+            }
+        }
+
+        // attempt to finalize
+        self.finalize_psbt(psbt, assume_height)
+    }
+
+    /// Return the spending policies for the wallet's descriptor
+    pub fn policies(&self, keychain: KeychainKind) -> Result<Option<Policy>, Error> {
+        match (keychain, self.change_descriptor.as_ref()) {
+            (KeychainKind::External, _) => {
+                Ok(self.descriptor.extract_policy(&self.signers, &self.secp)?)
+            }
+            (KeychainKind::Internal, None) => Ok(None),
+            (KeychainKind::Internal, Some(desc)) => {
+                Ok(desc.extract_policy(&self.change_signers, &self.secp)?)
+            }
+        }
+    }
+
+    /// Return the "public" version of the wallet's descriptor, meaning a new descriptor that has
+    /// the same structure but with every secret key removed
+    ///
+    /// This can be used to build a watch-only version of a wallet
+    pub fn public_descriptor(
+        &self,
+        keychain: KeychainKind,
+    ) -> Result<Option<ExtendedDescriptor>, Error> {
+        match (keychain, self.change_descriptor.as_ref()) {
+            (KeychainKind::External, _) => Ok(Some(self.descriptor.clone())),
+            (KeychainKind::Internal, None) => Ok(None),
+            (KeychainKind::Internal, Some(desc)) => Ok(Some(desc.clone())),
+        }
+    }
+
+    /// Try to finalize a PSBT
+    pub fn finalize_psbt(
+        &self,
+        mut psbt: PSBT,
+        assume_height: Option<u32>,
+    ) -> Result<(PSBT, bool), Error> {
+        let tx = &psbt.global.unsigned_tx;
+        let mut finished = true;
+
+        for (n, input) in tx.input.iter().enumerate() {
+            let psbt_input = &psbt.inputs[n];
+            if psbt_input.final_script_sig.is_some() || psbt_input.final_script_witness.is_some() {
+                continue;
+            }
+            // if the height is None in the database it means it's still unconfirmed, so consider
+            // that as a very high value
+            let create_height = self
+                .database
+                .borrow()
+                .get_tx(&input.previous_output.txid, false)?
+                .map(|tx| tx.height.unwrap_or(std::u32::MAX));
+            let current_height = assume_height.or(self.current_height);
+
+            debug!(
+                "Input #{} - {}, using `create_height` = {:?}, `current_height` = {:?}",
+                n, input.previous_output, create_height, current_height
+            );
+
+            // - Try to derive the descriptor by looking at the txout. If it's in our database, we
+            //   know exactly which `keychain` to use, and which derivation index it is
+            // - If that fails, try to derive it by looking at the psbt input: the complete logic
+            //   is in `src/descriptor/mod.rs`, but it will basically look at `hd_keypaths`,
+            //   `redeem_script` and `witness_script` to determine the right derivation
+            // - If that also fails, it will try it on the internal descriptor, if present
+            let desc = psbt
+                .get_utxo_for(n)
+                .map(|txout| self.get_descriptor_for_txout(&txout))
+                .transpose()?
+                .flatten()
+                .or_else(|| {
+                    self.descriptor.derive_from_psbt_input(
+                        psbt_input,
+                        psbt.get_utxo_for(n),
+                        &self.secp,
+                    )
+                })
+                .or_else(|| {
+                    self.change_descriptor.as_ref().and_then(|desc| {
+                        desc.derive_from_psbt_input(psbt_input, psbt.get_utxo_for(n), &self.secp)
+                    })
+                });
+
+            match desc {
+                Some(desc) => {
+                    let mut tmp_input = bitcoin::TxIn::default();
+                    let deriv_ctx = descriptor_to_pk_ctx(&self.secp);
+                    match desc.satisfy(
+                        &mut tmp_input,
+                        (
+                            PsbtInputSatisfier::new(&psbt, n),
+                            After::new(current_height, false),
+                            Older::new(current_height, create_height, false),
+                        ),
+                        deriv_ctx,
+                    ) {
+                        Ok(_) => {
+                            let psbt_input = &mut psbt.inputs[n];
+                            psbt_input.final_script_sig = Some(tmp_input.script_sig);
+                            psbt_input.final_script_witness = Some(tmp_input.witness);
+                        }
+                        Err(e) => {
+                            debug!("satisfy error {:?} for input {}", e, n);
+                            finished = false
+                        }
+                    }
+                }
+                None => finished = false,
+            }
+        }
+
+        Ok((psbt, finished))
+    }
+
+    /// Return the secp256k1 context used for all signing operations
+    pub fn secp_ctx(&self) -> &SecpCtx {
+        &self.secp
+    }
+
+    // Internals
+
+    fn get_descriptor_for_keychain(
+        &self,
+        keychain: KeychainKind,
+    ) -> (&ExtendedDescriptor, KeychainKind) {
+        match keychain {
+            KeychainKind::Internal if self.change_descriptor.is_some() => (
+                self.change_descriptor.as_ref().unwrap(),
+                KeychainKind::Internal,
+            ),
+            _ => (&self.descriptor, KeychainKind::External),
+        }
+    }
+
+    fn get_descriptor_for_txout(&self, txout: &TxOut) -> Result<Option<ExtendedDescriptor>, Error> {
+        Ok(self
+            .database
+            .borrow()
+            .get_path_from_script_pubkey(&txout.script_pubkey)?
+            .map(|(keychain, child)| (self.get_descriptor_for_keychain(keychain).0, child))
+            .map(|(desc, child)| desc.derive(ChildNumber::from_normal_idx(child).unwrap())))
+    }
+
+    fn get_change_address(&self) -> Result<Script, Error> {
+        let deriv_ctx = descriptor_to_pk_ctx(&self.secp);
+
+        let (desc, keychain) = self.get_descriptor_for_keychain(KeychainKind::Internal);
+        let index = self.fetch_and_increment_index(keychain)?;
+
+        Ok(desc
+            .derive(ChildNumber::from_normal_idx(index)?)
+            .script_pubkey(deriv_ctx))
+    }
+
+    fn fetch_and_increment_index(&self, keychain: KeychainKind) -> Result<u32, Error> {
+        let (descriptor, keychain) = self.get_descriptor_for_keychain(keychain);
+        let index = match descriptor.is_fixed() {
+            true => 0,
+            false => self.database.borrow_mut().increment_last_index(keychain)?,
+        };
+
+        if self
+            .database
+            .borrow()
+            .get_script_pubkey_from_path(keychain, index)?
+            .is_none()
+        {
+            self.cache_addresses(keychain, index, CACHE_ADDR_BATCH_SIZE)?;
+        }
+
+        let deriv_ctx = descriptor_to_pk_ctx(&self.secp);
+
+        let hd_keypaths = descriptor.get_hd_keypaths(index, &self.secp)?;
+        let script = descriptor
+            .derive(ChildNumber::from_normal_idx(index)?)
+            .script_pubkey(deriv_ctx);
+        for validator in &self.address_validators {
+            validator.validate(keychain, &hd_keypaths, &script)?;
+        }
+
+        Ok(index)
+    }
+
+    fn cache_addresses(
+        &self,
+        keychain: KeychainKind,
+        from: u32,
+        mut count: u32,
+    ) -> Result<(), Error> {
+        let (descriptor, keychain) = self.get_descriptor_for_keychain(keychain);
+        if descriptor.is_fixed() {
+            if from > 0 {
+                return Ok(());
+            }
+
+            count = 1;
+        }
+
+        let deriv_ctx = descriptor_to_pk_ctx(&self.secp);
+
+        let mut address_batch = self.database.borrow().begin_batch();
+
+        let start_time = time::Instant::new();
+        for i in from..(from + count) {
+            address_batch.set_script_pubkey(
+                &descriptor
+                    .derive(ChildNumber::from_normal_idx(i)?)
+                    .script_pubkey(deriv_ctx),
+                keychain,
+                i,
+            )?;
+        }
+
+        info!(
+            "Derivation of {} addresses from {} took {} ms",
+            count,
+            from,
+            start_time.elapsed().as_millis()
+        );
+
+        self.database.borrow_mut().commit_batch(address_batch)?;
+
+        Ok(())
+    }
+
+    fn get_available_utxos(&self) -> Result<Vec<(UTXO, usize)>, Error> {
+        let deriv_ctx = descriptor_to_pk_ctx(&self.secp);
+        Ok(self
+            .list_unspent()?
+            .into_iter()
+            .map(|utxo| {
+                let keychain = utxo.keychain;
+                (
+                    utxo,
+                    self.get_descriptor_for_keychain(keychain)
+                        .0
+                        .max_satisfaction_weight(deriv_ctx)
+                        .unwrap(),
+                )
+            })
+            .collect())
+    }
+
+    /// Given the options returns the list of utxos that must be used to form the
+    /// transaction and any further that may be used if needed.
+    #[allow(clippy::type_complexity)]
+    fn preselect_utxos(
+        &self,
+        change_policy: tx_builder::ChangeSpendPolicy,
+        unspendable: &HashSet<OutPoint>,
+        manually_selected: &[OutPoint],
+        must_use_all_available: bool,
+        manual_only: bool,
+        must_only_use_confirmed_tx: bool,
+    ) -> Result<(Vec<(UTXO, usize)>, Vec<(UTXO, usize)>), Error> {
+        //    must_spend <- manually selected utxos
+        //    may_spend  <- all other available utxos
+        let mut may_spend = self.get_available_utxos()?;
+        let mut must_spend = {
+            let must_spend_idx = manually_selected
+                .iter()
+                .map(|manually_selected| {
+                    may_spend
+                        .iter()
+                        .position(|available| available.0.outpoint == *manually_selected)
+                        .ok_or(Error::UnknownUTXO)
+                })
+                .collect::<Result<Vec<_>, _>>()?;
+
+            must_spend_idx
+                .into_iter()
+                .map(|i| may_spend.remove(i))
+                .collect()
+        };
+
+        // NOTE: we are intentionally ignoring `unspendable` here. i.e manual
+        // selection overrides unspendable.
+        if manual_only {
+            return Ok((must_spend, vec![]));
+        }
+
+        let satisfies_confirmed = match must_only_use_confirmed_tx {
+            true => {
+                let database = self.database.borrow_mut();
+                may_spend
+                    .iter()
+                    .map(|u| {
+                        database
+                            .get_tx(&u.0.outpoint.txid, true)
+                            .map(|tx| match tx {
+                                None => false,
+                                Some(tx) => tx.height.is_some(),
+                            })
+                    })
+                    .collect::<Result<Vec<_>, _>>()?
+            }
+            false => vec![true; may_spend.len()],
+        };
+
+        let mut i = 0;
+        may_spend.retain(|u| {
+            let retain = change_policy.is_satisfied_by(&u.0)
+                && !unspendable.contains(&u.0.outpoint)
+                && satisfies_confirmed[i];
+            i += 1;
+            retain
+        });
+
+        if must_use_all_available {
+            must_spend.append(&mut may_spend);
+        }
+
+        Ok((must_spend, may_spend))
+    }
+
+    fn complete_transaction<
+        Cs: coin_selection::CoinSelectionAlgorithm<D>,
+        Ctx: TxBuilderContext,
+    >(
+        &self,
+        tx: Transaction,
+        selected: Vec<UTXO>,
+        builder: TxBuilder<D, Cs, Ctx>,
+    ) -> Result<PSBT, Error> {
+        use bitcoin::util::psbt::serialize::Serialize;
+
+        let mut psbt = PSBT::from_unsigned_tx(tx)?;
+
+        if builder.add_global_xpubs {
+            let mut all_xpubs = self.descriptor.get_extended_keys()?;
+            if let Some(change_descriptor) = &self.change_descriptor {
+                all_xpubs.extend(change_descriptor.get_extended_keys()?);
+            }
+
+            for xpub in all_xpubs {
+                let serialized_xpub = base58::from_check(&xpub.xkey.to_string())
+                    .expect("Internal serialization error");
+                let key = PSBTKey {
+                    type_value: 0x01,
+                    key: serialized_xpub,
+                };
+
+                let origin = match xpub.origin {
+                    Some(origin) => origin,
+                    None if xpub.xkey.depth == 0 => {
+                        (xpub.root_fingerprint(&self.secp), vec![].into())
+                    }
+                    _ => return Err(Error::MissingKeyOrigin(xpub.xkey.to_string())),
+                };
+
+                psbt.global.unknown.insert(key, origin.serialize());
+            }
+        }
+
+        let lookup_output = selected
+            .into_iter()
+            .map(|utxo| (utxo.outpoint, utxo))
+            .collect::<HashMap<_, _>>();
+
+        // add metadata for the inputs
+        for (psbt_input, input) in psbt
+            .inputs
+            .iter_mut()
+            .zip(psbt.global.unsigned_tx.input.iter())
+        {
+            let utxo = match lookup_output.get(&input.previous_output) {
+                Some(utxo) => utxo,
+                None => continue,
+            };
+
+            // Only set it if the builder has a custom one, otherwise leave blank which defaults to
+            // SIGHASH_ALL
+            if let Some(sighash_type) = builder.sighash {
+                psbt_input.sighash_type = Some(sighash_type);
+            }
+
+            // Try to find the prev_script in our db to figure out if this is internal or external,
+            // and the derivation index
+            let (keychain, child) = match self
+                .database
+                .borrow()
+                .get_path_from_script_pubkey(&utxo.txout.script_pubkey)?
+            {
+                Some(x) => x,
+                None => continue,
+            };
+
+            let (desc, _) = self.get_descriptor_for_keychain(keychain);
+            psbt_input.hd_keypaths = desc.get_hd_keypaths(child, &self.secp)?;
+            let derived_descriptor = desc.derive(ChildNumber::from_normal_idx(child)?);
+
+            psbt_input.redeem_script = derived_descriptor.psbt_redeem_script(&self.secp);
+            psbt_input.witness_script = derived_descriptor.psbt_witness_script(&self.secp);
+
+            let prev_output = input.previous_output;
+            if let Some(prev_tx) = self.database.borrow().get_raw_tx(&prev_output.txid)? {
+                if derived_descriptor.is_witness() {
+                    psbt_input.witness_utxo =
+                        Some(prev_tx.output[prev_output.vout as usize].clone());
+                }
+                if !derived_descriptor.is_witness() || builder.force_non_witness_utxo {
+                    psbt_input.non_witness_utxo = Some(prev_tx);
+                }
+            }
+        }
+
+        // probably redundant but it doesn't hurt...
+        self.add_input_hd_keypaths(&mut psbt)?;
+
+        // add metadata for the outputs
+        for (psbt_output, tx_output) in psbt
+            .outputs
+            .iter_mut()
+            .zip(psbt.global.unsigned_tx.output.iter())
+        {
+            if let Some((keychain, child)) = self
+                .database
+                .borrow()
+                .get_path_from_script_pubkey(&tx_output.script_pubkey)?
+            {
+                let (desc, _) = self.get_descriptor_for_keychain(keychain);
+                psbt_output.hd_keypaths = desc.get_hd_keypaths(child, &self.secp)?;
+                if builder.include_output_redeem_witness_script {
+                    let derived_descriptor = desc.derive(ChildNumber::from_normal_idx(child)?);
+                    psbt_output.witness_script = derived_descriptor.psbt_witness_script(&self.secp);
+                    psbt_output.redeem_script = derived_descriptor.psbt_redeem_script(&self.secp);
+                };
+            }
+        }
+
+        Ok(psbt)
+    }
+
+    fn add_input_hd_keypaths(&self, psbt: &mut PSBT) -> Result<(), Error> {
+        let mut input_utxos = Vec::with_capacity(psbt.inputs.len());
+        for n in 0..psbt.inputs.len() {
+            input_utxos.push(psbt.get_utxo_for(n).clone());
+        }
+
+        // try to add hd_keypaths if we've already seen the output
+        for (psbt_input, out) in psbt.inputs.iter_mut().zip(input_utxos.iter()) {
+            if let Some(out) = out {
+                if let Some((keychain, child)) = self
+                    .database
+                    .borrow()
+                    .get_path_from_script_pubkey(&out.script_pubkey)?
+                {
+                    debug!("Found descriptor {:?}/{}", keychain, child);
+
+                    // merge hd_keypaths
+                    let (desc, _) = self.get_descriptor_for_keychain(keychain);
+                    let mut hd_keypaths = desc.get_hd_keypaths(child, &self.secp)?;
+                    psbt_input.hd_keypaths.append(&mut hd_keypaths);
+                }
+            }
+        }
+
+        Ok(())
+    }
+}
+
+impl<B, D> Wallet<B, D>
+where
+    B: Blockchain,
+    D: BatchDatabase,
+{
+    /// Create a new "online" wallet
+    #[maybe_async]
+    pub fn new<E: ToWalletDescriptor>(
+        descriptor: E,
+        change_descriptor: Option<E>,
+        network: Network,
+        database: D,
+        client: B,
+    ) -> Result<Self, Error> {
+        let mut wallet = Self::new_offline(descriptor, change_descriptor, network, database)?;
+
+        wallet.current_height = Some(maybe_await!(client.get_height())? as u32);
+        wallet.client = Some(client);
+
+        Ok(wallet)
+    }
+
+    /// Sync the internal database with the blockchain
+    #[maybe_async]
+    pub fn sync<P: 'static + Progress>(
+        &self,
+        progress_update: P,
+        max_address_param: Option<u32>,
+    ) -> Result<(), Error> {
+        debug!("Begin sync...");
+
+        let mut run_setup = false;
+
+        let max_address = match self.descriptor.is_fixed() {
+            true => 0,
+            false => max_address_param.unwrap_or(CACHE_ADDR_BATCH_SIZE),
+        };
+        if self
+            .database
+            .borrow()
+            .get_script_pubkey_from_path(KeychainKind::External, max_address.saturating_sub(1))?
+            .is_none()
+        {
+            run_setup = true;
+            self.cache_addresses(KeychainKind::External, 0, max_address)?;
+        }
+
+        if let Some(change_descriptor) = &self.change_descriptor {
+            let max_address = match change_descriptor.is_fixed() {
+                true => 0,
+                false => max_address_param.unwrap_or(CACHE_ADDR_BATCH_SIZE),
+            };
+
+            if self
+                .database
+                .borrow()
+                .get_script_pubkey_from_path(KeychainKind::Internal, max_address.saturating_sub(1))?
+                .is_none()
+            {
+                run_setup = true;
+                self.cache_addresses(KeychainKind::Internal, 0, max_address)?;
+            }
+        }
+
+        // TODO: what if i generate an address first and cache some addresses?
+        // TODO: we should sync if generating an address triggers a new batch to be stored
+        if run_setup {
+            maybe_await!(self.client.as_ref().ok_or(Error::OfflineClient)?.setup(
+                None,
+                self.database.borrow_mut().deref_mut(),
+                progress_update,
+            ))
+        } else {
+            maybe_await!(self.client.as_ref().ok_or(Error::OfflineClient)?.sync(
+                None,
+                self.database.borrow_mut().deref_mut(),
+                progress_update,
+            ))
+        }
+    }
+
+    /// Return a reference to the internal blockchain client
+    pub fn client(&self) -> Option<&B> {
+        self.client.as_ref()
+    }
+
+    /// Get the Bitcoin network the wallet is using.
+    pub fn network(&self) -> Network {
+        self.network
+    }
+
+    /// Broadcast a transaction to the network
+    #[maybe_async]
+    pub fn broadcast(&self, tx: Transaction) -> Result<Txid, Error> {
+        maybe_await!(self
+            .client
+            .as_ref()
+            .ok_or(Error::OfflineClient)?
+            .broadcast(&tx))?;
+
+        Ok(tx.txid())
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::str::FromStr;
+
+    use bitcoin::Network;
+
+    use crate::database::memory::MemoryDatabase;
+    use crate::database::Database;
+    use crate::types::KeychainKind;
+
+    use super::*;
+
+    #[test]
+    fn test_cache_addresses_fixed() {
+        let db = MemoryDatabase::new();
+        let wallet: OfflineWallet<_> = Wallet::new_offline(
+            "wpkh(L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6)",
+            None,
+            Network::Testnet,
+            db,
+        )
+        .unwrap();
+
+        assert_eq!(
+            wallet.get_new_address().unwrap().to_string(),
+            "tb1qj08ys4ct2hzzc2hcz6h2hgrvlmsjynaw43s835"
+        );
+        assert_eq!(
+            wallet.get_new_address().unwrap().to_string(),
+            "tb1qj08ys4ct2hzzc2hcz6h2hgrvlmsjynaw43s835"
+        );
+
+        assert!(wallet
+            .database
+            .borrow_mut()
+            .get_script_pubkey_from_path(KeychainKind::External, 0)
+            .unwrap()
+            .is_some());
+        assert!(wallet
+            .database
+            .borrow_mut()
+            .get_script_pubkey_from_path(KeychainKind::Internal, 0)
+            .unwrap()
+            .is_none());
+    }
+
+    #[test]
+    fn test_cache_addresses() {
+        let db = MemoryDatabase::new();
+        let wallet: OfflineWallet<_> = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
+
+        assert_eq!(
+            wallet.get_new_address().unwrap().to_string(),
+            "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
+        );
+        assert_eq!(
+            wallet.get_new_address().unwrap().to_string(),
+            "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
+        );
+
+        assert!(wallet
+            .database
+            .borrow_mut()
+            .get_script_pubkey_from_path(KeychainKind::External, CACHE_ADDR_BATCH_SIZE - 1)
+            .unwrap()
+            .is_some());
+        assert!(wallet
+            .database
+            .borrow_mut()
+            .get_script_pubkey_from_path(KeychainKind::External, CACHE_ADDR_BATCH_SIZE)
+            .unwrap()
+            .is_none());
+    }
+
+    #[test]
+    fn test_cache_addresses_refill() {
+        let db = MemoryDatabase::new();
+        let wallet: OfflineWallet<_> = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
+
+        assert_eq!(
+            wallet.get_new_address().unwrap().to_string(),
+            "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
+        );
+        assert!(wallet
+            .database
+            .borrow_mut()
+            .get_script_pubkey_from_path(KeychainKind::External, CACHE_ADDR_BATCH_SIZE - 1)
+            .unwrap()
+            .is_some());
+
+        for _ in 0..CACHE_ADDR_BATCH_SIZE {
+            wallet.get_new_address().unwrap();
+        }
+
+        assert!(wallet
+            .database
+            .borrow_mut()
+            .get_script_pubkey_from_path(KeychainKind::External, CACHE_ADDR_BATCH_SIZE * 2 - 1)
+            .unwrap()
+            .is_some());
+    }
+
+    pub(crate) fn get_test_wpkh() -> &'static str {
+        "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"
+    }
+
+    pub(crate) fn get_test_single_sig_csv() -> &'static str {
+        // and(pk(Alice),older(6))
+        "wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),older(6)))"
+    }
+
+    pub(crate) fn get_test_a_or_b_plus_csv() -> &'static str {
+        // or(pk(Alice),and(pk(Bob),older(144)))
+        "wsh(or_d(pk(cRjo6jqfVNP33HhSS76UhXETZsGTZYx8FMFvR9kpbtCSV1PmdZdu),and_v(v:pk(cMnkdebixpXMPfkcNEjjGin7s94hiehAH4mLbYkZoh9KSiNNmqC8),older(144))))"
+    }
+
+    pub(crate) fn get_test_single_sig_cltv() -> &'static str {
+        // and(pk(Alice),after(100000))
+        "wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),after(100000)))"
+    }
+
+    pub(crate) fn get_funded_wallet(
+        descriptor: &str,
+    ) -> (
+        OfflineWallet<MemoryDatabase>,
+        (String, Option<String>),
+        bitcoin::Txid,
+    ) {
+        let descriptors = testutils!(@descriptors (descriptor));
+        let wallet: OfflineWallet<_> = Wallet::new_offline(
+            &descriptors.0,
+            None,
+            Network::Regtest,
+            MemoryDatabase::new(),
+        )
+        .unwrap();
+
+        let txid = wallet.database.borrow_mut().received_tx(
+            testutils! {
+                @tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
+            },
+            Some(100),
+        );
+
+        (wallet, descriptors, txid)
+    }
+
+    macro_rules! assert_fee_rate {
+        ($tx:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({
+            let mut tx = $tx.clone();
+            $(
+                $( $add_signature )*
+                for txin in &mut tx.input {
+                    txin.witness.push([0x00; 108].to_vec()); // fake signature
+                }
+            )*
+
+            #[allow(unused_mut)]
+            #[allow(unused_assignments)]
+            let mut dust_change = false;
+            $(
+                $( $dust_change )*
+                dust_change = true;
+            )*
+
+            let tx_fee_rate = $fees as f32 / (tx.get_weight() as f32 / 4.0);
+            let fee_rate = $fee_rate.as_sat_vb();
+
+            if !dust_change {
+                assert!((tx_fee_rate - fee_rate).abs() < 0.5, format!("Expected fee rate of {}, the tx has {}", fee_rate, tx_fee_rate));
+            } else {
+                assert!(tx_fee_rate >= fee_rate, format!("Expected fee rate of at least {}, the tx has {}", fee_rate, tx_fee_rate));
+            }
+        });
+    }
+
+    #[test]
+    #[should_panic(expected = "NoRecipients")]
+    fn test_create_tx_empty_recipients() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        wallet
+            .create_tx(TxBuilder::with_recipients(vec![]))
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "NoUtxosSelected")]
+    fn test_create_tx_manually_selected_empty_utxos() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)])
+                    .manually_selected_only()
+                    .utxos(vec![]),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "Invalid version `0`")]
+    fn test_create_tx_version_0() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        wallet
+            .create_tx(TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).version(0))
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(
+        expected = "TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV"
+    )]
+    fn test_create_tx_version_1_csv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv());
+        let addr = wallet.get_new_address().unwrap();
+        wallet
+            .create_tx(TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).version(1))
+            .unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_custom_version() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).version(42))
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.version, 42);
+    }
+
+    #[test]
+    fn test_create_tx_default_locktime() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                25_000,
+            )]))
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.lock_time, 0);
+    }
+
+    #[test]
+    fn test_create_tx_default_locktime_cltv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                25_000,
+            )]))
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.lock_time, 100_000);
+    }
+
+    #[test]
+    fn test_create_tx_custom_locktime() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).nlocktime(630_000),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.lock_time, 630_000);
+    }
+
+    #[test]
+    fn test_create_tx_custom_locktime_compatible_with_cltv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).nlocktime(630_000),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.lock_time, 630_000);
+    }
+
+    #[test]
+    #[should_panic(
+        expected = "TxBuilder requested timelock of `50000`, but at least `100000` is required to spend from this script"
+    )]
+    fn test_create_tx_custom_locktime_incompatible_with_cltv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv());
+        let addr = wallet.get_new_address().unwrap();
+        wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).nlocktime(50000),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_no_rbf_csv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                25_000,
+            )]))
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 6);
+    }
+
+    #[test]
+    fn test_create_tx_with_default_rbf_csv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).enable_rbf(),
+            )
+            .unwrap();
+
+        // When CSV is enabled it takes precedence over the rbf value (unless forced by the user).
+        // It will be set to the OP_CSV value, in this case 6
+        assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 6);
+    }
+
+    #[test]
+    #[should_panic(
+        expected = "Cannot enable RBF with nSequence `3` given a required OP_CSV of `6`"
+    )]
+    fn test_create_tx_with_custom_rbf_csv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv());
+        let addr = wallet.get_new_address().unwrap();
+        wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)])
+                    .enable_rbf_with_sequence(3),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_no_rbf_cltv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                25_000,
+            )]))
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 0xFFFFFFFE);
+    }
+
+    #[test]
+    #[should_panic(expected = "Cannot enable RBF with a nSequence >= 0xFFFFFFFE")]
+    fn test_create_tx_invalid_rbf_sequence() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)])
+                    .enable_rbf_with_sequence(0xFFFFFFFE),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_custom_rbf_sequence() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)])
+                    .enable_rbf_with_sequence(0xDEADBEEF),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 0xDEADBEEF);
+    }
+
+    #[test]
+    fn test_create_tx_default_sequence() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                25_000,
+            )]))
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 0xFFFFFFFF);
+    }
+
+    #[test]
+    #[should_panic(
+        expected = "The `change_policy` can be set only if the wallet has a change_descriptor"
+    )]
+    fn test_create_tx_change_policy_no_internal() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)])
+                    .do_not_spend_change(),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_single_recipient_drain_wallet() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, details) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
+        assert_eq!(
+            psbt.global.unsigned_tx.output[0].value,
+            50_000 - details.fees
+        );
+    }
+
+    #[test]
+    fn test_create_tx_default_fee_rate() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, details) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                25_000,
+            )]))
+            .unwrap();
+
+        assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::default(), @add_signature);
+    }
+
+    #[test]
+    fn test_create_tx_custom_fee_rate() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)])
+                    .fee_rate(FeeRate::from_sat_per_vb(5.0)),
+            )
+            .unwrap();
+
+        assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(5.0), @add_signature);
+    }
+
+    #[test]
+    fn test_create_tx_absolute_fee() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, details) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet()
+                    .fee_absolute(100),
+            )
+            .unwrap();
+
+        assert_eq!(details.fees, 100);
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
+        assert_eq!(
+            psbt.global.unsigned_tx.output[0].value,
+            50_000 - details.fees
+        );
+    }
+
+    #[test]
+    fn test_create_tx_absolute_zero_fee() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, details) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet()
+                    .fee_absolute(0),
+            )
+            .unwrap();
+
+        assert_eq!(details.fees, 0);
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
+        assert_eq!(
+            psbt.global.unsigned_tx.output[0].value,
+            50_000 - details.fees
+        );
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_create_tx_absolute_high_fee() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (_psbt, _details) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet()
+                    .fee_absolute(60_000),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_add_change() {
+        use super::tx_builder::TxOrdering;
+
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)])
+                    .ordering(TxOrdering::Untouched),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 2);
+        assert_eq!(psbt.global.unsigned_tx.output[0].value, 25_000);
+        assert_eq!(
+            psbt.global.unsigned_tx.output[1].value,
+            25_000 - details.fees
+        );
+    }
+
+    #[test]
+    fn test_create_tx_skip_change_dust() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                49_800,
+            )]))
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
+        assert_eq!(psbt.global.unsigned_tx.output[0].value, 49_800);
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_create_tx_single_recipient_dust_amount() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        // very high fee rate, so that the only output would be below dust
+        wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet()
+                    .fee_rate(FeeRate::from_sat_per_vb(453.0)),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_ordering_respected() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![
+                    (addr.script_pubkey(), 30_000),
+                    (addr.script_pubkey(), 10_000),
+                ])
+                .ordering(super::tx_builder::TxOrdering::BIP69Lexicographic),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 3);
+        assert_eq!(
+            psbt.global.unsigned_tx.output[0].value,
+            10_000 - details.fees
+        );
+        assert_eq!(psbt.global.unsigned_tx.output[1].value, 10_000);
+        assert_eq!(psbt.global.unsigned_tx.output[2].value, 30_000);
+    }
+
+    #[test]
+    fn test_create_tx_default_sighash() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                30_000,
+            )]))
+            .unwrap();
+
+        assert_eq!(psbt.inputs[0].sighash_type, None);
+    }
+
+    #[test]
+    fn test_create_tx_custom_sighash() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 30_000)])
+                    .sighash(bitcoin::SigHashType::Single),
+            )
+            .unwrap();
+
+        assert_eq!(
+            psbt.inputs[0].sighash_type,
+            Some(bitcoin::SigHashType::Single)
+        );
+    }
+
+    #[test]
+    fn test_create_tx_input_hd_keypaths() {
+        use bitcoin::util::bip32::{DerivationPath, Fingerprint};
+        use std::str::FromStr;
+
+        let (wallet, _, _) = get_funded_wallet("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.inputs[0].hd_keypaths.len(), 1);
+        assert_eq!(
+            psbt.inputs[0].hd_keypaths.values().nth(0).unwrap(),
+            &(
+                Fingerprint::from_str("d34db33f").unwrap(),
+                DerivationPath::from_str("m/44'/0'/0'/0/0").unwrap()
+            )
+        );
+    }
+
+    #[test]
+    fn test_create_tx_output_hd_keypaths() {
+        use bitcoin::util::bip32::{DerivationPath, Fingerprint};
+        use std::str::FromStr;
+
+        let (wallet, descriptors, _) = get_funded_wallet("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)");
+        // cache some addresses
+        wallet.get_new_address().unwrap();
+
+        let addr = testutils!(@external descriptors, 5);
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.outputs[0].hd_keypaths.len(), 1);
+        assert_eq!(
+            psbt.outputs[0].hd_keypaths.values().nth(0).unwrap(),
+            &(
+                Fingerprint::from_str("d34db33f").unwrap(),
+                DerivationPath::from_str("m/44'/0'/0'/0/5").unwrap()
+            )
+        );
+    }
+
+    #[test]
+    fn test_create_tx_set_redeem_script_p2sh() {
+        use bitcoin::hashes::hex::FromHex;
+
+        let (wallet, _, _) =
+            get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        assert_eq!(
+            psbt.inputs[0].redeem_script,
+            Some(Script::from(
+                Vec::<u8>::from_hex(
+                    "21032b0558078bec38694a84933d659303e2575dae7e91685911454115bfd64487e3ac"
+                )
+                .unwrap()
+            ))
+        );
+        assert_eq!(psbt.inputs[0].witness_script, None);
+    }
+
+    #[test]
+    fn test_create_tx_set_witness_script_p2wsh() {
+        use bitcoin::hashes::hex::FromHex;
+
+        let (wallet, _, _) =
+            get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.inputs[0].redeem_script, None);
+        assert_eq!(
+            psbt.inputs[0].witness_script,
+            Some(Script::from(
+                Vec::<u8>::from_hex(
+                    "21032b0558078bec38694a84933d659303e2575dae7e91685911454115bfd64487e3ac"
+                )
+                .unwrap()
+            ))
+        );
+    }
+
+    #[test]
+    fn test_create_tx_set_redeem_witness_script_p2wsh_p2sh() {
+        use bitcoin::hashes::hex::FromHex;
+
+        let (wallet, _, _) =
+            get_funded_wallet("sh(wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)))");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        let script = Script::from(
+            Vec::<u8>::from_hex(
+                "21032b0558078bec38694a84933d659303e2575dae7e91685911454115bfd64487e3ac",
+            )
+            .unwrap(),
+        );
+
+        assert_eq!(psbt.inputs[0].redeem_script, Some(script.to_v0_p2wsh()));
+        assert_eq!(psbt.inputs[0].witness_script, Some(script));
+    }
+
+    #[test]
+    fn test_create_tx_non_witness_utxo() {
+        let (wallet, _, _) =
+            get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        assert!(psbt.inputs[0].non_witness_utxo.is_some());
+        assert!(psbt.inputs[0].witness_utxo.is_none());
+    }
+
+    #[test]
+    fn test_create_tx_only_witness_utxo() {
+        let (wallet, _, _) =
+            get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        assert!(psbt.inputs[0].non_witness_utxo.is_none());
+        assert!(psbt.inputs[0].witness_utxo.is_some());
+    }
+
+    #[test]
+    fn test_create_tx_shwpkh_has_witness_utxo() {
+        let (wallet, _, _) =
+            get_funded_wallet("sh(wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        assert!(psbt.inputs[0].non_witness_utxo.is_none());
+        assert!(psbt.inputs[0].witness_utxo.is_some());
+    }
+
+    #[test]
+    fn test_create_tx_both_non_witness_utxo_and_witness_utxo() {
+        let (wallet, _, _) =
+            get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet()
+                    .force_non_witness_utxo(),
+            )
+            .unwrap();
+
+        assert!(psbt.inputs[0].non_witness_utxo.is_some());
+        assert!(psbt.inputs[0].witness_utxo.is_some());
+    }
+
+    #[test]
+    fn test_create_tx_add_utxo() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        let small_output_txid = wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 30_000)]).add_utxo(
+                    OutPoint {
+                        txid: small_output_txid,
+                        vout: 0,
+                    },
+                ),
+            )
+            .unwrap();
+
+        assert_eq!(
+            psbt.global.unsigned_tx.input.len(),
+            2,
+            "should add an additional input since 25_000 < 30_000"
+        );
+        assert_eq!(details.sent, 75_000, "total should be sum of both inputs");
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_create_tx_manually_selected_insufficient() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        let small_output_txid = wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 30_000)])
+                    .add_utxo(OutPoint {
+                        txid: small_output_txid,
+                        vout: 0,
+                    })
+                    .manually_selected_only(),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "SpendingPolicyRequired(External)")]
+    fn test_create_tx_policy_path_required() {
+        let (wallet, _, _) = get_funded_wallet(get_test_a_or_b_plus_csv());
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                30_000,
+            )]))
+            .unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_policy_path_no_csv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_a_or_b_plus_csv());
+
+        let external_policy = wallet.policies(KeychainKind::External).unwrap().unwrap();
+        let root_id = external_policy.id;
+        // child #0 is just the key "A"
+        let path = vec![(root_id, vec![0])].into_iter().collect();
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 30_000)])
+                    .policy_path(path, KeychainKind::External),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 0xFFFFFFFF);
+    }
+
+    #[test]
+    fn test_create_tx_policy_path_use_csv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_a_or_b_plus_csv());
+
+        let external_policy = wallet.policies(KeychainKind::External).unwrap().unwrap();
+        let root_id = external_policy.id;
+        // child #1 is or(pk(B),older(144))
+        let path = vec![(root_id, vec![1])].into_iter().collect();
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 30_000)])
+                    .policy_path(path, KeychainKind::External),
+            )
+            .unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 144);
+    }
+
+    #[test]
+    fn test_create_tx_global_xpubs_with_origin() {
+        use bitcoin::hashes::hex::FromHex;
+        use bitcoin::util::base58;
+        use bitcoin::util::psbt::raw::Key;
+
+        let (wallet, _, _) = get_funded_wallet("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).add_global_xpubs(),
+            )
+            .unwrap();
+
+        let type_value = 0x01;
+        let key = base58::from_check("tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3").unwrap();
+
+        let psbt_key = Key { type_value, key };
+
+        // This key has an explicit origin, so it will be encoded here
+        let value_bytes = Vec::<u8>::from_hex("73756c7f30000080000000800000008002000080").unwrap();
+
+        assert_eq!(psbt.global.unknown.len(), 1);
+        assert_eq!(psbt.global.unknown.get(&psbt_key), Some(&value_bytes));
+    }
+
+    #[test]
+    #[should_panic(
+        expected = "MissingKeyOrigin(\"tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3\")"
+    )]
+    fn test_create_tx_global_xpubs_origin_missing() {
+        let (wallet, _, _) = get_funded_wallet("wpkh(tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)");
+        let addr = wallet.get_new_address().unwrap();
+        wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).add_global_xpubs(),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_global_xpubs_master_without_origin() {
+        use bitcoin::hashes::hex::FromHex;
+        use bitcoin::util::base58;
+        use bitcoin::util::psbt::raw::Key;
+
+        let (wallet, _, _) = get_funded_wallet("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).add_global_xpubs(),
+            )
+            .unwrap();
+
+        let type_value = 0x01;
+        let key = base58::from_check("tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL").unwrap();
+
+        let psbt_key = Key { type_value, key };
+
+        // This key doesn't have an explicit origin, but it's a master key (depth = 0). So we encode
+        // its fingerprint directly and an empty path
+        let value_bytes = Vec::<u8>::from_hex("997a323b").unwrap();
+
+        assert_eq!(psbt.global.unknown.len(), 1);
+        assert_eq!(psbt.global.unknown.get(&psbt_key), Some(&value_bytes));
+    }
+
+    #[test]
+    #[should_panic(expected = "IrreplaceableTransaction")]
+    fn test_bump_fee_irreplaceable_tx() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, mut details) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                25_000,
+            )]))
+            .unwrap();
+        let tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the utxos, we know they can't be used anyways
+        details.transaction = Some(tx);
+        wallet.database.borrow_mut().set_tx(&details).unwrap();
+
+        wallet.bump_fee(&txid, TxBuilder::new()).unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "TransactionConfirmed")]
+    fn test_bump_fee_confirmed_tx() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, mut details) = wallet
+            .create_tx(TxBuilder::with_recipients(vec![(
+                addr.script_pubkey(),
+                25_000,
+            )]))
+            .unwrap();
+        let tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the utxos, we know they can't be used anyways
+        details.transaction = Some(tx);
+        details.height = Some(42);
+        wallet.database.borrow_mut().set_tx(&details).unwrap();
+
+        wallet.bump_fee(&txid, TxBuilder::new()).unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "FeeRateTooLow")]
+    fn test_bump_fee_low_fee_rate() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, mut details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the utxos, we know they can't be used anyways
+        details.transaction = Some(tx);
+        wallet.database.borrow_mut().set_tx(&details).unwrap();
+
+        wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(1.0)),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "FeeTooLow")]
+    fn test_bump_fee_low_abs() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, mut details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the utxos, we know they can't be used anyways
+        details.transaction = Some(tx);
+        wallet.database.borrow_mut().set_tx(&details).unwrap();
+
+        wallet
+            .bump_fee(&txid, TxBuilder::new().fee_absolute(10))
+            .unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "FeeTooLow")]
+    fn test_bump_fee_zero_abs() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, mut details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the utxos, we know they can't be used anyways
+        details.transaction = Some(tx);
+        wallet.database.borrow_mut().set_tx(&details).unwrap();
+
+        wallet
+            .bump_fee(&txid, TxBuilder::new().fee_absolute(0))
+            .unwrap();
+    }
+
+    #[test]
+    fn test_bump_fee_reduce_change() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the new utxos, we know they can't be used anyways
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        let (psbt, details) = wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(2.5)),
+            )
+            .unwrap();
+
+        assert_eq!(details.sent, original_details.sent);
+        assert_eq!(
+            details.received + details.fees,
+            original_details.received + original_details.fees
+        );
+        assert!(details.fees > original_details.fees);
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.output.len(), 2);
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey == addr.script_pubkey())
+                .unwrap()
+                .value,
+            25_000
+        );
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey != addr.script_pubkey())
+                .unwrap()
+                .value,
+            details.received
+        );
+
+        assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(2.5), @add_signature);
+    }
+
+    #[test]
+    fn test_bump_fee_absolute_reduce_change() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 25_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the new utxos, we know they can't be used anyways
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        let (psbt, details) = wallet
+            .bump_fee(&txid, TxBuilder::new().fee_absolute(200))
+            .unwrap();
+
+        assert_eq!(details.sent, original_details.sent);
+        assert_eq!(
+            details.received + details.fees,
+            original_details.received + original_details.fees
+        );
+        assert!(
+            details.fees > original_details.fees,
+            "{} > {}",
+            details.fees,
+            original_details.fees
+        );
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.output.len(), 2);
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey == addr.script_pubkey())
+                .unwrap()
+                .value,
+            25_000
+        );
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey != addr.script_pubkey())
+                .unwrap()
+                .value,
+            details.received
+        );
+
+        assert_eq!(details.fees, 200);
+    }
+
+    #[test]
+    fn test_bump_fee_reduce_single_recipient() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet()
+                    .enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        let (psbt, details) = wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new()
+                    .maintain_single_recipient()
+                    .fee_rate(FeeRate::from_sat_per_vb(2.5)),
+            )
+            .unwrap();
+
+        assert_eq!(details.sent, original_details.sent);
+        assert!(details.fees > original_details.fees);
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.output.len(), 1);
+        assert_eq!(tx.output[0].value + details.fees, details.sent);
+
+        assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(2.5), @add_signature);
+    }
+
+    #[test]
+    fn test_bump_fee_absolute_reduce_single_recipient() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet()
+                    .enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        let (psbt, details) = wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new()
+                    .maintain_single_recipient()
+                    .fee_absolute(300),
+            )
+            .unwrap();
+
+        assert_eq!(details.sent, original_details.sent);
+        assert!(details.fees > original_details.fees);
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.output.len(), 1);
+        assert_eq!(tx.output[0].value + details.fees, details.sent);
+
+        assert_eq!(details.fees, 300);
+    }
+
+    #[test]
+    fn test_bump_fee_drain_wallet() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        // receive an extra tx so that our wallet has two utxos.
+        let incoming_txid = wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+        let outpoint = OutPoint {
+            txid: incoming_txid,
+            vout: 0,
+        };
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .utxos(vec![outpoint])
+                    .manually_selected_only()
+                    .enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+        assert_eq!(original_details.sent, 25_000);
+
+        // for the new feerate, it should be enough to reduce the output, but since we specify
+        // `drain_wallet` we expect to spend everything
+        let (_, details) = wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new()
+                    .drain_wallet()
+                    .maintain_single_recipient()
+                    .fee_rate(FeeRate::from_sat_per_vb(5.0)),
+            )
+            .unwrap();
+        assert_eq!(details.sent, 75_000);
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_bump_fee_remove_output_manually_selected_only() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        // receive an extra tx so that our wallet has two utxos. then we manually pick only one of
+        // them, and make sure that `bump_fee` doesn't try to add more. eventually, it should fail
+        // because the fee rate is too high and the single utxo isn't enough to create a non-dust
+        // output
+        let incoming_txid = wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+        let outpoint = OutPoint {
+            txid: incoming_txid,
+            vout: 0,
+        };
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .utxos(vec![outpoint])
+                    .manually_selected_only()
+                    .enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+        assert_eq!(original_details.sent, 25_000);
+
+        wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new()
+                    .utxos(vec![outpoint])
+                    .manually_selected_only()
+                    .fee_rate(FeeRate::from_sat_per_vb(225.0)),
+            )
+            .unwrap();
+    }
+
+    #[test]
+    fn test_bump_fee_add_input() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 45_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the new utxos, we know they can't be used anyways
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        let (psbt, details) = wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(50.0)),
+            )
+            .unwrap();
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fees + details.received, 30_000);
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.input.len(), 2);
+        assert_eq!(tx.output.len(), 2);
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey == addr.script_pubkey())
+                .unwrap()
+                .value,
+            45_000
+        );
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey != addr.script_pubkey())
+                .unwrap()
+                .value,
+            details.received
+        );
+
+        assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(50.0), @add_signature);
+    }
+
+    #[test]
+    fn test_bump_fee_absolute_add_input() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 45_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the new utxos, we know they can't be used anyways
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        let (psbt, details) = wallet
+            .bump_fee(&txid, TxBuilder::new().fee_absolute(6_000))
+            .unwrap();
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fees + details.received, 30_000);
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.input.len(), 2);
+        assert_eq!(tx.output.len(), 2);
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey == addr.script_pubkey())
+                .unwrap()
+                .value,
+            45_000
+        );
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey != addr.script_pubkey())
+                .unwrap()
+                .value,
+            details.received
+        );
+
+        assert_eq!(details.fees, 6_000);
+    }
+
+    #[test]
+    fn test_bump_fee_no_change_add_input_and_change() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        let incoming_txid = wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        // initially make a tx without change by using `set_single_recipient`
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .add_utxo(OutPoint {
+                        txid: incoming_txid,
+                        vout: 0,
+                    })
+                    .manually_selected_only()
+                    .enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the new utxos, we know they can't be used anyways
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        // now bump the fees without using `maintain_single_recipient`. the wallet should add an
+        // extra input and a change output, and leave the original output untouched
+        let (psbt, details) = wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(50.0)),
+            )
+            .unwrap();
+
+        let original_send_all_amount = original_details.sent - original_details.fees;
+        assert_eq!(details.sent, original_details.sent + 50_000);
+        assert_eq!(
+            details.received,
+            75_000 - original_send_all_amount - details.fees
+        );
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.input.len(), 2);
+        assert_eq!(tx.output.len(), 2);
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey == addr.script_pubkey())
+                .unwrap()
+                .value,
+            original_send_all_amount
+        );
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey != addr.script_pubkey())
+                .unwrap()
+                .value,
+            75_000 - original_send_all_amount - details.fees
+        );
+
+        assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(50.0), @add_signature);
+    }
+
+    #[test]
+    fn test_bump_fee_add_input_change_dust() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 45_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        assert_eq!(tx.input.len(), 1);
+        assert_eq!(tx.output.len(), 2);
+        let txid = tx.txid();
+        // skip saving the new utxos, we know they can't be used anyways
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        let (psbt, details) = wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new().fee_rate(FeeRate::from_sat_per_vb(140.0)),
+            )
+            .unwrap();
+
+        assert_eq!(original_details.received, 5_000 - original_details.fees);
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fees, 30_000);
+        assert_eq!(details.received, 0);
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.input.len(), 2);
+        assert_eq!(tx.output.len(), 1);
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey == addr.script_pubkey())
+                .unwrap()
+                .value,
+            45_000
+        );
+
+        assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(140.0), @dust_change, @add_signature);
+    }
+
+    #[test]
+    fn test_bump_fee_force_add_input() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        let incoming_txid = wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 45_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the new utxos, we know they can't be used anyways
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        // the new fee_rate is low enough that just reducing the change would be fine, but we force
+        // the addition of an extra input with `add_utxo()`
+        let (psbt, details) = wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new()
+                    .add_utxo(OutPoint {
+                        txid: incoming_txid,
+                        vout: 0,
+                    })
+                    .fee_rate(FeeRate::from_sat_per_vb(5.0)),
+            )
+            .unwrap();
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fees + details.received, 30_000);
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.input.len(), 2);
+        assert_eq!(tx.output.len(), 2);
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey == addr.script_pubkey())
+                .unwrap()
+                .value,
+            45_000
+        );
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey != addr.script_pubkey())
+                .unwrap()
+                .value,
+            details.received
+        );
+
+        assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(5.0), @add_signature);
+    }
+
+    #[test]
+    fn test_bump_fee_absolute_force_add_input() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        let incoming_txid = wallet.database.borrow_mut().received_tx(
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, mut original_details) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 45_000)]).enable_rbf(),
+            )
+            .unwrap();
+        let mut tx = psbt.extract_tx();
+        let txid = tx.txid();
+        // skip saving the new utxos, we know they can't be used anyways
+        for txin in &mut tx.input {
+            txin.witness.push([0x00; 108].to_vec()); // fake signature
+            wallet
+                .database
+                .borrow_mut()
+                .del_utxo(&txin.previous_output)
+                .unwrap();
+        }
+        original_details.transaction = Some(tx);
+        wallet
+            .database
+            .borrow_mut()
+            .set_tx(&original_details)
+            .unwrap();
+
+        // the new fee_rate is low enough that just reducing the change would be fine, but we force
+        // the addition of an extra input with `add_utxo()`
+        let (psbt, details) = wallet
+            .bump_fee(
+                &txid,
+                TxBuilder::new()
+                    .add_utxo(OutPoint {
+                        txid: incoming_txid,
+                        vout: 0,
+                    })
+                    .fee_absolute(250),
+            )
+            .unwrap();
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fees + details.received, 30_000);
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.input.len(), 2);
+        assert_eq!(tx.output.len(), 2);
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey == addr.script_pubkey())
+                .unwrap()
+                .value,
+            45_000
+        );
+        assert_eq!(
+            tx.output
+                .iter()
+                .find(|txout| txout.script_pubkey != addr.script_pubkey())
+                .unwrap()
+                .value,
+            details.received
+        );
+
+        assert_eq!(details.fees, 250);
+    }
+
+    #[test]
+    fn test_sign_single_xprv() {
+        let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap();
+        assert_eq!(finalized, true);
+
+        let extracted = signed_psbt.extract_tx();
+        assert_eq!(extracted.input[0].witness.len(), 2);
+    }
+
+    #[test]
+    fn test_sign_single_xprv_bip44_path() {
+        let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/44'/0'/0'/0/*)");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap();
+        assert_eq!(finalized, true);
+
+        let extracted = signed_psbt.extract_tx();
+        assert_eq!(extracted.input[0].witness.len(), 2);
+    }
+
+    #[test]
+    fn test_sign_single_xprv_sh_wpkh() {
+        let (wallet, _, _) = get_funded_wallet("sh(wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*))");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap();
+        assert_eq!(finalized, true);
+
+        let extracted = signed_psbt.extract_tx();
+        assert_eq!(extracted.input[0].witness.len(), 2);
+    }
+
+    #[test]
+    fn test_sign_single_wif() {
+        let (wallet, _, _) =
+            get_funded_wallet("wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)");
+        let addr = wallet.get_new_address().unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap();
+        assert_eq!(finalized, true);
+
+        let extracted = signed_psbt.extract_tx();
+        assert_eq!(extracted.input[0].witness.len(), 2);
+    }
+
+    #[test]
+    fn test_sign_single_xprv_no_hd_keypaths() {
+        let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)");
+        let addr = wallet.get_new_address().unwrap();
+        let (mut psbt, _) = wallet
+            .create_tx(
+                TxBuilder::new()
+                    .set_single_recipient(addr.script_pubkey())
+                    .drain_wallet(),
+            )
+            .unwrap();
+
+        psbt.inputs[0].hd_keypaths.clear();
+        assert_eq!(psbt.inputs[0].hd_keypaths.len(), 0);
+
+        let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap();
+        assert_eq!(finalized, true);
+
+        let extracted = signed_psbt.extract_tx();
+        assert_eq!(extracted.input[0].witness.len(), 2);
+    }
+
+    #[test]
+    fn test_include_output_redeem_witness_script() {
+        let (wallet, _, _) = get_funded_wallet("sh(wsh(multi(1,cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW,cRjo6jqfVNP33HhSS76UhXETZsGTZYx8FMFvR9kpbtCSV1PmdZdu)))");
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 45_000)])
+                    .include_output_redeem_witness_script(),
+            )
+            .unwrap();
+
+        // p2sh-p2wsh transaction should contain both witness and redeem scripts
+        assert!(psbt
+            .outputs
+            .iter()
+            .any(|output| output.redeem_script.is_some() && output.witness_script.is_some()));
+    }
+
+    #[test]
+    fn test_signing_only_one_of_multiple_inputs() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let (mut psbt, _) = wallet
+            .create_tx(
+                TxBuilder::with_recipients(vec![(addr.script_pubkey(), 45_000)])
+                    .include_output_redeem_witness_script(),
+            )
+            .unwrap();
+
+        // add another input to the psbt that is at least passable.
+        let mut dud_input = bitcoin::util::psbt::Input::default();
+        dud_input.witness_utxo = Some(TxOut {
+            value: 100_000,
+            script_pubkey: miniscript::Descriptor::<bitcoin::PublicKey>::from_str(
+                "wpkh(025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357)",
+            )
+            .unwrap()
+            .script_pubkey(miniscript::NullCtx),
+        });
+        psbt.inputs.push(dud_input);
+        psbt.global.unsigned_tx.input.push(bitcoin::TxIn::default());
+        let (psbt, is_final) = wallet.sign(psbt, None).unwrap();
+        assert!(
+            !is_final,
+            "shouldn't be final since we can't sign one of the inputs"
+        );
+        assert!(
+            psbt.inputs[0].final_script_witness.is_some(),
+            "should finalized input it signed"
+        )
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/signer.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/signer.rs.html new file mode 100644 index 0000000000..76c505864f --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/signer.rs.html @@ -0,0 +1,1358 @@ +signer.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Generalized signers
+//!
+//! This module provides the ability to add customized signers to a [`Wallet`](super::Wallet)
+//! through the [`Wallet::add_signer`](super::Wallet::add_signer) function.
+//!
+//! ```
+//! # use std::sync::Arc;
+//! # use std::str::FromStr;
+//! # use bitcoin::secp256k1::{Secp256k1, All};
+//! # use bitcoin::*;
+//! # use bitcoin::util::psbt;
+//! # use bitcoin::util::bip32::Fingerprint;
+//! # use bdk::signer::*;
+//! # use bdk::database::*;
+//! # use bdk::*;
+//! # #[derive(Debug)]
+//! # struct CustomHSM;
+//! # impl CustomHSM {
+//! #     fn sign_input(&self, _psbt: &mut psbt::PartiallySignedTransaction, _input: usize) -> Result<(), SignerError> {
+//! #         Ok(())
+//! #     }
+//! #     fn connect() -> Self {
+//! #         CustomHSM
+//! #     }
+//! # }
+//! #[derive(Debug)]
+//! struct CustomSigner {
+//!     device: CustomHSM,
+//! }
+//!
+//! impl CustomSigner {
+//!     fn connect() -> Self {
+//!         CustomSigner { device: CustomHSM::connect() }
+//!     }
+//! }
+//!
+//! impl Signer for CustomSigner {
+//!     fn sign(
+//!         &self,
+//!         psbt: &mut psbt::PartiallySignedTransaction,
+//!         input_index: Option<usize>,
+//!         _secp: &Secp256k1<All>,
+//!     ) -> Result<(), SignerError> {
+//!         let input_index = input_index.ok_or(SignerError::InputIndexOutOfRange)?;
+//!         self.device.sign_input(psbt, input_index)?;
+//!
+//!         Ok(())
+//!     }
+//!
+//!     fn sign_whole_tx(&self) -> bool {
+//!         false
+//!     }
+//! }
+//!
+//! let custom_signer = CustomSigner::connect();
+//!
+//! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+//! let mut wallet: OfflineWallet<_> = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+//! wallet.add_signer(
+//!     KeychainKind::External,
+//!     Fingerprint::from_str("e30f11b8").unwrap().into(),
+//!     SignerOrdering(200),
+//!     Arc::new(custom_signer)
+//! );
+//!
+//! # Ok::<_, bdk::Error>(())
+//! ```
+
+use std::cmp::Ordering;
+use std::collections::BTreeMap;
+use std::fmt;
+use std::ops::Bound::Included;
+use std::sync::Arc;
+
+use bitcoin::blockdata::opcodes;
+use bitcoin::blockdata::script::Builder as ScriptBuilder;
+use bitcoin::hashes::{hash160, Hash};
+use bitcoin::secp256k1::{Message, Secp256k1};
+use bitcoin::util::bip32::{ExtendedPrivKey, Fingerprint};
+use bitcoin::util::{bip143, psbt};
+use bitcoin::{PrivateKey, Script, SigHash, SigHashType};
+
+use miniscript::descriptor::{DescriptorSecretKey, DescriptorSinglePriv, DescriptorXKey, KeyMap};
+use miniscript::{Legacy, MiniscriptKey, Segwitv0};
+
+use super::utils::SecpCtx;
+use crate::descriptor::XKeyUtils;
+
+/// Identifier of a signer in the `SignersContainers`. Used as a key to find the right signer among
+/// multiple of them
+#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq, Hash)]
+pub enum SignerId {
+    /// Bitcoin HASH160 (RIPEMD160 after SHA256) hash of an ECDSA public key
+    PkHash(hash160::Hash),
+    /// The fingerprint of a BIP32 extended key
+    Fingerprint(Fingerprint),
+}
+
+impl From<hash160::Hash> for SignerId {
+    fn from(hash: hash160::Hash) -> SignerId {
+        SignerId::PkHash(hash)
+    }
+}
+
+impl From<Fingerprint> for SignerId {
+    fn from(fing: Fingerprint) -> SignerId {
+        SignerId::Fingerprint(fing)
+    }
+}
+
+/// Signing error
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub enum SignerError {
+    /// The private key is missing for the required public key
+    MissingKey,
+    /// The private key in use has the right fingerprint but derives differently than expected
+    InvalidKey,
+    /// The user canceled the operation
+    UserCanceled,
+    /// Input index is out of range
+    InputIndexOutOfRange,
+    /// The `non_witness_utxo` field of the transaction is required to sign this input
+    MissingNonWitnessUtxo,
+    /// The `non_witness_utxo` specified is invalid
+    InvalidNonWitnessUtxo,
+    /// The `witness_utxo` field of the transaction is required to sign this input
+    MissingWitnessUtxo,
+    /// The `witness_script` field of the transaction is requied to sign this input
+    MissingWitnessScript,
+    /// The fingerprint and derivation path are missing from the psbt input
+    MissingHDKeypath,
+}
+
+impl fmt::Display for SignerError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self)
+    }
+}
+
+impl std::error::Error for SignerError {}
+
+/// Trait for signers
+///
+/// This trait can be implemented to provide customized signers to the wallet. For an example see
+/// [`this module`](crate::wallet::signer)'s documentation.
+pub trait Signer: fmt::Debug + Send + Sync {
+    /// Sign a PSBT
+    ///
+    /// The `input_index` argument is only provided if the wallet doesn't declare to sign the whole
+    /// transaction in one go (see [`Signer::sign_whole_tx`]). Otherwise its value is `None` and
+    /// can be ignored.
+    fn sign(
+        &self,
+        psbt: &mut psbt::PartiallySignedTransaction,
+        input_index: Option<usize>,
+        secp: &SecpCtx,
+    ) -> Result<(), SignerError>;
+
+    /// Return whether or not the signer signs the whole transaction in one go instead of every
+    /// input individually
+    fn sign_whole_tx(&self) -> bool;
+
+    /// Return the secret key for the signer
+    ///
+    /// This is used internally to reconstruct the original descriptor that may contain secrets.
+    /// External signers that are meant to keep key isolated should just return `None` here (which
+    /// is the default for this method, if not overridden).
+    fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
+        None
+    }
+}
+
+impl Signer for DescriptorXKey<ExtendedPrivKey> {
+    fn sign(
+        &self,
+        psbt: &mut psbt::PartiallySignedTransaction,
+        input_index: Option<usize>,
+        secp: &SecpCtx,
+    ) -> Result<(), SignerError> {
+        let input_index = input_index.unwrap();
+        if input_index >= psbt.inputs.len() {
+            return Err(SignerError::InputIndexOutOfRange);
+        }
+
+        let (public_key, deriv_path) = match psbt.inputs[input_index]
+            .hd_keypaths
+            .iter()
+            .filter_map(|(pk, &(fingerprint, ref path))| {
+                if self.matches(&(fingerprint, path.clone()), &secp).is_some() {
+                    Some((pk, path))
+                } else {
+                    None
+                }
+            })
+            .next()
+        {
+            Some((pk, full_path)) => (pk, full_path.clone()),
+            None => return Ok(()),
+        };
+
+        let derived_key = self.xkey.derive_priv(&secp, &deriv_path).unwrap();
+        if &derived_key.private_key.public_key(&secp) != public_key {
+            Err(SignerError::InvalidKey)
+        } else {
+            derived_key.private_key.sign(psbt, Some(input_index), secp)
+        }
+    }
+
+    fn sign_whole_tx(&self) -> bool {
+        false
+    }
+
+    fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
+        Some(DescriptorSecretKey::XPrv(self.clone()))
+    }
+}
+
+impl Signer for PrivateKey {
+    fn sign(
+        &self,
+        psbt: &mut psbt::PartiallySignedTransaction,
+        input_index: Option<usize>,
+        secp: &SecpCtx,
+    ) -> Result<(), SignerError> {
+        let input_index = input_index.unwrap();
+        if input_index >= psbt.inputs.len() {
+            return Err(SignerError::InputIndexOutOfRange);
+        }
+
+        let pubkey = self.public_key(&secp);
+        if psbt.inputs[input_index].partial_sigs.contains_key(&pubkey) {
+            return Ok(());
+        }
+
+        // FIXME: use the presence of `witness_utxo` as an indication that we should make a bip143
+        // sig. Does this make sense? Should we add an extra argument to explicitly swith between
+        // these? The original idea was to declare sign() as sign<Ctx: ScriptContex>() and use Ctx,
+        // but that violates the rules for trait-objects, so we can't do it.
+        let (hash, sighash) = match psbt.inputs[input_index].witness_utxo {
+            Some(_) => Segwitv0::sighash(psbt, input_index)?,
+            None => Legacy::sighash(psbt, input_index)?,
+        };
+
+        let signature = secp.sign(
+            &Message::from_slice(&hash.into_inner()[..]).unwrap(),
+            &self.key,
+        );
+
+        let mut final_signature = Vec::with_capacity(75);
+        final_signature.extend_from_slice(&signature.serialize_der());
+        final_signature.push(sighash.as_u32() as u8);
+
+        psbt.inputs[input_index]
+            .partial_sigs
+            .insert(pubkey, final_signature);
+
+        Ok(())
+    }
+
+    fn sign_whole_tx(&self) -> bool {
+        false
+    }
+
+    fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> {
+        Some(DescriptorSecretKey::SinglePriv(DescriptorSinglePriv {
+            key: *self,
+            origin: None,
+        }))
+    }
+}
+
+/// Defines the order in which signers are called
+///
+/// The default value is `100`. Signers with an ordering above that will be called later,
+/// and they will thus see the partial signatures added to the transaction once they get to sign
+/// themselves.
+#[derive(Debug, Clone, PartialOrd, PartialEq, Ord, Eq)]
+pub struct SignerOrdering(pub usize);
+
+impl std::default::Default for SignerOrdering {
+    fn default() -> Self {
+        SignerOrdering(100)
+    }
+}
+
+#[derive(Debug, Clone)]
+struct SignersContainerKey {
+    id: SignerId,
+    ordering: SignerOrdering,
+}
+
+impl From<(SignerId, SignerOrdering)> for SignersContainerKey {
+    fn from(tuple: (SignerId, SignerOrdering)) -> Self {
+        SignersContainerKey {
+            id: tuple.0,
+            ordering: tuple.1,
+        }
+    }
+}
+
+/// Container for multiple signers
+#[derive(Debug, Default, Clone)]
+pub struct SignersContainer(BTreeMap<SignersContainerKey, Arc<dyn Signer>>);
+
+impl SignersContainer {
+    /// Create a map of public keys to secret keys
+    pub fn as_key_map(&self, secp: &SecpCtx) -> KeyMap {
+        self.0
+            .values()
+            .filter_map(|signer| signer.descriptor_secret_key())
+            .filter_map(|secret| secret.as_public(secp).ok().map(|public| (public, secret)))
+            .collect()
+    }
+}
+
+impl From<KeyMap> for SignersContainer {
+    fn from(keymap: KeyMap) -> SignersContainer {
+        let secp = Secp256k1::new();
+        let mut container = SignersContainer::new();
+
+        for (_, secret) in keymap {
+            match secret {
+                DescriptorSecretKey::SinglePriv(private_key) => container.add_external(
+                    SignerId::from(
+                        private_key
+                            .key
+                            .public_key(&Secp256k1::signing_only())
+                            .to_pubkeyhash(),
+                    ),
+                    SignerOrdering::default(),
+                    Arc::new(private_key.key),
+                ),
+                DescriptorSecretKey::XPrv(xprv) => container.add_external(
+                    SignerId::from(xprv.root_fingerprint(&secp)),
+                    SignerOrdering::default(),
+                    Arc::new(xprv),
+                ),
+            };
+        }
+
+        container
+    }
+}
+
+impl SignersContainer {
+    /// Default constructor
+    pub fn new() -> Self {
+        SignersContainer(Default::default())
+    }
+
+    /// Adds an external signer to the container for the specified id. Optionally returns the
+    /// signer that was previously in the container, if any
+    pub fn add_external(
+        &mut self,
+        id: SignerId,
+        ordering: SignerOrdering,
+        signer: Arc<dyn Signer>,
+    ) -> Option<Arc<dyn Signer>> {
+        self.0.insert((id, ordering).into(), signer)
+    }
+
+    /// Removes a signer from the container and returns it
+    pub fn remove(&mut self, id: SignerId, ordering: SignerOrdering) -> Option<Arc<dyn Signer>> {
+        self.0.remove(&(id, ordering).into())
+    }
+
+    /// Returns the list of identifiers of all the signers in the container
+    pub fn ids(&self) -> Vec<&SignerId> {
+        self.0
+            .keys()
+            .map(|SignersContainerKey { id, .. }| id)
+            .collect()
+    }
+
+    /// Returns the list of signers in the container, sorted by lowest to highest `ordering`
+    pub fn signers(&self) -> Vec<&Arc<dyn Signer>> {
+        self.0.values().collect()
+    }
+
+    /// Finds the signer with lowest ordering for a given id in the container.
+    pub fn find(&self, id: SignerId) -> Option<&Arc<dyn Signer>> {
+        self.0
+            .range((
+                Included(&(id.clone(), SignerOrdering(0)).into()),
+                Included(&(id.clone(), SignerOrdering(usize::MAX)).into()),
+            ))
+            .filter(|(k, _)| k.id == id)
+            .map(|(_, v)| v)
+            .next()
+    }
+}
+
+pub(crate) trait ComputeSighash {
+    fn sighash(
+        psbt: &psbt::PartiallySignedTransaction,
+        input_index: usize,
+    ) -> Result<(SigHash, SigHashType), SignerError>;
+}
+
+impl ComputeSighash for Legacy {
+    fn sighash(
+        psbt: &psbt::PartiallySignedTransaction,
+        input_index: usize,
+    ) -> Result<(SigHash, SigHashType), SignerError> {
+        if input_index >= psbt.inputs.len() {
+            return Err(SignerError::InputIndexOutOfRange);
+        }
+
+        let psbt_input = &psbt.inputs[input_index];
+        let tx_input = &psbt.global.unsigned_tx.input[input_index];
+
+        let sighash = psbt_input.sighash_type.unwrap_or(SigHashType::All);
+        let script = match psbt_input.redeem_script {
+            Some(ref redeem_script) => redeem_script.clone(),
+            None => {
+                let non_witness_utxo = psbt_input
+                    .non_witness_utxo
+                    .as_ref()
+                    .ok_or(SignerError::MissingNonWitnessUtxo)?;
+                let prev_out = non_witness_utxo
+                    .output
+                    .get(tx_input.previous_output.vout as usize)
+                    .ok_or(SignerError::InvalidNonWitnessUtxo)?;
+
+                prev_out.script_pubkey.clone()
+            }
+        };
+
+        Ok((
+            psbt.global
+                .unsigned_tx
+                .signature_hash(input_index, &script, sighash.as_u32()),
+            sighash,
+        ))
+    }
+}
+
+fn p2wpkh_script_code(script: &Script) -> Script {
+    ScriptBuilder::new()
+        .push_opcode(opcodes::all::OP_DUP)
+        .push_opcode(opcodes::all::OP_HASH160)
+        .push_slice(&script[2..])
+        .push_opcode(opcodes::all::OP_EQUALVERIFY)
+        .push_opcode(opcodes::all::OP_CHECKSIG)
+        .into_script()
+}
+
+impl ComputeSighash for Segwitv0 {
+    fn sighash(
+        psbt: &psbt::PartiallySignedTransaction,
+        input_index: usize,
+    ) -> Result<(SigHash, SigHashType), SignerError> {
+        if input_index >= psbt.inputs.len() {
+            return Err(SignerError::InputIndexOutOfRange);
+        }
+
+        let psbt_input = &psbt.inputs[input_index];
+
+        let sighash = psbt_input.sighash_type.unwrap_or(SigHashType::All);
+
+        let witness_utxo = psbt_input
+            .witness_utxo
+            .as_ref()
+            .ok_or(SignerError::MissingNonWitnessUtxo)?;
+        let value = witness_utxo.value;
+
+        let script = match psbt_input.witness_script {
+            Some(ref witness_script) => witness_script.clone(),
+            None => {
+                if witness_utxo.script_pubkey.is_v0_p2wpkh() {
+                    p2wpkh_script_code(&witness_utxo.script_pubkey)
+                } else if psbt_input
+                    .redeem_script
+                    .as_ref()
+                    .map(Script::is_v0_p2wpkh)
+                    .unwrap_or(false)
+                {
+                    p2wpkh_script_code(&psbt_input.redeem_script.as_ref().unwrap())
+                } else {
+                    return Err(SignerError::MissingWitnessScript);
+                }
+            }
+        };
+
+        Ok((
+            bip143::SigHashCache::new(&psbt.global.unsigned_tx).signature_hash(
+                input_index,
+                &script,
+                value,
+                sighash,
+            ),
+            sighash,
+        ))
+    }
+}
+
+impl PartialOrd for SignersContainerKey {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for SignersContainerKey {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.ordering
+            .cmp(&other.ordering)
+            .then(self.id.cmp(&other.id))
+    }
+}
+
+impl PartialEq for SignersContainerKey {
+    fn eq(&self, other: &Self) -> bool {
+        self.id == other.id && self.ordering == other.ordering
+    }
+}
+
+impl Eq for SignersContainerKey {}
+
+#[cfg(test)]
+mod signers_container_tests {
+    use super::*;
+    use crate::descriptor;
+    use crate::descriptor::ToWalletDescriptor;
+    use crate::keys::{DescriptorKey, ToDescriptorKey};
+    use bitcoin::secp256k1::All;
+    use bitcoin::util::bip32;
+    use bitcoin::util::psbt::PartiallySignedTransaction;
+    use bitcoin::Network;
+    use miniscript::ScriptContext;
+    use std::str::FromStr;
+
+    // Signers added with the same ordering (like `Ordering::default`) created from `KeyMap`
+    // should be preserved and not overwritten.
+    // This happens usually when a set of signers is created from a descriptor with private keys.
+    #[test]
+    fn signers_with_same_ordering() {
+        let (prvkey1, _, _) = setup_keys(TPRV0_STR);
+        let (prvkey2, _, _) = setup_keys(TPRV1_STR);
+        let desc = descriptor!(sh(multi 2, prvkey1, prvkey2)).unwrap();
+        let (_, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
+
+        let signers = SignersContainer::from(keymap);
+        assert_eq!(signers.ids().len(), 2);
+
+        let signers = signers.signers();
+        assert_eq!(signers.len(), 2);
+    }
+
+    #[test]
+    fn signers_sorted_by_ordering() {
+        let mut signers = SignersContainer::new();
+        let signer1 = Arc::new(DummySigner);
+        let signer2 = Arc::new(DummySigner);
+        let signer3 = Arc::new(DummySigner);
+
+        signers.add_external(
+            SignerId::Fingerprint(b"cafe"[..].into()),
+            SignerOrdering(1),
+            signer1.clone(),
+        );
+        signers.add_external(
+            SignerId::Fingerprint(b"babe"[..].into()),
+            SignerOrdering(2),
+            signer2.clone(),
+        );
+        signers.add_external(
+            SignerId::Fingerprint(b"feed"[..].into()),
+            SignerOrdering(3),
+            signer3.clone(),
+        );
+
+        // Check that signers are sorted from lowest to highest ordering
+        let signers = signers.signers();
+        assert_eq!(Arc::as_ptr(signers[0]), Arc::as_ptr(&signer1));
+        assert_eq!(Arc::as_ptr(signers[1]), Arc::as_ptr(&signer2));
+        assert_eq!(Arc::as_ptr(signers[2]), Arc::as_ptr(&signer3));
+    }
+
+    #[test]
+    fn find_signer_by_id() {
+        let mut signers = SignersContainer::new();
+        let signer1: Arc<dyn Signer> = Arc::new(DummySigner);
+        let signer2: Arc<dyn Signer> = Arc::new(DummySigner);
+        let signer3: Arc<dyn Signer> = Arc::new(DummySigner);
+        let signer4: Arc<dyn Signer> = Arc::new(DummySigner);
+
+        let id1 = SignerId::Fingerprint(b"cafe"[..].into());
+        let id2 = SignerId::Fingerprint(b"babe"[..].into());
+        let id3 = SignerId::Fingerprint(b"feed"[..].into());
+        let id_nonexistent = SignerId::Fingerprint(b"fefe"[..].into());
+
+        signers.add_external(id1.clone(), SignerOrdering(1), signer1.clone());
+        signers.add_external(id2.clone(), SignerOrdering(2), signer2.clone());
+        signers.add_external(id3.clone(), SignerOrdering(3), signer3.clone());
+
+        assert!(
+            matches!(signers.find(id1), Some(signer) if Arc::as_ptr(&signer1) == Arc::as_ptr(signer))
+        );
+        assert!(
+            matches!(signers.find(id2), Some(signer) if Arc::as_ptr(&signer2) == Arc::as_ptr(signer))
+        );
+        assert!(
+            matches!(signers.find(id3.clone()), Some(signer) if Arc::as_ptr(&signer3) == Arc::as_ptr(signer))
+        );
+
+        // The `signer4` has the same ID as `signer3` but lower ordering.
+        // It should be found by `id3` instead of `signer3`.
+        signers.add_external(id3.clone(), SignerOrdering(2), signer4.clone());
+        assert!(
+            matches!(signers.find(id3), Some(signer) if Arc::as_ptr(&signer4) == Arc::as_ptr(signer))
+        );
+
+        // Can't find anything with ID that doesn't exist
+        assert!(matches!(signers.find(id_nonexistent), None));
+    }
+
+    #[derive(Debug)]
+    struct DummySigner;
+    impl Signer for DummySigner {
+        fn sign(
+            &self,
+            _psbt: &mut PartiallySignedTransaction,
+            _input_index: Option<usize>,
+            _secp: &SecpCtx,
+        ) -> Result<(), SignerError> {
+            Ok(())
+        }
+
+        fn sign_whole_tx(&self) -> bool {
+            true
+        }
+    }
+
+    const TPRV0_STR:&str = "tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf";
+    const TPRV1_STR:&str = "tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N";
+
+    const PATH: &str = "m/44'/1'/0'/0";
+
+    fn setup_keys<Ctx: ScriptContext>(
+        tprv: &str,
+    ) -> (DescriptorKey<Ctx>, DescriptorKey<Ctx>, Fingerprint) {
+        let secp: Secp256k1<All> = Secp256k1::new();
+        let path = bip32::DerivationPath::from_str(PATH).unwrap();
+        let tprv = bip32::ExtendedPrivKey::from_str(tprv).unwrap();
+        let tpub = bip32::ExtendedPubKey::from_private(&secp, &tprv);
+        let fingerprint = tprv.fingerprint(&secp);
+        let prvkey = (tprv, path.clone()).to_descriptor_key().unwrap();
+        let pubkey = (tpub, path).to_descriptor_key().unwrap();
+
+        (prvkey, pubkey, fingerprint)
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/time.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/time.rs.html new file mode 100644 index 0000000000..d45d75e8a0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/time.rs.html @@ -0,0 +1,178 @@ +time.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Cross-platform time
+//!
+//! This module provides a function to get the current timestamp that works on all the platforms
+//! supported by the library.
+//!
+//! It can be useful to compare it with the timestamps found in
+//! [`TransactionDetails`](crate::types::TransactionDetails).
+
+use std::time::Duration;
+
+#[cfg(target_arch = "wasm32")]
+use js_sys::Date;
+#[cfg(not(target_arch = "wasm32"))]
+use std::time::{Instant as SystemInstant, SystemTime, UNIX_EPOCH};
+
+/// Return the current timestamp in seconds
+#[cfg(not(target_arch = "wasm32"))]
+pub fn get_timestamp() -> u64 {
+    SystemTime::now()
+        .duration_since(UNIX_EPOCH)
+        .unwrap()
+        .as_secs()
+}
+/// Return the current timestamp in seconds
+#[cfg(target_arch = "wasm32")]
+pub fn get_timestamp() -> u64 {
+    let millis = Date::now();
+
+    (millis / 1000.0) as u64
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+pub(crate) struct Instant(SystemInstant);
+#[cfg(target_arch = "wasm32")]
+pub(crate) struct Instant(Duration);
+
+impl Instant {
+    #[cfg(not(target_arch = "wasm32"))]
+    pub fn new() -> Self {
+        Instant(SystemInstant::now())
+    }
+    #[cfg(target_arch = "wasm32")]
+    pub fn new() -> Self {
+        let millis = Date::now();
+
+        let secs = millis / 1000.0;
+        let nanos = (millis % 1000.0) * 1e6;
+
+        Instant(Duration::new(secs as u64, nanos as u32))
+    }
+
+    #[cfg(not(target_arch = "wasm32"))]
+    pub fn elapsed(&self) -> Duration {
+        self.0.elapsed()
+    }
+    #[cfg(target_arch = "wasm32")]
+    pub fn elapsed(&self) -> Duration {
+        let now = Instant::new();
+
+        now.0.checked_sub(self.0).unwrap_or(Duration::new(0, 0))
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/tx_builder.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/tx_builder.rs.html new file mode 100644 index 0000000000..eceb370c5a --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/tx_builder.rs.html @@ -0,0 +1,1482 @@ +tx_builder.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+//! Transaction builder
+//!
+//! ## Example
+//!
+//! ```
+//! # use std::str::FromStr;
+//! # use bitcoin::*;
+//! # use bdk::*;
+//! # use bdk::wallet::tx_builder::CreateTx;
+//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+//! // Create a transaction with one output to `to_address` of 50_000 satoshi, with a custom fee rate
+//! // of 5.0 satoshi/vbyte, only spending non-change outputs and with RBF signaling
+//! // enabled
+//! let builder = TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
+//!     .fee_rate(FeeRate::from_sat_per_vb(5.0))
+//!     .do_not_spend_change()
+//!     .enable_rbf();
+//! # let builder: TxBuilder<bdk::database::MemoryDatabase, _, CreateTx> = builder;
+//! ```
+
+use std::collections::BTreeMap;
+use std::collections::HashSet;
+use std::default::Default;
+use std::marker::PhantomData;
+
+use bitcoin::{OutPoint, Script, SigHashType, Transaction};
+
+use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm};
+use crate::database::Database;
+use crate::types::{FeeRate, KeychainKind, UTXO};
+
+/// Context in which the [`TxBuilder`] is valid
+pub trait TxBuilderContext: std::fmt::Debug + Default + Clone {}
+
+/// [`Wallet::create_tx`](super::Wallet::create_tx) context
+#[derive(Debug, Default, Clone)]
+pub struct CreateTx;
+impl TxBuilderContext for CreateTx {}
+
+/// [`Wallet::bump_fee`](super::Wallet::bump_fee) context
+#[derive(Debug, Default, Clone)]
+pub struct BumpFee;
+impl TxBuilderContext for BumpFee {}
+
+/// A transaction builder
+///
+/// This structure contains the configuration that the wallet must follow to build a transaction.
+///
+/// For an example see [this module](super::tx_builder)'s documentation;
+#[derive(Debug)]
+pub struct TxBuilder<D: Database, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext> {
+    pub(crate) recipients: Vec<(Script, u64)>,
+    pub(crate) drain_wallet: bool,
+    pub(crate) single_recipient: Option<Script>,
+    pub(crate) fee_policy: Option<FeePolicy>,
+    pub(crate) internal_policy_path: Option<BTreeMap<String, Vec<usize>>>,
+    pub(crate) external_policy_path: Option<BTreeMap<String, Vec<usize>>>,
+    pub(crate) utxos: Vec<OutPoint>,
+    pub(crate) unspendable: HashSet<OutPoint>,
+    pub(crate) manually_selected_only: bool,
+    pub(crate) sighash: Option<SigHashType>,
+    pub(crate) ordering: TxOrdering,
+    pub(crate) locktime: Option<u32>,
+    pub(crate) rbf: Option<RBFValue>,
+    pub(crate) version: Option<Version>,
+    pub(crate) change_policy: ChangeSpendPolicy,
+    pub(crate) force_non_witness_utxo: bool,
+    pub(crate) add_global_xpubs: bool,
+    pub(crate) coin_selection: Cs,
+    pub(crate) include_output_redeem_witness_script: bool,
+
+    phantom: PhantomData<(D, Ctx)>,
+}
+
+#[derive(Debug)]
+pub(crate) enum FeePolicy {
+    FeeRate(FeeRate),
+    FeeAmount(u64),
+}
+
+impl std::default::Default for FeePolicy {
+    fn default() -> Self {
+        FeePolicy::FeeRate(FeeRate::default_min_relay_fee())
+    }
+}
+
+// Unfortunately derive doesn't work with `PhantomData`: https://github.com/rust-lang/rust/issues/26925
+impl<D: Database, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext> Default
+    for TxBuilder<D, Cs, Ctx>
+where
+    Cs: Default,
+{
+    fn default() -> Self {
+        TxBuilder {
+            recipients: Default::default(),
+            drain_wallet: Default::default(),
+            single_recipient: Default::default(),
+            fee_policy: Default::default(),
+            internal_policy_path: Default::default(),
+            external_policy_path: Default::default(),
+            utxos: Default::default(),
+            unspendable: Default::default(),
+            manually_selected_only: Default::default(),
+            sighash: Default::default(),
+            ordering: Default::default(),
+            locktime: Default::default(),
+            rbf: Default::default(),
+            version: Default::default(),
+            change_policy: Default::default(),
+            force_non_witness_utxo: Default::default(),
+            add_global_xpubs: Default::default(),
+            coin_selection: Default::default(),
+            include_output_redeem_witness_script: Default::default(),
+
+            phantom: PhantomData,
+        }
+    }
+}
+
+// methods supported by both contexts, but only for `DefaultCoinSelectionAlgorithm`
+impl<D: Database, Ctx: TxBuilderContext> TxBuilder<D, DefaultCoinSelectionAlgorithm, Ctx> {
+    /// Create an empty builder
+    pub fn new() -> Self {
+        Self::default()
+    }
+}
+
+// methods supported by both contexts, for any CoinSelectionAlgorithm
+impl<D: Database, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext> TxBuilder<D, Cs, Ctx> {
+    /// Set a custom fee rate
+    pub fn fee_rate(mut self, fee_rate: FeeRate) -> Self {
+        self.fee_policy = Some(FeePolicy::FeeRate(fee_rate));
+        self
+    }
+
+    /// Set an absolute fee
+    pub fn fee_absolute(mut self, fee_amount: u64) -> Self {
+        self.fee_policy = Some(FeePolicy::FeeAmount(fee_amount));
+        self
+    }
+
+    /// Set the policy path to use while creating the transaction for a given keychain.
+    ///
+    /// This method accepts a map where the key is the policy node id (see
+    /// [`Policy::id`](crate::descriptor::Policy::id)) and the value is the list of the indexes of
+    /// the items that are intended to be satisfied from the policy node (see
+    /// [`SatisfiableItem::Thresh::items`](crate::descriptor::policy::SatisfiableItem::Thresh::items)).
+    ///
+    /// ## Example
+    ///
+    /// An example of when the policy path is needed is the following descriptor:
+    /// `wsh(thresh(2,pk(A),sj:and_v(v:pk(B),n:older(6)),snj:and_v(v:pk(C),after(630000))))`,
+    /// derived from the miniscript policy `thresh(2,pk(A),and(pk(B),older(6)),and(pk(C),after(630000)))`.
+    /// It declares three descriptor fragments, and at the top level it uses `thresh()` to
+    /// ensure that at least two of them are satisfied. The individual fragments are:
+    ///
+    /// 1. `pk(A)`
+    /// 2. `and(pk(B),older(6))`
+    /// 3. `and(pk(C),after(630000))`
+    ///
+    /// When those conditions are combined in pairs, it's clear that the transaction needs to be created
+    /// differently depending on how the user intends to satisfy the policy afterwards:
+    ///
+    /// * If fragments `1` and `2` are used, the transaction will need to use a specific
+    ///   `n_sequence` in order to spend an `OP_CSV` branch.
+    /// * If fragments `1` and `3` are used, the transaction will need to use a specific `locktime`
+    ///   in order to spend an `OP_CLTV` branch.
+    /// * If fragments `2` and `3` are used, the transaction will need both.
+    ///
+    /// When the spending policy is represented as a tree (see
+    /// [`Wallet::policies`](super::Wallet::policies)), every node
+    /// is assigned a unique identifier that can be used in the policy path to specify which of
+    /// the node's children the user intends to satisfy: for instance, assuming the `thresh()`
+    /// root node of this example has an id of `aabbccdd`, the policy path map would look like:
+    ///
+    /// `{ "aabbccdd" => [0, 1] }`
+    ///
+    /// where the key is the node's id, and the value is a list of the children that should be
+    /// used, in no particular order.
+    ///
+    /// If a particularly complex descriptor has multiple ambiguous thresholds in its structure,
+    /// multiple entries can be added to the map, one for each node that requires an explicit path.
+    ///
+    /// ```
+    /// # use std::str::FromStr;
+    /// # use std::collections::BTreeMap;
+    /// # use bitcoin::*;
+    /// # use bdk::*;
+    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+    /// let mut path = BTreeMap::new();
+    /// path.insert("aabbccdd".to_string(), vec![0, 1]);
+    ///
+    /// let builder = TxBuilder::with_recipients(vec![(to_address.script_pubkey(), 50_000)])
+    ///     .policy_path(path, KeychainKind::External);
+    /// # let builder: TxBuilder<bdk::database::MemoryDatabase, _, _> = builder;
+    /// ```
+    pub fn policy_path(
+        mut self,
+        policy_path: BTreeMap<String, Vec<usize>>,
+        keychain: KeychainKind,
+    ) -> Self {
+        let to_update = match keychain {
+            KeychainKind::Internal => &mut self.internal_policy_path,
+            KeychainKind::External => &mut self.external_policy_path,
+        };
+
+        *to_update = Some(policy_path);
+        self
+    }
+
+    /// Replace the internal list of utxos that **must** be spent with a new list
+    ///
+    /// These have priority over the "unspendable" utxos, meaning that if a utxo is present both in
+    /// the "utxos" and the "unspendable" list, it will be spent.
+    pub fn utxos(mut self, utxos: Vec<OutPoint>) -> Self {
+        self.utxos = utxos;
+        self
+    }
+
+    /// Add a utxo to the internal list of utxos that **must** be spent
+    ///
+    /// These have priority over the "unspendable" utxos, meaning that if a utxo is present both in
+    /// the "utxos" and the "unspendable" list, it will be spent.
+    pub fn add_utxo(mut self, utxo: OutPoint) -> Self {
+        self.utxos.push(utxo);
+        self
+    }
+
+    /// Only spend utxos added by [`add_utxo`] and [`utxos`].
+    ///
+    /// The wallet will **not** add additional utxos to the transaction even if they are needed to
+    /// make the transaction valid.
+    ///
+    /// [`add_utxo`]: Self::add_utxo
+    /// [`utxos`]: Self::utxos
+    pub fn manually_selected_only(mut self) -> Self {
+        self.manually_selected_only = true;
+        self
+    }
+
+    /// Replace the internal list of unspendable utxos with a new list
+    ///
+    /// It's important to note that the "must-be-spent" utxos added with [`TxBuilder::utxos`] and
+    /// [`TxBuilder::add_utxo`] have priority over these. See the docs of the two linked methods
+    /// for more details.
+    pub fn unspendable(mut self, unspendable: Vec<OutPoint>) -> Self {
+        self.unspendable = unspendable.into_iter().collect();
+        self
+    }
+
+    /// Add a utxo to the internal list of unspendable utxos
+    ///
+    /// It's important to note that the "must-be-spent" utxos added with [`TxBuilder::utxos`] and
+    /// [`TxBuilder::add_utxo`] have priority over this. See the docs of the two linked methods
+    /// for more details.
+    pub fn add_unspendable(mut self, unspendable: OutPoint) -> Self {
+        self.unspendable.insert(unspendable);
+        self
+    }
+
+    /// Sign with a specific sig hash
+    ///
+    /// **Use this option very carefully**
+    pub fn sighash(mut self, sighash: SigHashType) -> Self {
+        self.sighash = Some(sighash);
+        self
+    }
+
+    /// Choose the ordering for inputs and outputs of the transaction
+    pub fn ordering(mut self, ordering: TxOrdering) -> Self {
+        self.ordering = ordering;
+        self
+    }
+
+    /// Use a specific nLockTime while creating the transaction
+    ///
+    /// This can cause conflicts if the wallet's descriptors contain an "after" (OP_CLTV) operator.
+    pub fn nlocktime(mut self, locktime: u32) -> Self {
+        self.locktime = Some(locktime);
+        self
+    }
+
+    /// Build a transaction with a specific version
+    ///
+    /// The `version` should always be greater than `0` and greater than `1` if the wallet's
+    /// descriptors contain an "older" (OP_CSV) operator.
+    pub fn version(mut self, version: i32) -> Self {
+        self.version = Some(Version(version));
+        self
+    }
+
+    /// Do not spend change outputs
+    ///
+    /// This effectively adds all the change outputs to the "unspendable" list. See
+    /// [`TxBuilder::unspendable`].
+    pub fn do_not_spend_change(mut self) -> Self {
+        self.change_policy = ChangeSpendPolicy::ChangeForbidden;
+        self
+    }
+
+    /// Only spend change outputs
+    ///
+    /// This effectively adds all the non-change outputs to the "unspendable" list. See
+    /// [`TxBuilder::unspendable`].
+    pub fn only_spend_change(mut self) -> Self {
+        self.change_policy = ChangeSpendPolicy::OnlyChange;
+        self
+    }
+
+    /// Set a specific [`ChangeSpendPolicy`]. See [`TxBuilder::do_not_spend_change`] and
+    /// [`TxBuilder::only_spend_change`] for some shortcuts.
+    pub fn change_policy(mut self, change_policy: ChangeSpendPolicy) -> Self {
+        self.change_policy = change_policy;
+        self
+    }
+
+    /// Fill-in the [`psbt::Input::non_witness_utxo`](bitcoin::util::psbt::Input::non_witness_utxo) field even if the wallet only has SegWit
+    /// descriptors.
+    ///
+    /// This is useful for signers which always require it, like Trezor hardware wallets.
+    pub fn force_non_witness_utxo(mut self) -> Self {
+        self.force_non_witness_utxo = true;
+        self
+    }
+
+    /// Fill-in the [`psbt::Output::redeem_script`](bitcoin::util::psbt::Output::redeem_script) and
+    /// [`psbt::Output::witness_script`](bitcoin::util::psbt::Output::witness_script) fields.
+    ///
+    /// This is useful for signers which always require it, like ColdCard hardware wallets.
+    pub fn include_output_redeem_witness_script(mut self) -> Self {
+        self.include_output_redeem_witness_script = true;
+        self
+    }
+
+    /// Fill-in the `PSBT_GLOBAL_XPUB` field with the extended keys contained in both the external
+    /// and internal descriptors
+    ///
+    /// This is useful for offline signers that take part to a multisig. Some hardware wallets like
+    /// BitBox and ColdCard are known to require this.
+    pub fn add_global_xpubs(mut self) -> Self {
+        self.add_global_xpubs = true;
+        self
+    }
+
+    /// Spend all the available inputs. This respects filters like [`TxBuilder::unspendable`] and the change policy.
+    pub fn drain_wallet(mut self) -> Self {
+        self.drain_wallet = true;
+        self
+    }
+
+    /// Choose the coin selection algorithm
+    ///
+    /// Overrides the [`DefaultCoinSelectionAlgorithm`](super::coin_selection::DefaultCoinSelectionAlgorithm).
+    pub fn coin_selection<P: CoinSelectionAlgorithm<D>>(
+        self,
+        coin_selection: P,
+    ) -> TxBuilder<D, P, Ctx> {
+        TxBuilder {
+            recipients: self.recipients,
+            drain_wallet: self.drain_wallet,
+            single_recipient: self.single_recipient,
+            fee_policy: self.fee_policy,
+            internal_policy_path: self.internal_policy_path,
+            external_policy_path: self.external_policy_path,
+            utxos: self.utxos,
+            unspendable: self.unspendable,
+            manually_selected_only: self.manually_selected_only,
+            sighash: self.sighash,
+            ordering: self.ordering,
+            locktime: self.locktime,
+            rbf: self.rbf,
+            version: self.version,
+            change_policy: self.change_policy,
+            force_non_witness_utxo: self.force_non_witness_utxo,
+            add_global_xpubs: self.add_global_xpubs,
+            include_output_redeem_witness_script: self.include_output_redeem_witness_script,
+            coin_selection,
+
+            phantom: PhantomData,
+        }
+    }
+}
+
+// methods supported only by create_tx, and only for `DefaultCoinSelectionAlgorithm`
+impl<D: Database> TxBuilder<D, DefaultCoinSelectionAlgorithm, CreateTx> {
+    /// Create a builder starting from a list of recipients
+    pub fn with_recipients(recipients: Vec<(Script, u64)>) -> Self {
+        Self::default().set_recipients(recipients)
+    }
+}
+
+// methods supported only by create_tx, for any `CoinSelectionAlgorithm`
+impl<D: Database, Cs: CoinSelectionAlgorithm<D>> TxBuilder<D, Cs, CreateTx> {
+    /// Replace the recipients already added with a new list
+    pub fn set_recipients(mut self, recipients: Vec<(Script, u64)>) -> Self {
+        self.recipients = recipients;
+        self
+    }
+
+    /// Add a recipient to the internal list
+    pub fn add_recipient(mut self, script_pubkey: Script, amount: u64) -> Self {
+        self.recipients.push((script_pubkey, amount));
+        self
+    }
+
+    /// Set a single recipient that will get all the selected funds minus the fee. No change will
+    /// be created
+    ///
+    /// This method overrides any recipient set with [`set_recipients`](Self::set_recipients) or
+    /// [`add_recipient`](Self::add_recipient).
+    ///
+    /// It can only be used in conjunction with [`drain_wallet`](Self::drain_wallet) to send the
+    /// entire content of the wallet (minus filters) to a single recipient or with a
+    /// list of manually selected UTXOs by enabling [`manually_selected_only`](Self::manually_selected_only)
+    /// and selecting them with [`utxos`](Self::utxos) or [`add_utxo`](Self::add_utxo).
+    ///
+    /// When bumping the fees of a transaction made with this option, the user should remeber to
+    /// add [`maintain_single_recipient`](Self::maintain_single_recipient) to correctly update the
+    /// single output instead of adding one more for the change.
+    pub fn set_single_recipient(mut self, recipient: Script) -> Self {
+        self.single_recipient = Some(recipient);
+        self.recipients.clear();
+
+        self
+    }
+
+    /// Enable signaling RBF
+    ///
+    /// This will use the default nSequence value of `0xFFFFFFFD`.
+    pub fn enable_rbf(mut self) -> Self {
+        self.rbf = Some(RBFValue::Default);
+        self
+    }
+
+    /// Enable signaling RBF with a specific nSequence value
+    ///
+    /// This can cause conflicts if the wallet's descriptors contain an "older" (OP_CSV) operator
+    /// and the given `nsequence` is lower than the CSV value.
+    ///
+    /// If the `nsequence` is higher than `0xFFFFFFFD` an error will be thrown, since it would not
+    /// be a valid nSequence to signal RBF.
+    pub fn enable_rbf_with_sequence(mut self, nsequence: u32) -> Self {
+        self.rbf = Some(RBFValue::Value(nsequence));
+        self
+    }
+}
+
+// methods supported only by bump_fee
+impl<D: Database> TxBuilder<D, DefaultCoinSelectionAlgorithm, BumpFee> {
+    /// Bump the fees of a transaction made with [`set_single_recipient`](Self::set_single_recipient)
+    ///
+    /// Unless extra inputs are specified with [`add_utxo`] or [`utxos`], this flag will make
+    /// `bump_fee` reduce the value of the existing output, or fail if it would be consumed
+    /// entirely given the higher new fee rate.
+    ///
+    /// If extra inputs are added and they are not entirely consumed in fees, a change output will not
+    /// be added; the existing output will simply grow in value.
+    ///
+    /// Fails if the transaction has more than one outputs.
+    ///
+    /// [`add_utxo`]: Self::add_utxo
+    /// [`utxos`]: Self::utxos
+    pub fn maintain_single_recipient(mut self) -> Self {
+        self.single_recipient = Some(Script::default());
+        self
+    }
+}
+
+/// Ordering of the transaction's inputs and outputs
+#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
+pub enum TxOrdering {
+    /// Randomized (default)
+    Shuffle,
+    /// Unchanged
+    Untouched,
+    /// BIP69 / Lexicographic
+    BIP69Lexicographic,
+}
+
+impl Default for TxOrdering {
+    fn default() -> Self {
+        TxOrdering::Shuffle
+    }
+}
+
+impl TxOrdering {
+    /// Sort transaction inputs and outputs by [`TxOrdering`] variant
+    pub fn sort_tx(&self, tx: &mut Transaction) {
+        match self {
+            TxOrdering::Untouched => {}
+            TxOrdering::Shuffle => {
+                use rand::seq::SliceRandom;
+                #[cfg(test)]
+                use rand::SeedableRng;
+
+                #[cfg(not(test))]
+                let mut rng = rand::thread_rng();
+                #[cfg(test)]
+                let mut rng = rand::rngs::StdRng::seed_from_u64(0);
+
+                tx.output.shuffle(&mut rng);
+            }
+            TxOrdering::BIP69Lexicographic => {
+                tx.input.sort_unstable_by_key(|txin| {
+                    (txin.previous_output.txid, txin.previous_output.vout)
+                });
+                tx.output
+                    .sort_unstable_by_key(|txout| (txout.value, txout.script_pubkey.clone()));
+            }
+        }
+    }
+}
+
+/// Transaction version
+///
+/// Has a default value of `1`
+#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
+pub(crate) struct Version(pub(crate) i32);
+
+impl Default for Version {
+    fn default() -> Self {
+        Version(1)
+    }
+}
+
+/// RBF nSequence value
+///
+/// Has a default value of `0xFFFFFFFD`
+#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
+pub(crate) enum RBFValue {
+    Default,
+    Value(u32),
+}
+
+impl RBFValue {
+    pub(crate) fn get_value(&self) -> u32 {
+        match self {
+            RBFValue::Default => 0xFFFFFFFD,
+            RBFValue::Value(v) => *v,
+        }
+    }
+}
+
+/// Policy regarding the use of change outputs when creating a transaction
+#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
+pub enum ChangeSpendPolicy {
+    /// Use both change and non-change outputs (default)
+    ChangeAllowed,
+    /// Only use change outputs (see [`TxBuilder::only_spend_change`])
+    OnlyChange,
+    /// Only use non-change outputs (see [`TxBuilder::do_not_spend_change`])
+    ChangeForbidden,
+}
+
+impl Default for ChangeSpendPolicy {
+    fn default() -> Self {
+        ChangeSpendPolicy::ChangeAllowed
+    }
+}
+
+impl ChangeSpendPolicy {
+    pub(crate) fn is_satisfied_by(&self, utxo: &UTXO) -> bool {
+        match self {
+            ChangeSpendPolicy::ChangeAllowed => true,
+            ChangeSpendPolicy::OnlyChange => utxo.keychain == KeychainKind::Internal,
+            ChangeSpendPolicy::ChangeForbidden => utxo.keychain == KeychainKind::External,
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    const ORDERING_TEST_TX: &'static str = "0200000003c26f3eb7932f7acddc5ddd26602b77e7516079b03090a16e2c2f54\
+                                            85d1fd600f0100000000ffffffffc26f3eb7932f7acddc5ddd26602b77e75160\
+                                            79b03090a16e2c2f5485d1fd600f0000000000ffffffff571fb3e02278217852\
+                                            dd5d299947e2b7354a639adc32ec1fa7b82cfb5dec530e0500000000ffffffff\
+                                            03e80300000000000002aaeee80300000000000001aa200300000000000001ff\
+                                            00000000";
+    macro_rules! ordering_test_tx {
+        () => {
+            deserialize::<bitcoin::Transaction>(&Vec::<u8>::from_hex(ORDERING_TEST_TX).unwrap())
+                .unwrap()
+        };
+    }
+
+    use bitcoin::consensus::deserialize;
+    use bitcoin::hashes::hex::FromHex;
+
+    use super::*;
+
+    #[test]
+    fn test_output_ordering_default_shuffle() {
+        assert_eq!(TxOrdering::default(), TxOrdering::Shuffle);
+    }
+
+    #[test]
+    fn test_output_ordering_untouched() {
+        let original_tx = ordering_test_tx!();
+        let mut tx = original_tx.clone();
+
+        TxOrdering::Untouched.sort_tx(&mut tx);
+
+        assert_eq!(original_tx, tx);
+    }
+
+    #[test]
+    fn test_output_ordering_shuffle() {
+        let original_tx = ordering_test_tx!();
+        let mut tx = original_tx.clone();
+
+        TxOrdering::Shuffle.sort_tx(&mut tx);
+
+        assert_eq!(original_tx.input, tx.input);
+        assert_ne!(original_tx.output, tx.output);
+    }
+
+    #[test]
+    fn test_output_ordering_bip69() {
+        use std::str::FromStr;
+
+        let original_tx = ordering_test_tx!();
+        let mut tx = original_tx.clone();
+
+        TxOrdering::BIP69Lexicographic.sort_tx(&mut tx);
+
+        assert_eq!(
+            tx.input[0].previous_output,
+            bitcoin::OutPoint::from_str(
+                "0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57:5"
+            )
+            .unwrap()
+        );
+        assert_eq!(
+            tx.input[1].previous_output,
+            bitcoin::OutPoint::from_str(
+                "0f60fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2:0"
+            )
+            .unwrap()
+        );
+        assert_eq!(
+            tx.input[2].previous_output,
+            bitcoin::OutPoint::from_str(
+                "0f60fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2:1"
+            )
+            .unwrap()
+        );
+
+        assert_eq!(tx.output[0].value, 800);
+        assert_eq!(tx.output[1].script_pubkey, From::from(vec![0xAA]));
+        assert_eq!(tx.output[2].script_pubkey, From::from(vec![0xAA, 0xEE]));
+    }
+
+    fn get_test_utxos() -> Vec<UTXO> {
+        vec![
+            UTXO {
+                outpoint: OutPoint {
+                    txid: Default::default(),
+                    vout: 0,
+                },
+                txout: Default::default(),
+                keychain: KeychainKind::External,
+            },
+            UTXO {
+                outpoint: OutPoint {
+                    txid: Default::default(),
+                    vout: 1,
+                },
+                txout: Default::default(),
+                keychain: KeychainKind::Internal,
+            },
+        ]
+    }
+
+    #[test]
+    fn test_change_spend_policy_default() {
+        let change_spend_policy = ChangeSpendPolicy::default();
+        let filtered = get_test_utxos()
+            .into_iter()
+            .filter(|u| change_spend_policy.is_satisfied_by(u))
+            .collect::<Vec<_>>();
+
+        assert_eq!(filtered.len(), 2);
+    }
+
+    #[test]
+    fn test_change_spend_policy_no_internal() {
+        let change_spend_policy = ChangeSpendPolicy::ChangeForbidden;
+        let filtered = get_test_utxos()
+            .into_iter()
+            .filter(|u| change_spend_policy.is_satisfied_by(u))
+            .collect::<Vec<_>>();
+
+        assert_eq!(filtered.len(), 1);
+        assert_eq!(filtered[0].keychain, KeychainKind::External);
+    }
+
+    #[test]
+    fn test_change_spend_policy_only_internal() {
+        let change_spend_policy = ChangeSpendPolicy::OnlyChange;
+        let filtered = get_test_utxos()
+            .into_iter()
+            .filter(|u| change_spend_policy.is_satisfied_by(u))
+            .collect::<Vec<_>>();
+
+        assert_eq!(filtered.len(), 1);
+        assert_eq!(filtered[0].keychain, KeychainKind::Internal);
+    }
+
+    #[test]
+    fn test_default_tx_version_1() {
+        let version = Version::default();
+        assert_eq!(version.0, 1);
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/utils.rs.html b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/utils.rs.html new file mode 100644 index 0000000000..e077192fc2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/src/bdk/wallet/utils.rs.html @@ -0,0 +1,580 @@ +utils.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+
+// Magical Bitcoin Library
+// Written in 2020 by
+//     Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020 Magical Bitcoin
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+use bitcoin::secp256k1::{All, Secp256k1};
+use bitcoin::util::bip32;
+
+use miniscript::descriptor::DescriptorPublicKeyCtx;
+use miniscript::{MiniscriptKey, Satisfier, ToPublicKey};
+
+// De-facto standard "dust limit" (even though it should change based on the output type)
+const DUST_LIMIT_SATOSHI: u64 = 546;
+
+// MSB of the nSequence. If set there's no consensus-constraint, so it must be disabled when
+// spending using CSV in order to enforce CSV rules
+pub(crate) const SEQUENCE_LOCKTIME_DISABLE_FLAG: u32 = 1 << 31;
+// When nSequence is lower than this flag the timelock is interpreted as block-height-based,
+// otherwise it's time-based
+pub(crate) const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = 1 << 22;
+// Mask for the bits used to express the timelock
+pub(crate) const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000FFFF;
+
+// Threshold for nLockTime to be considered a block-height-based timelock rather than time-based
+pub(crate) const BLOCKS_TIMELOCK_THRESHOLD: u32 = 500000000;
+
+/// Trait to check if a value is below the dust limit
+// we implement this trait to make sure we don't mess up the comparison with off-by-one like a <
+// instead of a <= etc. The constant value for the dust limit is not public on purpose, to
+// encourage the usage of this trait.
+pub trait IsDust {
+    /// Check whether or not a value is below dust limit
+    fn is_dust(&self) -> bool;
+}
+
+impl IsDust for u64 {
+    fn is_dust(&self) -> bool {
+        *self <= DUST_LIMIT_SATOSHI
+    }
+}
+
+pub struct After {
+    pub current_height: Option<u32>,
+    pub assume_height_reached: bool,
+}
+
+impl After {
+    pub(crate) fn new(current_height: Option<u32>, assume_height_reached: bool) -> After {
+        After {
+            current_height,
+            assume_height_reached,
+        }
+    }
+}
+
+pub(crate) fn check_nsequence_rbf(rbf: u32, csv: u32) -> bool {
+    // This flag cannot be set in the nSequence when spending using OP_CSV
+    if rbf & SEQUENCE_LOCKTIME_DISABLE_FLAG != 0 {
+        return false;
+    }
+
+    let mask = SEQUENCE_LOCKTIME_TYPE_FLAG | SEQUENCE_LOCKTIME_MASK;
+    let rbf = rbf & mask;
+    let csv = csv & mask;
+
+    // Both values should be represented in the same unit (either time-based or
+    // block-height based)
+    if (rbf < SEQUENCE_LOCKTIME_TYPE_FLAG) != (csv < SEQUENCE_LOCKTIME_TYPE_FLAG) {
+        return false;
+    }
+
+    // The value should be at least `csv`
+    if rbf < csv {
+        return false;
+    }
+
+    true
+}
+
+pub(crate) fn check_nlocktime(nlocktime: u32, required: u32) -> bool {
+    // Both values should be expressed in the same unit
+    if (nlocktime < BLOCKS_TIMELOCK_THRESHOLD) != (required < BLOCKS_TIMELOCK_THRESHOLD) {
+        return false;
+    }
+
+    // The value should be at least `required`
+    if nlocktime < required {
+        return false;
+    }
+
+    true
+}
+
+impl<ToPkCtx: Copy, Pk: MiniscriptKey + ToPublicKey<ToPkCtx>> Satisfier<ToPkCtx, Pk> for After {
+    fn check_after(&self, n: u32) -> bool {
+        if let Some(current_height) = self.current_height {
+            current_height >= n
+        } else {
+            self.assume_height_reached
+        }
+    }
+}
+
+pub struct Older {
+    pub current_height: Option<u32>,
+    pub create_height: Option<u32>,
+    pub assume_height_reached: bool,
+}
+
+impl Older {
+    pub(crate) fn new(
+        current_height: Option<u32>,
+        create_height: Option<u32>,
+        assume_height_reached: bool,
+    ) -> Older {
+        Older {
+            current_height,
+            create_height,
+            assume_height_reached,
+        }
+    }
+}
+
+impl<ToPkCtx: Copy, Pk: MiniscriptKey + ToPublicKey<ToPkCtx>> Satisfier<ToPkCtx, Pk> for Older {
+    fn check_older(&self, n: u32) -> bool {
+        if let Some(current_height) = self.current_height {
+            // TODO: test >= / >
+            current_height as u64 >= self.create_height.unwrap_or(0) as u64 + n as u64
+        } else {
+            self.assume_height_reached
+        }
+    }
+}
+
+pub(crate) type SecpCtx = Secp256k1<All>;
+pub(crate) fn descriptor_to_pk_ctx(secp: &SecpCtx) -> DescriptorPublicKeyCtx<'_, All> {
+    // Create a `to_pk_ctx` with a dummy derivation index, since we always use this on descriptor
+    // that have already been derived with `Descriptor::derive()`, so the child number added here
+    // is ignored.
+    DescriptorPublicKeyCtx::new(secp, bip32::ChildNumber::Normal { index: 0 })
+}
+
+pub struct ChunksIterator<I: Iterator> {
+    iter: I,
+    size: usize,
+}
+
+impl<I: Iterator> ChunksIterator<I> {
+    #[allow(dead_code)]
+    pub fn new(iter: I, size: usize) -> Self {
+        ChunksIterator { iter, size }
+    }
+}
+
+impl<I: Iterator> Iterator for ChunksIterator<I> {
+    type Item = Vec<<I as std::iter::Iterator>::Item>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let mut v = Vec::new();
+        for _ in 0..self.size {
+            let e = self.iter.next();
+
+            match e {
+                None => break,
+                Some(val) => v.push(val),
+            }
+        }
+
+        if v.is_empty() {
+            return None;
+        }
+
+        Some(v)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::{
+        check_nlocktime, check_nsequence_rbf, BLOCKS_TIMELOCK_THRESHOLD,
+        SEQUENCE_LOCKTIME_TYPE_FLAG,
+    };
+    use crate::types::FeeRate;
+
+    #[test]
+    fn test_fee_from_btc_per_kb() {
+        let fee = FeeRate::from_btc_per_kvb(1e-5);
+        assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001);
+    }
+
+    #[test]
+    fn test_fee_from_sats_vbyte() {
+        let fee = FeeRate::from_sat_per_vb(1.0);
+        assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001);
+    }
+
+    #[test]
+    fn test_fee_default_min_relay_fee() {
+        let fee = FeeRate::default_min_relay_fee();
+        assert!((fee.as_sat_vb() - 1.0).abs() < 0.0001);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_msb_set() {
+        let result = check_nsequence_rbf(0x80000000, 5000);
+        assert_eq!(result, false);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_lt_csv() {
+        let result = check_nsequence_rbf(4000, 5000);
+        assert_eq!(result, false);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_different_unit() {
+        let result = check_nsequence_rbf(SEQUENCE_LOCKTIME_TYPE_FLAG + 5000, 5000);
+        assert_eq!(result, false);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_mask() {
+        let result = check_nsequence_rbf(0x3f + 10_000, 5000);
+        assert_eq!(result, true);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_same_unit_blocks() {
+        let result = check_nsequence_rbf(10_000, 5000);
+        assert_eq!(result, true);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_same_unit_time() {
+        let result = check_nsequence_rbf(
+            SEQUENCE_LOCKTIME_TYPE_FLAG + 10_000,
+            SEQUENCE_LOCKTIME_TYPE_FLAG + 5000,
+        );
+        assert_eq!(result, true);
+    }
+
+    #[test]
+    fn test_check_nlocktime_lt_cltv() {
+        let result = check_nlocktime(4000, 5000);
+        assert_eq!(result, false);
+    }
+
+    #[test]
+    fn test_check_nlocktime_different_unit() {
+        let result = check_nlocktime(BLOCKS_TIMELOCK_THRESHOLD + 5000, 5000);
+        assert_eq!(result, false);
+    }
+
+    #[test]
+    fn test_check_nlocktime_same_unit_blocks() {
+        let result = check_nlocktime(10_000, 5000);
+        assert_eq!(result, true);
+    }
+
+    #[test]
+    fn test_check_nlocktime_same_unit_time() {
+        let result = check_nlocktime(
+            BLOCKS_TIMELOCK_THRESHOLD + 10_000,
+            BLOCKS_TIMELOCK_THRESHOLD + 5000,
+        );
+        assert_eq!(result, true);
+    }
+}
+
+
\ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/storage.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/storage.js new file mode 100644 index 0000000000..318275ed34 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/storage.js @@ -0,0 +1 @@ +var resourcesSuffix="";var darkThemes=["dark","ayu"];var currentTheme=document.getElementById("themeStyle");var mainTheme=document.getElementById("mainThemeStyle");var settingsDataset=(function(){var settingsElement=document.getElementById("default-settings");if(settingsElement===null){return null}var dataset=settingsElement.dataset;if(dataset===undefined){return null}return dataset})();function getSettingValue(settingName){var current=getCurrentValue('rustdoc-'+settingName);if(current!==null){return current}if(settingsDataset!==null){var def=settingsDataset[settingName.replace(/-/g,'_')];if(def!==undefined){return def}}return null}var localStoredTheme=getSettingValue("theme");var savedHref=[];function hasClass(elem,className){return elem&&elem.classList&&elem.classList.contains(className)}function addClass(elem,className){if(!elem||!elem.classList){return}elem.classList.add(className)}function removeClass(elem,className){if(!elem||!elem.classList){return}elem.classList.remove(className)}function onEach(arr,func,reversed){if(arr&&arr.length>0&&func){var length=arr.length;var i;if(reversed!==true){for(i=0;i=0;--i){if(func(arr[i])===true){return true}}}}return false}function onEachLazy(lazyArray,func,reversed){return onEach(Array.prototype.slice.call(lazyArray),func,reversed)}function hasOwnProperty(obj,property){return Object.prototype.hasOwnProperty.call(obj,property)}function usableLocalStorage(){if(typeof Storage==="undefined"){return false}try{return window.localStorage!==null&&window.localStorage!==undefined}catch(err){return false}}function updateLocalStorage(name,value){if(usableLocalStorage()){localStorage[name]=value}else{}}function getCurrentValue(name){if(usableLocalStorage()&&localStorage[name]!==undefined){return localStorage[name]}return null}function switchTheme(styleElem,mainStyleElem,newTheme,saveTheme){var fullBasicCss="rustdoc"+resourcesSuffix+".css";var fullNewTheme=newTheme+resourcesSuffix+".css";var newHref=mainStyleElem.href.replace(fullBasicCss,fullNewTheme);if(saveTheme===true){updateLocalStorage("rustdoc-theme",newTheme)}if(styleElem.href===newHref){return}var found=false;if(savedHref.length===0){onEachLazy(document.getElementsByTagName("link"),function(el){savedHref.push(el.href)})}onEach(savedHref,function(el){if(el===newHref){found=true;return true}});if(found===true){styleElem.href=newHref}}function useSystemTheme(value){if(value===undefined){value=true}updateLocalStorage("rustdoc-use-system-theme",value);var toggle=document.getElementById("use-system-theme");if(toggle&&toggle instanceof HTMLInputElement){toggle.checked=value}}var updateSystemTheme=(function(){if(!window.matchMedia){return function(){let cssTheme=getComputedStyle(document.documentElement).getPropertyValue('content');switchTheme(currentTheme,mainTheme,JSON.parse(cssTheme)||light,true)}}var mql=window.matchMedia("(prefers-color-scheme: dark)");function handlePreferenceChange(mql){if(getSettingValue("use-system-theme")!=="false"){var lightTheme=getSettingValue("preferred-light-theme")||"light";var darkTheme=getSettingValue("preferred-dark-theme")||"dark";if(mql.matches){switchTheme(currentTheme,mainTheme,darkTheme,true)}else{switchTheme(currentTheme,mainTheme,lightTheme,true)}}}mql.addListener(handlePreferenceChange);return function(){handlePreferenceChange(mql)}})();if(getSettingValue("use-system-theme")!=="false"&&window.matchMedia){if(getSettingValue("use-system-theme")===null&&getSettingValue("preferred-dark-theme")===null&&darkThemes.indexOf(localStoredTheme)>=0){updateLocalStorage("rustdoc-preferred-dark-theme",localStoredTheme)}updateSystemTheme()}else{switchTheme(currentTheme,mainTheme,getSettingValue("theme")||"light",false)} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/theme.js b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/theme.js new file mode 100644 index 0000000000..8f9c49a429 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/theme.js @@ -0,0 +1 @@ +var themes=document.getElementById("theme-choices");var themePicker=document.getElementById("theme-picker");function showThemeButtonState(){themes.style.display="block";themePicker.style.borderBottomRightRadius="0";themePicker.style.borderBottomLeftRadius="0"}function hideThemeButtonState(){themes.style.display="none";themePicker.style.borderBottomRightRadius="3px";themePicker.style.borderBottomLeftRadius="3px"}function switchThemeButtonState(){if(themes.style.display==="block"){hideThemeButtonState()}else{showThemeButtonState()}};function handleThemeButtonsBlur(e){var active=document.activeElement;var related=e.relatedTarget;if(active.id!=="theme-picker"&&(!active.parentNode||active.parentNode.id!=="theme-choices")&&(!related||(related.id!=="theme-picker"&&(!related.parentNode||related.parentNode.id!=="theme-choices")))){hideThemeButtonState()}}themePicker.onclick=switchThemeButtonState;themePicker.onblur=handleThemeButtonsBlur;["ayu","dark","light"].forEach(function(item){var but=document.createElement("button");but.textContent=item;but.onclick=function(el){switchTheme(currentTheme,mainTheme,item,true);useSystemTheme(false)};but.onblur=handleThemeButtonsBlur;themes.appendChild(but)}) \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/wheel.svg b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/wheel.svg new file mode 100644 index 0000000000..01da3b24c7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/b8c6732c74bf7d4558a85d39a9e423347acf5ea0/wheel.svg @@ -0,0 +1 @@ + \ No newline at end of file