From: github-actions Date: Fri, 8 Oct 2021 06:05:14 +0000 (+0000) Subject: Publish autogenerated nightly docs X-Git-Url: http://internal-gitweb-vhost/script/%22https:/database/struct.CodeLengthError.html?a=commitdiff_plain;h=ec033e55cabaf46710a0839c3e1ccec43363e659;p=bitcoindevkit.org Publish autogenerated nightly docs --- diff --git a/static/docs-rs/bdk/nightly/latest/.lock b/static/docs-rs/bdk/nightly/latest/.lock new file mode 100644 index 0000000000..e69de29bb2 diff --git a/static/docs-rs/bdk/nightly/latest/COPYRIGHT.txt b/static/docs-rs/bdk/nightly/latest/COPYRIGHT.txt new file mode 100644 index 0000000000..c2629a83f7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/COPYRIGHT.txt @@ -0,0 +1,50 @@ +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.woff2, FiraSans-Medium.woff2, + 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.ttf.woff2, + SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2, + SourceCodePro-Regular.ttf.woff, SourceCodePro-Semibold.ttf.woff, + SourceCodePro-It.ttf.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 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2, + SourceSerif4-It.ttf.woff2, SourceSerif4-Regular.ttf.woff, + SourceSerif4-Bold.ttf.woff, SourceSerif4-It.ttf.woff): + + Copyright 2014-2021 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. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerif4-LICENSE.md. + +This copyright file is intended to be distributed with rustdoc output. diff --git a/static/docs-rs/bdk/nightly/latest/FiraSans-LICENSE.txt b/static/docs-rs/bdk/nightly/latest/FiraSans-LICENSE.txt new file mode 100644 index 0000000000..ff9afab064 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/FiraSans-Medium.woff b/static/docs-rs/bdk/nightly/latest/FiraSans-Medium.woff new file mode 100644 index 0000000000..7d742c5fb7 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/FiraSans-Medium.woff differ diff --git a/static/docs-rs/bdk/nightly/latest/FiraSans-Medium.woff2 b/static/docs-rs/bdk/nightly/latest/FiraSans-Medium.woff2 new file mode 100644 index 0000000000..7a1e5fc548 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/FiraSans-Medium.woff2 differ diff --git a/static/docs-rs/bdk/nightly/latest/FiraSans-Regular.woff b/static/docs-rs/bdk/nightly/latest/FiraSans-Regular.woff new file mode 100644 index 0000000000..d8e0363f4e Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/FiraSans-Regular.woff differ diff --git a/static/docs-rs/bdk/nightly/latest/FiraSans-Regular.woff2 b/static/docs-rs/bdk/nightly/latest/FiraSans-Regular.woff2 new file mode 100644 index 0000000000..e766e06ccb Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/FiraSans-Regular.woff2 differ diff --git a/static/docs-rs/bdk/nightly/latest/LICENSE-APACHE.txt b/static/docs-rs/bdk/nightly/latest/LICENSE-APACHE.txt new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/LICENSE-MIT.txt b/static/docs-rs/bdk/nightly/latest/LICENSE-MIT.txt new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/SourceCodePro-It.ttf.woff b/static/docs-rs/bdk/nightly/latest/SourceCodePro-It.ttf.woff new file mode 100644 index 0000000000..8d68f2febd Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceCodePro-It.ttf.woff differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceCodePro-It.ttf.woff2 b/static/docs-rs/bdk/nightly/latest/SourceCodePro-It.ttf.woff2 new file mode 100644 index 0000000000..462c34efcd Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceCodePro-It.ttf.woff2 differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceCodePro-LICENSE.txt b/static/docs-rs/bdk/nightly/latest/SourceCodePro-LICENSE.txt new file mode 100644 index 0000000000..07542572e3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/SourceCodePro-Regular.ttf.woff b/static/docs-rs/bdk/nightly/latest/SourceCodePro-Regular.ttf.woff new file mode 100644 index 0000000000..7be076e1fc Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceCodePro-Regular.ttf.woff differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceCodePro-Regular.ttf.woff2 b/static/docs-rs/bdk/nightly/latest/SourceCodePro-Regular.ttf.woff2 new file mode 100644 index 0000000000..10b558e0b6 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceCodePro-Regular.ttf.woff2 differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceCodePro-Semibold.ttf.woff b/static/docs-rs/bdk/nightly/latest/SourceCodePro-Semibold.ttf.woff new file mode 100644 index 0000000000..61bc67b802 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceCodePro-Semibold.ttf.woff differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceCodePro-Semibold.ttf.woff2 b/static/docs-rs/bdk/nightly/latest/SourceCodePro-Semibold.ttf.woff2 new file mode 100644 index 0000000000..5ec64eef0e Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceCodePro-Semibold.ttf.woff2 differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceSerif4-Bold.ttf.woff b/static/docs-rs/bdk/nightly/latest/SourceSerif4-Bold.ttf.woff new file mode 100644 index 0000000000..8ad41888e6 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceSerif4-Bold.ttf.woff differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceSerif4-Bold.ttf.woff2 b/static/docs-rs/bdk/nightly/latest/SourceSerif4-Bold.ttf.woff2 new file mode 100644 index 0000000000..db57d21455 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceSerif4-Bold.ttf.woff2 differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceSerif4-It.ttf.woff b/static/docs-rs/bdk/nightly/latest/SourceSerif4-It.ttf.woff new file mode 100644 index 0000000000..2a34b5c42a Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceSerif4-It.ttf.woff differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceSerif4-It.ttf.woff2 b/static/docs-rs/bdk/nightly/latest/SourceSerif4-It.ttf.woff2 new file mode 100644 index 0000000000..1cbc021a3a Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceSerif4-It.ttf.woff2 differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceSerif4-LICENSE.md b/static/docs-rs/bdk/nightly/latest/SourceSerif4-LICENSE.md new file mode 100644 index 0000000000..68ea189240 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/SourceSerif4-LICENSE.md @@ -0,0 +1,93 @@ +Copyright 2014-2021 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/latest/SourceSerif4-Regular.ttf.woff b/static/docs-rs/bdk/nightly/latest/SourceSerif4-Regular.ttf.woff new file mode 100644 index 0000000000..45a5521ab0 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceSerif4-Regular.ttf.woff differ diff --git a/static/docs-rs/bdk/nightly/latest/SourceSerif4-Regular.ttf.woff2 b/static/docs-rs/bdk/nightly/latest/SourceSerif4-Regular.ttf.woff2 new file mode 100644 index 0000000000..2db73fe2b4 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/SourceSerif4-Regular.ttf.woff2 differ diff --git a/static/docs-rs/bdk/nightly/latest/ayu.css b/static/docs-rs/bdk/nightly/latest/ayu.css new file mode 100644 index 0000000000..cb83628657 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/ayu.css @@ -0,0 +1 @@ + body{background-color:#0f1419;color:#c5c5c5;}h1,h2,h3,h4{color:white;}h1.fqn{border-bottom-color:#5c6773;}h1.fqn a{color:#fff;}h2,h3,h4{border-bottom-color:#5c6773;}h4{border:none;}.in-band{background-color:#0f1419;}.invisible{background:rgba(0,0,0,0);}.docblock code{color:#ffb454;}.code-header{color:#e6e1cf;}.docblock pre>code,pre>code{color:#e6e1cf;}span code{color:#e6e1cf;}.docblock a>code{color:#39AFD7 !important;}.docblock code,.docblock-short code{background-color:#191f26;}pre,.rustdoc.source .example-wrap{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,.docblock h6{border-bottom-color:#5c6773;}.docblock table td,.docblock table th{border-color:#5c6773;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#c5c5c5;}.search-results a:hover{background-color:#777;}.search-results a:focus{color:#000 !important;background-color:#c6afb3;}.search-results a{color:#0096cf;}.search-results a div.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;}body.source .example-wrap pre.rust a{background:#333;}.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;}details.rustdoc-toggle>summary.hideme>span,details.rustdoc-toggle>summary::before,details.undocumented>summary::before{color:#999;}details.rustdoc-toggle>summary::before,details.undocumented>summary::before{filter:invert(100%);}#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-input:disabled{background-color:#3e3e3e;}.module-item .stab,.import-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:none;}#help>div{background:#14191f;box-shadow:0px 6px 20px 0px black;border:none;border-radius:4px;}#help span.bottom,#help span.top{border-color:#5c6773;}.since{color:grey;}.result-name .primitive>i,.result-name .keyword>i{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,.code-attribute{color:#999;}:target,:target>*{background:rgba(255,236,164,0.06);}:target{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::after{background-color:#314559;color:#c5c5c5;border:1px solid #5c6773;}.tooltip::before{border-color:transparent #314559 transparent transparent;}.notable-traits-tooltiptext{background-color:#314559;border-color:#5c6773;}.notable-traits-tooltiptext .notable{border-bottom-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;}.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 span.struct,.content a.struct,.block a.current.struct{}#titles>button:hover,#titles>button.selected{}.content span.type,.content a.type,.block a.current.type{}.content span.union,.content a.union,.block a.current.union{}pre.rust .lifetime{}.stab.unstable{}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 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 a.attr,.content a.derive,.content a.macro{}.stab.portability{}.content span.primitive,.content a.primitive,.block a.current.primitive{}.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod{}pre.rust .kw-2,pre.rust .prelude-ty{}.content span.trait,.content a.trait,.block a.current.trait{}.search-results a:focus span{}a.result-trait:focus{}a.result-traitalias:focus{}a.result-mod:focus,a.result-externcrate:focus{}a.result-mod:focus{}a.result-externcrate:focus{}a.result-enum:focus{}a.result-struct:focus{}a.result-union:focus{}a.result-fn:focus,a.result-method:focus,a.result-tymethod:focus{}a.result-type:focus{}a.result-foreigntype:focus{}a.result-attr:focus,a.result-derive:focus,a.result-macro:focus{}a.result-constant:focus,a.result-static:focus{}a.result-primitive:focus{}a.result-keyword:focus{}@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);}#copy-path{color:#fff;}#copy-path>img{filter:invert(70%);}#copy-path:hover>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 .result-name span.alias{color:#c5c5c5;}.search-results .result-name 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/latest/bdk/all.html b/static/docs-rs/bdk/nightly/latest/bdk/all.html new file mode 100644 index 0000000000..9ac8067545 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/all.html @@ -0,0 +1,5 @@ +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/latest/bdk/blockchain/any/enum.AnyBlockchain.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/any/enum.AnyBlockchain.html new file mode 100644 index 0000000000..24021ba699 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/any/enum.AnyBlockchain.html @@ -0,0 +1,41 @@ +AnyBlockchain in bdk::blockchain::any - Rust

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

pub enum AnyBlockchain {
+    Electrum(ElectrumBlockchain),
+    Esplora(EsploraBlockchain),
+    CompactFilters(CompactFiltersBlockchain),
+}
This is supported on crate features electrum or esplora or compact_filters or rpc only.
Expand description

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

+

Tuple Fields of Electrum

0: ElectrumBlockchain
This is supported on crate feature esplora only.

Esplora client

+

Tuple Fields of Esplora

0: EsploraBlockchain
CompactFilters(CompactFiltersBlockchain)
This is supported on crate feature compact_filters only.

Compact filters client

+

Tuple Fields of CompactFilters

0: CompactFiltersBlockchain

Trait Implementations

Return the set of Capability supported by this backend

+

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

+

Populate the internal database with transactions and UTXOs Read more

+

Fetch a transaction from the blockchain given its txid

+

Broadcast a transaction

+

Return the current height

+

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

+

Type that contains the configuration

+

Create a new instance given a configuration

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub enum AnyBlockchainConfig {
+    Electrum(ElectrumBlockchainConfig),
+    Esplora(EsploraBlockchainConfig),
+    CompactFilters(CompactFiltersBlockchainConfig),
+}
This is supported on crate features electrum or esplora or compact_filters or rpc only.
Expand description

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.

+

This type can be serialized from a JSON object like:

+ +
use bdk::blockchain::{electrum::ElectrumBlockchainConfig, AnyBlockchainConfig};
+let config: AnyBlockchainConfig = serde_json::from_str(
+    r#"{
+   "type" : "electrum",
+   "url" : "ssl://electrum.blockstream.info:50002",
+   "retry": 2,
+   "stop_gap": 20
+}"#,
+)
+.unwrap();
+assert_eq!(
+    config,
+    AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig {
+        url: "ssl://electrum.blockstream.info:50002".into(),
+        retry: 2,
+        socks5: None,
+        timeout: None,
+        stop_gap: 20,
+    })
+);
+

Variants

This is supported on crate feature electrum only.

Electrum client

+

Tuple Fields of Electrum

0: ElectrumBlockchainConfig
This is supported on crate feature esplora only.

Esplora client

+

Tuple Fields of Esplora

0: EsploraBlockchainConfig
This is supported on crate feature compact_filters only.

Compact filters client

+

Tuple Fields of CompactFilters

0: CompactFiltersBlockchainConfig

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

This is supported on crate features electrum or esplora or compact_filters or rpc only.
Expand description

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("...", 20);
+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

+

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

+

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/latest/bdk/blockchain/any/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/any/sidebar-items.js new file mode 100644 index 0000000000..14144cf693 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/blockchain/compact_filters/enum.CompactFiltersError.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/compact_filters/enum.CompactFiltersError.html new file mode 100644 index 0000000000..48a3cbca2d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/compact_filters/enum.CompactFiltersError.html @@ -0,0 +1,73 @@ +CompactFiltersError in bdk::blockchain::compact_filters - Rust

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

pub enum CompactFiltersError {
+
Show 15 variants InvalidResponse, + InvalidHeaders, + InvalidFilterHeader, + InvalidFilter, + MissingBlock, + DataCorruption, + NotConnected, + Timeout, + PeerBloomDisabled, + NoPeers, + Db(Error), + Io(Error), + Bip158(Error), + Time(SystemTimeError), + Global(Box<Error>), +
}
This is supported on crate feature compact_filters only.
Expand description

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

+
PeerBloomDisabled

The peer doesn’t advertise the BLOOM service flag

+
NoPeers

No peers have been specified

+
Db(Error)

Internal database error

+

Tuple Fields of Db

0: Error
Io(Error)

Internal I/O error

+

Tuple Fields of Io

0: Error
Bip158(Error)

Invalid BIP158 filter

+

Tuple Fields of Bip158

0: Error

Internal system time error

+

Tuple Fields of Time

0: SystemTimeError
Global(Box<Error>)

Wrapper for crate::error::Error

+

Tuple Fields of Global

0: Box<Error>

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Converts a reference to Self into a dynamic trait object of Fail.

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the “name” of the error. Read more

+

Returns a reference to the underlying cause of this failure, if it +is an error that wraps other errors. Read more

+

Returns a reference to the Backtrace carried by this failure, if it +carries one. Read more

+

Provides context for this failure. Read more

+

Wraps this failure in a compatibility wrapper that implements +std::error::Error. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

This is supported on crate feature compact_filters only.
Expand description

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

+

Data to connect to a Bitcoin P2P peer

+

Structure implementing the required blockchain traits

+

Container for unconfirmed, but valid Bitcoin transactions

+

A Bitcoin peer

+

Enums

+

An error that can occur during sync with a CompactFiltersBlockchain

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

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

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

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

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/compact_filters/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/compact_filters/sidebar-items.js new file mode 100644 index 0000000000..187af79563 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/blockchain/compact_filters/struct.BitcoinPeerConfig.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/compact_filters/struct.BitcoinPeerConfig.html new file mode 100644 index 0000000000..529f5ba605 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/compact_filters/struct.BitcoinPeerConfig.html @@ -0,0 +1,39 @@ +BitcoinPeerConfig in bdk::blockchain::compact_filters - Rust

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

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.
Expand description

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

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

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

Structure implementing the required blockchain traits

+

Example

+

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

+

Implementations

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

This is supported on non-WebAssembly and non-crate feature async-interface only.

Return the set of Capability supported by this backend

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

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

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Fetch a transaction from the blockchain given its txid

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Broadcast a transaction

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Return the current height

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

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

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Populate the internal database with transactions and UTXOs Read more

+

Type that contains the configuration

+

Create a new instance given a configuration

+

Formats the value using the given formatter. Read more

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

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.
Expand description

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

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Performs the conversion.

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub struct Mempool(_);
This is supported on crate feature compact_filters only.
Expand description

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

Create a new empty mempool

+

Add a transaction to the mempool

+

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

+

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

+

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

+

Return the list of transactions contained in the mempool

+

Trait Implementations

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

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

A Bitcoin peer

+

Implementations

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

+

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

+

Return the [VersionMessage] sent by the peer

+

Return the Bitcoin [Network] in use

+

Return the mempool used by this peer

+

Return whether or not the peer is still connected

+

Send a raw Bitcoin message to the peer

+

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

+

Trait Implementations

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

This is supported on crate feature electrum only.
Expand description

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

+

Wrapper over an Electrum Client that implements the required blockchain traits

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/electrum/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/electrum/sidebar-items.js new file mode 100644 index 0000000000..1bd5458912 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/blockchain/electrum/struct.ElectrumBlockchain.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/electrum/struct.ElectrumBlockchain.html new file mode 100644 index 0000000000..a642137f0a --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/electrum/struct.ElectrumBlockchain.html @@ -0,0 +1,33 @@ +ElectrumBlockchain in bdk::blockchain::electrum - Rust

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

pub struct ElectrumBlockchain { /* fields omitted */ }
This is supported on crate feature electrum only.
Expand description

Wrapper over an Electrum Client that implements the required blockchain traits

+

Example

+

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

+

Trait Implementations

This is supported on non-WebAssembly and non-crate feature async-interface only.

Return the set of Capability supported by this backend

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

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

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Fetch a transaction from the blockchain given its txid

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Broadcast a transaction

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Return the current height

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

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

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Populate the internal database with transactions and UTXOs Read more

+

Type that contains the configuration

+

Create a new instance given a configuration

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

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

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: Option<u8>

Request timeout (seconds)

+
stop_gap: usize

Stop searching addresses for transactions after finding an unused gap of this length

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Performs the conversion.

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

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

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

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub enum EsploraError {
+    Ureq(Error),
+    UreqTransport(Transport),
+    HttpResponse(u16),
+    Io(Error),
+    NoHeader,
+    Parsing(ParseIntError),
+    BitcoinEncoding(Error),
+    Hex(Error),
+    TransactionNotFound(Txid),
+    HeaderHeightNotFound(u32),
+    HeaderHashNotFound(BlockHash),
+}
This is supported on crate feature esplora only.
Expand description

Errors that can happen during a sync with EsploraBlockchain

+

Variants

Ureq(Error)
This is supported on crate feature ureq only.

Error during ureq HTTP request

+

Tuple Fields of Ureq

0: Error
UreqTransport(Transport)
This is supported on crate feature ureq only.

Transport error during the ureq HTTP call

+

Tuple Fields of UreqTransport

0: Transport
HttpResponse(u16)

HTTP response error

+

Tuple Fields of HttpResponse

0: u16
Io(Error)

IO error during ureq response read

+

Tuple Fields of Io

0: Error
NoHeader

No header found in ureq response

+
Parsing(ParseIntError)

Invalid number returned

+

Tuple Fields of Parsing

0: ParseIntError
BitcoinEncoding(Error)

Invalid Bitcoin data returned

+

Tuple Fields of BitcoinEncoding

0: Error
Hex(Error)

Invalid Hex data returned

+

Tuple Fields of Hex

0: Error
TransactionNotFound(Txid)

Transaction not found

+

Tuple Fields of TransactionNotFound

0: Txid
HeaderHeightNotFound(u32)

Header height not found

+

Tuple Fields of HeaderHeightNotFound

0: u32
HeaderHashNotFound(BlockHash)

Header hash not found

+

Tuple Fields of HeaderHashNotFound

0: BlockHash

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Converts a reference to Self into a dynamic trait object of Fail.

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the “name” of the error. Read more

+

Returns a reference to the underlying cause of this failure, if it +is an error that wraps other errors. Read more

+

Returns a reference to the Backtrace carried by this failure, if it +carries one. Read more

+

Provides context for this failure. Read more

+

Wraps this failure in a compatibility wrapper that implements +std::error::Error. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

This is supported on crate feature esplora only.
Expand description

Esplora

+

This module defines a EsploraBlockchain struct that can query an Esplora +backend populate the wallet’s database by:

+

Example

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

Esplora blockchain can use either ureq or reqwest for the HTTP client +depending on your needs (blocking or async respectively).

+

Please note, to configure the Esplora HTTP client correctly use one of: +Blocking: –features=‘esplora,ureq’ +Async: –features=‘async-interface,esplora,reqwest’ –no-default-features

+

Structs

+

Structure that implements the logic to sync with Esplora

+

Data type used when fetching transaction history from Esplora.

+

Enums

+

Errors that can happen during a sync with EsploraBlockchain

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/sidebar-items.js new file mode 100644 index 0000000000..bf88a1a159 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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`]"],["EsploraGetHistory","Data type used when fetching transaction history from Esplora."]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/struct.EsploraBlockchain.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/struct.EsploraBlockchain.html new file mode 100644 index 0000000000..98e2403893 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/struct.EsploraBlockchain.html @@ -0,0 +1,35 @@ +EsploraBlockchain in bdk::blockchain::esplora - Rust

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

pub struct EsploraBlockchain { /* fields omitted */ }
This is supported on crate feature esplora only.
Expand description

Structure that implements the logic to sync with Esplora

+

Example

+

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

+

Implementations

This is supported on crate feature ureq only.

Create a new instance of the client from a base URL and the stop_gap.

+
This is supported on crate feature ureq only.

Set the inner ureq agent.

+

Trait Implementations

This is supported on non-WebAssembly and non-crate feature async-interface only.

Return the set of Capability supported by this backend

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

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

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Fetch a transaction from the blockchain given its txid

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Broadcast a transaction

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Return the current height

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

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

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Populate the internal database with transactions and UTXOs Read more

+

Type that contains the configuration

+

Create a new instance given a configuration

+

Formats the value using the given formatter. Read more

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub struct EsploraBlockchainConfig {
+    pub base_url: String,
+    pub proxy: Option<String>,
+    pub timeout_read: u64,
+    pub timeout_write: u64,
+    pub stop_gap: usize,
+}
This is supported on crate feature esplora only.
Expand description

Configuration for an EsploraBlockchain

+

Fields

base_url: String

Base URL of the esplora service eg. https://blockstream.info/api/

+
proxy: Option<String>

Optional URL of the proxy to use to make requests to the Esplora server

+

The string should be formatted as: <protocol>://<user>:<password>@host:<port>.

+

Note that the format of this value and the supported protocols change slightly between the +sync version of esplora (using ureq) and the async version (using reqwest). For more +details check with the documentation of the two crates. Both of them are compiled with +the socks feature enabled.

+

The proxy is ignored when targeting wasm32.

+
timeout_read: u64

Socket read timeout.

+
timeout_write: u64

Socket write timeout.

+
stop_gap: usize

Stop searching addresses for transactions after finding an unused gap of this length.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Performs the conversion.

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/struct.EsploraGetHistory.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/struct.EsploraGetHistory.html new file mode 100644 index 0000000000..02fa3f15f5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/struct.EsploraGetHistory.html @@ -0,0 +1,21 @@ +EsploraGetHistory in bdk::blockchain::esplora - Rust

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

pub struct EsploraGetHistory { /* fields omitted */ }
This is supported on crate feature esplora only.
Expand description

Data type used when fetching transaction history from Esplora.

+

Trait Implementations

Deserialize this value from the given Serde deserializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/ureq/struct.EsploraBlockchain.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/ureq/struct.EsploraBlockchain.html new file mode 100644 index 0000000000..9e118ac7a5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/ureq/struct.EsploraBlockchain.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../bdk/blockchain/esplora/struct.EsploraBlockchain.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/ureq/struct.EsploraBlockchainConfig.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/ureq/struct.EsploraBlockchainConfig.html new file mode 100644 index 0000000000..40575d9a80 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/esplora/ureq/struct.EsploraBlockchainConfig.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../bdk/blockchain/esplora/struct.EsploraBlockchainConfig.html...

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

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

pub fn log_progress() -> LogProgress
Expand description

Create a new instance of LogProgress

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

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

pub fn noop_progress() -> NoopProgress
Expand description

Create a new instance of NoopProgress

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

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

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

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/latest/bdk/blockchain/index.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/index.html new file mode 100644 index 0000000000..5f01882fa1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/index.html @@ -0,0 +1,31 @@ +bdk::blockchain - Rust

Module bdk::blockchain[][src]

Expand description

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::compact_filters::CompactFiltersBlockchain;

Modules

+
anyelectrum or esplora or compact_filters or rpc

Runtime-checked blockchain types

+
compact_filterscompact_filters

Compact Filters

+
electrumelectrum

Electrum

+
esploraesplora

Esplora

+

Structs

+

Structure that implements the logic to sync with Esplora

+

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

+

Type that implements Progress and drops every update received

+

Enums

+

Capabilities that can be supported by a Blockchain backend

+

Traits

+
BlockchainNon-WebAssembly and non-async-interface

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

+

Trait for Blockchain types that can be created given a configuration

+

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

+

Functions

+

Create a new instance of LogProgress

+

Create a new instance of NoopProgress

+

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

+

Type Definitions

+

Data sent with a progress update over a channel

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/sidebar-items.js new file mode 100644 index 0000000000..8667824b32 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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 new 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":[["EsploraBlockchain","Structure that implements the logic to sync with Esplora"],["LogProgress","Type that implements [`Progress`] and logs at level `INFO` every update received"],["NoopProgress","Type that implements [`Progress`] and drops every update received"]],"trait":[["Blockchain","Trait that defines the actions that must be supported by 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/latest/bdk/blockchain/struct.EsploraBlockchain.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/struct.EsploraBlockchain.html new file mode 100644 index 0000000000..5dfa8160b6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/struct.EsploraBlockchain.html @@ -0,0 +1,35 @@ +EsploraBlockchain in bdk::blockchain - Rust

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

pub struct EsploraBlockchain { /* fields omitted */ }
Expand description

Structure that implements the logic to sync with Esplora

+

Example

+

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

+

Implementations

This is supported on crate features esplora and ureq only.

Create a new instance of the client from a base URL and the stop_gap.

+
This is supported on crate features esplora and ureq only.

Set the inner ureq agent.

+

Trait Implementations

This is supported on non-WebAssembly and non-crate feature async-interface only.

Return the set of Capability supported by this backend

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

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

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Fetch a transaction from the blockchain given its txid

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Broadcast a transaction

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Return the current height

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

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

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Populate the internal database with transactions and UTXOs Read more

+

Type that contains the configuration

+

Create a new instance given a configuration

+

Formats the value using the given formatter. Read more

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub struct LogProgress;
Expand description

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

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Send a new progress update Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub struct NoopProgress;
Expand description

Type that implements Progress and drops every update received

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Send a new progress update Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub trait Blockchain {
+    fn get_capabilities(&self) -> HashSet<Capability>;
+
fn setup<D: BatchDatabase, P: 'static + Progress>(
        &self,
        database: &mut D,
        progress_update: P
    ) -> Result<(), Error>; +
fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error>; +
fn broadcast(&self, tx: &Transaction) -> Result<(), Error>; +
fn get_height(&self) -> Result<u32, Error>; +
fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error>; + + fn sync<D: BatchDatabase, P: 'static + Progress>(
        &self,
        database: &mut D,
        progress_update: P
    ) -> Result<(), Error> { ... } +}
This is supported on non-WebAssembly and non-crate feature async-interface only.
Expand description

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

+

Required methods

Return the set of Capability supported by this backend

+

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.

+

Fetch a transaction from the blockchain given its txid

+

Broadcast a transaction

+

Return the current height

+

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

+

Provided methods

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.

+

Implementations on Foreign Types

Implementors

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

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

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

Trait for Blockchain types that can be created given a configuration

+

Associated Types

Type that contains the configuration

+

Required methods

Create a new instance given a configuration

+

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/trait.Progress.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/trait.Progress.html new file mode 100644 index 0000000000..7e670cad1a --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/trait.Progress.html @@ -0,0 +1,10 @@ +Progress in bdk::blockchain - Rust

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

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

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

+

Required methods

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.

+

Implementations on Foreign Types

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/blockchain/type.ProgressData.html b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/type.ProgressData.html new file mode 100644 index 0000000000..b00b9f8183 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/blockchain/type.ProgressData.html @@ -0,0 +1,4 @@ +ProgressData in bdk::blockchain - Rust

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

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

Data sent with a progress update over a channel

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

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

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

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

+

Variants

In-memory ephemeral database

+

Tuple Fields of Memory

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

Simple key-value embedded database based on [sled]

+

Tuple Fields of Sled

0: <Tree as BatchDatabase>::Batch
This is supported on crate feature sqlite only.

Sqlite embedded database using [rusqlite]

+

Tuple Fields of Sqlite

0: <SqliteDatabase as BatchDatabase>::Batch

Trait Implementations

Store a script_pubkey along with its keychain and child number.

+

Store a LocalUtxo

+

Store a raw transaction

+

Store the metadata of a transaction

+

Store the last derivation index for a given keychain.

+

Delete a script_pubkey given the keychain and its child number.

+

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

+

Delete a LocalUtxo given its [OutPoint]

+

Delete a raw transaction given its [Txid]

+

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

+

Delete the last derivation index for a keychain.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub enum AnyDatabase {
+    Memory(MemoryDatabase),
+    Sled(Tree),
+    Sqlite(SqliteDatabase),
+}
Expand description

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

+

Tuple Fields of Memory

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

Simple key-value embedded database based on [sled]

+

Tuple Fields of Sled

0: Tree
This is supported on crate feature sqlite only.

Sqlite embedded database using [rusqlite]

+

Tuple Fields of Sqlite

0: SqliteDatabase

Trait Implementations

Container for the operations

+

Create a new batch container

+

Consume and apply a batch of operations

+

Store a script_pubkey along with its keychain and child number.

+

Store a LocalUtxo

+

Store a raw transaction

+

Store the metadata of a transaction

+

Store the last derivation index for a given keychain.

+

Delete a script_pubkey given the keychain and its child number.

+

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

+

Delete a LocalUtxo given its [OutPoint]

+

Delete a raw transaction given its [Txid]

+

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

+

Delete the last derivation index for a keychain.

+

Type that contains the configuration

+

Create a new instance given a configuration

+

Read and checks the descriptor checksum for a given keychain. Read more

+

Return the list of script_pubkeys

+

Return the list of LocalUtxos

+

Return the list of raw transactions

+

Return the list of transactions metadata

+

Fetch a script_pubkey given the child number of a keychain.

+

Fetch the keychain and child number of a given script_pubkey

+

Fetch a LocalUtxo given its [OutPoint]

+

Fetch a raw transaction given its [Txid]

+

Fetch the transaction metadata and optionally also the raw transaction

+

Return the last defivation index for a keychain.

+

Increment the last derivation index for a keychain and return it Read more

+

Force changes to be written to disk

+

Formats the value using the given formatter. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub enum AnyDatabaseConfig {
+    Memory(()),
+    Sled(SledDbConfiguration),
+    Sqlite(SqliteDbConfiguration),
+}
Expand description

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

+

Tuple Fields of Memory

0: ()
This is supported on crate feature key-value-db only.

Simple key-value embedded database based on [sled]

+

Tuple Fields of Sled

0: SledDbConfiguration
This is supported on crate feature sqlite only.

Sqlite embedded database using [rusqlite]

+

Tuple Fields of Sqlite

0: SqliteDbConfiguration

Trait Implementations

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

Expand description

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<(), AnyDatabase>.

+ +
let memory = MemoryDatabase::default();
+let wallet_memory = Wallet::new_offline("...", None, Network::Testnet, memory)?;
+
+let sled = sled::open("my-database")?.open_tree("default_tree")?;
+let wallet_sled = 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 = Wallet::new_offline("...", None, Network::Testnet, database)?;
+

Structs

+

Configuration type for a [sled::Tree] database

+

Configuration type for a sqlite::SqliteDatabase database

+

Enums

+

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

+

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

+

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/latest/bdk/database/any/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/database/any/sidebar-items.js new file mode 100644 index 0000000000..b10a47631b --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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"],["SqliteDbConfiguration","Configuration type for a [`sqlite::SqliteDatabase`] database"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/database/any/struct.SledDbConfiguration.html b/static/docs-rs/bdk/nightly/latest/bdk/database/any/struct.SledDbConfiguration.html new file mode 100644 index 0000000000..5487064bf7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/database/any/struct.SledDbConfiguration.html @@ -0,0 +1,29 @@ +SledDbConfiguration in bdk::database::any - Rust

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

pub struct SledDbConfiguration {
+    pub path: String,
+    pub tree_name: String,
+}
This is supported on crate feature key-value-db only.
Expand description

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

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Performs the conversion.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/database/any/struct.SqliteDbConfiguration.html b/static/docs-rs/bdk/nightly/latest/bdk/database/any/struct.SqliteDbConfiguration.html new file mode 100644 index 0000000000..2d5d6845d5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/database/any/struct.SqliteDbConfiguration.html @@ -0,0 +1,27 @@ +SqliteDbConfiguration in bdk::database::any - Rust

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

pub struct SqliteDbConfiguration {
+    pub path: String,
+}
This is supported on crate feature sqlite only.
Expand description

Configuration type for a sqlite::SqliteDatabase database

+

Fields

path: String

Main directory of the db

+

Trait Implementations

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Performs the conversion.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

Module bdk::database[][src]

Expand description

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

+

Runtime-checked database types

+

In-memory ephemeral database

+

Structs

+

Sqlite database stored on filesystem

+

Traits

+

Trait for a database that supports batch operations

+

Trait for operations that can be batched

+

Trait for Database types that can be created given a configuration

+

Trait for reading data from a database

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

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

Expand description

In-memory ephemeral database

+

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

+

Structs

+

In-memory ephemeral database

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/database/memory/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/database/memory/sidebar-items.js new file mode 100644 index 0000000000..665f6718d0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/database/memory/struct.MemoryDatabase.html b/static/docs-rs/bdk/nightly/latest/bdk/database/memory/struct.MemoryDatabase.html new file mode 100644 index 0000000000..afb930e59e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/database/memory/struct.MemoryDatabase.html @@ -0,0 +1,60 @@ +MemoryDatabase in bdk::database::memory - Rust

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

pub struct MemoryDatabase { /* fields omitted */ }
Expand description

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

Create a new empty database

+

Trait Implementations

Container for the operations

+

Create a new batch container

+

Consume and apply a batch of operations

+

Store a script_pubkey along with its keychain and child number.

+

Store a LocalUtxo

+

Store a raw transaction

+

Store the metadata of a transaction

+

Store the last derivation index for a given keychain.

+

Delete a script_pubkey given the keychain and its child number.

+

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

+

Delete a LocalUtxo given its [OutPoint]

+

Delete a raw transaction given its [Txid]

+

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

+

Delete the last derivation index for a keychain.

+

Type that contains the configuration

+

Create a new instance given a configuration

+

Read and checks the descriptor checksum for a given keychain. Read more

+

Return the list of script_pubkeys

+

Return the list of LocalUtxos

+

Return the list of raw transactions

+

Return the list of transactions metadata

+

Fetch a script_pubkey given the child number of a keychain.

+

Fetch the keychain and child number of a given script_pubkey

+

Fetch a LocalUtxo given its [OutPoint]

+

Fetch a raw transaction given its [Txid]

+

Fetch the transaction metadata and optionally also the raw transaction

+

Return the last defivation index for a keychain.

+

Increment the last derivation index for a keychain and return it Read more

+

Force changes to be written to disk

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/database/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/database/sidebar-items.js new file mode 100644 index 0000000000..3856fe121b --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/database/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"mod":[["any","Runtime-checked database types"],["memory","In-memory ephemeral database"]],"struct":[["SqliteDatabase","Sqlite database stored on filesystem"]],"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/latest/bdk/database/sqlite/struct.SqliteDatabase.html b/static/docs-rs/bdk/nightly/latest/bdk/database/sqlite/struct.SqliteDatabase.html new file mode 100644 index 0000000000..803ba38ba6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/database/sqlite/struct.SqliteDatabase.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/database/struct.SqliteDatabase.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/database/struct.SqliteDatabase.html b/static/docs-rs/bdk/nightly/latest/bdk/database/struct.SqliteDatabase.html new file mode 100644 index 0000000000..58d0996b9e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/database/struct.SqliteDatabase.html @@ -0,0 +1,62 @@ +SqliteDatabase in bdk::database - Rust

Struct bdk::database::SqliteDatabase[][src]

pub struct SqliteDatabase {
+    pub path: String,
+    pub connection: Connection,
+}
Expand description

Sqlite database stored on filesystem

+

This is a permanent storage solution for devices and platforms that provide a filesystem. +crate::database

+

Fields

path: String

Path on the local filesystem to store the sqlite file

+
connection: Connection

A rusqlite connection object to the sqlite database

+

Implementations

This is supported on crate feature sqlite only.

Instantiate a new SqliteDatabase instance by creating a connection +to the database stored at path

+

Trait Implementations

Container for the operations

+

Create a new batch container

+

Consume and apply a batch of operations

+

Store a script_pubkey along with its keychain and child number.

+

Store a LocalUtxo

+

Store a raw transaction

+

Store the metadata of a transaction

+

Store the last derivation index for a given keychain.

+

Delete a script_pubkey given the keychain and its child number.

+

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

+

Delete a LocalUtxo given its [OutPoint]

+

Delete a raw transaction given its [Txid]

+

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

+

Delete the last derivation index for a keychain.

+

Type that contains the configuration

+

Create a new instance given a configuration

+

Read and checks the descriptor checksum for a given keychain. Read more

+

Return the list of script_pubkeys

+

Return the list of LocalUtxos

+

Return the list of raw transactions

+

Return the list of transactions metadata

+

Fetch a script_pubkey given the child number of a keychain.

+

Fetch the keychain and child number of a given script_pubkey

+

Fetch a LocalUtxo given its [OutPoint]

+

Fetch a raw transaction given its [Txid]

+

Fetch the transaction metadata and optionally also the raw transaction

+

Return the last defivation index for a keychain.

+

Increment the last derivation index for a keychain and return it Read more

+

Force changes to be written to disk

+

Formats the value using the given formatter. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/database/trait.BatchDatabase.html b/static/docs-rs/bdk/nightly/latest/bdk/database/trait.BatchDatabase.html new file mode 100644 index 0000000000..acbea968b7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/database/trait.BatchDatabase.html @@ -0,0 +1,12 @@ +BatchDatabase in bdk::database - Rust

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

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

Trait for a database that supports batch operations

+

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

+

Associated Types

Container for the operations

+

Required methods

Create a new batch container

+

Consume and apply a batch of operations

+

Implementations on Foreign Types

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/database/trait.BatchOperations.html b/static/docs-rs/bdk/nightly/latest/bdk/database/trait.BatchOperations.html new file mode 100644 index 0000000000..cc5faecac2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/database/trait.BatchOperations.html @@ -0,0 +1,30 @@ +BatchOperations in bdk::database - Rust

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

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

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

Store a script_pubkey along with its keychain and child number.

+

Store a LocalUtxo

+

Store a raw transaction

+

Store the metadata of a transaction

+

Store the last derivation index for a given keychain.

+

Delete a script_pubkey given the keychain and its child number.

+

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

+

Delete a LocalUtxo given its [OutPoint]

+

Delete a raw transaction given its [Txid]

+

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

+

Delete the last derivation index for a keychain.

+

Implementations on Foreign Types

Implementors

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

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

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

Trait for Database types that can be created given a configuration

+

Associated Types

Type that contains the configuration

+

Required methods

Create a new instance given a configuration

+

Implementations on Foreign Types

Implementors

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

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

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

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

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.

+

Return the list of script_pubkeys

+

Return the list of LocalUtxos

+

Return the list of raw transactions

+

Return the list of transactions metadata

+

Fetch a script_pubkey given the child number of a keychain.

+

Fetch the keychain and child number of a given script_pubkey

+

Fetch a LocalUtxo given its [OutPoint]

+

Fetch a raw transaction given its [Txid]

+

Fetch the transaction metadata and optionally also the raw transaction

+

Return the last defivation index for a keychain.

+

Increment the last derivation index for a keychain and return it

+

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

+

Force changes to be written to disk

+

Implementations on Foreign Types

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/checksum/fn.get_checksum.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/checksum/fn.get_checksum.html new file mode 100644 index 0000000000..55ce0b83b6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/checksum/fn.get_checksum.html @@ -0,0 +1,4 @@ +get_checksum in bdk::descriptor::checksum - Rust

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

pub fn get_checksum(desc: &str) -> Result<String, DescriptorError>
Expand description

Compute the checksum of a descriptor

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

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

Expand description

Descriptor checksum

+

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

+

Functions

+

Compute the checksum of a descriptor

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/checksum/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/checksum/sidebar-items.js new file mode 100644 index 0000000000..e1add094a5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/descriptor/derived/enum.Descriptor.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.Descriptor.html new file mode 100644 index 0000000000..d0003f40ac --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.Descriptor.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/descriptor/enum.Descriptor.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.DescriptorPublicKey.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.DescriptorPublicKey.html new file mode 100644 index 0000000000..05f9388e84 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.DescriptorPublicKey.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/keys/enum.DescriptorPublicKey.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.Legacy.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.Legacy.html new file mode 100644 index 0000000000..fb2dd3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.Legacy.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/descriptor/enum.Legacy.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.Segwitv0.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.Segwitv0.html new file mode 100644 index 0000000000..194aba17ab --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/enum.Segwitv0.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/descriptor/enum.Segwitv0.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/struct.DerivedDescriptorKey.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/struct.DerivedDescriptorKey.html new file mode 100644 index 0000000000..3d9e091385 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/struct.DerivedDescriptorKey.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/descriptor/struct.DerivedDescriptorKey.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/struct.Miniscript.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/struct.Miniscript.html new file mode 100644 index 0000000000..ca1ccb5a6e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/struct.Miniscript.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/descriptor/struct.Miniscript.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/trait.ScriptContext.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/trait.ScriptContext.html new file mode 100644 index 0000000000..08af1d1289 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/trait.ScriptContext.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/keys/trait.ScriptContext.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/type.KeyMap.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/type.KeyMap.html new file mode 100644 index 0000000000..2fdaa9d33d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/derived/type.KeyMap.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/keys/type.KeyMap.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/enum.Descriptor.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/enum.Descriptor.html new file mode 100644 index 0000000000..366ed8501c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/enum.Descriptor.html @@ -0,0 +1,153 @@ +Descriptor in bdk::descriptor - Rust

Enum bdk::descriptor::Descriptor[]

pub enum Descriptor<Pk> where
    Pk: MiniscriptKey, 
{ + Bare(Bare<Pk>), + Pkh(Pkh<Pk>), + Wpkh(Wpkh<Pk>), + Sh(Sh<Pk>), + Wsh(Wsh<Pk>), +}
Expand description

Script descriptor

+

Variants

Bare(Bare<Pk>)

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

+

Tuple Fields of Bare

0: Bare<Pk>
Pkh(Pkh<Pk>)

Pay-to-PubKey-Hash

+

Tuple Fields of Pkh

0: Pkh<Pk>
Wpkh(Wpkh<Pk>)

Pay-to-Witness-PubKey-Hash

+

Tuple Fields of Wpkh

0: Wpkh<Pk>
Sh(Sh<Pk>)

Pay-to-ScriptHash(includes nested wsh/wpkh/sorted multi)

+

Tuple Fields of Sh

0: Sh<Pk>
Wsh(Wsh<Pk>)

Pay-to-Witness-ScriptHash with Segwitv0 context

+

Tuple Fields of Wsh

0: Wsh<Pk>

Implementations

Create a new pk descriptor

+

Create a new PkH descriptor

+

Create a new Wpkh descriptor +Will return Err if uncompressed key is used

+

Create a new sh wrapped wpkh from Pk. +Errors when uncompressed keys are supplied

+

Create a new sh for a given redeem script +Errors when miniscript exceeds resource limits under p2sh context +or does not type check at the top level

+

Create a new wsh descriptor from witness script +Errors when miniscript exceeds resource limits under p2sh context +or does not type check at the top level

+

Create a new sh wrapped wsh descriptor with witness script +Errors when miniscript exceeds resource limits under wsh context +or does not type check at the top level

+

Create a new bare descriptor from witness script +Errors when miniscript exceeds resource limits under bare context +or does not type check at the top level

+

Create a new sh sortedmulti descriptor with threshold k +and Vec of pks. +Errors when miniscript exceeds resource limits under p2sh context

+

Create a new sh wrapped wsh sortedmulti descriptor from threshold +k and Vec of pks +Errors when miniscript exceeds resource limits under segwit context

+

Create a new wsh sorted multi descriptor +Errors when miniscript exceeds resource limits under p2sh context

+

Get the [DescriptorType] of Descriptor

+

Whether or not the descriptor has any wildcards

+

Derives all wildcard keys in the descriptor using the supplied index

+

Panics if given an index ≥ 2^31

+

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.

+

Serialize a descriptor to string with its secret keys

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

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

+

Computes the Bitcoin address of the descriptor, if one exists

+

Computes the scriptpubkey of the descriptor

+

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).

+

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.

+

Returns satisfying witness and scriptSig to spend an +output controlled by the given descriptor if it possible to +construct one using the satisfier S.

+

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.

+

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.

+

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. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Formats the value using the given formatter. Read more

+

Extract the spending policy

+

Run a predicate on every key in the descriptor, returning whether +the predicate returned true for every key Read more

+

Run a predicate on every key in the descriptor, returning whether +the predicate returned true for any key Read more

+

The associated error which can be returned from parsing.

+

Parses a string s to return a value of this type. Read more

+

Parse an expression tree into a descriptor

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

Convert the object into an abstract policy

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Serialize this value into the given Serde serializer. Read more

+

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.

+

The associated output type. This must be Self

+

Calls translate_pk with conversion functions that cannot fail

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

Enum bdk::descriptor::Legacy[]

pub enum Legacy {}
Expand description

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

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

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. Read more

+

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. Read more

+

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. Read more

+

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. Read more

+

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 Read more

+

Depending on script context, the size of a satifaction witness may slightly differ.

+

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. Read more

+

Check the consensus + policy(if not disabled) rules that are not based +satisfaction Read more

+

Check the consensus + policy(if not disabled) rules including the +ones for satisfaction Read more

+

Check whether the top-level is type B

+

Other top level checks that are context specific

+

Check top level consensus rules.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the ScriptContext as a ScriptContextEnum

+

Returns whether the script context is Legacy

+

Returns whether the script context is Segwitv0

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

Enum bdk::descriptor::Segwitv0[]

pub enum Segwitv0 {}
Expand description

Segwitv0 ScriptContext

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

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. Read more

+

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. Read more

+

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. Read more

+

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. Read more

+

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. Read more

+

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 Read more

+

Depending on script context, the size of a satifaction witness may slightly differ.

+

Check the consensus + policy(if not disabled) rules that are not based +satisfaction Read more

+

Check the consensus + policy(if not disabled) rules including the +ones for satisfaction Read more

+

Check whether the top-level is type B

+

Other top level checks that are context specific

+

Check top level consensus rules.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the ScriptContext as a ScriptContextEnum

+

Returns whether the script context is Legacy

+

Returns whether the script context is Segwitv0

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub enum Error {
+    InvalidHdKeyPath,
+    InvalidDescriptorChecksum,
+    HardenedDerivationXpub,
+    DuplicatedKeys,
+    Key(KeyError),
+    Policy(PolicyError),
+    InvalidDescriptorCharacter(char),
+    Bip32(Error),
+    Base58(Error),
+    Pk(Error),
+    Miniscript(Error),
+    Hex(Error),
+}
Expand description

Errors related to the parsing and usage of descriptors

+

Variants

InvalidHdKeyPath

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

+
InvalidDescriptorChecksum

The provided descriptor doesn’t match its checksum

+
HardenedDerivationXpub

The descriptor contains hardened derivation steps on public extended keys

+
DuplicatedKeys

The descriptor contains multiple keys with the same BIP32 fingerprint

+

Error thrown while working with keys

+

Tuple Fields of Key

0: KeyError
Policy(PolicyError)

Error while extracting and manipulating policies

+

Tuple Fields of Policy

0: PolicyError
InvalidDescriptorCharacter(char)

Invalid character found in the descriptor checksum

+

Tuple Fields of InvalidDescriptorCharacter

0: char
Bip32(Error)

BIP32 error

+

Tuple Fields of Bip32

0: Error
Base58(Error)

Error during base58 decoding

+

Tuple Fields of Base58

0: Error
Pk(Error)

Key-related error

+

Tuple Fields of Pk

0: Error
Miniscript(Error)

Miniscript error

+

Tuple Fields of Miniscript

0: Error
Hex(Error)

Hex decoding error

+

Tuple Fields of Hex

0: Error

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Converts a reference to Self into a dynamic trait object of Fail.

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the “name” of the error. Read more

+

Returns a reference to the underlying cause of this failure, if it +is an error that wraps other errors. Read more

+

Returns a reference to the Backtrace carried by this failure, if it +carries one. Read more

+

Provides context for this failure. Read more

+

Wraps this failure in a compatibility wrapper that implements +std::error::Error. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

Expand description

Descriptor errors

+

Enums

+

Errors related to the parsing and usage of descriptors

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/error/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/error/sidebar-items.js new file mode 100644 index 0000000000..1ad99d4faf --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/descriptor/index.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/index.html new file mode 100644 index 0000000000..7771e2fbb5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/index.html @@ -0,0 +1,35 @@ +bdk::descriptor - Rust

Module bdk::descriptor[][src]

Expand description

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::error::Error as DescriptorError;
pub use self::policy::Policy;

Modules

+

Descriptor checksum

+

Descriptor errors

+

Descriptor policy

+

Descriptor templates

+

Structs

+

Extended DescriptorPublicKey that has been derived

+

Top-level script AST type

+

Enums

+

Script descriptor

+

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

+

Segwitv0 ScriptContext

+

Traits

+

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

+

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

+

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

+

Type Definitions

+

Alias for a Descriptor that contains extended derived keys

+

Alias for a Descriptor that can contain extended keys using DescriptorPublicKey

+

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

+

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/latest/bdk/descriptor/policy/enum.BuildSatisfaction.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/policy/enum.BuildSatisfaction.html new file mode 100644 index 0000000000..fd9eddbd4f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/policy/enum.BuildSatisfaction.html @@ -0,0 +1,42 @@ +BuildSatisfaction in bdk::descriptor::policy - Rust

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

pub enum BuildSatisfaction<'a> {
+    None,
+    Psbt(&'a Psbt),
+    PsbtTimelocks {
+        psbt: &'a Psbt,
+        current_height: u32,
+        input_max_height: u32,
+    },
+}
Expand description

Options to build the satisfaction field in the policy

+

Variants

None

Don’t generate satisfaction field

+
Psbt(&'a Psbt)

Analyze the given PSBT to check for existing signatures

+

Tuple Fields of Psbt

0: &'a Psbt
PsbtTimelocks

Like Psbt variant and also check for expired timelocks

+

Fields of PsbtTimelocks

psbt: &'a Psbt

Given PSBT

+
current_height: u32

Current blockchain height

+
input_max_height: u32

The highest confirmation height between the inputs +CSV should consider different inputs, but we consider the worst condition for the tx as whole

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

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

Errors that can happen while extracting and manipulating policies

+

Variants

NotEnoughItemsSelected(String)

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

+

Tuple Fields of NotEnoughItemsSelected

0: String
IndexOutOfRange(usize)

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

+

Tuple Fields of IndexOutOfRange

0: usize
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

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

Performs the conversion.

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Converts a reference to Self into a dynamic trait object of Fail.

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the “name” of the error. Read more

+

Returns a reference to the underlying cause of this failure, if it +is an error that wraps other errors. Read more

+

Returns a reference to the Backtrace carried by this failure, if it +carries one. Read more

+

Provides context for this failure. Read more

+

Wraps this failure in a compatibility wrapper that implements +std::error::Error. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

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,
+}
Expand description

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 or are satisfied in the PSBT

+
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

Returns whether the Satisfaction is a leaf item

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Performs the conversion.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

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,
+    },
+}
Expand description

An item that needs to be satisfied

+

Variants

Signature(PkOrF)

Signature for a raw public key

+

Tuple Fields of Signature

0: PkOrF
SignatureKey(PkOrF)

Signature for an extended key fingerprint

+

Tuple Fields of SignatureKey

0: PkOrF
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

Returns whether the SatisfiableItem is a leaf item

+

Returns a unique id for the SatisfiableItem

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Performs the conversion.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

Expand description

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 bdk::descriptor::policy::BuildSatisfaction;
+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(&secp, desc)?;
+println!("{:?}", extended_desc);
+
+let signers = Arc::new(key_map.into());
+let policy = extended_desc.extract_policy(&signers, BuildSatisfaction::None, &secp)?;
+println!("policy: {}", serde_json::to_string(&policy)?);
+

Structs

+

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

+

Raw public key or extended key fingerprint

+

Descriptor spending policy

+

Enums

+

Options to build the satisfaction field in the policy

+

Errors that can happen while extracting and manipulating policies

+

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

+

An item that needs to be satisfied

+

Type Definitions

+

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

+

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/latest/bdk/descriptor/policy/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/policy/sidebar-items.js new file mode 100644 index 0000000000..40fd0e48aa --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/policy/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["BuildSatisfaction","Options to build the satisfaction field in the policy"],["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/latest/bdk/descriptor/policy/struct.Condition.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/policy/struct.Condition.html new file mode 100644 index 0000000000..a4bbaf39da --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/policy/struct.Condition.html @@ -0,0 +1,51 @@ +Condition in bdk::descriptor::policy - Rust

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

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

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

Returns true if there are no extra conditions to verify

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub struct PkOrF { /* fields omitted */ }
Expand description

Raw public key or extended key fingerprint

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

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

Descriptor spending policy

+

Fields

id: String

Identifier for this policy node

+
item: SatisfiableItem

Type of this policy node

+
satisfaction: Satisfaction

How much a given PSBT already satisfies this policy node in terms of signatures

+
contribution: Satisfaction

How the wallet’s descriptor can satisfy this policy node

+

Implementations

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.

+

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

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Performs the conversion.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

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

pub type ConditionMap = BTreeMap<usize, HashSet<Condition>>;
Expand description

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/latest/bdk/descriptor/policy/type.FoldedConditionMap.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/policy/type.FoldedConditionMap.html new file mode 100644 index 0000000000..a878b45589 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/policy/type.FoldedConditionMap.html @@ -0,0 +1,4 @@ +FoldedConditionMap in bdk::descriptor::policy - Rust

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

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

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/latest/bdk/descriptor/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/sidebar-items.js new file mode 100644 index 0000000000..e324d2a835 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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"]],"mod":[["checksum","Descriptor checksum"],["error","Descriptor errors"],["policy","Descriptor policy"],["template","Descriptor templates"]],"struct":[["DerivedDescriptorKey","Extended [`DescriptorPublicKey`] that has been derived"],["Miniscript","Top-level script AST type"]],"trait":[["ExtractPolicy","Trait implemented on [`Descriptor`]s to add a method to extract the spending [`policy`]"],["IntoWalletDescriptor","Trait for types which can be converted into an [`ExtendedDescriptor`] and a [`KeyMap`] usable by a wallet in a specific [`Network`]"],["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"]],"type":[["DerivedDescriptor","Alias for a [`Descriptor`] that contains extended derived keys"],["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/latest/bdk/descriptor/struct.DerivedDescriptorKey.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/struct.DerivedDescriptorKey.html new file mode 100644 index 0000000000..0d11c92705 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/struct.DerivedDescriptorKey.html @@ -0,0 +1,71 @@ +DerivedDescriptorKey in bdk::descriptor - Rust

Struct bdk::descriptor::DerivedDescriptorKey[][src]

pub struct DerivedDescriptorKey<'s>(_, _);
Expand description

Extended DescriptorPublicKey that has been derived

+

Derived keys are guaranteed to never contain wildcards of any kind

+

Implementations

Construct a new derived key

+

Panics if the key is wildcard

+

Methods from Deref<Target = DescriptorPublicKey>

The fingerprint of the master key associated with this key

+

Full path, from the master key

+

For wildcard keys this will return the path up to the wildcard, so you +can get full paths by appending one additional derivation step, according +to the wildcard type (hardened or normal)

+

Whether or not the key has a wildcards

+

Computes the public key corresponding to this descriptor key

+

Will return an error if the descriptor key has any hardened +derivation steps in its path, or if the key has any wildcards.

+

To ensure there are no wildcards, call .derive(0) or similar; +to avoid hardened derivation steps, start from a DescriptorSecretKey +and call as_public, or call TranslatePk2::translate_pk2 with +some function which has access to secret key data.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

The resulting type after dereferencing.

+

Dereferences the value.

+

Formats the value using the given formatter. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

The associated Hash type with the publicKey

+

Converts an object to PublicHash

+

Check if the publicKey is uncompressed. The default +implementation returns false Read more

+

Computes the size of a public key when serialized in a script, +including the length bytes Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Converts an object to a public key

+

Converts a hashed version of the public key to a hash160 hash. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/struct.Miniscript.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/struct.Miniscript.html new file mode 100644 index 0000000000..ee6aa89e4d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/struct.Miniscript.html @@ -0,0 +1,215 @@ +Miniscript in bdk::descriptor - Rust

Struct bdk::descriptor::Miniscript[]

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

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

Whether all spend paths of miniscript require a signature

+

Whether the miniscript is malleable

+

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

+

Whether the miniscript contains a combination of timelocks

+

Whether the miniscript has repeated Pk or Pkh

+

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

+

Iterator-related extensions for Miniscript

+

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.

+

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.

+

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.

+

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.

+

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

+

Returns child node with given index, if any

+

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 Miniscript::iter_pk() function, for example +miniscript.iter_pubkeys().collect().

+

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 Miniscript::iter_pkh() function, +for example miniscript.iter_pubkey_hashes().collect().

+

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 Miniscript::iter_pk_pkh() +function, for example miniscript.iter_pubkeys_and_hashes().collect().

+

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.

+

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.

+

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.

+

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.

+

Extracts the AstElem representing the root of the miniscript

+

Get a reference to the inner AstElem representing the root of miniscript

+

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.

+

Attempt to parse a Script into Miniscript representation. +This function will fail parsing for scripts that do not clear +the Miniscript::sanity_check checks. Use Miniscript::parse_insane to +parse such scripts.

+

Encode as a Bitcoin script

+

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.

+

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 returns Error when the Miniscript is +impossible to satisfy

+

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.

+

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.

+

Attempt to produce non-malleable satisfying witness for the +witness script represented by the parse tree

+

Attempt to produce a malleable satisfying witness for the +witness script represented by the parse tree

+

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

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Formats the value using the given formatter. Read more

+

Extract the spending policy

+

Run a predicate on every key in the descriptor, returning whether +the predicate returned true for every key Read more

+

Run a predicate on every key in the descriptor, returning whether +the predicate returned true for any key Read more

+

Parse a Miniscript from string and perform sanity checks +See Miniscript::from_str_insane to parse scripts from string that +do not clear the Miniscript::sanity_check checks.

+

The associated error which can be returned from parsing.

+

Parses a string s to return a value of this type. Read more

+

Parse an expression tree into a Miniscript. As a general rule, this +should not be called directly; rather go through the descriptor API.

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

Convert the object into an abstract policy

+

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.

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

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.

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

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.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Serialize this value into the given Serde serializer. Read more

+

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.

+

The associated output type. This must be Self

+

Calls translate_pk with conversion functions that cannot fail

+

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.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

Translate a struct from one generic to another where the +translation for Pk is provided by translatefpk Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

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

Module bdk::descriptor::template[][src]

Expand description

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 template. Expands to pkh(key/44'/0'/0'/{0,1}/*)

+

BIP44 public template. Expands to pkh(key/{0,1}/*)

+

BIP49 template. Expands to sh(wpkh(key/49'/0'/0'/{0,1}/*))

+

BIP49 public template. Expands to sh(wpkh(key/{0,1}/*))

+

BIP84 template. Expands to wpkh(key/84'/0'/0'/{0,1}/*)

+

BIP84 public template. Expands to wpkh(key/{0,1}/*)

+

P2PKH template. Expands to a descriptor pkh(key)

+

P2WPKH template. Expands to a descriptor wpkh(key)

+

P2WPKH-P2SH template. Expands to a descriptor sh(wpkh(key))

+

Traits

+

Trait for descriptor templates that can be built into a full descriptor

+

Type Definitions

+

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/latest/bdk/descriptor/template/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/sidebar-items.js new file mode 100644 index 0000000000..4ea3e793ef --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/descriptor/template/struct.Bip44.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip44.html new file mode 100644 index 0000000000..049e971472 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip44.html @@ -0,0 +1,37 @@ +Bip44 in bdk::descriptor::template - Rust

Struct bdk::descriptor::template::Bip44[][src]

pub struct Bip44<K: DerivableKey<Legacy>>(pub K, pub KeychainKind);
Expand description

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 = Wallet::new_offline(
+    Bip44(key.clone(), KeychainKind::External),
+    Some(Bip44(key, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_address(New)?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)#xgaaevjx");
+

Tuple Fields

0: K1: KeychainKind

Trait Implementations

Build the complete descriptor

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Convert to wallet descriptor

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip44Public.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip44Public.html new file mode 100644 index 0000000000..b104d4b18e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip44Public.html @@ -0,0 +1,40 @@ +Bip44Public in bdk::descriptor::template - Rust

Struct bdk::descriptor::template::Bip44Public[][src]

pub struct Bip44Public<K: DerivableKey<Legacy>>(pub K, pub Fingerprint, pub KeychainKind);
Expand description

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 = Wallet::new_offline(
+    Bip44Public(key.clone(), fingerprint, KeychainKind::External),
+    Some(Bip44Public(key, fingerprint, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_address(New)?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)#xgaaevjx");
+

Tuple Fields

0: K1: Fingerprint2: KeychainKind

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Convert to wallet descriptor

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip49.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip49.html new file mode 100644 index 0000000000..4707817ec7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip49.html @@ -0,0 +1,37 @@ +Bip49 in bdk::descriptor::template - Rust

Struct bdk::descriptor::template::Bip49[][src]

pub struct Bip49<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
Expand description

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 = Wallet::new_offline(
+    Bip49(key.clone(), KeychainKind::External),
+    Some(Bip49(key, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_address(New)?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))#gsmdv4xr");
+

Tuple Fields

0: K1: KeychainKind

Trait Implementations

Build the complete descriptor

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Convert to wallet descriptor

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip49Public.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip49Public.html new file mode 100644 index 0000000000..abf1c849fb --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip49Public.html @@ -0,0 +1,40 @@ +Bip49Public in bdk::descriptor::template - Rust

Struct bdk::descriptor::template::Bip49Public[][src]

pub struct Bip49Public<K: DerivableKey<Segwitv0>>(pub K, pub Fingerprint, pub KeychainKind);
Expand description

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 = Wallet::new_offline(
+    Bip49Public(key.clone(), fingerprint, KeychainKind::External),
+    Some(Bip49Public(key, fingerprint, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_address(New)?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))#gsmdv4xr");
+

Tuple Fields

0: K1: Fingerprint2: KeychainKind

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Convert to wallet descriptor

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip84.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip84.html new file mode 100644 index 0000000000..53b76daa92 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip84.html @@ -0,0 +1,37 @@ +Bip84 in bdk::descriptor::template - Rust

Struct bdk::descriptor::template::Bip84[][src]

pub struct Bip84<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
Expand description

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 = Wallet::new_offline(
+    Bip84(key.clone(), KeychainKind::External),
+    Some(Bip84(key, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_address(New)?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#nkk5dtkg");
+

Tuple Fields

0: K1: KeychainKind

Trait Implementations

Build the complete descriptor

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Convert to wallet descriptor

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip84Public.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip84Public.html new file mode 100644 index 0000000000..3526efa0e8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.Bip84Public.html @@ -0,0 +1,40 @@ +Bip84Public in bdk::descriptor::template - Rust

Struct bdk::descriptor::template::Bip84Public[][src]

pub struct Bip84Public<K: DerivableKey<Segwitv0>>(pub K, pub Fingerprint, pub KeychainKind);
Expand description

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 = Wallet::new_offline(
+    Bip84Public(key.clone(), fingerprint, KeychainKind::External),
+    Some(Bip84Public(key, fingerprint, KeychainKind::Internal)),
+    Network::Testnet,
+    MemoryDatabase::default()
+)?;
+
+assert_eq!(wallet.get_address(New)?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7");
+assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#nkk5dtkg");
+

Tuple Fields

0: K1: Fingerprint2: KeychainKind

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Convert to wallet descriptor

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.P2Pkh.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.P2Pkh.html new file mode 100644 index 0000000000..52abbfd944 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.P2Pkh.html @@ -0,0 +1,38 @@ +P2Pkh in bdk::descriptor::template - Rust

Struct bdk::descriptor::template::P2Pkh[][src]

pub struct P2Pkh<K: IntoDescriptorKey<Legacy>>(pub K);
Expand description

P2PKH template. Expands to a descriptor pkh(key)

+

Example

+
use bdk::template::P2Pkh;
+
+let key =
+    bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+let wallet = Wallet::new_offline(
+    P2Pkh(key),
+    None,
+    Network::Testnet,
+    MemoryDatabase::default(),
+)?;
+
+assert_eq!(
+    wallet.get_address(New)?.to_string(),
+    "mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT"
+);
+

Tuple Fields

0: K

Trait Implementations

Build the complete descriptor

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Convert to wallet descriptor

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.P2Wpkh.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.P2Wpkh.html new file mode 100644 index 0000000000..6d1385ea37 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.P2Wpkh.html @@ -0,0 +1,38 @@ +P2Wpkh in bdk::descriptor::template - Rust

Struct bdk::descriptor::template::P2Wpkh[][src]

pub struct P2Wpkh<K: IntoDescriptorKey<Segwitv0>>(pub K);
Expand description

P2WPKH template. Expands to a descriptor wpkh(key)

+

Example

+
use bdk::template::P2Wpkh;
+
+let key =
+    bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+let wallet = Wallet::new_offline(
+    P2Wpkh(key),
+    None,
+    Network::Testnet,
+    MemoryDatabase::default(),
+)?;
+
+assert_eq!(
+    wallet.get_address(New)?.to_string(),
+    "tb1q4525hmgw265tl3drrl8jjta7ayffu6jf68ltjd"
+);
+

Tuple Fields

0: K

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Convert to wallet descriptor

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.P2Wpkh_P2Sh.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.P2Wpkh_P2Sh.html new file mode 100644 index 0000000000..bfa70c67d5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/struct.P2Wpkh_P2Sh.html @@ -0,0 +1,38 @@ +P2Wpkh_P2Sh in bdk::descriptor::template - Rust

Struct bdk::descriptor::template::P2Wpkh_P2Sh[][src]

pub struct P2Wpkh_P2Sh<K: IntoDescriptorKey<Segwitv0>>(pub K);
Expand description

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 = Wallet::new_offline(
+    P2Wpkh_P2Sh(key),
+    None,
+    Network::Testnet,
+    MemoryDatabase::default(),
+)?;
+
+assert_eq!(
+    wallet.get_address(New)?.to_string(),
+    "2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5"
+);
+

Tuple Fields

0: K

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Convert to wallet descriptor

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/trait.DescriptorTemplate.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/trait.DescriptorTemplate.html new file mode 100644 index 0000000000..5c1f6f02f2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/template/trait.DescriptorTemplate.html @@ -0,0 +1,22 @@ +DescriptorTemplate in bdk::descriptor::template - Rust

Trait bdk::descriptor::template::DescriptorTemplate[][src]

pub trait DescriptorTemplate {
+    fn build(self) -> Result<DescriptorTemplateOut, DescriptorError>;
+}
Expand description

Trait for descriptor templates that can be built into a full descriptor

+

Since IntoWalletDescriptor is implemented for any DescriptorTemplate, they can also be +passed directly to the Wallet constructor.

+

Example

+
use bdk::descriptor::error::Error as DescriptorError;
+use bdk::keys::{IntoDescriptorKey, KeyError};
+use bdk::miniscript::Legacy;
+use bdk::template::{DescriptorTemplate, DescriptorTemplateOut};
+
+struct MyP2PKH<K: IntoDescriptorKey<Legacy>>(K);
+
+impl<K: IntoDescriptorKey<Legacy>> DescriptorTemplate for MyP2PKH<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
+        Ok(bdk::descriptor!(pkh(self.0))?)
+    }
+}
+

Required methods

Build the complete descriptor

+

Implementors

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

Type Definition bdk::descriptor::template::DescriptorTemplateOut[][src]

pub type DescriptorTemplateOut = (ExtendedDescriptor, KeyMap, ValidNetworks);
Expand description

Type alias for the return type of DescriptorTemplate, descriptor! and others

+

Trait Implementations

Convert to wallet descriptor

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

Trait bdk::descriptor::ExtractPolicy[][src]

pub trait ExtractPolicy {
+    fn extract_policy(
        &self,
        signers: &SignersContainer,
        psbt: BuildSatisfaction<'_>,
        secp: &Secp256k1<All>
    ) -> Result<Option<Policy>, DescriptorError>; +}
Expand description

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

+

Required methods

Extract the spending policy

+

Implementors

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

Trait bdk::descriptor::IntoWalletDescriptor[][src]

pub trait IntoWalletDescriptor {
+    fn into_wallet_descriptor(
        self,
        secp: &Secp256k1<All>,
        network: Network
    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError>; +}
Expand description

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

+

Required methods

Convert to wallet descriptor

+

Implementations on Foreign Types

Implementors

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

Trait bdk::descriptor::ScriptContext[]

pub trait ScriptContext: Debug + Clone + Ord + PartialOrd<Self> + Eq + PartialEq<Self> + Hash + Sealed {
+    fn check_terminal_non_malleable<Pk, Ctx>(
        _frag: &Terminal<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
; +
fn max_satisfaction_size<Pk, Ctx>(ms: &Miniscript<Pk, Ctx>) -> Option<usize>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
; + + fn check_witness<Pk, Ctx>(
        _witness: &[Vec<u8, Global>]
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_global_consensus_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_global_policy_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_local_consensus_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_local_policy_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_global_validity<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_local_validity<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn top_level_type_check<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn other_top_level_checks<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn top_level_checks<Pk, Ctx>(ms: &Miniscript<Pk, Ctx>) -> Result<(), Error>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +}
Expand description

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

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.

+

Depending on script context, the size of a satifaction witness may slightly differ.

+

Provided methods

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.

+

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.

+

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.

+

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.

+

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

+

Check the consensus + policy(if not disabled) rules that are not based +satisfaction

+

Check the consensus + policy(if not disabled) rules including the +ones for satisfaction

+

Check whether the top-level is type B

+

Other top level checks that are context specific

+

Check top level consensus rules.

+

Implementations on Foreign Types

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/descriptor/type.DerivedDescriptor.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/type.DerivedDescriptor.html new file mode 100644 index 0000000000..97508febab --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/type.DerivedDescriptor.html @@ -0,0 +1,4 @@ +DerivedDescriptor in bdk::descriptor - Rust

Type Definition bdk::descriptor::DerivedDescriptor[][src]

pub type DerivedDescriptor<'s> = Descriptor<DerivedDescriptorKey<'s>>;
Expand description

Alias for a Descriptor that contains extended derived keys

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

Type Definition bdk::descriptor::ExtendedDescriptor[][src]

pub type ExtendedDescriptor = Descriptor<DescriptorPublicKey>;
Expand description

Alias for a Descriptor that can contain extended keys using DescriptorPublicKey

+

Trait Implementations

Convert to wallet descriptor

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

Type Definition bdk::descriptor::HdKeyPaths[][src]

pub type HdKeyPaths = BTreeMap<PublicKey, KeySource>;
Expand description

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/latest/bdk/descriptor/type.KeyMap.html b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/type.KeyMap.html new file mode 100644 index 0000000000..417fe088cf --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/descriptor/type.KeyMap.html @@ -0,0 +1,8 @@ +KeyMap in bdk::descriptor - Rust

Type Definition bdk::descriptor::KeyMap[]

pub type KeyMap = HashMap<DescriptorPublicKey, DescriptorSecretKey, RandomState>;
Expand description

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/latest/bdk/enum.Error.html b/static/docs-rs/bdk/nightly/latest/bdk/enum.Error.html new file mode 100644 index 0000000000..4ea012e6e4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/enum.Error.html @@ -0,0 +1,158 @@ +Error in bdk - Rust

Enum bdk::Error[][src]

pub enum Error {
+
Show 41 variants InvalidU32Bytes(Vec<u8>), + Generic(String), + ScriptDoesntHaveAddressForm, + NoRecipients, + NoUtxosSelected, + OutputBelowDustLimit(usize), + InsufficientFunds { + needed: u64, + available: u64, + }, + BnBTotalTriesExceeded, + BnBNoExactMatch, + UnknownUtxo, + TransactionNotFound, + TransactionConfirmed, + IrreplaceableTransaction, + FeeRateTooLow { + required: FeeRate, + }, + FeeTooLow { + required: u64, + }, + FeeRateUnavailable, + MissingKeyOrigin(String), + Key(KeyError), + ChecksumMismatch, + SpendingPolicyRequired(KeychainKind), + InvalidPolicyPathError(PolicyError), + Signer(SignerError), + InvalidNetwork { + requested: Network, + found: Network, + }, + InvalidProgressValue(f32), + ProgressUpdateError, + InvalidOutpoint(OutPoint), + Descriptor(Error), + AddressValidator(AddressValidatorError), + Encode(Error), + Miniscript(Error), + Bip32(Error), + Secp256k1(Error), + Json(Error), + Hex(Error), + Psbt(Error), + PsbtParse(PsbtParseError), + Electrum(Error), + Esplora(Box<EsploraError>), + CompactFilters(CompactFiltersError), + Sled(Error), + Rusqlite(Error), +
}
Expand description

Errors that can be thrown by the Wallet

+

Variants

InvalidU32Bytes(Vec<u8>)

Wrong number of bytes found when trying to convert to u32

+

Tuple Fields of InvalidU32Bytes

0: Vec<u8>
Generic(String)

Generic error

+

Tuple Fields of Generic

0: String
ScriptDoesntHaveAddressForm

This error is thrown when trying to convert Bare and Public key script to address

+
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

+

Tuple Fields of OutputBelowDustLimit

0: usize
InsufficientFunds

Wallet’s UTXO set is not enough to cover recipient’s requested plus fee

+

Fields of InsufficientFunds

needed: u64

Sats needed for some transaction

+
available: u64

Sats available for spending

+
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)

+
FeeRateUnavailable

Node doesn’t have data to estimate a fee rate

+
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

+

Tuple Fields of MissingKeyOrigin

0: String

Error while working with keys

+

Tuple Fields of Key

0: KeyError
ChecksumMismatch

Descriptor checksum mismatch

+
SpendingPolicyRequired(KeychainKind)

Spending policy is not compatible with this KeychainKind

+

Tuple Fields of SpendingPolicyRequired

0: KeychainKind
InvalidPolicyPathError(PolicyError)

Error while extracting and manipulating policies

+

Tuple Fields of InvalidPolicyPathError

0: PolicyError
Signer(SignerError)

Signing error

+

Tuple Fields of Signer

0: SignerError
InvalidNetwork

Invalid network

+

Fields of InvalidNetwork

requested: Network

requested network, for example what is given as bdk-cli option

+
found: Network

found network, for example the network of the bitcoin node

+
InvalidProgressValue(f32)

Progress value must be between 0.0 (included) and 100.0 (included)

+

Tuple Fields of InvalidProgressValue

0: f32
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)

+

Tuple Fields of InvalidOutpoint

0: OutPoint
Descriptor(Error)

Error related to the parsing and usage of descriptors

+

Tuple Fields of Descriptor

0: Error
AddressValidator(AddressValidatorError)

Error that can be returned to fail the validation of an address

+

Tuple Fields of AddressValidator

0: AddressValidatorError
Encode(Error)

Encoding error

+

Tuple Fields of Encode

0: Error
Miniscript(Error)

Miniscript error

+

Tuple Fields of Miniscript

0: Error
Bip32(Error)

BIP32 error

+

Tuple Fields of Bip32

0: Error
Secp256k1(Error)

An ECDSA error

+

Tuple Fields of Secp256k1

0: Error
Json(Error)

Error serializing or deserializing JSON data

+

Tuple Fields of Json

0: Error
Hex(Error)

Hex decoding error

+

Tuple Fields of Hex

0: Error
Psbt(Error)

Partially signed bitcoin transaction error

+

Tuple Fields of Psbt

0: Error
PsbtParse(PsbtParseError)

Partially signed bitcoin transaction parseerror

+

Tuple Fields of PsbtParse

0: PsbtParseError
Electrum(Error)
This is supported on crate feature electrum only.

Electrum client error

+

Tuple Fields of Electrum

0: Error
Esplora(Box<EsploraError>)
This is supported on crate feature esplora only.

Esplora client error

+

Tuple Fields of Esplora

0: Box<EsploraError>
CompactFilters(CompactFiltersError)
This is supported on crate feature compact_filters only.

Compact filters client error)

+

Tuple Fields of CompactFilters

0: CompactFiltersError
Sled(Error)
This is supported on crate feature key-value-db only.

Sled database error

+

Tuple Fields of Sled

0: Error
Rusqlite(Error)
This is supported on crate feature sqlite only.

Rusqlite client error

+

Tuple Fields of Rusqlite

0: Error

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Converts a reference to Self into a dynamic trait object of Fail.

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the “name” of the error. Read more

+

Returns a reference to the underlying cause of this failure, if it +is an error that wraps other errors. Read more

+

Returns a reference to the Backtrace carried by this failure, if it +carries one. Read more

+

Provides context for this failure. Read more

+

Wraps this failure in a compatibility wrapper that implements +std::error::Error. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/enum.KeychainKind.html b/static/docs-rs/bdk/nightly/latest/bdk/enum.KeychainKind.html new file mode 100644 index 0000000000..3ba70285dd --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/enum.KeychainKind.html @@ -0,0 +1,47 @@ +KeychainKind in bdk - Rust

Enum bdk::KeychainKind[][src]

pub enum KeychainKind {
+    External,
+    Internal,
+}
Expand description

Types of keychains

+

Variants

External

External

+
Internal

Internal, usually used for change outputs

+

Implementations

Return KeychainKind as a byte

+

Trait Implementations

Performs the conversion.

+

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Calculate the base32 serialized length

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Error type if conversion fails

+

Check if all values are in range and return array-like struct of u5 values

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Encode as base32 and write it to the supplied writer +Implementations shouldn’t allocate. Read more

+

Convert Self to base32 vector

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/enum.Utxo.html b/static/docs-rs/bdk/nightly/latest/bdk/enum.Utxo.html new file mode 100644 index 0000000000..02d5db3d00 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/enum.Utxo.html @@ -0,0 +1,42 @@ +Utxo in bdk - Rust

Enum bdk::Utxo[][src]

pub enum Utxo {
+    Local(LocalUtxo),
+    Foreign {
+        outpoint: OutPoint,
+        psbt_input: Box<Input>,
+    },
+}
Expand description

An unspent transaction output (UTXO).

+

Variants

Local(LocalUtxo)

A UTXO owned by the local wallet.

+

Tuple Fields of Local

0: LocalUtxo
Foreign

A UTXO owned by another wallet.

+

Fields of Foreign

outpoint: OutPoint

The location of the output.

+
psbt_input: Box<Input>

The information about the input we require to add it to a PSBT.

+

Implementations

Get the location of the UTXO

+

Get the TxOut of the UTXO

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/error/enum.Error.html b/static/docs-rs/bdk/nightly/latest/bdk/error/enum.Error.html new file mode 100644 index 0000000000..9abf6d4a9c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/error/enum.Error.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bdk/enum.Error.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/fn.version.html b/static/docs-rs/bdk/nightly/latest/bdk/fn.version.html new file mode 100644 index 0000000000..32eb32ae0c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/fn.version.html @@ -0,0 +1,4 @@ +version in bdk - Rust

Function bdk::version[][src]

pub fn version() -> &'static str
Expand description

Get the version of BDK at runtime

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/index.html b/static/docs-rs/bdk/nightly/latest/bdk/index.html new file mode 100644 index 0000000000..8bd4517d47 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/index.html @@ -0,0 +1,169 @@ +bdk - Rust

Crate bdk[][src]

Expand description

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.12.0"

Sync the balance of a descriptor

Example

+
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};
+use bdk::database::MemoryDatabase;
+use bdk::wallet::AddressIndex::New;
+
+fn main() -> Result<(), bdk::Error> {
+let wallet = 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_address(New)?);
+    println!("Address #1: {}", wallet.get_address(New)?);
+    println!("Address #2: {}", wallet.get_address(New)?);
+
+    Ok(())
+}
+

Create a transaction

Example

+
use bdk::{FeeRate, Wallet};
+use bdk::database::MemoryDatabase;
+use bdk::blockchain::{noop_progress, ElectrumBlockchain};
+use bdk::electrum_client::Client;
+
+use bitcoin::consensus::serialize;
+use bdk::wallet::AddressIndex::New;
+
+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_address(New)?;
+    let (psbt, details) = {
+        let mut builder =  wallet.build_tx();
+        builder
+            .add_recipient(send_to.script_pubkey(), 50_000)
+            .enable_rbf()
+            .do_not_spend_change()
+            .fee_rate(FeeRate::from_sat_per_vb(5.0));
+        builder.finish()?
+    };
+
+    println!("Transaction details: {:#?}", details);
+    println!("Unsigned PSBT: {}", &psbt);
+
+    Ok(())
+}
+

Sign a transaction

Example

+
use std::str::FromStr;
+
+use bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
+
+use bdk::{Wallet, SignOptions};
+use bdk::database::MemoryDatabase;
+
+fn main() -> Result<(), bdk::Error> {
+    let wallet = 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 mut psbt = Psbt::from_str(psbt)?;
+
+    let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
+
+    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
  • +
  • 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 electrum_client;
pub extern crate miniscript;
pub extern crate rusqlite;
pub extern crate sled;
pub use descriptor::template;
pub use descriptor::HdKeyPaths;
pub use wallet::address_validator;
pub use wallet::signer;
pub use wallet::signer::SignOptions;
pub use wallet::tx_builder::TxBuilder;
pub use wallet::Wallet;

Modules

+

Blockchain backends

+

Database types

+

Descriptors

+

Key formats

+

Wallet

+

Macros

+

Macro to write full descriptors with code

+

Macro to write descriptor fragments with code

+

Structs

+

Block height and timestamp of the block containing the confirmed transaction

+

Fee rate

+

An unspent output owned by a Wallet.

+

A wallet transaction

+

A Utxo with its satisfaction_weight.

+

Enums

+

Errors that can be thrown by the Wallet

+

Types of keychains

+

An unspent transaction output (UTXO).

+

Traits

+

Trait implemented by types that can be used to measure weight units.

+

Functions

+

Get the version of BDK at runtime

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/enum.Language.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/enum.Language.html new file mode 100644 index 0000000000..bb345d3073 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/enum.Language.html @@ -0,0 +1,49 @@ +Language in bdk::keys::bip39 - Rust

Enum bdk::keys::bip39::Language[]

pub enum Language {
+    English,
+    ChineseSimplified,
+    ChineseTraditional,
+    French,
+    Italian,
+    Japanese,
+    Korean,
+    Spanish,
+}
This is supported on crate feature keys-bip39 only.
Expand description

The language determines which words will be used in a mnemonic phrase, but also indirectly +determines the binary value of each word when a Mnemonic is turned into a Seed.

+

These are not of much use right now, and may even be removed from the crate, as there is no +official language specified by the standard except English.

+

Variants

English
ChineseSimplified
This is supported on crate feature chinese-simplified only.
ChineseTraditional
This is supported on crate feature chinese-traditional only.
French
This is supported on crate feature french only.
Italian
This is supported on crate feature italian only.
Japanese
This is supported on crate feature japanese only.
Korean
This is supported on crate feature korean only.
Spanish
This is supported on crate feature spanish only.

Implementations

Construct a word list from its language code. Returns None +if the language code is not valid or not supported.

+

Get the word list for this language

+

Get a [WordMap][WordMap] that allows word -> index lookups in the word list

+

The index of an individual word in the word list is used as the binary value of that word +when the phrase is turned into a [Seed][Seed].

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/enum.MnemonicType.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/enum.MnemonicType.html new file mode 100644 index 0000000000..b1d5e996e7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/enum.MnemonicType.html @@ -0,0 +1,111 @@ +MnemonicType in bdk::keys::bip39 - Rust

Enum bdk::keys::bip39::MnemonicType[]

pub enum MnemonicType {
+    Words12,
+    Words15,
+    Words18,
+    Words21,
+    Words24,
+}
This is supported on crate feature keys-bip39 only.
Expand description

Determines the number of words that will be present in a Mnemonic phrase

+

Also directly affects the amount of entropy that will be used to create a Mnemonic, +and therefore the cryptographic strength of the HD wallet keys/addresses that can be derived from +it using the Seed.

+

For example, a 12 word mnemonic phrase is essentially a friendly representation of a 128-bit key, +while a 24 word mnemonic phrase is essentially a 256-bit key.

+

If you know you want a specific phrase length, you can use the enum variant directly, for example +MnemonicType::Words12.

+

You can also get a MnemonicType that corresponds to one of the standard BIP39 key sizes by +passing arbitrary usize values:

+ +
use bip39::{MnemonicType};
+
+let mnemonic_type = MnemonicType::for_key_size(128).unwrap();
+

Variants

Words12
Words15
Words18
Words21
Words24

Implementations

Get a MnemonicType for a mnemonic phrase with a specific number of words

+

Specifying a word count not provided for by the BIP39 standard will return an Error +of kind ErrorKind::InvalidWordLength.

+
Example
+
use bip39::{MnemonicType};
+
+let mnemonic_type = MnemonicType::for_word_count(12).unwrap();
+

Get a MnemonicType for a mnemonic phrase representing the given key size as bits

+

Specifying a key size not provided for by the BIP39 standard will return an Error +of kind ErrorKind::InvalidKeysize.

+
Example
+
use bip39::{MnemonicType};
+
+let mnemonic_type = MnemonicType::for_key_size(128).unwrap();
+

Get a MnemonicType for an existing mnemonic phrase

+

This can be used when you need information about a mnemonic phrase based on the number of +words, for example you can get the entropy value using MnemonicType::entropy_bits.

+

Specifying a phrase that does not match one of the standard BIP39 phrase lengths will return +an Error of kind ErrorKind::InvalidWordLength. The phrase will not be validated in any +other way.

+
Example
+
use bip39::{MnemonicType};
+
+let test_mnemonic = "park remain person kitchen mule spell knee armed position rail grid ankle";
+
+let mnemonic_type = MnemonicType::for_phrase(test_mnemonic).unwrap();
+
+let entropy_bits = mnemonic_type.entropy_bits();
+

Return the number of entropy+checksum bits

+
Example
+
use bip39::{MnemonicType};
+
+let test_mnemonic = "park remain person kitchen mule spell knee armed position rail grid ankle";
+
+let mnemonic_type = MnemonicType::for_phrase(test_mnemonic).unwrap();
+
+let total_bits = mnemonic_type.total_bits();
+

Return the number of entropy bits

+
Example
+
use bip39::{MnemonicType};
+
+let test_mnemonic = "park remain person kitchen mule spell knee armed position rail grid ankle";
+
+let mnemonic_type = MnemonicType::for_phrase(test_mnemonic).unwrap();
+
+let entropy_bits = mnemonic_type.entropy_bits();
+

Return the number of checksum bits

+
Example
+
use bip39::{MnemonicType};
+
+let test_mnemonic = "park remain person kitchen mule spell knee armed position rail grid ankle";
+
+let mnemonic_type = MnemonicType::for_phrase(test_mnemonic).unwrap();
+
+let checksum_bits = mnemonic_type.checksum_bits();
+

Return the number of words

+
Example
+
use bip39::{MnemonicType};
+
+let mnemonic_type = MnemonicType::Words12;
+
+let word_count = mnemonic_type.word_count();
+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/index.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/index.html new file mode 100644 index 0000000000..c546bbf144 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/index.html @@ -0,0 +1,13 @@ +bdk::keys::bip39 - Rust

Module bdk::keys::bip39[][src]

This is supported on crate feature keys-bip39 only.
Expand description

BIP-0039

+

Structs

+

The primary type in this crate, most tasks require creating or using one.

+

The secret value used to derive HD wallet addresses from a Mnemonic phrase.

+

Enums

+

The language determines which words will be used in a mnemonic phrase, but also indirectly +determines the binary value of each word when a Mnemonic is turned into a Seed.

+

Determines the number of words that will be present in a Mnemonic phrase

+

Type Definitions

+

Type for a BIP39 mnemonic with an optional passphrase

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/sidebar-items.js new file mode 100644 index 0000000000..4c0779de63 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["Language","The language determines which words will be used in a mnemonic phrase, but also indirectly determines the binary value of each word when a `Mnemonic` is turned into a `Seed`."],["MnemonicType","Determines the number of words that will be present in a `Mnemonic` phrase"]],"struct":[["Mnemonic","The primary type in this crate, most tasks require creating or using one."],["Seed","The secret value used to derive HD wallet addresses from a `Mnemonic` phrase."]],"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/latest/bdk/keys/bip39/struct.Mnemonic.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/struct.Mnemonic.html new file mode 100644 index 0000000000..094c94961e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/struct.Mnemonic.html @@ -0,0 +1,104 @@ +Mnemonic in bdk::keys::bip39 - Rust

Struct bdk::keys::bip39::Mnemonic[]

pub struct Mnemonic { /* fields omitted */ }
This is supported on crate feature keys-bip39 only.
Expand description

The primary type in this crate, most tasks require creating or using one.

+

To create a new Mnemonic from a randomly generated key, call Mnemonic::new().

+

To get a Mnemonic instance for an existing mnemonic phrase, including +those generated by other software or hardware wallets, use Mnemonic::from_phrase().

+

You can get the HD wallet Seed from a Mnemonic by calling Seed::new(). +From there you can either get the raw byte value with Seed::as_bytes(), or the hex +representation using Rust formatting: format!("{:X}", seed).

+

You can also get the original entropy value back from a Mnemonic with Mnemonic::entropy(), +but beware that the entropy value is not the same thing as an HD wallet seed, and should +never be used that way.

+

Implementations

Generates a new Mnemonic

+

Use Mnemonic::phrase() to get an str slice of the generated phrase.

+
Example
+
use bip39::{Mnemonic, MnemonicType, Language};
+
+let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English);
+let phrase = mnemonic.phrase();
+
+println!("phrase: {}", phrase);
+
+assert_eq!(phrase.split(" ").count(), 12);
+

Create a Mnemonic from pre-generated entropy

+
Example
+
use bip39::{Mnemonic, MnemonicType, Language};
+
+let entropy = &[0x33, 0xE4, 0x6B, 0xB1, 0x3A, 0x74, 0x6E, 0xA4, 0x1C, 0xDD, 0xE4, 0x5C, 0x90, 0x84, 0x6A, 0x79];
+let mnemonic = Mnemonic::from_entropy(entropy, Language::English).unwrap();
+
+assert_eq!("crop cash unable insane eight faith inflict route frame loud box vibrant", mnemonic.phrase());
+assert_eq!("33E46BB13A746EA41CDDE45C90846A79", format!("{:X}", mnemonic));
+

Create a Mnemonic from an existing mnemonic phrase

+

The phrase supplied will be checked for word length and validated according to the checksum +specified in BIP0039

+
Example
+
use bip39::{Mnemonic, Language};
+
+let phrase = "park remain person kitchen mule spell knee armed position rail grid ankle";
+let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
+
+assert_eq!(phrase, mnemonic.phrase());
+

Validate a mnemonic phrase

+

The phrase supplied will be checked for word length and validated according to the checksum +specified in BIP0039.

+
Example
+
use bip39::{Mnemonic, Language};
+
+let test_mnemonic = "park remain person kitchen mule spell knee armed position rail grid ankle";
+
+assert!(Mnemonic::validate(test_mnemonic, Language::English).is_ok());
+

Get the mnemonic phrase as a string reference.

+

Consume the Mnemonic and return the phrase as a String.

+

This operation doesn’t perform any allocations.

+

Get the original entropy value of the mnemonic phrase as a slice.

+
Example
+
use bip39::{Mnemonic, Language};
+
+let phrase = "park remain person kitchen mule spell knee armed position rail grid ankle";
+
+let mnemonic = Mnemonic::from_phrase(phrase, Language::English).unwrap();
+
+let entropy: &[u8] = mnemonic.entropy();
+

Note: You shouldn’t use the generated entropy as secrets, for that generate a new +Seed from the Mnemonic.

+

Get the Language

+

Trait Implementations

Performs the conversion.

+

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Consume self and turn it into an ExtendedKey Read more

+

Consume self and turn it into a DescriptorKey by adding the extra metadata, such as +key origin and derivation path Read more

+

Formats the value using the given formatter. Read more

+

Type specifying the amount of entropy required e.g. [u8;32]

+

Extra options required by the generate_with_entropy

+

Returned error in case of failure

+

Generate a key given the extra options and the entropy

+

Generate a key given the options with a random entropy

+

Formats the value using the given formatter.

+

Formats the value using the given formatter.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Outputs the hash in hexadecimal form

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/struct.Seed.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/struct.Seed.html new file mode 100644 index 0000000000..9f250b8fd3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/struct.Seed.html @@ -0,0 +1,48 @@ +Seed in bdk::keys::bip39 - Rust

Struct bdk::keys::bip39::Seed[]

pub struct Seed { /* fields omitted */ }
This is supported on crate feature keys-bip39 only.
Expand description

The secret value used to derive HD wallet addresses from a Mnemonic phrase.

+

Because it is not possible to create a Mnemonic instance that is invalid, it is +therefore impossible to have a Seed instance that is invalid. This guarantees that only +a valid, intact mnemonic phrase can be used to derive HD wallet addresses.

+

To get the raw byte value use Seed::as_bytes(). These can be used to derive +HD wallet addresses using another crate (deriving HD wallet addresses is outside the scope of this +crate and the BIP39 standard).

+

Implementations

Generates the seed from the Mnemonic and the password.

+

Get the seed value as a byte slice

+

Trait Implementations

Performs the conversion.

+

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Consume self and turn it into an ExtendedKey Read more

+

Consume self and turn it into a DescriptorKey by adding the extra metadata, such as +key origin and derivation path Read more

+

Formats the value using the given formatter.

+

Formats the value using the given formatter.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Calculate the base32 serialized length

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Error type if conversion fails

+

Check if all values are in range and return array-like struct of u5 values

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Encode as base32 and write it to the supplied writer +Implementations shouldn’t allocate. Read more

+

Convert Self to base32 vector

+

Outputs the hash in hexadecimal form

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/type.MnemonicWithPassphrase.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/type.MnemonicWithPassphrase.html new file mode 100644 index 0000000000..1b98adebbf --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/bip39/type.MnemonicWithPassphrase.html @@ -0,0 +1,7 @@ +MnemonicWithPassphrase in bdk::keys::bip39 - Rust

Type Definition bdk::keys::bip39::MnemonicWithPassphrase[][src]

pub type MnemonicWithPassphrase = (Mnemonic, Option<String>);
This is supported on crate feature keys-bip39 only.
Expand description

Type for a BIP39 mnemonic with an optional passphrase

+

Trait Implementations

Consume self and turn it into an ExtendedKey Read more

+

Consume self and turn it into a DescriptorKey by adding the extra metadata, such as +key origin and derivation path Read more

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.DescriptorKey.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.DescriptorKey.html new file mode 100644 index 0000000000..8a5149114e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.DescriptorKey.html @@ -0,0 +1,28 @@ +DescriptorKey in bdk::keys - Rust

Enum bdk::keys::DescriptorKey[][src]

pub enum DescriptorKey<Ctx: ScriptContext> {
+    // some variants omitted
+}
Expand description

Container for public or secret keys

+

Implementations

Create an instance given a public key and a set of valid networks

+

Create an instance given a secret key and a set of valid networks

+

Override the computed set of valid networks

+

Trait Implementations

Formats the value using the given formatter. Read more

+

The “identity” conversion is used internally by some bdk::fragments

+

Turn the key into a DescriptorKey within the requested ScriptContext

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.DescriptorPublicKey.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.DescriptorPublicKey.html new file mode 100644 index 0000000000..ac64f9af39 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.DescriptorPublicKey.html @@ -0,0 +1,75 @@ +DescriptorPublicKey in bdk::keys - Rust

Enum bdk::keys::DescriptorPublicKey[]

pub enum DescriptorPublicKey {
+    SinglePub(DescriptorSinglePub),
+    XPub(DescriptorXKey<ExtendedPubKey>),
+}
Expand description

The MiniscriptKey corresponding to Descriptors. This can +either be Single public key or a Xpub

+

Variants

Single Public Key

+

Tuple Fields of SinglePub

0: DescriptorSinglePub
XPub(DescriptorXKey<ExtendedPubKey>)

Xpub

+

Tuple Fields of XPub

0: DescriptorXKey<ExtendedPubKey>

Implementations

The fingerprint of the master key associated with this key

+

Full path, from the master key

+

For wildcard keys this will return the path up to the wildcard, so you +can get full paths by appending one additional derivation step, according +to the wildcard type (hardened or normal)

+

Whether or not the key has a wildcards

+

If this public key has a wildcard, replace it by the given index

+

Panics if given an index ≥ 2^31

+

Computes the public key corresponding to this descriptor key

+

Will return an error if the descriptor key has any hardened +derivation steps in its path, or if the key has any wildcards.

+

To ensure there are no wildcards, call .derive(0) or similar; +to avoid hardened derivation steps, start from a DescriptorSecretKey +and call as_public, or call TranslatePk2::translate_pk2 with +some function which has access to secret key data.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The associated error which can be returned from parsing.

+

Parses a string s to return a value of this type. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

Turn the key into a DescriptorKey within the requested ScriptContext

+

The associated Hash type with the publicKey

+

Check if the publicKey is uncompressed. The default +implementation returns false Read more

+

Converts an object to PublicHash

+

Computes the size of a public key when serialized in a script, +including the length bytes Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.DescriptorSecretKey.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.DescriptorSecretKey.html new file mode 100644 index 0000000000..5dcb6c1505 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.DescriptorSecretKey.html @@ -0,0 +1,37 @@ +DescriptorSecretKey in bdk::keys - Rust

Enum bdk::keys::DescriptorSecretKey[]

pub enum DescriptorSecretKey {
+    SinglePriv(DescriptorSinglePriv),
+    XPrv(DescriptorXKey<ExtendedPrivKey>),
+}
Expand description

A Secret Key that can be either a single key or an Xprv

+

Variants

Single Secret Key

+

Tuple Fields of SinglePriv

0: DescriptorSinglePriv
XPrv(DescriptorXKey<ExtendedPrivKey>)

Xprv

+

Tuple Fields of XPrv

0: DescriptorXKey<ExtendedPrivKey>

Implementations

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

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The associated error which can be returned from parsing.

+

Parses a string s to return a value of this type. Read more

+

Turn the key into a DescriptorKey within the requested ScriptContext

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.ExtendedKey.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.ExtendedKey.html new file mode 100644 index 0000000000..495b49355f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.ExtendedKey.html @@ -0,0 +1,39 @@ +ExtendedKey in bdk::keys - Rust

Enum bdk::keys::ExtendedKey[][src]

pub enum ExtendedKey<Ctx: ScriptContext = Legacy> {
+    Private((ExtendedPrivKey, PhantomData<Ctx>)),
+    Public((ExtendedPubKey, PhantomData<Ctx>)),
+}
Expand description

Enum for extended keys that can be either xprv or xpub

+

An instance of ExtendedKey can be constructed from an ExtendedPrivKey +or an ExtendedPubKey by using the From trait.

+

Defaults to the Legacy context.

+

Variants

Private((ExtendedPrivKey, PhantomData<Ctx>))

A private extended key, aka an xprv

+

Tuple Fields of Private

0: (ExtendedPrivKey, PhantomData<Ctx>)
Public((ExtendedPubKey, PhantomData<Ctx>))

A public extended key, aka an xpub

+

Tuple Fields of Public

0: (ExtendedPubKey, PhantomData<Ctx>)

Implementations

Return whether or not the key contains the private data

+

Transform the ExtendedKey into an ExtendedPrivKey for the +given [Network], if the key contains the private data

+

Transform the ExtendedKey into an ExtendedPubKey for the +given [Network]

+

Trait Implementations

Identity conversion

+

Consume self and turn it into an ExtendedKey Read more

+

Consume self and turn it into a DescriptorKey by adding the extra metadata, such as +key origin and derivation path Read more

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.KeyError.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.KeyError.html new file mode 100644 index 0000000000..d7865a4a16 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.KeyError.html @@ -0,0 +1,53 @@ +KeyError in bdk::keys - Rust

Enum bdk::keys::KeyError[][src]

pub enum KeyError {
+    InvalidScriptContext,
+    InvalidNetwork,
+    InvalidChecksum,
+    Message(String),
+    Bip32(Error),
+    Miniscript(Error),
+}
Expand description

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

+

Tuple Fields of Message

0: String
Bip32(Error)

BIP32 error

+

Tuple Fields of Bip32

0: Error
Miniscript(Error)

Miniscript error

+

Tuple Fields of Miniscript

0: Error

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Converts a reference to Self into a dynamic trait object of Fail.

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the “name” of the error. Read more

+

Returns a reference to the underlying cause of this failure, if it +is an error that wraps other errors. Read more

+

Returns a reference to the Backtrace carried by this failure, if it +carries one. Read more

+

Provides context for this failure. Read more

+

Wraps this failure in a compatibility wrapper that implements +std::error::Error. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.ScriptContextEnum.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.ScriptContextEnum.html new file mode 100644 index 0000000000..1a209b5c87 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/enum.ScriptContextEnum.html @@ -0,0 +1,37 @@ +ScriptContextEnum in bdk::keys - Rust

Enum bdk::keys::ScriptContextEnum[][src]

pub enum ScriptContextEnum {
+    Legacy,
+    Segwitv0,
+}
Expand description

Enum representation of the known valid ScriptContexts

+

Variants

Legacy

Legacy scripts

+
Segwitv0

Segwitv0 scripts

+

Implementations

Returns whether the script context is ScriptContextEnum::Legacy

+

Returns whether the script context is ScriptContextEnum::Segwitv0

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.any_network.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.any_network.html new file mode 100644 index 0000000000..3fdb567cb4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.any_network.html @@ -0,0 +1,4 @@ +any_network in bdk::keys - Rust

Function bdk::keys::any_network[][src]

pub fn any_network() -> ValidNetworks
Expand description

Create a set containing mainnet, testnet and regtest

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.mainnet_network.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.mainnet_network.html new file mode 100644 index 0000000000..5753bd5e40 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.mainnet_network.html @@ -0,0 +1,4 @@ +mainnet_network in bdk::keys - Rust

Function bdk::keys::mainnet_network[][src]

pub fn mainnet_network() -> ValidNetworks
Expand description

Create a set only containing mainnet

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.merge_networks.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.merge_networks.html new file mode 100644 index 0000000000..9b15a7abda --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.merge_networks.html @@ -0,0 +1,4 @@ +merge_networks in bdk::keys - Rust

Function bdk::keys::merge_networks[][src]

pub fn merge_networks(a: &ValidNetworks, b: &ValidNetworks) -> ValidNetworks
Expand description

Compute the intersection of two sets

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.test_networks.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.test_networks.html new file mode 100644 index 0000000000..efa8335377 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/fn.test_networks.html @@ -0,0 +1,4 @@ +test_networks in bdk::keys - Rust

Function bdk::keys::test_networks[][src]

pub fn test_networks() -> ValidNetworks
Expand description

Create a set containing testnet and regtest

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/index.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/index.html new file mode 100644 index 0000000000..8266d9bf22 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/index.html @@ -0,0 +1,38 @@ +bdk::keys - Rust

Module bdk::keys[][src]

Expand description

Key formats

+

Modules

+
bip39keys-bip39

BIP-0039

+

Structs

+

A Single Descriptor Secret Key with optional origin information

+

A Single Descriptor Key with optional origin information

+

Output of a GeneratableKey key generation

+

Options for generating a [PrivateKey]

+

Contents of a “sortedmulti” descriptor

+

Enums

+

Container for public or secret keys

+

The MiniscriptKey corresponding to Descriptors. This can +either be Single public key or a Xpub

+

A Secret Key that can be either a single key or an Xprv

+

Enum for extended keys that can be either xprv or xpub

+

Errors thrown while working with keys

+

Enum representation of the known valid ScriptContexts

+

Traits

+

Trait for keys that can be derived.

+

Trait that adds extra useful methods to ScriptContexts

+

Trait that allows generating a key with the default options

+

Trait for keys that can be generated

+

Trait for objects that can be turned into a public or secret DescriptorKey

+

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

+

Functions

+

Create a set containing mainnet, testnet and regtest

+

Create a set only containing mainnet

+

Compute the intersection of two sets

+

Create a set containing testnet and regtest

+

Type Definitions

+

Alias type for a map of public key to secret key

+

Set of valid networks for a key

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/keys/sidebar-items.js new file mode 100644 index 0000000000..9b1ae8b56f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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"],["ExtendedKey","Enum for extended keys that can be either `xprv` or `xpub`"],["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"],["IntoDescriptorKey","Trait for objects that can be turned into a public or secret [`DescriptorKey`]"],["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"]],"type":[["KeyMap","Alias type for a map of public key to secret key"],["ValidNetworks","Set of valid networks for a key"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.DescriptorSinglePriv.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.DescriptorSinglePriv.html new file mode 100644 index 0000000000..cafc8126d2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.DescriptorSinglePriv.html @@ -0,0 +1,26 @@ +DescriptorSinglePriv in bdk::keys - Rust

Struct bdk::keys::DescriptorSinglePriv[]

pub struct DescriptorSinglePriv {
+    pub origin: Option<(Fingerprint, DerivationPath)>,
+    pub key: PrivateKey,
+}
Expand description

A Single Descriptor Secret Key with optional origin information

+

Fields

origin: Option<(Fingerprint, DerivationPath)>

Origin information

+
key: PrivateKey

The key

+

Trait Implementations

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.DescriptorSinglePub.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.DescriptorSinglePub.html new file mode 100644 index 0000000000..a9d8545f6c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.DescriptorSinglePub.html @@ -0,0 +1,48 @@ +DescriptorSinglePub in bdk::keys - Rust

Struct bdk::keys::DescriptorSinglePub[]

pub struct DescriptorSinglePub {
+    pub origin: Option<(Fingerprint, DerivationPath)>,
+    pub key: PublicKey,
+}
Expand description

A Single Descriptor Key with optional origin information

+

Fields

origin: Option<(Fingerprint, DerivationPath)>

Origin information

+
key: PublicKey

The key

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.GeneratedKey.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.GeneratedKey.html new file mode 100644 index 0000000000..8f36f2d9a5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.GeneratedKey.html @@ -0,0 +1,27 @@ +GeneratedKey in bdk::keys - Rust

Struct bdk::keys::GeneratedKey[][src]

pub struct GeneratedKey<K, Ctx: ScriptContext> { /* fields omitted */ }
Expand description

Output of a GeneratableKey key generation

+

Implementations

Consumes self and returns the key

+

Trait Implementations

The resulting type after dereferencing.

+

Dereferences the value.

+

Consume self and turn it into an ExtendedKey Read more

+

Consume self and turn it into a DescriptorKey by adding the extra metadata, such as +key origin and derivation path Read more

+

Turn the key into a DescriptorKey within the requested ScriptContext

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.PrivateKeyGenerateOptions.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.PrivateKeyGenerateOptions.html new file mode 100644 index 0000000000..672f14fa46 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.PrivateKeyGenerateOptions.html @@ -0,0 +1,32 @@ +PrivateKeyGenerateOptions in bdk::keys - Rust

Struct bdk::keys::PrivateKeyGenerateOptions[][src]

pub struct PrivateKeyGenerateOptions {
+    pub compressed: bool,
+}
Expand description

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

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.SortedMultiVec.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.SortedMultiVec.html new file mode 100644 index 0000000000..d0718d74b3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/struct.SortedMultiVec.html @@ -0,0 +1,87 @@ +SortedMultiVec in bdk::keys - Rust

Struct bdk::keys::SortedMultiVec[]

pub struct SortedMultiVec<Pk, Ctx> where
    Pk: MiniscriptKey,
    Ctx: ScriptContext
{ + pub k: usize, + pub pks: Vec<Pk, Global>, + // some fields omitted +}
Expand description

Contents of a “sortedmulti” descriptor

+

Fields

k: usize

signatures required

+
pks: Vec<Pk, Global>

public keys inside sorted Multi

+

Implementations

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.

+

Parse an expression tree into a SortedMultiVec

+

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.

+

utility function to sanity a sorted multi vec

+

Create Terminal::Multi containing sorted pubkeys

+

Encode as a Bitcoin script

+

Attempt to produce a satisfying witness for the +witness script represented by the parse tree

+

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.

+

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.)

+

Maximum size, in bytes, of a satisfying witness. +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.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

Run a predicate on every key in the descriptor, returning whether +the predicate returned true for every key Read more

+

Run a predicate on every key in the descriptor, returning whether +the predicate returned true for any key Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

Convert the object into an abstract policy

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.DerivableKey.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.DerivableKey.html new file mode 100644 index 0000000000..5caa8426f3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.DerivableKey.html @@ -0,0 +1,103 @@ +DerivableKey in bdk::keys - Rust

Trait bdk::keys::DerivableKey[][src]

pub trait DerivableKey<Ctx: ScriptContext = Legacy>: Sized {
+    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError>;
+
+    fn into_descriptor_key(
        self,
        origin: Option<KeySource>,
        derivation_path: DerivationPath
    ) -> Result<DescriptorKey<Ctx>, KeyError> { ... } +}
Expand description

Trait for keys that can be derived.

+

When extra metadata are provided, a DerivableKey can be transofrmed into a +DescriptorKey: the trait IntoDescriptorKey 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 IntoDescriptorKey. The same +rules regarding script context and valid networks apply.

+

Examples

+

Key types that can be directly converted into an ExtendedPrivKey or +an ExtendedPubKey can implement only the required into_extended_key() method.

+ +
use bdk::bitcoin;
+use bdk::bitcoin::util::bip32;
+use bdk::keys::{DerivableKey, ExtendedKey, KeyError, ScriptContext};
+
+struct MyCustomKeyType {
+    key_data: bitcoin::PrivateKey,
+    chain_code: Vec<u8>,
+    network: bitcoin::Network,
+}
+
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
+    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+        let xprv = bip32::ExtendedPrivKey {
+            network: self.network,
+            depth: 0,
+            parent_fingerprint: bip32::Fingerprint::default(),
+            private_key: self.key_data,
+            chain_code: bip32::ChainCode::from(self.chain_code.as_ref()),
+            child_number: bip32::ChildNumber::Normal { index: 0 },
+        };
+
+        xprv.into_extended_key()
+    }
+}
+

Types that don’t internally encode the Network in which they are valid need some extra +steps to override the set of valid networks, otherwise only the network specified in the +ExtendedPrivKey or ExtendedPubKey will be considered valid.

+ +
use bdk::bitcoin;
+use bdk::bitcoin::util::bip32;
+use bdk::keys::{
+    any_network, DerivableKey, DescriptorKey, ExtendedKey, KeyError, ScriptContext,
+};
+
+struct MyCustomKeyType {
+    key_data: bitcoin::PrivateKey,
+    chain_code: Vec<u8>,
+}
+
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
+    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+        let xprv = bip32::ExtendedPrivKey {
+            network: bitcoin::Network::Bitcoin, // pick an arbitrary network here
+            depth: 0,
+            parent_fingerprint: bip32::Fingerprint::default(),
+            private_key: self.key_data,
+            chain_code: bip32::ChainCode::from(self.chain_code.as_ref()),
+            child_number: bip32::ChildNumber::Normal { index: 0 },
+        };
+
+        xprv.into_extended_key()
+    }
+
+    fn into_descriptor_key(
+        self,
+        source: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let descriptor_key = self
+            .into_extended_key()?
+            .into_descriptor_key(source, derivation_path)?;
+
+        // Override the set of valid networks here
+        Ok(descriptor_key.override_valid_networks(any_network()))
+    }
+}
+

Required methods

Consume self and turn it into an ExtendedKey

+

This can be used to get direct access to xprvs and xpubs for types that implement this trait, +like Mnemonic when the keys-bip39 feature is enabled.

+ +
use bdk::bitcoin::Network;
+use bdk::keys::{DerivableKey, ExtendedKey};
+use bdk::keys::bip39::{Mnemonic, Language};
+
+let xkey: ExtendedKey =
+    Mnemonic::from_phrase(
+        "jelly crash boy whisper mouse ecology tuna soccer memory million news short",
+        Language::English
+    )?
+    .into_extended_key()?;
+let xprv = xkey.into_xprv(Network::Bitcoin).unwrap();
+

Provided methods

Consume self and turn it into a DescriptorKey by adding the extra metadata, such as +key origin and derivation path

+

Implementations on Foreign Types

Implementors

Identity conversion

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.ExtScriptContext.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.ExtScriptContext.html new file mode 100644 index 0000000000..80e9abffa1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.ExtScriptContext.html @@ -0,0 +1,12 @@ +ExtScriptContext in bdk::keys - Rust

Trait bdk::keys::ExtScriptContext[][src]

pub trait ExtScriptContext: ScriptContext {
+    fn as_enum() -> ScriptContextEnum;
+
+    fn is_legacy() -> bool { ... }
+
fn is_segwit_v0() -> bool { ... } +}
Expand description

Trait that adds extra useful methods to ScriptContexts

+

Required methods

Provided methods

Returns whether the script context is Legacy

+

Returns whether the script context is Segwitv0

+

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.GeneratableDefaultOptions.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.GeneratableDefaultOptions.html new file mode 100644 index 0000000000..4e6cf622b1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.GeneratableDefaultOptions.html @@ -0,0 +1,12 @@ +GeneratableDefaultOptions in bdk::keys - Rust

Trait bdk::keys::GeneratableDefaultOptions[][src]

pub trait GeneratableDefaultOptions<Ctx>: GeneratableKey<Ctx> where
    Ctx: ScriptContext,
    <Self as GeneratableKey<Ctx>>::Options: Default
{ + fn generate_with_entropy_default(
        entropy: Self::Entropy
    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> { ... } +
fn generate_default() -> Result<GeneratedKey<Self, Ctx>, Self::Error> { ... } +}
Expand description

Trait that allows generating a key with the default options

+

This trait is automatically implemented if the GeneratableKey::Options implements Default.

+

Provided methods

Generate a key with the default options and a given entropy

+

Generate a key with the default options and a random entropy

+

Implementors

Automatic implementation of GeneratableDefaultOptions for GeneratableKeys where +Options implements Default

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.GeneratableKey.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.GeneratableKey.html new file mode 100644 index 0000000000..49dc544363 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.GeneratableKey.html @@ -0,0 +1,21 @@ +GeneratableKey in bdk::keys - Rust

Trait bdk::keys::GeneratableKey[][src]

pub trait GeneratableKey<Ctx: ScriptContext>: Sized {
+    type Entropy: AsMut<[u8]> + Default;
+    type Options;
+    type Error: Debug;
+    fn generate_with_entropy(
        options: Self::Options,
        entropy: Self::Entropy
    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error>; + + fn generate(
        options: Self::Options
    ) -> Result<GeneratedKey<Self, Ctx>, Self::Error> { ... } +}
Expand description

Trait for keys that can be generated

+

The same rules about ScriptContext and ValidNetworks from IntoDescriptorKey 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 +IntoDescriptorKey: the generated keys can be directly used in descriptors if Self is also +IntoDescriptorKey.

+

Associated Types

Type specifying the amount of entropy required e.g. [u8;32]

+

Extra options required by the generate_with_entropy

+

Returned error in case of failure

+

Required methods

Generate a key given the extra options and the entropy

+

Provided methods

Generate a key given the options with a random entropy

+

Implementations on Foreign Types

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.IntoDescriptorKey.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.IntoDescriptorKey.html new file mode 100644 index 0000000000..c4475690cf --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.IntoDescriptorKey.html @@ -0,0 +1,107 @@ +IntoDescriptorKey in bdk::keys - Rust

Trait bdk::keys::IntoDescriptorKey[][src]

pub trait IntoDescriptorKey<Ctx: ScriptContext>: Sized {
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError>;
+}
Expand description

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, IntoDescriptorKey, KeyError, ScriptContext};
+
+pub struct MyKeyType {
+    pubkey: PublicKey,
+}
+
+impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for MyKeyType {
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        self.pubkey.into_descriptor_key()
+    }
+}
+

Key type that is only valid on mainnet:

+ +
use bdk::bitcoin::PublicKey;
+
+use bdk::keys::{
+    mainnet_network, DescriptorKey, DescriptorPublicKey, DescriptorSinglePub,
+    IntoDescriptorKey, KeyError, ScriptContext,
+};
+
+pub struct MyKeyType {
+    pubkey: PublicKey,
+}
+
+impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for MyKeyType {
+    fn into_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, IntoDescriptorKey, KeyError, ScriptContext};
+
+pub struct MyKeyType {
+    is_legacy: bool,
+    pubkey: PublicKey,
+}
+
+impl<Ctx: ScriptContext + 'static> IntoDescriptorKey<Ctx> for MyKeyType {
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        if Ctx::is_legacy() == self.is_legacy {
+            self.pubkey.into_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.

+ +
ⓘ
use bdk::bitcoin::PublicKey;
+use std::str::FromStr;
+
+use bdk::keys::{DescriptorKey, IntoDescriptorKey, KeyError};
+
+pub struct MySegwitOnlyKeyType {
+    pubkey: PublicKey,
+}
+
+impl IntoDescriptorKey<bdk::miniscript::Segwitv0> for MySegwitOnlyKeyType {
+    fn into_descriptor_key(self) -> Result<DescriptorKey<bdk::miniscript::Segwitv0>, KeyError> {
+        self.pubkey.into_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

Turn the key into a DescriptorKey within the requested ScriptContext

+

Implementations on Foreign Types

Implementors

The “identity” conversion is used internally by some bdk::fragments

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.ScriptContext.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.ScriptContext.html new file mode 100644 index 0000000000..90b0e08b91 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/trait.ScriptContext.html @@ -0,0 +1,77 @@ +ScriptContext in bdk::keys - Rust

Trait bdk::keys::ScriptContext[]

pub trait ScriptContext: Debug + Clone + Ord + PartialOrd<Self> + Eq + PartialEq<Self> + Hash + Sealed {
+    fn check_terminal_non_malleable<Pk, Ctx>(
        _frag: &Terminal<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
; +
fn max_satisfaction_size<Pk, Ctx>(ms: &Miniscript<Pk, Ctx>) -> Option<usize>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
; + + fn check_witness<Pk, Ctx>(
        _witness: &[Vec<u8, Global>]
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_global_consensus_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_global_policy_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_local_consensus_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_local_policy_validity<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_global_validity<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn check_local_validity<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), ScriptContextError>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn top_level_type_check<Pk, Ctx>(
        ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn other_top_level_checks<Pk, Ctx>(
        _ms: &Miniscript<Pk, Ctx>
    ) -> Result<(), Error>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +
fn top_level_checks<Pk, Ctx>(ms: &Miniscript<Pk, Ctx>) -> Result<(), Error>
    where
        Pk: MiniscriptKey,
        Ctx: ScriptContext
, + { ... } +}
Expand description

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

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.

+

Depending on script context, the size of a satifaction witness may slightly differ.

+

Provided methods

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.

+

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.

+

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.

+

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.

+

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

+

Check the consensus + policy(if not disabled) rules that are not based +satisfaction

+

Check the consensus + policy(if not disabled) rules including the +ones for satisfaction

+

Check whether the top-level is type B

+

Other top level checks that are context specific

+

Check top level consensus rules.

+

Implementations on Foreign Types

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/keys/type.KeyMap.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/type.KeyMap.html new file mode 100644 index 0000000000..29c7f03dff --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/type.KeyMap.html @@ -0,0 +1,8 @@ +KeyMap in bdk::keys - Rust

Type Definition bdk::keys::KeyMap[]

pub type KeyMap = HashMap<DescriptorPublicKey, DescriptorSecretKey, RandomState>;
Expand description

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/latest/bdk/keys/type.ValidNetworks.html b/static/docs-rs/bdk/nightly/latest/bdk/keys/type.ValidNetworks.html new file mode 100644 index 0000000000..9265ef2898 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/keys/type.ValidNetworks.html @@ -0,0 +1,4 @@ +ValidNetworks in bdk::keys - Rust

Type Definition bdk::keys::ValidNetworks[][src]

pub type ValidNetworks = HashSet<Network>;
Expand description

Set of valid networks for a key

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/macro.descriptor!.html b/static/docs-rs/bdk/nightly/latest/bdk/macro.descriptor!.html new file mode 100644 index 0000000000..976e018bd9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/macro.descriptor!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.descriptor.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/macro.descriptor.html b/static/docs-rs/bdk/nightly/latest/bdk/macro.descriptor.html new file mode 100644 index 0000000000..3cf1c67646 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/macro.descriptor.html @@ -0,0 +1,79 @@ +descriptor in bdk - Rust

Macro bdk::descriptor[][src]

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) *)) => { ... };
+}
+
Expand description

Macro to write full descriptors with code

+

This macro expands to a Result of +DescriptorTemplateOut and DescriptorError

+

The syntax is very similar to the normal descriptor syntax, with the exception that modifiers +cannot be grouped together. For instance, a descriptor fragment like sdv:older(144) has to be +broken up to s:d:v:older(144).

+

The pk(), pk_k() and pk_h() operands can take as argument any type that implements +IntoDescriptorKey. This means that keys can also be written inline as strings, but in that +case they must be wrapped in quotes, which is another difference compared to the standard +descriptor syntax.

+

Example

+

Signature plus timelock descriptor:

+ +
let (my_descriptor, my_keys_map, networks) = bdk::descriptor!(sh(wsh(and_v(v:pk("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"),older(50)))))?;
+
+

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))
+    )
+}?;
+
+#[rustfmt::skip]
+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/latest/bdk/macro.fragment!.html b/static/docs-rs/bdk/nightly/latest/bdk/macro.fragment!.html new file mode 100644 index 0000000000..6eeebba321 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/macro.fragment!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.fragment.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/macro.fragment.html b/static/docs-rs/bdk/nightly/latest/bdk/macro.fragment.html new file mode 100644 index 0000000000..9f748be2b1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/macro.fragment.html @@ -0,0 +1,35 @@ +fragment in bdk - Rust

Macro bdk::fragment[][src]

macro_rules! fragment {
+    ($modif : tt : $($tail : tt) *) => { ... };
+    (true) => { ... };
+    (false) => { ... };
+    (pk_k($key : expr)) => { ... };
+    (pk($key : expr)) => { ... };
+    (pk_h($key : expr)) => { ... };
+    (after($value : expr)) => { ... };
+    (older($value : expr)) => { ... };
+    (sha256($hash : expr)) => { ... };
+    (hash256($hash : expr)) => { ... };
+    (ripemd160($hash : expr)) => { ... };
+    (hash160($hash : expr)) => { ... };
+    (and_v($($inner : tt) *)) => { ... };
+    (and_b($($inner : tt) *)) => { ... };
+    (and_or($($inner : tt) *)) => { ... };
+    (andor($($inner : tt) *)) => { ... };
+    (or_b($($inner : tt) *)) => { ... };
+    (or_d($($inner : tt) *)) => { ... };
+    (or_c($($inner : tt) *)) => { ... };
+    (or_i($($inner : tt) *)) => { ... };
+    (thresh_vec($thresh : expr, $items : expr)) => { ... };
+    (thresh($thresh : expr, $($inner : tt) *)) => { ... };
+    (multi_vec($thresh : expr, $keys : expr)) => { ... };
+    (multi($thresh : expr $(, $key : expr) +)) => { ... };
+    (sortedmulti($($inner : tt) *)) => { ... };
+    (sortedmulti_vec($($inner : tt) *)) => { ... };
+}
+
Expand description

Macro to write descriptor fragments with code

+

This macro will be expanded to an object of type Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), DescriptorError>. It allows writing +fragments of larger descriptors that can be pieced together using fragment!(thresh_vec(m, ...)).

+

The syntax to write macro fragment is the same as documented for the descriptor macro.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/sidebar-items.js new file mode 100644 index 0000000000..5670daf604 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["Error","Errors that can be thrown by the `Wallet`"],["KeychainKind","Types of keychains"],["Utxo","An unspent transaction output (UTXO)."]],"externcrate":[["bitcoin",""],["electrum_client",""],["miniscript",""],["rusqlite",""],["sled",""]],"fn":[["version","Get the version of BDK at runtime"]],"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":[["ConfirmationTime","Block height and timestamp of the block containing the confirmed transaction"],["FeeRate","Fee rate"],["LocalUtxo","An unspent output owned by a `Wallet`."],["TransactionDetails","A wallet transaction"],["WeightedUtxo","A [`Utxo`] with its `satisfaction_weight`."]],"trait":[["Vbytes","Trait implemented by types that can be used to measure weight units."]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/struct.ConfirmationTime.html b/static/docs-rs/bdk/nightly/latest/bdk/struct.ConfirmationTime.html new file mode 100644 index 0000000000..492d39ca1a --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/struct.ConfirmationTime.html @@ -0,0 +1,39 @@ +ConfirmationTime in bdk - Rust

Struct bdk::ConfirmationTime[][src]

pub struct ConfirmationTime {
+    pub height: u32,
+    pub timestamp: u64,
+}
Expand description

Block height and timestamp of the block containing the confirmed transaction

+

Fields

height: u32

confirmation block height

+
timestamp: u64

confirmation block timestamp

+

Implementations

Returns Some ConfirmationTime if both height and timestamp are Some

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/struct.FeeRate.html b/static/docs-rs/bdk/nightly/latest/bdk/struct.FeeRate.html new file mode 100644 index 0000000000..2edd5a044f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/struct.FeeRate.html @@ -0,0 +1,48 @@ +FeeRate in bdk - Rust

Struct bdk::FeeRate[][src]

pub struct FeeRate(_);
Expand description

Fee rate

+

Implementations

Create a new instance of FeeRate given a float fee rate in btc/kvbytes

+

Create a new instance of FeeRate given a float fee rate in satoshi/vbyte

+

Create a new FeeRate with the default min relay fee value

+

Calculate fee rate from fee and weight units (wu).

+

Calculate fee rate from fee and vbytes.

+

Return the value as satoshi/vbyte

+

Calculate absolute fee in Satoshis using size in weight units.

+

Calculate absolute fee in Satoshis using size in virtual bytes.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

The resulting type after applying the - operator.

+

Performs the - operation. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/struct.LocalUtxo.html b/static/docs-rs/bdk/nightly/latest/bdk/struct.LocalUtxo.html new file mode 100644 index 0000000000..1a1805fb94 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/struct.LocalUtxo.html @@ -0,0 +1,41 @@ +LocalUtxo in bdk - Rust

Struct bdk::LocalUtxo[][src]

pub struct LocalUtxo {
+    pub outpoint: OutPoint,
+    pub txout: TxOut,
+    pub keychain: KeychainKind,
+}
Expand description

An unspent output owned by a Wallet.

+

Fields

outpoint: OutPoint

Reference to a transaction output

+
txout: TxOut

Transaction output

+
keychain: KeychainKind

Type of keychain

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/struct.TransactionDetails.html b/static/docs-rs/bdk/nightly/latest/bdk/struct.TransactionDetails.html new file mode 100644 index 0000000000..c15c400d81 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/struct.TransactionDetails.html @@ -0,0 +1,56 @@ +TransactionDetails in bdk - Rust

Struct bdk::TransactionDetails[][src]

pub struct TransactionDetails {
+    pub transaction: Option<Transaction>,
+    pub txid: Txid,
+    pub received: u64,
+    pub sent: u64,
+    pub fee: Option<u64>,
+    pub confirmation_time: Option<ConfirmationTime>,
+    pub verified: bool,
+}
Expand description

A wallet transaction

+

Fields

transaction: Option<Transaction>

Optional transaction

+
txid: Txid

Transaction id

+
received: u64

Received value (sats)

+
sent: u64

Sent value (sats)

+
fee: Option<u64>

Fee value (sats) if available. +The availability of the fee depends on the backend. It’s never None with an Electrum +Server backend, but it could be None with a Bitcoin RPC node without txindex that receive +funds while offline.

+
confirmation_time: Option<ConfirmationTime>

If the transaction is confirmed, contains height and timestamp of the block containing the +transaction, unconfirmed transaction contains None.

+
verified: bool

Whether the tx has been verified against the consensus rules

+

Confirmed txs are considered “verified” by default, while unconfirmed txs are checked to +ensure an unstrusted Blockchain backend can’t trick the +wallet into using an invalid tx as an RBF template.

+

The check is only perfomed when the verify feature is enabled.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Serialize this value into the given Serde serializer. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/struct.WeightedUtxo.html b/static/docs-rs/bdk/nightly/latest/bdk/struct.WeightedUtxo.html new file mode 100644 index 0000000000..219f9a145b --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/struct.WeightedUtxo.html @@ -0,0 +1,36 @@ +WeightedUtxo in bdk - Rust

Struct bdk::WeightedUtxo[][src]

pub struct WeightedUtxo {
+    pub satisfaction_weight: usize,
+    pub utxo: Utxo,
+}
Expand description

A Utxo with its satisfaction_weight.

+

Fields

satisfaction_weight: usize

The weight of the witness data and scriptSig expressed in weight units. This is used to +properly maintain the feerate when adding this input to a transaction during coin selection.

+
utxo: Utxo

The UTXO

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/trait.Vbytes.html b/static/docs-rs/bdk/nightly/latest/bdk/trait.Vbytes.html new file mode 100644 index 0000000000..3248bdd2a4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/trait.Vbytes.html @@ -0,0 +1,7 @@ +Vbytes in bdk - Rust

Trait bdk::Vbytes[][src]

pub trait Vbytes {
+    fn vbytes(self) -> usize;
+}
Expand description

Trait implemented by types that can be used to measure weight units.

+

Required methods

Convert weight units to virtual bytes.

+

Implementations on Foreign Types

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/types/enum.KeychainKind.html b/static/docs-rs/bdk/nightly/latest/bdk/types/enum.KeychainKind.html new file mode 100644 index 0000000000..03524a9b17 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/types/enum.KeychainKind.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bdk/enum.KeychainKind.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/types/enum.Utxo.html b/static/docs-rs/bdk/nightly/latest/bdk/types/enum.Utxo.html new file mode 100644 index 0000000000..03f5add737 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/types/enum.Utxo.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bdk/enum.Utxo.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/types/struct.ConfirmationTime.html b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.ConfirmationTime.html new file mode 100644 index 0000000000..31758b8f04 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.ConfirmationTime.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bdk/struct.ConfirmationTime.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/types/struct.FeeRate.html b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.FeeRate.html new file mode 100644 index 0000000000..fae2b90fdc --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.FeeRate.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bdk/struct.FeeRate.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/types/struct.LocalUtxo.html b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.LocalUtxo.html new file mode 100644 index 0000000000..eeb7867365 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.LocalUtxo.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bdk/struct.LocalUtxo.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/types/struct.TransactionDetails.html b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.TransactionDetails.html new file mode 100644 index 0000000000..4348bd4a45 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.TransactionDetails.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bdk/struct.TransactionDetails.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/types/struct.WeightedUtxo.html b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.WeightedUtxo.html new file mode 100644 index 0000000000..5e7d643399 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/types/struct.WeightedUtxo.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bdk/struct.WeightedUtxo.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/types/trait.Vbytes.html b/static/docs-rs/bdk/nightly/latest/bdk/types/trait.Vbytes.html new file mode 100644 index 0000000000..1074aa3d4a --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/types/trait.Vbytes.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../bdk/trait.Vbytes.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/enum.AddressValidatorError.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/enum.AddressValidatorError.html new file mode 100644 index 0000000000..17d623682d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/enum.AddressValidatorError.html @@ -0,0 +1,57 @@ +AddressValidatorError in bdk::wallet::address_validator - Rust

Enum bdk::wallet::address_validator::AddressValidatorError[][src]

pub enum AddressValidatorError {
+    UserRejected,
+    ConnectionError,
+    TimeoutError,
+    InvalidScript,
+    Message(String),
+}
Expand description

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

+

Tuple Fields of Message

0: String

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Converts a reference to Self into a dynamic trait object of Fail.

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the “name” of the error. Read more

+

Returns a reference to the underlying cause of this failure, if it +is an error that wraps other errors. Read more

+

Returns a reference to the Backtrace carried by this failure, if it +carries one. Read more

+

Provides context for this failure. Read more

+

Wraps this failure in a compatibility wrapper that implements +std::error::Error. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/index.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/index.html new file mode 100644 index 0000000000..2b4abe6753 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/index.html @@ -0,0 +1,46 @@ +bdk::wallet::address_validator - Rust

Module bdk::wallet::address_validator[][src]

Expand description

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_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

+
#[derive(Debug)]
+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 = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+wallet.add_address_validator(Arc::new(PrintAddressAndContinue));
+
+let address = wallet.get_address(New)?;
+println!("Address: {}", address);
+

Enums

+

Errors that can be returned to fail the validation of an address

+

Traits

+

Trait to build address validators

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/sidebar-items.js new file mode 100644 index 0000000000..58959ba340 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/wallet/address_validator/trait.AddressValidator.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/trait.AddressValidator.html new file mode 100644 index 0000000000..6938b2051d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/address_validator/trait.AddressValidator.html @@ -0,0 +1,11 @@ +AddressValidator in bdk::wallet::address_validator - Rust

Trait bdk::wallet::address_validator::AddressValidator[][src]

pub trait AddressValidator: Send + Sync + Debug {
+    fn validate(
        &self,
        keychain: KeychainKind,
        hd_keypaths: &HdKeyPaths,
        script: &Script
    ) -> Result<(), AddressValidatorError>; +}
Expand description

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

Validate or inspect an address

+

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/index.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/index.html new file mode 100644 index 0000000000..1a4e2a573f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/index.html @@ -0,0 +1,73 @@ +bdk::wallet::coin_selection - Rust

Module bdk::wallet::coin_selection[][src]

Expand description

Coin selection

+

This module provides the trait CoinSelectionAlgorithm that can be implemented to +define custom coin selection algorithms.

+

You can specify a custom coin selection algorithm through the coin_selection method on +TxBuilder. DefaultCoinSelectionAlgorithm aliases the coin selection algorithm that will +be used if it is not explicitly set.

+

Example

+
#[derive(Debug)]
+struct AlwaysSpendEverything;
+
+impl<D: Database> CoinSelectionAlgorithm<D> for AlwaysSpendEverything {
+    fn coin_select(
+        &self,
+        database: &D,
+        required_utxos: Vec<WeightedUtxo>,
+        optional_utxos: Vec<WeightedUtxo>,
+        fee_rate: FeeRate,
+        amount_needed: u64,
+        fee_amount: u64,
+    ) -> 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), weighted_utxo| {
+                    **selected_amount += weighted_utxo.utxo.txout().value;
+                    **additional_weight += TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight;
+                    Some(weighted_utxo.utxo)
+                },
+            )
+            .collect::<Vec<_>>();
+        let additional_fees = fee_rate.fee_wu(additional_weight);
+        let amount_needed_with_fees = (fee_amount + additional_fees) + amount_needed;
+        if amount_needed_with_fees > selected_amount {
+            return Err(bdk::Error::InsufficientFunds {
+                needed: amount_needed_with_fees,
+                available: selected_amount,
+            });
+        }
+
+        Ok(CoinSelectionResult {
+            selected: all_utxos_selected,
+            fee_amount: fee_amount + additional_fees,
+        })
+    }
+}
+
+// create wallet, sync, ...
+
+let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+let (psbt, details) = {
+    let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything);
+    builder.add_recipient(to_address.script_pubkey(), 50_000);
+    builder.finish()?
+};
+
+// inspect, sign, broadcast, ...
+
+

Structs

+

Branch and bound coin selection

+

Result of a successful coin selection

+

Simple and dumb coin selection

+

Traits

+

Trait for generalized coin selection algorithms

+

Type Definitions

+

Default coin selection algorithm used by TxBuilder if not +overridden

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/sidebar-items.js new file mode 100644 index 0000000000..8e7e293b89 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/wallet/coin_selection/struct.BranchAndBoundCoinSelection.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/struct.BranchAndBoundCoinSelection.html new file mode 100644 index 0000000000..da3d47f8fc --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/struct.BranchAndBoundCoinSelection.html @@ -0,0 +1,25 @@ +BranchAndBoundCoinSelection in bdk::wallet::coin_selection - Rust

Struct bdk::wallet::coin_selection::BranchAndBoundCoinSelection[][src]

pub struct BranchAndBoundCoinSelection { /* fields omitted */ }
Expand description

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

Create new instance with target size for change output

+

Trait Implementations

Perform the coin selection Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/struct.CoinSelectionResult.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/struct.CoinSelectionResult.html new file mode 100644 index 0000000000..2fc68a28c6 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/struct.CoinSelectionResult.html @@ -0,0 +1,28 @@ +CoinSelectionResult in bdk::wallet::coin_selection - Rust

Struct bdk::wallet::coin_selection::CoinSelectionResult[][src]

pub struct CoinSelectionResult {
+    pub selected: Vec<Utxo>,
+    pub fee_amount: u64,
+}
Expand description

Result of a successful coin selection

+

Fields

selected: Vec<Utxo>

List of outputs selected for use as inputs

+
fee_amount: u64

Total fee amount in satoshi

+

Implementations

The total value of the inputs selected.

+

The total value of the inputs selected from the local wallet.

+

Trait Implementations

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/struct.LargestFirstCoinSelection.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/struct.LargestFirstCoinSelection.html new file mode 100644 index 0000000000..2967b66122 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/struct.LargestFirstCoinSelection.html @@ -0,0 +1,31 @@ +LargestFirstCoinSelection in bdk::wallet::coin_selection - Rust

Struct bdk::wallet::coin_selection::LargestFirstCoinSelection[][src]

pub struct LargestFirstCoinSelection;
Expand description

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

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Perform the coin selection Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.html new file mode 100644 index 0000000000..1aadde9c06 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.html @@ -0,0 +1,22 @@ +CoinSelectionAlgorithm in bdk::wallet::coin_selection - Rust

Trait bdk::wallet::coin_selection::CoinSelectionAlgorithm[][src]

pub trait CoinSelectionAlgorithm<D: Database>: Debug {
+    fn coin_select(
        &self,
        database: &D,
        required_utxos: Vec<WeightedUtxo>,
        optional_utxos: Vec<WeightedUtxo>,
        fee_rate: FeeRate,
        amount_needed: u64,
        fee_amount: u64
    ) -> Result<CoinSelectionResult, Error>; +}
Expand description

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

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
  • +
+

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/type.DefaultCoinSelectionAlgorithm.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/type.DefaultCoinSelectionAlgorithm.html new file mode 100644 index 0000000000..64cd3ecd47 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/coin_selection/type.DefaultCoinSelectionAlgorithm.html @@ -0,0 +1,5 @@ +DefaultCoinSelectionAlgorithm in bdk::wallet::coin_selection - Rust

Type Definition bdk::wallet::coin_selection::DefaultCoinSelectionAlgorithm[][src]

pub type DefaultCoinSelectionAlgorithm = BranchAndBoundCoinSelection;
This is supported on non-test only.
Expand description

Default coin selection algorithm used by TxBuilder if not +overridden

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/enum.AddressIndex.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/enum.AddressIndex.html new file mode 100644 index 0000000000..d20d05b94a --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/enum.AddressIndex.html @@ -0,0 +1,45 @@ +AddressIndex in bdk::wallet - Rust

Enum bdk::wallet::AddressIndex[][src]

pub enum AddressIndex {
+    New,
+    LastUnused,
+    Peek(u32),
+    Reset(u32),
+}
Expand description

The address index selection strategy to use to derived an address from the wallet’s external +descriptor. See Wallet::get_address. If you’re unsure which one to use use WalletIndex::New.

+

Variants

New

Return a new address after incrementing the current descriptor index.

+
LastUnused

Return the address for the current descriptor index if it has not been used in a received +transaction. Otherwise return a new address as with AddressIndex::New.

+

Use with caution, if the wallet has not yet detected an address has been used it could +return an already used address. This function is primarily meant for situations where the +caller is untrusted; for example when deriving donation addresses on-demand for a public +web page.

+
Peek(u32)

Return the address for a specific descriptor index. Does not change the current descriptor +index used by AddressIndex::New and AddressIndex::LastUsed.

+

Use with caution, if an index is given that is less than the current descriptor index +then the returned address may have already been used.

+

Tuple Fields of Peek

0: u32
Reset(u32)

Return the address for a specific descriptor index and reset the current descriptor index +used by AddressIndex::New and AddressIndex::LastUsed to this value.

+

Use with caution, if an index is given that is less than the current descriptor index +then the returned address and subsequent addresses returned by calls to AddressIndex::New +and AddressIndex::LastUsed may have already been used. Also if the index is reset to a +value earlier than the crate::blockchain::Blockchain stop_gap (default is 20) then a +larger stop_gap should be used to monitor for all possibly used addresses.

+

Tuple Fields of Reset

0: u32

Trait Implementations

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/export/index.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/export/index.html new file mode 100644 index 0000000000..62ceef6b8d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/export/index.html @@ -0,0 +1,33 @@ +bdk::wallet::export - Rust

Module bdk::wallet::export[][src]

Expand description

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 = Wallet::new_offline(
+    &import.descriptor(),
+    import.change_descriptor().as_ref(),
+    Network::Testnet,
+    MemoryDatabase::default(),
+)?;
+

Export a Wallet

+
let wallet = 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

+

Structure that contains the export of a wallet

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/export/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/wallet/export/sidebar-items.js new file mode 100644 index 0000000000..06abb3c4ee --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/wallet/export/struct.WalletExport.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/export/struct.WalletExport.html new file mode 100644 index 0000000000..6ff227a440 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/export/struct.WalletExport.html @@ -0,0 +1,43 @@ +WalletExport in bdk::wallet::export - Rust

Struct bdk::wallet::export::WalletExport[][src]

pub struct WalletExport {
+    pub blockheight: u32,
+    pub label: String,
+    // some fields omitted
+}
Expand description

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

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.

+

Return the external descriptor

+

Return the internal descriptor, if present

+

Trait Implementations

Formats the value using the given formatter. Read more

+

Deserialize this value from the given Serde deserializer. Read more

+

The associated error which can be returned from parsing.

+

Parses a string s to return a value of this type. Read more

+

Serialize this value into the given Serde serializer. Read more

+

Converts the given value to a String. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/fn.get_funded_wallet.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/fn.get_funded_wallet.html new file mode 100644 index 0000000000..e93825a76c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/fn.get_funded_wallet.html @@ -0,0 +1,4 @@ +get_funded_wallet in bdk::wallet - Rust

Function bdk::wallet::get_funded_wallet[][src]

pub fn get_funded_wallet(
    descriptor: &str
) -> (Wallet<(), MemoryDatabase>, (String, Option<String>), Txid)
Expand description

Return a fake wallet that appears to be funded for testing.

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

Module bdk::wallet[][src]

Expand description

Wallet

+

This module defines the Wallet structure.

+

Modules

+

Address validation callbacks

+

Coin selection

+

Wallet export

+

Generalized signers

+

Cross-platform time

+

Transaction builder

+

Structs

+

A derived address and the index it was found at +For convenience this automatically derefs to Address

+

A Bitcoin wallet

+

Enums

+

The address index selection strategy to use to derived an address from the wallet’s external +descriptor. See Wallet::get_address. If you’re unsure which one to use use WalletIndex::New.

+

Traits

+

Trait to check if a value is below the dust limit

+

Functions

+

Return a fake wallet that appears to be funded for testing.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/wallet/sidebar-items.js new file mode 100644 index 0000000000..20bdf7e32f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["AddressIndex","The address index selection strategy to use to derived an address from the wallet’s external descriptor. See [`Wallet::get_address`]. If you’re unsure which one to use use `WalletIndex::New`."]],"fn":[["get_funded_wallet","Return a fake wallet that appears to be funded for testing."]],"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":[["AddressInfo","A derived address and the index it was found at For convenience this automatically derefs to `Address`"],["Wallet","A Bitcoin wallet"]],"trait":[["IsDust","Trait to check if a value is below the dust limit"]]}); \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/enum.SignerError.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/enum.SignerError.html new file mode 100644 index 0000000000..e85b17844b --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/enum.SignerError.html @@ -0,0 +1,70 @@ +SignerError in bdk::wallet::signer - Rust

Enum bdk::wallet::signer::SignerError[][src]

pub enum SignerError {
+    MissingKey,
+    InvalidKey,
+    UserCanceled,
+    InputIndexOutOfRange,
+    MissingNonWitnessUtxo,
+    InvalidNonWitnessUtxo,
+    MissingWitnessUtxo,
+    MissingWitnessScript,
+    MissingHdKeypath,
+    NonStandardSighash,
+}
Expand description

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

+
NonStandardSighash

The psbt contains a non-SIGHASH_ALL sighash in one of its input and the user hasn’t +explicitly allowed them

+

To enable signing transactions with non-standard sighashes set +SignOptions::allow_all_sighashes to true.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Converts a reference to Self into a dynamic trait object of Fail.

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Returns the “name” of the error. Read more

+

Returns a reference to the underlying cause of this failure, if it +is an error that wraps other errors. Read more

+

Returns a reference to the Backtrace carried by this failure, if it +carries one. Read more

+

Provides context for this failure. Read more

+

Wraps this failure in a compatibility wrapper that implements +std::error::Error. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/enum.SignerId.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/enum.SignerId.html new file mode 100644 index 0000000000..bf5403e67f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/enum.SignerId.html @@ -0,0 +1,53 @@ +SignerId in bdk::wallet::signer - Rust

Enum bdk::wallet::signer::SignerId[][src]

pub enum SignerId {
+    PkHash(Hash),
+    Fingerprint(Fingerprint),
+    Dummy(u64),
+}
Expand description

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

+

Tuple Fields of PkHash

0: Hash
Fingerprint(Fingerprint)

The fingerprint of a BIP32 extended key

+

Tuple Fields of Fingerprint

0: Fingerprint
Dummy(u64)

Dummy identifier

+

Tuple Fields of Dummy

0: u64

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/index.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/index.html new file mode 100644 index 0000000000..20e1930378 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/index.html @@ -0,0 +1,60 @@ +bdk::wallet::signer - Rust

Module bdk::wallet::signer[][src]

Expand description

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 id(&self, _secp: &Secp256k1<All>) -> SignerId {
+        self.device.get_id()
+    }
+
+    fn sign_whole_tx(&self) -> bool {
+        false
+    }
+}
+
+let custom_signer = CustomSigner::connect();
+
+let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+let mut wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+wallet.add_signer(
+    KeychainKind::External,
+    SignerOrdering(200),
+    Arc::new(custom_signer)
+);
+
+

Structs

+

Options for a software signer

+

Defines the order in which signers are called

+

Container for multiple signers

+

Enums

+

Signing error

+

Identifier of a signer in the SignersContainers. Used as a key to find the right signer among +multiple of them

+

Traits

+

Trait for signers

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/sidebar-items.js new file mode 100644 index 0000000000..5700429cf3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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":[["SignOptions","Options for a software signer"],["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/latest/bdk/wallet/signer/struct.SignOptions.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/struct.SignOptions.html new file mode 100644 index 0000000000..e981dcc3d4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/struct.SignOptions.html @@ -0,0 +1,50 @@ +SignOptions in bdk::wallet::signer - Rust

Struct bdk::wallet::signer::SignOptions[][src]

pub struct SignOptions {
+    pub trust_witness_utxo: bool,
+    pub assume_height: Option<u32>,
+    pub allow_all_sighashes: bool,
+}
Expand description

Options for a software signer

+

Adjust the behavior of our software signers and the way a transaction is finalized

+

Fields

trust_witness_utxo: bool

Whether the signer should trust the witness_utxo, if the non_witness_utxo hasn’t been +provided

+

Defaults to false to mitigate the “SegWit bug” which chould trick the wallet into +paying a fee larger than expected.

+

Some wallets, especially if relatively old, might not provide the non_witness_utxo for +SegWit transactions in the PSBT they generate: in those cases setting this to true +should correctly produce a signature, at the expense of an increased trust in the creator +of the PSBT.

+

For more details see: https://blog.trezor.io/details-of-firmware-updates-for-trezor-one-version-1-9-1-and-trezor-model-t-version-2-3-1-1eba8f60f2dd

+
assume_height: Option<u32>

Whether the wallet should assume a specific height has been reached when trying to finalize +a transaction

+

The wallet will only “use” a timelock to satisfy the spending policy of an input if the +timelock height has already been reached. This option allows overriding the “current height” to let the +wallet use timelocks in the future to spend a coin.

+
allow_all_sighashes: bool

Whether the signer should use the sighash_type set in the PSBT when signing, no matter +what its value is

+

Defaults to false which will only allow signing using SIGHASH_ALL.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/struct.SignerOrdering.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/struct.SignerOrdering.html new file mode 100644 index 0000000000..05b7104659 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/struct.SignerOrdering.html @@ -0,0 +1,45 @@ +SignerOrdering in bdk::wallet::signer - Rust

Struct bdk::wallet::signer::SignerOrdering[][src]

pub struct SignerOrdering(pub usize);
Expand description

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.

+

Tuple Fields

0: usize

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/struct.SignersContainer.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/struct.SignersContainer.html new file mode 100644 index 0000000000..3f8eae4d00 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/struct.SignersContainer.html @@ -0,0 +1,37 @@ +SignersContainer in bdk::wallet::signer - Rust

Struct bdk::wallet::signer::SignersContainer[][src]

pub struct SignersContainer(_);
Expand description

Container for multiple signers

+

Implementations

Create a map of public keys to secret keys

+

Default constructor

+

Adds an external signer to the container for the specified id. Optionally returns the +signer that was previously in the container, if any

+

Removes a signer from the container and returns it

+

Returns the list of identifiers of all the signers in the container

+

Returns the list of signers in the container, sorted by lowest to highest ordering

+

Finds the signer with lowest ordering for a given id in the container.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/trait.Signer.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/trait.Signer.html new file mode 100644 index 0000000000..0ebe55a44a --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/signer/trait.Signer.html @@ -0,0 +1,25 @@ +Signer in bdk::wallet::signer - Rust

Trait bdk::wallet::signer::Signer[][src]

pub trait Signer: Debug + Send + Sync {
+    fn sign(
        &self,
        psbt: &mut PartiallySignedTransaction,
        input_index: Option<usize>,
        secp: &Secp256k1<All>
    ) -> Result<(), SignerError>; +
fn sign_whole_tx(&self) -> bool; +
fn id(&self, secp: &Secp256k1<All>) -> SignerId; + + fn descriptor_secret_key(&self) -> Option<DescriptorSecretKey> { ... } +}
Expand description

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

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.

+

Return whether or not the signer signs the whole transaction in one go instead of every +input individually

+

Return the SignerId for this signer

+

The SignerId can be used to lookup a signer in the Wallet’s signers map or to +compare two signers.

+

Provided methods

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).

+

Implementations on Foreign Types

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/struct.AddressInfo.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/struct.AddressInfo.html new file mode 100644 index 0000000000..f97a3cd4d2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/struct.AddressInfo.html @@ -0,0 +1,46 @@ +AddressInfo in bdk::wallet - Rust

Struct bdk::wallet::AddressInfo[][src]

pub struct AddressInfo {
+    pub index: u32,
+    pub address: Address,
+}
Expand description

A derived address and the index it was found at +For convenience this automatically derefs to Address

+

Fields

index: u32

Child index of this address

+
address: Address

Address

+

Methods from Deref<Target = Address>

Get the address type of the address. +None if unknown or non-standard.

+

Check whether or not the address is following Bitcoin +standardness rules.

+

Segwit addresses with unassigned witness versions or non-standard +program sizes are considered non-standard.

+

Generates a script pubkey spending to this address

+

Creates a URI string bitcoin:address optimized to be encoded in QR codes.

+

If the address is bech32, both the schema and the address become uppercase. +If the address is base58, the schema is lowercase and the address is left mixed case.

+

Quoting BIP 173 “inside QR codes uppercase SHOULD be used, as those permit the use of +alphanumeric mode, which is 45% more compact than the normal byte mode.”

+

Trait Implementations

Formats the value using the given formatter. Read more

+

The resulting type after dereferencing.

+

Dereferences the value.

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/struct.Wallet.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/struct.Wallet.html new file mode 100644 index 0000000000..280ce6b2f3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/struct.Wallet.html @@ -0,0 +1,114 @@ +Wallet in bdk::wallet - Rust

Struct bdk::wallet::Wallet[][src]

pub struct Wallet<B, D> { /* fields omitted */ }
Expand description

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” if it is the unit type (). Offline wallets only expose +methods that don’t need any interaction with the blockchain to work.

+

Implementations

Create a new “offline” wallet

+

Get the Bitcoin network the wallet is using.

+

Return a derived address using the external descriptor, see AddressIndex for +available address index selection strategies. If none of the keys in the descriptor are derivable +(ie. does not end with /*) then the same address will always be returned for any AddressIndex.

+

Return whether or not a script is part of this wallet (either internal or external)

+

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.

+

Returns the UTXO owned by this wallet corresponding to outpoint if it exists in the +wallet’s database.

+

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.

+

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.

+

Add an external signer

+

See the signer module for an example.

+

Add an address validator

+

See the address_validator module for an example.

+

Start building a transaction.

+

This returns a blank TxBuilder from which you can specify the parameters for the transaction.

+
Example
+
let (psbt, details) = {
+   let mut builder =  wallet.build_tx();
+   builder
+       .add_recipient(to_address.script_pubkey(), 50_000);
+   builder.finish()?
+};
+
+// sign and broadcast ...
+

Bump the fee of a transaction previously created with this wallet.

+

Returns an error if the transaction is already confirmed or doesn’t explicitly signal +repalce by fee (RBF). If the transaction can be fee bumped then it returns a TxBuilder +pre-populated with the inputs and outputs of the original transaction.

+
Example
+
let (mut psbt, _) = {
+    let mut builder = wallet.build_tx();
+    builder
+        .add_recipient(to_address.script_pubkey(), 50_000)
+        .enable_rbf();
+    builder.finish()?
+};
+let _ = wallet.sign(&mut psbt, SignOptions::default())?;
+let tx = psbt.extract_tx();
+// broadcast tx but it's taking too long to confirm so we want to bump the fee
+let (mut psbt, _) =  {
+    let mut builder = wallet.build_fee_bump(tx.txid())?;
+    builder
+        .fee_rate(FeeRate::from_sat_per_vb(5.0));
+    builder.finish()?
+};
+
+let _ = wallet.sign(&mut psbt, SignOptions::default())?;
+let fee_bumped_tx = psbt.extract_tx();
+// broadcast fee_bumped_tx to replace original
+

Sign a transaction with all the wallet’s signers, in the order specified by every signer’s +SignerOrdering

+

The SignOptions can be used to tweak the behavior of the software signers, and the way +the transaction is finalized at the end. Note that it can’t be guaranteed that every +signers will follow the options, but the “software signers” (WIF keys and xprv) defined +in this library will.

+
Example
+
let (mut psbt, _) = {
+    let mut builder = wallet.build_tx();
+    builder.add_recipient(to_address.script_pubkey(), 50_000);
+    builder.finish()?
+};
+let  finalized = wallet.sign(&mut psbt, SignOptions::default())?;
+assert!(finalized, "we should have signed all the inputs");
+

Return the spending policies for the wallet’s descriptor

+

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

+

Try to finalize a PSBT

+

The SignOptions can be used to tweak the behavior of the finalizer.

+

Return the secp256k1 context used for all signing operations

+

Returns the descriptor used to create adddresses for a particular keychain.

+

get the corresponding PSBT Input for a LocalUtxo

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Create a new “online” wallet

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Sync the internal database with the blockchain

+

Return a reference to the internal blockchain client

+
This is supported on non-WebAssembly and non-crate feature async-interface only.

Broadcast a transaction to the network

+

Trait Implementations

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/time/fn.get_timestamp.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/time/fn.get_timestamp.html new file mode 100644 index 0000000000..8ad1f886cf --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/time/fn.get_timestamp.html @@ -0,0 +1,4 @@ +get_timestamp in bdk::wallet::time - Rust

Function bdk::wallet::time::get_timestamp[][src]

pub fn get_timestamp() -> u64
This is supported on non-WebAssembly only.
Expand description

Return the current timestamp in seconds

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/time/index.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/time/index.html new file mode 100644 index 0000000000..439faff9e4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/time/index.html @@ -0,0 +1,10 @@ +bdk::wallet::time - Rust

Module bdk::wallet::time[][src]

Expand description

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_timestampNon-WebAssembly

Return the current timestamp in seconds

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/time/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/wallet/time/sidebar-items.js new file mode 100644 index 0000000000..22164ef49f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/bdk/wallet/trait.IsDust.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/trait.IsDust.html new file mode 100644 index 0000000000..368609d8ab --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/trait.IsDust.html @@ -0,0 +1,7 @@ +IsDust in bdk::wallet - Rust

Trait bdk::wallet::IsDust[][src]

pub trait IsDust {
+    fn is_dust(&self) -> bool;
+}
Expand description

Trait to check if a value is below the dust limit

+

Required methods

Check whether or not a value is below dust limit

+

Implementations on Foreign Types

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/enum.ChangeSpendPolicy.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/enum.ChangeSpendPolicy.html new file mode 100644 index 0000000000..d7c76a34e9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/enum.ChangeSpendPolicy.html @@ -0,0 +1,51 @@ +ChangeSpendPolicy in bdk::wallet::tx_builder - Rust

Enum bdk::wallet::tx_builder::ChangeSpendPolicy[][src]

pub enum ChangeSpendPolicy {
+    ChangeAllowed,
+    OnlyChange,
+    ChangeForbidden,
+}
Expand description

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

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/enum.TxOrdering.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/enum.TxOrdering.html new file mode 100644 index 0000000000..03cbae2eee --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/enum.TxOrdering.html @@ -0,0 +1,52 @@ +TxOrdering in bdk::wallet::tx_builder - Rust

Enum bdk::wallet::tx_builder::TxOrdering[][src]

pub enum TxOrdering {
+    Shuffle,
+    Untouched,
+    Bip69Lexicographic,
+}
Expand description

Ordering of the transaction’s inputs and outputs

+

Variants

Shuffle

Randomized (default)

+
Untouched

Unchanged

+
Bip69Lexicographic

BIP69 / Lexicographic

+

Implementations

Sort transaction inputs and outputs by TxOrdering variant

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/index.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/index.html new file mode 100644 index 0000000000..aaf29b0c2b --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/index.html @@ -0,0 +1,28 @@ +bdk::wallet::tx_builder - Rust

Module bdk::wallet::tx_builder[][src]

Expand description

Transaction builder

+

Example

+
// create a TxBuilder from a wallet
+let mut tx_builder = wallet.build_tx();
+
+tx_builder
+    // Create a transaction with one output to `to_address` of 50_000 satoshi
+    .add_recipient(to_address.script_pubkey(), 50_000)
+    // With a custom fee rate of 5.0 satoshi/vbyte
+    .fee_rate(FeeRate::from_sat_per_vb(5.0))
+    // Only spend non-change outputs
+    .do_not_spend_change()
+    // Turn on RBF signaling
+    .enable_rbf();
+let (psbt, tx_details) = tx_builder.finish()?;
+

Structs

+

Marker type to indicate the TxBuilder is being used to bump the fee of an existing transaction.

+

Marker type to indicate the TxBuilder is being used to create a new transaction (as opposed +to bumping the fee of an existing one).

+

A transaction builder

+

Enums

+

Policy regarding the use of change outputs when creating a transaction

+

Ordering of the transaction’s inputs and outputs

+

Traits

+

Context in which the TxBuilder is valid

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/sidebar-items.js b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/sidebar-items.js new file mode 100644 index 0000000000..dcd52e5dff --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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","Marker type to indicate the [`TxBuilder`] is being used to bump the fee of an existing transaction."],["CreateTx","Marker type to indicate the [`TxBuilder`] is being used to create a new transaction (as opposed to bumping the fee of an existing one)."],["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/latest/bdk/wallet/tx_builder/struct.BumpFee.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/struct.BumpFee.html new file mode 100644 index 0000000000..82a9195942 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/struct.BumpFee.html @@ -0,0 +1,28 @@ +BumpFee in bdk::wallet::tx_builder - Rust

Struct bdk::wallet::tx_builder::BumpFee[][src]

pub struct BumpFee;
Expand description

Marker type to indicate the TxBuilder is being used to bump the fee of an existing transaction.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/struct.CreateTx.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/struct.CreateTx.html new file mode 100644 index 0000000000..bc3c167a86 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/struct.CreateTx.html @@ -0,0 +1,29 @@ +CreateTx in bdk::wallet::tx_builder - Rust

Struct bdk::wallet::tx_builder::CreateTx[][src]

pub struct CreateTx;
Expand description

Marker type to indicate the TxBuilder is being used to create a new transaction (as opposed +to bumping the fee of an existing one).

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Returns the “default value” for a type. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/struct.TxBuilder.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/struct.TxBuilder.html new file mode 100644 index 0000000000..007f0c8545 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/struct.TxBuilder.html @@ -0,0 +1,226 @@ +TxBuilder in bdk::wallet::tx_builder - Rust

Struct bdk::wallet::tx_builder::TxBuilder[][src]

pub struct TxBuilder<'a, B, D, Cs, Ctx> { /* fields omitted */ }
Expand description

A transaction builder

+

A TxBuilder is created by calling build_tx or build_fee_bump on a wallet. After +assigning it, you set options on it until finally calling finish to consume the builder and +generate the transaction.

+

Each option setting method on TxBuilder takes and returns &mut self so you can chain calls +as in the following example:

+ +
// chaining
+let (psbt1, details) = {
+    let mut builder = wallet.build_tx();
+    builder
+        .ordering(TxOrdering::Untouched)
+        .add_recipient(addr1.script_pubkey(), 50_000)
+        .add_recipient(addr2.script_pubkey(), 50_000);
+    builder.finish()?
+};
+
+// non-chaining
+let (psbt2, details) = {
+    let mut builder = wallet.build_tx();
+    builder.ordering(TxOrdering::Untouched);
+    for addr in &[addr1, addr2] {
+        builder.add_recipient(addr.script_pubkey(), 50_000);
+    }
+    builder.finish()?
+};
+
+assert_eq!(
+    psbt1.global.unsigned_tx.output[..2],
+    psbt2.global.unsigned_tx.output[..2]
+);
+

At the moment coin_selection is an exception to the rule as it consumes self. +This means it is usually best to call coin_selection on the return value of build_tx before assigning it.

+

For further examples see this module’s documentation;

+

Implementations

Set a custom fee rate

+

Set an absolute fee

+

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 = wallet
+    .build_tx()
+    .add_recipient(to_address.script_pubkey(), 50_000)
+    .policy_path(path, KeychainKind::External);
+
+

Add the list of outpoints to the internal list of UTXOs that must be spent.

+

If an error occurs while adding any of the UTXOs then none of them are added and the error is returned.

+

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.

+

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.

+

Add a foreign UTXO i.e. a UTXO not owned by this wallet.

+

At a minimum to add a foreign UTXO we need:

+
    +
  1. outpoint: To add it to the raw transaction.
  2. +
  3. psbt_input: To know the value.
  4. +
  5. satisfaction_weight: To know how much weight/vbytes the input will add to the transaction for fee calculation.
  6. +
+

There are several security concerns about adding foregin UTXOs that application +developers should consider. First, how do you know the value of the input is correct? If a +non_witness_utxo is provided in the psbt_input then this method implicitly verifies the +value by checking it against the transaction. If only a witness_utxo is provided then this +method doesn’t verify the value but just takes it as a given – it is up to you to check +that whoever sent you the input_psbt was not lying!

+

Secondly, you must somehow provide satisfaction_weight of the input. Depending on your +application it may be important that this be known precisely. If not, a malicious +counterparty may fool you into putting in a value that is too low, giving the transaction a +lower than expected feerate. They could also fool you into putting a value that is too high +causing you to pay a fee that is too high. The party who is broadcasting the transaction can +of course check the real input weight matches the expected weight prior to broadcasting.

+

To guarantee the satisfaction_weight is correct, you can require the party providing the +psbt_input provide a miniscript descriptor for the input so you can check it against the +script_pubkey and then ask it for the max_satisfaction_weight.

+

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

+
Errors
+

This method returns errors in the following circumstances:

+
    +
  1. The psbt_input does not contain a witness_utxo or non_witness_utxo.
  2. +
  3. The data in non_witness_utxo does not match what is in outpoint.
  4. +
+

Note unless you set only_witness_utxo any psbt_input you pass to this method must +have non_witness_utxo set otherwise you will get an error when finish is called.

+

Only spend utxos added by add_utxo.

+

The wallet will not add additional utxos to the transaction even if they are needed to +make the transaction valid.

+

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::add_utxo +have priority over these. See the docs of the two linked methods for more details.

+

Add a utxo to the internal list of unspendable utxos

+

It’s important to note that the “must-be-spent” utxos added with TxBuilder::add_utxo +have priority over this. See the docs of the two linked methods for more details.

+

Sign with a specific sig hash

+

Use this option very carefully

+

Choose the ordering for inputs and outputs of the transaction

+

Use a specific nLockTime while creating the transaction

+

This can cause conflicts if the wallet’s descriptors contain an “after” (OP_CLTV) operator.

+

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.

+

Do not spend change outputs

+

This effectively adds all the change outputs to the “unspendable” list. See +TxBuilder::unspendable.

+

Only spend change outputs

+

This effectively adds all the non-change outputs to the “unspendable” list. See +TxBuilder::unspendable.

+

Only Fill-in the psbt::Input::witness_utxo field when spending from +SegWit descriptors.

+

This reduces the size of the PSBT, but some signers might reject them due to the lack of +the non_witness_utxo.

+

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.

+

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.

+

Spend all the available inputs. This respects filters like TxBuilder::unspendable and the change policy.

+

Choose the coin selection algorithm

+

Overrides the DefaultCoinSelectionAlgorithm.

+

Note that this function consumes the builder and returns it so it is usually best to put this as the first call on the builder.

+

Finish the building the transaction.

+

Returns the BIP174 “PSBT” and summary details about the transaction.

+

Enable signaling RBF

+

This will use the default nSequence value of 0xFFFFFFFD.

+

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.

+

Replace the recipients already added with a new list

+

Add a recipient to the internal list

+

Sets the address to drain excess coins to.

+

Usually, when there are excess coins they are sent to a change address generated by the +wallet. This option replaces the usual change address with an arbitrary script_pubkey of +your choosing. Just as with a change output, if the drain output is not needed (the excess +coins are too small) it will not be included in the resulting transaction. The only +difference is that it is valid to use drain_to without setting any ordinary recipients +with add_recipient (but it is perfectly fine to add recipients as well).

+

When bumping the fees of a transaction made with this option, you probably want to +use allow_shrinking to allow this output to be reduced to pay for the extra fees.

+
Example
+

drain_to is very useful for draining all the coins in a wallet with drain_wallet to a +single address.

+ +
let mut tx_builder = wallet.build_tx();
+
+tx_builder
+    // Spend all outputs in this wallet.
+    .drain_wallet()
+    // Send the excess (which is all the coins minus the fee) to this address.
+    .drain_to(to_address.script_pubkey())
+    .fee_rate(FeeRate::from_sat_per_vb(5.0))
+    .enable_rbf();
+let (psbt, tx_details) = tx_builder.finish()?;
+

Explicitly tells the wallet that it is allowed to reduce the fee of the output matching this +script_pubkey in order to bump the transaction fee. Without specifying this the wallet +will attempt to find a change output to shrink instead.

+

Note that the output may shrink to below the dust limit and therefore be removed. If it is +preserved then it is currently not guaranteed to be in the same position as it was +originally.

+

Returns an Err if script_pubkey can’t be found among the recipients of the +transaction we are bumping.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

Should always be Self

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/trait.TxBuilderContext.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/trait.TxBuilderContext.html new file mode 100644 index 0000000000..15e506e385 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/tx_builder/trait.TxBuilderContext.html @@ -0,0 +1,4 @@ +TxBuilderContext in bdk::wallet::tx_builder - Rust

Trait bdk::wallet::tx_builder::TxBuilderContext[][src]

pub trait TxBuilderContext: Debug + Default + Clone { }
Expand description

Context in which the TxBuilder is valid

+

Implementors

+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/bdk/wallet/utils/trait.IsDust.html b/static/docs-rs/bdk/nightly/latest/bdk/wallet/utils/trait.IsDust.html new file mode 100644 index 0000000000..c0e56858e7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/bdk/wallet/utils/trait.IsDust.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../bdk/wallet/trait.IsDust.html...

+ + + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/brush.svg b/static/docs-rs/bdk/nightly/latest/brush.svg new file mode 100644 index 0000000000..ea266e856a --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/brush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/clipboard.svg b/static/docs-rs/bdk/nightly/latest/clipboard.svg new file mode 100644 index 0000000000..8adbd99630 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/clipboard.svg @@ -0,0 +1 @@ + diff --git a/static/docs-rs/bdk/nightly/latest/crates.js b/static/docs-rs/bdk/nightly/latest/crates.js new file mode 100644 index 0000000000..0abc2ef87a --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["bdk"]; \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/dark.css b/static/docs-rs/bdk/nightly/latest/dark.css new file mode 100644 index 0000000000..cb246dc8a0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/dark.css @@ -0,0 +1 @@ +body{background-color:#353535;color:#ddd;}h1,h2,h3,h4{color:#ddd;}h1.fqn{border-bottom-color:#d2d2d2;}h2,h3,h4{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,.rustdoc.source .example-wrap{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,.docblock h6{border-bottom-color:#DDD;}.docblock table td,.docblock table th{border-color:#ddd;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#ddd;}.search-results a:hover{background-color:#777;}.search-results a:focus{color:#eee !important;background-color:#616161;}.search-results a:focus span{color:#eee !important;}a.result-trait:focus{background-color:#013191;}a.result-traitalias:focus{background-color:#013191;}a.result-mod:focus,a.result-externcrate:focus{background-color:#afc6e4;}a.result-mod:focus{background-color:#803a1b;}a.result-externcrate:focus{background-color:#396bac;}a.result-enum:focus{background-color:#5b4e68;}a.result-struct:focus{background-color:#194e9f;}a.result-union:focus{background-color:#b7bd49;}a.result-fn:focus,a.result-method:focus,a.result-tymethod:focus{background-color:#4950ed;}a.result-type:focus{background-color:#38902c;}a.result-foreigntype:focus{background-color:#b200d6;}a.result-attr:focus,a.result-derive:focus,a.result-macro:focus{background-color:#217d1c;}a.result-constant:focus,a.result-static:focus{background-color:#0063cc;}a.result-primitive:focus{background-color:#00708a;}a.result-keyword:focus{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;}body.source .example-wrap pre.rust a{background:#333;}.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;}details.rustdoc-toggle>summary.hideme>span,details.rustdoc-toggle>summary::before,details.undocumented>summary::before{color:#999;}details.rustdoc-toggle>summary::before,details.undocumented>summary::before{filter:invert(100%);}#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-input:disabled{background-color:#c5c4c4;}#crate-search+.search-input:focus{box-shadow:0 0 8px 4px #078dd8;}.module-item .stab,.import-item .stab{color:#ddd;}.stab.unstable{background:#FFF5D6;border-color:#FFC600;color:#2f2f2f;}.stab.deprecated{background:#ffc4c4;border-color:#db7b7b;color:#2f2f2f;}.stab.portability{background:#F3DFFF;border-color:#b07bdb;color:#2f2f2f;}.stab.portability>code{background:none;}#help>div{background:#4d4d4d;border-color:#bfbfbf;}#help span.bottom,#help span.top{border-color:#bfbfbf;}#help dt{border-color:#bfbfbf;background:rgba(0,0,0,0);}.since{color:grey;}.result-name .primitive>i,.result-name .keyword>i{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,.code-attribute{color:#999;}:target,:target>*{background-color:#494a3d;}:target{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::after{background-color:#000;color:#fff;border-color:#000;}.tooltip::before{border-color:transparent black transparent transparent;}.notable-traits-tooltiptext{background-color:#111;border-color:#777;}.notable-traits-tooltiptext .notable{border-bottom-color:#d2d2d2;}#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;}#copy-path{color:#999;}#copy-path>img{filter:invert(50%);}#copy-path:hover>img{filter:invert(65%);}#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 .result-name span.alias{color:#fff;}.search-results .result-name 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/latest/down-arrow.svg b/static/docs-rs/bdk/nightly/latest/down-arrow.svg new file mode 100644 index 0000000000..35437e77a7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/down-arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/favicon-16x16.png b/static/docs-rs/bdk/nightly/latest/favicon-16x16.png new file mode 100644 index 0000000000..7cfe6c1355 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/favicon-16x16.png differ diff --git a/static/docs-rs/bdk/nightly/latest/favicon-32x32.png b/static/docs-rs/bdk/nightly/latest/favicon-32x32.png new file mode 100644 index 0000000000..5109c1de8b Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/favicon-32x32.png differ diff --git a/static/docs-rs/bdk/nightly/latest/favicon.svg b/static/docs-rs/bdk/nightly/latest/favicon.svg new file mode 100644 index 0000000000..8b34b51198 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/favicon.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/static/docs-rs/bdk/nightly/latest/implementors/alloc/string/trait.ToString.js b/static/docs-rs/bdk/nightly/latest/implementors/alloc/string/trait.ToString.js new file mode 100644 index 0000000000..f3e935dbe1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/alloc/string/trait.ToString.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl ToString for WalletExport","synthetic":false,"types":["bdk::wallet::export::WalletExport"]}]; +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/latest/implementors/bdk/blockchain/trait.Blockchain.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/blockchain/trait.Blockchain.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/blockchain/trait.ConfigurableBlockchain.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/blockchain/trait.ConfigurableBlockchain.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/blockchain/trait.Progress.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/blockchain/trait.Progress.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/database/trait.BatchDatabase.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/database/trait.BatchDatabase.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/database/trait.BatchOperations.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/database/trait.BatchOperations.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/database/trait.ConfigurableDatabase.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/database/trait.ConfigurableDatabase.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/database/trait.Database.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/database/trait.Database.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/descriptor/template/trait.DescriptorTemplate.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/descriptor/template/trait.DescriptorTemplate.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/descriptor/trait.ExtractPolicy.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/descriptor/trait.ExtractPolicy.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/descriptor/trait.IntoWalletDescriptor.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/descriptor/trait.IntoWalletDescriptor.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/bdk/descriptor/trait.IntoWalletDescriptor.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/latest/implementors/bdk/keys/trait.DerivableKey.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/keys/trait.DerivableKey.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/keys/trait.ExtScriptContext.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/keys/trait.ExtScriptContext.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/keys/trait.GeneratableDefaultOptions.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/keys/trait.GeneratableDefaultOptions.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/keys/trait.GeneratableKey.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/keys/trait.GeneratableKey.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/keys/trait.IntoDescriptorKey.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/keys/trait.IntoDescriptorKey.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/bdk/keys/trait.IntoDescriptorKey.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/latest/implementors/bdk/keys/trait.ScriptContext.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/keys/trait.ScriptContext.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/trait.Vbytes.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/trait.Vbytes.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/bdk/trait.Vbytes.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/latest/implementors/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/wallet/coin_selection/trait.CoinSelectionAlgorithm.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/wallet/signer/trait.Signer.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/wallet/signer/trait.Signer.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/wallet/trait.IsDust.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/wallet/trait.IsDust.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/bdk/wallet/tx_builder/trait.TxBuilderContext.js b/static/docs-rs/bdk/nightly/latest/implementors/bdk/wallet/tx_builder/trait.TxBuilderContext.js new file mode 100644 index 0000000000..8262d3bea5 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/implementors/core/clone/trait.Clone.js b/static/docs-rs/bdk/nightly/latest/implementors/core/clone/trait.Clone.js new file mode 100644 index 0000000000..fc88bc958d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/clone/trait.Clone.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Clone for AnyBlockchainConfig","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl Clone for ElectrumBlockchainConfig","synthetic":false,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl Clone for EsploraBlockchainConfig","synthetic":false,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl Clone for BitcoinPeerConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl Clone for CompactFiltersBlockchainConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl Clone for Capability","synthetic":false,"types":["bdk::blockchain::Capability"]},{"text":"impl Clone for NoopProgress","synthetic":false,"types":["bdk::blockchain::NoopProgress"]},{"text":"impl Clone for LogProgress","synthetic":false,"types":["bdk::blockchain::LogProgress"]},{"text":"impl<'s> Clone for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Clone for PkOrF","synthetic":false,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl Clone for SatisfiableItem","synthetic":false,"types":["bdk::descriptor::policy::SatisfiableItem"]},{"text":"impl Clone for Satisfaction","synthetic":false,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl Clone for Policy","synthetic":false,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl Clone for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl<'a> Clone for BuildSatisfaction<'a>","synthetic":false,"types":["bdk::descriptor::policy::BuildSatisfaction"]},{"text":"impl Clone for ScriptContextEnum","synthetic":false,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl Clone for PrivateKeyGenerateOptions","synthetic":false,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl Clone for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl Clone for FeeRate","synthetic":false,"types":["bdk::types::FeeRate"]},{"text":"impl Clone for LocalUtxo","synthetic":false,"types":["bdk::types::LocalUtxo"]},{"text":"impl Clone for WeightedUtxo","synthetic":false,"types":["bdk::types::WeightedUtxo"]},{"text":"impl Clone for Utxo","synthetic":false,"types":["bdk::types::Utxo"]},{"text":"impl Clone for TransactionDetails","synthetic":false,"types":["bdk::types::TransactionDetails"]},{"text":"impl Clone for ConfirmationTime","synthetic":false,"types":["bdk::types::ConfirmationTime"]},{"text":"impl Clone for AddressValidatorError","synthetic":false,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl Clone for LargestFirstCoinSelection","synthetic":false,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl Clone for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl Clone for SignerError","synthetic":false,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl Clone for SignerOrdering","synthetic":false,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl Clone for SignersContainer","synthetic":false,"types":["bdk::wallet::signer::SignersContainer"]},{"text":"impl Clone for SignOptions","synthetic":false,"types":["bdk::wallet::signer::SignOptions"]},{"text":"impl Clone for CreateTx","synthetic":false,"types":["bdk::wallet::tx_builder::CreateTx"]},{"text":"impl Clone for BumpFee","synthetic":false,"types":["bdk::wallet::tx_builder::BumpFee"]},{"text":"impl<'a, Cs: Clone, Ctx, B, D> Clone for TxBuilder<'a, B, D, Cs, Ctx>","synthetic":false,"types":["bdk::wallet::tx_builder::TxBuilder"]},{"text":"impl Clone for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Clone for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]}]; +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/latest/implementors/core/cmp/trait.Eq.js b/static/docs-rs/bdk/nightly/latest/implementors/core/cmp/trait.Eq.js new file mode 100644 index 0000000000..f7925a3bf8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/cmp/trait.Eq.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Eq for Capability","synthetic":false,"types":["bdk::blockchain::Capability"]},{"text":"impl<'s> Eq for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Eq for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Eq for PolicyError","synthetic":false,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl Eq for ScriptContextEnum","synthetic":false,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl Eq for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl Eq for LocalUtxo","synthetic":false,"types":["bdk::types::LocalUtxo"]},{"text":"impl Eq for TransactionDetails","synthetic":false,"types":["bdk::types::TransactionDetails"]},{"text":"impl Eq for ConfirmationTime","synthetic":false,"types":["bdk::types::ConfirmationTime"]},{"text":"impl Eq for AddressValidatorError","synthetic":false,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl Eq for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl Eq for SignerError","synthetic":false,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl Eq for SignerOrdering","synthetic":false,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl Eq for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Eq for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]}]; +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/latest/implementors/core/cmp/trait.Ord.js b/static/docs-rs/bdk/nightly/latest/implementors/core/cmp/trait.Ord.js new file mode 100644 index 0000000000..d19ffc9f15 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/cmp/trait.Ord.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl<'s> Ord for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Ord for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Ord for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl Ord for SignerOrdering","synthetic":false,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl Ord for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Ord for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]}]; +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/latest/implementors/core/cmp/trait.PartialEq.js b/static/docs-rs/bdk/nightly/latest/implementors/core/cmp/trait.PartialEq.js new file mode 100644 index 0000000000..d505fe207f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/cmp/trait.PartialEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl PartialEq<AnyBlockchainConfig> for AnyBlockchainConfig","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl PartialEq<ElectrumBlockchainConfig> for ElectrumBlockchainConfig","synthetic":false,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl PartialEq<EsploraBlockchainConfig> for EsploraBlockchainConfig","synthetic":false,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl PartialEq<BitcoinPeerConfig> for BitcoinPeerConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl PartialEq<CompactFiltersBlockchainConfig> for CompactFiltersBlockchainConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl PartialEq<Capability> for Capability","synthetic":false,"types":["bdk::blockchain::Capability"]},{"text":"impl<'s> PartialEq<DerivedDescriptorKey<'s>> for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl PartialEq<Condition> for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl PartialEq<PolicyError> for PolicyError","synthetic":false,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl PartialEq<ScriptContextEnum> for ScriptContextEnum","synthetic":false,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl PartialEq<KeychainKind> for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl PartialEq<FeeRate> for FeeRate","synthetic":false,"types":["bdk::types::FeeRate"]},{"text":"impl PartialEq<LocalUtxo> for LocalUtxo","synthetic":false,"types":["bdk::types::LocalUtxo"]},{"text":"impl PartialEq<WeightedUtxo> for WeightedUtxo","synthetic":false,"types":["bdk::types::WeightedUtxo"]},{"text":"impl PartialEq<Utxo> for Utxo","synthetic":false,"types":["bdk::types::Utxo"]},{"text":"impl PartialEq<TransactionDetails> for TransactionDetails","synthetic":false,"types":["bdk::types::TransactionDetails"]},{"text":"impl PartialEq<ConfirmationTime> for ConfirmationTime","synthetic":false,"types":["bdk::types::ConfirmationTime"]},{"text":"impl PartialEq<AddressValidatorError> for AddressValidatorError","synthetic":false,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl PartialEq<SignerId> for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl PartialEq<SignerError> for SignerError","synthetic":false,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl PartialEq<SignerOrdering> for SignerOrdering","synthetic":false,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl PartialEq<TxOrdering> for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl PartialEq<ChangeSpendPolicy> for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]},{"text":"impl PartialEq<AddressInfo> for AddressInfo","synthetic":false,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/cmp/trait.PartialOrd.js b/static/docs-rs/bdk/nightly/latest/implementors/core/cmp/trait.PartialOrd.js new file mode 100644 index 0000000000..1e33ba386e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/cmp/trait.PartialOrd.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl<'s> PartialOrd<DerivedDescriptorKey<'s>> for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl PartialOrd<Condition> for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl PartialOrd<FeeRate> for FeeRate","synthetic":false,"types":["bdk::types::FeeRate"]},{"text":"impl PartialOrd<SignerId> for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl PartialOrd<SignerOrdering> for SignerOrdering","synthetic":false,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl PartialOrd<TxOrdering> for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl PartialOrd<ChangeSpendPolicy> for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]}]; +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/latest/implementors/core/convert/trait.AsRef.js b/static/docs-rs/bdk/nightly/latest/implementors/core/convert/trait.AsRef.js new file mode 100644 index 0000000000..cc88354e83 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/convert/trait.AsRef.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl AsRef<[u8]> for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]}]; +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/latest/implementors/core/convert/trait.From.js b/static/docs-rs/bdk/nightly/latest/implementors/core/convert/trait.From.js new file mode 100644 index 0000000000..ee9e5bfa5c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/convert/trait.From.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<AddressValidatorError> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<PolicyError> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<SignerError> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<KeyError> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<PsbtParseError> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<CompactFiltersError> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<EsploraError> for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl From<ElectrumBlockchain> for AnyBlockchain","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchain"]},{"text":"impl From<EsploraBlockchain> for AnyBlockchain","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchain"]},{"text":"impl From<CompactFiltersBlockchain> for AnyBlockchain","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchain"]},{"text":"impl From<ElectrumBlockchainConfig> for AnyBlockchainConfig","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl From<EsploraBlockchainConfig> for AnyBlockchainConfig","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl From<CompactFiltersBlockchainConfig> for AnyBlockchainConfig","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl From<Client> for ElectrumBlockchain","synthetic":false,"types":["bdk::blockchain::electrum::ElectrumBlockchain"]},{"text":"impl From<Error> for EsploraError","synthetic":false,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl From<Transport> for EsploraError","synthetic":false,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl From<Error> for EsploraError","synthetic":false,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl From<ParseIntError> for EsploraError","synthetic":false,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl From<Error> for EsploraError","synthetic":false,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl From<Error> for EsploraError","synthetic":false,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl From<Error> for CompactFiltersError","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl From<Error> for CompactFiltersError","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl From<Error> for CompactFiltersError","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl From<SystemTimeError> for CompactFiltersError","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl From<Error> for CompactFiltersError","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl From<MemoryDatabase> for AnyDatabase","synthetic":false,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl From<Tree> for AnyDatabase","synthetic":false,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl From<SqliteDatabase> for AnyDatabase","synthetic":false,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl From<<MemoryDatabase as BatchDatabase>::Batch> for AnyBatch","synthetic":false,"types":["bdk::database::any::AnyBatch"]},{"text":"impl From<<Tree as BatchDatabase>::Batch> for AnyBatch","synthetic":false,"types":["bdk::database::any::AnyBatch"]},{"text":"impl From<<SqliteDatabase as BatchDatabase>::Batch> for AnyBatch","synthetic":false,"types":["bdk::database::any::AnyBatch"]},{"text":"impl From<()> for AnyDatabaseConfig","synthetic":false,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl From<SledDbConfiguration> for AnyDatabaseConfig","synthetic":false,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl From<SqliteDbConfiguration> for AnyDatabaseConfig","synthetic":false,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl From<KeyError> for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl From<PolicyError> for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl From<bool> for Satisfaction","synthetic":false,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl From<SatisfiableItem> for Policy","synthetic":false,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl<Ctx: ScriptContext> From<ExtendedPubKey> for ExtendedKey<Ctx>","synthetic":false,"types":["bdk::keys::ExtendedKey"]},{"text":"impl<Ctx: ScriptContext> From<ExtendedPrivKey> for ExtendedKey<Ctx>","synthetic":false,"types":["bdk::keys::ExtendedKey"]},{"text":"impl From<Error> for KeyError","synthetic":false,"types":["bdk::keys::KeyError"]},{"text":"impl From<Error> for KeyError","synthetic":false,"types":["bdk::keys::KeyError"]},{"text":"impl From<Hash> for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl From<Fingerprint> for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl From<HashMap<DescriptorPublicKey, DescriptorSecretKey, RandomState>> for SignersContainer","synthetic":false,"types":["bdk::wallet::signer::SignersContainer"]}]; +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/latest/implementors/core/default/trait.Default.js b/static/docs-rs/bdk/nightly/latest/implementors/core/default/trait.Default.js new file mode 100644 index 0000000000..f8973ba8b2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/default/trait.Default.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Default for Mempool","synthetic":false,"types":["bdk::blockchain::compact_filters::peer::Mempool"]},{"text":"impl Default for MemoryDatabase","synthetic":false,"types":["bdk::database::memory::MemoryDatabase"]},{"text":"impl Default for PkOrF","synthetic":false,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl Default for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Default for PrivateKeyGenerateOptions","synthetic":false,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl Default for FeeRate","synthetic":false,"types":["bdk::types::FeeRate"]},{"text":"impl Default for TransactionDetails","synthetic":false,"types":["bdk::types::TransactionDetails"]},{"text":"impl Default for ConfirmationTime","synthetic":false,"types":["bdk::types::ConfirmationTime"]},{"text":"impl Default for LargestFirstCoinSelection","synthetic":false,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl Default for BranchAndBoundCoinSelection","synthetic":false,"types":["bdk::wallet::coin_selection::BranchAndBoundCoinSelection"]},{"text":"impl Default for SignerOrdering","synthetic":false,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl Default for SignersContainer","synthetic":false,"types":["bdk::wallet::signer::SignersContainer"]},{"text":"impl Default for SignOptions","synthetic":false,"types":["bdk::wallet::signer::SignOptions"]},{"text":"impl Default for CreateTx","synthetic":false,"types":["bdk::wallet::tx_builder::CreateTx"]},{"text":"impl Default for BumpFee","synthetic":false,"types":["bdk::wallet::tx_builder::BumpFee"]},{"text":"impl Default for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Default for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]}]; +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/latest/implementors/core/fmt/trait.Debug.js b/static/docs-rs/bdk/nightly/latest/implementors/core/fmt/trait.Debug.js new file mode 100644 index 0000000000..f8b8e915aa --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/fmt/trait.Debug.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Debug for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl Debug for AnyBlockchainConfig","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl Debug for ElectrumBlockchainConfig","synthetic":false,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl Debug for EsploraBlockchain","synthetic":false,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchain"]},{"text":"impl Debug for EsploraBlockchainConfig","synthetic":false,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl Debug for EsploraError","synthetic":false,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl Debug for Mempool","synthetic":false,"types":["bdk::blockchain::compact_filters::peer::Mempool"]},{"text":"impl Debug for Peer","synthetic":false,"types":["bdk::blockchain::compact_filters::peer::Peer"]},{"text":"impl Debug for CompactFiltersBlockchain","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchain"]},{"text":"impl Debug for BitcoinPeerConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl Debug for CompactFiltersBlockchainConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl Debug for CompactFiltersError","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl Debug for Capability","synthetic":false,"types":["bdk::blockchain::Capability"]},{"text":"impl Debug for AnyDatabase","synthetic":false,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl Debug for SledDbConfiguration","synthetic":false,"types":["bdk::database::any::SledDbConfiguration"]},{"text":"impl Debug for SqliteDbConfiguration","synthetic":false,"types":["bdk::database::any::SqliteDbConfiguration"]},{"text":"impl Debug for AnyDatabaseConfig","synthetic":false,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl Debug for SqliteDatabase","synthetic":false,"types":["bdk::database::sqlite::SqliteDatabase"]},{"text":"impl Debug for MemoryDatabase","synthetic":false,"types":["bdk::database::memory::MemoryDatabase"]},{"text":"impl<'s> Debug for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Debug for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl Debug for PkOrF","synthetic":false,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl Debug for SatisfiableItem","synthetic":false,"types":["bdk::descriptor::policy::SatisfiableItem"]},{"text":"impl Debug for Satisfaction","synthetic":false,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl Debug for Policy","synthetic":false,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl Debug for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Debug for PolicyError","synthetic":false,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl<'a> Debug for BuildSatisfaction<'a>","synthetic":false,"types":["bdk::descriptor::policy::BuildSatisfaction"]},{"text":"impl<Ctx: Debug + ScriptContext> Debug for DescriptorKey<Ctx>","synthetic":false,"types":["bdk::keys::DescriptorKey"]},{"text":"impl Debug for ScriptContextEnum","synthetic":false,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl Debug for PrivateKeyGenerateOptions","synthetic":false,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl Debug for KeyError","synthetic":false,"types":["bdk::keys::KeyError"]},{"text":"impl Debug for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl Debug for FeeRate","synthetic":false,"types":["bdk::types::FeeRate"]},{"text":"impl Debug for LocalUtxo","synthetic":false,"types":["bdk::types::LocalUtxo"]},{"text":"impl Debug for WeightedUtxo","synthetic":false,"types":["bdk::types::WeightedUtxo"]},{"text":"impl Debug for Utxo","synthetic":false,"types":["bdk::types::Utxo"]},{"text":"impl Debug for TransactionDetails","synthetic":false,"types":["bdk::types::TransactionDetails"]},{"text":"impl Debug for ConfirmationTime","synthetic":false,"types":["bdk::types::ConfirmationTime"]},{"text":"impl Debug for AddressValidatorError","synthetic":false,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl Debug for CoinSelectionResult","synthetic":false,"types":["bdk::wallet::coin_selection::CoinSelectionResult"]},{"text":"impl Debug for LargestFirstCoinSelection","synthetic":false,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl Debug for BranchAndBoundCoinSelection","synthetic":false,"types":["bdk::wallet::coin_selection::BranchAndBoundCoinSelection"]},{"text":"impl Debug for WalletExport","synthetic":false,"types":["bdk::wallet::export::WalletExport"]},{"text":"impl Debug for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl Debug for SignerError","synthetic":false,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl Debug for SignerOrdering","synthetic":false,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl Debug for SignersContainer","synthetic":false,"types":["bdk::wallet::signer::SignersContainer"]},{"text":"impl Debug for SignOptions","synthetic":false,"types":["bdk::wallet::signer::SignOptions"]},{"text":"impl Debug for CreateTx","synthetic":false,"types":["bdk::wallet::tx_builder::CreateTx"]},{"text":"impl Debug for BumpFee","synthetic":false,"types":["bdk::wallet::tx_builder::BumpFee"]},{"text":"impl<'a, B: Debug, D: Debug, Cs: Debug, Ctx: Debug> Debug for TxBuilder<'a, B, D, Cs, Ctx>","synthetic":false,"types":["bdk::wallet::tx_builder::TxBuilder"]},{"text":"impl Debug for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Debug for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]},{"text":"impl<B: Debug, D: Debug> Debug for Wallet<B, D>","synthetic":false,"types":["bdk::wallet::Wallet"]},{"text":"impl Debug for AddressIndex","synthetic":false,"types":["bdk::wallet::AddressIndex"]},{"text":"impl Debug for AddressInfo","synthetic":false,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/fmt/trait.Display.js b/static/docs-rs/bdk/nightly/latest/implementors/core/fmt/trait.Display.js new file mode 100644 index 0000000000..01fb89d0ac --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/fmt/trait.Display.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Display for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl Display for EsploraError","synthetic":false,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl Display for CompactFiltersError","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl<'s> Display for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Display for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl Display for PolicyError","synthetic":false,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl Display for KeyError","synthetic":false,"types":["bdk::keys::KeyError"]},{"text":"impl Display for AddressValidatorError","synthetic":false,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl Display for SignerError","synthetic":false,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl Display for AddressInfo","synthetic":false,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/hash/trait.Hash.js b/static/docs-rs/bdk/nightly/latest/implementors/core/hash/trait.Hash.js new file mode 100644 index 0000000000..c02f002754 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/hash/trait.Hash.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Hash for Capability","synthetic":false,"types":["bdk::blockchain::Capability"]},{"text":"impl<'s> Hash for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Hash for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Hash for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl Hash for LocalUtxo","synthetic":false,"types":["bdk::types::LocalUtxo"]},{"text":"impl Hash for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl Hash for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Hash for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]}]; +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/latest/implementors/core/marker/trait.Copy.js b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Copy.js new file mode 100644 index 0000000000..b95912a278 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Copy.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Copy for Capability","synthetic":false,"types":["bdk::blockchain::Capability"]},{"text":"impl Copy for NoopProgress","synthetic":false,"types":["bdk::blockchain::NoopProgress"]},{"text":"impl Copy for LogProgress","synthetic":false,"types":["bdk::blockchain::LogProgress"]},{"text":"impl Copy for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl<'a> Copy for BuildSatisfaction<'a>","synthetic":false,"types":["bdk::descriptor::policy::BuildSatisfaction"]},{"text":"impl Copy for ScriptContextEnum","synthetic":false,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl Copy for PrivateKeyGenerateOptions","synthetic":false,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl Copy for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl Copy for FeeRate","synthetic":false,"types":["bdk::types::FeeRate"]},{"text":"impl Copy for LargestFirstCoinSelection","synthetic":false,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl Copy for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Copy for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]}]; +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/latest/implementors/core/marker/trait.Freeze.js b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Freeze.js new file mode 100644 index 0000000000..469a139430 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Freeze.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Freeze for Error","synthetic":true,"types":["bdk::error::Error"]},{"text":"impl !Freeze for AnyBlockchain","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchain"]},{"text":"impl Freeze for AnyBlockchainConfig","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl !Freeze for ElectrumBlockchain","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchain"]},{"text":"impl Freeze for ElectrumBlockchainConfig","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl Freeze for EsploraBlockchain","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchain"]},{"text":"impl Freeze for EsploraBlockchainConfig","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl Freeze for EsploraGetHistory","synthetic":true,"types":["bdk::blockchain::esplora::EsploraGetHistory"]},{"text":"impl Freeze for EsploraError","synthetic":true,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl !Freeze for Mempool","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Mempool"]},{"text":"impl Freeze for Peer","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Peer"]},{"text":"impl Freeze for CompactFiltersBlockchain","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchain"]},{"text":"impl Freeze for BitcoinPeerConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl Freeze for CompactFiltersBlockchainConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl Freeze for CompactFiltersError","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl Freeze for Capability","synthetic":true,"types":["bdk::blockchain::Capability"]},{"text":"impl Freeze for NoopProgress","synthetic":true,"types":["bdk::blockchain::NoopProgress"]},{"text":"impl Freeze for LogProgress","synthetic":true,"types":["bdk::blockchain::LogProgress"]},{"text":"impl !Freeze for AnyDatabase","synthetic":true,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl !Freeze for AnyBatch","synthetic":true,"types":["bdk::database::any::AnyBatch"]},{"text":"impl Freeze for SledDbConfiguration","synthetic":true,"types":["bdk::database::any::SledDbConfiguration"]},{"text":"impl Freeze for SqliteDbConfiguration","synthetic":true,"types":["bdk::database::any::SqliteDbConfiguration"]},{"text":"impl Freeze for AnyDatabaseConfig","synthetic":true,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl !Freeze for SqliteDatabase","synthetic":true,"types":["bdk::database::sqlite::SqliteDatabase"]},{"text":"impl Freeze for MemoryDatabase","synthetic":true,"types":["bdk::database::memory::MemoryDatabase"]},{"text":"impl<'s> Freeze for DerivedDescriptorKey<'s>","synthetic":true,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Freeze for Error","synthetic":true,"types":["bdk::descriptor::error::Error"]},{"text":"impl Freeze for PkOrF","synthetic":true,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl Freeze for SatisfiableItem","synthetic":true,"types":["bdk::descriptor::policy::SatisfiableItem"]},{"text":"impl Freeze for Satisfaction","synthetic":true,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl Freeze for Policy","synthetic":true,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl Freeze for Condition","synthetic":true,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Freeze for PolicyError","synthetic":true,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl<'a> Freeze for BuildSatisfaction<'a>","synthetic":true,"types":["bdk::descriptor::policy::BuildSatisfaction"]},{"text":"impl<K> Freeze for P2Pkh<K> where
    K: Freeze, 
","synthetic":true,"types":["bdk::descriptor::template::P2Pkh"]},{"text":"impl<K> Freeze for P2Wpkh_P2Sh<K> where
    K: Freeze, 
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh_P2Sh"]},{"text":"impl<K> Freeze for P2Wpkh<K> where
    K: Freeze, 
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh"]},{"text":"impl<K> Freeze for Bip44<K> where
    K: Freeze, 
","synthetic":true,"types":["bdk::descriptor::template::Bip44"]},{"text":"impl<K> Freeze for Bip44Public<K> where
    K: Freeze, 
","synthetic":true,"types":["bdk::descriptor::template::Bip44Public"]},{"text":"impl<K> Freeze for Bip49<K> where
    K: Freeze, 
","synthetic":true,"types":["bdk::descriptor::template::Bip49"]},{"text":"impl<K> Freeze for Bip49Public<K> where
    K: Freeze, 
","synthetic":true,"types":["bdk::descriptor::template::Bip49Public"]},{"text":"impl<K> Freeze for Bip84<K> where
    K: Freeze, 
","synthetic":true,"types":["bdk::descriptor::template::Bip84"]},{"text":"impl<K> Freeze for Bip84Public<K> where
    K: Freeze, 
","synthetic":true,"types":["bdk::descriptor::template::Bip84Public"]},{"text":"impl<Ctx> Freeze for DescriptorKey<Ctx>","synthetic":true,"types":["bdk::keys::DescriptorKey"]},{"text":"impl Freeze for ScriptContextEnum","synthetic":true,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl<Ctx> Freeze for ExtendedKey<Ctx>","synthetic":true,"types":["bdk::keys::ExtendedKey"]},{"text":"impl<K, Ctx> Freeze for GeneratedKey<K, Ctx> where
    K: Freeze, 
","synthetic":true,"types":["bdk::keys::GeneratedKey"]},{"text":"impl Freeze for PrivateKeyGenerateOptions","synthetic":true,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl Freeze for KeyError","synthetic":true,"types":["bdk::keys::KeyError"]},{"text":"impl Freeze for KeychainKind","synthetic":true,"types":["bdk::types::KeychainKind"]},{"text":"impl Freeze for FeeRate","synthetic":true,"types":["bdk::types::FeeRate"]},{"text":"impl Freeze for LocalUtxo","synthetic":true,"types":["bdk::types::LocalUtxo"]},{"text":"impl Freeze for WeightedUtxo","synthetic":true,"types":["bdk::types::WeightedUtxo"]},{"text":"impl Freeze for Utxo","synthetic":true,"types":["bdk::types::Utxo"]},{"text":"impl Freeze for TransactionDetails","synthetic":true,"types":["bdk::types::TransactionDetails"]},{"text":"impl Freeze for ConfirmationTime","synthetic":true,"types":["bdk::types::ConfirmationTime"]},{"text":"impl Freeze for AddressValidatorError","synthetic":true,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl Freeze for CoinSelectionResult","synthetic":true,"types":["bdk::wallet::coin_selection::CoinSelectionResult"]},{"text":"impl Freeze for LargestFirstCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl Freeze for BranchAndBoundCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::BranchAndBoundCoinSelection"]},{"text":"impl Freeze for WalletExport","synthetic":true,"types":["bdk::wallet::export::WalletExport"]},{"text":"impl Freeze for SignerId","synthetic":true,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl Freeze for SignerError","synthetic":true,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl Freeze for SignerOrdering","synthetic":true,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl Freeze for SignersContainer","synthetic":true,"types":["bdk::wallet::signer::SignersContainer"]},{"text":"impl Freeze for SignOptions","synthetic":true,"types":["bdk::wallet::signer::SignOptions"]},{"text":"impl Freeze for CreateTx","synthetic":true,"types":["bdk::wallet::tx_builder::CreateTx"]},{"text":"impl Freeze for BumpFee","synthetic":true,"types":["bdk::wallet::tx_builder::BumpFee"]},{"text":"impl<'a, B, D, Cs, Ctx> Freeze for TxBuilder<'a, B, D, Cs, Ctx> where
    Cs: Freeze, 
","synthetic":true,"types":["bdk::wallet::tx_builder::TxBuilder"]},{"text":"impl Freeze for TxOrdering","synthetic":true,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Freeze for ChangeSpendPolicy","synthetic":true,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]},{"text":"impl<B, D> !Freeze for Wallet<B, D>","synthetic":true,"types":["bdk::wallet::Wallet"]},{"text":"impl Freeze for AddressIndex","synthetic":true,"types":["bdk::wallet::AddressIndex"]},{"text":"impl Freeze for AddressInfo","synthetic":true,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/marker/trait.Send.js b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Send.js new file mode 100644 index 0000000000..8af424700c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Send.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Send for Error","synthetic":true,"types":["bdk::error::Error"]},{"text":"impl Send for AnyBlockchain","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchain"]},{"text":"impl Send for AnyBlockchainConfig","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl Send for ElectrumBlockchain","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchain"]},{"text":"impl Send for ElectrumBlockchainConfig","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl Send for EsploraBlockchain","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchain"]},{"text":"impl Send for EsploraBlockchainConfig","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl Send for EsploraGetHistory","synthetic":true,"types":["bdk::blockchain::esplora::EsploraGetHistory"]},{"text":"impl Send for EsploraError","synthetic":true,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl Send for Mempool","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Mempool"]},{"text":"impl Send for Peer","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Peer"]},{"text":"impl Send for CompactFiltersBlockchain","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchain"]},{"text":"impl Send for BitcoinPeerConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl Send for CompactFiltersBlockchainConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl Send for CompactFiltersError","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl Send for Capability","synthetic":true,"types":["bdk::blockchain::Capability"]},{"text":"impl Send for NoopProgress","synthetic":true,"types":["bdk::blockchain::NoopProgress"]},{"text":"impl Send for LogProgress","synthetic":true,"types":["bdk::blockchain::LogProgress"]},{"text":"impl !Send for AnyDatabase","synthetic":true,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl !Send for AnyBatch","synthetic":true,"types":["bdk::database::any::AnyBatch"]},{"text":"impl Send for SledDbConfiguration","synthetic":true,"types":["bdk::database::any::SledDbConfiguration"]},{"text":"impl Send for SqliteDbConfiguration","synthetic":true,"types":["bdk::database::any::SqliteDbConfiguration"]},{"text":"impl Send for AnyDatabaseConfig","synthetic":true,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl Send for SqliteDatabase","synthetic":true,"types":["bdk::database::sqlite::SqliteDatabase"]},{"text":"impl !Send for MemoryDatabase","synthetic":true,"types":["bdk::database::memory::MemoryDatabase"]},{"text":"impl<'s> Send for DerivedDescriptorKey<'s>","synthetic":true,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Send for Error","synthetic":true,"types":["bdk::descriptor::error::Error"]},{"text":"impl Send for PkOrF","synthetic":true,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl Send for SatisfiableItem","synthetic":true,"types":["bdk::descriptor::policy::SatisfiableItem"]},{"text":"impl Send for Satisfaction","synthetic":true,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl Send for Policy","synthetic":true,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl Send for Condition","synthetic":true,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Send for PolicyError","synthetic":true,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl<'a> Send for BuildSatisfaction<'a>","synthetic":true,"types":["bdk::descriptor::policy::BuildSatisfaction"]},{"text":"impl<K> Send for P2Pkh<K> where
    K: Send
","synthetic":true,"types":["bdk::descriptor::template::P2Pkh"]},{"text":"impl<K> Send for P2Wpkh_P2Sh<K> where
    K: Send
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh_P2Sh"]},{"text":"impl<K> Send for P2Wpkh<K> where
    K: Send
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh"]},{"text":"impl<K> Send for Bip44<K> where
    K: Send
","synthetic":true,"types":["bdk::descriptor::template::Bip44"]},{"text":"impl<K> Send for Bip44Public<K> where
    K: Send
","synthetic":true,"types":["bdk::descriptor::template::Bip44Public"]},{"text":"impl<K> Send for Bip49<K> where
    K: Send
","synthetic":true,"types":["bdk::descriptor::template::Bip49"]},{"text":"impl<K> Send for Bip49Public<K> where
    K: Send
","synthetic":true,"types":["bdk::descriptor::template::Bip49Public"]},{"text":"impl<K> Send for Bip84<K> where
    K: Send
","synthetic":true,"types":["bdk::descriptor::template::Bip84"]},{"text":"impl<K> Send for Bip84Public<K> where
    K: Send
","synthetic":true,"types":["bdk::descriptor::template::Bip84Public"]},{"text":"impl<Ctx> Send for DescriptorKey<Ctx> where
    Ctx: Send
","synthetic":true,"types":["bdk::keys::DescriptorKey"]},{"text":"impl Send for ScriptContextEnum","synthetic":true,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl<Ctx> Send for ExtendedKey<Ctx> where
    Ctx: Send
","synthetic":true,"types":["bdk::keys::ExtendedKey"]},{"text":"impl<K, Ctx> Send for GeneratedKey<K, Ctx> where
    Ctx: Send,
    K: Send
","synthetic":true,"types":["bdk::keys::GeneratedKey"]},{"text":"impl Send for PrivateKeyGenerateOptions","synthetic":true,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl Send for KeyError","synthetic":true,"types":["bdk::keys::KeyError"]},{"text":"impl Send for KeychainKind","synthetic":true,"types":["bdk::types::KeychainKind"]},{"text":"impl Send for FeeRate","synthetic":true,"types":["bdk::types::FeeRate"]},{"text":"impl Send for LocalUtxo","synthetic":true,"types":["bdk::types::LocalUtxo"]},{"text":"impl Send for WeightedUtxo","synthetic":true,"types":["bdk::types::WeightedUtxo"]},{"text":"impl Send for Utxo","synthetic":true,"types":["bdk::types::Utxo"]},{"text":"impl Send for TransactionDetails","synthetic":true,"types":["bdk::types::TransactionDetails"]},{"text":"impl Send for ConfirmationTime","synthetic":true,"types":["bdk::types::ConfirmationTime"]},{"text":"impl Send for AddressValidatorError","synthetic":true,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl Send for CoinSelectionResult","synthetic":true,"types":["bdk::wallet::coin_selection::CoinSelectionResult"]},{"text":"impl Send for LargestFirstCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl Send for BranchAndBoundCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::BranchAndBoundCoinSelection"]},{"text":"impl Send for WalletExport","synthetic":true,"types":["bdk::wallet::export::WalletExport"]},{"text":"impl Send for SignerId","synthetic":true,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl Send for SignerError","synthetic":true,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl Send for SignerOrdering","synthetic":true,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl Send for SignersContainer","synthetic":true,"types":["bdk::wallet::signer::SignersContainer"]},{"text":"impl Send for SignOptions","synthetic":true,"types":["bdk::wallet::signer::SignOptions"]},{"text":"impl Send for CreateTx","synthetic":true,"types":["bdk::wallet::tx_builder::CreateTx"]},{"text":"impl Send for BumpFee","synthetic":true,"types":["bdk::wallet::tx_builder::BumpFee"]},{"text":"impl<'a, B, D, Cs, Ctx> !Send for TxBuilder<'a, B, D, Cs, Ctx>","synthetic":true,"types":["bdk::wallet::tx_builder::TxBuilder"]},{"text":"impl Send for TxOrdering","synthetic":true,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Send for ChangeSpendPolicy","synthetic":true,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]},{"text":"impl<B, D> Send for Wallet<B, D> where
    B: Send,
    D: Send
","synthetic":true,"types":["bdk::wallet::Wallet"]},{"text":"impl Send for AddressIndex","synthetic":true,"types":["bdk::wallet::AddressIndex"]},{"text":"impl Send for AddressInfo","synthetic":true,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/marker/trait.StructuralEq.js b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.StructuralEq.js new file mode 100644 index 0000000000..f0a5dbaf05 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.StructuralEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl StructuralEq for Capability","synthetic":false,"types":["bdk::blockchain::Capability"]},{"text":"impl StructuralEq for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl StructuralEq for PolicyError","synthetic":false,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl StructuralEq for ScriptContextEnum","synthetic":false,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl StructuralEq for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl StructuralEq for LocalUtxo","synthetic":false,"types":["bdk::types::LocalUtxo"]},{"text":"impl StructuralEq for TransactionDetails","synthetic":false,"types":["bdk::types::TransactionDetails"]},{"text":"impl StructuralEq for ConfirmationTime","synthetic":false,"types":["bdk::types::ConfirmationTime"]},{"text":"impl StructuralEq for AddressValidatorError","synthetic":false,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl StructuralEq for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl StructuralEq for SignerError","synthetic":false,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl StructuralEq for SignerOrdering","synthetic":false,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl StructuralEq for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl StructuralEq for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]}]; +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/latest/implementors/core/marker/trait.StructuralPartialEq.js b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.StructuralPartialEq.js new file mode 100644 index 0000000000..faa39c8c1e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.StructuralPartialEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl StructuralPartialEq for AnyBlockchainConfig","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl StructuralPartialEq for ElectrumBlockchainConfig","synthetic":false,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl StructuralPartialEq for EsploraBlockchainConfig","synthetic":false,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl StructuralPartialEq for BitcoinPeerConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl StructuralPartialEq for CompactFiltersBlockchainConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl StructuralPartialEq for Capability","synthetic":false,"types":["bdk::blockchain::Capability"]},{"text":"impl StructuralPartialEq for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl StructuralPartialEq for PolicyError","synthetic":false,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl StructuralPartialEq for ScriptContextEnum","synthetic":false,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl StructuralPartialEq for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl StructuralPartialEq for FeeRate","synthetic":false,"types":["bdk::types::FeeRate"]},{"text":"impl StructuralPartialEq for LocalUtxo","synthetic":false,"types":["bdk::types::LocalUtxo"]},{"text":"impl StructuralPartialEq for WeightedUtxo","synthetic":false,"types":["bdk::types::WeightedUtxo"]},{"text":"impl StructuralPartialEq for Utxo","synthetic":false,"types":["bdk::types::Utxo"]},{"text":"impl StructuralPartialEq for TransactionDetails","synthetic":false,"types":["bdk::types::TransactionDetails"]},{"text":"impl StructuralPartialEq for ConfirmationTime","synthetic":false,"types":["bdk::types::ConfirmationTime"]},{"text":"impl StructuralPartialEq for AddressValidatorError","synthetic":false,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl StructuralPartialEq for SignerId","synthetic":false,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl StructuralPartialEq for SignerError","synthetic":false,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl StructuralPartialEq for SignerOrdering","synthetic":false,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl StructuralPartialEq for TxOrdering","synthetic":false,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl StructuralPartialEq for ChangeSpendPolicy","synthetic":false,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]},{"text":"impl StructuralPartialEq for AddressInfo","synthetic":false,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/marker/trait.Sync.js b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Sync.js new file mode 100644 index 0000000000..2d66194d8d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Sync.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Sync for Error","synthetic":true,"types":["bdk::error::Error"]},{"text":"impl Sync for AnyBlockchain","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchain"]},{"text":"impl Sync for AnyBlockchainConfig","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl Sync for ElectrumBlockchain","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchain"]},{"text":"impl Sync for ElectrumBlockchainConfig","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl Sync for EsploraBlockchain","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchain"]},{"text":"impl Sync for EsploraBlockchainConfig","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl Sync for EsploraGetHistory","synthetic":true,"types":["bdk::blockchain::esplora::EsploraGetHistory"]},{"text":"impl Sync for EsploraError","synthetic":true,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl Sync for Mempool","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Mempool"]},{"text":"impl Sync for Peer","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Peer"]},{"text":"impl Sync for CompactFiltersBlockchain","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchain"]},{"text":"impl Sync for BitcoinPeerConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl Sync for CompactFiltersBlockchainConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl Sync for CompactFiltersError","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl Sync for Capability","synthetic":true,"types":["bdk::blockchain::Capability"]},{"text":"impl Sync for NoopProgress","synthetic":true,"types":["bdk::blockchain::NoopProgress"]},{"text":"impl Sync for LogProgress","synthetic":true,"types":["bdk::blockchain::LogProgress"]},{"text":"impl !Sync for AnyDatabase","synthetic":true,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl !Sync for AnyBatch","synthetic":true,"types":["bdk::database::any::AnyBatch"]},{"text":"impl Sync for SledDbConfiguration","synthetic":true,"types":["bdk::database::any::SledDbConfiguration"]},{"text":"impl Sync for SqliteDbConfiguration","synthetic":true,"types":["bdk::database::any::SqliteDbConfiguration"]},{"text":"impl Sync for AnyDatabaseConfig","synthetic":true,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl !Sync for SqliteDatabase","synthetic":true,"types":["bdk::database::sqlite::SqliteDatabase"]},{"text":"impl !Sync for MemoryDatabase","synthetic":true,"types":["bdk::database::memory::MemoryDatabase"]},{"text":"impl<'s> Sync for DerivedDescriptorKey<'s>","synthetic":true,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Sync for Error","synthetic":true,"types":["bdk::descriptor::error::Error"]},{"text":"impl Sync for PkOrF","synthetic":true,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl Sync for SatisfiableItem","synthetic":true,"types":["bdk::descriptor::policy::SatisfiableItem"]},{"text":"impl Sync for Satisfaction","synthetic":true,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl Sync for Policy","synthetic":true,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl Sync for Condition","synthetic":true,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Sync for PolicyError","synthetic":true,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl<'a> Sync for BuildSatisfaction<'a>","synthetic":true,"types":["bdk::descriptor::policy::BuildSatisfaction"]},{"text":"impl<K> Sync for P2Pkh<K> where
    K: Sync
","synthetic":true,"types":["bdk::descriptor::template::P2Pkh"]},{"text":"impl<K> Sync for P2Wpkh_P2Sh<K> where
    K: Sync
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh_P2Sh"]},{"text":"impl<K> Sync for P2Wpkh<K> where
    K: Sync
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh"]},{"text":"impl<K> Sync for Bip44<K> where
    K: Sync
","synthetic":true,"types":["bdk::descriptor::template::Bip44"]},{"text":"impl<K> Sync for Bip44Public<K> where
    K: Sync
","synthetic":true,"types":["bdk::descriptor::template::Bip44Public"]},{"text":"impl<K> Sync for Bip49<K> where
    K: Sync
","synthetic":true,"types":["bdk::descriptor::template::Bip49"]},{"text":"impl<K> Sync for Bip49Public<K> where
    K: Sync
","synthetic":true,"types":["bdk::descriptor::template::Bip49Public"]},{"text":"impl<K> Sync for Bip84<K> where
    K: Sync
","synthetic":true,"types":["bdk::descriptor::template::Bip84"]},{"text":"impl<K> Sync for Bip84Public<K> where
    K: Sync
","synthetic":true,"types":["bdk::descriptor::template::Bip84Public"]},{"text":"impl<Ctx> Sync for DescriptorKey<Ctx> where
    Ctx: Sync
","synthetic":true,"types":["bdk::keys::DescriptorKey"]},{"text":"impl Sync for ScriptContextEnum","synthetic":true,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl<Ctx> Sync for ExtendedKey<Ctx> where
    Ctx: Sync
","synthetic":true,"types":["bdk::keys::ExtendedKey"]},{"text":"impl<K, Ctx> Sync for GeneratedKey<K, Ctx> where
    Ctx: Sync,
    K: Sync
","synthetic":true,"types":["bdk::keys::GeneratedKey"]},{"text":"impl Sync for PrivateKeyGenerateOptions","synthetic":true,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl Sync for KeyError","synthetic":true,"types":["bdk::keys::KeyError"]},{"text":"impl Sync for KeychainKind","synthetic":true,"types":["bdk::types::KeychainKind"]},{"text":"impl Sync for FeeRate","synthetic":true,"types":["bdk::types::FeeRate"]},{"text":"impl Sync for LocalUtxo","synthetic":true,"types":["bdk::types::LocalUtxo"]},{"text":"impl Sync for WeightedUtxo","synthetic":true,"types":["bdk::types::WeightedUtxo"]},{"text":"impl Sync for Utxo","synthetic":true,"types":["bdk::types::Utxo"]},{"text":"impl Sync for TransactionDetails","synthetic":true,"types":["bdk::types::TransactionDetails"]},{"text":"impl Sync for ConfirmationTime","synthetic":true,"types":["bdk::types::ConfirmationTime"]},{"text":"impl Sync for AddressValidatorError","synthetic":true,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl Sync for CoinSelectionResult","synthetic":true,"types":["bdk::wallet::coin_selection::CoinSelectionResult"]},{"text":"impl Sync for LargestFirstCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl Sync for BranchAndBoundCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::BranchAndBoundCoinSelection"]},{"text":"impl Sync for WalletExport","synthetic":true,"types":["bdk::wallet::export::WalletExport"]},{"text":"impl Sync for SignerId","synthetic":true,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl Sync for SignerError","synthetic":true,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl Sync for SignerOrdering","synthetic":true,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl Sync for SignersContainer","synthetic":true,"types":["bdk::wallet::signer::SignersContainer"]},{"text":"impl Sync for SignOptions","synthetic":true,"types":["bdk::wallet::signer::SignOptions"]},{"text":"impl Sync for CreateTx","synthetic":true,"types":["bdk::wallet::tx_builder::CreateTx"]},{"text":"impl Sync for BumpFee","synthetic":true,"types":["bdk::wallet::tx_builder::BumpFee"]},{"text":"impl<'a, B, D, Cs, Ctx> !Sync for TxBuilder<'a, B, D, Cs, Ctx>","synthetic":true,"types":["bdk::wallet::tx_builder::TxBuilder"]},{"text":"impl Sync for TxOrdering","synthetic":true,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Sync for ChangeSpendPolicy","synthetic":true,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]},{"text":"impl<B, D> !Sync for Wallet<B, D>","synthetic":true,"types":["bdk::wallet::Wallet"]},{"text":"impl Sync for AddressIndex","synthetic":true,"types":["bdk::wallet::AddressIndex"]},{"text":"impl Sync for AddressInfo","synthetic":true,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/marker/trait.Unpin.js b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Unpin.js new file mode 100644 index 0000000000..834a73d904 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/marker/trait.Unpin.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Unpin for Error","synthetic":true,"types":["bdk::error::Error"]},{"text":"impl Unpin for AnyBlockchain","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchain"]},{"text":"impl Unpin for AnyBlockchainConfig","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl Unpin for ElectrumBlockchain","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchain"]},{"text":"impl Unpin for ElectrumBlockchainConfig","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl Unpin for EsploraBlockchain","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchain"]},{"text":"impl Unpin for EsploraBlockchainConfig","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl Unpin for EsploraGetHistory","synthetic":true,"types":["bdk::blockchain::esplora::EsploraGetHistory"]},{"text":"impl Unpin for EsploraError","synthetic":true,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl Unpin for Mempool","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Mempool"]},{"text":"impl Unpin for Peer","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Peer"]},{"text":"impl Unpin for CompactFiltersBlockchain","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchain"]},{"text":"impl Unpin for BitcoinPeerConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl Unpin for CompactFiltersBlockchainConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl Unpin for CompactFiltersError","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl Unpin for Capability","synthetic":true,"types":["bdk::blockchain::Capability"]},{"text":"impl Unpin for NoopProgress","synthetic":true,"types":["bdk::blockchain::NoopProgress"]},{"text":"impl Unpin for LogProgress","synthetic":true,"types":["bdk::blockchain::LogProgress"]},{"text":"impl Unpin for AnyDatabase","synthetic":true,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl Unpin for AnyBatch","synthetic":true,"types":["bdk::database::any::AnyBatch"]},{"text":"impl Unpin for SledDbConfiguration","synthetic":true,"types":["bdk::database::any::SledDbConfiguration"]},{"text":"impl Unpin for SqliteDbConfiguration","synthetic":true,"types":["bdk::database::any::SqliteDbConfiguration"]},{"text":"impl Unpin for AnyDatabaseConfig","synthetic":true,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl Unpin for SqliteDatabase","synthetic":true,"types":["bdk::database::sqlite::SqliteDatabase"]},{"text":"impl Unpin for MemoryDatabase","synthetic":true,"types":["bdk::database::memory::MemoryDatabase"]},{"text":"impl<'s> Unpin for DerivedDescriptorKey<'s>","synthetic":true,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl Unpin for Error","synthetic":true,"types":["bdk::descriptor::error::Error"]},{"text":"impl Unpin for PkOrF","synthetic":true,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl Unpin for SatisfiableItem","synthetic":true,"types":["bdk::descriptor::policy::SatisfiableItem"]},{"text":"impl Unpin for Satisfaction","synthetic":true,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl Unpin for Policy","synthetic":true,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl Unpin for Condition","synthetic":true,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Unpin for PolicyError","synthetic":true,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl<'a> Unpin for BuildSatisfaction<'a>","synthetic":true,"types":["bdk::descriptor::policy::BuildSatisfaction"]},{"text":"impl<K> Unpin for P2Pkh<K> where
    K: Unpin
","synthetic":true,"types":["bdk::descriptor::template::P2Pkh"]},{"text":"impl<K> Unpin for P2Wpkh_P2Sh<K> where
    K: Unpin
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh_P2Sh"]},{"text":"impl<K> Unpin for P2Wpkh<K> where
    K: Unpin
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh"]},{"text":"impl<K> Unpin for Bip44<K> where
    K: Unpin
","synthetic":true,"types":["bdk::descriptor::template::Bip44"]},{"text":"impl<K> Unpin for Bip44Public<K> where
    K: Unpin
","synthetic":true,"types":["bdk::descriptor::template::Bip44Public"]},{"text":"impl<K> Unpin for Bip49<K> where
    K: Unpin
","synthetic":true,"types":["bdk::descriptor::template::Bip49"]},{"text":"impl<K> Unpin for Bip49Public<K> where
    K: Unpin
","synthetic":true,"types":["bdk::descriptor::template::Bip49Public"]},{"text":"impl<K> Unpin for Bip84<K> where
    K: Unpin
","synthetic":true,"types":["bdk::descriptor::template::Bip84"]},{"text":"impl<K> Unpin for Bip84Public<K> where
    K: Unpin
","synthetic":true,"types":["bdk::descriptor::template::Bip84Public"]},{"text":"impl<Ctx> Unpin for DescriptorKey<Ctx> where
    Ctx: Unpin
","synthetic":true,"types":["bdk::keys::DescriptorKey"]},{"text":"impl Unpin for ScriptContextEnum","synthetic":true,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl<Ctx> Unpin for ExtendedKey<Ctx> where
    Ctx: Unpin
","synthetic":true,"types":["bdk::keys::ExtendedKey"]},{"text":"impl<K, Ctx> Unpin for GeneratedKey<K, Ctx> where
    Ctx: Unpin,
    K: Unpin
","synthetic":true,"types":["bdk::keys::GeneratedKey"]},{"text":"impl Unpin for PrivateKeyGenerateOptions","synthetic":true,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl Unpin for KeyError","synthetic":true,"types":["bdk::keys::KeyError"]},{"text":"impl Unpin for KeychainKind","synthetic":true,"types":["bdk::types::KeychainKind"]},{"text":"impl Unpin for FeeRate","synthetic":true,"types":["bdk::types::FeeRate"]},{"text":"impl Unpin for LocalUtxo","synthetic":true,"types":["bdk::types::LocalUtxo"]},{"text":"impl Unpin for WeightedUtxo","synthetic":true,"types":["bdk::types::WeightedUtxo"]},{"text":"impl Unpin for Utxo","synthetic":true,"types":["bdk::types::Utxo"]},{"text":"impl Unpin for TransactionDetails","synthetic":true,"types":["bdk::types::TransactionDetails"]},{"text":"impl Unpin for ConfirmationTime","synthetic":true,"types":["bdk::types::ConfirmationTime"]},{"text":"impl Unpin for AddressValidatorError","synthetic":true,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl Unpin for CoinSelectionResult","synthetic":true,"types":["bdk::wallet::coin_selection::CoinSelectionResult"]},{"text":"impl Unpin for LargestFirstCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl Unpin for BranchAndBoundCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::BranchAndBoundCoinSelection"]},{"text":"impl Unpin for WalletExport","synthetic":true,"types":["bdk::wallet::export::WalletExport"]},{"text":"impl Unpin for SignerId","synthetic":true,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl Unpin for SignerError","synthetic":true,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl Unpin for SignerOrdering","synthetic":true,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl Unpin for SignersContainer","synthetic":true,"types":["bdk::wallet::signer::SignersContainer"]},{"text":"impl Unpin for SignOptions","synthetic":true,"types":["bdk::wallet::signer::SignOptions"]},{"text":"impl Unpin for CreateTx","synthetic":true,"types":["bdk::wallet::tx_builder::CreateTx"]},{"text":"impl Unpin for BumpFee","synthetic":true,"types":["bdk::wallet::tx_builder::BumpFee"]},{"text":"impl<'a, B, D, Cs, Ctx> Unpin for TxBuilder<'a, B, D, Cs, Ctx> where
    Cs: Unpin,
    Ctx: Unpin
","synthetic":true,"types":["bdk::wallet::tx_builder::TxBuilder"]},{"text":"impl Unpin for TxOrdering","synthetic":true,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl Unpin for ChangeSpendPolicy","synthetic":true,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]},{"text":"impl<B, D> Unpin for Wallet<B, D> where
    B: Unpin,
    D: Unpin
","synthetic":true,"types":["bdk::wallet::Wallet"]},{"text":"impl Unpin for AddressIndex","synthetic":true,"types":["bdk::wallet::AddressIndex"]},{"text":"impl Unpin for AddressInfo","synthetic":true,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/ops/arith/trait.Sub.js b/static/docs-rs/bdk/nightly/latest/implementors/core/ops/arith/trait.Sub.js new file mode 100644 index 0000000000..0527a76602 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/ops/arith/trait.Sub.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Sub<FeeRate> for FeeRate","synthetic":false,"types":["bdk::types::FeeRate"]}]; +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/latest/implementors/core/ops/deref/trait.Deref.js b/static/docs-rs/bdk/nightly/latest/implementors/core/ops/deref/trait.Deref.js new file mode 100644 index 0000000000..172ef72b01 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/ops/deref/trait.Deref.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl<'s> Deref for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl<K, Ctx: ScriptContext> Deref for GeneratedKey<K, Ctx>","synthetic":false,"types":["bdk::keys::GeneratedKey"]},{"text":"impl Deref for AddressInfo","synthetic":false,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/panic/unwind_safe/trait.RefUnwindSafe.js b/static/docs-rs/bdk/nightly/latest/implementors/core/panic/unwind_safe/trait.RefUnwindSafe.js new file mode 100644 index 0000000000..43f5c13951 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/panic/unwind_safe/trait.RefUnwindSafe.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl !RefUnwindSafe for Error","synthetic":true,"types":["bdk::error::Error"]},{"text":"impl !RefUnwindSafe for AnyBlockchain","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchain"]},{"text":"impl RefUnwindSafe for AnyBlockchainConfig","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl RefUnwindSafe for ElectrumBlockchain","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchain"]},{"text":"impl RefUnwindSafe for ElectrumBlockchainConfig","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl !RefUnwindSafe for EsploraBlockchain","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchain"]},{"text":"impl RefUnwindSafe for EsploraBlockchainConfig","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl RefUnwindSafe for EsploraGetHistory","synthetic":true,"types":["bdk::blockchain::esplora::EsploraGetHistory"]},{"text":"impl !RefUnwindSafe for EsploraError","synthetic":true,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl RefUnwindSafe for Mempool","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Mempool"]},{"text":"impl !RefUnwindSafe for Peer","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Peer"]},{"text":"impl !RefUnwindSafe for CompactFiltersBlockchain","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchain"]},{"text":"impl RefUnwindSafe for BitcoinPeerConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl RefUnwindSafe for CompactFiltersBlockchainConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl !RefUnwindSafe for CompactFiltersError","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl RefUnwindSafe for Capability","synthetic":true,"types":["bdk::blockchain::Capability"]},{"text":"impl RefUnwindSafe for NoopProgress","synthetic":true,"types":["bdk::blockchain::NoopProgress"]},{"text":"impl RefUnwindSafe for LogProgress","synthetic":true,"types":["bdk::blockchain::LogProgress"]},{"text":"impl !RefUnwindSafe for AnyDatabase","synthetic":true,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl !RefUnwindSafe for AnyBatch","synthetic":true,"types":["bdk::database::any::AnyBatch"]},{"text":"impl RefUnwindSafe for SledDbConfiguration","synthetic":true,"types":["bdk::database::any::SledDbConfiguration"]},{"text":"impl RefUnwindSafe for SqliteDbConfiguration","synthetic":true,"types":["bdk::database::any::SqliteDbConfiguration"]},{"text":"impl RefUnwindSafe for AnyDatabaseConfig","synthetic":true,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl !RefUnwindSafe for SqliteDatabase","synthetic":true,"types":["bdk::database::sqlite::SqliteDatabase"]},{"text":"impl !RefUnwindSafe for MemoryDatabase","synthetic":true,"types":["bdk::database::memory::MemoryDatabase"]},{"text":"impl<'s> RefUnwindSafe for DerivedDescriptorKey<'s>","synthetic":true,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl RefUnwindSafe for Error","synthetic":true,"types":["bdk::descriptor::error::Error"]},{"text":"impl RefUnwindSafe for PkOrF","synthetic":true,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl RefUnwindSafe for SatisfiableItem","synthetic":true,"types":["bdk::descriptor::policy::SatisfiableItem"]},{"text":"impl RefUnwindSafe for Satisfaction","synthetic":true,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl RefUnwindSafe for Policy","synthetic":true,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl RefUnwindSafe for Condition","synthetic":true,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl RefUnwindSafe for PolicyError","synthetic":true,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl<'a> RefUnwindSafe for BuildSatisfaction<'a>","synthetic":true,"types":["bdk::descriptor::policy::BuildSatisfaction"]},{"text":"impl<K> RefUnwindSafe for P2Pkh<K> where
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::P2Pkh"]},{"text":"impl<K> RefUnwindSafe for P2Wpkh_P2Sh<K> where
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh_P2Sh"]},{"text":"impl<K> RefUnwindSafe for P2Wpkh<K> where
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh"]},{"text":"impl<K> RefUnwindSafe for Bip44<K> where
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip44"]},{"text":"impl<K> RefUnwindSafe for Bip44Public<K> where
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip44Public"]},{"text":"impl<K> RefUnwindSafe for Bip49<K> where
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip49"]},{"text":"impl<K> RefUnwindSafe for Bip49Public<K> where
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip49Public"]},{"text":"impl<K> RefUnwindSafe for Bip84<K> where
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip84"]},{"text":"impl<K> RefUnwindSafe for Bip84Public<K> where
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip84Public"]},{"text":"impl<Ctx> RefUnwindSafe for DescriptorKey<Ctx> where
    Ctx: RefUnwindSafe
","synthetic":true,"types":["bdk::keys::DescriptorKey"]},{"text":"impl RefUnwindSafe for ScriptContextEnum","synthetic":true,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl<Ctx> RefUnwindSafe for ExtendedKey<Ctx> where
    Ctx: RefUnwindSafe
","synthetic":true,"types":["bdk::keys::ExtendedKey"]},{"text":"impl<K, Ctx> RefUnwindSafe for GeneratedKey<K, Ctx> where
    Ctx: RefUnwindSafe,
    K: RefUnwindSafe
","synthetic":true,"types":["bdk::keys::GeneratedKey"]},{"text":"impl RefUnwindSafe for PrivateKeyGenerateOptions","synthetic":true,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl RefUnwindSafe for KeyError","synthetic":true,"types":["bdk::keys::KeyError"]},{"text":"impl RefUnwindSafe for KeychainKind","synthetic":true,"types":["bdk::types::KeychainKind"]},{"text":"impl RefUnwindSafe for FeeRate","synthetic":true,"types":["bdk::types::FeeRate"]},{"text":"impl RefUnwindSafe for LocalUtxo","synthetic":true,"types":["bdk::types::LocalUtxo"]},{"text":"impl RefUnwindSafe for WeightedUtxo","synthetic":true,"types":["bdk::types::WeightedUtxo"]},{"text":"impl RefUnwindSafe for Utxo","synthetic":true,"types":["bdk::types::Utxo"]},{"text":"impl RefUnwindSafe for TransactionDetails","synthetic":true,"types":["bdk::types::TransactionDetails"]},{"text":"impl RefUnwindSafe for ConfirmationTime","synthetic":true,"types":["bdk::types::ConfirmationTime"]},{"text":"impl RefUnwindSafe for AddressValidatorError","synthetic":true,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl RefUnwindSafe for CoinSelectionResult","synthetic":true,"types":["bdk::wallet::coin_selection::CoinSelectionResult"]},{"text":"impl RefUnwindSafe for LargestFirstCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl RefUnwindSafe for BranchAndBoundCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::BranchAndBoundCoinSelection"]},{"text":"impl RefUnwindSafe for WalletExport","synthetic":true,"types":["bdk::wallet::export::WalletExport"]},{"text":"impl RefUnwindSafe for SignerId","synthetic":true,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl RefUnwindSafe for SignerError","synthetic":true,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl RefUnwindSafe for SignerOrdering","synthetic":true,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl !RefUnwindSafe for SignersContainer","synthetic":true,"types":["bdk::wallet::signer::SignersContainer"]},{"text":"impl RefUnwindSafe for SignOptions","synthetic":true,"types":["bdk::wallet::signer::SignOptions"]},{"text":"impl RefUnwindSafe for CreateTx","synthetic":true,"types":["bdk::wallet::tx_builder::CreateTx"]},{"text":"impl RefUnwindSafe for BumpFee","synthetic":true,"types":["bdk::wallet::tx_builder::BumpFee"]},{"text":"impl<'a, B, D, Cs, Ctx> !RefUnwindSafe for TxBuilder<'a, B, D, Cs, Ctx>","synthetic":true,"types":["bdk::wallet::tx_builder::TxBuilder"]},{"text":"impl RefUnwindSafe for TxOrdering","synthetic":true,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl RefUnwindSafe for ChangeSpendPolicy","synthetic":true,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]},{"text":"impl<B, D> !RefUnwindSafe for Wallet<B, D>","synthetic":true,"types":["bdk::wallet::Wallet"]},{"text":"impl RefUnwindSafe for AddressIndex","synthetic":true,"types":["bdk::wallet::AddressIndex"]},{"text":"impl RefUnwindSafe for AddressInfo","synthetic":true,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/panic/unwind_safe/trait.UnwindSafe.js b/static/docs-rs/bdk/nightly/latest/implementors/core/panic/unwind_safe/trait.UnwindSafe.js new file mode 100644 index 0000000000..8eff90f98d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/panic/unwind_safe/trait.UnwindSafe.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl !UnwindSafe for Error","synthetic":true,"types":["bdk::error::Error"]},{"text":"impl !UnwindSafe for AnyBlockchain","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchain"]},{"text":"impl UnwindSafe for AnyBlockchainConfig","synthetic":true,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl UnwindSafe for ElectrumBlockchain","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchain"]},{"text":"impl UnwindSafe for ElectrumBlockchainConfig","synthetic":true,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl !UnwindSafe for EsploraBlockchain","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchain"]},{"text":"impl UnwindSafe for EsploraBlockchainConfig","synthetic":true,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl UnwindSafe for EsploraGetHistory","synthetic":true,"types":["bdk::blockchain::esplora::EsploraGetHistory"]},{"text":"impl !UnwindSafe for EsploraError","synthetic":true,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl UnwindSafe for Mempool","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Mempool"]},{"text":"impl !UnwindSafe for Peer","synthetic":true,"types":["bdk::blockchain::compact_filters::peer::Peer"]},{"text":"impl !UnwindSafe for CompactFiltersBlockchain","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchain"]},{"text":"impl UnwindSafe for BitcoinPeerConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl UnwindSafe for CompactFiltersBlockchainConfig","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl !UnwindSafe for CompactFiltersError","synthetic":true,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl UnwindSafe for Capability","synthetic":true,"types":["bdk::blockchain::Capability"]},{"text":"impl UnwindSafe for NoopProgress","synthetic":true,"types":["bdk::blockchain::NoopProgress"]},{"text":"impl UnwindSafe for LogProgress","synthetic":true,"types":["bdk::blockchain::LogProgress"]},{"text":"impl !UnwindSafe for AnyDatabase","synthetic":true,"types":["bdk::database::any::AnyDatabase"]},{"text":"impl !UnwindSafe for AnyBatch","synthetic":true,"types":["bdk::database::any::AnyBatch"]},{"text":"impl UnwindSafe for SledDbConfiguration","synthetic":true,"types":["bdk::database::any::SledDbConfiguration"]},{"text":"impl UnwindSafe for SqliteDbConfiguration","synthetic":true,"types":["bdk::database::any::SqliteDbConfiguration"]},{"text":"impl UnwindSafe for AnyDatabaseConfig","synthetic":true,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl !UnwindSafe for SqliteDatabase","synthetic":true,"types":["bdk::database::sqlite::SqliteDatabase"]},{"text":"impl !UnwindSafe for MemoryDatabase","synthetic":true,"types":["bdk::database::memory::MemoryDatabase"]},{"text":"impl<'s> UnwindSafe for DerivedDescriptorKey<'s>","synthetic":true,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]},{"text":"impl UnwindSafe for Error","synthetic":true,"types":["bdk::descriptor::error::Error"]},{"text":"impl UnwindSafe for PkOrF","synthetic":true,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl UnwindSafe for SatisfiableItem","synthetic":true,"types":["bdk::descriptor::policy::SatisfiableItem"]},{"text":"impl UnwindSafe for Satisfaction","synthetic":true,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl UnwindSafe for Policy","synthetic":true,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl UnwindSafe for Condition","synthetic":true,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl UnwindSafe for PolicyError","synthetic":true,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl<'a> UnwindSafe for BuildSatisfaction<'a>","synthetic":true,"types":["bdk::descriptor::policy::BuildSatisfaction"]},{"text":"impl<K> UnwindSafe for P2Pkh<K> where
    K: UnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::P2Pkh"]},{"text":"impl<K> UnwindSafe for P2Wpkh_P2Sh<K> where
    K: UnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh_P2Sh"]},{"text":"impl<K> UnwindSafe for P2Wpkh<K> where
    K: UnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::P2Wpkh"]},{"text":"impl<K> UnwindSafe for Bip44<K> where
    K: UnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip44"]},{"text":"impl<K> UnwindSafe for Bip44Public<K> where
    K: UnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip44Public"]},{"text":"impl<K> UnwindSafe for Bip49<K> where
    K: UnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip49"]},{"text":"impl<K> UnwindSafe for Bip49Public<K> where
    K: UnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip49Public"]},{"text":"impl<K> UnwindSafe for Bip84<K> where
    K: UnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip84"]},{"text":"impl<K> UnwindSafe for Bip84Public<K> where
    K: UnwindSafe
","synthetic":true,"types":["bdk::descriptor::template::Bip84Public"]},{"text":"impl<Ctx> UnwindSafe for DescriptorKey<Ctx> where
    Ctx: UnwindSafe
","synthetic":true,"types":["bdk::keys::DescriptorKey"]},{"text":"impl UnwindSafe for ScriptContextEnum","synthetic":true,"types":["bdk::keys::ScriptContextEnum"]},{"text":"impl<Ctx> UnwindSafe for ExtendedKey<Ctx> where
    Ctx: UnwindSafe
","synthetic":true,"types":["bdk::keys::ExtendedKey"]},{"text":"impl<K, Ctx> UnwindSafe for GeneratedKey<K, Ctx> where
    Ctx: UnwindSafe,
    K: UnwindSafe
","synthetic":true,"types":["bdk::keys::GeneratedKey"]},{"text":"impl UnwindSafe for PrivateKeyGenerateOptions","synthetic":true,"types":["bdk::keys::PrivateKeyGenerateOptions"]},{"text":"impl UnwindSafe for KeyError","synthetic":true,"types":["bdk::keys::KeyError"]},{"text":"impl UnwindSafe for KeychainKind","synthetic":true,"types":["bdk::types::KeychainKind"]},{"text":"impl UnwindSafe for FeeRate","synthetic":true,"types":["bdk::types::FeeRate"]},{"text":"impl UnwindSafe for LocalUtxo","synthetic":true,"types":["bdk::types::LocalUtxo"]},{"text":"impl UnwindSafe for WeightedUtxo","synthetic":true,"types":["bdk::types::WeightedUtxo"]},{"text":"impl UnwindSafe for Utxo","synthetic":true,"types":["bdk::types::Utxo"]},{"text":"impl UnwindSafe for TransactionDetails","synthetic":true,"types":["bdk::types::TransactionDetails"]},{"text":"impl UnwindSafe for ConfirmationTime","synthetic":true,"types":["bdk::types::ConfirmationTime"]},{"text":"impl UnwindSafe for AddressValidatorError","synthetic":true,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl UnwindSafe for CoinSelectionResult","synthetic":true,"types":["bdk::wallet::coin_selection::CoinSelectionResult"]},{"text":"impl UnwindSafe for LargestFirstCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::LargestFirstCoinSelection"]},{"text":"impl UnwindSafe for BranchAndBoundCoinSelection","synthetic":true,"types":["bdk::wallet::coin_selection::BranchAndBoundCoinSelection"]},{"text":"impl UnwindSafe for WalletExport","synthetic":true,"types":["bdk::wallet::export::WalletExport"]},{"text":"impl UnwindSafe for SignerId","synthetic":true,"types":["bdk::wallet::signer::SignerId"]},{"text":"impl UnwindSafe for SignerError","synthetic":true,"types":["bdk::wallet::signer::SignerError"]},{"text":"impl UnwindSafe for SignerOrdering","synthetic":true,"types":["bdk::wallet::signer::SignerOrdering"]},{"text":"impl !UnwindSafe for SignersContainer","synthetic":true,"types":["bdk::wallet::signer::SignersContainer"]},{"text":"impl UnwindSafe for SignOptions","synthetic":true,"types":["bdk::wallet::signer::SignOptions"]},{"text":"impl UnwindSafe for CreateTx","synthetic":true,"types":["bdk::wallet::tx_builder::CreateTx"]},{"text":"impl UnwindSafe for BumpFee","synthetic":true,"types":["bdk::wallet::tx_builder::BumpFee"]},{"text":"impl<'a, B, D, Cs, Ctx> !UnwindSafe for TxBuilder<'a, B, D, Cs, Ctx>","synthetic":true,"types":["bdk::wallet::tx_builder::TxBuilder"]},{"text":"impl UnwindSafe for TxOrdering","synthetic":true,"types":["bdk::wallet::tx_builder::TxOrdering"]},{"text":"impl UnwindSafe for ChangeSpendPolicy","synthetic":true,"types":["bdk::wallet::tx_builder::ChangeSpendPolicy"]},{"text":"impl<B, D> !UnwindSafe for Wallet<B, D>","synthetic":true,"types":["bdk::wallet::Wallet"]},{"text":"impl UnwindSafe for AddressIndex","synthetic":true,"types":["bdk::wallet::AddressIndex"]},{"text":"impl UnwindSafe for AddressInfo","synthetic":true,"types":["bdk::wallet::AddressInfo"]}]; +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/latest/implementors/core/str/traits/trait.FromStr.js b/static/docs-rs/bdk/nightly/latest/implementors/core/str/traits/trait.FromStr.js new file mode 100644 index 0000000000..b76335d1f3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/core/str/traits/trait.FromStr.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl FromStr for WalletExport","synthetic":false,"types":["bdk::wallet::export::WalletExport"]}]; +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/latest/implementors/miniscript/trait.MiniscriptKey.js b/static/docs-rs/bdk/nightly/latest/implementors/miniscript/trait.MiniscriptKey.js new file mode 100644 index 0000000000..15310a1788 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/miniscript/trait.MiniscriptKey.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl<'s> MiniscriptKey for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]}]; +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/latest/implementors/miniscript/trait.ToPublicKey.js b/static/docs-rs/bdk/nightly/latest/implementors/miniscript/trait.ToPublicKey.js new file mode 100644 index 0000000000..6c57ee9682 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/miniscript/trait.ToPublicKey.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl<'s> ToPublicKey for DerivedDescriptorKey<'s>","synthetic":false,"types":["bdk::descriptor::derived::DerivedDescriptorKey"]}]; +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/latest/implementors/serde/de/trait.Deserialize.js b/static/docs-rs/bdk/nightly/latest/implementors/serde/de/trait.Deserialize.js new file mode 100644 index 0000000000..4dddf8a258 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl<'de> Deserialize<'de> for ElectrumBlockchainConfig","synthetic":false,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl<'de> Deserialize<'de> for EsploraBlockchainConfig","synthetic":false,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl<'de> Deserialize<'de> for EsploraGetHistory","synthetic":false,"types":["bdk::blockchain::esplora::EsploraGetHistory"]},{"text":"impl<'de> Deserialize<'de> for BitcoinPeerConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl<'de> Deserialize<'de> for CompactFiltersBlockchainConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl<'de> Deserialize<'de> for SledDbConfiguration","synthetic":false,"types":["bdk::database::any::SledDbConfiguration"]},{"text":"impl<'de> Deserialize<'de> for SqliteDbConfiguration","synthetic":false,"types":["bdk::database::any::SqliteDbConfiguration"]},{"text":"impl<'de> Deserialize<'de> for AnyDatabaseConfig","synthetic":false,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl<'de> Deserialize<'de> for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl<'de> Deserialize<'de> for LocalUtxo","synthetic":false,"types":["bdk::types::LocalUtxo"]},{"text":"impl<'de> Deserialize<'de> for TransactionDetails","synthetic":false,"types":["bdk::types::TransactionDetails"]},{"text":"impl<'de> Deserialize<'de> for ConfirmationTime","synthetic":false,"types":["bdk::types::ConfirmationTime"]},{"text":"impl<'de> Deserialize<'de> for WalletExport","synthetic":false,"types":["bdk::wallet::export::WalletExport"]}]; +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/latest/implementors/serde/ser/trait.Serialize.js b/static/docs-rs/bdk/nightly/latest/implementors/serde/ser/trait.Serialize.js new file mode 100644 index 0000000000..11272bbb51 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/serde/ser/trait.Serialize.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Serialize for AnyBlockchainConfig","synthetic":false,"types":["bdk::blockchain::any::AnyBlockchainConfig"]},{"text":"impl Serialize for ElectrumBlockchainConfig","synthetic":false,"types":["bdk::blockchain::electrum::ElectrumBlockchainConfig"]},{"text":"impl Serialize for EsploraBlockchainConfig","synthetic":false,"types":["bdk::blockchain::esplora::ureq::EsploraBlockchainConfig"]},{"text":"impl Serialize for BitcoinPeerConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::BitcoinPeerConfig"]},{"text":"impl Serialize for CompactFiltersBlockchainConfig","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersBlockchainConfig"]},{"text":"impl Serialize for SledDbConfiguration","synthetic":false,"types":["bdk::database::any::SledDbConfiguration"]},{"text":"impl Serialize for SqliteDbConfiguration","synthetic":false,"types":["bdk::database::any::SqliteDbConfiguration"]},{"text":"impl Serialize for AnyDatabaseConfig","synthetic":false,"types":["bdk::database::any::AnyDatabaseConfig"]},{"text":"impl Serialize for PkOrF","synthetic":false,"types":["bdk::descriptor::policy::PkOrF"]},{"text":"impl Serialize for SatisfiableItem","synthetic":false,"types":["bdk::descriptor::policy::SatisfiableItem"]},{"text":"impl Serialize for Satisfaction","synthetic":false,"types":["bdk::descriptor::policy::Satisfaction"]},{"text":"impl Serialize for Policy","synthetic":false,"types":["bdk::descriptor::policy::Policy"]},{"text":"impl Serialize for Condition","synthetic":false,"types":["bdk::descriptor::policy::Condition"]},{"text":"impl Serialize for KeychainKind","synthetic":false,"types":["bdk::types::KeychainKind"]},{"text":"impl Serialize for LocalUtxo","synthetic":false,"types":["bdk::types::LocalUtxo"]},{"text":"impl Serialize for TransactionDetails","synthetic":false,"types":["bdk::types::TransactionDetails"]},{"text":"impl Serialize for ConfirmationTime","synthetic":false,"types":["bdk::types::ConfirmationTime"]},{"text":"impl Serialize for WalletExport","synthetic":false,"types":["bdk::wallet::export::WalletExport"]}]; +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/latest/implementors/std/error/trait.Error.js b/static/docs-rs/bdk/nightly/latest/implementors/std/error/trait.Error.js new file mode 100644 index 0000000000..a772f567ff --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/implementors/std/error/trait.Error.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["bdk"] = [{"text":"impl Error for Error","synthetic":false,"types":["bdk::error::Error"]},{"text":"impl Error for EsploraError","synthetic":false,"types":["bdk::blockchain::esplora::EsploraError"]},{"text":"impl Error for CompactFiltersError","synthetic":false,"types":["bdk::blockchain::compact_filters::CompactFiltersError"]},{"text":"impl Error for Error","synthetic":false,"types":["bdk::descriptor::error::Error"]},{"text":"impl Error for PolicyError","synthetic":false,"types":["bdk::descriptor::policy::PolicyError"]},{"text":"impl Error for KeyError","synthetic":false,"types":["bdk::keys::KeyError"]},{"text":"impl Error for AddressValidatorError","synthetic":false,"types":["bdk::wallet::address_validator::AddressValidatorError"]},{"text":"impl Error for SignerError","synthetic":false,"types":["bdk::wallet::signer::SignerError"]}]; +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/latest/light.css b/static/docs-rs/bdk/nightly/latest/light.css new file mode 100644 index 0000000000..9ad7a698b1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/light.css @@ -0,0 +1 @@ + body{background-color:white;color:black;}h1,h2,h3,h4{color:black;}h1.fqn{border-bottom-color:#D5D5D5;}h2,h3,h4{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,.rustdoc.source .example-wrap{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,.docblock h6{border-bottom-color:#ddd;}.docblock table td,.docblock table th{border-color:#ddd;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#4E4C4C;}.search-results a:hover{background-color:#ddd;}.search-results a:focus{color:#000 !important;background-color:#ccc;}.search-results a:focus span{color:#000 !important;}a.result-trait:focus{background-color:#c7b6ff;}a.result-traitalias:focus{background-color:#c7b6ff;}a.result-mod:focus,a.result-externcrate:focus{background-color:#afc6e4;}a.result-enum:focus{background-color:#b4d1b9;}a.result-struct:focus{background-color:#e7b1a0;}a.result-union:focus{background-color:#b7bd49;}a.result-fn:focus,a.result-method:focus,a.result-tymethod:focus{background-color:#c6afb3;}a.result-type:focus{background-color:#ffc891;}a.result-foreigntype:focus{background-color:#f5c4ff;}a.result-attr:focus,a.result-derive:focus,a.result-macro:focus{background-color:#8ce488;}a.result-constant:focus,a.result-static:focus{background-color:#c3e0ff;}a.result-primitive:focus{background-color:#9aecff;}a.result-keyword:focus{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;}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;}body.source .example-wrap pre.rust a{background:#eee;}.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;}details.rustdoc-toggle>summary.hideme>span,details.rustdoc-toggle>summary::before,details.undocumented>summary::before{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-input:disabled{background-color:#e6e6e6;}#crate-search+.search-input:focus{box-shadow:0 0 8px #078dd8;}.module-item .stab,.import-item .stab{color:#000;}.stab.unstable{background:#FFF5D6;border-color:#FFC600;}.stab.deprecated{background:#ffc4c4;border-color:#db7b7b;}.stab.portability{background:#F3DFFF;border-color:#b07bdb;}.stab.portability>code{background:none;}#help>div{background:#e9e9e9;border-color:#bfbfbf;}#help span.bottom,#help span.top{border-color:#bfbfbf;}.since{color:grey;}.result-name .primitive>i,.result-name .keyword>i{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 .comment{color:#8E908C;}pre.rust .doccomment{color:#4D4D4C;}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,.code-attribute{color:#999;}:target,:target>*{background:#FDFFD3;}:target{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::after{background-color:#000;color:#fff;}.tooltip::before{border-color:transparent black transparent transparent;}.notable-traits-tooltiptext{background-color:#eee;border-color:#999;}.notable-traits-tooltiptext .notable{border-bottom-color:#DDDDDD;}#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;}#copy-path{color:#999;}#copy-path>img{filter:invert(50%);}#copy-path:hover>img{filter:invert(35%);}#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 .result-name span.alias{color:#000;}.search-results .result-name 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/latest/main.js b/static/docs-rs/bdk/nightly/latest/main.js new file mode 100644 index 0000000000..67e23ae0a0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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(){var rustdocVars=document.getElementById("rustdoc-vars");if(rustdocVars){window.rootPath=rustdocVars.attributes["data-root-path"].value;window.currentCrate=rustdocVars.attributes["data-current-crate"].value;window.searchJS=rustdocVars.attributes["data-search-js"].value;window.searchIndexJS=rustdocVars.attributes["data-search-index-js"].value}var sidebarVars=document.getElementById("sidebar-vars");if(sidebarVars){window.sidebarCurrent={name:sidebarVars.attributes["data-name"].value,ty:sidebarVars.attributes["data-ty"].value,relpath:sidebarVars.attributes["data-relpath"].value,}}}());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)}var THEME_PICKER_ELEMENT_ID="theme-picker";var THEMES_ELEMENT_ID="theme-choices";function getThemesElement(){return document.getElementById(THEMES_ELEMENT_ID)}function getThemePickerElement(){return document.getElementById(THEME_PICKER_ELEMENT_ID)}function getNakedUrl(){return window.location.href.split("?")[0].split("#")[0]}function showThemeButtonState(){var themePicker=getThemePickerElement();var themeChoices=getThemesElement();themeChoices.style.display="block";themePicker.style.borderBottomRightRadius="0";themePicker.style.borderBottomLeftRadius="0"}function hideThemeButtonState(){var themePicker=getThemePickerElement();var themeChoices=getThemesElement();themeChoices.style.display="none";themePicker.style.borderBottomRightRadius="3px";themePicker.style.borderBottomLeftRadius="3px"}(function(){var themeChoices=getThemesElement();var themePicker=getThemePickerElement();var availableThemes=["ayu","dark","light"];function switchThemeButtonState(){if(themeChoices.style.display==="block"){hideThemeButtonState()}else{showThemeButtonState()}}function handleThemeButtonsBlur(e){var active=document.activeElement;var related=e.relatedTarget;if(active.id!==THEME_PICKER_ELEMENT_ID&&(!active.parentNode||active.parentNode.id!==THEMES_ELEMENT_ID)&&(!related||(related.id!==THEME_PICKER_ELEMENT_ID&&(!related.parentNode||related.parentNode.id!==THEMES_ELEMENT_ID)))){hideThemeButtonState()}}themePicker.onclick=switchThemeButtonState;themePicker.onblur=handleThemeButtonsBlur;availableThemes.forEach(function(item){var but=document.createElement("button");but.textContent=item;but.onclick=function(){switchTheme(window.currentTheme,window.mainTheme,item,true);useSystemTheme(false)};but.onblur=handleThemeButtonsBlur;themeChoices.appendChild(but)})}());(function(){"use strict";window.searchState={loadingText:"Loading search results...",input:document.getElementsByClassName("search-input")[0],outputElement:function(){return document.getElementById("search")},title:document.title,titleBeforeSearch:document.title,timeout:null,currentTab:0,focusedByTab:[null,null,null],clearInputTimeout:function(){if(searchState.timeout!==null){clearTimeout(searchState.timeout);searchState.timeout=null}},focus:function(){searchState.input.focus()},defocus:function(){searchState.input.blur()},showResults:function(search){if(search===null||typeof search==='undefined'){search=searchState.outputElement()}addClass(main,"hidden");removeClass(search,"hidden");searchState.mouseMovedAfterSearch=false;document.title=searchState.title},hideResults:function(search){if(search===null||typeof search==='undefined'){search=searchState.outputElement()}addClass(search,"hidden");removeClass(main,"hidden");document.title=searchState.titleBeforeSearch;if(searchState.browserSupportsHistoryApi()){history.replaceState("",window.currentCrate+" - Rust",getNakedUrl()+window.location.hash)}},getQueryStringParams:function(){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},putBackSearch:function(search_input){var search=searchState.outputElement();if(search_input.value!==""&&hasClass(search,"hidden")){searchState.showResults(search);if(searchState.browserSupportsHistoryApi()){var extra="?search="+encodeURIComponent(search_input.value);history.replaceState(search_input.value,"",getNakedUrl()+extra+window.location.hash)}document.title=searchState.title}},browserSupportsHistoryApi:function(){return window.history&&typeof window.history.pushState==="function"},setup:function(){var search_input=searchState.input;if(!searchState.input){return}function loadScript(url){var script=document.createElement('script');script.src=url;document.head.append(script)}var searchLoaded=false;function loadSearch(){if(!searchLoaded){searchLoaded=true;loadScript(window.searchJS);loadScript(window.searchIndexJS)}}search_input.addEventListener("focus",function(){searchState.putBackSearch(this);search_input.origPlaceholder=searchState.input.placeholder;search_input.placeholder="Type your search here.";loadSearch()});search_input.addEventListener("blur",function(){search_input.placeholder=searchState.input.origPlaceholder});search_input.removeAttribute('disabled');searchState.addCrateDropdown(window.ALL_CRATES);var params=searchState.getQueryStringParams();if(params.search!==undefined){var search=searchState.outputElement();search.innerHTML="

"+searchState.loadingText+"

";searchState.showResults(search);loadSearch()}},addCrateDropdown:function(crates){var elem=document.getElementById("crate-search");if(!elem){return}var savedCrate=getSettingValue("saved-filter-crate");for(var i=0,len=crates.length;i0){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=""}var toggleAllDocsId="toggle-all-docs";var main=document.getElementById("main");var savedHash="";function handleHashes(ev){var elem;var search=searchState.outputElement();if(ev!==null&&search&&!hasClass(search,"hidden")&&ev.newURL){searchState.hideResults(search);var hash=ev.newURL.slice(ev.newURL.indexOf("#")+1);if(searchState.browserSupportsHistoryApi()){history.replaceState(hash,"",getNakedUrl()+window.location.search+"#"+hash)}elem=document.getElementById(hash);if(elem){elem.scrollIntoView()}}if(savedHash!==window.location.hash){savedHash=window.location.hash;if(savedHash.length===0){return}expandSection(savedHash.slice(1))}}function onHashChange(ev){hideSidebar();handleHashes(ev)}function openParentDetails(elem){while(elem){if(elem.tagName==="DETAILS"){elem.open=true}elem=elem.parentNode}}function expandSection(id){openParentDetails(document.getElementById(id))}function getHelpElement(build){if(build){buildHelperPopup()}return document.getElementById("help")}function displayHelp(display,ev,help){if(display){help=help?help:getHelpElement(true);if(hasClass(help,"hidden")){ev.preventDefault();removeClass(help,"hidden");addClass(document.body,"blur")}}else{help=help?help:getHelpElement(false);if(help&&!hasClass(help,"hidden")){ev.preventDefault();addClass(help,"hidden");removeClass(document.body,"blur")}}}function handleEscape(ev){var help=getHelpElement(false);var search=searchState.outputElement();if(help&&!hasClass(help,"hidden")){displayHelp(false,ev,help)}else if(search&&!hasClass(search,"hidden")){searchState.clearInputTimeout();ev.preventDefault();searchState.hideResults(search)}searchState.defocus();hideThemeButtonState()}var disableShortcuts=getSettingValue("disable-shortcuts")==="true";function handleShortcut(ev){if(ev.ctrlKey||ev.altKey||ev.metaKey||disableShortcuts){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();searchState.focus();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:if(getThemePickerElement().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_ELEMENT_ID){active.previousElementSibling.focus()}else{showThemeButtonState();themes.lastElementChild.focus()}break;case"ArrowDown":ev.preventDefault();if(active.nextElementSibling&&ev.target.id!==THEME_PICKER_ELEMENT_ID){active.nextElementSibling.focus()}else{showThemeButtonState();themes.firstElementChild.focus()}break;case"Enter":case"Return":case"Space":if(ev.target.id===THEME_PICKER_ELEMENT_ID&&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}}document.addEventListener("keypress",handleShortcut);document.addEventListener("keydown",handleShortcut);(function(){var x=document.getElementsByClassName("version-selector");if(x.length>0){x[0].onchange=function(){var i,match,url=document.location.href,stripped="",len=window.rootPath.match(/\.\.\//g).length+1;for(i=0;i .in-band > .trait").textContent;var baseIdName="impl-"+traitName+"-";var libs=Object.getOwnPropertyNames(imp);for(var i=0,llength=libs.length;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"],["← / →","Switch result tab (when results focused)"],["⏎","Go to active search result"],["+","Expand all sections"],["-","Collapse all sections"],].map(function(x){return"
"+x[0].split(" ").map(function(y,index){return(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(function(x){return"

"+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);var rustdoc_version=document.createElement("span");rustdoc_version.className="bottom";var rustdoc_version_code=document.createElement("code");rustdoc_version_code.innerText="rustdoc 1.57.0-nightly (485ced56b 2021-10-07)";rustdoc_version.appendChild(rustdoc_version_code);container.appendChild(rustdoc_version);popup.appendChild(container);insertAfter(popup,searchState.outputElement());buildHelperPopup=function(){}};onHashChange(null);window.addEventListener("hashchange",onHashChange);searchState.setup()}());(function(){var reset_button_timeout=null;window.copy_path=function(but){var parent=but.parentElement;var path=[];onEach(parent.childNodes,function(child){if(child.tagName==='A'){path.push(child.textContent)}});var el=document.createElement('textarea');el.value=path.join('::');el.setAttribute('readonly','');el.style.position='absolute';el.style.left='-9999px';document.body.appendChild(el);el.select();document.execCommand('copy');document.body.removeChild(el);but.children[0].style.display='none';var tmp;if(but.childNodes.length<2){tmp=document.createTextNode('✓');but.appendChild(tmp)}else{onEachLazy(but.childNodes,function(e){if(e.nodeType===Node.TEXT_NODE){tmp=e;return true}});tmp.textContent='✓'}if(reset_button_timeout!==null){window.clearTimeout(reset_button_timeout)}function reset_button(){tmp.textContent='';reset_button_timeout=null;but.children[0].style.display=""}reset_button_timeout=window.setTimeout(reset_button,1000)}}()) \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/normalize.css b/static/docs-rs/bdk/nightly/latest/normalize.css new file mode 100644 index 0000000000..469959f137 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/normalize.css @@ -0,0 +1,2 @@ + /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/noscript.css b/static/docs-rs/bdk/nightly/latest/noscript.css new file mode 100644 index 0000000000..aea68efbc9 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/noscript.css @@ -0,0 +1 @@ + #main .attributes{margin-left:0 !important;}#copy-path{display:none;} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/noto-sans-kr-v13-korean-regular-LICENSE.txt b/static/docs-rs/bdk/nightly/latest/noto-sans-kr-v13-korean-regular-LICENSE.txt new file mode 100644 index 0000000000..922d5fdc18 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/noto-sans-kr-v13-korean-regular-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2014, 2015 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/latest/noto-sans-kr-v13-korean-regular.woff b/static/docs-rs/bdk/nightly/latest/noto-sans-kr-v13-korean-regular.woff new file mode 100644 index 0000000000..01d6b6b546 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/noto-sans-kr-v13-korean-regular.woff differ diff --git a/static/docs-rs/bdk/nightly/latest/rust-logo.png b/static/docs-rs/bdk/nightly/latest/rust-logo.png new file mode 100644 index 0000000000..74b4bd6950 Binary files /dev/null and b/static/docs-rs/bdk/nightly/latest/rust-logo.png differ diff --git a/static/docs-rs/bdk/nightly/latest/rustdoc.css b/static/docs-rs/bdk/nightly/latest/rustdoc.css new file mode 100644 index 0000000000..bced0db9fe --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/rustdoc.css @@ -0,0 +1 @@ + @font-face {font-family:'Fira Sans';font-style:normal;font-weight:400;src:local('Fira Sans'),url("FiraSans-Regular.woff2") format("woff2"),url("FiraSans-Regular.woff") format('woff');font-display:swap;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:500;src:local('Fira Sans Medium'),url("FiraSans-Medium.woff2") format("woff2"),url("FiraSans-Medium.woff") format('woff');font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:400;src:local('Source Serif 4'),url("SourceSerif4-Regular.ttf.woff2") format("woff2"),url("SourceSerif4-Regular.ttf.woff") format("woff");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:italic;font-weight:400;src:local('Source Serif 4 Italic'),url("SourceSerif4-It.ttf.woff2") format("woff2"),url("SourceSerif4-It.ttf.woff") format("woff");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:700;src:local('Source Serif 4 Bold'),url("SourceSerif4-Bold.ttf.woff2") format("woff2"),url("SourceSerif4-Bold.ttf.woff") format("woff");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:400;src:url("SourceCodePro-Regular.ttf.woff2") format("woff2"),url("SourceCodePro-Regular.ttf.woff") format("woff");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:italic;font-weight:400;src:url("SourceCodePro-It.ttf.woff2") format("woff2"),url("SourceCodePro-It.ttf.woff") format("woff");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:600;src:url("SourceCodePro-Semibold.ttf.woff2") format("woff2"),url("SourceCodePro-Semibold.ttf.woff") format("woff");font-display:swap;}@font-face {font-family:'Noto Sans KR';src:url("noto-sans-kr-v13-korean-regular.woff") format("woff");font-display:swap;unicode-range:U+A960-A97F,U+AC00-D7AF,U+D7B0-D7FF;}*{-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 4","Noto Sans KR",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,h4,h5,h6{font-weight:500;margin:20px 0 15px 0;padding-bottom:6px;}h1.fqn{display:flex;border-bottom:1px dashed;margin-top:0;padding-left:1px;}h1.fqn>.in-band>a:hover{text-decoration:underline;}h2,h3,h4{border-bottom:1px solid;}h3.code-header,h4.code-header{font-size:1em;font-weight:600;border:none;padding:0;margin:0;}.impl,.impl-items .method,.methods .method,.impl-items .type,.methods .type,.impl-items .associatedconstant,.methods .associatedconstant,.impl-items .associatedtype,.methods .associatedtype{flex-basis:100%;font-weight:600;margin-top:16px;margin-bottom:10px;position:relative;}.impl,.method.trait-impl,.type.trait-impl,.associatedconstant.trait-impl,.associatedtype.trait-impl{padding-left:15px;}div.impl-items>div{padding-left:0;}h1,h2,h3,h4,h5,h6,.sidebar,a.source,.search-input,.search-results .result-name,.content table td:first-child>a,.item-left>a,div.item-list .out-of-band,span.since,#source-sidebar,#sidebar-toggle,details.rustdoc-toggle>summary::before,details.undocumented>summary::before,div.impl-items>div:not(.docblock):not(.item-info),.content ul.crate a.crate,a.srclink,#main>ul.docblock>li>a{font-family:"Fira Sans",Arial,sans-serif;}.content ul.crate a.crate{font-size:16px/1.6;}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;}td,th{padding:0;}table{border-collapse:collapse;}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0;}details:not(.rustdoc-toggle) summary{margin-bottom:.6em;}code,pre,a.test-arrow,.code-header{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{padding:0;}pre{padding:14px;}.type-decl pre{overflow-x:auto;}.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;}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;height:100%;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;font-weight:inherit;padding:0;}.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-of-type{font-weight:500;}.location a:hover{text-decoration:underline;}.block{padding:0;margin-bottom:14px;}.block h2,.block h3{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;font-weight:inherit;padding:0;}.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 .example-wrap{display:inline-flex;margin-bottom:10px;}.example-wrap{position:relative;width:100%;}.example-wrap>pre.line-number{overflow:initial;border:1px solid;padding:13px 8px;text-align:right;border-top-left-radius:5px;border-bottom-left-radius:5px;}.example-wrap>pre.rust a:hover{text-decoration:underline;}.rustdoc:not(.source) .example-wrap>pre:not(.line-number){width:100%;overflow-x:auto;}.rustdoc .example-wrap>pre{margin:0;}#search{margin-left:230px;position:relative;}#results>table{width:100%;table-layout:fixed;}.content>.example-wrap pre.line-numbers{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>:not(pre)>code,.docblock-short>:not(pre)>code{white-space:pre-wrap;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5,.docblock h6{border-bottom:1px solid;}.top-doc .docblock h2{font-size:1.3em;}.top-doc .docblock h3{font-size:1.15em;}.top-doc .docblock h4,.top-doc .docblock h5,.top-doc .docblock h6{font-size:1em;}.docblock h5{font-size:1em;}.docblock h6{font-size:0.95em;}.docblock{margin-left:24px;position:relative;}.docblock>*{max-width:100%;overflow-x:auto;}.content .out-of-band{flex-grow:0;text-align:right;font-size:23px;margin:0px;padding:0 0 0 12px;font-weight:normal;}.method>.code-header,.trait-impl>.code-header,.invisible>.code-header{max-width:calc(100% - 41px);display:block;}.invisible{width:100%;display:inline-block;}.content .in-band{flex-grow:1;margin:0px;padding:0px;}.in-band>code,.in-band>.code-header{display:inline-block;}#main{position:relative;}#main>.since{top:inherit;font-family:"Fira Sans",Arial,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);overflow-x:auto;display:block;}.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>.methods>.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):not(.method){margin-left:40px;margin-bottom:15px;}.content .docblock>.impl-items{margin-left:20px;margin-top:-34px;}.content .docblock>.impl-items .table-display{margin:0;}.content .docblock>.impl-items table td{padding:0;}.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;}.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,.impl-items>.associatedtype,.content .impl-items details>summary>.type,.impl-items details>summary>.associatedconstant,.impl-items details>summary>.associatedtype{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{display:flex;justify-content:space-between;position:relative;}.small-section-header:hover>.anchor{display:initial;}.in-band:hover>.anchor,.impl:hover>.anchor,.method.trait-impl:hover>.anchor,.type.trait-impl:hover>.anchor,.associatedconstant.trait-impl:hover>.anchor,.associatedtype.trait-impl:hover>.anchor{display:inline-block;position:absolute;}.anchor{display:none;position:absolute;left:0;background:none !important;}.anchor.field{left:-5px;}.small-section-header>.anchor{left:-15px;padding-right:8px;}h2.small-section-header>.anchor{padding-right:6px;}.anchor::before{content:'§';}.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,.method>.code-header+.srclink{position:absolute;top:0;right:0;font-size:17px;font-weight:normal;}.block a.current.crate{font-weight:500;}.item-table{display:table-row;justify-items:start;}.item-row{display:table-row;}.item-left,.item-right{display:table-cell;}.item-left{padding-right:1.2rem;}.search-container{position:relative;}.search-container>div{display:inline-flex;width:calc(100% - 63px);}#crate-search{min-width:115px;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{display:none;padding-bottom:2em;}.search-results.active{display:block;clear:both;}.search-results .desc>span{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;display:block;}.search-results>a{display:block;width:100%;margin-left:2px;margin-right:2px;border-bottom:1px solid #aaa3;}.search-results>a>div{display:flex;flex-flow:row wrap;}.search-results .result-name,.search-results div.desc,.search-results .result-description{width:50%;}.search-results .result-name{padding-right:1em;}.search-results .result-name>span{display:inline-block;margin:0;font-weight:normal;}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;margin-right:0.5rem;}#help span.top,#help span.bottom{text-align:center;display:block;font-size:18px;}#help span.top{text-align:center;display:block;margin:10px 0;border-bottom:1px solid;padding-bottom:4px;margin-bottom:6px;}#help span.bottom{clear:both;border-top:1px solid;}#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;;}.item-info .stab{display:table;}.stab{border-width:1px;border-style:solid;padding:3px;margin-bottom:5px;font-size:90%;font-weight:normal;}.stab p{display:inline;}.stab .emoji{font-size:1.5em;}.emoji{text-shadow:1px 0 0 black,-1px 0 0 black,0 1px 0 black,0 -1px 0 black;}.module-item .stab,.import-item .stab{border-radius:3px;display:inline-block;font-size:80%;line-height:1.2;margin-bottom:0;margin-left:.3em;padding:2px;vertical-align:text-bottom;}.module-item.unstable,.import-item.unstable{opacity:0.65;}.since{font-weight:normal;font-size:initial;}.impl-items .since,.impl .since,.methods .since{padding-left:12px;padding-right:2px;position:initial;}.impl-items .srclink,.impl .srclink,.methods .srclink{font-size:17px;font-weight:normal;}.rightside{float:right;}.has-srclink{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;}.code-attribute{font-weight:300;}.since+.srclink{padding-left:10px;}.item-spacer{width:100%;height:12px;}.out-of-band>span.since{position:initial;font-size:20px;margin-right:5px;}.sub-variant,.sub-variant>h3{margin-top:0px !important;padding-top:1px;}#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;}.docblock>.section-header:first-child{margin-left:15px;margin-top:0;}.docblock>.section-header:first-child:hover>a:before{left:-10px;}:target>code,:target>.code-header{opacity:1;}:target{padding-right:3px;}.information{position:absolute;left:-25px;margin-top:7px;z-index:1;}.tooltip{position:relative;display:inline-block;cursor:pointer;}.tooltip::after{display:none;text-align:center;padding:5px 3px 3px 3px;border-radius:6px;margin-left:5px;font-size:16px;}.tooltip.ignore::after{content:"This example is not tested";}.tooltip.compile_fail::after{content:"This example deliberately fails to compile";}.tooltip.should_panic::after{content:"This example panics";}.tooltip.edition::after{content:"This code runs with edition " attr(data-edition);}.tooltip::before{content:" ";position:absolute;top:50%;left:16px;margin-top:-5px;border-width:5px;border-style:solid;display:none;}.tooltip:hover::before,.tooltip:hover::after{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 .notable{margin:0;margin-bottom:13px;font-size:19px;font-weight:600;}.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;display:none;}.search-failed.active{display:block;}.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;}#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;}#theme-picker,#settings-menu,#help-button,#copy-path{padding:4px;width:27px;height:29px;border:1px solid;border-radius:3px;cursor:pointer;}#help-button{right:30px;font-family:"Fira Sans",Arial,sans-serif;text-align:center;font-size:17px;padding-top:2px;}#copy-path{background:initial;margin-left:10px;padding:0;padding-left:2px;border:0;}#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;}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;}details.rustdoc-toggle>summary.hideme{cursor:pointer;}details.rustdoc-toggle>summary,details.undocumented>summary{list-style:none;}details.rustdoc-toggle>summary::-webkit-details-marker,details.rustdoc-toggle>summary::marker,details.undocumented>summary::-webkit-details-marker,details.undocumented>summary::marker{display:none;}details.rustdoc-toggle>summary.hideme>span{margin-left:9px;}details.rustdoc-toggle>summary::before{content:"";cursor:pointer;width:17px;height:max(17px,1.1em);background-repeat:no-repeat;background-position:top left;display:inline-block;vertical-align:middle;opacity:.5;}details.rustdoc-toggle>summary::after{content:"Expand";overflow:hidden;width:0;height:0;position:absolute;}details.rustdoc-toggle>summary.hideme::after{content:"";}details.rustdoc-toggle>summary:focus::before,details.rustdoc-toggle>summary:hover::before{opacity:1;}details.rustdoc-toggle.top-doc>summary,details.rustdoc-toggle.top-doc>summary::before,details.rustdoc-toggle.non-exhaustive>summary,details.rustdoc-toggle.non-exhaustive>summary::before{font-family:'Fira Sans';font-size:16px;}details.non-exhaustive{margin-bottom:8px;}details.rustdoc-toggle>summary.hideme::before{position:relative;}details.rustdoc-toggle>summary:not(.hideme)::before{position:absolute;left:-23px;top:3px;}.impl-items>details.rustdoc-toggle>summary:not(.hideme)::before,.undocumented>details.rustdoc-toggle>summary:not(.hideme)::before{position:absolute;left:-2px;}details.rustdoc-toggle[open] >summary.hideme{position:absolute;}details.rustdoc-toggle,details.undocumented{position:relative;}details.rustdoc-toggle[open] >summary.hideme>span{display:none;}details.rustdoc-toggle[open] >summary::before,details.rustdoc-toggle[open] >summary.hideme::before{width:17px;height:max(17px,1.1em);background-repeat:no-repeat;background-position:top left;display:inline-block;content:"";}details.rustdoc-toggle[open] >summary::after,details.rustdoc-toggle[open] >summary.hideme::after{content:"Collapse";}details.undocumented>summary::before{padding-left:17px;height:max(17px,1.1em);background-repeat:no-repeat;background-position:top left;content:"Show hidden undocumented items";cursor:pointer;font-size:16px;font-weight:300;opacity:.5;}details.undocumented>summary:focus::before,details.undocumented>summary:hover::before{opacity:1;}details.undocumented[open] >summary::before{padding-left:17px;height:max(17px,1.1em);background-repeat:no-repeat background-position:top left;content:"Hide undocumented items";}@media (min-width:701px){.docblock>.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;top:45px;bottom:0;width:246px;left:-246px;overflow-y:auto;border-right:1px solid;}.sidebar>.block.version{overflow:hidden;border-bottom:none;margin-bottom:0;height:100%;padding-left:12px;}.sidebar>.block.version>div.narrow-helper{float:left;width:1px;height:100%;}.sidebar>.block.version>p{margin:0;min-width:55px;display:flex;align-items:center;height:100%;}nav.sub{width:calc(100% - 32px);float:right;}.content{margin-left:0px;}#main,#search{margin-top:45px;padding:0;}#search{margin-left:0;}.anchor{display:none !important;}.theme-picker{left:10px;top:54px;z-index:1;}.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.mobile>div.version{overflow:hidden;max-height:33px;}.sidebar{width:calc(100% + 30px);}.show-it,.sidebar-elems:focus-within{z-index:2;left:0;}.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;}#main>details.rustdoc-toggle>summary::before,#main>div>details.rustdoc-toggle>summary::before{left:-11px;}#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;}.item-table{display:block;}.item-row{display:flex;flex-flow:column wrap;}.item-left,.item-right{width:100%;}.search-container>div{width:calc(100% - 32px);}.search-results>a{border-bottom:1px solid #aaa9;padding:5px 0px;}.search-results .result-name,.search-results div.desc,.search-results .result-description{width:100%;}.search-results div.desc,.search-results .result-description,.item-right{padding-left:2em;}}@media print{nav.sub,.content .out-of-band{display:none;}}@media (max-width:464px){#titles,#titles>button{height:73px;}#main,#search{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;}.docblock{margin-left:12px;}}details.undocumented[open] >summary::before,details.rustdoc-toggle[open] >summary::before,details.rustdoc-toggle[open] >summary.hideme::before{background-image:url(toggle-minus.svg);}details.undocumented>summary::before,details.rustdoc-toggle>summary::before{background-image:url(toggle-plus.svg);} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/search-index.js b/static/docs-rs/bdk/nightly/latest/search-index.js new file mode 100644 index 0000000000..662b65612b --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/search-index.js @@ -0,0 +1,4 @@ +var searchIndex = JSON.parse('{\ +"bdk":{"doc":"A modern, lightweight, descriptor-based wallet library …","t":[13,13,13,13,13,13,3,13,13,13,4,13,13,3,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,4,13,3,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,3,13,13,4,8,3,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,14,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,14,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,0,11,11,11,11,11,11,11,11,12,11,12,12,12,11,11,11,11,11,12,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,12,11,11,11,11,11,11,11,11,12,10,12,5,11,11,11,11,11,11,11,11,0,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,8,4,16,8,3,13,13,3,3,8,6,0,11,11,11,11,11,11,10,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,0,11,0,10,11,11,11,11,10,10,11,10,10,11,11,11,11,11,11,11,5,5,5,10,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,4,4,13,13,13,13,13,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,13,3,3,3,4,13,13,13,13,13,13,13,13,3,13,13,13,3,13,13,13,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,12,11,11,11,11,11,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,12,12,12,11,11,11,11,11,11,11,12,11,11,13,3,3,4,3,13,13,13,13,13,13,13,13,13,13,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,16,8,8,16,8,8,3,0,10,11,11,11,10,11,10,11,12,10,11,10,11,10,11,10,11,10,11,10,11,11,11,11,10,11,11,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,11,11,10,11,10,11,10,11,10,11,0,11,12,10,11,10,11,10,11,10,11,10,11,11,11,11,11,4,4,4,13,13,13,13,13,13,3,13,13,13,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13,6,3,4,6,8,6,8,6,4,3,13,8,4,13,13,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,12,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,5,13,13,13,4,13,13,13,13,13,13,13,13,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,13,13,13,4,13,3,6,6,13,13,13,13,13,13,13,13,13,13,13,3,3,4,13,13,13,13,4,4,13,13,13,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,12,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,3,3,3,3,3,3,8,6,3,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13,8,4,4,4,3,3,16,16,8,4,8,8,3,8,13,13,13,4,6,13,13,13,16,13,3,13,8,4,13,13,13,3,6,13,13,5,10,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,12,12,12,11,5,11,10,11,11,5,11,11,11,11,12,12,11,11,11,11,11,11,12,11,11,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,4,3,4,6,3,13,13,13,13,13,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,4,3,8,13,13,13,13,3,11,11,12,0,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,5,11,11,12,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,0,11,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,12,12,8,4,13,13,13,13,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,12,3,8,3,6,3,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,3,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,12,13,13,13,13,13,13,13,13,13,13,13,13,3,8,4,4,3,3,13,11,12,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,10,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,5,13,3,13,13,4,3,13,13,3,8,4,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11],"n":["AddressValidator","Bip32","BnBNoExactMatch","BnBTotalTriesExceeded","ChecksumMismatch","CompactFilters","ConfirmationTime","Descriptor","Electrum","Encode","Error","Esplora","External","FeeRate","FeeRateTooLow","FeeRateUnavailable","FeeTooLow","Foreign","Generic","Hex","InsufficientFunds","Internal","InvalidNetwork","InvalidOutpoint","InvalidPolicyPathError","InvalidProgressValue","InvalidU32Bytes","IrreplaceableTransaction","Json","Key","KeychainKind","Local","LocalUtxo","Miniscript","MissingKeyOrigin","NoRecipients","NoUtxosSelected","OutputBelowDustLimit","ProgressUpdateError","Psbt","PsbtParse","Rusqlite","ScriptDoesntHaveAddressForm","Secp256k1","Signer","Sled","SpendingPolicyRequired","TransactionConfirmed","TransactionDetails","TransactionNotFound","UnknownUtxo","Utxo","Vbytes","WeightedUtxo","as_byte","as_fail","as_ref","as_sat_vb","base32_len","blockchain","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","check_base32","clone","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","confirmation_time","database","default","default","default","default_min_relay_fee","deref","deref","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","descriptor","descriptor","deserialize","deserialize","deserialize","deserialize","drop","drop","drop","drop","drop","drop","drop","drop","eq","eq","eq","eq","eq","eq","eq","fee","fee_vb","fee_wu","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fragment","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_btc_per_kvb","from_sat_per_vb","from_vb","from_wu","get_hash","get_hash","hash","hash","height","init","init","init","init","init","init","init","init","into","into","into","into","into","into","into","into","into_descriptor_key","into_extended_key","into_wallet_descriptor","into_wallet_descriptor","keychain","keys","ne","ne","ne","ne","ne","ne","new","outpoint","outpoint","partial_cmp","received","satisfaction_weight","sent","serialize","serialize","serialize","serialize","sub","timestamp","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_string","transaction","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","txid","txout","txout","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","utxo","vbytes","verified","version","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","wallet","write_base32","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","available","found","needed","requested","required","required","0","outpoint","psbt_input","AccurateFees","Blockchain","Capability","Config","ConfigurableBlockchain","EsploraBlockchain","FullHistory","GetAnyTx","LogProgress","NoopProgress","Progress","ProgressData","any","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","broadcast","clone","clone","clone","clone_into","clone_into","clone_into","compact_filters","deref","deref","deref","deref_mut","deref_mut","deref_mut","drop","drop","drop","electrum","eq","esplora","estimate_fee","fmt","from","from","from","from_config","get_capabilities","get_hash","get_height","get_tx","hash","init","init","init","into","into","into","log_progress","noop_progress","progress","setup","sync","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","update","update","update","vzip","vzip","vzip","AnyBlockchain","AnyBlockchainConfig","CompactFilters","CompactFilters","Electrum","Electrum","Esplora","Esplora","borrow","borrow","borrow_mut","borrow_mut","broadcast","clone","clone_into","deref","deref","deref_mut","deref_mut","deserialize","drop","drop","eq","estimate_fee","fmt","from","from","from","from","from","from","from","from","from_config","get_capabilities","get_height","get_tx","init","init","into","into","ne","serialize","setup","sync","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","vzip","vzip","0","0","0","0","0","0","Bip158","BitcoinPeerConfig","CompactFiltersBlockchain","CompactFiltersBlockchainConfig","CompactFiltersError","DataCorruption","Db","Global","InvalidFilter","InvalidFilterHeader","InvalidHeaders","InvalidResponse","Io","Mempool","MissingBlock","NoPeers","NotConnected","Peer","PeerBloomDisabled","Time","Timeout","add_tx","address","as_fail","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","broadcast","clone","clone","clone_into","clone_into","connect","connect_proxy","default","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deserialize","deserialize","drop","drop","drop","drop","drop","drop","eq","eq","estimate_fee","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from_config","get_capabilities","get_height","get_mempool","get_network","get_tx","get_tx","get_version","has_tx","init","init","init","init","init","init","into","into","into","into","into","into","is_connected","iter_txs","ne","ne","network","new","new","peers","recv","send","serialize","serialize","setup","skip_blocks","socks5","socks5_credentials","storage_dir","to_owned","to_owned","to_string","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","vzip","0","0","0","0","0","ElectrumBlockchain","ElectrumBlockchainConfig","borrow","borrow","borrow_mut","borrow_mut","broadcast","clone","clone_into","deref","deref","deref_mut","deref_mut","deserialize","drop","drop","eq","estimate_fee","fmt","from","from","from","from_config","get_capabilities","get_height","get_tx","init","init","into","into","ne","retry","serialize","setup","socks5","stop_gap","timeout","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","url","vzip","vzip","BitcoinEncoding","EsploraBlockchain","EsploraBlockchainConfig","EsploraError","EsploraGetHistory","HeaderHashNotFound","HeaderHeightNotFound","Hex","HttpResponse","Io","NoHeader","Parsing","TransactionNotFound","Ureq","UreqTransport","as_fail","base_url","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","broadcast","clone","clone_into","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deserialize","deserialize","drop","drop","drop","drop","eq","estimate_fee","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from_config","get_capabilities","get_height","get_tx","init","init","init","init","into","into","into","into","ne","new","proxy","serialize","setup","stop_gap","timeout_read","timeout_write","to_owned","to_string","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","with_agent","0","0","0","0","0","0","0","0","0","0","Batch","BatchDatabase","BatchOperations","Config","ConfigurableDatabase","Database","SqliteDatabase","any","begin_batch","begin_batch","borrow","borrow_mut","check_descriptor_checksum","check_descriptor_checksum","commit_batch","commit_batch","connection","del_last_index","del_last_index","del_path_from_script_pubkey","del_path_from_script_pubkey","del_raw_tx","del_raw_tx","del_script_pubkey_from_path","del_script_pubkey_from_path","del_tx","del_tx","del_utxo","del_utxo","deref","deref_mut","drop","flush","flush","fmt","from","from_config","from_config","get_last_index","get_last_index","get_path_from_script_pubkey","get_path_from_script_pubkey","get_raw_tx","get_raw_tx","get_script_pubkey_from_path","get_script_pubkey_from_path","get_tx","get_tx","get_utxo","get_utxo","increment_last_index","increment_last_index","init","into","iter_raw_txs","iter_raw_txs","iter_script_pubkeys","iter_script_pubkeys","iter_txs","iter_txs","iter_utxos","iter_utxos","memory","new","path","set_last_index","set_last_index","set_raw_tx","set_raw_tx","set_script_pubkey","set_script_pubkey","set_tx","set_tx","set_utxo","set_utxo","try_from","try_into","type_id","vzip","AnyBatch","AnyDatabase","AnyDatabaseConfig","Memory","Memory","Memory","Sled","Sled","Sled","SledDbConfiguration","Sqlite","Sqlite","Sqlite","SqliteDbConfiguration","begin_batch","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","check_descriptor_checksum","commit_batch","del_last_index","del_last_index","del_path_from_script_pubkey","del_path_from_script_pubkey","del_raw_tx","del_raw_tx","del_script_pubkey_from_path","del_script_pubkey_from_path","del_tx","del_tx","del_utxo","del_utxo","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deserialize","deserialize","deserialize","drop","drop","drop","drop","drop","flush","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_config","get_last_index","get_path_from_script_pubkey","get_raw_tx","get_script_pubkey_from_path","get_tx","get_utxo","increment_last_index","init","init","init","init","init","into","into","into","into","into","iter_raw_txs","iter_script_pubkeys","iter_txs","iter_utxos","path","path","serialize","serialize","serialize","set_last_index","set_last_index","set_raw_tx","set_raw_tx","set_script_pubkey","set_script_pubkey","set_tx","set_tx","set_utxo","set_utxo","tree_name","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","0","0","0","0","0","0","0","0","0","MemoryDatabase","begin_batch","borrow","borrow_mut","check_descriptor_checksum","commit_batch","default","del_last_index","del_path_from_script_pubkey","del_raw_tx","del_script_pubkey_from_path","del_tx","del_utxo","deref","deref_mut","drop","flush","fmt","from","from_config","get_last_index","get_path_from_script_pubkey","get_raw_tx","get_script_pubkey_from_path","get_tx","get_utxo","increment_last_index","init","into","iter_raw_txs","iter_script_pubkeys","iter_txs","iter_utxos","new","set_last_index","set_raw_tx","set_script_pubkey","set_tx","set_utxo","try_from","try_into","type_id","vzip","Bare","DerivedDescriptor","DerivedDescriptorKey","Descriptor","ExtendedDescriptor","ExtractPolicy","HdKeyPaths","IntoWalletDescriptor","KeyMap","Legacy","Miniscript","Pkh","ScriptContext","Segwitv0","Sh","Wpkh","Wsh","address","as_enum","as_enum","as_inner","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","branches","check_global_consensus_validity","check_global_consensus_validity","check_global_consensus_validity","check_global_policy_validity","check_global_policy_validity","check_global_validity","check_local_consensus_validity","check_local_consensus_validity","check_local_consensus_validity","check_local_policy_validity","check_local_policy_validity","check_local_policy_validity","check_local_validity","check_terminal_non_malleable","check_terminal_non_malleable","check_terminal_non_malleable","check_witness","check_witness","check_witness","checksum","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","cmp","cmp","cmp","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","derive","desc_type","deserialize","deserialize","drop","drop","drop","drop","drop","encode","eq","eq","eq","eq","eq","error","explicit_script","ext","extract_policy","extract_policy","extract_policy","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","for_each_key","for_each_key","from","from","from","from","from","from_ast","from_str","from_str","from_str_insane","from_tree","from_tree","get_hash","get_hash","get_hash","get_hash","get_hash","get_leaf_pk","get_leaf_pk_pkh","get_leaf_pkh","get_nth_child","get_nth_pk","get_nth_pk_pkh","get_nth_pkh","get_satisfaction","has_mixed_timelocks","has_repeated_keys","hash","hash","hash","hash","hash","hash_to_hash160","init","init","init","init","init","into","into","into","into","into","into_inner","into_wallet_descriptor","is_deriveable","is_non_malleable","is_uncompressed","iter","iter_pk","iter_pk_pkh","iter_pkh","lift","lift","lift_check","max_satisfaction_size","max_satisfaction_size","max_satisfaction_size","max_satisfaction_size","max_satisfaction_weight","max_satisfaction_witness_elements","ne","new","new_bare","new_pk","new_pkh","new_sh","new_sh_sortedmulti","new_sh_wpkh","new_sh_wsh","new_sh_wsh_sortedmulti","new_wpkh","new_wsh","new_wsh_sortedmulti","node","other_top_level_checks","parse","parse_descriptor","parse_insane","partial_cmp","partial_cmp","partial_cmp","partial_cmp","partial_cmp","policy","requires_sig","sanity_check","sanity_check","satisfy","satisfy_malleable","script_code","script_pubkey","script_size","serialize","serialize","serialized_len","template","to_owned","to_owned","to_owned","to_owned","to_owned","to_pubkeyhash","to_public_key","to_string","to_string","to_string","to_string_with_secret","top_level_checks","top_level_type_check","translate_pk","translate_pk","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","ty","type_id","type_id","type_id","type_id","type_id","unsigned_script_sig","vzip","vzip","vzip","vzip","vzip","within_resource_limits","0","0","0","0","0","get_checksum","Base58","Bip32","DuplicatedKeys","Error","HardenedDerivationXpub","Hex","InvalidDescriptorCharacter","InvalidDescriptorChecksum","InvalidHdKeyPath","Key","Miniscript","Pk","Policy","as_fail","borrow","borrow_mut","deref","deref_mut","drop","fmt","fmt","from","from","from","from","from","from","from","from","init","into","to_string","try_from","try_into","type_id","vzip","0","0","0","0","0","0","0","0","AbsoluteTimelock","AddOnLeaf","AddOnPartialComplete","BuildSatisfaction","Complete","Condition","ConditionMap","FoldedConditionMap","Hash160Preimage","Hash256Preimage","IncompatibleConditions","IndexOutOfRange","MixedTimelockUnits","Multisig","None","None","NotEnoughItemsSelected","Partial","PartialComplete","PkOrF","Policy","PolicyError","Psbt","PsbtTimelocks","RelativeTimelock","Ripemd160Preimage","Satisfaction","SatisfiableItem","Sha256Preimage","Signature","SignatureKey","Thresh","as_fail","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","contribution","csv","default","default","deref","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","drop","drop","drop","drop","drop","drop","drop","eq","eq","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","get_condition","get_hash","hash","id","id","init","init","init","init","init","init","init","into","into","into","into","into","into","into","is_leaf","is_leaf","is_null","item","ne","ne","partial_cmp","requires_path","satisfaction","serialize","serialize","serialize","serialize","serialize","timelock","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_string","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","vzip","vzip","0","current_height","input_max_height","psbt","0","0","condition","conditions","conditions","items","items","m","m","n","n","sorted","sorted","0","0","hash","hash","hash","hash","items","keys","threshold","threshold","value","value","0","0","0","0","0","0","0","0","0","1","1","1","1","1","1","2","2","2","Bip44","Bip44Public","Bip49","Bip49Public","Bip84","Bip84Public","DescriptorTemplate","DescriptorTemplateOut","P2Pkh","P2Wpkh","P2Wpkh_P2Sh","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","build","build","build","build","build","build","build","build","build","build","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","drop","drop","drop","drop","drop","drop","drop","drop","drop","from","from","from","from","from","from","from","from","from","init","init","init","init","init","init","init","init","init","into","into","into","into","into","into","into","into","into","into_wallet_descriptor","into_wallet_descriptor","into_wallet_descriptor","into_wallet_descriptor","into_wallet_descriptor","into_wallet_descriptor","into_wallet_descriptor","into_wallet_descriptor","into_wallet_descriptor","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","Bip32","DerivableKey","DescriptorKey","DescriptorPublicKey","DescriptorSecretKey","DescriptorSinglePriv","DescriptorSinglePub","Entropy","Error","ExtScriptContext","ExtendedKey","GeneratableDefaultOptions","GeneratableKey","GeneratedKey","IntoDescriptorKey","InvalidChecksum","InvalidNetwork","InvalidScriptContext","KeyError","KeyMap","Legacy","Message","Miniscript","Options","Private","PrivateKeyGenerateOptions","Public","ScriptContext","ScriptContextEnum","Segwitv0","SinglePriv","SinglePub","SortedMultiVec","ValidNetworks","XPrv","XPub","any_network","as_enum","as_fail","as_public","bip39","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","check_global_consensus_validity","check_global_consensus_validity","check_global_policy_validity","check_global_policy_validity","check_global_validity","check_global_validity","check_local_consensus_validity","check_local_consensus_validity","check_local_policy_validity","check_local_policy_validity","check_local_validity","check_local_validity","check_terminal_non_malleable","check_witness","check_witness","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","cmp","compressed","default","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","derive","derive_public_key","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","encode","eq","eq","eq","eq","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","for_each_key","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_public","from_secret","from_str","from_str","from_tree","full_derivation_path","generate","generate_default","generate_with_entropy","generate_with_entropy_default","get_hash","get_hash","get_hash","has_secret","hash","hash","hash","init","init","init","init","init","init","init","init","init","init","init","into","into","into","into","into","into","into","into","into","into","into","into_descriptor_key","into_descriptor_key","into_descriptor_key","into_descriptor_key","into_descriptor_key","into_descriptor_key","into_descriptor_key","into_extended_key","into_extended_key","into_extended_key","into_key","into_xprv","into_xpub","is_deriveable","is_legacy","is_legacy","is_segwit_v0","is_segwit_v0","is_uncompressed","k","key","key","lift","mainnet_network","master_fingerprint","max_satisfaction_size","max_satisfaction_size","max_satisfaction_witness_elements","merge_networks","ne","ne","ne","new","origin","origin","other_top_level_checks","other_top_level_checks","override_valid_networks","partial_cmp","partial_cmp","partial_cmp","pks","sanity_check","satisfy","script_size","sorted_node","test_networks","to_owned","to_owned","to_owned","to_owned","to_owned","to_pubkeyhash","to_string","to_string","to_string","to_string","top_level_checks","top_level_checks","top_level_type_check","top_level_type_check","translate_pk","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","0","0","0","0","0","0","0","0","0","ChineseSimplified","ChineseTraditional","English","French","Italian","Japanese","Korean","Language","Mnemonic","MnemonicType","MnemonicWithPassphrase","Seed","Spanish","Words12","Words15","Words18","Words21","Words24","as_bytes","as_ref","as_ref","base32_len","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","check_base32","checksum_bits","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","default","default","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","drop","drop","drop","drop","entropy","entropy_bits","eq","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","for_key_size","for_phrase","for_word_count","from","from","from","from","from_entropy","from_language_code","from_phrase","generate_with_entropy","init","init","init","init","into","into","into","into","into_descriptor_key","into_descriptor_key","into_extended_key","into_extended_key","into_phrase","language","new","new","phrase","to_hex","to_hex","to_owned","to_owned","to_owned","to_owned","to_string","to_string","total_bits","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","validate","vzip","vzip","vzip","vzip","word_count","wordlist","wordmap","write_base32","AddressIndex","AddressInfo","IsDust","LastUnused","New","Peek","Reset","Wallet","add_address_validator","add_signer","address","address_validator","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","broadcast","build_fee_bump","build_tx","client","coin_selection","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","drop","drop","drop","eq","export","finalize_psbt","fmt","fmt","fmt","fmt","from","from","from","get_address","get_balance","get_descriptor_for_keychain","get_funded_wallet","get_psbt_input","get_utxo","index","init","init","init","into","into","into","is_dust","is_mine","list_transactions","list_unspent","ne","network","new","new_offline","policies","public_descriptor","secp_ctx","sign","signer","sync","time","to_string","try_from","try_from","try_from","try_into","try_into","try_into","tx_builder","type_id","type_id","type_id","vzip","vzip","vzip","0","0","AddressValidator","AddressValidatorError","ConnectionError","InvalidScript","Message","TimeoutError","UserRejected","as_fail","borrow","borrow_mut","clone","clone_into","deref","deref_mut","drop","eq","fmt","fmt","from","init","into","ne","to_owned","to_string","try_from","try_into","type_id","validate","vzip","0","BranchAndBoundCoinSelection","CoinSelectionAlgorithm","CoinSelectionResult","DefaultCoinSelectionAlgorithm","LargestFirstCoinSelection","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone_into","coin_select","coin_select","coin_select","default","default","deref","deref","deref","deref_mut","deref_mut","deref_mut","drop","drop","drop","fee_amount","fmt","fmt","fmt","from","from","from","init","init","init","into","into","into","local_selected_amount","new","selected","selected_amount","to_owned","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","WalletExport","blockheight","borrow","borrow_mut","change_descriptor","deref","deref_mut","descriptor","deserialize","drop","export_wallet","fmt","from","from_str","init","into","label","serialize","to_string","try_from","try_into","type_id","vzip","0","Dummy","Fingerprint","InputIndexOutOfRange","InvalidKey","InvalidNonWitnessUtxo","MissingHdKeypath","MissingKey","MissingNonWitnessUtxo","MissingWitnessScript","MissingWitnessUtxo","NonStandardSighash","PkHash","SignOptions","Signer","SignerError","SignerId","SignerOrdering","SignersContainer","UserCanceled","add_external","allow_all_sighashes","as_fail","as_key_map","assume_height","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","default","default","default","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","descriptor_secret_key","drop","drop","drop","drop","drop","eq","eq","eq","find","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","get_hash","hash","id","ids","init","init","init","init","init","into","into","into","into","into","ne","ne","new","partial_cmp","partial_cmp","remove","sign","sign_whole_tx","signers","to_owned","to_owned","to_owned","to_owned","to_owned","to_string","trust_witness_utxo","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","0","0","0","get_timestamp","Bip69Lexicographic","BumpFee","ChangeAllowed","ChangeForbidden","ChangeSpendPolicy","CreateTx","OnlyChange","Shuffle","TxBuilder","TxBuilderContext","TxOrdering","Untouched","add_foreign_utxo","add_global_xpubs","add_recipient","add_unspendable","add_utxo","add_utxos","allow_shrinking","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","change_policy","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","coin_selection","default","default","default","default","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","do_not_spend_change","drain_to","drain_wallet","drop","drop","drop","drop","drop","enable_rbf","enable_rbf_with_sequence","eq","eq","fee_absolute","fee_rate","finish","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","get_hash","get_hash","hash","hash","include_output_redeem_witness_script","init","init","init","init","init","into","into","into","into","into","manually_selected_only","nlocktime","only_spend_change","only_witness_utxo","ordering","partial_cmp","partial_cmp","policy_path","set_recipients","sighash","sort_tx","to_owned","to_owned","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","unspendable","version","vzip","vzip","vzip","vzip","vzip"],"q":["bdk","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::Error","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::Utxo","","","bdk::blockchain","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::blockchain::any","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::blockchain::any::AnyBlockchain","","","bdk::blockchain::any::AnyBlockchainConfig","","","bdk::blockchain::compact_filters","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::blockchain::compact_filters::CompactFiltersError","","","","","bdk::blockchain::electrum","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::blockchain::esplora","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::blockchain::esplora::EsploraError","","","","","","","","","","bdk::database","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::database::any","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::database::any::AnyBatch","","","bdk::database::any::AnyDatabase","","","bdk::database::any::AnyDatabaseConfig","","","bdk::database::memory","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::descriptor","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::descriptor::Descriptor","","","","","bdk::descriptor::checksum","bdk::descriptor::error","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::descriptor::error::Error","","","","","","","","bdk::descriptor::policy","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::descriptor::policy::BuildSatisfaction","","","","bdk::descriptor::policy::PolicyError","","bdk::descriptor::policy::Satisfaction","","","","","","","","","","","bdk::descriptor::policy::SatisfiableItem","","","","","","","","","","","","bdk::descriptor::template","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::keys","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::keys::DescriptorPublicKey","","bdk::keys::DescriptorSecretKey","","bdk::keys::ExtendedKey","","bdk::keys::KeyError","","","bdk::keys::bip39","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::wallet","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::wallet::AddressIndex","","bdk::wallet::address_validator","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::wallet::address_validator::AddressValidatorError","bdk::wallet::coin_selection","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::wallet::export","","","","","","","","","","","","","","","","","","","","","","","bdk::wallet::signer","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","bdk::wallet::signer::SignerId","","","bdk::wallet::time","bdk::wallet::tx_builder","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["Error that can be returned to fail the validation of an …","BIP32 error","Branch and bound coin selection tries to avoid needing a …","Branch and bound coin selection possible attempts with …","Descriptor checksum mismatch","Compact filters client error)","Block height and timestamp of the block containing the …","Error related to the parsing and usage of descriptors","Electrum client error","Encoding error","Errors that can be thrown by the Wallet","Esplora client error","External","Fee rate","When bumping a tx the fee rate requested is lower than …","Node doesn’t have data to estimate a fee rate","When bumping a tx the absolute fee requested is lower than …","A UTXO owned by another wallet.","Generic error","Hex decoding error","Wallet’s UTXO set is not enough to cover recipient’s …","Internal, usually used for change outputs","Invalid network","Requested outpoint doesn’t exist in the tx (vout greater …","Error while extracting and manipulating policies","Progress value must be between 0.0 (included) and 100.0 …","Wrong number of bytes found when trying to convert to u32","Trying to replace a tx that has a sequence >= 0xFFFFFFFE","Error serializing or deserializing JSON data","Error while working with keys","Types of keychains","A UTXO owned by the local wallet.","An unspent output owned by a Wallet.","Miniscript error","In order to use the TxBuilder::add_global_xpubs option …","Cannot build a tx without recipients","manually_selected_only option is selected but no utxo has …","Output created is under the dust limit, 546 satoshis","Progress update error (maybe the channel has been closed)","Partially signed bitcoin transaction error","Partially signed bitcoin transaction parseerror","Rusqlite client error","This error is thrown when trying to convert Bare and …","An ECDSA error","Signing error","Sled database error","Spending policy is not compatible with this KeychainKind","Happens when trying to bump a transaction that is already …","A wallet transaction","Thrown when a tx is not found in the internal database","Happens when trying to spend an UTXO that is not in the …","An unspent transaction output (UTXO).","Trait implemented by types that can be used to measure …","A Utxo with its satisfaction_weight.","Return KeychainKind as a byte","","","Return the value as satoshi/vbyte","","Blockchain backends","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","If the transaction is confirmed, contains height and …","Database types","","","","Create a new FeeRate with the default min relay fee value","","","","","","","","","","","","","","","","","Descriptors","Macro to write full descriptors with code","","","","","","","","","","","","","","","","","","","","Fee value (sats) if available. The availability of the fee …","Calculate absolute fee in Satoshis using size in virtual …","Calculate absolute fee in Satoshis using size in weight …","","","","","","","","","","Macro to write descriptor fragments with code","","","","","","","","","","","","","","","","","","","","","","","","","","","Create a new instance of FeeRate given a float fee rate in …","Create a new instance of FeeRate given a float fee rate in …","Calculate fee rate from fee and vbytes.","Calculate fee rate from fee and weight units (wu).","","","","","confirmation block height","","","","","","","","","","","","","","","","","","","","","Type of keychain","Key formats","","","","","","","Returns Some ConfirmationTime if both height and timestamp …","Get the location of the UTXO","Reference to a transaction output","","Received value (sats)","The weight of the witness data and scriptSig expressed in …","Sent value (sats)","","","","","","confirmation block timestamp","","","","","","","","","Optional transaction","","","","","","","","","","","","","","","","","Transaction id","Get the TxOut of the UTXO","Transaction output","","","","","","","","","The UTXO","Convert weight units to virtual bytes.","Whether the tx has been verified against the consensus …","Get the version of BDK at runtime","","","","","","","","","Wallet","","","","","","","","","","","","","","","","","","","","","","","","","","","Sats available for spending","found network, for example the network of the bitcoin node","Sats needed for some transaction","requested network, for example what is given as bdk-cli …","Required fee rate (satoshi/vbyte)","Required fee absolute value (satoshi)","","The location of the output.","The information about the input we require to add it to a …","Can compute accurate fees for the transactions found …","Trait that defines the actions that must be supported by a …","Capabilities that can be supported by a Blockchain backend","Type that contains the configuration","Trait for Blockchain types that can be created given a …","Structure that implements the logic to sync with Esplora","Can recover the full history of a wallet and not only the …","Can fetch any historical transaction given its txid","Type that implements Progress and logs at level INFO every …","Type that implements Progress and drops every update …","Trait for types that can receive and process progress …","Data sent with a progress update over a channel","Runtime-checked blockchain types","","","","","","","Broadcast a transaction","","","","","","","Compact Filters","","","","","","","","","","Electrum","","Esplora","Estimate the fee rate required to confirm a transaction in …","","","","","Create a new instance given a configuration","Return the set of Capability supported by this backend","","Return the current height","Fetch a transaction from the blockchain given its txid","","","","","","","","Create a new instance of LogProgress","Create a new instance of NoopProgress","Shortcut to create a channel (pair of Sender and Receiver) …","Setup the backend and populate the internal database for …","Populate the internal database with transactions and UTXOs","","","","","","","","","","","","","Send a new progress update","","","","","","Type that can contain any of the Blockchain types defined …","Type that can contain any of the blockchain configurations …","Compact filters client","Compact filters client","Electrum client","Electrum client","Esplora client","Esplora client","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Invalid BIP158 filter","Data to connect to a Bitcoin P2P peer","Structure implementing the required blockchain traits","Configuration for a CompactFiltersBlockchain","An error that can occur during sync with a …","The data stored in the block filters storage are corrupted","Internal database error","Wrapper for crate::error::Error","The compact filter returned is invalid","The compact filter headers returned are invalid","The headers returned are invalid","A peer sent an invalid or unexpected response","Internal I/O error","Container for unconfirmed, but valid Bitcoin transactions","The peer is missing a block in the valid chain","No peers have been specified","A peer is not connected","A Bitcoin peer","The peer doesn’t advertise the BLOOM service flag","Internal system time error","A peer took too long to reply to one of our messages","Add a transaction to the mempool","Peer address such as 127.0.0.1:18333","","","","","","","","","","","","","","","","","","","Connect to a peer over a plaintext TCP connection","Connect to a peer through a SOCKS5 proxy, optionally by …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Return the mempool used by this peer","Return the Bitcoin Network in use","Look-up a transaction in the mempool given an Inventory …","","Return the VersionMessage sent by the peer","Return whether or not the mempool contains a transaction …","","","","","","","","","","","","","Return whether or not the peer is still connected","Return the list of transactions contained in the mempool","","","Network used","Create a new empty mempool","Construct a new instance given a list of peers, a path to …","List of peers to try to connect to for asking headers and …","Waits for a specific incoming Bitcoin message, optionally …","Send a raw Bitcoin message to the peer","","","","Optionally skip initial skip_blocks blocks (default: 0)","Optional socks5 proxy","Optional socks5 proxy credentials","Storage dir to save partially downloaded headers and full …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Wrapper over an Electrum Client that implements the …","Configuration for an ElectrumBlockchain","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Request retry count","","","URL of the socks5 proxy server or a Tor service","Stop searching addresses for transactions after finding an …","Request timeout (seconds)","","","","","","","","URL of the Electrum server (such as ElectrumX, Esplora, …","","","Invalid Bitcoin data returned","Structure that implements the logic to sync with Esplora","Configuration for an EsploraBlockchain","Errors that can happen during a sync with EsploraBlockchain","Data type used when fetching transaction history from …","Header hash not found","Header height not found","Invalid Hex data returned","HTTP response error","IO error during ureq response read","No header found in ureq response","Invalid number returned","Transaction not found","Error during ureq HTTP request","Transport error during the ureq HTTP call","","Base URL of the esplora service eg. …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Create a new instance of the client from a base URL and …","Optional URL of the proxy to use to make requests to the …","","","Stop searching addresses for transactions after finding an …","Socket read timeout.","Socket write timeout.","","","","","","","","","","","","","","","","","","","Set the inner ureq agent.","","","","","","","","","","","Container for the operations","Trait for a database that supports batch operations","Trait for operations that can be batched","Type that contains the configuration","Trait for Database types that can be created given a …","Trait for reading data from a database","Sqlite database stored on filesystem","Runtime-checked database types","Create a new batch container","","","","Read and checks the descriptor checksum for a given …","","Consume and apply a batch of operations","","A rusqlite connection object to the sqlite database","Delete the last derivation index for a keychain.","","Delete the data related to a specific script_pubkey, …","","Delete a raw transaction given its Txid","","Delete a script_pubkey given the keychain and its child …","","Delete the metadata of a transaction and optionally the …","","Delete a LocalUtxo given its OutPoint","","","","","Force changes to be written to disk","","","","Create a new instance given a configuration","","Return the last defivation index for a keychain.","","Fetch the keychain and child number of a given …","","Fetch a raw transaction given its Txid","","Fetch a script_pubkey given the child number of a keychain.","","Fetch the transaction metadata and optionally also the raw …","","Fetch a LocalUtxo given its OutPoint","","Increment the last derivation index for a keychain and …","","","","Return the list of raw transactions","","Return the list of script_pubkeys","","Return the list of transactions metadata","","Return the list of LocalUtxos","","In-memory ephemeral database","Instantiate a new SqliteDatabase instance by creating a …","Path on the local filesystem to store the sqlite file","Store the last derivation index for a given keychain.","","Store a raw transaction","","Store a script_pubkey along with its keychain and child …","","Store the metadata of a transaction","","Store a LocalUtxo","","","","","","Type that contains any of the BatchDatabase::Batch types …","Type that can contain any of the Database types defined by …","Type that can contain any of the database configurations …","In-memory ephemeral database","In-memory ephemeral database","Memory database has no config","Simple key-value embedded database based on sled","Simple key-value embedded database based on sled","Simple key-value embedded database based on sled","Configuration type for a sled::Tree database","Sqlite embedded database using rusqlite","Sqlite embedded database using rusqlite","Sqlite embedded database using rusqlite","Configuration type for a sqlite::SqliteDatabase database","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Main directory of the db","Main directory of the db","","","","","","","","","","","","","","Name of the database tree, a separated namespace for the …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","In-memory ephemeral database","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Create a new empty database","","","","","","","","","","A raw scriptpubkey (including pay-to-pubkey) under Legacy …","Alias for a Descriptor that contains extended derived keys","Extended DescriptorPublicKey that has been derived","Script descriptor","Alias for a Descriptor that can contain extended keys …","Trait implemented on Descriptors to add a method to …","Alias for the type of maps that represent derivation paths …","Trait for types which can be converted into an …","Alias type for a map of public key to secret key","Legacy ScriptContext To be used as P2SH scripts For …","Top-level script AST type","Pay-to-PubKey-Hash","The ScriptContext for Miniscript. Additional type …","Segwitv0 ScriptContext","Pay-to-ScriptHash(includes nested wsh/wpkh/sorted multi)","Pay-to-Witness-PubKey-Hash","Pay-to-Witness-ScriptHash with Segwitv0 context","Computes the Bitcoin address of the descriptor, if one …","","","Get a reference to the inner AstElem representing the root …","","","","","","","","","","","Enumerates all child nodes of the current AST node (self) …","Depending on script Context, some of the Terminals might …","","","Depending on script Context, some of the script resource …","","Check the consensus + policy(if not disabled) rules that …","Consensus rules at the Miniscript satisfaction time. It is …","","","Policy rules at the Miniscript satisfaction time. It is …","","","Check the consensus + policy(if not disabled) rules …","Depending on ScriptContext, fragments can be malleable. …","","","Check whether the given satisfaction is valid under the …","","","Descriptor checksum","","","","","","","","","","","","","","","","","","","","","","","","","","","Derives all wildcard keys in the descriptor using the …","Get the DescriptorType of Descriptor","","","","","","","","Encode as a Bitcoin script","","","","","","Descriptor errors","Computes the “witness script” of the descriptor, i.e. …","Additional information helpful for extra analysis.","Extract the spending policy","","","","","","","","","","","","","","","","","","Add type information(Type and Extdata) to Miniscript based …","","","Attempt to parse an insane(scripts don’t clear sanity …","Parse an expression tree into a descriptor","Parse an expression tree into a Miniscript. As a general …","","","","","","Returns Vec with cloned version of all public keys from …","Returns Vec of PkPkh entries, representing either public …","Returns Vec with hashes of all public keys from the …","Returns child node with given index, if any","Returns Option::Some with cloned n’th public key from …","Returns Option::Some with hash of n’th public key or …","Returns Option::Some with hash of n’th public key from …","Returns satisfying witness and scriptSig to spend an …","Whether the miniscript contains a combination of timelocks","Whether the miniscript has repeated Pk or Pkh","","","","","","","","","","","","","","","","","Extracts the AstElem representing the root of the …","Convert to wallet descriptor","Whether or not the descriptor has any wildcards","Whether the miniscript is malleable","","Creates a new Iter iterator that will iterate over all …","Creates a new PkIter iterator that will iterate over all …","Creates a new PkPkhIter iterator that will iterate over …","Creates a new PkhIter iterator that will iterate over all …","","","Lifting corresponds conversion of miniscript into Policy […","Depending on script context, the size of a satifaction …","","","Maximum size, in bytes, of a satisfying witness. For …","Computes an upper bound on the weight of a satisfying …","Maximum number of witness elements used to satisfy the …","","Construct a new derived key","Create a new bare descriptor from witness script Errors …","Create a new pk descriptor","Create a new PkH descriptor","Create a new sh for a given redeem script Errors when …","Create a new sh sortedmulti descriptor with threshold k …","Create a new sh wrapped wpkh from Pk. Errors when …","Create a new sh wrapped wsh descriptor with witness script …","Create a new sh wrapped wsh sortedmulti descriptor from …","Create a new Wpkh descriptor Will return Err if …","Create a new wsh descriptor from witness script Errors …","Create a new wsh sorted multi descriptor Errors when …","A node in the Abstract Syntax Tree(","Other top level checks that are context specific","Attempt to parse a Script into Miniscript representation. …","Parse a descriptor that may contain secret keys","Attempt to parse an insane(scripts don’t clear sanity …","","","","","","Descriptor policy","Whether all spend paths of miniscript require a signature","Whether the descriptor is safe Checks whether all the …","Check whether the underlying Miniscript is safe under the …","Attempt to produce non-malleable satisfying witness for the","Attempt to produce a malleable satisfying witness for the …","Get the scriptCode of a transaction output.","Computes the scriptpubkey of the descriptor","Size, in bytes of the script-pubkey. If this Miniscript is …","","","","Descriptor templates","","","","","","","","","","","Serialize a descriptor to string with its secret keys","Check top level consensus rules.","Check whether the top-level is type B","Convert a descriptor using abstract keys to one using …","This will panic if translatefpk returns an uncompressed …","","","","","","","","","","","The correctness and malleability type information for the …","","","","","","Computes the scriptSig that will be in place for an …","","","","","","Whether the miniscript can exceed the resource …","","","","","","Compute the checksum of a descriptor","Error during base58 decoding","BIP32 error","The descriptor contains multiple keys with the same BIP32 …","Errors related to the parsing and usage of descriptors","The descriptor contains hardened derivation steps on …","Hex decoding error","Invalid character found in the descriptor checksum","The provided descriptor doesn’t match its checksum","Invalid HD Key path, such as having a wildcard but a …","Error thrown while working with keys","Miniscript error","Key-related error","Error while extracting and manipulating policies","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Absolute timeclock timestamp","Can not add to an item that is Satisfaction::None or …","Can not add to an item that is …","Options to build the satisfaction field in the policy","Can satisfy the policy item","An extra condition that must be satisfied but that is out …","Type for a map of sets of Condition items keyed by each set…","Type for a map of folded sets of Condition items keyed by …","SHA256 then RIPEMD160 preimage hash","Double SHA256 preimage hash","Incompatible conditions (not currently used)","Index out of range for an item to satisfy a …","Can not merge CSV or timelock values unless both are less …","Multi-signature public keys with threshold count","Cannot satisfy or contribute to the policy item","Don’t generate satisfaction field","Not enough items are selected to satisfy a …","Only a partial satisfaction of some kind of threshold …","Can reach the threshold of some kind of threshold policy","Raw public key or extended key fingerprint","Descriptor spending policy","Errors that can happen while extracting and manipulating …","Analyze the given PSBT to check for existing signatures","Like Psbt variant and also check for expired timelocks","Relative timelock locktime","RIPEMD160 preimage hash","Represent if and how much a policy item is satisfied by …","An item that needs to be satisfied","SHA256 preimage hash","Signature for a raw public key","Signature for an extended key fingerprint","Threshold items with threshold count","","","","","","","","","","","","","","","","","","","","","","","","","","","","","How the wallet’s descriptor can satisfy this policy node","Optional CheckSequenceVerify condition","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Return the conditions that are set by the spending policy …","","","Returns a unique id for the SatisfiableItem","Identifier for this policy node","","","","","","","","","","","","","","","Returns whether the SatisfiableItem is a leaf item","Returns whether the Satisfaction is a leaf item","Returns true if there are no extra conditions to verify","Type of this policy node","","","","Return whether or not a specific path in the policy tree …","How much a given PSBT already satisfies this policy node …","","","","","","Optional timelock condition","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Current blockchain height","The highest confirmation height between the inputs CSV …","Given PSBT","","","Extra conditions that also need to be satisfied","Extra conditions that also need to be satisfied","Extra conditions that also need to be satisfied","The items that can be satisfied by the descriptor or are …","The items that can be satisfied by the descriptor","Threshold","Threshold","Total number of items","Total number of items","Whether the items are sorted in lexicographic order (used …","Whether the items are sorted in lexicographic order (used …","","","The digest value","The digest value","The digest value","The digest value","The policy items","The raw public key or extended key fingerprint","The required threshold count","The required threshold count","The timestamp value","The locktime value","","","","","","","","","","","","","","","","","","","BIP44 template. Expands to pkh(key/44'/0'/0'/{0,1}/*)","BIP44 public template. Expands to pkh(key/{0,1}/*)","BIP49 template. Expands to sh(wpkh(key/49'/0'/0'/{0,1}/*))","BIP49 public template. Expands to sh(wpkh(key/{0,1}/*))","BIP84 template. Expands to wpkh(key/84'/0'/0'/{0,1}/*)","BIP84 public template. Expands to wpkh(key/{0,1}/*)","Trait for descriptor templates that can be built into a …","Type alias for the return type of DescriptorTemplate, …","P2PKH template. Expands to a descriptor pkh(key)","P2WPKH template. Expands to a descriptor wpkh(key)","P2WPKH-P2SH template. Expands to a descriptor sh(wpkh(key))","","","","","","","","","","","","","","","","","","","Build the complete descriptor","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","BIP32 error","Trait for keys that can be derived.","Container for public or secret keys","The MiniscriptKey corresponding to Descriptors. This can …","A Secret Key that can be either a single key or an Xprv","A Single Descriptor Secret Key with optional origin …","A Single Descriptor Key with optional origin information","Type specifying the amount of entropy required e.g. [u8;32]","Returned error in case of failure","Trait that adds extra useful methods to ScriptContexts","Enum for extended keys that can be either xprv or xpub","Trait that allows generating a key with the default options","Trait for keys that can be generated","Output of a GeneratableKey key generation","Trait for objects that can be turned into a public or …","The key has an invalid checksum","The key is not valid for the given network","The key cannot exist in the given script context","Errors thrown while working with keys","Alias type for a map of public key to secret key","Legacy scripts","Custom error message","Miniscript error","Extra options required by the generate_with_entropy","A private extended key, aka an xprv","Options for generating a PrivateKey","A public extended key, aka an xpub","The ScriptContext for Miniscript. Additional type …","Enum representation of the known valid ScriptContexts","Segwitv0 scripts","Single Secret Key","Single Public Key","Contents of a “sortedmulti” descriptor","Set of valid networks for a key","Xprv","Xpub","Create a set containing mainnet, testnet and regtest","Returns the ScriptContext as a ScriptContextEnum","","Return the public version of this key, by applying either …","BIP-0039","","","","","","","","","","","","","","","","","","","","","","","Depending on script Context, some of the Terminals might …","Depending on script Context, some of the Terminals might …","Depending on script Context, some of the script resource …","Depending on script Context, some of the script resource …","Check the consensus + policy(if not disabled) rules that …","Check the consensus + policy(if not disabled) rules that …","Consensus rules at the Miniscript satisfaction time. It is …","Consensus rules at the Miniscript satisfaction time. It is …","Policy rules at the Miniscript satisfaction time. It is …","Policy rules at the Miniscript satisfaction time. It is …","Check the consensus + policy(if not disabled) rules …","Check the consensus + policy(if not disabled) rules …","Depending on ScriptContext, fragments can be malleable. …","Check whether the given satisfaction is valid under the …","Check whether the given satisfaction is valid under the …","","","","","","","","","","","","","","Whether the generated key should be “compressed” or not","","","","","","","","","","","","","","","","","","","","","","","","","If this public key has a wildcard, replace it by the given …","Computes the public key corresponding to this descriptor …","","","","","","","","","","","","Encode as a Bitcoin script","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Create an instance given a public key and a set of valid …","Create an instance given a secret key and a set of valid …","","","Parse an expression tree into a SortedMultiVec","Full path, from the master key","Generate a key given the options with a random entropy","Generate a key with the default options and a random …","Generate a key given the extra options and the entropy","Generate a key with the default options and a given entropy","","","","Return whether or not the key contains the private data","","","","","","","","","","","","","","","","","","","","","","","","","","Turn the key into a DescriptorKey within the requested …","Consume self and turn it into a DescriptorKey by adding …","","","","","","Consume self and turn it into an ExtendedKey","","","Consumes self and returns the key","Transform the ExtendedKey into an ExtendedPrivKey for the …","Transform the ExtendedKey into an ExtendedPubKey for the …","Whether or not the key has a wildcards","Returns whether the script context is Legacy","Returns whether the script context is …","Returns whether the script context is Segwitv0","Returns whether the script context is …","","signatures required","The key","The key","","Create a set only containing mainnet","The fingerprint of the master key associated with this key","Depending on script context, the size of a satifaction …","Maximum size, in bytes, of a satisfying witness. In …","Maximum number of witness elements used to satisfy the …","Compute the intersection of two sets","","","","Create a new instance of SortedMultiVec given a list of …","Origin information","Origin information","Other top level checks that are context specific","Other top level checks that are context specific","Override the computed set of valid networks","","","","public keys inside sorted Multi","utility function to sanity a sorted multi vec","Attempt to produce a satisfying witness for the witness …","Size, in bytes of the script-pubkey. If this Miniscript is …","Create Terminal::Multi containing sorted pubkeys","Create a set containing testnet and regtest","","","","","","","","","","","Check top level consensus rules.","Check top level consensus rules.","Check whether the top-level is type B","Check whether the top-level is type B","This will panic if translatefpk returns an uncompressed …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","The language determines which words will be used in a …","The primary type in this crate, most tasks require …","Determines the number of words that will be present in a …","Type for a BIP39 mnemonic with an optional passphrase","The secret value used to derive HD wallet addresses from a …","","","","","","","Get the seed value as a byte slice","","","","","","","","","","","","","Return the number of checksum bits","","","","","","","","","","","","","","","","","","","","","","","Get the original entropy value of the mnemonic phrase as a …","Return the number of entropy bits","","","","","","","","","","","","Get a MnemonicType for a mnemonic phrase representing the …","Get a MnemonicType for an existing mnemonic phrase","Get a MnemonicType for a mnemonic phrase with a specific …","","","","","Create a Mnemonic from pre-generated entropy","Construct a word list from its language code. Returns None …","Create a Mnemonic from an existing mnemonic phrase","","","","","","","","","","","","","","Consume the Mnemonic and return the phrase as a String.","Get the Language","Generates a new Mnemonic","Generates the seed from the Mnemonic and the password.","Get the mnemonic phrase as a string reference.","Outputs the hash in hexadecimal form","Outputs the hash in hexadecimal form","","","","","","","Return the number of entropy+checksum bits","","","","","","","","","","","","","Validate a mnemonic phrase","","","","","Return the number of words","Get the word list for this language","Get a WordMap that allows word -> index lookups in the …","","The address index selection strategy to use to derived an …","A derived address and the index it was found at For …","Trait to check if a value is below the dust limit","Return the address for the current descriptor index if it …","Return a new address after incrementing the current …","Return the address for a specific descriptor index. Does …","Return the address for a specific descriptor index and …","A Bitcoin wallet","Add an address validator","Add an external signer","Address","Address validation callbacks","","","","","","","Broadcast a transaction to the network","Bump the fee of a transaction previously created with this …","Start building a transaction.","Return a reference to the internal blockchain client","Coin selection","","","","","","","","","","","","Wallet export","Try to finalize a PSBT","","","","","","","","Return a derived address using the external descriptor, …","Return the balance, meaning the sum of this wallet’s …","Returns the descriptor used to create adddresses for a …","Return a fake wallet that appears to be funded for testing.","get the corresponding PSBT Input for a LocalUtxo","Returns the UTXO owned by this wallet corresponding to …","Child index of this address","","","","","","","Check whether or not a value is below dust limit","Return whether or not a script is part of this wallet …","Return the list of transactions made and received by the …","Return the list of unspent outputs of this wallet","","Get the Bitcoin network the wallet is using.","Create a new “online” wallet","Create a new “offline” wallet","Return the spending policies for the wallet’s descriptor","Return the “public” version of the wallet’s …","Return the secp256k1 context used for all signing …","Sign a transaction with all the wallet’s signers, in the …","Generalized signers","Sync the internal database with the blockchain","Cross-platform time","","","","","","","","Transaction builder","","","","","","","","","Trait to build address validators","Errors that can be returned to fail the validation of an …","Network connection error","Invalid script","A custom error message","Network request timeout error","User rejected the address","","","","","","","","","","","","","","","","","","","","","Validate or inspect an address","","","Branch and bound coin selection","Trait for generalized coin selection algorithms","Result of a successful coin selection","Default coin selection algorithm used by TxBuilder if not …","Simple and dumb coin selection","","","","","","","","","Perform the coin selection","","","","","","","","","","","","","","Total fee amount in satoshi","","","","","","","","","","","","","The total value of the inputs selected from the local …","Create new instance with target size for change output","List of outputs selected for use as inputs","The total value of the inputs selected.","","","","","","","","","","","","","","Structure that contains the export of a wallet","Earliest block to rescan when looking for the wallet’s …","","","Return the internal descriptor, if present","","","Return the external descriptor","","","Export a wallet","","","","","","Arbitrary label for the wallet","","","","","","","","Dummy identifier","The fingerprint of a BIP32 extended key","Input index is out of range","The private key in use has the right fingerprint but …","The non_witness_utxo specified is invalid","The fingerprint and derivation path are missing from the …","The private key is missing for the required public key","The non_witness_utxo field of the transaction is required …","The witness_script field of the transaction is requied to …","The witness_utxo field of the transaction is required to …","The psbt contains a non-SIGHASH_ALL sighash in one of its …","Bitcoin HASH160 (RIPEMD160 after SHA256) hash of an ECDSA …","Options for a software signer","Trait for signers","Signing error","Identifier of a signer in the SignersContainers. Used as a …","Defines the order in which signers are called","Container for multiple signers","The user canceled the operation","Adds an external signer to the container for the specified …","Whether the signer should use the sighash_type set in the …","","Create a map of public keys to secret keys","Whether the wallet should assume a specific height has …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Return the secret key for the signer","","","","","","","","","Finds the signer with lowest ordering for a given id in …","","","","","","","","","","","","","","","","","Return the SignerId for this signer","Returns the list of identifiers of all the signers in the …","","","","","","","","","","","","","Default constructor","","","Removes a signer from the container and returns it","Sign a PSBT","Return whether or not the signer signs the whole …","Returns the list of signers in the container, sorted by …","","","","","","","Whether the signer should trust the witness_utxo, if the …","","","","","","","","","","","","","","","","","","","","","","","","Return the current timestamp in seconds","BIP69 / Lexicographic","Marker type to indicate the TxBuilder is being used to …","Use both change and non-change outputs (default)","Only use non-change outputs (see …","Policy regarding the use of change outputs when creating a …","Marker type to indicate the TxBuilder is being used to …","Only use change outputs (see TxBuilder::only_spend_change)","Randomized (default)","A transaction builder","Context in which the TxBuilder is valid","Ordering of the transaction’s inputs and outputs","Unchanged","Add a foreign UTXO i.e. a UTXO not owned by this wallet.","Fill-in the PSBT_GLOBAL_XPUB field with the extended keys …","Add a recipient to the internal list","Add a utxo to the internal list of unspendable utxos","Add a utxo to the internal list of utxos that must be spent","Add the list of outpoints to the internal list of UTXOs …","Explicitly tells the wallet that it is allowed to reduce …","","","","","","","","","","","Set a specific ChangeSpendPolicy. See …","","","","","","","","","","","","","Choose the coin selection algorithm","","","","","","","","","","","","","","","Do not spend change outputs","Sets the address to drain excess coins to.","Spend all the available inputs. This respects filters like …","","","","","","Enable signaling RBF","Enable signaling RBF with a specific nSequence value","","","Set an absolute fee","Set a custom fee rate","Finish the building the transaction.","","","","","","","","","","","","","","","Fill-in the psbt::Output::redeem_script and …","","","","","","","","","","","Only spend utxos added by add_utxo.","Use a specific nLockTime while creating the transaction","Only spend change outputs","Only Fill-in the psbt::Input::witness_utxo field when …","Choose the ordering for inputs and outputs of the …","","","Set the policy path to use while creating the transaction …","Replace the recipients already added with a new list","Sign with a specific sig hash","Sort transaction inputs and outputs by TxOrdering variant","","","","","","","","","","","","","","","","","","","","","Replace the internal list of unspendable utxos with a new …","Build a transaction with a specific version","","","","",""],"i":[1,1,1,1,1,1,0,1,1,1,0,1,2,0,1,1,1,3,1,1,1,2,1,1,1,1,1,1,1,1,0,3,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,2,1,2,4,2,0,1,2,4,5,6,3,7,8,1,2,4,5,6,3,7,8,2,2,4,5,6,3,7,8,2,4,5,6,3,7,8,7,0,4,7,8,4,1,2,4,5,6,3,7,8,1,2,4,5,6,3,7,8,0,0,2,5,7,8,1,2,4,5,6,3,7,8,2,4,5,6,3,7,8,7,4,4,1,1,2,4,5,6,3,7,8,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,4,5,6,3,7,8,4,4,4,4,2,5,2,5,8,1,2,4,5,6,3,7,8,1,2,4,5,6,3,7,8,9,9,10,11,5,0,4,5,6,3,7,8,8,3,5,4,7,6,7,2,5,7,8,4,8,2,4,5,6,3,7,8,1,7,1,2,4,5,6,3,7,8,1,2,4,5,6,3,7,8,7,3,5,1,2,4,5,6,3,7,8,6,12,7,0,1,2,4,5,6,3,7,8,0,2,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,38,39,40,41,42,43,43,44,0,0,45,0,0,44,44,0,0,0,0,0,44,46,47,44,46,47,48,44,46,47,44,46,47,0,44,46,47,44,46,47,44,46,47,0,44,0,48,44,44,46,47,45,48,44,48,48,44,44,46,47,44,46,47,0,0,0,48,48,44,46,47,44,46,47,44,46,47,44,46,47,49,46,47,44,46,47,0,0,50,51,50,51,50,51,50,51,50,51,50,51,51,50,51,50,51,51,50,51,51,50,51,50,50,50,50,51,51,51,51,50,50,50,50,50,51,50,51,51,51,50,50,51,50,51,50,51,50,51,50,51,52,53,54,55,56,57,58,0,0,0,0,58,58,58,58,58,58,58,58,0,58,58,58,0,58,58,58,59,60,58,59,61,62,60,63,58,59,61,62,60,63,58,62,60,63,60,63,61,61,59,59,61,62,60,63,58,59,61,62,60,63,58,60,63,59,61,62,60,63,58,60,63,62,59,61,62,60,63,58,58,59,61,62,60,63,58,58,58,58,58,58,62,62,62,61,61,59,62,61,59,59,61,62,60,63,58,59,61,62,60,63,58,61,59,60,63,63,59,62,63,61,61,60,63,62,63,60,60,63,60,63,58,59,61,62,60,63,58,59,61,62,60,63,58,59,61,62,60,63,58,59,61,62,60,63,58,64,65,66,67,68,0,0,69,70,69,70,69,70,70,69,70,69,70,70,69,70,70,69,70,69,69,70,69,69,69,69,69,70,69,70,70,70,70,69,70,70,70,70,69,70,69,70,69,70,70,69,70,71,0,0,0,0,71,71,71,71,71,71,71,71,71,71,71,72,73,72,74,71,73,72,74,71,73,72,72,73,72,74,71,73,72,74,71,72,74,73,72,74,71,72,73,73,72,71,71,73,72,74,71,71,71,71,71,71,71,73,73,73,73,73,72,74,71,73,72,74,71,72,73,72,72,73,72,72,72,72,71,73,72,74,71,73,72,74,71,73,72,74,71,73,72,74,71,73,75,76,77,78,79,80,81,82,83,84,85,0,0,86,0,0,0,0,85,87,87,87,88,87,85,87,87,89,87,89,87,89,87,89,87,89,87,89,87,87,87,87,88,87,87,87,86,87,88,87,88,87,88,87,88,87,88,87,88,87,88,87,87,87,88,87,88,87,88,87,88,87,0,87,87,89,87,89,87,89,87,89,87,89,87,87,87,87,87,0,0,0,90,91,92,90,91,92,0,90,91,92,0,91,90,91,93,94,92,90,91,93,94,92,91,91,90,91,90,91,90,91,90,91,90,91,90,91,90,91,93,94,92,90,91,93,94,92,93,94,92,90,91,93,94,92,91,91,93,94,92,90,90,90,90,91,91,91,91,93,94,92,92,92,92,91,91,91,91,91,91,91,91,90,91,93,94,92,90,91,93,94,92,91,91,91,91,93,94,93,94,92,90,91,90,91,90,91,90,91,90,91,93,90,91,93,94,92,90,91,93,94,92,90,91,93,94,92,90,91,93,94,92,95,96,97,98,99,100,101,102,103,0,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,105,0,0,0,0,0,0,0,0,0,0,105,0,0,105,105,105,105,106,107,108,109,105,106,107,108,109,105,106,107,108,108,110,106,107,110,107,110,110,106,107,110,106,107,110,110,106,107,110,106,107,0,109,105,106,107,108,109,105,106,107,108,109,105,106,107,108,109,109,105,106,107,108,109,105,106,107,108,105,105,105,108,109,105,106,107,108,108,109,105,106,107,108,0,105,108,111,105,108,109,109,105,105,106,107,108,108,105,108,109,105,106,107,108,108,105,108,108,105,108,109,105,106,107,108,108,108,108,108,108,108,108,105,108,108,109,105,106,107,108,109,109,105,106,107,108,109,105,106,107,108,108,112,105,108,109,108,108,108,108,105,108,108,110,106,107,108,105,108,105,109,105,105,105,105,105,105,105,105,105,105,105,108,110,108,105,108,109,105,106,107,108,0,108,105,108,108,108,105,105,108,105,108,109,0,109,105,106,107,108,109,109,109,105,108,105,110,110,105,108,109,105,106,107,108,109,105,106,107,108,108,109,105,106,107,108,105,109,105,106,107,108,108,113,114,115,116,117,0,118,118,118,0,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,119,120,121,122,123,124,125,126,127,128,128,0,129,0,0,0,127,127,128,128,128,127,129,130,128,129,129,0,0,0,130,130,127,127,0,0,127,127,127,127,128,131,127,129,132,133,128,130,131,127,129,132,133,128,130,131,127,129,132,133,130,131,127,129,132,133,130,133,132,133,131,133,131,127,129,132,133,128,130,131,127,129,132,133,128,130,131,127,129,132,133,128,130,133,128,131,127,129,132,133,128,128,130,131,127,129,129,132,132,133,128,130,132,133,133,127,132,131,127,129,132,133,128,130,131,127,129,132,133,128,130,127,129,133,132,133,128,133,132,132,131,127,129,132,133,133,131,127,129,132,133,130,128,131,127,129,132,133,128,130,131,127,129,132,133,128,130,131,127,129,132,133,128,130,131,127,129,132,133,128,130,134,135,135,135,136,137,138,139,140,139,140,139,140,139,140,139,140,141,142,143,144,145,146,147,148,148,147,149,150,151,152,153,154,155,156,157,158,159,154,155,156,157,158,159,155,157,159,0,0,0,0,0,0,0,0,0,0,0,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,160,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,151,152,153,154,155,156,157,158,159,161,0,0,0,0,0,0,162,162,0,0,0,0,0,0,161,161,161,0,0,163,161,161,162,164,0,164,0,0,163,165,166,0,0,165,166,0,167,161,165,0,164,168,169,163,170,161,171,166,172,173,165,164,168,169,163,170,161,171,166,172,173,165,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,163,170,171,166,172,163,170,171,166,172,171,166,172,170,170,164,168,168,169,163,170,161,171,166,172,173,165,164,168,169,163,170,161,171,166,172,173,165,166,166,164,168,169,163,170,161,171,166,172,173,165,171,163,171,166,172,169,163,170,161,161,171,171,166,166,172,173,165,165,171,164,164,164,168,169,163,170,161,161,161,171,166,172,173,165,169,169,166,165,171,166,162,174,162,174,171,166,172,164,171,166,172,164,168,169,163,170,161,171,166,172,173,165,164,168,169,163,170,161,171,166,172,173,165,175,176,168,168,169,166,165,176,164,168,168,164,164,166,167,163,167,163,166,171,172,173,171,0,166,110,171,171,0,171,166,172,171,172,173,110,110,169,171,166,172,171,171,171,171,171,0,163,170,171,166,172,166,161,171,166,165,110,110,110,110,171,164,168,169,163,170,161,171,166,172,173,165,164,168,169,163,170,161,171,166,172,173,165,164,168,169,163,170,161,171,166,172,173,165,164,168,169,163,170,161,171,166,172,173,165,177,178,179,180,181,182,183,184,185,186,186,186,186,186,186,186,0,0,0,0,0,186,187,187,187,187,187,188,189,188,188,186,189,187,188,186,189,187,188,188,187,186,189,187,188,186,189,187,188,186,187,186,189,187,188,186,189,187,188,186,189,187,188,189,187,186,186,189,189,189,189,187,187,188,188,188,187,187,187,186,189,187,188,189,186,189,189,186,189,187,188,186,189,187,188,189,188,189,188,189,189,189,188,189,189,188,186,189,187,188,189,187,187,186,189,187,188,186,189,187,188,186,189,187,188,189,186,189,187,188,187,186,186,188,0,0,0,190,190,190,190,0,191,191,192,0,191,190,192,191,190,192,191,191,191,191,0,191,190,192,192,191,190,192,191,190,192,192,0,191,191,190,192,192,191,190,192,191,191,191,0,191,191,192,191,190,192,191,190,192,193,191,191,191,192,191,191,191,191,191,191,191,0,191,0,192,191,190,192,191,190,192,0,191,190,192,191,190,192,194,195,0,0,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,197,196,198,0,0,0,0,0,199,200,201,199,200,201,200,200,202,200,201,200,201,199,200,201,199,200,201,199,200,201,199,199,200,201,199,200,201,199,200,201,199,200,201,199,201,199,199,200,199,200,201,199,200,201,199,200,201,199,200,201,0,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,204,205,205,206,206,206,206,206,206,206,206,206,205,0,0,0,0,0,0,206,207,208,206,207,208,205,206,204,207,208,205,206,204,207,208,205,206,204,207,208,205,206,204,207,208,205,204,204,207,208,205,206,204,207,208,205,206,204,207,208,209,205,206,204,207,208,205,206,204,207,205,206,206,204,207,208,205,205,205,206,204,207,207,208,205,205,209,207,205,206,204,207,208,205,206,204,207,208,205,204,207,205,204,207,209,209,207,205,206,204,207,208,206,208,205,206,204,207,208,205,206,204,207,208,205,206,204,207,208,205,206,204,207,208,210,211,212,0,213,0,214,214,0,0,214,213,0,0,0,213,215,215,215,215,215,215,215,216,217,215,213,214,216,217,215,213,214,215,216,217,215,213,214,216,217,215,213,214,213,214,215,216,217,213,214,216,217,215,213,214,216,217,215,213,214,215,215,215,216,217,215,213,214,215,215,213,214,215,215,215,216,217,215,213,214,216,217,215,213,214,213,214,213,214,215,216,217,215,213,214,216,217,215,213,214,215,215,215,215,215,213,214,215,215,215,213,216,217,215,213,214,216,217,215,213,214,216,217,215,213,214,216,217,215,213,214,215,215,216,217,215,213,214],"f":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[],["u8",15]],[[],["fail",8]],[[]],[[],["f32",15]],[[],["usize",15]],null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],[["result",4,["vec"]],["vec",3,["u5","global"]]]],[[],["keychainkind",4]],[[],["feerate",3]],[[],["localutxo",3]],[[],["weightedutxo",3]],[[],["utxo",4]],[[],["transactiondetails",3]],[[],["confirmationtime",3]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],null,null,[[]],[[],["transactiondetails",3]],[[],["confirmationtime",3]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],null,null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["keychainkind",4]],["bool",15]],[[["feerate",3]],["bool",15]],[[["localutxo",3]],["bool",15]],[[["weightedutxo",3]],["bool",15]],[[["utxo",4]],["bool",15]],[[["transactiondetails",3]],["bool",15]],[[["confirmationtime",3]],["bool",15]],null,[[["usize",15]],["u64",15]],[[["usize",15]],["u64",15]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],null,[[["error",4]]],[[["error",4]]],[[["esploraerror",4]]],[[["compactfilterserror",4]]],[[["signererror",4]]],[[["error",4]]],[[["error",4]]],[[["error",4]]],[[]],[[["error",4]]],[[["psbtparseerror",4]]],[[["keyerror",4]],["error",4]],[[["error",4]]],[[["error",3]]],[[["error",4]]],[[["addressvalidatorerror",4]]],[[["error",4]]],[[["policyerror",4]]],[[["error",4]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["f32",15]]],[[["f32",15]]],[[["u64",15],["usize",15]],["feerate",3]],[[["u64",15],["usize",15]],["feerate",3]],[[],["u64",15]],[[],["u64",15]],[[]],[[]],null,[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["option",4,["keysource"]],["keysource",6],["derivationpath",3]],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[],[["keyerror",4],["extendedkey",4],["result",4,["extendedkey","keyerror"]]]],[[["secp256k1",3],["network",4]],[["result",4,["descriptorerror"]],["descriptorerror",4]]],[[["secp256k1",3],["network",4]],[["result",4,["descriptorerror"]],["descriptorerror",4]]],null,null,[[["feerate",3]],["bool",15]],[[["localutxo",3]],["bool",15]],[[["weightedutxo",3]],["bool",15]],[[["utxo",4]],["bool",15]],[[["transactiondetails",3]],["bool",15]],[[["confirmationtime",3]],["bool",15]],[[["u64",15],["u32",15],["option",4,["u64"]],["option",4,["u32"]]],["option",4]],[[],["outpoint",3]],null,[[["feerate",3]],[["option",4,["ordering"]],["ordering",4]]],null,null,null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[["feerate",3]]],null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["string",3]],null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],null,[[],["txout",3]],null,[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],null,[[],["usize",15]],null,[[],["str",15]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],null,[[],["result",4]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[],["capability",4]],[[],["noopprogress",3]],[[],["logprogress",3]],[[]],[[]],[[]],null,[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],null,[[["capability",4]],["bool",15]],null,[[["usize",15]],[["result",4,["feerate","error"]],["feerate",3],["error",4]]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[],[["result",4,["error"]],["error",4]]],[[],[["hashset",3,["capability"]],["capability",4]]],[[],["u64",15]],[[],[["result",4,["u32","error"]],["error",4],["u32",15]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[],["logprogress",3]],[[],["noopprogress",3]],[[]],[[["progress",8]],[["error",4],["result",4,["error"]]]],[[["progress",8]],[["error",4],["result",4,["error"]]]],[[]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[["f32",15],["option",4,["string"]],["string",3]],[["error",4],["result",4,["error"]]]],[[["f32",15],["option",4,["string"]],["string",3]],[["error",4],["result",4,["error"]]]],[[["f32",15],["option",4,["string"]],["string",3]],[["error",4],["result",4,["error"]]]],[[]],[[]],[[]],null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[],["anyblockchainconfig",4]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],["result",4]],[[["usize",15]]],[[["usize",15]]],[[["anyblockchainconfig",4]],["bool",15]],[[["usize",15]],[["result",4,["feerate","error"]],["feerate",3],["error",4]]],[[["formatter",3]],["result",6]],[[]],[[["electrumblockchain",3]]],[[["compactfiltersblockchain",3]]],[[["esplorablockchain",3]]],[[["electrumblockchainconfig",3]]],[[]],[[["compactfiltersblockchainconfig",3]]],[[["esplorablockchainconfig",3]]],[[],[["result",4,["error"]],["error",4]]],[[],[["hashset",3,["capability"]],["capability",4]]],[[],[["result",4,["u32","error"]],["error",4],["u32",15]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[["anyblockchainconfig",4]],["bool",15]],[[],["result",4]],[[["progress",8]],[["error",4],["result",4,["error"]]]],[[["progress",8]],[["error",4],["result",4,["error"]]]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[["transaction",3]]],null,[[],["fail",8]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[],["bitcoinpeerconfig",3]],[[],["compactfiltersblockchainconfig",3]],[[]],[[]],[[["network",4],["arc",3,["mempool"]],["tosocketaddrs",8],["mempool",3]],[["result",4,["compactfilterserror"]],["compactfilterserror",4]]],[[["option",4],["tosocketaddrs",8],["arc",3,["mempool"]],["network",4],["totargetaddr",8],["mempool",3]],[["result",4,["compactfilterserror"]],["compactfilterserror",4]]],[[],["mempool",3]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],["result",4]],[[],["result",4]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["bitcoinpeerconfig",3]],["bool",15]],[[["compactfiltersblockchainconfig",3]],["bool",15]],[[["usize",15]],[["result",4,["feerate","error"]],["feerate",3],["error",4]]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[]],[[]],[[["error",3]]],[[]],[[["error",4]]],[[["systemtimeerror",3]]],[[["error",4]]],[[["error",3]]],[[],[["result",4,["error"]],["error",4]]],[[],[["hashset",3,["capability"]],["capability",4]]],[[],[["result",4,["u32","error"]],["error",4],["u32",15]]],[[],[["mempool",3],["arc",3,["mempool"]]]],[[],["network",4]],[[["inventory",4]],[["option",4,["transaction"]],["transaction",3]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[],["versionmessage",3]],[[["txid",3]],["bool",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["bool",15]],[[],[["vec",3,["transaction"]],["transaction",3]]],[[["bitcoinpeerconfig",3]],["bool",15]],[[["compactfiltersblockchainconfig",3]],["bool",15]],null,[[]],[[["usize",15],["path",3],["peer",3],["asref",8,["path"]],["vec",3,["peer"]],["option",4,["usize"]]],[["result",4,["compactfilterserror"]],["compactfilterserror",4]]],null,[[["option",4,["duration"]],["str",15],["duration",3]],[["option",4,["networkmessage"]],["result",4,["option","compactfilterserror"]],["compactfilterserror",4]]],[[["networkmessage",4]],[["result",4,["compactfilterserror"]],["compactfilterserror",4]]],[[],["result",4]],[[],["result",4]],[[["progress",8]],[["error",4],["result",4,["error"]]]],null,null,null,null,[[]],[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],[[]],[[]],[[]],[[]],null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[],["electrumblockchainconfig",3]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],["result",4]],[[["usize",15]]],[[["usize",15]]],[[["electrumblockchainconfig",3]],["bool",15]],[[["usize",15]],[["result",4,["feerate","error"]],["feerate",3],["error",4]]],[[["formatter",3]],["result",6]],[[]],[[["client",3]]],[[]],[[],[["result",4,["error"]],["error",4]]],[[],[["hashset",3,["capability"]],["capability",4]]],[[],[["result",4,["u32","error"]],["error",4],["u32",15]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[["electrumblockchainconfig",3]],["bool",15]],null,[[],["result",4]],[[["progress",8]],[["error",4],["result",4,["error"]]]],null,null,null,[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],null,[[]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[],["fail",8]],null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[],["esplorablockchainconfig",3]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],["result",4]],[[],["result",4]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["esplorablockchainconfig",3]],["bool",15]],[[["usize",15]],[["result",4,["feerate","error"]],["feerate",3],["error",4]]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[["error",4]]],[[["error",4]]],[[["error",4]]],[[["parseinterror",3]]],[[["error",3]]],[[["transport",3]]],[[]],[[],[["result",4,["error"]],["error",4]]],[[],[["hashset",3,["capability"]],["capability",4]]],[[],[["result",4,["u32","error"]],["error",4],["u32",15]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[["esplorablockchainconfig",3]],["bool",15]],[[["str",15],["usize",15]]],null,[[],["result",4]],[[["progress",8]],[["error",4],["result",4,["error"]]]],null,null,null,[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],[[]],[[]],[[["agent",3]]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[["keychainkind",4],["asref",8]],[["error",4],["result",4,["error"]]]],[[["keychainkind",4],["asref",8]],[["error",4],["result",4,["error"]]]],[[],[["error",4],["result",4,["error"]]]],[[],[["error",4],["result",4,["error"]]]],null,[[["keychainkind",4]],[["error",4],["result",4,["option","error"]],["option",4,["u32"]]]],[[["keychainkind",4]],[["error",4],["result",4,["option","error"]],["option",4,["u32"]]]],[[["script",3]],[["result",4,["option","error"]],["option",4],["error",4]]],[[["script",3]],[["result",4,["option","error"]],["option",4],["error",4]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["option","error"]],["option",4,["script"]]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["option","error"]],["option",4,["script"]]]],[[["bool",15],["txid",3]],[["result",4,["option","error"]],["option",4,["transactiondetails"]],["error",4]]],[[["bool",15],["txid",3]],[["result",4,["option","error"]],["option",4,["transactiondetails"]],["error",4]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],[["error",4],["result",4,["error"]]]],[[],[["error",4],["result",4,["error"]]]],[[["formatter",3]],["result",6]],[[]],[[],[["result",4,["error"]],["error",4]]],[[],[["result",4,["error"]],["error",4]]],[[["keychainkind",4]],[["error",4],["result",4,["option","error"]],["option",4,["u32"]]]],[[["keychainkind",4]],[["error",4],["result",4,["option","error"]],["option",4,["u32"]]]],[[["script",3]],[["result",4,["option","error"]],["option",4],["error",4]]],[[["script",3]],[["result",4,["option","error"]],["option",4],["error",4]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["option","error"]],["option",4,["script"]]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["option","error"]],["option",4,["script"]]]],[[["bool",15],["txid",3]],[["result",4,["option","error"]],["option",4,["transactiondetails"]],["error",4]]],[[["bool",15],["txid",3]],[["result",4,["option","error"]],["option",4,["transactiondetails"]],["error",4]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],[[["keychainkind",4]],[["result",4,["u32","error"]],["error",4],["u32",15]]],[[["keychainkind",4]],[["result",4,["u32","error"]],["error",4],["u32",15]]],[[],["usize",15]],[[]],[[],[["vec",3,["transaction"]],["error",4],["result",4,["vec","error"]]]],[[],[["vec",3,["transaction"]],["error",4],["result",4,["vec","error"]]]],[[["keychainkind",4],["option",4,["keychainkind"]]],[["result",4,["vec","error"]],["error",4],["vec",3,["script"]]]],[[["keychainkind",4],["option",4,["keychainkind"]]],[["result",4,["vec","error"]],["error",4],["vec",3,["script"]]]],[[["bool",15]],[["result",4,["vec","error"]],["error",4],["vec",3,["transactiondetails"]]]],[[["bool",15]],[["result",4,["vec","error"]],["error",4],["vec",3,["transactiondetails"]]]],[[],[["result",4,["vec","error"]],["vec",3,["localutxo"]],["error",4]]],[[],[["result",4,["vec","error"]],["vec",3,["localutxo"]],["error",4]]],null,[[["string",3]]],null,[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["error"]]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["error"]]]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[["keychainkind",4],["u32",15],["script",3]],[["error",4],["result",4,["error"]]]],[[["keychainkind",4],["u32",15],["script",3]],[["error",4],["result",4,["error"]]]],[[["transactiondetails",3]],[["error",4],["result",4,["error"]]]],[[["transactiondetails",3]],[["error",4],["result",4,["error"]]]],[[["localutxo",3]],[["error",4],["result",4,["error"]]]],[[["localutxo",3]],[["error",4],["result",4,["error"]]]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["keychainkind",4],["asref",8]],[["error",4],["result",4,["error"]]]],[[],[["error",4],["result",4,["error"]]]],[[["keychainkind",4]],[["error",4],["result",4,["option","error"]],["option",4,["u32"]]]],[[["keychainkind",4]],[["error",4],["result",4,["option","error"]],["option",4,["u32"]]]],[[["script",3]],[["result",4,["option","error"]],["option",4],["error",4]]],[[["script",3]],[["result",4,["option","error"]],["option",4],["error",4]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["option","error"]],["option",4,["script"]]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["option","error"]],["option",4,["script"]]]],[[["bool",15],["txid",3]],[["result",4,["option","error"]],["option",4,["transactiondetails"]],["error",4]]],[[["bool",15],["txid",3]],[["result",4,["option","error"]],["option",4,["transactiondetails"]],["error",4]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],[["error",4],["result",4,["error"]]]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[]],[[["memorydatabase",3]]],[[["sqlitedatabase",3]]],[[]],[[["tree",3]]],[[]],[[]],[[["sqlitedbconfiguration",3]]],[[]],[[]],[[["sleddbconfiguration",3]]],[[],[["result",4,["error"]],["error",4]]],[[["keychainkind",4]],[["error",4],["result",4,["option","error"]],["option",4,["u32"]]]],[[["script",3]],[["result",4,["option","error"]],["option",4],["error",4]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["option","error"]],["option",4,["script"]]]],[[["bool",15],["txid",3]],[["result",4,["option","error"]],["option",4,["transactiondetails"]],["error",4]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],[[["keychainkind",4]],[["result",4,["u32","error"]],["error",4],["u32",15]]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[],[["vec",3,["transaction"]],["error",4],["result",4,["vec","error"]]]],[[["keychainkind",4],["option",4,["keychainkind"]]],[["result",4,["vec","error"]],["error",4],["vec",3,["script"]]]],[[["bool",15]],[["result",4,["vec","error"]],["error",4],["vec",3,["transactiondetails"]]]],[[],[["result",4,["vec","error"]],["vec",3,["localutxo"]],["error",4]]],null,null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["error"]]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["error"]]]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[["keychainkind",4],["u32",15],["script",3]],[["error",4],["result",4,["error"]]]],[[["keychainkind",4],["u32",15],["script",3]],[["error",4],["result",4,["error"]]]],[[["transactiondetails",3]],[["error",4],["result",4,["error"]]]],[[["transactiondetails",3]],[["error",4],["result",4,["error"]]]],[[["localutxo",3]],[["error",4],["result",4,["error"]]]],[[["localutxo",3]],[["error",4],["result",4,["error"]]]],null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],[[]],[[]],[[]],null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[["keychainkind",4],["asref",8]],[["error",4],["result",4,["error"]]]],[[],[["error",4],["result",4,["error"]]]],[[],["memorydatabase",3]],[[["keychainkind",4]],[["error",4],["result",4,["option","error"]],["option",4,["u32"]]]],[[["script",3]],[["result",4,["option","error"]],["option",4],["error",4]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["option","error"]],["option",4,["script"]]]],[[["bool",15],["txid",3]],[["result",4,["option","error"]],["option",4,["transactiondetails"]],["error",4]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],[["error",4],["result",4,["error"]]]],[[["formatter",3]],["result",6]],[[]],[[],[["result",4,["error"]],["error",4]]],[[["keychainkind",4]],[["error",4],["result",4,["option","error"]],["option",4,["u32"]]]],[[["script",3]],[["result",4,["option","error"]],["option",4],["error",4]]],[[["txid",3]],[["option",4,["transaction"]],["result",4,["option","error"]],["error",4]]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["option","error"]],["option",4,["script"]]]],[[["bool",15],["txid",3]],[["result",4,["option","error"]],["option",4,["transactiondetails"]],["error",4]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],[[["keychainkind",4]],[["result",4,["u32","error"]],["error",4],["u32",15]]],[[],["usize",15]],[[]],[[],[["vec",3,["transaction"]],["error",4],["result",4,["vec","error"]]]],[[["keychainkind",4],["option",4,["keychainkind"]]],[["result",4,["vec","error"]],["error",4],["vec",3,["script"]]]],[[["bool",15]],[["result",4,["vec","error"]],["error",4],["vec",3,["transactiondetails"]]]],[[],[["result",4,["vec","error"]],["vec",3,["localutxo"]],["error",4]]],[[]],[[["keychainkind",4],["u32",15]],[["error",4],["result",4,["error"]]]],[[["transaction",3]],[["error",4],["result",4,["error"]]]],[[["keychainkind",4],["u32",15],["script",3]],[["error",4],["result",4,["error"]]]],[[["transactiondetails",3]],[["error",4],["result",4,["error"]]]],[[["localutxo",3]],[["error",4],["result",4,["error"]]]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[["network",4]],[["result",4,["address","error"]],["address",3],["error",4]]],[[],["scriptcontextenum",4]],[[],["scriptcontextenum",4]],[[],["terminal",4]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],[["vec",3,["miniscript","global"]],["global",3],["miniscript",3]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["terminal",4]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["terminal",4]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["terminal",4]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],null,[[],["deriveddescriptorkey",3]],[[],["descriptor",4]],[[],["legacy",4]],[[],["segwitv0",4]],[[],["miniscript",3]],[[]],[[]],[[]],[[]],[[]],[[],["ordering",4]],[[["descriptor",4]],["ordering",4]],[[["legacy",4]],["ordering",4]],[[["segwitv0",4]],["ordering",4]],[[["miniscript",3]],["ordering",4]],[[["usize",15]]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["u32",15]],[["descriptor",4,["descriptorpublickey"]],["descriptorpublickey",4]]],[[],["descriptortype",4]],[[],[["result",4,["descriptor"]],["descriptor",4]]],[[],[["result",4,["miniscript"]],["miniscript",3]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],["script",3]],[[],["bool",15]],[[["descriptor",4]],["bool",15]],[[["legacy",4]],["bool",15]],[[["segwitv0",4]],["bool",15]],[[["miniscript",3]],["bool",15]],null,[[],["script",3]],null,[[["secp256k1",3],["buildsatisfaction",4],["signerscontainer",3]],[["result",4,["option","descriptorerror"]],["option",4,["policy"]],["descriptorerror",4]]],[[["secp256k1",3],["buildsatisfaction",4],["signerscontainer",3]],[["error",4],["result",4,["option","error"]],["option",4,["policy"]]]],[[["secp256k1",3],["buildsatisfaction",4],["signerscontainer",3]],[["error",4],["result",4,["option","error"]],["option",4,["policy"]]]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[],["bool",15]],[[],["bool",15]],[[]],[[]],[[]],[[]],[[]],[[["terminal",4]],[["result",4,["miniscript","error"]],["miniscript",3],["error",4]]],[[["str",15]],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[["str",15]],[["result",4,["miniscript","error"]],["miniscript",3],["error",4]]],[[["str",15]],[["result",4,["miniscript","error"]],["miniscript",3],["error",4]]],[[["tree",3]],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[["tree",3]],[["result",4,["miniscript","error"]],["miniscript",3],["error",4]]],[[],["u64",15]],[[],["u64",15]],[[],["u64",15]],[[],["u64",15]],[[],["u64",15]],[[],[["vec",3,["global"]],["global",3]]],[[],[["global",3],["pkpkh",4],["vec",3,["pkpkh","global"]]]],[[],[["vec",3,["global"]],["global",3]]],[[["usize",15]],[["option",4,["miniscript"]],["miniscript",3]]],[[["usize",15]],["option",4]],[[["usize",15]],[["pkpkh",4],["option",4,["pkpkh"]]]],[[["usize",15]],["option",4]],[[],[["error",4],["result",4,["error"]]]],[[],["bool",15]],[[],["bool",15]],[[]],[[]],[[]],[[]],[[]],[[],["hash",3]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[],["terminal",4]],[[["secp256k1",3],["network",4]],[["result",4,["descriptorerror"]],["descriptorerror",4]]],[[],["bool",15]],[[],["bool",15]],[[],["bool",15]],[[],["iter",3]],[[],["pkiter",3]],[[],["pkpkhiter",3]],[[],["pkhiter",3]],[[],[["result",4,["policy","error"]],["policy",4],["error",4]]],[[],[["result",4,["policy","error"]],["policy",4],["error",4]]],[[],[["result",4,["lifterror"]],["lifterror",4]]],[[["miniscript",3]],[["usize",15],["option",4,["usize"]]]],[[["miniscript",3]],[["usize",15],["option",4,["usize"]]]],[[["miniscript",3]],[["usize",15],["option",4,["usize"]]]],[[],[["usize",15],["result",4,["usize","error"]],["error",4]]],[[],[["usize",15],["result",4,["usize","error"]],["error",4]]],[[],[["usize",15],["result",4,["usize","error"]],["error",4]]],[[["descriptor",4]],["bool",15]],[[["descriptorpublickey",4],["secp256k1",3]],["deriveddescriptorkey",3]],[[["barectx",4],["miniscript",3,["barectx"]]],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[],["descriptor",4]],[[],["descriptor",4]],[[["miniscript",3,["legacy"]],["legacy",4]],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[["usize",15],["vec",3,["global"]],["global",3]],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[["segwitv0",4],["miniscript",3,["segwitv0"]]],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[["usize",15],["vec",3,["global"]],["global",3]],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[["segwitv0",4],["miniscript",3,["segwitv0"]]],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],[[["usize",15],["vec",3,["global"]],["global",3]],[["descriptor",4],["result",4,["descriptor","error"]],["error",4]]],null,[[["miniscript",3]],[["result",4,["error"]],["error",4]]],[[["script",3]],[["error",4],["miniscript",3,["publickey"]],["result",4,["miniscript","error"]]]],[[["secp256k1",3],["str",15]],[["result",4,["error"]],["error",4]]],[[["script",3]],[["error",4],["miniscript",3,["publickey"]],["result",4,["miniscript","error"]]]],[[],[["option",4,["ordering"]],["ordering",4]]],[[["descriptor",4]],[["option",4,["ordering"]],["ordering",4]]],[[["legacy",4]],[["option",4,["ordering"]],["ordering",4]]],[[["segwitv0",4]],[["option",4,["ordering"]],["ordering",4]]],[[["miniscript",3]],[["option",4,["ordering"]],["ordering",4]]],null,[[],["bool",15]],[[],[["result",4,["error"]],["error",4]]],[[],[["result",4,["analysiserror"]],["analysiserror",4]]],[[],[["result",4,["vec","error"]],["vec",3,["vec","global"]],["error",4]]],[[],[["result",4,["vec","error"]],["vec",3,["vec","global"]],["error",4]]],[[],["script",3]],[[],["script",3]],[[],["usize",15]],[[],["result",4]],[[],["result",4]],[[],["usize",15]],null,[[]],[[]],[[]],[[]],[[]],[[]],[[],["publickey",3]],[[],["string",3]],[[],["string",3]],[[],["string",3]],[[["hashmap",3]],["string",3]],[[["miniscript",3]],[["result",4,["error"]],["error",4]]],[[["miniscript",3]],[["result",4,["error"]],["error",4]]],[[],[["result",4,["descriptor"]],["descriptor",4]]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],null,[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["script",3]],[[]],[[]],[[]],[[]],[[]],[[],["bool",15]],null,null,null,null,null,[[["str",15]],[["result",4,["string","descriptorerror"]],["string",3],["descriptorerror",4]]],null,null,null,null,null,null,null,null,null,null,null,null,null,[[],["fail",8]],[[]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["error",4]]],[[["policyerror",4]]],[[]],[[["error",4]]],[[["error",4]]],[[["error",4]]],[[["keyerror",4]],["error",4]],[[["error",4]]],[[],["usize",15]],[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[],["fail",8]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["pkorf",3]],[[],["satisfiableitem",4]],[[],["satisfaction",4]],[[],["policy",3]],[[],["condition",3]],[[],["buildsatisfaction",4]],[[]],[[]],[[]],[[]],[[]],[[]],[[["condition",3]],["ordering",4]],null,null,[[],["pkorf",3]],[[],["condition",3]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["condition",3]],["bool",15]],[[["policyerror",4]],["bool",15]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[["bool",15]]],[[]],[[["satisfiableitem",4]]],[[]],[[]],[[]],[[]],[[["btreemap",3]],[["policyerror",4],["condition",3],["result",4,["condition","policyerror"]]]],[[],["u64",15]],[[]],[[],["string",3]],null,[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["bool",15]],[[],["bool",15]],[[],["bool",15]],null,[[["condition",3]],["bool",15]],[[["policyerror",4]],["bool",15]],[[["condition",3]],[["option",4,["ordering"]],["ordering",4]]],[[],["bool",15]],null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],null,[[]],[[]],[[]],[[]],[[]],[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[],[["result",4,["descriptortemplateout","descriptorerror"]],["descriptortemplateout",6],["descriptorerror",4]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["secp256k1",3],["network",4]],[["error",4],["result",4,["error"]]]],[[["secp256k1",3],["network",4]],[["error",4],["result",4,["error"]]]],[[["secp256k1",3],["network",4]],[["error",4],["result",4,["error"]]]],[[["secp256k1",3],["network",4]],[["error",4],["result",4,["error"]]]],[[["secp256k1",3],["network",4]],[["error",4],["result",4,["error"]]]],[[["secp256k1",3],["network",4]],[["error",4],["result",4,["error"]]]],[[["secp256k1",3],["network",4]],[["error",4],["result",4,["error"]]]],[[["secp256k1",3],["network",4]],[["error",4],["result",4,["error"]]]],[[["secp256k1",3],["network",4]],[["error",4],["result",4,["error"]]]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[],["validnetworks",6]],[[],["scriptcontextenum",4]],[[],["fail",8]],[[["secp256k1",3]],[["result",4,["descriptorpublickey","descriptorkeyparseerror"]],["descriptorpublickey",4],["descriptorkeyparseerror",3]]],null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["miniscript",3]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[["terminal",4]],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[],[["result",4,["scriptcontexterror"]],["scriptcontexterror",4]]],[[],["scriptcontextenum",4]],[[],["privatekeygenerateoptions",3]],[[],["sortedmultivec",3]],[[],["descriptorpublickey",4]],[[],["descriptorsinglepub",3]],[[]],[[]],[[]],[[]],[[]],[[["sortedmultivec",3]],["ordering",4]],[[["descriptorpublickey",4]],["ordering",4]],[[["descriptorsinglepub",3]],["ordering",4]],null,[[]],[[["usize",15]]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["u32",15]],["descriptorpublickey",4]],[[["secp256k1",3]],[["conversionerror",4],["publickey",3],["result",4,["publickey","conversionerror"]]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],["script",3]],[[["scriptcontextenum",4]],["bool",15]],[[["sortedmultivec",3]],["bool",15]],[[["descriptorpublickey",4]],["bool",15]],[[["descriptorsinglepub",3]],["bool",15]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[],["bool",15]],[[["extendedpubkey",3]]],[[]],[[["extendedprivkey",3]]],[[]],[[]],[[]],[[]],[[["error",4]]],[[["error",4]]],[[]],[[]],[[]],[[]],[[]],[[]],[[["descriptorpublickey",4],["validnetworks",6]]],[[["descriptorsecretkey",4],["validnetworks",6]]],[[["str",15]],[["result",4,["descriptorpublickey"]],["descriptorpublickey",4]]],[[["str",15]],[["descriptorsecretkey",4],["result",4,["descriptorsecretkey"]]]],[[["tree",3]],[["sortedmultivec",3],["error",4],["result",4,["sortedmultivec","error"]]]],[[],["derivationpath",3]],[[],[["result",4,["generatedkey"]],["generatedkey",3]]],[[],[["result",4,["generatedkey"]],["generatedkey",3]]],[[],[["result",4,["generatedkey"]],["generatedkey",3]]],[[],[["result",4,["generatedkey"]],["generatedkey",3]]],[[],["u64",15]],[[],["u64",15]],[[],["u64",15]],[[],["bool",15]],[[]],[[]],[[]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[["option",4,["keysource"]],["keysource",6],["derivationpath",3]],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[["option",4,["keysource"]],["keysource",6],["derivationpath",3]],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[],[["keyerror",4],["extendedkey",4],["result",4,["extendedkey","keyerror"]]]],[[],[["keyerror",4],["extendedkey",4],["result",4,["extendedkey","keyerror"]]]],[[],[["keyerror",4],["extendedkey",4],["result",4,["extendedkey","keyerror"]]]],[[]],[[["network",4]],[["extendedprivkey",3],["option",4,["extendedprivkey"]]]],[[["secp256k1",3],["network",4]],["extendedpubkey",3]],[[],["bool",15]],[[],["bool",15]],[[],["bool",15]],[[],["bool",15]],[[],["bool",15]],[[],["bool",15]],null,null,null,[[],[["result",4,["policy","error"]],["policy",4],["error",4]]],[[],["validnetworks",6]],[[],["fingerprint",3]],[[["miniscript",3]],[["usize",15],["option",4,["usize"]]]],[[],["usize",15]],[[],["usize",15]],[[["validnetworks",6]],["validnetworks",6]],[[["sortedmultivec",3]],["bool",15]],[[["descriptorpublickey",4]],["bool",15]],[[["descriptorsinglepub",3]],["bool",15]],[[["usize",15],["vec",3,["global"]],["global",3]],[["sortedmultivec",3],["error",4],["result",4,["sortedmultivec","error"]]]],null,null,[[["miniscript",3]],[["result",4,["error"]],["error",4]]],[[["miniscript",3]],[["result",4,["error"]],["error",4]]],[[["validnetworks",6]]],[[["sortedmultivec",3]],[["option",4,["ordering"]],["ordering",4]]],[[["descriptorpublickey",4]],[["option",4,["ordering"]],["ordering",4]]],[[["descriptorsinglepub",3]],[["option",4,["ordering"]],["ordering",4]]],null,[[],[["result",4,["error"]],["error",4]]],[[],[["result",4,["vec","error"]],["vec",3,["vec","global"]],["error",4]]],[[],["usize",15]],[[],["terminal",4]],[[],["validnetworks",6]],[[]],[[]],[[]],[[]],[[]],[[],["descriptorpublickey",4]],[[],["string",3]],[[],["string",3]],[[],["string",3]],[[],["string",3]],[[["miniscript",3]],[["result",4,["error"]],["error",4]]],[[["miniscript",3]],[["result",4,["error"]],["error",4]]],[[["miniscript",3]],[["result",4,["error"]],["error",4]]],[[["miniscript",3]],[["result",4,["error"]],["error",4]]],[[],[["result",4,["sortedmultivec"]],["sortedmultivec",3]]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[],["str",15]],[[]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],[["result",4,["vec"]],["vec",3,["u5","global"]]]],[[],["u8",15]],[[],["language",4]],[[],["mnemonic",3]],[[],["mnemonictype",4]],[[],["seed",3]],[[]],[[]],[[]],[[]],[[],["language",4]],[[],["mnemonictype",4]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[]],[[],["usize",15]],[[["language",4]],["bool",15]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["formatter",3]],[["error",3],["result",4,["error"]]]],[[["usize",15]],[["result",4,["mnemonictype","error"]],["mnemonictype",4],["error",3]]],[[["str",15]],[["result",4,["mnemonictype","error"]],["mnemonictype",4],["error",3]]],[[["usize",15]],[["result",4,["mnemonictype","error"]],["mnemonictype",4],["error",3]]],[[]],[[]],[[]],[[]],[[["language",4]],[["result",4,["mnemonic","error"]],["error",3],["mnemonic",3]]],[[["str",15]],[["option",4,["language"]],["language",4]]],[[["str",15],["language",4]],[["result",4,["mnemonic","error"]],["error",3],["mnemonic",3]]],[[],[["result",4,["generatedkey"]],["generatedkey",3]]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[["option",4,["keysource"]],["keysource",6],["derivationpath",3]],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[["option",4,["keysource"]],["keysource",6],["derivationpath",3]],[["descriptorkey",4],["keyerror",4],["result",4,["descriptorkey","keyerror"]]]],[[],[["keyerror",4],["extendedkey",4],["result",4,["extendedkey","keyerror"]]]],[[],[["keyerror",4],["extendedkey",4],["result",4,["extendedkey","keyerror"]]]],[[],["string",3]],[[],["language",4]],[[["mnemonictype",4],["language",4]],["mnemonic",3]],[[["str",15],["mnemonic",3]],["seed",3]],[[],["str",15]],[[],["string",3]],[[],["string",3]],[[]],[[]],[[]],[[]],[[],["string",3]],[[],["string",3]],[[],["usize",15]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[["str",15],["language",4]],[["result",4,["error"]],["error",3]]],[[]],[[]],[[]],[[]],[[],["usize",15]],[[],["wordlist",3]],[[],["wordmap",3]],[[],["result",4]],null,null,null,null,null,null,null,null,[[["arc",3,["addressvalidator"]],["addressvalidator",8]]],[[["keychainkind",4],["arc",3,["signer"]],["signer",8],["signerordering",3]]],null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[["transaction",3]],[["result",4,["txid","error"]],["txid",3],["error",4]]],[[["txid",3]],[["txbuilder",3,["defaultcoinselectionalgorithm","bumpfee"]],["error",4],["result",4,["txbuilder","error"]]]],[[],[["createtx",3],["txbuilder",3,["defaultcoinselectionalgorithm","createtx"]],["defaultcoinselectionalgorithm",6]]],[[]],null,[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["addressinfo",3]],["bool",15]],null,[[["signoptions",3],["psbt",3]],[["bool",15],["error",4],["result",4,["bool","error"]]]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[["addressindex",4]],[["addressinfo",3],["result",4,["addressinfo","error"]],["error",4]]],[[],[["u64",15],["error",4],["result",4,["u64","error"]]]],[[["keychainkind",4]],["extendeddescriptor",6]],[[["str",15]]],[[["localutxo",3],["sighashtype",4],["option",4,["sighashtype"]],["bool",15]],[["input",3],["result",4,["input","error"]],["error",4]]],[[["outpoint",3]],[["result",4,["option","error"]],["error",4],["option",4,["localutxo"]]]],null,[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[],["bool",15]],[[["script",3]],[["bool",15],["error",4],["result",4,["bool","error"]]]],[[["bool",15]],[["result",4,["vec","error"]],["error",4],["vec",3,["transactiondetails"]]]],[[],[["result",4,["vec","error"]],["vec",3,["localutxo"]],["error",4]]],[[["addressinfo",3]],["bool",15]],[[],["network",4]],[[["option",4],["network",4],["intowalletdescriptor",8]],[["result",4,["error"]],["error",4]]],[[["option",4],["network",4],["intowalletdescriptor",8]],[["result",4,["error"]],["error",4]]],[[["keychainkind",4]],[["result",4,["option","error"]],["option",4,["policy"]],["error",4]]],[[["keychainkind",4]],[["option",4,["extendeddescriptor"]],["error",4],["result",4,["option","error"]]]],[[],["secp256k1",3]],[[["signoptions",3],["psbt",3]],[["bool",15],["error",4],["result",4,["bool","error"]]]],null,[[["u32",15],["option",4,["u32"]],["progress",8]],[["error",4],["result",4,["error"]]]],null,[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],null,[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],[[]],null,null,null,null,null,null,null,null,null,[[],["fail",8]],[[]],[[]],[[],["addressvalidatorerror",4]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["addressvalidatorerror",4]],["bool",15]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[],["usize",15]],[[]],[[["addressvalidatorerror",4]],["bool",15]],[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[["keychainkind",4],["hdkeypaths",6],["script",3]],[["result",4,["addressvalidatorerror"]],["addressvalidatorerror",4]]],[[]],null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[],["largestfirstcoinselection",3]],[[]],[[["u64",15],["vec",3,["weightedutxo"]],["feerate",3],["weightedutxo",3]],[["result",4,["coinselectionresult","error"]],["error",4],["coinselectionresult",3]]],[[["u64",15],["vec",3,["weightedutxo"]],["feerate",3],["weightedutxo",3]],[["result",4,["coinselectionresult","error"]],["error",4],["coinselectionresult",3]]],[[["u64",15],["vec",3,["weightedutxo"]],["feerate",3],["weightedutxo",3]],[["result",4,["coinselectionresult","error"]],["error",4],["coinselectionresult",3]]],[[],["largestfirstcoinselection",3]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],null,[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[],["u64",15]],[[["u64",15]]],null,[[],["u64",15]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],[[]],null,null,[[]],[[]],[[],[["option",4,["string"]],["string",3]]],[[["usize",15]]],[[["usize",15]]],[[],["string",3]],[[],["result",4]],[[["usize",15]]],[[["str",15],["wallet",3],["bool",15]],[["str",15],["result",4,["str"]]]],[[["formatter",3]],["result",6]],[[]],[[["str",15]],["result",4]],[[],["usize",15]],[[]],null,[[],["result",4]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[["arc",3,["signer"]],["signer",8],["signerid",4],["signerordering",3]],[["option",4,["arc"]],["arc",3,["signer"]]]],null,[[],["fail",8]],[[["secp256k1",3]],["keymap",6]],null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["signerid",4]],[[],["signererror",4]],[[],["signerordering",3]],[[],["signerscontainer",3]],[[],["signoptions",3]],[[]],[[]],[[]],[[]],[[]],[[["signerid",4]],["ordering",4]],[[["signerordering",3]],["ordering",4]],[[]],[[],["signerscontainer",3]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[],[["descriptorsecretkey",4],["option",4,["descriptorsecretkey"]]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["signerid",4]],["bool",15]],[[["signererror",4]],["bool",15]],[[["signerordering",3]],["bool",15]],[[["signerid",4]],[["option",4,["arc"]],["arc",3]]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[["hash",3]],["signerid",4]],[[["fingerprint",3]],["signerid",4]],[[]],[[]],[[]],[[["keymap",6]],["signerscontainer",3]],[[]],[[],["u64",15]],[[]],[[["secp256k1",3]],["signerid",4]],[[],[["signerid",4],["vec",3,["signerid"]]]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[["signerid",4]],["bool",15]],[[["signerordering",3]],["bool",15]],[[]],[[["signerid",4]],[["option",4,["ordering"]],["ordering",4]]],[[["signerordering",3]],[["option",4,["ordering"]],["ordering",4]]],[[["signerid",4],["signerordering",3]],[["option",4,["arc"]],["arc",3,["signer"]]]],[[["usize",15],["partiallysignedtransaction",3],["secp256k1",3],["option",4,["usize"]]],[["result",4,["signererror"]],["signererror",4]]],[[],["bool",15]],[[],[["vec",3,["arc"]],["arc",3]]],[[]],[[]],[[]],[[]],[[]],[[],["string",3]],null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[]],[[]],[[]],[[]],[[]],null,null,null,[[],["u64",15]],null,null,null,null,null,null,null,null,null,null,null,null,[[["input",3],["usize",15],["outpoint",3]],[["error",4],["result",4,["error"]]]],[[]],[[["u64",15],["script",3]]],[[["outpoint",3]]],[[["outpoint",3]],[["error",4],["result",4,["error"]]]],[[],[["error",4],["result",4,["error"]]]],[[["script",3]],[["error",4],["result",4,["error"]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["changespendpolicy",4]]],[[],["createtx",3]],[[],["bumpfee",3]],[[]],[[],["txordering",4]],[[],["changespendpolicy",4]],[[]],[[]],[[]],[[]],[[]],[[["txordering",4]],["ordering",4]],[[["changespendpolicy",4]],["ordering",4]],[[["coinselectionalgorithm",8]],[["coinselectionalgorithm",8],["txbuilder",3]]],[[],["createtx",3]],[[],["bumpfee",3]],[[]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[]],[[["script",3]]],[[]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[]],[[["u32",15]]],[[["txordering",4]],["bool",15]],[[["changespendpolicy",4]],["bool",15]],[[["u64",15]]],[[["feerate",3]]],[[],[["error",4],["result",4,["error"]]]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[]],[[]],[[],["u64",15]],[[],["u64",15]],[[]],[[]],[[]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[]],[[]],[[["u32",15]]],[[]],[[]],[[["txordering",4]]],[[["txordering",4]],[["option",4,["ordering"]],["ordering",4]]],[[["changespendpolicy",4]],[["option",4,["ordering"]],["ordering",4]]],[[["keychainkind",4],["vec",3,["usize"]],["btreemap",3,["string","vec"]],["string",3]]],[[["vec",3]]],[[["sighashtype",4]]],[[["transaction",3]]],[[]],[[]],[[]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[["outpoint",3],["vec",3,["outpoint"]]]],[[["i32",15]]],[[]],[[]],[[]],[[]],[[]]],"p":[[4,"Error"],[4,"KeychainKind"],[4,"Utxo"],[3,"FeeRate"],[3,"LocalUtxo"],[3,"WeightedUtxo"],[3,"TransactionDetails"],[3,"ConfirmationTime"],[6,"MnemonicWithPassphrase"],[6,"DescriptorTemplateOut"],[6,"ExtendedDescriptor"],[8,"Vbytes"],[13,"InvalidU32Bytes"],[13,"Generic"],[13,"OutputBelowDustLimit"],[13,"MissingKeyOrigin"],[13,"Key"],[13,"SpendingPolicyRequired"],[13,"InvalidPolicyPathError"],[13,"Signer"],[13,"InvalidProgressValue"],[13,"InvalidOutpoint"],[13,"Descriptor"],[13,"AddressValidator"],[13,"Encode"],[13,"Miniscript"],[13,"Bip32"],[13,"Secp256k1"],[13,"Json"],[13,"Hex"],[13,"Psbt"],[13,"PsbtParse"],[13,"Electrum"],[13,"Esplora"],[13,"CompactFilters"],[13,"Sled"],[13,"Rusqlite"],[13,"InsufficientFunds"],[13,"InvalidNetwork"],[13,"FeeRateTooLow"],[13,"FeeTooLow"],[13,"Local"],[13,"Foreign"],[4,"Capability"],[8,"ConfigurableBlockchain"],[3,"NoopProgress"],[3,"LogProgress"],[8,"Blockchain"],[8,"Progress"],[4,"AnyBlockchain"],[4,"AnyBlockchainConfig"],[13,"Electrum"],[13,"Esplora"],[13,"CompactFilters"],[13,"Electrum"],[13,"Esplora"],[13,"CompactFilters"],[4,"CompactFiltersError"],[3,"Mempool"],[3,"BitcoinPeerConfig"],[3,"Peer"],[3,"CompactFiltersBlockchain"],[3,"CompactFiltersBlockchainConfig"],[13,"Db"],[13,"Io"],[13,"Bip158"],[13,"Time"],[13,"Global"],[3,"ElectrumBlockchain"],[3,"ElectrumBlockchainConfig"],[4,"EsploraError"],[3,"EsploraBlockchainConfig"],[3,"EsploraBlockchain"],[3,"EsploraGetHistory"],[13,"Ureq"],[13,"UreqTransport"],[13,"HttpResponse"],[13,"Io"],[13,"Parsing"],[13,"BitcoinEncoding"],[13,"Hex"],[13,"TransactionNotFound"],[13,"HeaderHeightNotFound"],[13,"HeaderHashNotFound"],[8,"BatchDatabase"],[8,"ConfigurableDatabase"],[3,"SqliteDatabase"],[8,"Database"],[8,"BatchOperations"],[4,"AnyBatch"],[4,"AnyDatabase"],[4,"AnyDatabaseConfig"],[3,"SledDbConfiguration"],[3,"SqliteDbConfiguration"],[13,"Memory"],[13,"Sled"],[13,"Sqlite"],[13,"Memory"],[13,"Sled"],[13,"Sqlite"],[13,"Memory"],[13,"Sled"],[13,"Sqlite"],[3,"MemoryDatabase"],[4,"Descriptor"],[4,"Legacy"],[4,"Segwitv0"],[3,"Miniscript"],[3,"DerivedDescriptorKey"],[8,"ScriptContext"],[8,"ExtractPolicy"],[8,"IntoWalletDescriptor"],[13,"Bare"],[13,"Pkh"],[13,"Wpkh"],[13,"Sh"],[13,"Wsh"],[4,"Error"],[13,"Key"],[13,"Policy"],[13,"InvalidDescriptorCharacter"],[13,"Bip32"],[13,"Base58"],[13,"Pk"],[13,"Miniscript"],[13,"Hex"],[4,"SatisfiableItem"],[4,"PolicyError"],[4,"Satisfaction"],[4,"BuildSatisfaction"],[3,"PkOrF"],[3,"Policy"],[3,"Condition"],[13,"Psbt"],[13,"PsbtTimelocks"],[13,"NotEnoughItemsSelected"],[13,"IndexOutOfRange"],[13,"Complete"],[13,"Partial"],[13,"PartialComplete"],[13,"Signature"],[13,"SignatureKey"],[13,"Sha256Preimage"],[13,"Hash256Preimage"],[13,"Ripemd160Preimage"],[13,"Hash160Preimage"],[13,"Thresh"],[13,"Multisig"],[13,"AbsoluteTimelock"],[13,"RelativeTimelock"],[3,"P2Pkh"],[3,"P2Wpkh_P2Sh"],[3,"P2Wpkh"],[3,"Bip44"],[3,"Bip44Public"],[3,"Bip49"],[3,"Bip49Public"],[3,"Bip84"],[3,"Bip84Public"],[8,"DescriptorTemplate"],[4,"KeyError"],[8,"GeneratableKey"],[4,"ScriptContextEnum"],[4,"ExtendedKey"],[4,"DescriptorSecretKey"],[4,"DescriptorPublicKey"],[8,"ExtScriptContext"],[3,"GeneratedKey"],[4,"DescriptorKey"],[3,"PrivateKeyGenerateOptions"],[3,"SortedMultiVec"],[3,"DescriptorSinglePub"],[3,"DescriptorSinglePriv"],[8,"GeneratableDefaultOptions"],[8,"IntoDescriptorKey"],[8,"DerivableKey"],[13,"SinglePub"],[13,"XPub"],[13,"SinglePriv"],[13,"XPrv"],[13,"Private"],[13,"Public"],[13,"Message"],[13,"Bip32"],[13,"Miniscript"],[4,"Language"],[4,"MnemonicType"],[3,"Seed"],[3,"Mnemonic"],[4,"AddressIndex"],[3,"Wallet"],[3,"AddressInfo"],[8,"IsDust"],[13,"Peek"],[13,"Reset"],[4,"AddressValidatorError"],[8,"AddressValidator"],[13,"Message"],[3,"CoinSelectionResult"],[3,"LargestFirstCoinSelection"],[3,"BranchAndBoundCoinSelection"],[8,"CoinSelectionAlgorithm"],[3,"WalletExport"],[3,"SignerOrdering"],[4,"SignerId"],[4,"SignerError"],[3,"SignersContainer"],[3,"SignOptions"],[8,"Signer"],[13,"PkHash"],[13,"Fingerprint"],[13,"Dummy"],[4,"TxOrdering"],[4,"ChangeSpendPolicy"],[3,"TxBuilder"],[3,"CreateTx"],[3,"BumpFee"]]}\ +}'); +if (window.initSearch) {window.initSearch(searchIndex)}; \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/search.js b/static/docs-rs/bdk/nightly/latest/search.js new file mode 100644 index 0000000000..91de2a155a --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/search.js @@ -0,0 +1 @@ +(function(){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 TY_PRIMITIVE=itemTypes.indexOf("primitive");var TY_KEYWORD=itemTypes.indexOf("keyword");function printTab(nb){if(nb===0||nb===1||nb===2){searchState.currentTab=nb}var nb_copy=nb;onEachLazy(document.getElementById("titles").childNodes,function(elem){if(nb_copy===0){addClass(elem,"selected")}else{removeClass(elem,"selected")}nb_copy-=1});onEachLazy(document.getElementById("results").childNodes,function(elem){if(nb===0){addClass(elem,"active")}else{removeClass(elem,"active")}nb-=1})}function removeEmptyStringsFromArray(x){for(var i=0,len=x.length;i-1){var obj=searchIndex[results[i].id];obj.lev=results[i].lev;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(hasOwnPropertyRustdoc(results,entry)){ar.push(results[entry])}}results=ar;var i,len,result;for(i=0,len=results.length;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});for(i=0,len=results.length;i"));return{name:val.substring(0,val.indexOf("<")),generics:values.split(/\s*,\s*/),}}return{name:val,generics:[],}}function checkGenerics(obj,val){var tmp_lev,elem_name;if(val.generics.length>0){if(obj.length>GENERICS_DATA&&obj[GENERICS_DATA].length>=val.generics.length){var elems=Object.create(null);var elength=obj[GENERICS_DATA].length;for(var x=0;xGENERICS_DATA&&obj[GENERICS_DATA].length>0){var elems=Object.create(null);len=obj[GENERICS_DATA].length;for(x=0;xGENERICS_DATA&&obj[GENERICS_DATA].length!==0){var tmp_lev=checkGenerics(obj,val);if(tmp_lev<=MAX_LEV_DISTANCE){return tmp_lev}}}}else if(literalSearch){if((!val.generics||val.generics.length===0)&&obj.length>GENERICS_DATA&&obj[GENERICS_DATA].length>0){return obj[GENERICS_DATA].some(function(name){return name===val.name})}return false}lev_distance=Math.min(levenshtein(obj[NAME],val.name),lev_distance);if(lev_distance<=MAX_LEV_DISTANCE){lev_distance=Math.ceil((checkGenerics(obj,val)+lev_distance)/2)}else if(obj.length>GENERICS_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,len=ret.length;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){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 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=[];if(filterCrates!==undefined){if(ALIASES[filterCrates]&&ALIASES[filterCrates][query.search]){var query_aliases=ALIASES[filterCrates][query.search];var len=query_aliases.length;for(var i=0;iMAX_RESULTS){ret.others.pop()}};onEach(aliases,pushFunc);onEach(crateAliases,pushFunc)}var nSearchWords=searchWords.length;var i,it;var ty;var fullId;var returned;var in_args;var len;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,len=inputs.length;i1?paths.length-1:1);var lev,j;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=ty.id;if(searchWords[j].indexOf(split[i])>-1||searchWords[j].indexOf(val)>-1||ty.normalizedName.indexOf(val)>-1){if(typePassesFilter(typeFilter,ty.ty)&&results[fullId]===undefined){index=ty.normalizedName.indexOf(val)}}if((lev=levenshtein(searchWords[j],val))<=MAX_LEV_DISTANCE){if(typePassesFilter(typeFilter,ty.ty)){lev+=1}else{lev=MAX_LEV_DISTANCE+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(typePassesFilter(typeFilter,ty.ty)&&(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,false),};handleAliases(ret,query,filterCrates);return ret}function validateResult(name,path,keys,parent){for(var i=0,len=keys.length;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 nextTab(direction){var next=(searchState.currentTab+direction+3)%searchState.focusedByTab.length;searchState.focusedByTab[searchState.currentTab]=document.activeElement;printTab(next);focusSearchResult()}function focusSearchResult(){var target=searchState.focusedByTab[searchState.currentTab]||document.querySelectorAll(".search-results.active a").item(0)||document.querySelectorAll("#titles > button").item(searchState.currentTab);if(target){target.focus()}}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=window.rootPath+path.replace(/::/g,"/")+"/"+name+"/index.html"}else if(type==="primitive"||type==="keyword"){displayPath="";href=window.rootPath+path.replace(/::/g,"/")+"/"+type+"."+name+".html"}else if(type==="externcrate"){displayPath="";href=window.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 enumNameIdx=item.path.lastIndexOf("::");var enumName=item.path.substr(enumNameIdx+2);path=item.path.substr(0,enumNameIdx);displayPath=path+"::"+enumName+"::"+myparent.name+"::";anchor="#variant."+myparent.name+".field."+name;pageType="enum";pageName=enumName}else{displayPath=path+"::"+myparent.name+"::"}href=window.rootPath+path.replace(/::/g,"/")+"/"+pageType+"."+pageName+".html"+anchor}else{displayPath=item.path+"::";href=window.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 extraClass="";if(display===true){extraClass=" active"}var output=document.createElement("div");var duplicates={};var length=0;if(array.length>0){output.className="search-results "+extraClass;array.forEach(function(item){if(item.is_alias!==true){if(duplicates[item.fullPath]){return}duplicates[item.fullPath]=true}var name=item.name;var type=itemTypes[item.ty];length+=1;var extra="";if(type==="primitive"){extra=" (primitive type)"}else if(type==="keyword"){extra=" (keyword)"}var link=document.createElement("a");link.className="result-"+type;link.href=item.href;var wrapper=document.createElement("div");var resultName=document.createElement("div");resultName.className="result-name";if(item.is_alias){var alias=document.createElement("span");alias.className="alias";var bold=document.createElement("b");bold.innerText=item.alias;alias.appendChild(bold);alias.insertAdjacentHTML("beforeend"," - see ");resultName.appendChild(alias)}resultName.insertAdjacentHTML("beforeend",item.displayPath+""+name+extra+"");wrapper.appendChild(resultName);var description=document.createElement("div");description.className="desc";var spanDesc=document.createElement("span");spanDesc.insertAdjacentHTML("beforeend",item.desc);description.appendChild(spanDesc);wrapper.appendChild(description);link.appendChild(wrapper);output.appendChild(link)})}else{output.className="search-failed"+extraClass;output.innerHTML="No results :(
"+"Try on DuckDuckGo?

"+"Or try looking in one of these:"}return[output,length]}function makeTabHeader(tabNb,text,nbElems){if(searchState.currentTab===tabNb){return""}return""}function showResults(results,go_to_first){var search=searchState.outputElement();if(go_to_first||(results.others.length===1&&getSettingValue("go-to-only-result")==="true"&&(!search.firstChild||search.firstChild.innerText!==searchState.loadingText))){var elem=document.createElement("a");elem.href=results.others[0].href;removeClass(elem,"active");document.body.appendChild(elem);elem.click();return}var query=getQuery(searchState.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 currentTab=searchState.currentTab;if((currentTab===0&&ret_others[1]===0)||(currentTab===1&&ret_in_args[1]===0)||(currentTab===2&&ret_returned[1]===0)){if(ret_others[1]!==0){currentTab=0}else if(ret_in_args[1]!==0){currentTab=1}else if(ret_returned[1]!==0){currentTab=2}}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])+"
";var resultsElem=document.createElement("div");resultsElem.id="results";resultsElem.appendChild(ret_others[0]);resultsElem.appendChild(ret_in_args[0]);resultsElem.appendChild(ret_returned[0]);search.innerHTML=output;search.appendChild(resultsElem);searchState.focusedByTab=[null,null,null];searchState.showResults(search);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,len=positions.length;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,arrays_len=arrays.length;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}function tokenizeQuery(raw){var i,matched;var l=raw.length;var depth=0;var nextAngle=/(<|>)/g;var ret=[];var start=0;for(i=0;i'){depth+=1}break;case">":if(depth>0){depth-=1}break;case",":if(depth===0){ret.push(raw.substring(start,i));start=i+1}break}}if(start!==i){ret.push(raw.substring(start,i))}return ret}var queries=tokenizeQuery(query.raw);var results={"in_args":[],"returned":[],"others":[],};for(var i=0,len=queries.length;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"&&hasOwnPropertyRustdoc(rawSearchIndex,elem.value)){return elem.value}return undefined}function search(e,forced){var params=searchState.getQueryStringParams();var query=getQuery(searchState.input.value.trim());if(e){e.preventDefault()}if(query.query.length===0){return}if(!forced&&query.id===currentResults){if(query.query.length>0){searchState.putBackSearch(searchState.input)}return}searchState.title="Results for "+query.query+" - Rust";if(searchState.browserSupportsHistoryApi()){var newURL=getNakedUrl()+"?search="+encodeURIComponent(query.raw)+window.location.hash;if(!history.state&&!params.search){history.pushState(query,"",newURL)}else{history.replaceState(query,"",newURL)}}var filterCrates=getFilterCrates();showResults(execSearch(query,index,filterCrates),params.go_to_first)}function buildIndex(rawSearchIndex){searchIndex=[];var searchWords=[];var i,word;var currentIndex=0;var id=0;for(var crate in rawSearchIndex){if(!hasOwnPropertyRustdoc(rawSearchIndex,crate)){continue}var crateSize=0;searchWords.push(crate);var crateRow={crate:crate,ty:1,name:crate,path:"",desc:rawSearchIndex[crate].doc,parent:undefined,type:null,id:id,normalizedName:crate.indexOf("_")===-1?crate:crate.replace(/_/g,""),};id+=1;searchIndex.push(crateRow);currentIndex+=1;var itemTypes=rawSearchIndex[crate].t;var itemNames=rawSearchIndex[crate].n;var itemPaths=rawSearchIndex[crate].q;var itemDescs=rawSearchIndex[crate].d;var itemParentIdxs=rawSearchIndex[crate].i;var itemFunctionSearchTypes=rawSearchIndex[crate].f;var paths=rawSearchIndex[crate].p;var aliases=rawSearchIndex[crate].a;var len=paths.length;for(i=0;i0?paths[itemParentIdxs[i]-1]:undefined,type:itemFunctionSearchTypes[i],id:id,normalizedName:word.indexOf("_")===-1?word:word.replace(/_/g,""),};id+=1;searchIndex.push(row);lastPath=row.path;crateSize+=1}if(aliases){ALIASES[crate]={};var j,local_aliases;for(var alias_name in aliases){if(!hasOwnPropertyRustdoc(aliases,alias_name)){continue}if(!hasOwnPropertyRustdoc(ALIASES[crate],alias_name)){ALIASES[crate][alias_name]=[]}local_aliases=aliases[alias_name];for(j=0,len=local_aliases.length;j0){searchState.input.value=params.search;search(e)}else{searchState.input.value="";searchState.hideResults()}})}window.onpageshow=function(){var qSearch=searchState.getQueryStringParams().search;if(searchState.input.value===""&&qSearch){searchState.input.value=qSearch}search()}}index=buildIndex(rawSearchIndex);registerSearchEvents();if(searchState.getQueryStringParams().search){search()}};if(window.searchIndex!==undefined){initSearch(window.searchIndex)}})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/settings.css b/static/docs-rs/bdk/nightly/latest/settings.css new file mode 100644 index 0000000000..670986588e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/settings.html b/static/docs-rs/bdk/nightly/latest/settings.html new file mode 100644 index 0000000000..e04d80ec2e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/settings.html @@ -0,0 +1,4 @@ +Rustdoc settings

Rustdoc settings

Theme preferences
Use system theme
Preferred dark theme
Preferred light theme
+
Auto-hide item contents for large items.
Auto-hide item methods' documentation
Auto-hide trait implementation documentation
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/latest/settings.js b/static/docs-rs/bdk/nightly/latest/settings.js new file mode 100644 index 0000000000..b4d6fdcd78 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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/latest/source-files.js b/static/docs-rs/bdk/nightly/latest/source-files.js new file mode 100644 index 0000000000..34aad7c3a4 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/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"]},{"name":"esplora","files":["mod.rs","ureq.rs"]}],"files":["any.rs","electrum.rs","mod.rs","utils.rs"]},{"name":"database","files":["any.rs","keyvalue.rs","memory.rs","mod.rs","sqlite.rs"]},{"name":"descriptor","files":["checksum.rs","derived.rs","dsl.rs","error.rs","mod.rs","policy.rs","template.rs"]},{"name":"keys","files":["bip39.rs","mod.rs"]},{"name":"psbt","files":["mod.rs"]},{"name":"testutils","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/latest/source-script.js b/static/docs-rs/bdk/nightly/latest/source-script.js new file mode 100644 index 0000000000..5dc8fee0f2 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/source-script.js @@ -0,0 +1 @@ +(function(){function getCurrentFilePath(){var parts=window.location.pathname.split("/");var rootPathParts=window.rootPath.split("/");for(var i=0,len=rootPathParts.length;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("/")){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()}}var lineNumbersRegex=/^#?(\d+)(?:-(\d+))?$/;function highlightSourceLines(scrollTo,match){if(typeof match==="undefined"){match=window.location.hash.match(lineNumbersRegex)}if(!match){return}var from=parseInt(match[1],10);var to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(tocur_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)}}}());window.addEventListener("hashchange",function(){var match=window.location.hash.match(lineNumbersRegex);if(match){return highlightSourceLines(false,match)}});onEachLazy(document.getElementsByClassName("line-numbers"),function(el){el.addEventListener("click",handleSourceHighlight)});highlightSourceLines(true);window.createSourceSidebar=createSourceSidebar})() \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/any.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/any.rs.html new file mode 100644 index 0000000000..977b1afcca --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/any.rs.html @@ -0,0 +1,510 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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(all(feature = "esplora", feature = "ureq"))]
+//! # {
+//! let esplora_blockchain = EsploraBlockchain::new("...", 20);
+//! 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;
+//! # #[cfg(all(feature = "esplora", feature = "ureq"))]
+//! # {
+//! 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, )* ),
+            #[cfg(feature = "rpc")]
+            AnyBlockchain::Rpc(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),
+    #[cfg(feature = "rpc")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "rpc")))]
+    /// RPC client
+    Rpc(rpc::RpcBlockchain),
+}
+
+#[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,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(impl_inner_method!(self, setup, database, progress_update))
+    }
+    fn sync<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(impl_inner_method!(self, sync, 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")]);
+impl_from!(rpc::RpcBlockchain, AnyBlockchain, Rpc, #[cfg(feature = "rpc")]);
+
+/// 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.
+///
+/// This type can be serialized from a JSON object like:
+///
+/// ```
+/// # #[cfg(feature = "electrum")]
+/// # {
+/// use bdk::blockchain::{electrum::ElectrumBlockchainConfig, AnyBlockchainConfig};
+/// let config: AnyBlockchainConfig = serde_json::from_str(
+///     r#"{
+///    "type" : "electrum",
+///    "url" : "ssl://electrum.blockstream.info:50002",
+///    "retry": 2,
+///    "stop_gap": 20
+/// }"#,
+/// )
+/// .unwrap();
+/// assert_eq!(
+///     config,
+///     AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig {
+///         url: "ssl://electrum.blockstream.info:50002".into(),
+///         retry: 2,
+///         socks5: None,
+///         timeout: None,
+///         stop_gap: 20,
+///     })
+/// );
+/// # }
+/// ```
+#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq)]
+#[serde(tag = "type", rename_all = "snake_case")]
+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),
+    #[cfg(feature = "rpc")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "rpc")))]
+    /// RPC client configuration
+    Rpc(rpc::RpcConfig),
+}
+
+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)?,
+            ),
+            #[cfg(feature = "rpc")]
+            AnyBlockchainConfig::Rpc(inner) => {
+                AnyBlockchain::Rpc(rpc::RpcBlockchain::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")]);
+impl_from!(rpc::RpcConfig, AnyBlockchainConfig, Rpc, #[cfg(feature = "rpc")]);
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/compact_filters/mod.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/compact_filters/mod.rs.html new file mode 100644 index 0000000000..4927399c69 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/compact_filters/mod.rs.html @@ -0,0 +1,1140 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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, LocalUtxo, TransactionDetails};
+use crate::{ConfirmationTime, 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_else(|_| 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: Option<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(&LocalUtxo {
+                    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,
+                confirmation_time: ConfirmationTime::new(height, timestamp),
+                verified: height.is_some(),
+                fee: Some(inputs_sum.saturating_sub(outputs_sum)),
+            };
+
+            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()
+    }
+
+    #[allow(clippy::mutex_atomic)] // Mutex is easier to understand than a CAS loop.
+    fn setup<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        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.saturating_sub(cf_sync.pruned_bundles()?);
+
+        let headers_cost = (first_peer.get_version().start_height as usize)
+            .saturating_sub(initial_height) 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.saturating_sub(initial_height) 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.saturating_sub(sync::BURIED_CONFIRMATIONS);
+        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<_>>(),
+        );
+
+        #[allow(clippy::mutex_atomic)]
+        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 = matches!(headers.get_full_block(block_height)?, Some(block) if &block.block_hash() == block_hash);
+
+                        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.confirmation_time {
+                Some(c) if (c.height as usize) < last_synced_block => continue,
+                _ => updates.del_tx(&details.txid, false)?,
+            };
+        }
+        database.commit_batch(updates)?;
+
+        match first_peer.ask_for_mempool() {
+            Err(CompactFiltersError::PeerBloomDisabled) => {
+                log::warn!("Peer has BLOOM disabled, we can't ask for the mempool")
+            }
+            e => e?,
+        };
+
+        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),
+                    None,
+                    &mut internal_max_deriv,
+                    &mut external_max_deriv,
+                )?;
+            }
+        }
+        for tx in first_peer.get_mempool().iter_txs().iter() {
+            self.process_tx(
+                database,
+                tx,
+                None,
+                None,
+                &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, Clone, PartialEq)]
+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, Clone, PartialEq)]
+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,
+    /// The peer doesn't advertise the [`BLOOM`](bitcoin::network::constants::ServiceFlags::BLOOM) service flag
+    PeerBloomDisabled,
+
+    /// 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/latest/src/bdk/blockchain/compact_filters/peer.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/compact_filters/peer.rs.html new file mode 100644 index 0000000000..c9f3b00e9c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/compact_filters/peer.rs.html @@ -0,0 +1,1148 @@ +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
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+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::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, Wtxid};
+
+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(RwLock<InnerMempool>);
+
+#[derive(Debug, Default)]
+struct InnerMempool {
+    txs: HashMap<Txid, Transaction>,
+    wtxids: HashMap<Wtxid, Txid>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum TxIdentifier {
+    Wtxid(Wtxid),
+    Txid(Txid),
+}
+
+impl Mempool {
+    /// Create a new empty mempool
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// 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) {
+        let mut guard = self.0.write().unwrap();
+
+        guard.wtxids.insert(tx.wtxid(), tx.txid());
+        guard.txs.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 identifer = match inventory {
+            Inventory::Error | Inventory::Block(_) | Inventory::WitnessBlock(_) => return None,
+            Inventory::Transaction(txid) => TxIdentifier::Txid(*txid),
+            Inventory::WitnessTransaction(txid) => TxIdentifier::Txid(*txid),
+            Inventory::WTx(wtxid) => TxIdentifier::Wtxid(*wtxid),
+            Inventory::Unknown { inv_type, hash } => {
+                log::warn!(
+                    "Unknown inventory request type `{}`, hash `{:?}`",
+                    inv_type,
+                    hash
+                );
+                return None;
+            }
+        };
+
+        let txid = match identifer {
+            TxIdentifier::Txid(txid) => Some(txid),
+            TxIdentifier::Wtxid(wtxid) => self.0.read().unwrap().wtxids.get(&wtxid).cloned(),
+        };
+
+        txid.map(|txid| self.0.read().unwrap().txs.get(&txid).cloned())
+            .flatten()
+    }
+
+    /// Return whether or not the mempool contains a transaction with a given txid
+    pub fn has_tx(&self, txid: &Txid) -> bool {
+        self.0.read().unwrap().txs.contains_key(txid)
+    }
+
+    /// Return the list of transactions contained in the mempool
+    pub fn iter_txs(&self) -> Vec<Transaction> {
+        self.0.read().unwrap().txs.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,
+            responses,
+            reader_thread,
+            connected,
+            mempool,
+            version,
+            network,
+        })
+    }
+
+    /// 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>,
+    ) -> Option<NetworkMessage> {
+        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 None;
+                    }
+                    messages = result.0;
+                }
+            }
+        }
+
+        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
+                        .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> {
+        Ok(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> {
+        if !self.version.services.has(ServiceFlags::BLOOM) {
+            return Err(CompactFiltersError::PeerBloomDisabled);
+        }
+
+        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| matches!(item, Inventory::Transaction(txid) if !self.mempool.has_tx(txid)),
+            )
+            .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/latest/src/bdk/blockchain/compact_filters/store.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/compact_filters/store.rs.html new file mode 100644 index 0000000000..e7ee810018 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/compact_filters/store.rs.html @@ -0,0 +1,1704 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+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, FilterHeader};
+use bitcoin::hashes::hex::FromHex;
+use bitcoin::hashes::Hash;
+use bitcoin::util::bip158::BlockFilter;
+use bitcoin::util::uint::Uint256;
+use bitcoin::Block;
+use bitcoin::BlockHash;
+use bitcoin::BlockHeader;
+use bitcoin::Network;
+
+use lazy_static::lazy_static;
+
+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();
+    static ref SIGNET_GENESIS: Block = deserialize(&Vec::<u8>::from_hex("0100000000000000000000000000000000000000000000000000000000000000000000003BA3EDFD7A7B12B27AC72C3E67768F617FC81BC3888A51323A9FB8AA4B1E5E4A008F4D5FAE77031E8AD222030101000000010000000000000000000000000000000000000000000000000000000000000000FFFFFFFF4D04FFFF001D0104455468652054696D65732030332F4A616E2F32303039204368616E63656C6C6F72206F6E206272696E6B206F66207365636F6E64206261696C6F757420666F722062616E6B73FFFFFFFF0100F2052A01000000434104678AFDB0FE5548271967F1A67130B7105CD6A828E03909A67962E0EA1F61DEB649F6BC3F4CEF38C4F35504E51EC112DE5C384DF7BA0B8D578A4C702B6BF11D5FAC00000000").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> {
+        deserialize(data).map_err(|_| CompactFiltersError::DataCorruption)
+    }
+}
+
+impl Encodable for BundleStatus {
+    fn consensus_encode<W: Write>(&self, mut e: W) -> Result<usize, std::io::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(),
+            Network::Signet => SIGNET_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(usize::from_be_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(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)).get_key();
+        let data = read_store.get_pinned_cf(cf_handle, key)?;
+        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)?;
+        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)?;
+
+        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);
+
+        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(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 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, FilterHeader);
+
+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(),
+            Network::Signet => SIGNET_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_header(&FilterHeader::from_hash(Default::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<FilterHeader>, 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))
+            .skip(1)
+            .map(|(_, data)| Ok::<_, CompactFiltersError>(BundleEntry::deserialize(&data)?.1))
+            .collect::<Result<_, _>>()
+    }
+
+    pub fn replace_checkpoints(
+        &self,
+        checkpoints: Vec<FilterHeader>,
+    ) -> 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: FilterHeader,
+        filter_hashes: Vec<FilterHash>,
+    ) -> Result<BundleStatus, CompactFiltersError> {
+        let cf_headers: Vec<FilterHeader> = filter_hashes
+            .into_iter()
+            .scan(checkpoint, |prev_header, filter_hash| {
+                let filter_header = filter_hash.filter_header(&prev_header);
+                *prev_header = filter_header;
+
+                Some(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 cf_headers.iter().last() != Some(&next_checkpoint) {
+                return Err(CompactFiltersError::InvalidFilterHeader);
+            }
+        }
+
+        let key = StoreEntry::CFilterTable((self.filter_type, Some(bundle))).get_key();
+        let value = (BundleStatus::CfHeaders { cf_headers }, checkpoint);
+
+        read_store.put(key, value.serialize())?;
+
+        Ok(value.0)
+    }
+
+    pub fn advance_to_cf_filters(
+        &self,
+        bundle: usize,
+        checkpoint: FilterHeader,
+        headers: Vec<FilterHeader>,
+        filters: Vec<(usize, Vec<u8>)>,
+    ) -> Result<BundleStatus, CompactFiltersError> {
+        let cf_filters = filters
+            .into_iter()
+            .zip(headers.into_iter())
+            .scan(checkpoint, |prev_header, ((_, filter_content), header)| {
+                let filter = BlockFilter::new(&filter_content);
+                if header != filter.filter_header(&prev_header) {
+                    return Some(Err(CompactFiltersError::InvalidFilter));
+                }
+                *prev_header = header;
+
+                Some(Ok::<_, CompactFiltersError>(filter_content))
+            })
+            .collect::<Result<_, _>>()?;
+
+        let key = StoreEntry::CFilterTable((self.filter_type, Some(bundle))).get_key();
+        let value = (BundleStatus::CFilters { cf_filters }, checkpoint);
+
+        let read_store = self.store.read().unwrap();
+        read_store.put(key, value.serialize())?;
+
+        Ok(value.0)
+    }
+
+    pub fn prune_filters(
+        &self,
+        bundle: usize,
+        checkpoint: FilterHeader,
+    ) -> Result<BundleStatus, CompactFiltersError> {
+        let key = StoreEntry::CFilterTable((self.filter_type, Some(bundle))).get_key();
+        let value = (BundleStatus::Pruned, checkpoint);
+
+        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: FilterHeader,
+    ) -> Result<BundleStatus, CompactFiltersError> {
+        let key = StoreEntry::CFilterTable((self.filter_type, Some(bundle))).get_key();
+        let value = (BundleStatus::Tip { cf_filters }, checkpoint);
+
+        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/latest/src/bdk/blockchain/compact_filters/sync.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/compact_filters/sync.rs.html new file mode 100644 index 0000000000..9e1601fadd --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/compact_filters/sync.rs.html @@ -0,0 +1,596 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+use std::collections::{BTreeMap, HashMap, VecDeque};
+use std::sync::{Arc, Mutex};
+use std::time::Duration;
+
+use bitcoin::hash_types::{BlockHash, FilterHeader};
+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, FilterHeader, 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_header == 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).saturating_sub(BURIED_CONFIRMATIONS);
+
+                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),
+        }
+    } 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/latest/src/bdk/blockchain/electrum.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/electrum.rs.html new file mode 100644 index 0000000000..a51f2cbb78 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/electrum.rs.html @@ -0,0 +1,374 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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::{ElectrumLikeSync, ElsGetHistoryRes};
+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: Client,
+    stop_gap: usize,
+}
+
+impl std::convert::From<Client> for ElectrumBlockchain {
+    fn from(client: Client) -> Self {
+        ElectrumBlockchain {
+            client,
+            stop_gap: 20,
+        }
+    }
+}
+
+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,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        self.client
+            .electrum_like_setup(self.stop_gap, database, progress_update)
+    }
+
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.client.transaction_get(txid).map(Option::Some)?)
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        Ok(self.client.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
+            .client
+            .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.client.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, Clone, PartialEq)]
+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: Option<u8>,
+    /// Stop searching addresses for transactions after finding an unused gap of this length
+    pub stop_gap: usize,
+}
+
+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)
+            .timeout(config.timeout)?
+            .socks5(socks5)?
+            .build();
+
+        Ok(ElectrumBlockchain {
+            client: Client::from_config(config.url.as_str(), electrum_config)?,
+            stop_gap: config.stop_gap,
+        })
+    }
+}
+
+#[cfg(test)]
+#[cfg(feature = "test-electrum")]
+crate::bdk_blockchain_tests! {
+    fn test_instance(test_client: &TestClient) -> ElectrumBlockchain {
+        ElectrumBlockchain::from(Client::new(&test_client.electrsd.electrum_url).unwrap())
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/esplora/mod.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/esplora/mod.rs.html new file mode 100644 index 0000000000..7d87905c9b --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/esplora/mod.rs.html @@ -0,0 +1,262 @@ +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
+
//! Esplora
+//!
+//! This module defines a [`EsploraBlockchain`] 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", 20);
+//! # Ok::<(), bdk::Error>(())
+//! ```
+//!
+//! Esplora blockchain can use either `ureq` or `reqwest` for the HTTP client
+//! depending on your needs (blocking or async respectively).
+//!
+//! Please note, to configure the Esplora HTTP client correctly use one of:
+//! Blocking:  --features='esplora,ureq'
+//! Async:     --features='async-interface,esplora,reqwest' --no-default-features
+use std::collections::HashMap;
+use std::fmt;
+use std::io;
+
+use serde::Deserialize;
+
+use bitcoin::consensus;
+use bitcoin::{BlockHash, Txid};
+
+use crate::error::Error;
+use crate::FeeRate;
+
+#[cfg(feature = "reqwest")]
+mod reqwest;
+
+#[cfg(feature = "reqwest")]
+pub use self::reqwest::*;
+
+#[cfg(feature = "ureq")]
+mod ureq;
+
+#[cfg(feature = "ureq")]
+pub use self::ureq::*;
+
+fn into_fee_rate(target: usize, estimates: HashMap<String, f64>) -> Result<FeeRate, Error> {
+    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))
+}
+
+/// Data type used when fetching transaction history from Esplora.
+#[derive(Deserialize)]
+pub struct EsploraGetHistory {
+    txid: Txid,
+    status: EsploraGetHistoryStatus,
+}
+
+#[derive(Deserialize)]
+struct EsploraGetHistoryStatus {
+    block_height: Option<usize>,
+}
+
+/// Errors that can happen during a sync with [`EsploraBlockchain`]
+#[derive(Debug)]
+pub enum EsploraError {
+    /// Error during ureq HTTP request
+    #[cfg(feature = "ureq")]
+    Ureq(::ureq::Error),
+    /// Transport error during the ureq HTTP call
+    #[cfg(feature = "ureq")]
+    UreqTransport(::ureq::Transport),
+    /// Error during reqwest HTTP request
+    #[cfg(feature = "reqwest")]
+    Reqwest(::reqwest::Error),
+    /// HTTP response error
+    HttpResponse(u16),
+    /// IO error during ureq response read
+    Io(io::Error),
+    /// No header found in ureq response
+    NoHeader,
+    /// 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 {}
+
+#[cfg(feature = "ureq")]
+impl_error!(::ureq::Error, Ureq, EsploraError);
+#[cfg(feature = "ureq")]
+impl_error!(::ureq::Transport, UreqTransport, EsploraError);
+#[cfg(feature = "reqwest")]
+impl_error!(::reqwest::Error, Reqwest, EsploraError);
+impl_error!(io::Error, Io, EsploraError);
+impl_error!(std::num::ParseIntError, Parsing, EsploraError);
+impl_error!(consensus::encode::Error, BitcoinEncoding, EsploraError);
+impl_error!(bitcoin::hashes::hex::Error, Hex, EsploraError);
+
+#[cfg(test)]
+#[cfg(feature = "test-esplora")]
+crate::bdk_blockchain_tests! {
+    fn test_instance(test_client: &TestClient) -> EsploraBlockchain {
+        EsploraBlockchain::new(&format!("http://{}",test_client.electrsd.esplora_url.as_ref().unwrap()), 20)
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/esplora/ureq.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/esplora/ureq.rs.html new file mode 100644 index 0000000000..10f92a0fea --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/esplora/ureq.rs.html @@ -0,0 +1,800 @@ +ureq.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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Esplora by way of `ureq` HTTP client.
+
+use std::collections::{HashMap, HashSet};
+use std::io;
+use std::io::Read;
+use std::time::Duration;
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+
+use ureq::{Agent, Proxy, Response};
+
+use bitcoin::consensus::{deserialize, serialize};
+use bitcoin::hashes::hex::{FromHex, ToHex};
+use bitcoin::hashes::{sha256, Hash};
+use bitcoin::{BlockHeader, Script, Transaction, Txid};
+
+use crate::blockchain::esplora::{EsploraError, EsploraGetHistory};
+use crate::blockchain::utils::{ElectrumLikeSync, ElsGetHistoryRes};
+use crate::blockchain::*;
+use crate::database::BatchDatabase;
+use crate::error::Error;
+use crate::FeeRate;
+
+#[derive(Debug)]
+struct UrlClient {
+    url: String,
+    agent: Agent,
+}
+
+/// 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 {
+    url_client: UrlClient,
+    stop_gap: usize,
+}
+
+impl std::convert::From<UrlClient> for EsploraBlockchain {
+    fn from(url_client: UrlClient) -> Self {
+        EsploraBlockchain {
+            url_client,
+            stop_gap: 20,
+        }
+    }
+}
+
+impl EsploraBlockchain {
+    /// Create a new instance of the client from a base URL and the `stop_gap`.
+    pub fn new(base_url: &str, stop_gap: usize) -> Self {
+        EsploraBlockchain {
+            url_client: UrlClient {
+                url: base_url.to_string(),
+                agent: Agent::new(),
+            },
+            stop_gap,
+        }
+    }
+
+    /// Set the inner `ureq` agent.
+    pub fn with_agent(mut self, agent: Agent) -> Self {
+        self.url_client.agent = agent;
+        self
+    }
+}
+
+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,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        self.url_client
+            .electrum_like_setup(self.stop_gap, database, progress_update)
+    }
+
+    fn get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        Ok(self.url_client._get_tx(txid)?)
+    }
+
+    fn broadcast(&self, tx: &Transaction) -> Result<(), Error> {
+        let _txid = self.url_client._broadcast(tx)?;
+        Ok(())
+    }
+
+    fn get_height(&self) -> Result<u32, Error> {
+        Ok(self.url_client._get_height()?)
+    }
+
+    fn estimate_fee(&self, target: usize) -> Result<FeeRate, Error> {
+        let estimates = self.url_client._get_fee_estimates()?;
+        super::into_fee_rate(target, estimates)
+    }
+}
+
+impl UrlClient {
+    fn script_to_scripthash(script: &Script) -> String {
+        sha256::Hash::hash(script.as_bytes()).into_inner().to_hex()
+    }
+
+    fn _get_tx(&self, txid: &Txid) -> Result<Option<Transaction>, EsploraError> {
+        let resp = self
+            .agent
+            .get(&format!("{}/tx/{}/raw", self.url, txid))
+            .call();
+
+        match resp {
+            Ok(resp) => Ok(Some(deserialize(&into_bytes(resp)?)?)),
+            Err(ureq::Error::Status(code, _)) => {
+                if is_status_not_found(code) {
+                    return Ok(None);
+                }
+                Err(EsploraError::HttpResponse(code))
+            }
+            Err(e) => Err(EsploraError::Ureq(e)),
+        }
+    }
+
+    fn _get_tx_no_opt(&self, txid: &Txid) -> Result<Transaction, EsploraError> {
+        match self._get_tx(txid) {
+            Ok(Some(tx)) => Ok(tx),
+            Ok(None) => Err(EsploraError::TransactionNotFound(*txid)),
+            Err(e) => Err(e),
+        }
+    }
+
+    fn _get_header(&self, block_height: u32) -> Result<BlockHeader, EsploraError> {
+        let resp = self
+            .agent
+            .get(&format!("{}/block-height/{}", self.url, block_height))
+            .call();
+
+        let bytes = match resp {
+            Ok(resp) => Ok(into_bytes(resp)?),
+            Err(ureq::Error::Status(code, _)) => Err(EsploraError::HttpResponse(code)),
+            Err(e) => Err(EsploraError::Ureq(e)),
+        }?;
+
+        let hash = std::str::from_utf8(&bytes)
+            .map_err(|_| EsploraError::HeaderHeightNotFound(block_height))?;
+
+        let resp = self
+            .agent
+            .get(&format!("{}/block/{}/header", self.url, hash))
+            .call();
+
+        match resp {
+            Ok(resp) => Ok(deserialize(&Vec::from_hex(&resp.into_string()?)?)?),
+            Err(ureq::Error::Status(code, _)) => Err(EsploraError::HttpResponse(code)),
+            Err(e) => Err(EsploraError::Ureq(e)),
+        }
+    }
+
+    fn _broadcast(&self, transaction: &Transaction) -> Result<(), EsploraError> {
+        let resp = self
+            .agent
+            .post(&format!("{}/tx", self.url))
+            .send_string(&serialize(transaction).to_hex());
+
+        match resp {
+            Ok(_) => Ok(()), // We do not return the txid?
+            Err(ureq::Error::Status(code, _)) => Err(EsploraError::HttpResponse(code)),
+            Err(e) => Err(EsploraError::Ureq(e)),
+        }
+    }
+
+    fn _get_height(&self) -> Result<u32, EsploraError> {
+        let resp = self
+            .agent
+            .get(&format!("{}/blocks/tip/height", self.url))
+            .call();
+
+        match resp {
+            Ok(resp) => Ok(resp.into_string()?.parse()?),
+            Err(ureq::Error::Status(code, _)) => Err(EsploraError::HttpResponse(code)),
+            Err(e) => Err(EsploraError::Ureq(e)),
+        }
+    }
+
+    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
+
+        let resp = self
+            .agent
+            .get(&format!(
+                "{}/scripthash/{}/txs/mempool",
+                self.url, scripthash
+            ))
+            .call();
+
+        let v = match resp {
+            Ok(resp) => {
+                let v: Vec<EsploraGetHistory> = resp.into_json()?;
+                Ok(v)
+            }
+            Err(ureq::Error::Status(code, _)) => Err(EsploraError::HttpResponse(code)),
+            Err(e) => Err(EsploraError::Ureq(e)),
+        }?;
+
+        result.extend(v.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 resp = self
+                .agent
+                .get(&format!(
+                    "{}/scripthash/{}/txs/chain/{}",
+                    self.url, scripthash, last_txid
+                ))
+                .call();
+
+            let v = match resp {
+                Ok(resp) => {
+                    let v: Vec<EsploraGetHistory> = resp.into_json()?;
+                    Ok(v)
+                }
+                Err(ureq::Error::Status(code, _)) => Err(EsploraError::HttpResponse(code)),
+                Err(e) => Err(EsploraError::Ureq(e)),
+            }?;
+
+            let len = v.len();
+            if let Some(elem) = v.last() {
+                last_txid = elem.txid.to_hex();
+            }
+
+            debug!("... adding {} confirmed transactions", len);
+
+            result.extend(v.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)
+    }
+
+    fn _get_fee_estimates(&self) -> Result<HashMap<String, f64>, EsploraError> {
+        let resp = self
+            .agent
+            .get(&format!("{}/fee-estimates", self.url,))
+            .call();
+
+        let map = match resp {
+            Ok(resp) => {
+                let map: HashMap<String, f64> = resp.into_json()?;
+                Ok(map)
+            }
+            Err(ureq::Error::Status(code, _)) => Err(EsploraError::HttpResponse(code)),
+            Err(e) => Err(EsploraError::Ureq(e)),
+        }?;
+
+        Ok(map)
+    }
+}
+
+fn is_status_not_found(status: u16) -> bool {
+    status == 404
+}
+
+fn into_bytes(resp: Response) -> Result<Vec<u8>, io::Error> {
+    const BYTES_LIMIT: usize = 10 * 1_024 * 1_024;
+
+    let mut buf: Vec<u8> = vec![];
+    resp.into_reader()
+        .take((BYTES_LIMIT + 1) as u64)
+        .read_to_end(&mut buf)?;
+    if buf.len() > BYTES_LIMIT {
+        return Err(io::Error::new(
+            io::ErrorKind::Other,
+            "response too big for into_bytes",
+        ));
+    }
+
+    Ok(buf)
+}
+
+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 mut results = vec![];
+        for script in scripts.into_iter() {
+            let v = self._script_get_history(script)?;
+            results.push(v);
+        }
+        Ok(results)
+    }
+
+    fn els_batch_transaction_get<'s, I: IntoIterator<Item = &'s Txid>>(
+        &self,
+        txids: I,
+    ) -> Result<Vec<Transaction>, Error> {
+        let mut results = vec![];
+        for txid in txids.into_iter() {
+            let tx = self._get_tx_no_opt(txid)?;
+            results.push(tx);
+        }
+        Ok(results)
+    }
+
+    fn els_batch_block_header<I: IntoIterator<Item = u32>>(
+        &self,
+        heights: I,
+    ) -> Result<Vec<BlockHeader>, Error> {
+        let mut results = vec![];
+        for height in heights.into_iter() {
+            let header = self._get_header(height)?;
+            results.push(header);
+        }
+        Ok(results)
+    }
+}
+
+/// Configuration for an [`EsploraBlockchain`]
+#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, PartialEq)]
+pub struct EsploraBlockchainConfig {
+    /// Base URL of the esplora service eg. `https://blockstream.info/api/`
+    pub base_url: String,
+    /// Optional URL of the proxy to use to make requests to the Esplora server
+    ///
+    /// The string should be formatted as: `<protocol>://<user>:<password>@host:<port>`.
+    ///
+    /// Note that the format of this value and the supported protocols change slightly between the
+    /// sync version of esplora (using `ureq`) and the async version (using `reqwest`). For more
+    /// details check with the documentation of the two crates. Both of them are compiled with
+    /// the `socks` feature enabled.
+    ///
+    /// The proxy is ignored when targeting `wasm32`.
+    pub proxy: Option<String>,
+    /// Socket read timeout.
+    pub timeout_read: u64,
+    /// Socket write timeout.
+    pub timeout_write: u64,
+    /// Stop searching addresses for transactions after finding an unused gap of this length.
+    pub stop_gap: usize,
+}
+
+impl ConfigurableBlockchain for EsploraBlockchain {
+    type Config = EsploraBlockchainConfig;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        let mut agent_builder = ureq::AgentBuilder::new()
+            .timeout_read(Duration::from_secs(config.timeout_read))
+            .timeout_write(Duration::from_secs(config.timeout_write));
+
+        if let Some(proxy) = &config.proxy {
+            agent_builder = agent_builder
+                .proxy(Proxy::new(proxy).map_err(|e| Error::Esplora(Box::new(e.into())))?);
+        }
+
+        Ok(
+            EsploraBlockchain::new(config.base_url.as_str(), config.stop_gap)
+                .with_agent(agent_builder.build()),
+        )
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/mod.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/mod.rs.html new file mode 100644 index 0000000000..6bac7fc40c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/mod.rs.html @@ -0,0 +1,516 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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",
+    feature = "rpc"
+))]
+pub mod any;
+#[cfg(any(
+    feature = "electrum",
+    feature = "esplora",
+    feature = "compact_filters",
+    feature = "rpc"
+))]
+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 = "rpc")]
+#[cfg_attr(docsrs, doc(cfg(feature = "rpc")))]
+pub mod rpc;
+#[cfg(feature = "rpc")]
+pub use self::rpc::RpcBlockchain;
+#[cfg(feature = "rpc")]
+pub use self::rpc::RpcConfig;
+
+#[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,
+}
+
+/// Trait that defines the actions that must be supported by a blockchain backend
+#[maybe_async]
+pub trait Blockchain {
+    /// 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,
+        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,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(self.setup(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 !(0.0..=100.0).contains(&progress) {
+            return Err(Error::InvalidProgressValue(progress));
+        }
+
+        self.send((progress, message))
+            .map_err(|_| Error::ProgressUpdateError)
+    }
+}
+
+/// Type that implements [`Progress`] and drops every update received
+#[derive(Clone, Copy)]
+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, Copy)]
+pub struct LogProgress;
+
+/// Create a new 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,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(self.deref().setup(database, progress_update))
+    }
+
+    fn sync<D: BatchDatabase, P: 'static + Progress>(
+        &self,
+        database: &mut D,
+        progress_update: P,
+    ) -> Result<(), Error> {
+        maybe_await!(self.deref().sync(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/latest/src/bdk/blockchain/utils.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/utils.rs.html new file mode 100644 index 0000000000..c5288d5967 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/blockchain/utils.rs.html @@ -0,0 +1,780 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+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::{ConfirmationTime, KeychainKind, LocalUtxo, TransactionDetails};
+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: usize,
+        db: &mut D,
+        _progress_update: P,
+    ) -> Result<(), Error> {
+        // TODO: progress
+        let start = Instant::new();
+        debug!("start setup");
+
+        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).cloned();
+            if let Some(tx_details) = txs_details_in_db.get(txid) {
+                // check if tx height matches, otherwise updates it. timestamp is not in the if clause
+                // because we are not asking headers for confirmed tx we know about
+                if tx_details.confirmation_time.as_ref().map(|c| c.height) != height {
+                    let confirmation_time = ConfirmationTime::new(height, timestamp);
+                    let mut new_tx_details = tx_details.clone();
+                    new_tx_details.confirmation_time = confirmation_time;
+                    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 txid_in_db_with_conf: HashSet<_> = txs_details_in_db
+            .values()
+            .filter_map(|details| details.confirmation_time.as_ref().map(|_| details.txid))
+            .collect();
+        let needed_txid_height: HashMap<&Txid, u32> = txid_height
+            .iter()
+            .filter(|(t, _)| !txid_in_db_with_conf.contains(*t))
+            .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: Option<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(&LocalUtxo {
+                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,
+        confirmation_time: ConfirmationTime::new(height, timestamp),
+        fee: Some(inputs_sum.saturating_sub(outputs_sum)), /* if the tx is a coinbase, fees would be negative */
+        verified: height.is_some(),
+    };
+    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 with [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/latest/src/bdk/database/any.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/database/any.rs.html new file mode 100644 index 0000000000..a259b301c3 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/database/any.rs.html @@ -0,0 +1,834 @@ +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
+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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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<(), AnyDatabase>`.
+//!
+//! ```no_run
+//! # use bitcoin::Network;
+//! # use bdk::database::{AnyDatabase, MemoryDatabase};
+//! # use bdk::{Wallet};
+//! let memory = MemoryDatabase::default();
+//! let wallet_memory = Wallet::new_offline("...", None, Network::Testnet, memory)?;
+//!
+//! # #[cfg(feature = "key-value-db")]
+//! # {
+//! let sled = sled::open("my-database")?.open_tree("default_tree")?;
+//! let wallet_sled = 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};
+//! let config = serde_json::from_str("...")?;
+//! let database = AnyDatabase::from_config(&config)?;
+//! let wallet = 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, )* ),
+            #[cfg(feature = "sqlite")]
+            $enum_name::Sqlite(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),
+    #[cfg(feature = "sqlite")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))]
+    /// Sqlite embedded database using [`rusqlite`]
+    Sqlite(sqlite::SqliteDatabase),
+}
+
+impl_from!(memory::MemoryDatabase, AnyDatabase, Memory,);
+impl_from!(sled::Tree, AnyDatabase, Sled, #[cfg(feature = "key-value-db")]);
+impl_from!(sqlite::SqliteDatabase, AnyDatabase, Sqlite, #[cfg(feature = "sqlite")]);
+
+/// 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),
+    #[cfg(feature = "sqlite")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))]
+    /// Sqlite embedded database using [`rusqlite`]
+    Sqlite(<sqlite::SqliteDatabase 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_from!(<sqlite::SqliteDatabase as BatchDatabase>::Batch, AnyBatch, Sqlite, #[cfg(feature = "sqlite")]);
+
+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: &LocalUtxo) -> 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<LocalUtxo>, 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<LocalUtxo>, 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<LocalUtxo>, 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)
+    }
+
+    fn flush(&mut self) -> Result<(), Error> {
+        impl_inner_method!(AnyDatabase, self, flush)
+    }
+}
+
+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: &LocalUtxo) -> 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<LocalUtxo>, 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(),
+            #[cfg(feature = "sqlite")]
+            AnyDatabase::Sqlite(inner) => inner.begin_batch().into(),
+        }
+    }
+    fn commit_batch(&mut self, batch: Self::Batch) -> Result<(), Error> {
+        match self {
+            AnyDatabase::Memory(db) => match batch {
+                AnyBatch::Memory(batch) => db.commit_batch(batch),
+                #[cfg(any(feature = "key-value-db", feature = "sqlite"))]
+                _ => unimplemented!("Other batch shouldn't be used with Memory db."),
+            },
+            #[cfg(feature = "key-value-db")]
+            AnyDatabase::Sled(db) => match batch {
+                AnyBatch::Sled(batch) => db.commit_batch(batch),
+                _ => unimplemented!("Other batch shouldn't be used with Sled db."),
+            },
+            #[cfg(feature = "sqlite")]
+            AnyDatabase::Sqlite(db) => match batch {
+                AnyBatch::Sqlite(batch) => db.commit_batch(batch),
+                _ => unimplemented!("Other batch shouldn't be used with Sqlite db."),
+            },
+        }
+    }
+}
+
+/// 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)?)
+    }
+}
+
+/// Configuration type for a [`sqlite::SqliteDatabase`] database
+#[cfg(feature = "sqlite")]
+#[derive(Debug, serde::Serialize, serde::Deserialize)]
+pub struct SqliteDbConfiguration {
+    /// Main directory of the db
+    pub path: String,
+}
+
+#[cfg(feature = "sqlite")]
+impl ConfigurableDatabase for sqlite::SqliteDatabase {
+    type Config = SqliteDbConfiguration;
+
+    fn from_config(config: &Self::Config) -> Result<Self, Error> {
+        Ok(sqlite::SqliteDatabase::new(config.path.clone()))
+    }
+}
+
+/// 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),
+    #[cfg(feature = "sqlite")]
+    #[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))]
+    /// Sqlite embedded database using [`rusqlite`]
+    Sqlite(SqliteDbConfiguration),
+}
+
+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)?),
+            #[cfg(feature = "sqlite")]
+            AnyDatabaseConfig::Sqlite(inner) => {
+                AnyDatabase::Sqlite(sqlite::SqliteDatabase::from_config(inner)?)
+            }
+        })
+    }
+}
+
+impl_from!((), AnyDatabaseConfig, Memory,);
+impl_from!(SledDbConfiguration, AnyDatabaseConfig, Sled, #[cfg(feature = "key-value-db")]);
+impl_from!(SqliteDbConfiguration, AnyDatabaseConfig, Sqlite, #[cfg(feature = "sqlite")]);
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/database/keyvalue.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/database/keyvalue.rs.html new file mode 100644 index 0000000000..111cc74a11 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/database/keyvalue.rs.html @@ -0,0 +1,950 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+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: &LocalUtxo) -> 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<LocalUtxo>, 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(LocalUtxo { 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<LocalUtxo>, 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(LocalUtxo {
+                    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<LocalUtxo>, 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(LocalUtxo {
+                    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)
+        })
+    }
+
+    fn flush(&mut self) -> Result<(), Error> {
+        Ok(Tree::flush(self).map(|_| ())?)
+    }
+}
+
+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 lazy_static::lazy_static;
+    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/latest/src/bdk/database/memory.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/database/memory.rs.html new file mode 100644 index 0000000000..5c0d43db48 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/database/memory.rs.html @@ -0,0 +1,1188 @@ +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
+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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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: &LocalUtxo) -> 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<LocalUtxo>, 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(LocalUtxo {
+                    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<LocalUtxo>, 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(LocalUtxo {
+                    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<LocalUtxo>, 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();
+            LocalUtxo {
+                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)
+    }
+
+    fn flush(&mut self) -> Result<(), Error> {
+        Ok(())
+    }
+}
+
+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.iter() {
+            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())
+    }
+}
+
+#[macro_export]
+#[doc(hidden)]
+/// Artificially insert a tx in the database, as if we had found it with a `sync`. This is a hidden
+/// macro and not a `[cfg(test)]` function so it can be called within the context of doctests which
+/// don't have `test` set.
+macro_rules! populate_test_db {
+    ($db:expr, $tx_meta:expr, $current_height:expr$(,)?) => {{
+        use std::str::FromStr;
+        use $crate::database::BatchOperations;
+        let mut db = $db;
+        let tx_meta = $tx_meta;
+        let current_height: Option<u32> = $current_height;
+        let tx = $crate::bitcoin::Transaction {
+            version: 1,
+            lock_time: 0,
+            input: vec![],
+            output: tx_meta
+                .output
+                .iter()
+                .map(|out_meta| $crate::bitcoin::TxOut {
+                    value: out_meta.value,
+                    script_pubkey: $crate::bitcoin::Address::from_str(&out_meta.to_address)
+                        .unwrap()
+                        .script_pubkey(),
+                })
+                .collect(),
+        };
+
+        let txid = tx.txid();
+        let confirmation_time = tx_meta
+            .min_confirmations
+            .map(|conf| $crate::ConfirmationTime {
+                height: current_height.unwrap().checked_sub(conf as u32).unwrap(),
+                timestamp: 0,
+            });
+
+        let tx_details = $crate::TransactionDetails {
+            transaction: Some(tx.clone()),
+            txid,
+            fee: Some(0),
+            received: 0,
+            sent: 0,
+            confirmation_time,
+            verified: current_height.is_some(),
+        };
+
+        db.set_tx(&tx_details).unwrap();
+        for (vout, out) in tx.output.iter().enumerate() {
+            db.set_utxo(&$crate::LocalUtxo {
+                txout: out.clone(),
+                outpoint: $crate::bitcoin::OutPoint {
+                    txid,
+                    vout: vout as u32,
+                },
+                keychain: $crate::KeychainKind::External,
+            })
+            .unwrap();
+        }
+
+        txid
+    }};
+}
+
+#[macro_export]
+#[doc(hidden)]
+/// Macro for getting a wallet for use in a doctest
+macro_rules! doctest_wallet {
+    () => {{
+        use $crate::bitcoin::Network;
+        use $crate::database::MemoryDatabase;
+        use $crate::testutils;
+        let descriptor = "wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)";
+        let descriptors = testutils!(@descriptors (descriptor) (descriptor));
+
+        let mut db = MemoryDatabase::new();
+        let txid = populate_test_db!(
+            &mut db,
+            testutils! {
+                @tx ( (@external descriptors, 0) => 500_000 ) (@confirmations 1)
+            },
+            Some(100),
+        );
+
+        $crate::Wallet::new_offline(
+            &descriptors.0,
+            descriptors.1.as_ref(),
+            Network::Regtest,
+            db
+        )
+        .unwrap()
+    }}
+}
+
+#[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/latest/src/bdk/database/mod.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/database/mod.rs.html new file mode 100644 index 0000000000..8dfc8a0079 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/database/mod.rs.html @@ -0,0 +1,766 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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;
+
+#[cfg(feature = "sqlite")]
+pub(crate) mod sqlite;
+#[cfg(feature = "sqlite")]
+pub use sqlite::SqliteDatabase;
+
+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 [`LocalUtxo`]
+    fn set_utxo(&mut self, utxo: &LocalUtxo) -> 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 [`LocalUtxo`] given its [`OutPoint`]
+    fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<LocalUtxo>, 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 [`LocalUtxo`]s
+    fn iter_utxos(&self) -> Result<Vec<LocalUtxo>, 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 [`LocalUtxo`] given its [`OutPoint`]
+    fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<LocalUtxo>, 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>;
+
+    /// Force changes to be written to disk
+    fn flush(&mut self) -> Result<(), 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<D>(&self, txid: &Txid, default: D) -> Result<Option<Transaction>, Error>
+    where
+        D: FnOnce() -> Result<Option<Transaction>, Error>,
+    {
+        self.get_tx(txid, true)?
+            .map(|t| t.transaction)
+            .flatten()
+            .map_or_else(default, |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))
+        );
+    }
+
+    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))
+        );
+    }
+
+    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 = LocalUtxo {
+            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,
+            received: 1337,
+            sent: 420420,
+            fee: Some(140),
+            confirmation_time: Some(ConfirmationTime {
+                timestamp: 123456,
+                height: 1000,
+            }),
+            verified: true,
+        };
+
+        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/latest/src/bdk/database/sqlite.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/database/sqlite.rs.html new file mode 100644 index 0000000000..ff5e01c5bf --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/database/sqlite.rs.html @@ -0,0 +1,1940 @@ +sqlite.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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+use bitcoin::consensus::encode::{deserialize, serialize};
+use bitcoin::hash_types::Txid;
+use bitcoin::{OutPoint, Script, Transaction, TxOut};
+
+use crate::database::{BatchDatabase, BatchOperations, Database};
+use crate::error::Error;
+use crate::types::*;
+
+use rusqlite::{named_params, Connection};
+
+static MIGRATIONS: &[&str] = &[
+    "CREATE TABLE version (version INTEGER)",
+    "INSERT INTO version VALUES (1)",
+    "CREATE TABLE script_pubkeys (keychain TEXT, child INTEGER, script BLOB);",
+    "CREATE INDEX idx_keychain_child ON script_pubkeys(keychain, child);",
+    "CREATE INDEX idx_script ON script_pubkeys(script);",
+    "CREATE TABLE utxos (value INTEGER, keychain TEXT, vout INTEGER, txid BLOB, script BLOB);",
+    "CREATE INDEX idx_txid_vout ON utxos(txid, vout);",
+    "CREATE TABLE transactions (txid BLOB, raw_tx BLOB);",
+    "CREATE INDEX idx_txid ON transactions(txid);",
+    "CREATE TABLE transaction_details (txid BLOB, timestamp INTEGER, received INTEGER, sent INTEGER, fee INTEGER, height INTEGER, verified INTEGER DEFAULT 0);",
+    "CREATE INDEX idx_txdetails_txid ON transaction_details(txid);",
+    "CREATE TABLE last_derivation_indices (keychain TEXT, value INTEGER);",
+    "CREATE UNIQUE INDEX idx_indices_keychain ON last_derivation_indices(keychain);",
+    "CREATE TABLE checksums (keychain TEXT, checksum BLOB);",
+    "CREATE INDEX idx_checksums_keychain ON checksums(keychain);",
+];
+
+/// Sqlite database stored on filesystem
+///
+/// This is a permanent storage solution for devices and platforms that provide a filesystem.
+/// [`crate::database`]
+#[derive(Debug)]
+pub struct SqliteDatabase {
+    /// Path on the local filesystem to store the sqlite file
+    pub path: String,
+    /// A rusqlite connection object to the sqlite database
+    pub connection: Connection,
+}
+
+impl SqliteDatabase {
+    /// Instantiate a new SqliteDatabase instance by creating a connection
+    /// to the database stored at path
+    pub fn new(path: String) -> Self {
+        let connection = get_connection(&path).unwrap();
+        SqliteDatabase { path, connection }
+    }
+    fn insert_script_pubkey(
+        &self,
+        keychain: String,
+        child: u32,
+        script: &[u8],
+    ) -> Result<i64, Error> {
+        let mut statement = self.connection.prepare_cached("INSERT INTO script_pubkeys (keychain, child, script) VALUES (:keychain, :child, :script)")?;
+        statement.execute(named_params! {
+            ":keychain": keychain,
+            ":child": child,
+            ":script": script
+        })?;
+
+        Ok(self.connection.last_insert_rowid())
+    }
+    fn insert_utxo(
+        &self,
+        value: u64,
+        keychain: String,
+        vout: u32,
+        txid: &[u8],
+        script: &[u8],
+    ) -> Result<i64, Error> {
+        let mut statement = self.connection.prepare_cached("INSERT INTO utxos (value, keychain, vout, txid, script) VALUES (:value, :keychain, :vout, :txid, :script)")?;
+        statement.execute(named_params! {
+            ":value": value,
+            ":keychain": keychain,
+            ":vout": vout,
+            ":txid": txid,
+            ":script": script
+        })?;
+
+        Ok(self.connection.last_insert_rowid())
+    }
+    fn insert_transaction(&self, txid: &[u8], raw_tx: &[u8]) -> Result<i64, Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("INSERT INTO transactions (txid, raw_tx) VALUES (:txid, :raw_tx)")?;
+        statement.execute(named_params! {
+            ":txid": txid,
+            ":raw_tx": raw_tx,
+        })?;
+
+        Ok(self.connection.last_insert_rowid())
+    }
+
+    fn update_transaction(&self, txid: &[u8], raw_tx: &[u8]) -> Result<(), Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("UPDATE transactions SET raw_tx=:raw_tx WHERE txid=:txid")?;
+
+        statement.execute(named_params! {
+            ":txid": txid,
+            ":raw_tx": raw_tx,
+        })?;
+
+        Ok(())
+    }
+
+    fn insert_transaction_details(&self, transaction: &TransactionDetails) -> Result<i64, Error> {
+        let (timestamp, height) = match &transaction.confirmation_time {
+            Some(confirmation_time) => (
+                Some(confirmation_time.timestamp),
+                Some(confirmation_time.height),
+            ),
+            None => (None, None),
+        };
+
+        let txid: &[u8] = &transaction.txid;
+
+        let mut statement = self.connection.prepare_cached("INSERT INTO transaction_details (txid, timestamp, received, sent, fee, height, verified) VALUES (:txid, :timestamp, :received, :sent, :fee, :height, :verified)")?;
+
+        statement.execute(named_params! {
+            ":txid": txid,
+            ":timestamp": timestamp,
+            ":received": transaction.received,
+            ":sent": transaction.sent,
+            ":fee": transaction.fee,
+            ":height": height,
+            ":verified": transaction.verified
+        })?;
+
+        Ok(self.connection.last_insert_rowid())
+    }
+
+    fn update_transaction_details(&self, transaction: &TransactionDetails) -> Result<(), Error> {
+        let (timestamp, height) = match &transaction.confirmation_time {
+            Some(confirmation_time) => (
+                Some(confirmation_time.timestamp),
+                Some(confirmation_time.height),
+            ),
+            None => (None, None),
+        };
+
+        let txid: &[u8] = &transaction.txid;
+
+        let mut statement = self.connection.prepare_cached("UPDATE transaction_details SET timestamp=:timestamp, received=:received, sent=:sent, fee=:fee, height=:height, verified=:verified WHERE txid=:txid")?;
+
+        statement.execute(named_params! {
+            ":txid": txid,
+            ":timestamp": timestamp,
+            ":received": transaction.received,
+            ":sent": transaction.sent,
+            ":fee": transaction.fee,
+            ":height": height,
+            ":verified": transaction.verified,
+        })?;
+
+        Ok(())
+    }
+
+    fn insert_last_derivation_index(&self, keychain: String, value: u32) -> Result<i64, Error> {
+        let mut statement = self.connection.prepare_cached(
+            "INSERT INTO last_derivation_indices (keychain, value) VALUES (:keychain, :value)",
+        )?;
+
+        statement.execute(named_params! {
+            ":keychain": keychain,
+            ":value": value,
+        })?;
+
+        Ok(self.connection.last_insert_rowid())
+    }
+
+    fn insert_checksum(&self, keychain: String, checksum: &[u8]) -> Result<i64, Error> {
+        let mut statement = self.connection.prepare_cached(
+            "INSERT INTO checksums (keychain, checksum) VALUES (:keychain, :checksum)",
+        )?;
+        statement.execute(named_params! {
+            ":keychain": keychain,
+            ":checksum": checksum,
+        })?;
+
+        Ok(self.connection.last_insert_rowid())
+    }
+
+    fn update_last_derivation_index(&self, keychain: String, value: u32) -> Result<(), Error> {
+        let mut statement = self.connection.prepare_cached(
+            "INSERT INTO last_derivation_indices (keychain, value) VALUES (:keychain, :value) ON CONFLICT(keychain) DO UPDATE SET value=:value WHERE keychain=:keychain",
+        )?;
+
+        statement.execute(named_params! {
+            ":keychain": keychain,
+            ":value": value,
+        })?;
+
+        Ok(())
+    }
+
+    fn select_script_pubkeys(&self) -> Result<Vec<Script>, Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("SELECT script FROM script_pubkeys")?;
+        let mut scripts: Vec<Script> = vec![];
+        let mut rows = statement.query([])?;
+        while let Some(row) = rows.next()? {
+            let raw_script: Vec<u8> = row.get(0)?;
+            scripts.push(raw_script.into());
+        }
+
+        Ok(scripts)
+    }
+
+    fn select_script_pubkeys_by_keychain(&self, keychain: String) -> Result<Vec<Script>, Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("SELECT script FROM script_pubkeys WHERE keychain=:keychain")?;
+        let mut scripts: Vec<Script> = vec![];
+        let mut rows = statement.query(named_params! {":keychain": keychain})?;
+        while let Some(row) = rows.next()? {
+            let raw_script: Vec<u8> = row.get(0)?;
+            scripts.push(raw_script.into());
+        }
+
+        Ok(scripts)
+    }
+
+    fn select_script_pubkey_by_path(
+        &self,
+        keychain: String,
+        child: u32,
+    ) -> Result<Option<Script>, Error> {
+        let mut statement = self.connection.prepare_cached(
+            "SELECT script FROM script_pubkeys WHERE keychain=:keychain AND child=:child",
+        )?;
+        let mut rows = statement.query(named_params! {":keychain": keychain,":child": child})?;
+
+        match rows.next()? {
+            Some(row) => {
+                let script: Vec<u8> = row.get(0)?;
+                let script: Script = script.into();
+                Ok(Some(script))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn select_script_pubkey_by_script(
+        &self,
+        script: &[u8],
+    ) -> Result<Option<(KeychainKind, u32)>, Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("SELECT keychain, child FROM script_pubkeys WHERE script=:script")?;
+        let mut rows = statement.query(named_params! {":script": script})?;
+        match rows.next()? {
+            Some(row) => {
+                let keychain: String = row.get(0)?;
+                let keychain: KeychainKind = serde_json::from_str(&keychain)?;
+                let child: u32 = row.get(1)?;
+                Ok(Some((keychain, child)))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn select_utxos(&self) -> Result<Vec<LocalUtxo>, Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("SELECT value, keychain, vout, txid, script FROM utxos")?;
+        let mut utxos: Vec<LocalUtxo> = vec![];
+        let mut rows = statement.query([])?;
+        while let Some(row) = rows.next()? {
+            let value = row.get(0)?;
+            let keychain: String = row.get(1)?;
+            let vout = row.get(2)?;
+            let txid: Vec<u8> = row.get(3)?;
+            let script: Vec<u8> = row.get(4)?;
+
+            let keychain: KeychainKind = serde_json::from_str(&keychain)?;
+
+            utxos.push(LocalUtxo {
+                outpoint: OutPoint::new(deserialize(&txid)?, vout),
+                txout: TxOut {
+                    value,
+                    script_pubkey: script.into(),
+                },
+                keychain,
+            })
+        }
+
+        Ok(utxos)
+    }
+
+    fn select_utxo_by_outpoint(
+        &self,
+        txid: &[u8],
+        vout: u32,
+    ) -> Result<Option<(u64, KeychainKind, Script)>, Error> {
+        let mut statement = self.connection.prepare_cached(
+            "SELECT value, keychain, script FROM utxos WHERE txid=:txid AND vout=:vout",
+        )?;
+        let mut rows = statement.query(named_params! {":txid": txid,":vout": vout})?;
+        match rows.next()? {
+            Some(row) => {
+                let value: u64 = row.get(0)?;
+                let keychain: String = row.get(1)?;
+                let keychain: KeychainKind = serde_json::from_str(&keychain)?;
+                let script: Vec<u8> = row.get(2)?;
+                let script: Script = script.into();
+
+                Ok(Some((value, keychain, script)))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn select_transactions(&self) -> Result<Vec<Transaction>, Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("SELECT raw_tx FROM transactions")?;
+        let mut txs: Vec<Transaction> = vec![];
+        let mut rows = statement.query([])?;
+        while let Some(row) = rows.next()? {
+            let raw_tx: Vec<u8> = row.get(0)?;
+            let tx: Transaction = deserialize(&raw_tx)?;
+            txs.push(tx);
+        }
+        Ok(txs)
+    }
+
+    fn select_transaction_by_txid(&self, txid: &[u8]) -> Result<Option<Transaction>, Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("SELECT raw_tx FROM transactions WHERE txid=:txid")?;
+        let mut rows = statement.query(named_params! {":txid": txid})?;
+        match rows.next()? {
+            Some(row) => {
+                let raw_tx: Vec<u8> = row.get(0)?;
+                let tx: Transaction = deserialize(&raw_tx)?;
+                Ok(Some(tx))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn select_transaction_details_with_raw(&self) -> Result<Vec<TransactionDetails>, Error> {
+        let mut statement = self.connection.prepare_cached("SELECT transaction_details.txid, transaction_details.timestamp, transaction_details.received, transaction_details.sent, transaction_details.fee, transaction_details.height, transaction_details.verified, transactions.raw_tx FROM transaction_details, transactions WHERE transaction_details.txid = transactions.txid")?;
+        let mut transaction_details: Vec<TransactionDetails> = vec![];
+        let mut rows = statement.query([])?;
+        while let Some(row) = rows.next()? {
+            let txid: Vec<u8> = row.get(0)?;
+            let txid: Txid = deserialize(&txid)?;
+            let timestamp: Option<u64> = row.get(1)?;
+            let received: u64 = row.get(2)?;
+            let sent: u64 = row.get(3)?;
+            let fee: Option<u64> = row.get(4)?;
+            let height: Option<u32> = row.get(5)?;
+            let verified: bool = row.get(6)?;
+            let raw_tx: Option<Vec<u8>> = row.get(7)?;
+            let tx: Option<Transaction> = match raw_tx {
+                Some(raw_tx) => {
+                    let tx: Transaction = deserialize(&raw_tx)?;
+                    Some(tx)
+                }
+                None => None,
+            };
+
+            let confirmation_time = match (height, timestamp) {
+                (Some(height), Some(timestamp)) => Some(ConfirmationTime { height, timestamp }),
+                _ => None,
+            };
+
+            transaction_details.push(TransactionDetails {
+                transaction: tx,
+                txid,
+                received,
+                sent,
+                fee,
+                confirmation_time,
+                verified,
+            });
+        }
+        Ok(transaction_details)
+    }
+
+    fn select_transaction_details(&self) -> Result<Vec<TransactionDetails>, Error> {
+        let mut statement = self.connection.prepare_cached(
+            "SELECT txid, timestamp, received, sent, fee, height, verified FROM transaction_details",
+        )?;
+        let mut transaction_details: Vec<TransactionDetails> = vec![];
+        let mut rows = statement.query([])?;
+        while let Some(row) = rows.next()? {
+            let txid: Vec<u8> = row.get(0)?;
+            let txid: Txid = deserialize(&txid)?;
+            let timestamp: Option<u64> = row.get(1)?;
+            let received: u64 = row.get(2)?;
+            let sent: u64 = row.get(3)?;
+            let fee: Option<u64> = row.get(4)?;
+            let height: Option<u32> = row.get(5)?;
+            let verified: bool = row.get(6)?;
+
+            let confirmation_time = match (height, timestamp) {
+                (Some(height), Some(timestamp)) => Some(ConfirmationTime { height, timestamp }),
+                _ => None,
+            };
+
+            transaction_details.push(TransactionDetails {
+                transaction: None,
+                txid,
+                received,
+                sent,
+                fee,
+                confirmation_time,
+                verified,
+            });
+        }
+        Ok(transaction_details)
+    }
+
+    fn select_transaction_details_by_txid(
+        &self,
+        txid: &[u8],
+    ) -> Result<Option<TransactionDetails>, Error> {
+        let mut statement = self.connection.prepare_cached("SELECT transaction_details.timestamp, transaction_details.received, transaction_details.sent, transaction_details.fee, transaction_details.height, transaction_details.verified, transactions.raw_tx FROM transaction_details, transactions WHERE transaction_details.txid=transactions.txid AND transaction_details.txid=:txid")?;
+        let mut rows = statement.query(named_params! { ":txid": txid })?;
+
+        match rows.next()? {
+            Some(row) => {
+                let timestamp: Option<u64> = row.get(0)?;
+                let received: u64 = row.get(1)?;
+                let sent: u64 = row.get(2)?;
+                let fee: Option<u64> = row.get(3)?;
+                let height: Option<u32> = row.get(4)?;
+                let verified: bool = row.get(5)?;
+
+                let raw_tx: Option<Vec<u8>> = row.get(6)?;
+                let tx: Option<Transaction> = match raw_tx {
+                    Some(raw_tx) => {
+                        let tx: Transaction = deserialize(&raw_tx)?;
+                        Some(tx)
+                    }
+                    None => None,
+                };
+
+                let confirmation_time = match (height, timestamp) {
+                    (Some(height), Some(timestamp)) => Some(ConfirmationTime { height, timestamp }),
+                    _ => None,
+                };
+
+                Ok(Some(TransactionDetails {
+                    transaction: tx,
+                    txid: deserialize(txid)?,
+                    received,
+                    sent,
+                    fee,
+                    confirmation_time,
+                    verified,
+                }))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn select_last_derivation_index_by_keychain(
+        &self,
+        keychain: String,
+    ) -> Result<Option<u32>, Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("SELECT value FROM last_derivation_indices WHERE keychain=:keychain")?;
+        let mut rows = statement.query(named_params! {":keychain": keychain})?;
+        match rows.next()? {
+            Some(row) => {
+                let value: u32 = row.get(0)?;
+                Ok(Some(value))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn select_checksum_by_keychain(&self, keychain: String) -> Result<Option<Vec<u8>>, Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("SELECT checksum FROM checksums WHERE keychain=:keychain")?;
+        let mut rows = statement.query(named_params! {":keychain": keychain})?;
+
+        match rows.next()? {
+            Some(row) => {
+                let checksum: Vec<u8> = row.get(0)?;
+                Ok(Some(checksum))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn delete_script_pubkey_by_path(&self, keychain: String, child: u32) -> Result<(), Error> {
+        let mut statement = self.connection.prepare_cached(
+            "DELETE FROM script_pubkeys WHERE keychain=:keychain AND child=:child",
+        )?;
+        statement.execute(named_params! {
+            ":keychain": keychain,
+            ":child": child
+        })?;
+
+        Ok(())
+    }
+
+    fn delete_script_pubkey_by_script(&self, script: &[u8]) -> Result<(), Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("DELETE FROM script_pubkeys WHERE script=:script")?;
+        statement.execute(named_params! {
+            ":script": script
+        })?;
+
+        Ok(())
+    }
+
+    fn delete_utxo_by_outpoint(&self, txid: &[u8], vout: u32) -> Result<(), Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("DELETE FROM utxos WHERE txid=:txid AND vout=:vout")?;
+        statement.execute(named_params! {
+            ":txid": txid,
+            ":vout": vout
+        })?;
+
+        Ok(())
+    }
+
+    fn delete_transaction_by_txid(&self, txid: &[u8]) -> Result<(), Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("DELETE FROM transactions WHERE txid=:txid")?;
+        statement.execute(named_params! {":txid": txid})?;
+        Ok(())
+    }
+
+    fn delete_transaction_details_by_txid(&self, txid: &[u8]) -> Result<(), Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("DELETE FROM transaction_details WHERE txid=:txid")?;
+        statement.execute(named_params! {":txid": txid})?;
+        Ok(())
+    }
+
+    fn delete_last_derivation_index_by_keychain(&self, keychain: String) -> Result<(), Error> {
+        let mut statement = self
+            .connection
+            .prepare_cached("DELETE FROM last_derivation_indices WHERE keychain=:keychain")?;
+        statement.execute(named_params! {
+            ":keychain": &keychain
+        })?;
+
+        Ok(())
+    }
+}
+
+impl BatchOperations for SqliteDatabase {
+    fn set_script_pubkey(
+        &mut self,
+        script: &Script,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<(), Error> {
+        let keychain = serde_json::to_string(&keychain)?;
+        self.insert_script_pubkey(keychain, child, script.as_bytes())?;
+        Ok(())
+    }
+
+    fn set_utxo(&mut self, utxo: &LocalUtxo) -> Result<(), Error> {
+        self.insert_utxo(
+            utxo.txout.value,
+            serde_json::to_string(&utxo.keychain)?,
+            utxo.outpoint.vout,
+            &utxo.outpoint.txid,
+            utxo.txout.script_pubkey.as_bytes(),
+        )?;
+        Ok(())
+    }
+
+    fn set_raw_tx(&mut self, transaction: &Transaction) -> Result<(), Error> {
+        match self.select_transaction_by_txid(&transaction.txid())? {
+            Some(_) => {
+                self.update_transaction(&transaction.txid(), &serialize(transaction))?;
+            }
+            None => {
+                self.insert_transaction(&transaction.txid(), &serialize(transaction))?;
+            }
+        }
+        Ok(())
+    }
+
+    fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error> {
+        match self.select_transaction_details_by_txid(&transaction.txid)? {
+            Some(_) => {
+                self.update_transaction_details(transaction)?;
+            }
+            None => {
+                self.insert_transaction_details(transaction)?;
+            }
+        }
+
+        if let Some(tx) = &transaction.transaction {
+            self.set_raw_tx(tx)?;
+        }
+
+        Ok(())
+    }
+
+    fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> {
+        self.update_last_derivation_index(serde_json::to_string(&keychain)?, value)?;
+        Ok(())
+    }
+
+    fn del_script_pubkey_from_path(
+        &mut self,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<Option<Script>, Error> {
+        let keychain = serde_json::to_string(&keychain)?;
+        let script = self.select_script_pubkey_by_path(keychain.clone(), child)?;
+        match script {
+            Some(script) => {
+                self.delete_script_pubkey_by_path(keychain, child)?;
+                Ok(Some(script))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn del_path_from_script_pubkey(
+        &mut self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error> {
+        match self.select_script_pubkey_by_script(script.as_bytes())? {
+            Some((keychain, child)) => {
+                self.delete_script_pubkey_by_script(script.as_bytes())?;
+                Ok(Some((keychain, child)))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<LocalUtxo>, Error> {
+        match self.select_utxo_by_outpoint(&outpoint.txid, outpoint.vout)? {
+            Some((value, keychain, script_pubkey)) => {
+                self.delete_utxo_by_outpoint(&outpoint.txid, outpoint.vout)?;
+                Ok(Some(LocalUtxo {
+                    outpoint: *outpoint,
+                    txout: TxOut {
+                        value,
+                        script_pubkey,
+                    },
+                    keychain,
+                }))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn del_raw_tx(&mut self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        match self.select_transaction_by_txid(txid)? {
+            Some(tx) => {
+                self.delete_transaction_by_txid(txid)?;
+                Ok(Some(tx))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn del_tx(
+        &mut self,
+        txid: &Txid,
+        include_raw: bool,
+    ) -> Result<Option<TransactionDetails>, Error> {
+        match self.select_transaction_details_by_txid(txid)? {
+            Some(transaction_details) => {
+                self.delete_transaction_details_by_txid(txid)?;
+
+                if include_raw {
+                    self.delete_transaction_by_txid(txid)?;
+                }
+                Ok(Some(transaction_details))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
+        let keychain = serde_json::to_string(&keychain)?;
+        match self.select_last_derivation_index_by_keychain(keychain.clone())? {
+            Some(value) => {
+                self.delete_last_derivation_index_by_keychain(keychain)?;
+
+                Ok(Some(value))
+            }
+            None => Ok(None),
+        }
+    }
+}
+
+impl Database for SqliteDatabase {
+    fn check_descriptor_checksum<B: AsRef<[u8]>>(
+        &mut self,
+        keychain: KeychainKind,
+        bytes: B,
+    ) -> Result<(), Error> {
+        let keychain = serde_json::to_string(&keychain)?;
+
+        match self.select_checksum_by_keychain(keychain.clone())? {
+            Some(checksum) => {
+                if checksum == bytes.as_ref().to_vec() {
+                    Ok(())
+                } else {
+                    Err(Error::ChecksumMismatch)
+                }
+            }
+            None => {
+                self.insert_checksum(keychain, bytes.as_ref())?;
+                Ok(())
+            }
+        }
+    }
+
+    fn iter_script_pubkeys(&self, keychain: Option<KeychainKind>) -> Result<Vec<Script>, Error> {
+        match keychain {
+            Some(keychain) => {
+                let keychain = serde_json::to_string(&keychain)?;
+                self.select_script_pubkeys_by_keychain(keychain)
+            }
+            None => self.select_script_pubkeys(),
+        }
+    }
+
+    fn iter_utxos(&self) -> Result<Vec<LocalUtxo>, Error> {
+        self.select_utxos()
+    }
+
+    fn iter_raw_txs(&self) -> Result<Vec<Transaction>, Error> {
+        self.select_transactions()
+    }
+
+    fn iter_txs(&self, include_raw: bool) -> Result<Vec<TransactionDetails>, Error> {
+        match include_raw {
+            true => self.select_transaction_details_with_raw(),
+            false => self.select_transaction_details(),
+        }
+    }
+
+    fn get_script_pubkey_from_path(
+        &self,
+        keychain: KeychainKind,
+        child: u32,
+    ) -> Result<Option<Script>, Error> {
+        let keychain = serde_json::to_string(&keychain)?;
+        match self.select_script_pubkey_by_path(keychain, child)? {
+            Some(script) => Ok(Some(script)),
+            None => Ok(None),
+        }
+    }
+
+    fn get_path_from_script_pubkey(
+        &self,
+        script: &Script,
+    ) -> Result<Option<(KeychainKind, u32)>, Error> {
+        match self.select_script_pubkey_by_script(script.as_bytes())? {
+            Some((keychain, child)) => Ok(Some((keychain, child))),
+            None => Ok(None),
+        }
+    }
+
+    fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<LocalUtxo>, Error> {
+        match self.select_utxo_by_outpoint(&outpoint.txid, outpoint.vout)? {
+            Some((value, keychain, script_pubkey)) => Ok(Some(LocalUtxo {
+                outpoint: *outpoint,
+                txout: TxOut {
+                    value,
+                    script_pubkey,
+                },
+                keychain,
+            })),
+            None => Ok(None),
+        }
+    }
+
+    fn get_raw_tx(&self, txid: &Txid) -> Result<Option<Transaction>, Error> {
+        match self.select_transaction_by_txid(txid)? {
+            Some(tx) => Ok(Some(tx)),
+            None => Ok(None),
+        }
+    }
+
+    fn get_tx(&self, txid: &Txid, include_raw: bool) -> Result<Option<TransactionDetails>, Error> {
+        match self.select_transaction_details_by_txid(txid)? {
+            Some(mut transaction_details) => {
+                if !include_raw {
+                    transaction_details.transaction = None;
+                }
+                Ok(Some(transaction_details))
+            }
+            None => Ok(None),
+        }
+    }
+
+    fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
+        let keychain = serde_json::to_string(&keychain)?;
+        let value = self.select_last_derivation_index_by_keychain(keychain)?;
+        Ok(value)
+    }
+
+    fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> {
+        let keychain_string = serde_json::to_string(&keychain)?;
+        match self.get_last_index(keychain)? {
+            Some(value) => {
+                self.update_last_derivation_index(keychain_string, value + 1)?;
+                Ok(value + 1)
+            }
+            None => {
+                self.insert_last_derivation_index(keychain_string, 0)?;
+                Ok(0)
+            }
+        }
+    }
+
+    fn flush(&mut self) -> Result<(), Error> {
+        Ok(())
+    }
+}
+
+impl BatchDatabase for SqliteDatabase {
+    type Batch = SqliteDatabase;
+
+    fn begin_batch(&self) -> Self::Batch {
+        let db = SqliteDatabase::new(self.path.clone());
+        db.connection.execute("BEGIN TRANSACTION", []).unwrap();
+        db
+    }
+
+    fn commit_batch(&mut self, batch: Self::Batch) -> Result<(), Error> {
+        batch.connection.execute("COMMIT TRANSACTION", [])?;
+        Ok(())
+    }
+}
+
+pub fn get_connection(path: &str) -> Result<Connection, Error> {
+    let connection = Connection::open(path)?;
+    migrate(&connection)?;
+    Ok(connection)
+}
+
+pub fn get_schema_version(conn: &Connection) -> rusqlite::Result<i32> {
+    let statement = conn.prepare_cached("SELECT version FROM version");
+    match statement {
+        Err(rusqlite::Error::SqliteFailure(e, Some(msg))) => {
+            if msg == "no such table: version" {
+                Ok(0)
+            } else {
+                Err(rusqlite::Error::SqliteFailure(e, Some(msg)))
+            }
+        }
+        Ok(mut stmt) => {
+            let mut rows = stmt.query([])?;
+            match rows.next()? {
+                Some(row) => {
+                    let version: i32 = row.get(0)?;
+                    Ok(version)
+                }
+                None => Ok(0),
+            }
+        }
+        _ => Ok(0),
+    }
+}
+
+pub fn set_schema_version(conn: &Connection, version: i32) -> rusqlite::Result<usize> {
+    conn.execute(
+        "UPDATE version SET version=:version",
+        named_params! {":version": version},
+    )
+}
+
+pub fn migrate(conn: &Connection) -> rusqlite::Result<()> {
+    let version = get_schema_version(conn)?;
+    let stmts = &MIGRATIONS[(version as usize)..];
+    let mut i: i32 = version;
+
+    if version == MIGRATIONS.len() as i32 {
+        log::info!("db up to date, no migration needed");
+        return Ok(());
+    }
+
+    for stmt in stmts {
+        let res = conn.execute(stmt, []);
+        if res.is_err() {
+            println!("migration failed on:\n{}\n{:?}", stmt, res);
+            break;
+        }
+
+        i += 1;
+    }
+
+    set_schema_version(conn, i)?;
+
+    Ok(())
+}
+
+#[cfg(test)]
+pub mod test {
+    use crate::database::SqliteDatabase;
+    use std::time::{SystemTime, UNIX_EPOCH};
+
+    fn get_database() -> SqliteDatabase {
+        let time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
+        let mut dir = std::env::temp_dir();
+        dir.push(format!("bdk_{}", time.as_nanos()));
+        SqliteDatabase::new(String::from(dir.to_str().unwrap()))
+    }
+
+    #[test]
+    fn test_script_pubkey() {
+        crate::database::test::test_script_pubkey(get_database());
+    }
+
+    #[test]
+    fn test_batch_script_pubkey() {
+        crate::database::test::test_batch_script_pubkey(get_database());
+    }
+
+    #[test]
+    fn test_iter_script_pubkey() {
+        crate::database::test::test_iter_script_pubkey(get_database());
+    }
+
+    #[test]
+    fn test_del_script_pubkey() {
+        crate::database::test::test_del_script_pubkey(get_database());
+    }
+
+    #[test]
+    fn test_utxo() {
+        crate::database::test::test_utxo(get_database());
+    }
+
+    #[test]
+    fn test_raw_tx() {
+        crate::database::test::test_raw_tx(get_database());
+    }
+
+    #[test]
+    fn test_tx() {
+        crate::database::test::test_tx(get_database());
+    }
+
+    #[test]
+    fn test_last_index() {
+        crate::database::test::test_last_index(get_database());
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/checksum.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/checksum.rs.html new file mode 100644 index 0000000000..93562a5060 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/checksum.rs.html @@ -0,0 +1,230 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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::DescriptorError;
+
+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, DescriptorError> {
+    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(DescriptorError::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(DescriptorError::InvalidDescriptorCharacter(invalid_char)) if invalid_char == sparkle_heart
+        ));
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/derived.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/derived.rs.html new file mode 100644 index 0000000000..edd1b2714d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/derived.rs.html @@ -0,0 +1,304 @@ +derived.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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Derived descriptor keys
+
+use std::cmp::Ordering;
+use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::ops::Deref;
+
+use bitcoin::hashes::hash160;
+use bitcoin::PublicKey;
+
+pub use miniscript::{
+    descriptor::KeyMap, descriptor::Wildcard, Descriptor, DescriptorPublicKey, Legacy, Miniscript,
+    ScriptContext, Segwitv0,
+};
+use miniscript::{MiniscriptKey, ToPublicKey, TranslatePk};
+
+use crate::wallet::utils::SecpCtx;
+
+/// Extended [`DescriptorPublicKey`] that has been derived
+///
+/// Derived keys are guaranteed to never contain wildcards of any kind
+#[derive(Debug, Clone)]
+pub struct DerivedDescriptorKey<'s>(DescriptorPublicKey, &'s SecpCtx);
+
+impl<'s> DerivedDescriptorKey<'s> {
+    /// Construct a new derived key
+    ///
+    /// Panics if the key is wildcard
+    pub fn new(key: DescriptorPublicKey, secp: &'s SecpCtx) -> DerivedDescriptorKey<'s> {
+        if let DescriptorPublicKey::XPub(xpub) = &key {
+            assert!(xpub.wildcard == Wildcard::None)
+        }
+
+        DerivedDescriptorKey(key, secp)
+    }
+}
+
+impl<'s> Deref for DerivedDescriptorKey<'s> {
+    type Target = DescriptorPublicKey;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<'s> PartialEq for DerivedDescriptorKey<'s> {
+    fn eq(&self, other: &Self) -> bool {
+        self.0 == other.0
+    }
+}
+
+impl<'s> Eq for DerivedDescriptorKey<'s> {}
+
+impl<'s> PartialOrd for DerivedDescriptorKey<'s> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.0.partial_cmp(&other.0)
+    }
+}
+
+impl<'s> Ord for DerivedDescriptorKey<'s> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.0.cmp(&other.0)
+    }
+}
+
+impl<'s> fmt::Display for DerivedDescriptorKey<'s> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl<'s> Hash for DerivedDescriptorKey<'s> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+impl<'s> MiniscriptKey for DerivedDescriptorKey<'s> {
+    type Hash = Self;
+
+    fn to_pubkeyhash(&self) -> Self::Hash {
+        DerivedDescriptorKey(self.0.to_pubkeyhash(), self.1)
+    }
+
+    fn is_uncompressed(&self) -> bool {
+        self.0.is_uncompressed()
+    }
+    fn serialized_len(&self) -> usize {
+        self.0.serialized_len()
+    }
+}
+
+impl<'s> ToPublicKey for DerivedDescriptorKey<'s> {
+    fn to_public_key(&self) -> PublicKey {
+        match &self.0 {
+            DescriptorPublicKey::SinglePub(ref spub) => spub.key.to_public_key(),
+            DescriptorPublicKey::XPub(ref xpub) => {
+                xpub.xkey
+                    .derive_pub(self.1, &xpub.derivation_path)
+                    .expect("Shouldn't fail, only normal derivations")
+                    .public_key
+            }
+        }
+    }
+
+    fn hash_to_hash160(hash: &Self::Hash) -> hash160::Hash {
+        hash.to_public_key().to_pubkeyhash()
+    }
+}
+
+pub(crate) trait AsDerived {
+    // Derive a descriptor and transform all of its keys to `DerivedDescriptorKey`
+    fn as_derived<'s>(&self, index: u32, secp: &'s SecpCtx)
+        -> Descriptor<DerivedDescriptorKey<'s>>;
+
+    // Transform the keys into `DerivedDescriptorKey`.
+    //
+    // Panics if the descriptor is not "fixed", i.e. if it's derivable
+    fn as_derived_fixed<'s>(&self, secp: &'s SecpCtx) -> Descriptor<DerivedDescriptorKey<'s>>;
+}
+
+impl AsDerived for Descriptor<DescriptorPublicKey> {
+    fn as_derived<'s>(
+        &self,
+        index: u32,
+        secp: &'s SecpCtx,
+    ) -> Descriptor<DerivedDescriptorKey<'s>> {
+        self.derive(index).translate_pk_infallible(
+            |key| DerivedDescriptorKey::new(key.clone(), secp),
+            |key| DerivedDescriptorKey::new(key.clone(), secp),
+        )
+    }
+
+    fn as_derived_fixed<'s>(&self, secp: &'s SecpCtx) -> Descriptor<DerivedDescriptorKey<'s>> {
+        assert!(!self.is_deriveable());
+
+        self.as_derived(0, secp)
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/dsl.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/dsl.rs.html new file mode 100644 index 0000000000..4914cdfc1d --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/dsl.rs.html @@ -0,0 +1,2134 @@ +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
+ 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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Descriptors DSL
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_top_level_sh {
+    // disallow `sortedmulti` in `bare()`
+    ( Bare, new, new, Legacy, sortedmulti $( $inner:tt )* ) => {
+        compile_error!("`bare()` descriptors can't contain any `sortedmulti()` operands");
+    };
+    ( Bare, new, new, Legacy, sortedmulti_vec $( $inner:tt )* ) => {
+        compile_error!("`bare()` descriptors can't contain any `sortedmulti_vec()` operands");
+    };
+
+    ( $inner_struct:ident, $constructor:ident, $sortedmulti_constructor:ident, $ctx:ident, sortedmulti $( $inner:tt )* ) => {{
+        use std::marker::PhantomData;
+
+        use $crate::miniscript::descriptor::{$inner_struct, Descriptor, DescriptorPublicKey};
+        use $crate::miniscript::$ctx;
+
+        let build_desc = |k, pks| {
+            Ok((Descriptor::<DescriptorPublicKey>::$inner_struct($inner_struct::$sortedmulti_constructor(k, pks)?), PhantomData::<$ctx>))
+        };
+
+        $crate::impl_sortedmulti!(build_desc, sortedmulti $( $inner )*)
+    }};
+    ( $inner_struct:ident, $constructor:ident, $sortedmulti_constructor:ident, $ctx:ident, sortedmulti_vec $( $inner:tt )* ) => {{
+        use std::marker::PhantomData;
+
+        use $crate::miniscript::descriptor::{$inner_struct, Descriptor, DescriptorPublicKey};
+        use $crate::miniscript::$ctx;
+
+        let build_desc = |k, pks| {
+            Ok((Descriptor::<DescriptorPublicKey>::$inner_struct($inner_struct::$sortedmulti_constructor(k, pks)?), PhantomData::<$ctx>))
+        };
+
+        $crate::impl_sortedmulti!(build_desc, sortedmulti_vec $( $inner )*)
+    }};
+
+    ( $inner_struct:ident, $constructor:ident, $sortedmulti_constructor:ident, $ctx:ident, $( $minisc:tt )* ) => {{
+        use $crate::miniscript::descriptor::{$inner_struct, Descriptor, DescriptorPublicKey};
+
+        $crate::fragment!($( $minisc )*)
+            .and_then(|(minisc, keymap, networks)| Ok(($inner_struct::$constructor(minisc)?, keymap, networks)))
+            .and_then(|(inner, key_map, valid_networks)| Ok((Descriptor::<DescriptorPublicKey>::$inner_struct(inner), key_map, valid_networks)))
+    }};
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_top_level_pk {
+    ( $inner_type:ident, $ctx:ty, $key:expr ) => {{
+        use $crate::miniscript::descriptor::$inner_type;
+
+        #[allow(unused_imports)]
+        use $crate::keys::{DescriptorKey, IntoDescriptorKey};
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+
+        $key.into_descriptor_key()
+            .and_then(|key: DescriptorKey<$ctx>| key.extract(&secp))
+            .map_err($crate::descriptor::DescriptorError::Key)
+            .map(|(pk, key_map, valid_networks)| ($inner_type::new(pk), key_map, valid_networks))
+    }};
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_leaf_opcode {
+    ( $terminal_variant:ident ) => {{
+        use $crate::descriptor::CheckMiniscript;
+
+        $crate::miniscript::Miniscript::from_ast(
+            $crate::miniscript::miniscript::decode::Terminal::$terminal_variant,
+        )
+        .map_err($crate::descriptor::DescriptorError::Miniscript)
+        .and_then(|minisc| {
+            minisc.check_minsicript()?;
+            Ok(minisc)
+        })
+        .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 ) => {{
+        use $crate::descriptor::CheckMiniscript;
+
+        $crate::miniscript::Miniscript::from_ast(
+            $crate::miniscript::miniscript::decode::Terminal::$terminal_variant($value),
+        )
+        .map_err($crate::descriptor::DescriptorError::Miniscript)
+        .and_then(|minisc| {
+            minisc.check_minsicript()?;
+            Ok(minisc)
+        })
+        .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 ) => {{
+        use $crate::descriptor::CheckMiniscript;
+
+        $crate::miniscript::Miniscript::from_ast(
+            $crate::miniscript::miniscript::decode::Terminal::$terminal_variant($one, $two),
+        )
+        .map_err($crate::descriptor::DescriptorError::Miniscript)
+        .and_then(|minisc| {
+            minisc.check_minsicript()?;
+            Ok(minisc)
+        })
+        .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, $( $inner:tt )* ) => ({
+        use $crate::descriptor::CheckMiniscript;
+
+        let inner = $crate::fragment_internal!( @t $( $inner )* );
+        let (a, b) = $crate::descriptor::dsl::TupleTwo::from(inner).flattened();
+
+        a
+            .and_then(|a| Ok((a, 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());
+
+                let minisc = $crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
+                    std::sync::Arc::new(a_minisc),
+                    std::sync::Arc::new(b_minisc),
+                ))?;
+
+                minisc.check_minsicript()?;
+
+                Ok((minisc, a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks)))
+            })
+    });
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_node_opcode_three {
+    ( $terminal_variant:ident, $( $inner:tt )* ) => ({
+        use $crate::descriptor::CheckMiniscript;
+
+        let inner = $crate::fragment_internal!( @t $( $inner )* );
+        let (a, b, c) = $crate::descriptor::dsl::TupleThree::from(inner).flattened();
+
+        a
+            .and_then(|a| Ok((a, b?, 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);
+
+                let minisc = $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),
+                ))?;
+
+                minisc.check_minsicript()?;
+
+                Ok((minisc, a_keymap, networks))
+            })
+    });
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! impl_sortedmulti {
+    ( $build_desc:expr, sortedmulti_vec ( $thresh:expr, $keys:expr ) ) => ({
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+        $crate::keys::make_sortedmulti($thresh, $keys, $build_desc, &secp)
+    });
+    ( $build_desc:expr, sortedmulti ( $thresh:expr $(, $key:expr )+ ) ) => ({
+        use $crate::keys::IntoDescriptorKey;
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+
+        let keys = vec![
+            $(
+                $key.into_descriptor_key(),
+            )*
+        ];
+
+        keys.into_iter().collect::<Result<Vec<_>, _>>()
+            .map_err($crate::descriptor::DescriptorError::Key)
+            .and_then(|keys| $crate::keys::make_sortedmulti($thresh, keys, $build_desc, &secp))
+    });
+
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! apply_modifier {
+    ( $terminal_variant:ident, $inner:expr ) => {{
+        use $crate::descriptor::CheckMiniscript;
+
+        $inner
+            .map_err(|e| -> $crate::descriptor::DescriptorError { e.into() })
+            .and_then(|(minisc, keymap, networks)| {
+                let minisc = $crate::miniscript::Miniscript::from_ast(
+                    $crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
+                        std::sync::Arc::new(minisc),
+                    ),
+                )?;
+
+                minisc.check_minsicript()?;
+
+                Ok((minisc, keymap, networks))
+            })
+    }};
+
+    ( a: $inner:expr ) => {{
+        $crate::apply_modifier!(Alt, $inner)
+    }};
+    ( s: $inner:expr ) => {{
+        $crate::apply_modifier!(Swap, $inner)
+    }};
+    ( c: $inner:expr ) => {{
+        $crate::apply_modifier!(Check, $inner)
+    }};
+    ( d: $inner:expr ) => {{
+        $crate::apply_modifier!(DupIf, $inner)
+    }};
+    ( v: $inner:expr ) => {{
+        $crate::apply_modifier!(Verify, $inner)
+    }};
+    ( j: $inner:expr ) => {{
+        $crate::apply_modifier!(NonZero, $inner)
+    }};
+    ( n: $inner:expr ) => {{
+        $crate::apply_modifier!(ZeroNotEqual, $inner)
+    }};
+
+    // Modifiers expanded to other operators
+    ( t: $inner:expr ) => {{
+        $inner.and_then(|(a_minisc, a_keymap, a_networks)| {
+            $crate::impl_leaf_opcode_value_two!(
+                AndV,
+                std::sync::Arc::new(a_minisc),
+                std::sync::Arc::new($crate::fragment!(true).unwrap().0)
+            )
+            .map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
+        })
+    }};
+    ( l: $inner:expr ) => {{
+        $inner.and_then(|(a_minisc, a_keymap, a_networks)| {
+            $crate::impl_leaf_opcode_value_two!(
+                OrI,
+                std::sync::Arc::new($crate::fragment!(false).unwrap().0),
+                std::sync::Arc::new(a_minisc)
+            )
+            .map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
+        })
+    }};
+    ( u: $inner:expr ) => {{
+        $inner.and_then(|(a_minisc, a_keymap, a_networks)| {
+            $crate::impl_leaf_opcode_value_two!(
+                OrI,
+                std::sync::Arc::new(a_minisc),
+                std::sync::Arc::new($crate::fragment!(false).unwrap().0)
+            )
+            .map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
+        })
+    }};
+}
+
+/// Macro to write full descriptors with code
+///
+/// This macro expands to a `Result` of
+/// [`DescriptorTemplateOut`](super::template::DescriptorTemplateOut) and [`DescriptorError`](crate::descriptor::DescriptorError)
+///
+/// The syntax is very similar to the normal descriptor syntax, with the exception that modifiers
+/// cannot be grouped together. For instance, a descriptor fragment like `sdv:older(144)` has to be
+/// broken up to `s:d:v:older(144)`.
+///
+/// The `pk()`, `pk_k()` and `pk_h()` operands can take as argument any type that implements
+/// [`IntoDescriptorKey`]. This means that keys can also be written inline as strings, but in that
+/// case they must be wrapped in quotes, which is another difference compared to the standard
+/// descriptor syntax.
+///
+/// [`IntoDescriptorKey`]: crate::keys::IntoDescriptorKey
+///
+/// ## Example
+///
+/// Signature plus timelock descriptor:
+///
+/// ```
+/// # use std::str::FromStr;
+/// let (my_descriptor, my_keys_map, networks) = bdk::descriptor!(sh(wsh(and_v(v:pk("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"),older(50)))))?;
+/// # 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))
+///     )
+/// }?;
+///
+/// #[rustfmt::skip]
+/// 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, new, new, Legacy, $( $minisc )*)
+    });
+    ( sh ( wsh ( $( $minisc:tt )* ) ) ) => ({
+        $crate::descriptor!(shwsh ($( $minisc )*))
+    });
+    ( shwsh ( $( $minisc:tt )* ) ) => ({
+        $crate::impl_top_level_sh!(Sh, new_wsh, new_wsh_sortedmulti, Segwitv0, $( $minisc )*)
+    });
+    ( pk ( $key:expr ) ) => ({
+        // `pk()` is actually implemented as `bare(pk())`
+        $crate::descriptor!( bare ( pk ( $key ) ) )
+    });
+    ( pkh ( $key:expr ) ) => ({
+        use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey};
+
+        $crate::impl_top_level_pk!(Pkh, $crate::miniscript::Legacy, $key)
+            .map(|(a, b, c)| (Descriptor::<DescriptorPublicKey>::Pkh(a), b, c))
+    });
+    ( wpkh ( $key:expr ) ) => ({
+        use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey};
+
+        $crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key)
+            .and_then(|(a, b, c)| Ok((a?, b, c)))
+            .map(|(a, b, c)| (Descriptor::<DescriptorPublicKey>::Wpkh(a), b, c))
+    });
+    ( sh ( wpkh ( $key:expr ) ) ) => ({
+        $crate::descriptor!(shwpkh ( $key ))
+    });
+    ( shwpkh ( $key:expr ) ) => ({
+        use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey, Sh};
+
+        $crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key)
+            .and_then(|(a, b, c)| Ok((a?, b, c)))
+            .and_then(|(a, b, c)| Ok((Descriptor::<DescriptorPublicKey>::Sh(Sh::new_wpkh(a.into_inner())?), b, c)))
+    });
+    ( sh ( $( $minisc:tt )* ) ) => ({
+        $crate::impl_top_level_sh!(Sh, new, new_sortedmulti, Legacy, $( $minisc )*)
+    });
+    ( wsh ( $( $minisc:tt )* ) ) => ({
+        $crate::impl_top_level_sh!(Wsh, new, new_sortedmulti, Segwitv0, $( $minisc )*)
+    });
+}
+
+#[doc(hidden)]
+pub struct TupleTwo<A, B> {
+    pub a: A,
+    pub b: B,
+}
+
+impl<A, B> TupleTwo<A, B> {
+    pub fn flattened(self) -> (A, B) {
+        (self.a, self.b)
+    }
+}
+
+impl<A, B> From<(A, (B, ()))> for TupleTwo<A, B> {
+    fn from((a, (b, _)): (A, (B, ()))) -> Self {
+        TupleTwo { a, b }
+    }
+}
+
+#[doc(hidden)]
+pub struct TupleThree<A, B, C> {
+    pub a: A,
+    pub b: B,
+    pub c: C,
+}
+
+impl<A, B, C> TupleThree<A, B, C> {
+    pub fn flattened(self) -> (A, B, C) {
+        (self.a, self.b, self.c)
+    }
+}
+
+impl<A, B, C> From<(A, (B, (C, ())))> for TupleThree<A, B, C> {
+    fn from((a, (b, (c, _))): (A, (B, (C, ())))) -> Self {
+        TupleThree { a, b, c }
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! fragment_internal {
+    // The @v prefix is used to parse a sequence of operands and return them in a vector. This is
+    // used by operands that take a variable number of arguments, like `thresh()` and `multi()`.
+    ( @v $op:ident ( $( $args:tt )* ) $( $tail:tt )* ) => ({
+        let mut v = vec![$crate::fragment!( $op ( $( $args )* ) )];
+        v.append(&mut $crate::fragment_internal!( @v $( $tail )* ));
+
+        v
+    });
+    // Match modifiers
+    ( @v $modif:tt : $( $tail:tt )* ) => ({
+        let mut v = $crate::fragment_internal!( @v $( $tail )* );
+        let first = v.drain(..1).next().unwrap();
+
+        let first = $crate::apply_modifier!($modif:first);
+
+        let mut v_final = vec![first];
+        v_final.append(&mut v);
+
+        v_final
+    });
+    // Remove commas between operands
+    ( @v , $( $tail:tt )* ) => ({
+        $crate::fragment_internal!( @v $( $tail )* )
+    });
+    ( @v ) => ({
+        vec![]
+    });
+
+    // The @t prefix is used to parse a sequence of operands and return them in a tuple. This
+    // allows checking at compile-time the number of arguments passed to an operand. For this
+    // reason it's used by `and_*()`, `or_*()`, etc.
+    //
+    // Unfortunately, due to the fact that concatenating tuples is pretty hard, the final result
+    // adds in the first spot the parsed operand and in the second spot the result of parsing
+    // all the following ones. For two operands the type then corresponds to: (X, (X, ())). For
+    // three operands it's (X, (X, (X, ()))), etc.
+    //
+    // To check that the right number of arguments has been passed we can "cast" those tuples to
+    // more convenient structures like `TupleTwo`. If the conversion succedes, the right number of
+    // args was passed. Otherwise the compilation fails entirely.
+    ( @t $op:ident ( $( $args:tt )* ) $( $tail:tt )* ) => ({
+        ($crate::fragment!( $op ( $( $args )* ) ), $crate::fragment_internal!( @t $( $tail )* ))
+    });
+    // Match modifiers
+    ( @t $modif:tt : $( $tail:tt )* ) => ({
+        let (first, tail) = $crate::fragment_internal!( @t $( $tail )* );
+        ($crate::apply_modifier!($modif:first), tail)
+    });
+    // Remove commas between operands
+    ( @t , $( $tail:tt )* ) => ({
+        $crate::fragment_internal!( @t $( $tail )* )
+    });
+    ( @t ) => ({});
+
+    // Fallback to calling `fragment!()`
+    ( $( $tokens:tt )* ) => ({
+        $crate::fragment!($( $tokens )*)
+    });
+}
+
+/// Macro to write descriptor fragments with code
+///
+/// This macro will be expanded to an object of type `Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), DescriptorError>`. It allows writing
+/// fragments of larger descriptors that can be pieced together using `fragment!(thresh_vec(m, ...))`.
+///
+/// The syntax to write macro fragment is the same as documented for the [`descriptor`] macro.
+#[macro_export]
+macro_rules! fragment {
+    // Modifiers
+    ( $modif:tt : $( $tail:tt )* ) => ({
+        let op = $crate::fragment!( $( $tail )* );
+        $crate::apply_modifier!($modif:op)
+    });
+
+    // 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:expr ) ) => ({
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+        $crate::keys::make_pkh($key, &secp)
+    });
+    ( 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 ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(AndV, $( $inner )*)
+    });
+    ( and_b ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(AndB, $( $inner )*)
+    });
+    ( and_or ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_three!(AndOr, $( $inner )*)
+    });
+    ( andor ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_three!(AndOr, $( $inner )*)
+    });
+    ( or_b ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrB, $( $inner )*)
+    });
+    ( or_d ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrD, $( $inner )*)
+    });
+    ( or_c ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrC, $( $inner )*)
+    });
+    ( or_i ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrI, $( $inner )*)
+    });
+    ( 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, $( $inner:tt )* ) ) => ({
+        let items = $crate::fragment_internal!( @v $( $inner )* );
+
+        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::IntoDescriptorKey;
+        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
+
+        let keys = vec![
+            $(
+                $key.into_descriptor_key(),
+            )*
+        ];
+
+        keys.into_iter().collect::<Result<Vec<_>, _>>()
+            .map_err($crate::descriptor::DescriptorError::Key)
+            .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, DescriptorTrait, KeyMap};
+    use miniscript::{Descriptor, Legacy, Segwitv0};
+
+    use std::str::FromStr;
+
+    use crate::descriptor::{DescriptorError, DescriptorMeta};
+    use crate::keys::{DescriptorKey, IntoDescriptorKey, ValidNetworks};
+    use bitcoin::network::constants::Network::{Bitcoin, Regtest, Signet, Testnet};
+    use bitcoin::util::bip32;
+    use bitcoin::PrivateKey;
+
+    use crate::descriptor::derived::AsDerived;
+
+    // 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), DescriptorError>,
+        is_witness: bool,
+        is_fixed: bool,
+        expected: &[&str],
+    ) {
+        let secp = Secp256k1::new();
+
+        let (desc, _key_map, _networks) = desc.unwrap();
+        assert_eq!(desc.is_witness(), is_witness);
+        assert_eq!(!desc.is_deriveable(), is_fixed);
+        for i in 0..expected.len() {
+            let index = i as u32;
+            let child_desc = if !desc.is_deriveable() {
+                desc.as_derived_fixed(&secp)
+            } else {
+                desc.as_derived(index, &secp)
+            };
+            let address = child_desc.address(Regtest);
+            if let Ok(address) = address {
+                assert_eq!(address.to_string(), *expected.get(i).unwrap());
+            } else {
+                let script = child_desc.script_pubkey();
+                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 IntoDescriptorKey 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_fixed_threeop_descriptors() {
+        let redeem_key = bitcoin::PublicKey::from_str(
+            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
+        )
+        .unwrap();
+        let move_key = bitcoin::PublicKey::from_str(
+            "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
+        )
+        .unwrap();
+
+        check(
+            descriptor!(sh(wsh(and_or(pk(redeem_key), older(1000), pk(move_key))))),
+            true,
+            true,
+            &["2MypGwr5eQWAWWJtiJgUEToVxc4zuokjQRe"],
+        );
+    }
+
+    #[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()).into_descriptor_key().unwrap();
+        check(
+            descriptor!(pk(desc_key)),
+            false,
+            false,
+            &[
+                "2102363ad03c10024e1b597a5b01b9982807fb638e00b06f3b2d4a89707de3b93c37ac",
+                "2102063a21fd780df370ed2fc8c4b86aa5ea642630609c203009df631feb7b480dd2ac",
+                "2102ba2685ad1fa5891cb100f1656b2ce3801822ccb9bac0336734a6f8c1b93ebbc0ac",
+            ],
+        );
+
+        let desc_key = (xprv, path.clone()).into_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).into_descriptor_key().unwrap();
+        let desc_key2 = (xprv, path2).into_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()).into_descriptor_key().unwrap();
+        check(
+            descriptor!(wpkh(desc_key)),
+            true,
+            false,
+            &[
+                "bcrt1qnhm8w9fhc8cxzgqsmqdf9fyjccyvc0gltnymu0",
+                "bcrt1qhylfd55rn75w9fj06zspctad5w4hz33rf0ttad",
+                "bcrt1qq5sq3a6k9av9d8cne0k9wcldy4nqey5yt6889r",
+            ],
+        );
+
+        let desc_key = (xprv, path.clone()).into_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()).into_descriptor_key().unwrap();
+        let desc_key2 = (xprv, path2.clone()).into_descriptor_key().unwrap();
+        check(
+            descriptor!(wsh(multi(1, desc_key1, desc_key2))),
+            true,
+            false,
+            &[
+                "bcrt1qfxv8mxmlv5sz8q2mnuyaqdfe9jr4vvmx0csjhn092p6f4qfygfkq2hng49",
+                "bcrt1qerj85g243e6jlcdxpmn9spk0gefcwvu7nw7ee059d5ydzpdhkm2qwfkf5k",
+                "bcrt1qxkl2qss3k58q9ktc8e89pwr4gnptfpw4hju4xstxcjc0hkcae3jstluty7",
+            ],
+        );
+
+        let desc_key1 = (xprv, path).into_descriptor_key().unwrap();
+        let desc_key2 = (xprv, path2).into_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).into_descriptor_key().unwrap();
+
+        let (_desc, _key_map, valid_networks) = descriptor!(pkh(desc_key)).unwrap();
+        assert_eq!(
+            valid_networks,
+            [Testnet, Regtest, Signet].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).into_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()).into_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()).into_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()).into_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).into_descriptor_key().unwrap();
+        let desc_key2: DescriptorKey<Segwitv0> = (xprv2, path2).into_descriptor_key().unwrap();
+        let desc_key3: DescriptorKey<Segwitv0> = (xprv3, path3).into_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 IntoDescriptorKey<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).into_descriptor_key().unwrap();
+
+        let (desc, _key_map, _valid_networks) = descriptor!(pkh(desc_key)).unwrap();
+        assert_eq!(desc.to_string(), "pkh(tpubD6NzVbkrYhZ4WR7a4vY1VT3khMJMeAxVsfq9TBJyJWrNk247zCJtV7AWf6UJP7rAVsn8NNKdJi3gFyKPTmWZS9iukb91xbn2HbFSMQm2igY/0/*)#yrnz9pp2");
+
+        // as expected this does not compile due to invalid context
+        //let desc_key:DescriptorKey<Segwitv0> = (xprv, path.clone()).into_descriptor_key().unwrap();
+        //let (desc, _key_map, _valid_networks) = descriptor!(pkh(desc_key)).unwrap();
+    }
+
+    #[test]
+    fn test_dsl_modifiers() {
+        let private_key =
+            PrivateKey::from_wif("cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR").unwrap();
+        let (descriptor, _, _) =
+            descriptor!(wsh(thresh(2,d:v:older(1),s:pk(private_key),s:pk(private_key)))).unwrap();
+
+        assert_eq!(descriptor.to_string(), "wsh(thresh(2,dv:older(1),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c)))#cfdcqs3s")
+    }
+
+    #[test]
+    #[should_panic(expected = "Miniscript(ContextError(CompressedOnly))")]
+    fn test_dsl_miniscript_checks() {
+        let mut uncompressed_pk =
+            PrivateKey::from_wif("L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6").unwrap();
+        uncompressed_pk.compressed = false;
+
+        descriptor!(wsh(v: pk(uncompressed_pk))).unwrap();
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/error.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/error.rs.html new file mode 100644 index 0000000000..49cea1f62b --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/error.rs.html @@ -0,0 +1,142 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Descriptor errors
+
+/// Errors related to the parsing and usage of descriptors
+#[derive(Debug)]
+pub enum Error {
+    /// Invalid HD Key path, such as having a wildcard but a length != 1
+    InvalidHdKeyPath,
+    /// The provided descriptor doesn't match its checksum
+    InvalidDescriptorChecksum,
+    /// The descriptor contains hardened derivation steps on public extended keys
+    HardenedDerivationXpub,
+    /// The descriptor contains multiple keys with the same BIP32 fingerprint
+    DuplicatedKeys,
+
+    /// Error thrown while working with [`keys`](crate::keys)
+    Key(crate::keys::KeyError),
+    /// Error while extracting and manipulating policies
+    Policy(crate::descriptor::policy::PolicyError),
+
+    /// Invalid character found in the descriptor checksum
+    InvalidDescriptorCharacter(char),
+
+    /// 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/latest/src/bdk/descriptor/mod.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/mod.rs.html new file mode 100644 index 0000000000..628c70d6f8 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/mod.rs.html @@ -0,0 +1,1612 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Descriptors
+//!
+//! This module contains generic utilities to work with descriptors, plus some re-exported types
+//! from [`miniscript`].
+
+use std::collections::{BTreeMap, HashMap, HashSet};
+use std::ops::Deref;
+
+use bitcoin::util::bip32::{
+    ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey, Fingerprint, KeySource,
+};
+use bitcoin::util::psbt;
+use bitcoin::{Network, PublicKey, Script, TxOut};
+
+use miniscript::descriptor::{DescriptorPublicKey, DescriptorType, DescriptorXKey, Wildcard};
+pub use miniscript::{descriptor::KeyMap, Descriptor, Legacy, Miniscript, ScriptContext, Segwitv0};
+use miniscript::{DescriptorTrait, ForEachKey, TranslatePk};
+
+use crate::descriptor::policy::BuildSatisfaction;
+
+pub mod checksum;
+pub(crate) mod derived;
+#[doc(hidden)]
+pub mod dsl;
+pub mod error;
+pub mod policy;
+pub mod template;
+
+pub use self::checksum::get_checksum;
+use self::derived::AsDerived;
+pub use self::derived::DerivedDescriptorKey;
+pub use self::error::Error as DescriptorError;
+pub use self::policy::Policy;
+use self::template::DescriptorTemplateOut;
+use crate::keys::{IntoDescriptorKey, KeyError};
+use crate::wallet::signer::SignersContainer;
+use crate::wallet::utils::SecpCtx;
+
+/// Alias for a [`Descriptor`] that can contain extended keys using [`DescriptorPublicKey`]
+pub type ExtendedDescriptor = Descriptor<DescriptorPublicKey>;
+
+/// Alias for a [`Descriptor`] that contains extended **derived** keys
+pub type DerivedDescriptor<'s> = Descriptor<DerivedDescriptorKey<'s>>;
+
+/// 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 IntoWalletDescriptor {
+    /// Convert to wallet descriptor
+    fn into_wallet_descriptor(
+        self,
+        secp: &SecpCtx,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError>;
+}
+
+impl IntoWalletDescriptor for &str {
+    fn into_wallet_descriptor(
+        self,
+        secp: &SecpCtx,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
+        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(DescriptorError::InvalidDescriptorChecksum);
+            }
+
+            parts[0]
+        } else {
+            self
+        };
+
+        ExtendedDescriptor::parse_descriptor(secp, descriptor)?
+            .into_wallet_descriptor(secp, network)
+    }
+}
+
+impl IntoWalletDescriptor for &String {
+    fn into_wallet_descriptor(
+        self,
+        secp: &SecpCtx,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
+        self.as_str().into_wallet_descriptor(secp, network)
+    }
+}
+
+impl IntoWalletDescriptor for ExtendedDescriptor {
+    fn into_wallet_descriptor(
+        self,
+        secp: &SecpCtx,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
+        (self, KeyMap::default()).into_wallet_descriptor(secp, network)
+    }
+}
+
+impl IntoWalletDescriptor for (ExtendedDescriptor, KeyMap) {
+    fn into_wallet_descriptor(
+        self,
+        secp: &SecpCtx,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
+        use crate::keys::DescriptorKey;
+
+        let check_key = |pk: &DescriptorPublicKey| {
+            let (pk, _, networks) = if self.0.is_witness() {
+                let desciptor_key: DescriptorKey<miniscript::Segwitv0> =
+                    pk.clone().into_descriptor_key()?;
+                desciptor_key.extract(secp)?
+            } else {
+                let desciptor_key: DescriptorKey<miniscript::Legacy> =
+                    pk.clone().into_descriptor_key()?;
+                desciptor_key.extract(secp)?
+            };
+
+            if networks.contains(&network) {
+                Ok(pk)
+            } else {
+                Err(DescriptorError::Key(KeyError::InvalidNetwork))
+            }
+        };
+
+        // check the network for the keys
+        let translated = self.0.translate_pk(check_key, check_key)?;
+
+        Ok((translated, self.1))
+    }
+}
+
+impl IntoWalletDescriptor for DescriptorTemplateOut {
+    fn into_wallet_descriptor(
+        self,
+        _secp: &SecpCtx,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
+        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(DescriptorError::Key(KeyError::InvalidNetwork))
+            }
+        };
+
+        // fixup the network for keys that need it
+        let translated = self.0.translate_pk(fix_key, fix_key)?;
+
+        Ok((translated, self.1))
+    }
+}
+
+/// Wrapper for `IntoWalletDescriptor` that performs additional checks on the keys contained in the
+/// descriptor
+pub(crate) fn into_wallet_descriptor_checked<T: IntoWalletDescriptor>(
+    inner: T,
+    secp: &SecpCtx,
+    network: Network,
+) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
+    let (descriptor, keymap) = inner.into_wallet_descriptor(secp, network)?;
+
+    // Ensure the keys don't contain any hardened derivation steps or hardened wildcards
+    let descriptor_contains_hardened_steps = descriptor.for_any_key(|k| {
+        if let DescriptorPublicKey::XPub(DescriptorXKey {
+            derivation_path,
+            wildcard,
+            ..
+        }) = k.as_key()
+        {
+            return *wildcard == Wildcard::Hardened
+                || derivation_path.into_iter().any(ChildNumber::is_hardened);
+        }
+
+        false
+    });
+    if descriptor_contains_hardened_steps {
+        return Err(DescriptorError::HardenedDerivationXpub);
+    }
+
+    // Ensure that there are no duplicated keys
+    let mut found_keys = HashSet::new();
+    let descriptor_contains_duplicated_keys = descriptor.for_any_key(|k| {
+        if let DescriptorPublicKey::XPub(xkey) = k.as_key() {
+            let fingerprint = xkey.root_fingerprint(secp);
+            if found_keys.contains(&fingerprint) {
+                return true;
+            }
+
+            found_keys.insert(fingerprint);
+        }
+
+        false
+    });
+    if descriptor_contains_duplicated_keys {
+        return Err(DescriptorError::DuplicatedKeys);
+    }
+
+    Ok((descriptor, keymap))
+}
+
+#[doc(hidden)]
+/// Used internally mainly by the `descriptor!()` and `fragment!()` macros
+pub trait CheckMiniscript<Ctx: miniscript::ScriptContext> {
+    fn check_minsicript(&self) -> Result<(), miniscript::Error>;
+}
+
+impl<Ctx: miniscript::ScriptContext, Pk: miniscript::MiniscriptKey> CheckMiniscript<Ctx>
+    for miniscript::Miniscript<Pk, Ctx>
+{
+    fn check_minsicript(&self) -> Result<(), miniscript::Error> {
+        Ctx::check_global_validity(self)?;
+
+        Ok(())
+    }
+}
+
+/// 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,
+        psbt: BuildSatisfaction,
+        secp: &SecpCtx,
+    ) -> Result<Option<Policy>, DescriptorError>;
+}
+
+pub(crate) trait XKeyUtils {
+    fn full_path(&self, append: &[ChildNumber]) -> DerivationPath;
+    fn root_fingerprint(&self, secp: &SecpCtx) -> Fingerprint;
+}
+
+// FIXME: `InnerXKey` was made private in rust-miniscript, so we have to implement this manually on
+// both `ExtendedPubKey` and `ExtendedPrivKey`.
+//
+// Revert back to using the trait once https://github.com/rust-bitcoin/rust-miniscript/pull/230 is
+// released
+impl XKeyUtils for DescriptorXKey<ExtendedPubKey> {
+    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.wildcard != Wildcard::None {
+            full_path
+                .into_iter()
+                .chain(append.iter())
+                .cloned()
+                .collect()
+        } else {
+            full_path
+        }
+    }
+
+    fn root_fingerprint(&self, _: &SecpCtx) -> Fingerprint {
+        match self.origin {
+            Some((fingerprint, _)) => fingerprint,
+            None => self.xkey.fingerprint(),
+        }
+    }
+}
+impl XKeyUtils for DescriptorXKey<ExtendedPrivKey> {
+    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.wildcard != Wildcard::None {
+            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.fingerprint(secp),
+        }
+    }
+}
+
+pub(crate) trait DerivedDescriptorMeta {
+    fn get_hd_keypaths(&self, secp: &SecpCtx) -> Result<HdKeyPaths, DescriptorError>;
+}
+
+pub(crate) trait DescriptorMeta {
+    fn is_witness(&self) -> bool;
+    fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, DescriptorError>;
+    fn derive_from_hd_keypaths<'s>(
+        &self,
+        hd_keypaths: &HdKeyPaths,
+        secp: &'s SecpCtx,
+    ) -> Option<DerivedDescriptor<'s>>;
+    fn derive_from_psbt_input<'s>(
+        &self,
+        psbt_input: &psbt::Input,
+        utxo: Option<TxOut>,
+        secp: &'s SecpCtx,
+    ) -> Option<DerivedDescriptor<'s>>;
+}
+
+pub(crate) trait DescriptorScripts {
+    fn psbt_redeem_script(&self) -> Option<Script>;
+    fn psbt_witness_script(&self) -> Option<Script>;
+}
+
+impl<'s> DescriptorScripts for DerivedDescriptor<'s> {
+    fn psbt_redeem_script(&self) -> Option<Script> {
+        match self.desc_type() {
+            DescriptorType::ShWpkh => Some(self.explicit_script()),
+            DescriptorType::ShWsh => Some(self.explicit_script().to_v0_p2wsh()),
+            DescriptorType::Sh => Some(self.explicit_script()),
+            DescriptorType::Bare => Some(self.explicit_script()),
+            DescriptorType::ShSortedMulti => Some(self.explicit_script()),
+            _ => None,
+        }
+    }
+
+    fn psbt_witness_script(&self) -> Option<Script> {
+        match self.desc_type() {
+            DescriptorType::Wsh => Some(self.explicit_script()),
+            DescriptorType::ShWsh => Some(self.explicit_script()),
+            DescriptorType::WshSortedMulti | DescriptorType::ShWshSortedMulti => {
+                Some(self.explicit_script())
+            }
+            _ => None,
+        }
+    }
+}
+
+impl DescriptorMeta for ExtendedDescriptor {
+    fn is_witness(&self) -> bool {
+        matches!(
+            self.desc_type(),
+            DescriptorType::Wpkh
+                | DescriptorType::ShWpkh
+                | DescriptorType::Wsh
+                | DescriptorType::ShWsh
+                | DescriptorType::ShWshSortedMulti
+                | DescriptorType::WshSortedMulti
+        )
+    }
+
+    fn get_extended_keys(&self) -> Result<Vec<DescriptorXKey<ExtendedPubKey>>, DescriptorError> {
+        let mut answer = Vec::new();
+
+        self.for_each_key(|pk| {
+            if let DescriptorPublicKey::XPub(xpub) = pk.as_key() {
+                answer.push(xpub.clone());
+            }
+
+            true
+        });
+
+        Ok(answer)
+    }
+
+    fn derive_from_hd_keypaths<'s>(
+        &self,
+        hd_keypaths: &HdKeyPaths,
+        secp: &'s SecpCtx,
+    ) -> Option<DerivedDescriptor<'s>> {
+        let index: HashMap<_, _> = hd_keypaths.values().map(|(a, b)| (a, b)).collect();
+
+        let mut path_found = None;
+        self.for_each_key(|key| {
+            if path_found.is_some() {
+                // already found a matching path, we are done
+                return true;
+            }
+
+            if let DescriptorPublicKey::XPub(xpub) = key.as_key().deref() {
+                // 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.wildcard != Wildcard::None && path.len() == 1 => {
+                        // Ignore hardened wildcards
+                        if let ChildNumber::Normal { index } = path[0] {
+                            path_found = Some(index)
+                        }
+                    }
+                    Some(path) if xpub.wildcard == Wildcard::None && path.is_empty() => {
+                        path_found = Some(0)
+                    }
+                    _ => {}
+                }
+            }
+
+            true
+        });
+
+        path_found.map(|path| self.as_derived(path, secp))
+    }
+
+    fn derive_from_psbt_input<'s>(
+        &self,
+        psbt_input: &psbt::Input,
+        utxo: Option<TxOut>,
+        secp: &'s SecpCtx,
+    ) -> Option<DerivedDescriptor<'s>> {
+        if let Some(derived) = self.derive_from_hd_keypaths(&psbt_input.bip32_derivation, secp) {
+            return Some(derived);
+        }
+        if self.is_deriveable() {
+            // We can't try to bruteforce the derivation index, exit here
+            return None;
+        }
+
+        let descriptor = self.as_derived_fixed(secp);
+        match descriptor.desc_type() {
+            // TODO: add pk() here
+            DescriptorType::Pkh | DescriptorType::Wpkh | DescriptorType::ShWpkh
+                if utxo.is_some()
+                    && descriptor.script_pubkey() == utxo.as_ref().unwrap().script_pubkey =>
+            {
+                Some(descriptor)
+            }
+            DescriptorType::Bare | DescriptorType::Sh | DescriptorType::ShSortedMulti
+                if psbt_input.redeem_script.is_some()
+                    && &descriptor.explicit_script()
+                        == psbt_input.redeem_script.as_ref().unwrap() =>
+            {
+                Some(descriptor)
+            }
+            DescriptorType::Wsh
+            | DescriptorType::ShWsh
+            | DescriptorType::ShWshSortedMulti
+            | DescriptorType::WshSortedMulti
+                if psbt_input.witness_script.is_some()
+                    && &descriptor.explicit_script()
+                        == psbt_input.witness_script.as_ref().unwrap() =>
+            {
+                Some(descriptor)
+            }
+            _ => None,
+        }
+    }
+}
+
+impl<'s> DerivedDescriptorMeta for DerivedDescriptor<'s> {
+    fn get_hd_keypaths(&self, secp: &SecpCtx) -> Result<HdKeyPaths, DescriptorError> {
+        let mut answer = BTreeMap::new();
+        self.for_each_key(|key| {
+            if let DescriptorPublicKey::XPub(xpub) = key.as_key().deref() {
+                let derived_pubkey = xpub
+                    .xkey
+                    .derive_pub(secp, &xpub.derivation_path)
+                    .expect("Derivation can't fail");
+
+                answer.insert(
+                    derived_pubkey.public_key,
+                    (xpub.root_fingerprint(secp), xpub.full_path(&[])),
+                );
+            }
+
+            true
+        });
+
+        Ok(answer)
+    }
+}
+
+#[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, IntoDescriptorKey};
+
+        let secp = Secp256k1::new();
+
+        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).into_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
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+
+        assert_eq!(wallet_desc.to_string(), "wpkh(tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)#y8p7e8kk");
+    }
+
+    // test IntoWalletDescriptor trait from &str with and without checksum appended
+    #[test]
+    fn test_descriptor_from_str_with_checksum() {
+        let secp = Secp256k1::new();
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#tqz0nc62"
+            .into_wallet_descriptor(&secp, Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
+            .into_wallet_descriptor(&secp, Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)#67ju93jw"
+            .into_wallet_descriptor(&secp, Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
+            .into_wallet_descriptor(&secp, Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw"
+            .into_wallet_descriptor(&secp, Network::Testnet);
+        assert!(matches!(
+            desc.err(),
+            Some(DescriptorError::InvalidDescriptorChecksum)
+        ));
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)#67ju93jw"
+            .into_wallet_descriptor(&secp, Network::Testnet);
+        assert!(matches!(
+            desc.err(),
+            Some(DescriptorError::InvalidDescriptorChecksum)
+        ));
+    }
+
+    // test IntoWalletDescriptor trait from &str with keys from right and wrong network
+    #[test]
+    fn test_descriptor_from_str_with_keys_network() {
+        let secp = Secp256k1::new();
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
+            .into_wallet_descriptor(&secp, Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
+            .into_wallet_descriptor(&secp, Network::Regtest);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
+            .into_wallet_descriptor(&secp, Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
+            .into_wallet_descriptor(&secp, Network::Regtest);
+        assert!(desc.is_ok());
+
+        let desc = "sh(wpkh(02864bb4ad00cefa806098a69e192bbda937494e69eb452b87bb3f20f6283baedb))"
+            .into_wallet_descriptor(&secp, Network::Testnet);
+        assert!(desc.is_ok());
+
+        let desc = "sh(wpkh(02864bb4ad00cefa806098a69e192bbda937494e69eb452b87bb3f20f6283baedb))"
+            .into_wallet_descriptor(&secp, Network::Bitcoin);
+        assert!(desc.is_ok());
+
+        let desc = "wpkh(tprv8ZgxMBicQKsPdpkqS7Eair4YxjcuuvDPNYmKX3sCniCf16tHEVrjjiSXEkFRnUH77yXc6ZcwHHcLNfjdi5qUvw3VDfgYiH5mNsj5izuiu2N/1/2/*)"
+            .into_wallet_descriptor(&secp, Network::Bitcoin);
+        assert!(matches!(
+            desc.err(),
+            Some(DescriptorError::Key(KeyError::InvalidNetwork))
+        ));
+
+        let desc = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)"
+            .into_wallet_descriptor(&secp, Network::Bitcoin);
+        assert!(matches!(
+            desc.err(),
+            Some(DescriptorError::Key(KeyError::InvalidNetwork))
+        ));
+    }
+
+    // test IntoWalletDescriptor trait from the output of the descriptor!() macro
+    #[test]
+    fn test_descriptor_from_str_from_output_of_macro() {
+        let secp = Secp256k1::new();
+
+        let tpub = bip32::ExtendedPubKey::from_str("tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK").unwrap();
+        let path = bip32::DerivationPath::from_str("m/1/2").unwrap();
+        let key = (tpub, path).into_descriptor_key().unwrap();
+
+        // make a descriptor out of it
+        let desc = crate::descriptor!(wpkh(key)).unwrap();
+
+        let (wallet_desc, _) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let wallet_desc_str = wallet_desc.to_string();
+        assert_eq!(wallet_desc_str, "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/2/*)#67ju93jw");
+
+        let (wallet_desc2, _) = wallet_desc_str
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        assert_eq!(wallet_desc, wallet_desc2)
+    }
+
+    #[test]
+    fn test_into_wallet_descriptor_checked() {
+        let secp = Secp256k1::new();
+
+        let descriptor = "wpkh(tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0'/1/2/*)";
+        let result = into_wallet_descriptor_checked(descriptor, &secp, Network::Testnet);
+
+        assert!(result.is_err());
+        assert!(matches!(
+            result.unwrap_err(),
+            DescriptorError::HardenedDerivationXpub
+        ));
+
+        let descriptor = "wsh(multi(2,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/0/*,tpubD6NzVbkrYhZ4XHndKkuB8FifXm8r5FQHwrN6oZuWCz13qb93rtgKvD4PQsqC4HP4yhV3tA2fqr2RbY5mNXfM7RxXUoeABoDtsFUq2zJq6YK/1/*))";
+        let result = into_wallet_descriptor_checked(descriptor, &secp, Network::Testnet);
+
+        assert!(result.is_err());
+        assert!(matches!(
+            result.unwrap_err(),
+            DescriptorError::DuplicatedKeys
+        ));
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/policy.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/policy.rs.html new file mode 100644 index 0000000000..98bb3b3e19 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/policy.rs.html @@ -0,0 +1,3208 @@ +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
+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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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;
+//! use bdk::descriptor::policy::BuildSatisfaction;
+//! 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(&secp, desc)?;
+//! println!("{:?}", extended_desc);
+//!
+//! let signers = Arc::new(key_map.into());
+//! let policy = extended_desc.extract_policy(&signers, BuildSatisfaction::None, &secp)?;
+//! println!("policy: {}", serde_json::to_string(&policy)?);
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use std::cmp::max;
+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, ShInner, SortedMultiVec, WshInner};
+use miniscript::{Descriptor, Miniscript, MiniscriptKey, Satisfier, ScriptContext, Terminal};
+
+#[allow(unused_imports)]
+use log::{debug, error, info, trace};
+
+use crate::descriptor::ExtractPolicy;
+use crate::wallet::signer::{SignerId, SignersContainer};
+use crate::wallet::utils::{self, After, Older, SecpCtx};
+
+use super::checksum::get_checksum;
+use super::error::Error;
+use super::XKeyUtils;
+use bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
+use miniscript::psbt::PsbtInputSatisfier;
+
+/// 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()
+            },
+        }
+    }
+}
+
+/// 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 or are satisfied in the PSBT
+        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) {
+        // 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,
+                };
+            }
+        }
+    }
+}
+
+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 much a given PSBT already satisfies this policy node in terms of signatures
+    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, PartialEq, Eq)]
+pub enum PolicyError {
+    /// Not enough items are selected to satisfy a [`SatisfiableItem::Thresh`] or a [`SatisfiableItem::Multisig`]
+    NotEnoughItemsSelected(String),
+    /// Index out of range for an item to satisfy a [`SatisfiableItem::Thresh`] or a [`SatisfiableItem::Multisig`]
+    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,
+        };
+        let mut satisfaction = contribution.clone();
+        for (index, item) in items.iter().enumerate() {
+            contribution.add(&item.contribution, index)?;
+            satisfaction.add(&item.satisfaction, index)?;
+        }
+
+        contribution.finalize();
+        satisfaction.finalize();
+
+        let mut policy: Policy = SatisfiableItem::Thresh { items, threshold }.into();
+        policy.contribution = contribution;
+        policy.satisfaction = satisfaction;
+
+        Ok(Some(policy))
+    }
+
+    fn make_multisig(
+        keys: &[DescriptorPublicKey],
+        signers: &SignersContainer,
+        build_sat: BuildSatisfaction,
+        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),
+        };
+        let mut satisfaction = contribution.clone();
+
+        for (index, key) in keys.iter().enumerate() {
+            if signers.find(signer_id(key, secp)).is_some() {
+                contribution.add(
+                    &Satisfaction::Complete {
+                        condition: Default::default(),
+                    },
+                    index,
+                )?;
+            }
+
+            if let Some(psbt) = build_sat.psbt() {
+                if signature_in_psbt(psbt, key, secp) {
+                    satisfaction.add(
+                        &Satisfaction::Complete {
+                            condition: Default::default(),
+                        },
+                        index,
+                    )?;
+                }
+            }
+        }
+        satisfaction.finalize();
+        contribution.finalize();
+
+        let mut policy: Policy = SatisfiableItem::Multisig {
+            keys: parsed_keys,
+            threshold,
+        }
+        .into();
+        policy.contribution = contribution;
+        policy.satisfaction = satisfaction;
+
+        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()
+            }
+            SatisfiableItem::Multisig { keys, .. } => (0..keys.len()).collect(),
+            _ => vec![],
+        };
+        let selected = match path.get(&self.id) {
+            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
+                if selected.len() < *threshold {
+                    return Err(PolicyError::NotEnoughItemsSelected(self.id.clone()));
+                }
+
+                // 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)
+            }
+            SatisfiableItem::Multisig { keys, threshold } => {
+                if selected.len() < *threshold {
+                    return Err(PolicyError::NotEnoughItemsSelected(self.id.clone()));
+                }
+                if let Some(item) = selected.iter().find(|i| **i >= keys.len()) {
+                    return Err(PolicyError::IndexOutOfRange(*item));
+                }
+
+                Ok(Condition::default())
+            }
+            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,
+    build_sat: BuildSatisfaction,
+    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
+    };
+
+    if let Some(psbt) = build_sat.psbt() {
+        policy.satisfaction = if signature_in_psbt(psbt, key, secp) {
+            Satisfaction::Complete {
+                condition: Default::default(),
+            }
+        } else {
+            Satisfaction::None
+        };
+    }
+
+    policy
+}
+
+fn signature_in_psbt(psbt: &Psbt, key: &DescriptorPublicKey, secp: &SecpCtx) -> bool {
+    //TODO check signature validity
+    psbt.inputs.iter().all(|input| match key {
+        DescriptorPublicKey::SinglePub(key) => input.partial_sigs.contains_key(&key.key),
+        DescriptorPublicKey::XPub(xpub) => {
+            let pubkey = input
+                .bip32_derivation
+                .iter()
+                .find(|(_, (f, _))| *f == xpub.root_fingerprint(secp))
+                .map(|(p, _)| p);
+            //TODO check actual derivation matches
+            match pubkey {
+                Some(pubkey) => input.partial_sigs.contains_key(pubkey),
+                None => false,
+            }
+        }
+    })
+}
+
+impl<Ctx: ScriptContext> ExtractPolicy for Miniscript<DescriptorPublicKey, Ctx> {
+    fn extract_policy(
+        &self,
+        signers: &SignersContainer,
+        build_sat: BuildSatisfaction,
+        secp: &SecpCtx,
+    ) -> Result<Option<Policy>, Error> {
+        Ok(match &self.node {
+            // Leaves
+            Terminal::True | Terminal::False => None,
+            Terminal::PkK(pubkey) => Some(signature(pubkey, signers, build_sat, secp)),
+            Terminal::PkH(pubkey_hash) => Some(signature(pubkey_hash, signers, build_sat, secp)),
+            Terminal::After(value) => {
+                let mut policy: Policy = SatisfiableItem::AbsoluteTimelock { value: *value }.into();
+                policy.contribution = Satisfaction::Complete {
+                    condition: Condition {
+                        timelock: Some(*value),
+                        csv: None,
+                    },
+                };
+                if let BuildSatisfaction::PsbtTimelocks {
+                    current_height,
+                    psbt,
+                    ..
+                } = build_sat
+                {
+                    let after = After::new(Some(current_height), false);
+                    let after_sat = Satisfier::<bitcoin::PublicKey>::check_after(&after, *value);
+                    let inputs_sat = psbt_inputs_sat(psbt)
+                        .all(|sat| Satisfier::<bitcoin::PublicKey>::check_after(&sat, *value));
+                    if after_sat && inputs_sat {
+                        policy.satisfaction = policy.contribution.clone();
+                    }
+                }
+
+                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),
+                    },
+                };
+                if let BuildSatisfaction::PsbtTimelocks {
+                    current_height,
+                    input_max_height,
+                    psbt,
+                } = build_sat
+                {
+                    let older = Older::new(Some(current_height), Some(input_max_height), false);
+                    let older_sat = Satisfier::<bitcoin::PublicKey>::check_older(&older, *value);
+                    let inputs_sat = psbt_inputs_sat(psbt)
+                        .all(|sat| Satisfier::<bitcoin::PublicKey>::check_older(&sat, *value));
+                    if older_sat && inputs_sat {
+                        policy.satisfaction = policy.contribution.clone();
+                    }
+                }
+
+                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, build_sat, *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, build_sat, secp)?,
+            // Complex policies
+            Terminal::AndV(a, b) | Terminal::AndB(a, b) => Policy::make_and(
+                a.extract_policy(signers, build_sat, secp)?,
+                b.extract_policy(signers, build_sat, secp)?,
+            )?,
+            Terminal::AndOr(x, y, z) => Policy::make_or(
+                Policy::make_and(
+                    x.extract_policy(signers, build_sat, secp)?,
+                    y.extract_policy(signers, build_sat, secp)?,
+                )?,
+                z.extract_policy(signers, build_sat, secp)?,
+            )?,
+            Terminal::OrB(a, b)
+            | Terminal::OrD(a, b)
+            | Terminal::OrC(a, b)
+            | Terminal::OrI(a, b) => Policy::make_or(
+                a.extract_policy(signers, build_sat, secp)?,
+                b.extract_policy(signers, build_sat, secp)?,
+            )?,
+            Terminal::Thresh(k, nodes) => {
+                let mut threshold = *k;
+                let mapped: Vec<_> = nodes
+                    .iter()
+                    .map(|n| n.extract_policy(signers, build_sat, secp))
+                    .collect::<Result<Vec<_>, _>>()?
+                    .into_iter()
+                    .flatten()
+                    .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)?
+            }
+        })
+    }
+}
+
+fn psbt_inputs_sat(psbt: &Psbt) -> impl Iterator<Item = PsbtInputSatisfier> {
+    (0..psbt.inputs.len()).map(move |i| PsbtInputSatisfier::new(psbt, i))
+}
+
+/// Options to build the satisfaction field in the policy
+#[derive(Debug, Clone, Copy)]
+pub enum BuildSatisfaction<'a> {
+    /// Don't generate `satisfaction` field
+    None,
+    /// Analyze the given PSBT to check for existing signatures
+    Psbt(&'a Psbt),
+    /// Like `Psbt` variant and also check for expired timelocks
+    PsbtTimelocks {
+        /// Given PSBT
+        psbt: &'a Psbt,
+        /// Current blockchain height
+        current_height: u32,
+        /// The highest confirmation height between the inputs
+        /// CSV should consider different inputs, but we consider the worst condition for the tx as whole
+        input_max_height: u32,
+    },
+}
+impl<'a> BuildSatisfaction<'a> {
+    fn psbt(&self) -> Option<&'a Psbt> {
+        match self {
+            BuildSatisfaction::None => None,
+            BuildSatisfaction::Psbt(psbt) => Some(psbt),
+            BuildSatisfaction::PsbtTimelocks { psbt, .. } => Some(psbt),
+        }
+    }
+}
+
+impl ExtractPolicy for Descriptor<DescriptorPublicKey> {
+    fn extract_policy(
+        &self,
+        signers: &SignersContainer,
+        build_sat: BuildSatisfaction,
+        secp: &SecpCtx,
+    ) -> Result<Option<Policy>, Error> {
+        fn make_sortedmulti<Ctx: ScriptContext>(
+            keys: &SortedMultiVec<DescriptorPublicKey, Ctx>,
+            signers: &SignersContainer,
+            build_sat: BuildSatisfaction,
+            secp: &SecpCtx,
+        ) -> Result<Option<Policy>, Error> {
+            Ok(Policy::make_multisig(
+                keys.pks.as_ref(),
+                signers,
+                build_sat,
+                keys.k,
+                true,
+                secp,
+            )?)
+        }
+
+        match self {
+            Descriptor::Pkh(pk) => Ok(Some(signature(pk.as_inner(), signers, build_sat, secp))),
+            Descriptor::Wpkh(pk) => Ok(Some(signature(pk.as_inner(), signers, build_sat, secp))),
+            Descriptor::Sh(sh) => match sh.as_inner() {
+                ShInner::Wpkh(pk) => Ok(Some(signature(pk.as_inner(), signers, build_sat, secp))),
+                ShInner::Ms(ms) => Ok(ms.extract_policy(signers, build_sat, secp)?),
+                ShInner::SortedMulti(ref keys) => make_sortedmulti(keys, signers, build_sat, secp),
+                ShInner::Wsh(wsh) => match wsh.as_inner() {
+                    WshInner::Ms(ms) => Ok(ms.extract_policy(signers, build_sat, secp)?),
+                    WshInner::SortedMulti(ref keys) => {
+                        make_sortedmulti(keys, signers, build_sat, secp)
+                    }
+                },
+            },
+            Descriptor::Wsh(wsh) => match wsh.as_inner() {
+                WshInner::Ms(ms) => Ok(ms.extract_policy(signers, build_sat, secp)?),
+                WshInner::SortedMulti(ref keys) => make_sortedmulti(keys, signers, build_sat, secp),
+            },
+            Descriptor::Bare(ms) => Ok(ms.as_inner().extract_policy(signers, build_sat, secp)?),
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::descriptor;
+    use crate::descriptor::{ExtractPolicy, IntoWalletDescriptor};
+
+    use super::*;
+    use crate::descriptor::derived::AsDerived;
+    use crate::descriptor::policy::SatisfiableItem::{Multisig, Signature, Thresh};
+    use crate::keys::{DescriptorKey, IntoDescriptorKey};
+    use crate::wallet::signer::SignersContainer;
+    use bitcoin::secp256k1::Secp256k1;
+    use bitcoin::util::bip32;
+    use bitcoin::Network;
+    use miniscript::DescriptorTrait;
+    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,
+        path: &str,
+        secp: &SecpCtx,
+    ) -> (DescriptorKey<Ctx>, DescriptorKey<Ctx>, Fingerprint) {
+        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()).into_descriptor_key().unwrap();
+        let pubkey = (tpub, path).into_descriptor_key().unwrap();
+
+        (prvkey, pubkey, fingerprint)
+    }
+
+    // test ExtractPolicy trait for simple descriptors; wpkh(), sh(multi())
+
+    #[test]
+    fn test_extract_policy_for_wpkh() {
+        let secp = Secp256k1::new();
+
+        let (prvkey, pubkey, fingerprint) = setup_keys(TPRV0_STR, PATH, &secp);
+        let desc = descriptor!(wpkh(pubkey)).unwrap();
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .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
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .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 secp = Secp256k1::new();
+        let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR, PATH, &secp);
+        let (_prvkey1, pubkey1, fingerprint1) = setup_keys(TPRV1_STR, PATH, &secp);
+        let desc = descriptor!(sh(multi(2, pubkey0, pubkey1))).unwrap();
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .unwrap()
+            .unwrap();
+
+        assert!(
+            matches!(&policy.item, Multisig { keys, threshold } if threshold == &2usize
+            && 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 == &2usize
+            && m == &2usize
+            && 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 secp = Secp256k1::new();
+        let (prvkey0, _pubkey0, fingerprint0) = setup_keys(TPRV0_STR, PATH, &secp);
+        let (_prvkey1, pubkey1, fingerprint1) = setup_keys(TPRV1_STR, PATH, &secp);
+        let desc = descriptor!(sh(multi(2, prvkey0, pubkey1))).unwrap();
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .unwrap()
+            .unwrap();
+        assert!(
+            matches!(&policy.item, Multisig { keys, threshold } if threshold == &2usize
+            && keys[0].fingerprint.unwrap() == fingerprint0
+            && keys[1].fingerprint.unwrap() == fingerprint1)
+        );
+
+        assert!(
+            matches!(&policy.contribution, Satisfaction::Partial { n, m, items, conditions, ..} if n == &2usize
+             && m == &2usize
+             && items.len() == 1
+             && conditions.contains_key(&0)
+            )
+        );
+    }
+
+    // 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 secp = Secp256k1::new();
+
+        let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR, PATH, &secp);
+        let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR, PATH, &secp);
+        let desc = descriptor!(sh(multi(1, pubkey0, prvkey1))).unwrap();
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .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 secp = Secp256k1::new();
+
+        let (prvkey0, _pubkey0, fingerprint0) = setup_keys(TPRV0_STR, PATH, &secp);
+        let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR, PATH, &secp);
+        let desc = descriptor!(sh(multi(2, prvkey0, prvkey1))).unwrap();
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .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 secp = Secp256k1::new();
+
+        let (prvkey, pubkey, fingerprint) = setup_keys(TPRV0_STR, PATH, &secp);
+        let desc = descriptor!(wpkh(pubkey)).unwrap();
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let single_key = wallet_desc.derive(0);
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = single_key
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .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
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let single_key = wallet_desc.derive(0);
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = single_key
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .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 secp = Secp256k1::new();
+
+        let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR, PATH, &secp);
+        let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR, PATH, &secp);
+        let desc = descriptor!(sh(multi(1, pubkey0, prvkey1))).unwrap();
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let single_key = wallet_desc.derive(0);
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = single_key
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .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 secp = Secp256k1::new();
+
+        let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR, PATH, &secp);
+        let (_prvkey1, pubkey1, _fingerprint1) = setup_keys(TPRV1_STR, PATH, &secp);
+        let sequence = 50;
+        #[rustfmt::skip]
+        let desc = descriptor!(wsh(thresh(
+            2,
+            pk(prvkey0),
+            s:pk(pubkey1),
+            s:d:v:older(sequence)
+        )))
+        .unwrap();
+
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .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]
+    #[ignore]
+    fn test_extract_policy_for_wsh_mixed_timelocks() {
+        let secp = Secp256k1::new();
+        let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR, PATH, &secp);
+        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
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .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]
+    #[ignore]
+    fn test_extract_policy_for_multiple_same_timelocks() {
+        let secp = Secp256k1::new();
+        let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR, PATH, &secp);
+        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
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .unwrap()
+            .unwrap();
+        println!("desc policy = {:?}", policy); // TODO remove
+                                                // TODO how should this merge timelocks?
+        let (prvkey1, _pubkey1, _fingerprint1) = setup_keys(TPRV0_STR, PATH, &secp);
+        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
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+        let policy = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::None, &secp)
+            .unwrap()
+            .unwrap();
+
+        println!("desc policy = {:?}", policy); // TODO remove
+
+        // TODO how should this merge timelocks?
+    }
+
+    #[test]
+    fn test_get_condition_multisig() {
+        let secp = Secp256k1::new();
+
+        let (_, pk0, _) = setup_keys(TPRV0_STR, PATH, &secp);
+        let (_, pk1, _) = setup_keys(TPRV1_STR, PATH, &secp);
+
+        let desc = descriptor!(wsh(multi(1, pk0, pk1))).unwrap();
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers = keymap.into();
+
+        let policy = wallet_desc
+            .extract_policy(&signers, BuildSatisfaction::None, &secp)
+            .unwrap()
+            .unwrap();
+
+        // no args, choose the default
+        let no_args = policy.get_condition(&vec![].into_iter().collect());
+        assert_eq!(no_args, Ok(Condition::default()));
+
+        // enough args
+        let eq_thresh =
+            policy.get_condition(&vec![(policy.id.clone(), vec![0])].into_iter().collect());
+        assert_eq!(eq_thresh, Ok(Condition::default()));
+
+        // more args, it doesn't really change anything
+        let gt_thresh =
+            policy.get_condition(&vec![(policy.id.clone(), vec![0, 1])].into_iter().collect());
+        assert_eq!(gt_thresh, Ok(Condition::default()));
+
+        // not enough args, error
+        let lt_thresh =
+            policy.get_condition(&vec![(policy.id.clone(), vec![])].into_iter().collect());
+        assert_eq!(
+            lt_thresh,
+            Err(PolicyError::NotEnoughItemsSelected(policy.id.clone()))
+        );
+
+        // index out of range
+        let out_of_range =
+            policy.get_condition(&vec![(policy.id.clone(), vec![5])].into_iter().collect());
+        assert_eq!(out_of_range, Err(PolicyError::IndexOutOfRange(5)));
+    }
+
+    const ALICE_TPRV_STR:&str = "tprv8ZgxMBicQKsPf6T5X327efHnvJDr45Xnb8W4JifNWtEoqXu9MRYS4v1oYe6DFcMVETxy5w3bqpubYRqvcVTqovG1LifFcVUuJcbwJwrhYzP";
+    const BOB_TPRV_STR:&str = "tprv8ZgxMBicQKsPeinZ155cJAn117KYhbaN6MV3WeG6sWhxWzcvX1eg1awd4C9GpUN1ncLEM2rzEvunAg3GizdZD4QPPCkisTz99tXXB4wZArp";
+    const CAROL_TPRV_STR:&str = "tprv8ZgxMBicQKsPdC3CicFifuLCEyVVdXVUNYorxUWj3iGZ6nimnLAYAY9SYB7ib8rKzRxrCKFcEytCt6szwd2GHnGPRCBLAEAoSVDefSNk4Bt";
+    const ALICE_BOB_PATH: &str = "m/0'";
+
+    #[test]
+    fn test_extract_satisfaction() {
+        const ALICE_SIGNED_PSBT: &str = "cHNidP8BAFMBAAAAAZb0njwT2wRS3AumaaP3yb7T4MxOePpSWih4Nq+jWChMAQAAAAD/////Af4lAAAAAAAAF6kUXv2Fn+YemPP4PUpNR1ZbU16/eRCHAAAAAAABASuJJgAAAAAAACIAIERw5kTLo9DUH9QDJSClHQwPpC7VGJ+ZMDpa8U+2fzcYIgIDeAtjYQk/Vfu4db2+68hyMKjc38+kWl5sP5QH8L42ZstHMEQCIBj0jLjUeVYXNQ6cqB+gbtvuKMjV54wSgWlm1cfcgpHVAiBa3DtC9l/1Mt4IDCvR7mmwQd3eAP/m5++81euhJNSrgQEBBUdSIQN4C2NhCT9V+7h1vb7ryHIwqNzfz6RaXmw/lAfwvjZmyyEC+GE/y+LptI8xmiR6sOe998IGzybox0Qfz4+BQl1nmYhSriIGAvhhP8vi6bSPMZokerDnvffCBs8m6MdEH8+PgUJdZ5mIDBwu7j4AAACAAAAAACIGA3gLY2EJP1X7uHW9vuvIcjCo3N/PpFpebD+UB/C+NmbLDMkRfC4AAACAAAAAAAAA";
+        const BOB_SIGNED_PSBT: &str =   "cHNidP8BAFMBAAAAAZb0njwT2wRS3AumaaP3yb7T4MxOePpSWih4Nq+jWChMAQAAAAD/////Af4lAAAAAAAAF6kUXv2Fn+YemPP4PUpNR1ZbU16/eRCHAAAAAAABASuJJgAAAAAAACIAIERw5kTLo9DUH9QDJSClHQwPpC7VGJ+ZMDpa8U+2fzcYIgIC+GE/y+LptI8xmiR6sOe998IGzybox0Qfz4+BQl1nmYhIMEUCIQD5zDtM5MwklurwJ5aW76RsO36Iqyu+6uMdVlhL6ws2GQIgesAiz4dbKS7UmhDsC/c1ezu0o6hp00UUtsCMfUZ4anYBAQVHUiEDeAtjYQk/Vfu4db2+68hyMKjc38+kWl5sP5QH8L42ZsshAvhhP8vi6bSPMZokerDnvffCBs8m6MdEH8+PgUJdZ5mIUq4iBgL4YT/L4um0jzGaJHqw5733wgbPJujHRB/Pj4FCXWeZiAwcLu4+AAAAgAAAAAAiBgN4C2NhCT9V+7h1vb7ryHIwqNzfz6RaXmw/lAfwvjZmywzJEXwuAAAAgAAAAAAAAA==";
+        const ALICE_BOB_SIGNED_PSBT: &str =   "cHNidP8BAFMBAAAAAZb0njwT2wRS3AumaaP3yb7T4MxOePpSWih4Nq+jWChMAQAAAAD/////Af4lAAAAAAAAF6kUXv2Fn+YemPP4PUpNR1ZbU16/eRCHAAAAAAABASuJJgAAAAAAACIAIERw5kTLo9DUH9QDJSClHQwPpC7VGJ+ZMDpa8U+2fzcYIgIC+GE/y+LptI8xmiR6sOe998IGzybox0Qfz4+BQl1nmYhIMEUCIQD5zDtM5MwklurwJ5aW76RsO36Iqyu+6uMdVlhL6ws2GQIgesAiz4dbKS7UmhDsC/c1ezu0o6hp00UUtsCMfUZ4anYBIgIDeAtjYQk/Vfu4db2+68hyMKjc38+kWl5sP5QH8L42ZstHMEQCIBj0jLjUeVYXNQ6cqB+gbtvuKMjV54wSgWlm1cfcgpHVAiBa3DtC9l/1Mt4IDCvR7mmwQd3eAP/m5++81euhJNSrgQEBBUdSIQN4C2NhCT9V+7h1vb7ryHIwqNzfz6RaXmw/lAfwvjZmyyEC+GE/y+LptI8xmiR6sOe998IGzybox0Qfz4+BQl1nmYhSriIGAvhhP8vi6bSPMZokerDnvffCBs8m6MdEH8+PgUJdZ5mIDBwu7j4AAACAAAAAACIGA3gLY2EJP1X7uHW9vuvIcjCo3N/PpFpebD+UB/C+NmbLDMkRfC4AAACAAAAAAAEHAAEI2wQARzBEAiAY9Iy41HlWFzUOnKgfoG7b7ijI1eeMEoFpZtXH3IKR1QIgWtw7QvZf9TLeCAwr0e5psEHd3gD/5ufvvNXroSTUq4EBSDBFAiEA+cw7TOTMJJbq8CeWlu+kbDt+iKsrvurjHVZYS+sLNhkCIHrAIs+HWyku1JoQ7Av3NXs7tKOoadNFFLbAjH1GeGp2AUdSIQN4C2NhCT9V+7h1vb7ryHIwqNzfz6RaXmw/lAfwvjZmyyEC+GE/y+LptI8xmiR6sOe998IGzybox0Qfz4+BQl1nmYhSrgAA";
+
+        let secp = Secp256k1::new();
+
+        let (prvkey_alice, _, _) = setup_keys(ALICE_TPRV_STR, ALICE_BOB_PATH, &secp);
+        let (prvkey_bob, _, _) = setup_keys(BOB_TPRV_STR, ALICE_BOB_PATH, &secp);
+
+        let desc = descriptor!(wsh(multi(2, prvkey_alice, prvkey_bob))).unwrap();
+
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+
+        let addr = wallet_desc
+            .as_derived(0, &secp)
+            .address(Network::Testnet)
+            .unwrap();
+        assert_eq!(
+            "tb1qg3cwv3xt50gdg875qvjjpfgaps86gtk4rz0ejvp6ttc5ldnlxuvqlcn0xk",
+            addr.to_string()
+        );
+
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+
+        let psbt = Psbt::from_str(ALICE_SIGNED_PSBT).unwrap();
+
+        let policy_alice_psbt = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::Psbt(&psbt), &secp)
+            .unwrap()
+            .unwrap();
+        //println!("{}", serde_json::to_string(&policy_alice_psbt).unwrap());
+
+        assert!(
+            matches!(&policy_alice_psbt.satisfaction, Satisfaction::Partial { n, m, items, .. } if n == &2
+             && m == &2
+             && items == &vec![0]
+            )
+        );
+
+        let psbt = Psbt::from_str(BOB_SIGNED_PSBT).unwrap();
+        let policy_bob_psbt = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::Psbt(&psbt), &secp)
+            .unwrap()
+            .unwrap();
+        //println!("{}", serde_json::to_string(&policy_bob_psbt).unwrap());
+
+        assert!(
+            matches!(&policy_bob_psbt.satisfaction, Satisfaction::Partial { n, m, items, .. } if n == &2
+             && m == &2
+             && items == &vec![1]
+            )
+        );
+
+        let psbt = Psbt::from_str(ALICE_BOB_SIGNED_PSBT).unwrap();
+        let policy_alice_bob_psbt = wallet_desc
+            .extract_policy(&signers_container, BuildSatisfaction::Psbt(&psbt), &secp)
+            .unwrap()
+            .unwrap();
+        assert!(
+            matches!(&policy_alice_bob_psbt.satisfaction, Satisfaction::PartialComplete { n, m, items, .. } if n == &2
+             && m == &2
+             && items == &vec![0, 1]
+            )
+        );
+    }
+
+    #[test]
+    fn test_extract_satisfaction_timelock() {
+        //const PSBT_POLICY_CONSIDER_TIMELOCK_NOT_EXPIRED: &str = "cHNidP8BAFMBAAAAAdld52uJFGT7Yde0YZdSVh2vL020Zm2exadH5R4GSNScAAAAAAD/////ATrcAAAAAAAAF6kUXv2Fn+YemPP4PUpNR1ZbU16/eRCHAAAAAAABASvI3AAAAAAAACIAILhzvvcBzw/Zfnc9ispRK0PCahxn1F6RHXTZAmw5tqNPAQVSdmNSsmlofCEDeAtjYQk/Vfu4db2+68hyMKjc38+kWl5sP5QH8L42Zsusk3whAvhhP8vi6bSPMZokerDnvffCBs8m6MdEH8+PgUJdZ5mIrJNShyIGAvhhP8vi6bSPMZokerDnvffCBs8m6MdEH8+PgUJdZ5mIDBwu7j4AAACAAAAAACIGA3gLY2EJP1X7uHW9vuvIcjCo3N/PpFpebD+UB/C+NmbLDMkRfC4AAACAAAAAAAAA";
+        const PSBT_POLICY_CONSIDER_TIMELOCK_EXPIRED:     &str = "cHNidP8BAFMCAAAAAdld52uJFGT7Yde0YZdSVh2vL020Zm2exadH5R4GSNScAAAAAAACAAAAATrcAAAAAAAAF6kUXv2Fn+YemPP4PUpNR1ZbU16/eRCHAAAAAAABASvI3AAAAAAAACIAILhzvvcBzw/Zfnc9ispRK0PCahxn1F6RHXTZAmw5tqNPAQVSdmNSsmlofCEDeAtjYQk/Vfu4db2+68hyMKjc38+kWl5sP5QH8L42Zsusk3whAvhhP8vi6bSPMZokerDnvffCBs8m6MdEH8+PgUJdZ5mIrJNShyIGAvhhP8vi6bSPMZokerDnvffCBs8m6MdEH8+PgUJdZ5mIDBwu7j4AAACAAAAAACIGA3gLY2EJP1X7uHW9vuvIcjCo3N/PpFpebD+UB/C+NmbLDMkRfC4AAACAAAAAAAAA";
+        const PSBT_POLICY_CONSIDER_TIMELOCK_EXPIRED_SIGNED: &str ="cHNidP8BAFMCAAAAAdld52uJFGT7Yde0YZdSVh2vL020Zm2exadH5R4GSNScAAAAAAACAAAAATrcAAAAAAAAF6kUXv2Fn+YemPP4PUpNR1ZbU16/eRCHAAAAAAABASvI3AAAAAAAACIAILhzvvcBzw/Zfnc9ispRK0PCahxn1F6RHXTZAmw5tqNPIgIDeAtjYQk/Vfu4db2+68hyMKjc38+kWl5sP5QH8L42ZstIMEUCIQCtZxNm6H3Ux3pnc64DSpgohMdBj+57xhFHcURYt2BpPAIgG3OnI7bcj/3GtWX1HHyYGSI7QGa/zq5YnsmK1Cw29NABAQVSdmNSsmlofCEDeAtjYQk/Vfu4db2+68hyMKjc38+kWl5sP5QH8L42Zsusk3whAvhhP8vi6bSPMZokerDnvffCBs8m6MdEH8+PgUJdZ5mIrJNShyIGAvhhP8vi6bSPMZokerDnvffCBs8m6MdEH8+PgUJdZ5mIDBwu7j4AAACAAAAAACIGA3gLY2EJP1X7uHW9vuvIcjCo3N/PpFpebD+UB/C+NmbLDMkRfC4AAACAAAAAAAEHAAEIoAQASDBFAiEArWcTZuh91Md6Z3OuA0qYKITHQY/ue8YRR3FEWLdgaTwCIBtzpyO23I/9xrVl9Rx8mBkiO0Bmv86uWJ7JitQsNvTQAQEBUnZjUrJpaHwhA3gLY2EJP1X7uHW9vuvIcjCo3N/PpFpebD+UB/C+NmbLrJN8IQL4YT/L4um0jzGaJHqw5733wgbPJujHRB/Pj4FCXWeZiKyTUocAAA==";
+
+        let secp = Secp256k1::new();
+
+        let (prvkey_alice, _, _) = setup_keys(ALICE_TPRV_STR, ALICE_BOB_PATH, &secp);
+        let (prvkey_bob, _, _) = setup_keys(BOB_TPRV_STR, ALICE_BOB_PATH, &secp);
+
+        let desc =
+            descriptor!(wsh(thresh(2,d:v:older(2),s:pk(prvkey_alice),s:pk(prvkey_bob)))).unwrap();
+
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+
+        let addr = wallet_desc
+            .as_derived(0, &secp)
+            .address(Network::Testnet)
+            .unwrap();
+        assert_eq!(
+            "tb1qhpemaacpeu8ajlnh8k9v55ftg0px58r8630fz8t5mypxcwdk5d8sum522g",
+            addr.to_string()
+        );
+
+        let psbt = Psbt::from_str(PSBT_POLICY_CONSIDER_TIMELOCK_EXPIRED).unwrap();
+
+        let build_sat = BuildSatisfaction::PsbtTimelocks {
+            psbt: &psbt,
+            current_height: 10,
+            input_max_height: 9,
+        };
+
+        let policy = wallet_desc
+            .extract_policy(&signers_container, build_sat, &secp)
+            .unwrap()
+            .unwrap();
+        assert!(
+            matches!(&policy.satisfaction, Satisfaction::Partial { n, m, items, .. } if n == &3
+             && m == &2
+             && items.is_empty()
+            )
+        );
+        //println!("{}", serde_json::to_string(&policy).unwrap());
+
+        let build_sat_expired = BuildSatisfaction::PsbtTimelocks {
+            psbt: &psbt,
+            current_height: 12,
+            input_max_height: 9,
+        };
+
+        let policy_expired = wallet_desc
+            .extract_policy(&signers_container, build_sat_expired, &secp)
+            .unwrap()
+            .unwrap();
+        assert!(
+            matches!(&policy_expired.satisfaction, Satisfaction::Partial { n, m, items, .. } if n == &3
+             && m == &2
+             && items == &vec![0]
+            )
+        );
+        //println!("{}", serde_json::to_string(&policy_expired).unwrap());
+
+        let psbt_signed = Psbt::from_str(PSBT_POLICY_CONSIDER_TIMELOCK_EXPIRED_SIGNED).unwrap();
+
+        let build_sat_expired_signed = BuildSatisfaction::PsbtTimelocks {
+            psbt: &psbt_signed,
+            current_height: 12,
+            input_max_height: 9,
+        };
+
+        let policy_expired_signed = wallet_desc
+            .extract_policy(&signers_container, build_sat_expired_signed, &secp)
+            .unwrap()
+            .unwrap();
+        assert!(
+            matches!(&policy_expired_signed.satisfaction, Satisfaction::PartialComplete { n, m, items, .. } if n == &3
+             && m == &2
+             && items == &vec![0, 1]
+            )
+        );
+        //println!("{}", serde_json::to_string(&policy_expired_signed).unwrap());
+    }
+
+    #[test]
+    fn test_extract_pkh() {
+        let secp = Secp256k1::new();
+
+        let (prvkey_alice, _, _) = setup_keys(ALICE_TPRV_STR, ALICE_BOB_PATH, &secp);
+        let (prvkey_bob, _, _) = setup_keys(BOB_TPRV_STR, ALICE_BOB_PATH, &secp);
+        let (prvkey_carol, _, _) = setup_keys(CAROL_TPRV_STR, ALICE_BOB_PATH, &secp);
+
+        let desc = descriptor!(wsh(c: andor(
+            pk(prvkey_alice),
+            pk_k(prvkey_bob),
+            pk_h(prvkey_carol),
+        )))
+        .unwrap();
+
+        let (wallet_desc, keymap) = desc
+            .into_wallet_descriptor(&secp, Network::Testnet)
+            .unwrap();
+        let signers_container = Arc::new(SignersContainer::from(keymap));
+
+        let policy = wallet_desc.extract_policy(&signers_container, BuildSatisfaction::None, &secp);
+        assert!(policy.is_ok());
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/template.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/template.rs.html new file mode 100644 index 0000000000..31d6c7edbe --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/descriptor/template.rs.html @@ -0,0 +1,1456 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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, IntoWalletDescriptor, KeyMap};
+use crate::descriptor::DescriptorError;
+use crate::keys::{DerivableKey, IntoDescriptorKey, ValidNetworks};
+use crate::wallet::utils::SecpCtx;
+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 [`IntoWalletDescriptor`] is implemented for any [`DescriptorTemplate`], they can also be
+/// passed directly to the [`Wallet`](crate::Wallet) constructor.
+///
+/// ## Example
+///
+/// ```
+/// use bdk::descriptor::error::Error as DescriptorError;
+/// use bdk::keys::{IntoDescriptorKey, KeyError};
+/// use bdk::miniscript::Legacy;
+/// use bdk::template::{DescriptorTemplate, DescriptorTemplateOut};
+///
+/// struct MyP2PKH<K: IntoDescriptorKey<Legacy>>(K);
+///
+/// impl<K: IntoDescriptorKey<Legacy>> DescriptorTemplate for MyP2PKH<K> {
+///     fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
+///         Ok(bdk::descriptor!(pkh(self.0))?)
+///     }
+/// }
+/// ```
+pub trait DescriptorTemplate {
+    /// Build the complete descriptor
+    fn build(self) -> Result<DescriptorTemplateOut, DescriptorError>;
+}
+
+/// Turns a [`DescriptorTemplate`] into a valid wallet descriptor by calling its
+/// [`build`](DescriptorTemplate::build) method
+impl<T: DescriptorTemplate> IntoWalletDescriptor for T {
+    fn into_wallet_descriptor(
+        self,
+        secp: &SecpCtx,
+        network: Network,
+    ) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
+        self.build()?.into_wallet_descriptor(secp, network)
+    }
+}
+
+/// P2PKH template. Expands to a descriptor `pkh(key)`
+///
+/// ## Example
+///
+/// ```
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet};
+/// # use bdk::database::MemoryDatabase;
+/// # use bdk::wallet::AddressIndex::New;
+/// use bdk::template::P2Pkh;
+///
+/// let key =
+///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+/// let wallet = Wallet::new_offline(
+///     P2Pkh(key),
+///     None,
+///     Network::Testnet,
+///     MemoryDatabase::default(),
+/// )?;
+///
+/// assert_eq!(
+///     wallet.get_address(New)?.to_string(),
+///     "mwJ8hxFYW19JLuc65RCTaP4v1rzVU8cVMT"
+/// );
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct P2Pkh<K: IntoDescriptorKey<Legacy>>(pub K);
+
+impl<K: IntoDescriptorKey<Legacy>> DescriptorTemplate for P2Pkh<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
+        descriptor!(pkh(self.0))
+    }
+}
+
+/// P2WPKH-P2SH template. Expands to a descriptor `sh(wpkh(key))`
+///
+/// ## Example
+///
+/// ```
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet};
+/// # use bdk::database::MemoryDatabase;
+/// # use bdk::wallet::AddressIndex::New;
+/// use bdk::template::P2Wpkh_P2Sh;
+///
+/// let key =
+///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+/// let wallet = Wallet::new_offline(
+///     P2Wpkh_P2Sh(key),
+///     None,
+///     Network::Testnet,
+///     MemoryDatabase::default(),
+/// )?;
+///
+/// assert_eq!(
+///     wallet.get_address(New)?.to_string(),
+///     "2NB4ox5VDRw1ecUv6SnT3VQHPXveYztRqk5"
+/// );
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+#[allow(non_camel_case_types)]
+pub struct P2Wpkh_P2Sh<K: IntoDescriptorKey<Segwitv0>>(pub K);
+
+impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2Wpkh_P2Sh<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
+        descriptor!(sh(wpkh(self.0)))
+    }
+}
+
+/// P2WPKH template. Expands to a descriptor `wpkh(key)`
+///
+/// ## Example
+///
+/// ```
+/// # use bdk::bitcoin::{PrivateKey, Network};
+/// # use bdk::{Wallet};
+/// # use bdk::database::MemoryDatabase;
+/// # use bdk::wallet::AddressIndex::New;
+/// use bdk::template::P2Wpkh;
+///
+/// let key =
+///     bitcoin::PrivateKey::from_wif("cTc4vURSzdx6QE6KVynWGomDbLaA75dNALMNyfjh3p8DRRar84Um")?;
+/// let wallet = Wallet::new_offline(
+///     P2Wpkh(key),
+///     None,
+///     Network::Testnet,
+///     MemoryDatabase::default(),
+/// )?;
+///
+/// assert_eq!(
+///     wallet.get_address(New)?.to_string(),
+///     "tb1q4525hmgw265tl3drrl8jjta7ayffu6jf68ltjd"
+/// );
+/// # Ok::<_, Box<dyn std::error::Error>>(())
+/// ```
+pub struct P2Wpkh<K: IntoDescriptorKey<Segwitv0>>(pub K);
+
+impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2Wpkh<K> {
+    fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
+        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,  KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// # use bdk::wallet::AddressIndex::New;
+/// use bdk::template::Bip44;
+///
+/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let wallet = Wallet::new_offline(
+///     Bip44(key.clone(), KeychainKind::External),
+///     Some(Bip44(key, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_address(New)?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)#xgaaevjx");
+/// # 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, DescriptorError> {
+        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,  KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// # use bdk::wallet::AddressIndex::New;
+/// use bdk::template::Bip44Public;
+///
+/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU")?;
+/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let wallet = Wallet::new_offline(
+///     Bip44Public(key.clone(), fingerprint, KeychainKind::External),
+///     Some(Bip44Public(key, fingerprint, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_address(New)?.to_string(), "miNG7dJTzJqNbFS19svRdTCisC65dsubtR");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "pkh([c55b303f/44'/0'/0']tpubDDDzQ31JkZB7VxUr9bjvBivDdqoFLrDPyLWtLapArAi51ftfmCb2DPxwLQzX65iNcXz1DGaVvyvo6JQ6rTU73r2gqdEo8uov9QKRb7nKCSU/0/*)#xgaaevjx");
+/// # 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, DescriptorError> {
+        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,  KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// # use bdk::wallet::AddressIndex::New;
+/// use bdk::template::Bip49;
+///
+/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let wallet = Wallet::new_offline(
+///     Bip49(key.clone(), KeychainKind::External),
+///     Some(Bip49(key, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_address(New)?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))#gsmdv4xr");
+/// # 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, DescriptorError> {
+        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,  KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// # use bdk::wallet::AddressIndex::New;
+/// use bdk::template::Bip49Public;
+///
+/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L")?;
+/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let wallet = Wallet::new_offline(
+///     Bip49Public(key.clone(), fingerprint, KeychainKind::External),
+///     Some(Bip49Public(key, fingerprint, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_address(New)?.to_string(), "2N3K4xbVAHoiTQSwxkZjWDfKoNC27pLkYnt");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "sh(wpkh([c55b303f/49\'/0\'/0\']tpubDC49r947KGK52X5rBWS4BLs5m9SRY3pYHnvRrm7HcybZ3BfdEsGFyzCMzayi1u58eT82ZeyFZwH7DD6Q83E3fM9CpfMtmnTygnLfP59jL9L/0/*))#gsmdv4xr");
+/// # 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, DescriptorError> {
+        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,  KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// # use bdk::wallet::AddressIndex::New;
+/// use bdk::template::Bip84;
+///
+/// let key = bitcoin::util::bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPeZRHk4rTG6orPS2CRNFX3njhUXx5vj9qGog5ZMH4uGReDWN5kCkY3jmWEtWause41CDvBRXD1shKknAMKxT99o9qUTRVC6m")?;
+/// let wallet = Wallet::new_offline(
+///     Bip84(key.clone(), KeychainKind::External),
+///     Some(Bip84(key, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_address(New)?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#nkk5dtkg");
+/// # 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, DescriptorError> {
+        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,  KeychainKind};
+/// # use bdk::database::MemoryDatabase;
+/// # use bdk::wallet::AddressIndex::New;
+/// use bdk::template::Bip84Public;
+///
+/// let key = bitcoin::util::bip32::ExtendedPubKey::from_str("tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q")?;
+/// let fingerprint = bitcoin::util::bip32::Fingerprint::from_str("c55b303f")?;
+/// let wallet = Wallet::new_offline(
+///     Bip84Public(key.clone(), fingerprint, KeychainKind::External),
+///     Some(Bip84Public(key, fingerprint, KeychainKind::Internal)),
+///     Network::Testnet,
+///     MemoryDatabase::default()
+/// )?;
+///
+/// assert_eq!(wallet.get_address(New)?.to_string(), "tb1qedg9fdlf8cnnqfd5mks6uz5w4kgpk2pr6y4qc7");
+/// assert_eq!(wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string(), "wpkh([c55b303f/84\'/0\'/0\']tpubDC2Qwo2TFsaNC4ju8nrUJ9mqVT3eSgdmy1yPqhgkjwmke3PRXutNGRYAUo6RCHTcVQaDR3ohNU9we59brGHuEKPvH1ags2nevW5opEE9Z5Q/0/*)#nkk5dtkg");
+/// # 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, DescriptorError> {
+        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 IntoDescriptorKey<$ctx>, DescriptorError> {
+                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 IntoDescriptorKey<$ctx>, DescriptorError> {
+                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 source_path = bip32::DerivationPath::from(vec![
+                    bip32::ChildNumber::from_hardened_idx(bip)?,
+                    bip32::ChildNumber::from_hardened_idx(0)?,
+                    bip32::ChildNumber::from_hardened_idx(0)?,
+                ]);
+
+                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 std::str::FromStr;
+
+    use super::*;
+    use crate::descriptor::derived::AsDerived;
+    use crate::descriptor::{DescriptorError, DescriptorMeta};
+    use crate::keys::ValidNetworks;
+    use bitcoin::network::constants::Network::Regtest;
+    use bitcoin::secp256k1::Secp256k1;
+    use miniscript::descriptor::{DescriptorPublicKey, DescriptorTrait, KeyMap};
+    use miniscript::Descriptor;
+
+    // verify template descriptor generates expected address(es)
+    fn check(
+        desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>,
+        is_witness: bool,
+        is_fixed: bool,
+        expected: &[&str],
+    ) {
+        let secp = Secp256k1::new();
+
+        let (desc, _key_map, _networks) = desc.unwrap();
+        assert_eq!(desc.is_witness(), is_witness);
+        assert_eq!(!desc.is_deriveable(), is_fixed);
+        for i in 0..expected.len() {
+            let index = i as u32;
+            let child_desc = if !desc.is_deriveable() {
+                desc.as_derived_fixed(&secp)
+            } else {
+                desc.as_derived(index, &secp)
+            };
+            let address = child_desc.address(Regtest).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/latest/src/bdk/error.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/error.rs.html new file mode 100644 index 0000000000..d6c5f36fbc --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/error.rs.html @@ -0,0 +1,460 @@ +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
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+use std::fmt;
+
+use crate::bitcoin::Network;
+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,
+    /// 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 {
+        /// Sats needed for some transaction
+        needed: u64,
+        /// Sats available for spending
+        available: u64,
+    },
+    /// 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,
+    },
+    /// Node doesn't have data to estimate a fee rate
+    FeeRateUnavailable,
+    /// 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),
+    /// Invalid network
+    InvalidNetwork {
+        /// requested network, for example what is given as bdk-cli option
+        requested: Network,
+        /// found network, for example the network of the bitcoin node
+        found: Network,
+    },
+    #[cfg(feature = "verify")]
+    /// Transaction verification error
+    Verification(crate::wallet::verify::VerifyError),
+
+    /// 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),
+    /// Partially signed bitcoin transaction parseerror
+    PsbtParse(bitcoin::util::psbt::PsbtParseError),
+
+    //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(Box<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),
+    #[cfg(feature = "rpc")]
+    /// Rpc client error
+    Rpc(core_rpc::Error),
+    #[cfg(feature = "sqlite")]
+    /// Rusqlite client error
+    Rusqlite(rusqlite::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);
+impl_error!(bitcoin::util::psbt::PsbtParseError, PsbtParse);
+
+#[cfg(feature = "electrum")]
+impl_error!(electrum_client::Error, Electrum);
+#[cfg(feature = "key-value-db")]
+impl_error!(sled::Error, Sled);
+#[cfg(feature = "rpc")]
+impl_error!(core_rpc::Error, Rpc);
+#[cfg(feature = "sqlite")]
+impl_error!(rusqlite::Error, Rusqlite);
+
+#[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),
+        }
+    }
+}
+
+#[cfg(feature = "verify")]
+impl From<crate::wallet::verify::VerifyError> for Error {
+    fn from(other: crate::wallet::verify::VerifyError) -> Self {
+        match other {
+            crate::wallet::verify::VerifyError::Global(inner) => *inner,
+            err => Error::Verification(err),
+        }
+    }
+}
+
+#[cfg(feature = "esplora")]
+impl From<crate::blockchain::esplora::EsploraError> for Error {
+    fn from(other: crate::blockchain::esplora::EsploraError) -> Self {
+        Error::Esplora(Box::new(other))
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/keys/bip39.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/keys/bip39.rs.html new file mode 100644 index 0000000000..3cf8935dbd --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/keys/bip39.rs.html @@ -0,0 +1,384 @@ +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
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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;
+
+pub use bip39::{Language, Mnemonic, MnemonicType, Seed};
+
+use super::{
+    any_network, DerivableKey, DescriptorKey, ExtendedKey, GeneratableKey, GeneratedKey, KeyError,
+};
+
+fn set_valid_on_any_network<Ctx: ScriptContext>(
+    descriptor_key: DescriptorKey<Ctx>,
+) -> DescriptorKey<Ctx> {
+    // We have to pick one network to build the xprv, but since the bip39 standard doesn't
+    // encode the network, the xprv we create is actually valid everywhere. So we override the
+    // valid networks with `any_network()`.
+    descriptor_key.override_valid_networks(any_network())
+}
+
+/// 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 into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+        Ok(bip32::ExtendedPrivKey::new_master(Network::Bitcoin, &self.as_bytes())?.into())
+    }
+
+    fn into_descriptor_key(
+        self,
+        source: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let descriptor_key = self
+            .into_extended_key()?
+            .into_descriptor_key(source, derivation_path)?;
+
+        Ok(set_valid_on_any_network(descriptor_key))
+    }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for MnemonicWithPassphrase {
+    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+        let (mnemonic, passphrase) = self;
+        let seed = Seed::new(&mnemonic, passphrase.as_deref().unwrap_or(""));
+
+        seed.into_extended_key()
+    }
+
+    fn into_descriptor_key(
+        self,
+        source: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let descriptor_key = self
+            .into_extended_key()?
+            .into_descriptor_key(source, derivation_path)?;
+
+        Ok(set_valid_on_any_network(descriptor_key))
+    }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "keys-bip39")))]
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for Mnemonic {
+    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+        (self, None).into_extended_key()
+    }
+
+    fn into_descriptor_key(
+        self,
+        source: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let descriptor_key = self
+            .into_extended_key()?
+            .into_descriptor_key(source, derivation_path)?;
+
+        Ok(set_valid_on_any_network(descriptor_key))
+    }
+}
+
+#[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/*)#0r8v4nkv");
+        assert_eq!(keys.len(), 1);
+        assert_eq!(networks.len(), 4);
+    }
+
+    #[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/*)#h0j0tg5m");
+        assert_eq!(keys.len(), 1);
+        assert_eq!(networks.len(), 4);
+    }
+
+    #[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/latest/src/bdk/keys/mod.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/keys/mod.rs.html new file mode 100644 index 0000000000..7dc8e48126 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/keys/mod.rs.html @@ -0,0 +1,1872 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Key formats
+
+use std::any::TypeId;
+use std::collections::HashSet;
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::str::FromStr;
+
+use bitcoin::secp256k1::{self, Secp256k1, Signing};
+
+use bitcoin::util::bip32;
+use bitcoin::{Network, PrivateKey, PublicKey};
+
+use miniscript::descriptor::{Descriptor, DescriptorXKey, Wildcard};
+pub use miniscript::descriptor::{
+    DescriptorPublicKey, DescriptorSecretKey, DescriptorSinglePriv, DescriptorSinglePub, KeyMap,
+    SortedMultiVec,
+};
+pub use miniscript::ScriptContext;
+use miniscript::{Miniscript, Terminal};
+
+use crate::descriptor::{CheckMiniscript, DescriptorError};
+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,
+        Network::Signet,
+    ]
+    .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, Network::Signet]
+        .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, IntoDescriptorKey, KeyError, ScriptContext};
+///
+/// pub struct MyKeyType {
+///     pubkey: PublicKey,
+/// }
+///
+/// impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for MyKeyType {
+///     fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+///         self.pubkey.into_descriptor_key()
+///     }
+/// }
+/// ```
+///
+/// Key type that is only valid on mainnet:
+///
+/// ```
+/// use bdk::bitcoin::PublicKey;
+///
+/// use bdk::keys::{
+///     mainnet_network, DescriptorKey, DescriptorPublicKey, DescriptorSinglePub,
+///     IntoDescriptorKey, KeyError, ScriptContext,
+/// };
+///
+/// pub struct MyKeyType {
+///     pubkey: PublicKey,
+/// }
+///
+/// impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for MyKeyType {
+///     fn into_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, IntoDescriptorKey, KeyError, ScriptContext};
+///
+/// pub struct MyKeyType {
+///     is_legacy: bool,
+///     pubkey: PublicKey,
+/// }
+///
+/// impl<Ctx: ScriptContext + 'static> IntoDescriptorKey<Ctx> for MyKeyType {
+///     fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+///         if Ctx::is_legacy() == self.is_legacy {
+///             self.pubkey.into_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, IntoDescriptorKey, KeyError};
+///
+/// pub struct MySegwitOnlyKeyType {
+///     pubkey: PublicKey,
+/// }
+///
+/// impl IntoDescriptorKey<bdk::miniscript::Segwitv0> for MySegwitOnlyKeyType {
+///     fn into_descriptor_key(self) -> Result<DescriptorKey<bdk::miniscript::Segwitv0>, KeyError> {
+///         self.pubkey.into_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 IntoDescriptorKey<Ctx: ScriptContext>: Sized {
+    /// Turn the key into a [`DescriptorKey`] within the requested [`ScriptContext`]
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError>;
+}
+
+/// Enum for extended keys that can be either `xprv` or `xpub`
+///
+/// An instance of [`ExtendedKey`] can be constructed from an [`ExtendedPrivKey`](bip32::ExtendedPrivKey)
+/// or an [`ExtendedPubKey`](bip32::ExtendedPubKey) by using the `From` trait.
+///
+/// Defaults to the [`Legacy`](miniscript::Legacy) context.
+pub enum ExtendedKey<Ctx: ScriptContext = miniscript::Legacy> {
+    /// A private extended key, aka an `xprv`
+    Private((bip32::ExtendedPrivKey, PhantomData<Ctx>)),
+    /// A public extended key, aka an `xpub`
+    Public((bip32::ExtendedPubKey, PhantomData<Ctx>)),
+}
+
+impl<Ctx: ScriptContext> ExtendedKey<Ctx> {
+    /// Return whether or not the key contains the private data
+    pub fn has_secret(&self) -> bool {
+        match self {
+            ExtendedKey::Private(_) => true,
+            ExtendedKey::Public(_) => false,
+        }
+    }
+
+    /// Transform the [`ExtendedKey`] into an [`ExtendedPrivKey`](bip32::ExtendedPrivKey) for the
+    /// given [`Network`], if the key contains the private data
+    pub fn into_xprv(self, network: Network) -> Option<bip32::ExtendedPrivKey> {
+        match self {
+            ExtendedKey::Private((mut xprv, _)) => {
+                xprv.network = network;
+                Some(xprv)
+            }
+            ExtendedKey::Public(_) => None,
+        }
+    }
+
+    /// Transform the [`ExtendedKey`] into an [`ExtendedPubKey`](bip32::ExtendedPubKey) for the
+    /// given [`Network`]
+    pub fn into_xpub<C: Signing>(
+        self,
+        network: bitcoin::Network,
+        secp: &Secp256k1<C>,
+    ) -> bip32::ExtendedPubKey {
+        let mut xpub = match self {
+            ExtendedKey::Private((xprv, _)) => bip32::ExtendedPubKey::from_private(secp, &xprv),
+            ExtendedKey::Public((xpub, _)) => xpub,
+        };
+
+        xpub.network = network;
+        xpub
+    }
+}
+
+impl<Ctx: ScriptContext> From<bip32::ExtendedPubKey> for ExtendedKey<Ctx> {
+    fn from(xpub: bip32::ExtendedPubKey) -> Self {
+        ExtendedKey::Public((xpub, PhantomData))
+    }
+}
+
+impl<Ctx: ScriptContext> From<bip32::ExtendedPrivKey> for ExtendedKey<Ctx> {
+    fn from(xprv: bip32::ExtendedPrivKey) -> Self {
+        ExtendedKey::Private((xprv, PhantomData))
+    }
+}
+
+/// Trait for keys that can be derived.
+///
+/// When extra metadata are provided, a [`DerivableKey`] can be transofrmed into a
+/// [`DescriptorKey`]: the trait [`IntoDescriptorKey`] 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 [`IntoDescriptorKey`]. The same
+/// rules regarding script context and valid networks apply.
+///
+/// ## Examples
+///
+/// Key types that can be directly converted into an [`ExtendedPrivKey`] or
+/// an [`ExtendedPubKey`] can implement only the required `into_extended_key()` method.
+///
+/// ```
+/// use bdk::bitcoin;
+/// use bdk::bitcoin::util::bip32;
+/// use bdk::keys::{DerivableKey, ExtendedKey, KeyError, ScriptContext};
+///
+/// struct MyCustomKeyType {
+///     key_data: bitcoin::PrivateKey,
+///     chain_code: Vec<u8>,
+///     network: bitcoin::Network,
+/// }
+///
+/// impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
+///     fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+///         let xprv = bip32::ExtendedPrivKey {
+///             network: self.network,
+///             depth: 0,
+///             parent_fingerprint: bip32::Fingerprint::default(),
+///             private_key: self.key_data,
+///             chain_code: bip32::ChainCode::from(self.chain_code.as_ref()),
+///             child_number: bip32::ChildNumber::Normal { index: 0 },
+///         };
+///
+///         xprv.into_extended_key()
+///     }
+/// }
+/// ```
+///
+/// Types that don't internally encode the [`Network`](bitcoin::Network) in which they are valid need some extra
+/// steps to override the set of valid networks, otherwise only the network specified in the
+/// [`ExtendedPrivKey`] or [`ExtendedPubKey`] will be considered valid.
+///
+/// ```
+/// use bdk::bitcoin;
+/// use bdk::bitcoin::util::bip32;
+/// use bdk::keys::{
+///     any_network, DerivableKey, DescriptorKey, ExtendedKey, KeyError, ScriptContext,
+/// };
+///
+/// struct MyCustomKeyType {
+///     key_data: bitcoin::PrivateKey,
+///     chain_code: Vec<u8>,
+/// }
+///
+/// impl<Ctx: ScriptContext> DerivableKey<Ctx> for MyCustomKeyType {
+///     fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+///         let xprv = bip32::ExtendedPrivKey {
+///             network: bitcoin::Network::Bitcoin, // pick an arbitrary network here
+///             depth: 0,
+///             parent_fingerprint: bip32::Fingerprint::default(),
+///             private_key: self.key_data,
+///             chain_code: bip32::ChainCode::from(self.chain_code.as_ref()),
+///             child_number: bip32::ChildNumber::Normal { index: 0 },
+///         };
+///
+///         xprv.into_extended_key()
+///     }
+///
+///     fn into_descriptor_key(
+///         self,
+///         source: Option<bip32::KeySource>,
+///         derivation_path: bip32::DerivationPath,
+///     ) -> Result<DescriptorKey<Ctx>, KeyError> {
+///         let descriptor_key = self
+///             .into_extended_key()?
+///             .into_descriptor_key(source, derivation_path)?;
+///
+///         // Override the set of valid networks here
+///         Ok(descriptor_key.override_valid_networks(any_network()))
+///     }
+/// }
+/// ```
+///
+/// [`DerivationPath`]: (bip32::DerivationPath)
+/// [`ExtendedPrivKey`]: (bip32::ExtendedPrivKey)
+/// [`ExtendedPubKey`]: (bip32::ExtendedPubKey)
+pub trait DerivableKey<Ctx: ScriptContext = miniscript::Legacy>: Sized {
+    /// Consume `self` and turn it into an [`ExtendedKey`]
+    ///
+    /// This can be used to get direct access to `xprv`s and `xpub`s for types that implement this trait,
+    /// like [`Mnemonic`](bip39::Mnemonic) when the `keys-bip39` feature is enabled.
+    #[cfg_attr(
+        feature = "keys-bip39",
+        doc = r##"
+```rust
+use bdk::bitcoin::Network;
+use bdk::keys::{DerivableKey, ExtendedKey};
+use bdk::keys::bip39::{Mnemonic, Language};
+
+# fn main() -> Result<(), Box<dyn std::error::Error>> {
+let xkey: ExtendedKey =
+    Mnemonic::from_phrase(
+        "jelly crash boy whisper mouse ecology tuna soccer memory million news short",
+        Language::English
+    )?
+    .into_extended_key()?;
+let xprv = xkey.into_xprv(Network::Bitcoin).unwrap();
+# Ok(()) }
+```
+"##
+    )]
+    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError>;
+
+    /// Consume `self` and turn it into a [`DescriptorKey`] by adding the extra metadata, such as
+    /// key origin and derivation path
+    fn into_descriptor_key(
+        self,
+        origin: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        match self.into_extended_key()? {
+            ExtendedKey::Private((xprv, _)) => DescriptorSecretKey::XPrv(DescriptorXKey {
+                origin,
+                xkey: xprv,
+                derivation_path,
+                wildcard: Wildcard::Unhardened,
+            })
+            .into_descriptor_key(),
+            ExtendedKey::Public((xpub, _)) => DescriptorPublicKey::XPub(DescriptorXKey {
+                origin,
+                xkey: xpub,
+                derivation_path,
+                wildcard: Wildcard::Unhardened,
+            })
+            .into_descriptor_key(),
+        }
+    }
+}
+
+/// Identity conversion
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for ExtendedKey<Ctx> {
+    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+        Ok(self)
+    }
+}
+
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPubKey {
+    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+        Ok(self.into())
+    }
+}
+
+impl<Ctx: ScriptContext> DerivableKey<Ctx> for bip32::ExtendedPrivKey {
+    fn into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+        Ok(self.into())
+    }
+}
+
+/// 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 into_extended_key(self) -> Result<ExtendedKey<Ctx>, KeyError> {
+        self.key.into_extended_key()
+    }
+
+    fn into_descriptor_key(
+        self,
+        origin: Option<bip32::KeySource>,
+        derivation_path: bip32::DerivationPath,
+    ) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let descriptor_key = self.key.into_descriptor_key(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> IntoDescriptorKey<Ctx> for GeneratedKey<K, Ctx>
+where
+    Ctx: ScriptContext,
+    K: IntoDescriptorKey<Ctx>,
+{
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        let desc_key = self.key.into_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 [`IntoDescriptorKey`] 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
+/// [`IntoDescriptorKey`]: the generated keys can be directly used in descriptors if `Self` is also
+/// [`IntoDescriptorKey`].
+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>> IntoDescriptorKey<Ctx>
+    for (T, bip32::DerivationPath)
+{
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        self.0.into_descriptor_key(None, self.1)
+    }
+}
+
+impl<Ctx: ScriptContext, T: DerivableKey<Ctx>> IntoDescriptorKey<Ctx>
+    for (T, bip32::KeySource, bip32::DerivationPath)
+{
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        self.0.into_descriptor_key(Some(self.1), self.2)
+    }
+}
+
+fn expand_multi_keys<Pk: IntoDescriptorKey<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| key.into_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: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
+    descriptor_key: Pk,
+    secp: &SecpCtx,
+) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
+    let (key, key_map, valid_networks) = descriptor_key.into_descriptor_key()?.extract(secp)?;
+    let minisc = Miniscript::from_ast(Terminal::PkK(key))?;
+
+    minisc.check_minsicript()?;
+
+    Ok((minisc, key_map, valid_networks))
+}
+
+// Used internally by `bdk::fragment!` to build `pk_h()` fragments
+#[doc(hidden)]
+pub fn make_pkh<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
+    descriptor_key: Pk,
+    secp: &SecpCtx,
+) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
+    let (key, key_map, valid_networks) = descriptor_key.into_descriptor_key()?.extract(secp)?;
+    let minisc = Miniscript::from_ast(Terminal::PkH(key))?;
+
+    minisc.check_minsicript()?;
+
+    Ok((minisc, key_map, valid_networks))
+}
+
+// Used internally by `bdk::fragment!` to build `multi()` fragments
+#[doc(hidden)]
+pub fn make_multi<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
+    thresh: usize,
+    pks: Vec<Pk>,
+    secp: &SecpCtx,
+) -> Result<(Miniscript<DescriptorPublicKey, Ctx>, KeyMap, ValidNetworks), DescriptorError> {
+    let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
+    let minisc = Miniscript::from_ast(Terminal::Multi(thresh, pks))?;
+
+    minisc.check_minsicript()?;
+
+    Ok((minisc, key_map, valid_networks))
+}
+
+// Used internally by `bdk::descriptor!` to build `sortedmulti()` fragments
+#[doc(hidden)]
+pub fn make_sortedmulti<Pk, Ctx, F>(
+    thresh: usize,
+    pks: Vec<Pk>,
+    build_desc: F,
+    secp: &SecpCtx,
+) -> Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>
+where
+    Pk: IntoDescriptorKey<Ctx>,
+    Ctx: ScriptContext,
+    F: Fn(
+        usize,
+        Vec<DescriptorPublicKey>,
+    ) -> Result<(Descriptor<DescriptorPublicKey>, PhantomData<Ctx>), DescriptorError>,
+{
+    let (pks, key_map, valid_networks) = expand_multi_keys(pks, secp)?;
+    let descriptor = build_desc(thresh, pks)?.0;
+
+    Ok((descriptor, key_map, valid_networks))
+}
+
+/// The "identity" conversion is used internally by some `bdk::fragment`s
+impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorKey<Ctx> {
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        Ok(self)
+    }
+}
+
+impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorPublicKey {
+    fn into_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> IntoDescriptorKey<Ctx> for PublicKey {
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        DescriptorPublicKey::SinglePub(DescriptorSinglePub {
+            key: self,
+            origin: None,
+        })
+        .into_descriptor_key()
+    }
+}
+
+impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for DescriptorSecretKey {
+    fn into_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> IntoDescriptorKey<Ctx> for &'_ str {
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        DescriptorSecretKey::from_str(self)
+            .map_err(|e| KeyError::Message(e.to_string()))?
+            .into_descriptor_key()
+    }
+}
+
+impl<Ctx: ScriptContext> IntoDescriptorKey<Ctx> for PrivateKey {
+    fn into_descriptor_key(self) -> Result<DescriptorKey<Ctx>, KeyError> {
+        DescriptorSecretKey::SinglePriv(DescriptorSinglePriv {
+            key: self,
+            origin: None,
+        })
+        .into_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/latest/src/bdk/lib.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/lib.rs.html new file mode 100644 index 0000000000..52c94a3205 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/lib.rs.html @@ -0,0 +1,570 @@ +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
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+// 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))]
+
+//! 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.12.0"
+//! ```
+#![cfg_attr(
+    feature = "electrum",
+    doc = r##"
+## Sync the balance of a descriptor
+
+### Example
+```no_run
+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};
+//! use bdk::database::MemoryDatabase;
+//! use bdk::wallet::AddressIndex::New;
+//!
+//! fn main() -> Result<(), bdk::Error> {
+//! let wallet = 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_address(New)?);
+//!     println!("Address #1: {}", wallet.get_address(New)?);
+//!     println!("Address #2: {}", wallet.get_address(New)?);
+//!
+//!     Ok(())
+//! }
+//! ```
+#![cfg_attr(
+    feature = "electrum",
+    doc = r##"
+## Create a transaction
+
+### Example
+```no_run
+use bdk::{FeeRate, Wallet};
+use bdk::database::MemoryDatabase;
+use bdk::blockchain::{noop_progress, ElectrumBlockchain};
+use bdk::electrum_client::Client;
+
+use bitcoin::consensus::serialize;
+use bdk::wallet::AddressIndex::New;
+
+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_address(New)?;
+    let (psbt, details) = {
+        let mut builder =  wallet.build_tx();
+        builder
+            .add_recipient(send_to.script_pubkey(), 50_000)
+            .enable_rbf()
+            .do_not_spend_change()
+            .fee_rate(FeeRate::from_sat_per_vb(5.0));
+        builder.finish()?
+    };
+
+    println!("Transaction details: {:#?}", details);
+    println!("Unsigned PSBT: {}", &psbt);
+
+    Ok(())
+}
+```
+"##
+)]
+//!
+//! ## Sign a transaction
+//!
+//! ### Example
+//! ```no_run
+//! use std::str::FromStr;
+//!
+//! use bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
+//!
+//! use bdk::{Wallet, SignOptions};
+//! use bdk::database::MemoryDatabase;
+//!
+//! fn main() -> Result<(), bdk::Error> {
+//!     let wallet = 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 mut psbt = Psbt::from_str(psbt)?;
+//!
+//!     let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
+//!
+//!     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
+//! * `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(all(feature = "reqwest", feature = "ureq"))]
+compile_error!("Features reqwest and ureq are mutually exclusive and cannot be enabled together");
+
+#[cfg(all(feature = "async-interface", feature = "electrum"))]
+compile_error!(
+    "Features async-interface and electrum are mutually exclusive and cannot be enabled together"
+);
+
+#[cfg(all(feature = "async-interface", feature = "ureq"))]
+compile_error!(
+    "Features async-interface and ureq are mutually exclusive and cannot be enabled together"
+);
+
+#[cfg(all(feature = "async-interface", feature = "compact_filters"))]
+compile_error!(
+    "Features async-interface and compact_filters are mutually exclusive and cannot be enabled together"
+);
+
+#[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")]
+extern crate lazy_static;
+
+#[cfg(feature = "rpc")]
+pub extern crate core_rpc;
+
+#[cfg(feature = "electrum")]
+pub extern crate electrum_client;
+
+#[cfg(feature = "key-value-db")]
+pub extern crate sled;
+
+#[cfg(feature = "sqlite")]
+pub extern crate rusqlite;
+
+#[allow(unused_imports)]
+#[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::signer::SignOptions;
+pub use wallet::tx_builder::TxBuilder;
+pub use wallet::Wallet;
+
+/// Get the version of BDK at runtime
+pub fn version() -> &'static str {
+    env!("CARGO_PKG_VERSION", "unknown")
+}
+
+// We should consider putting this under a feature flag but we need the macro in doctets so we need
+// to wait until https://github.com/rust-lang/rust/issues/67295 is fixed.
+//
+// Stuff in here is too rough to document atm
+#[doc(hidden)]
+pub mod testutils;
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/psbt/mod.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/psbt/mod.rs.html new file mode 100644 index 0000000000..ca046b7b88 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/psbt/mod.rs.html @@ -0,0 +1,248 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+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 {
+    #[allow(clippy::all)] // We want to allow `manual_map` but it is too new.
+    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
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::bitcoin::TxIn;
+    use crate::psbt::Psbt;
+    use crate::wallet::AddressIndex;
+    use crate::wallet::{get_funded_wallet, test::get_test_wpkh};
+    use crate::SignOptions;
+    use std::str::FromStr;
+
+    // from bip 174
+    const PSBT_STR: &str = "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA";
+
+    #[test]
+    #[should_panic(expected = "InputIndexOutOfRange")]
+    fn test_psbt_malformed_psbt_input_legacy() {
+        let psbt_bip = Psbt::from_str(PSBT_STR).unwrap();
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let send_to = wallet.get_address(AddressIndex::New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(send_to.script_pubkey(), 10_000);
+        let (mut psbt, _) = builder.finish().unwrap();
+        psbt.inputs.push(psbt_bip.inputs[0].clone());
+        let options = SignOptions {
+            trust_witness_utxo: true,
+            ..Default::default()
+        };
+        let _ = wallet.sign(&mut psbt, options).unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "InputIndexOutOfRange")]
+    fn test_psbt_malformed_psbt_input_segwit() {
+        let psbt_bip = Psbt::from_str(PSBT_STR).unwrap();
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let send_to = wallet.get_address(AddressIndex::New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(send_to.script_pubkey(), 10_000);
+        let (mut psbt, _) = builder.finish().unwrap();
+        psbt.inputs.push(psbt_bip.inputs[1].clone());
+        let options = SignOptions {
+            trust_witness_utxo: true,
+            ..Default::default()
+        };
+        let _ = wallet.sign(&mut psbt, options).unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "InputIndexOutOfRange")]
+    fn test_psbt_malformed_tx_input() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let send_to = wallet.get_address(AddressIndex::New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(send_to.script_pubkey(), 10_000);
+        let (mut psbt, _) = builder.finish().unwrap();
+        psbt.global.unsigned_tx.input.push(TxIn::default());
+        let options = SignOptions {
+            trust_witness_utxo: true,
+            ..Default::default()
+        };
+        let _ = wallet.sign(&mut psbt, options).unwrap();
+    }
+
+    #[test]
+    fn test_psbt_sign_with_finalized() {
+        let psbt_bip = Psbt::from_str(PSBT_STR).unwrap();
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let send_to = wallet.get_address(AddressIndex::New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(send_to.script_pubkey(), 10_000);
+        let (mut psbt, _) = builder.finish().unwrap();
+
+        // add a finalized input
+        psbt.inputs.push(psbt_bip.inputs[0].clone());
+        psbt.global
+            .unsigned_tx
+            .input
+            .push(psbt_bip.global.unsigned_tx.input[0].clone());
+
+        let _ = wallet.sign(&mut psbt, SignOptions::default()).unwrap();
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/testutils/mod.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/testutils/mod.rs.html new file mode 100644 index 0000000000..a673857c4e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/testutils/mod.rs.html @@ -0,0 +1,466 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+#![allow(missing_docs)]
+
+#[cfg(test)]
+#[cfg(feature = "test-blockchains")]
+pub mod blockchain_tests;
+
+use bitcoin::secp256k1::{Secp256k1, Verification};
+use bitcoin::{Address, PublicKey};
+
+use miniscript::descriptor::DescriptorPublicKey;
+use miniscript::{Descriptor, MiniscriptKey, TranslatePk};
+
+#[derive(Clone, Debug)]
+pub struct TestIncomingOutput {
+    pub value: u64,
+    pub to_address: String,
+}
+
+impl TestIncomingOutput {
+    pub fn new(value: u64, to_address: Address) -> Self {
+        Self {
+            value,
+            to_address: to_address.to_string(),
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct TestIncomingTx {
+    pub output: Vec<TestIncomingOutput>,
+    pub min_confirmations: Option<u64>,
+    pub locktime: Option<i64>,
+    pub replaceable: Option<bool>,
+}
+
+impl TestIncomingTx {
+    pub fn new(
+        output: Vec<TestIncomingOutput>,
+        min_confirmations: Option<u64>,
+        locktime: Option<i64>,
+        replaceable: Option<bool>,
+    ) -> Self {
+        Self {
+            output,
+            min_confirmations,
+            locktime,
+            replaceable,
+        }
+    }
+
+    pub fn add_output(&mut self, output: TestIncomingOutput) {
+        self.output.push(output);
+    }
+}
+
+#[doc(hidden)]
+pub trait TranslateDescriptor {
+    // derive and translate a `Descriptor<DescriptorPublicKey>` into a `Descriptor<PublicKey>`
+    fn derive_translated<C: Verification>(
+        &self,
+        secp: &Secp256k1<C>,
+        index: u32,
+    ) -> Descriptor<PublicKey>;
+}
+
+impl TranslateDescriptor for Descriptor<DescriptorPublicKey> {
+    fn derive_translated<C: Verification>(
+        &self,
+        secp: &Secp256k1<C>,
+        index: u32,
+    ) -> Descriptor<PublicKey> {
+        let translate = |key: &DescriptorPublicKey| -> PublicKey {
+            match key {
+                DescriptorPublicKey::XPub(xpub) => {
+                    xpub.xkey
+                        .derive_pub(secp, &xpub.derivation_path)
+                        .expect("hardened derivation steps")
+                        .public_key
+                }
+                DescriptorPublicKey::SinglePub(key) => key.key,
+            }
+        };
+
+        self.derive(index)
+            .translate_pk_infallible(|pk| translate(pk), |pkh| translate(pkh).to_pubkeyhash())
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! testutils {
+    ( @external $descriptors:expr, $child:expr ) => ({
+        use $crate::bitcoin::secp256k1::Secp256k1;
+        use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey, DescriptorTrait};
+
+        use $crate::testutils::TranslateDescriptor;
+
+        let secp = Secp256k1::new();
+
+        let parsed = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, &$descriptors.0).expect("Failed to parse descriptor in `testutils!(@external)`").0;
+        parsed.derive_translated(&secp, $child).address(bitcoin::Network::Regtest).expect("No address form")
+    });
+    ( @internal $descriptors:expr, $child:expr ) => ({
+        use $crate::bitcoin::secp256k1::Secp256k1;
+        use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey, DescriptorTrait};
+
+        use $crate::testutils::TranslateDescriptor;
+
+        let secp = Secp256k1::new();
+
+        let parsed = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, &$descriptors.1.expect("Missing internal descriptor")).expect("Failed to parse descriptor in `testutils!(@internal)`").0;
+        parsed.derive_translated(&secp, $child).address($crate::bitcoin::Network::Regtest).expect("No address form")
+    });
+    ( @e $descriptors:expr, $child:expr ) => ({ testutils!(@external $descriptors, $child) });
+    ( @i $descriptors:expr, $child:expr ) => ({ testutils!(@internal $descriptors, $child) });
+
+    ( @tx ( $( ( $( $addr:tt )* ) => $amount:expr ),+ ) $( ( @locktime $locktime:expr ) )? $( ( @confirmations $confirmations:expr ) )? $( ( @replaceable $replaceable:expr ) )? ) => ({
+        let outs = vec![$( $crate::testutils::TestIncomingOutput::new($amount, testutils!( $($addr)* ))),+];
+
+        let locktime = None::<i64>$(.or(Some($locktime)))?;
+
+        let min_confirmations = None::<u64>$(.or(Some($confirmations)))?;
+        let replaceable = None::<bool>$(.or(Some($replaceable)))?;
+
+        $crate::testutils::TestIncomingTx::new(outs, min_confirmations, locktime, replaceable)
+    });
+
+    ( @literal $key:expr ) => ({
+        let key = $key.to_string();
+        (key, None::<String>, None::<String>)
+    });
+    ( @generate_xprv $( $external_path:expr )? $( ,$internal_path:expr )? ) => ({
+        use rand::Rng;
+
+        let mut seed = [0u8; 32];
+        rand::thread_rng().fill(&mut seed[..]);
+
+        let key = $crate::bitcoin::util::bip32::ExtendedPrivKey::new_master(
+            $crate::bitcoin::Network::Testnet,
+            &seed,
+        );
+
+        let external_path = None::<String>$(.or(Some($external_path.to_string())))?;
+        let internal_path = None::<String>$(.or(Some($internal_path.to_string())))?;
+
+        (key.unwrap().to_string(), external_path, internal_path)
+    });
+    ( @generate_wif ) => ({
+        use rand::Rng;
+
+        let mut key = [0u8; $crate::bitcoin::secp256k1::constants::SECRET_KEY_SIZE];
+        rand::thread_rng().fill(&mut key[..]);
+
+        ($crate::bitcoin::PrivateKey {
+            compressed: true,
+            network: $crate::bitcoin::Network::Testnet,
+            key: $crate::bitcoin::secp256k1::SecretKey::from_slice(&key).unwrap(),
+        }.to_string(), None::<String>, None::<String>)
+    });
+
+    ( @keys ( $( $alias:expr => ( $( $key_type:tt )* ) ),+ ) ) => ({
+        let mut map = std::collections::HashMap::new();
+        $(
+            let alias: &str = $alias;
+            map.insert(alias, testutils!( $($key_type)* ));
+        )+
+
+        map
+    });
+
+    ( @descriptors ( $external_descriptor:expr ) $( ( $internal_descriptor:expr ) )? $( ( @keys $( $keys:tt )* ) )* ) => ({
+        use std::str::FromStr;
+        use std::collections::HashMap;
+        use $crate::miniscript::descriptor::Descriptor;
+        use $crate::miniscript::TranslatePk;
+
+        #[allow(unused_assignments, unused_mut)]
+        let mut keys: HashMap<&'static str, (String, Option<String>, Option<String>)> = HashMap::new();
+        $(
+            keys = testutils!{ @keys $( $keys )* };
+        )*
+
+        let external: Descriptor<String> = FromStr::from_str($external_descriptor).unwrap();
+        let external: Descriptor<String> = external.translate_pk_infallible::<_, _>(|k| {
+            if let Some((key, ext_path, _)) = keys.get(&k.as_str()) {
+                format!("{}{}", key, ext_path.as_ref().unwrap_or(&"".into()))
+            } else {
+                k.clone()
+            }
+        }, |kh| {
+            if let Some((key, ext_path, _)) = keys.get(&kh.as_str()) {
+                format!("{}{}", key, ext_path.as_ref().unwrap_or(&"".into()))
+            } else {
+                kh.clone()
+            }
+
+        });
+        let external = external.to_string();
+
+        let internal = None::<String>$(.or({
+            let string_internal: Descriptor<String> = FromStr::from_str($internal_descriptor).unwrap();
+
+            let string_internal: Descriptor<String> = string_internal.translate_pk_infallible::<_, _>(|k| {
+                if let Some((key, _, int_path)) = keys.get(&k.as_str()) {
+                    format!("{}{}", key, int_path.as_ref().unwrap_or(&"".into()))
+                } else {
+                    k.clone()
+                }
+            }, |kh| {
+                if let Some((key, _, int_path)) = keys.get(&kh.as_str()) {
+                    format!("{}{}", key, int_path.as_ref().unwrap_or(&"".into()))
+                } else {
+                    kh.clone()
+                }
+            });
+            Some(string_internal.to_string())
+        }))?;
+
+        (external, internal)
+    })
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/types.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/types.rs.html new file mode 100644 index 0000000000..a5f9e76a88 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/types.rs.html @@ -0,0 +1,510 @@ +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
+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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+use std::convert::AsRef;
+use std::ops::Sub;
+
+use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut};
+use bitcoin::{hash_types::Txid, util::psbt};
+
+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 const 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 const fn default_min_relay_fee() -> Self {
+        FeeRate(1.0)
+    }
+
+    /// Calculate fee rate from `fee` and weight units (`wu`).
+    pub fn from_wu(fee: u64, wu: usize) -> FeeRate {
+        Self::from_vb(fee, wu.vbytes())
+    }
+
+    /// Calculate fee rate from `fee` and `vbytes`.
+    pub fn from_vb(fee: u64, vbytes: usize) -> FeeRate {
+        let rate = fee as f32 / vbytes as f32;
+        Self::from_sat_per_vb(rate)
+    }
+
+    /// Return the value as satoshi/vbyte
+    pub fn as_sat_vb(&self) -> f32 {
+        self.0
+    }
+
+    /// Calculate absolute fee in Satoshis using size in weight units.
+    pub fn fee_wu(&self, wu: usize) -> u64 {
+        self.fee_vb(wu.vbytes())
+    }
+
+    /// Calculate absolute fee in Satoshis using size in virtual bytes.
+    pub fn fee_vb(&self, vbytes: usize) -> u64 {
+        (self.as_sat_vb() * vbytes as f32).ceil() as u64
+    }
+}
+
+impl std::default::Default for FeeRate {
+    fn default() -> Self {
+        FeeRate::default_min_relay_fee()
+    }
+}
+
+impl Sub for FeeRate {
+    type Output = Self;
+
+    fn sub(self, other: FeeRate) -> Self::Output {
+        FeeRate(self.0 - other.0)
+    }
+}
+
+/// Trait implemented by types that can be used to measure weight units.
+pub trait Vbytes {
+    /// Convert weight units to virtual bytes.
+    fn vbytes(self) -> usize;
+}
+
+impl Vbytes for usize {
+    fn vbytes(self) -> usize {
+        // ref: https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki#transaction-size-calculations
+        (self as f32 / 4.0).ceil() as usize
+    }
+}
+
+/// An unspent output owned by a [`Wallet`].
+///
+/// [`Wallet`]: crate::Wallet
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
+pub struct LocalUtxo {
+    /// Reference to a transaction output
+    pub outpoint: OutPoint,
+    /// Transaction output
+    pub txout: TxOut,
+    /// Type of keychain
+    pub keychain: KeychainKind,
+}
+
+/// A [`Utxo`] with its `satisfaction_weight`.
+#[derive(Debug, Clone, PartialEq)]
+pub struct WeightedUtxo {
+    /// The weight of the witness data and `scriptSig` expressed in [weight units]. This is used to
+    /// properly maintain the feerate when adding this input to a transaction during coin selection.
+    ///
+    /// [weight units]: https://en.bitcoin.it/wiki/Weight_units
+    pub satisfaction_weight: usize,
+    /// The UTXO
+    pub utxo: Utxo,
+}
+
+#[derive(Debug, Clone, PartialEq)]
+/// An unspent transaction output (UTXO).
+pub enum Utxo {
+    /// A UTXO owned by the local wallet.
+    Local(LocalUtxo),
+    /// A UTXO owned by another wallet.
+    Foreign {
+        /// The location of the output.
+        outpoint: OutPoint,
+        /// The information about the input we require to add it to a PSBT.
+        // Box it to stop the type being too big.
+        psbt_input: Box<psbt::Input>,
+    },
+}
+
+impl Utxo {
+    /// Get the location of the UTXO
+    pub fn outpoint(&self) -> OutPoint {
+        match &self {
+            Utxo::Local(local) => local.outpoint,
+            Utxo::Foreign { outpoint, .. } => *outpoint,
+        }
+    }
+
+    /// Get the `TxOut` of the UTXO
+    pub fn txout(&self) -> &TxOut {
+        match &self {
+            Utxo::Local(local) => &local.txout,
+            Utxo::Foreign {
+                outpoint,
+                psbt_input,
+            } => {
+                if let Some(prev_tx) = &psbt_input.non_witness_utxo {
+                    return &prev_tx.output[outpoint.vout as usize];
+                }
+
+                if let Some(txout) = &psbt_input.witness_utxo {
+                    return txout;
+                }
+
+                unreachable!("Foreign UTXOs will always have one of these set")
+            }
+        }
+    }
+}
+
+/// 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,
+
+    /// Received value (sats)
+    pub received: u64,
+    /// Sent value (sats)
+    pub sent: u64,
+    /// Fee value (sats) if available.
+    /// The availability of the fee depends on the backend. It's never `None` with an Electrum
+    /// Server backend, but it could be `None` with a Bitcoin RPC node without txindex that receive
+    /// funds while offline.
+    pub fee: Option<u64>,
+    /// If the transaction is confirmed, contains height and timestamp of the block containing the
+    /// transaction, unconfirmed transaction contains `None`.
+    pub confirmation_time: Option<ConfirmationTime>,
+    /// Whether the tx has been verified against the consensus rules
+    ///
+    /// Confirmed txs are considered "verified" by default, while unconfirmed txs are checked to
+    /// ensure an unstrusted [`Blockchain`](crate::blockchain::Blockchain) backend can't trick the
+    /// wallet into using an invalid tx as an RBF template.
+    ///
+    /// The check is only perfomed when the `verify` feature is enabled.
+    #[serde(default = "bool::default")] // default to `false` if not specified
+    pub verified: bool,
+}
+
+/// Block height and timestamp of the block containing the confirmed transaction
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
+pub struct ConfirmationTime {
+    /// confirmation block height
+    pub height: u32,
+    /// confirmation block timestamp
+    pub timestamp: u64,
+}
+
+impl ConfirmationTime {
+    /// Returns `Some` `ConfirmationTime` if both `height` and `timestamp` are `Some`
+    pub fn new(height: Option<u32>, timestamp: Option<u64>) -> Option<Self> {
+        match (height, timestamp) {
+            (Some(height), Some(timestamp)) => Some(ConfirmationTime { height, timestamp }),
+            _ => None,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn can_store_feerate_in_const() {
+        const _MY_RATE: FeeRate = FeeRate::from_sat_per_vb(10.0);
+        const _MIN_RELAY: FeeRate = FeeRate::default_min_relay_fee();
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/address_validator.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/address_validator.rs.html new file mode 100644 index 0000000000..b4b1b942ac --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/address_validator.rs.html @@ -0,0 +1,312 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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_address`](super::Wallet::get_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::*;
+//! # use bdk::wallet::AddressIndex::New;
+//! #[derive(Debug)]
+//! 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 = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+//! wallet.add_address_validator(Arc::new(PrintAddressAndContinue));
+//!
+//! let address = wallet.get_address(New)?;
+//! 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 + fmt::Debug {
+    /// 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::AddressIndex::New;
+    use crate::wallet::{get_funded_wallet, test::get_test_wpkh};
+
+    #[derive(Debug)]
+    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_address(New).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 = crate::testutils!(@external descriptors, 10);
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 25_000);
+        builder.finish().unwrap();
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/coin_selection.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/coin_selection.rs.html new file mode 100644 index 0000000000..dc5c9f14b7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/coin_selection.rs.html @@ -0,0 +1,2122 @@ +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
+ 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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Coin selection
+//!
+//! This module provides the trait [`CoinSelectionAlgorithm`] that can be implemented to
+//! define custom coin selection algorithms.
+//!
+//! You can specify a custom coin selection algorithm through the [`coin_selection`] method on
+//! [`TxBuilder`]. [`DefaultCoinSelectionAlgorithm`] aliases the coin selection algorithm that will
+//! be used if it is not explicitly set.
+//!
+//! [`TxBuilder`]: super::tx_builder::TxBuilder
+//! [`coin_selection`]: super::tx_builder::TxBuilder::coin_selection
+//!
+//! ## Example
+//!
+//! ```
+//! # use std::str::FromStr;
+//! # use bitcoin::*;
+//! # use bdk::wallet::{self, 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<WeightedUtxo>,
+//!         optional_utxos: Vec<WeightedUtxo>,
+//!         fee_rate: FeeRate,
+//!         amount_needed: u64,
+//!         fee_amount: u64,
+//!     ) -> 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), weighted_utxo| {
+//!                     **selected_amount += weighted_utxo.utxo.txout().value;
+//!                     **additional_weight += TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight;
+//!                     Some(weighted_utxo.utxo)
+//!                 },
+//!             )
+//!             .collect::<Vec<_>>();
+//!         let additional_fees = fee_rate.fee_wu(additional_weight);
+//!         let amount_needed_with_fees = (fee_amount + additional_fees) + amount_needed;
+//!         if amount_needed_with_fees > selected_amount {
+//!             return Err(bdk::Error::InsufficientFunds {
+//!                 needed: amount_needed_with_fees,
+//!                 available: selected_amount,
+//!             });
+//!         }
+//!
+//!         Ok(CoinSelectionResult {
+//!             selected: all_utxos_selected,
+//!             fee_amount: fee_amount + additional_fees,
+//!         })
+//!     }
+//! }
+//!
+//! # let wallet = doctest_wallet!();
+//! // create wallet, sync, ...
+//!
+//! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+//! let (psbt, details) = {
+//!     let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything);
+//!     builder.add_recipient(to_address.script_pubkey(), 50_000);
+//!     builder.finish()?
+//! };
+//!
+//! // inspect, sign, broadcast, ...
+//!
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use crate::types::FeeRate;
+use crate::{database::Database, WeightedUtxo};
+use crate::{error::Error, Utxo};
+
+use rand::seq::SliceRandom;
+#[cfg(not(test))]
+use rand::thread_rng;
+#[cfg(test)]
+use rand::{rngs::StdRng, SeedableRng};
+use std::convert::TryInto;
+
+/// 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>,
+    /// Total fee amount in satoshi
+    pub fee_amount: u64,
+}
+
+impl CoinSelectionResult {
+    /// The total value of the inputs selected.
+    pub fn selected_amount(&self) -> u64 {
+        self.selected.iter().map(|u| u.txout().value).sum()
+    }
+
+    /// The total value of the inputs selected from the local wallet.
+    pub fn local_selected_amount(&self) -> u64 {
+        self.selected
+            .iter()
+            .filter_map(|u| match u {
+                Utxo::Local(_) => Some(u.txout().value),
+                _ => None,
+            })
+            .sum()
+    }
+}
+
+/// 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<WeightedUtxo>,
+        optional_utxos: Vec<WeightedUtxo>,
+        fee_rate: FeeRate,
+        amount_needed: u64,
+        fee_amount: u64,
+    ) -> 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, Clone, Copy)]
+pub struct LargestFirstCoinSelection;
+
+impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection {
+    fn coin_select(
+        &self,
+        _database: &D,
+        required_utxos: Vec<WeightedUtxo>,
+        mut optional_utxos: Vec<WeightedUtxo>,
+        fee_rate: FeeRate,
+        amount_needed: u64,
+        mut fee_amount: u64,
+    ) -> Result<CoinSelectionResult, Error> {
+        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(|wu| wu.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, weighted_utxo)| {
+                    if must_use || **selected_amount < amount_needed + **fee_amount {
+                        **fee_amount +=
+                            fee_rate.fee_wu(TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight);
+                        **selected_amount += weighted_utxo.utxo.txout().value;
+
+                        log::debug!(
+                            "Selected {}, updated fee_amount = `{}`",
+                            weighted_utxo.utxo.outpoint(),
+                            fee_amount
+                        );
+
+                        Some(weighted_utxo.utxo)
+                    } else {
+                        None
+                    }
+                },
+            )
+            .collect::<Vec<_>>();
+
+        let amount_needed_with_fees = amount_needed + fee_amount;
+        if selected_amount < amount_needed_with_fees {
+            return Err(Error::InsufficientFunds {
+                needed: amount_needed_with_fees,
+                available: selected_amount,
+            });
+        }
+
+        Ok(CoinSelectionResult {
+            selected,
+            fee_amount,
+        })
+    }
+}
+
+#[derive(Debug, Clone)]
+// Adds fee information to an UTXO.
+struct OutputGroup {
+    weighted_utxo: WeightedUtxo,
+    // Amount of fees for spending a certain utxo, calculated using a certain FeeRate
+    fee: u64,
+    // The effective value of the UTXO, i.e., the utxo value minus the fee for spending it
+    effective_value: i64,
+}
+
+impl OutputGroup {
+    fn new(weighted_utxo: WeightedUtxo, fee_rate: FeeRate) -> Self {
+        let fee = fee_rate.fee_wu(TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight);
+        let effective_value = weighted_utxo.utxo.txout().value as i64 - fee as i64;
+        OutputGroup {
+            weighted_utxo,
+            fee,
+            effective_value,
+        }
+    }
+}
+
+/// 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<WeightedUtxo>,
+        optional_utxos: Vec<WeightedUtxo>,
+        fee_rate: FeeRate,
+        amount_needed: u64,
+        fee_amount: u64,
+    ) -> 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, fee_rate))
+            .collect();
+
+        // Mapping every (UTXO, usize) to an output group.
+        let optional_utxos: Vec<OutputGroup> = optional_utxos
+            .into_iter()
+            .map(|u| OutputGroup::new(u, fee_rate))
+            .collect();
+
+        let curr_value = required_utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value);
+
+        let curr_available_value = optional_utxos
+            .iter()
+            .fold(0, |acc, x| acc + x.effective_value);
+
+        let actual_target = fee_amount + amount_needed;
+        let cost_of_change = self.size_of_change as f32 * fee_rate.as_sat_vb();
+
+        let expected = (curr_available_value + curr_value)
+            .try_into()
+            .map_err(|_| {
+                Error::Generic("Sum of UTXO spendable values does not fit into u64".to_string())
+            })?;
+
+        if expected < actual_target {
+            return Err(Error::InsufficientFunds {
+                needed: actual_target,
+                available: expected,
+            });
+        }
+
+        let actual_target = actual_target
+            .try_into()
+            .expect("Bitcoin amount to fit into i64");
+
+        if curr_value > actual_target {
+            return Ok(BranchAndBoundCoinSelection::calculate_cs_result(
+                vec![],
+                required_utxos,
+                fee_amount,
+            ));
+        }
+
+        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: i64,
+        mut curr_available_value: i64,
+        actual_target: i64,
+        fee_amount: u64,
+        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 i64
+            {
+                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;
+                }
+
+                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;
+            } 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;
+
+                // Inclusion branch first (Largest First Exploration)
+                current_selection.push(true);
+                curr_value += utxo.effective_value;
+            }
+        }
+
+        // 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: i64,
+        actual_target: i64,
+        fee_amount: u64,
+    ) -> 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;
+                    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: u64,
+    ) -> CoinSelectionResult {
+        selected_utxos.append(&mut required_utxos);
+        fee_amount += selected_utxos.iter().map(|u| u.fee).sum::<u64>();
+        let selected = selected_utxos
+            .into_iter()
+            .map(|u| u.weighted_utxo.utxo)
+            .collect::<Vec<_>>();
+
+        CoinSelectionResult {
+            selected,
+            fee_amount,
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use std::str::FromStr;
+
+    use bitcoin::{OutPoint, Script, TxOut};
+
+    use super::*;
+    use crate::database::MemoryDatabase;
+    use crate::types::*;
+    use crate::wallet::Vbytes;
+
+    use rand::rngs::StdRng;
+    use rand::seq::SliceRandom;
+    use rand::{Rng, SeedableRng};
+
+    const P2WPKH_WITNESS_SIZE: usize = 73 + 33 + 2;
+
+    const FEE_AMOUNT: u64 = 50;
+
+    fn utxo(value: u64, index: u32) -> WeightedUtxo {
+        assert!(index < 10);
+        let outpoint = OutPoint::from_str(&format!(
+            "000000000000000000000000000000000000000000000000000000000000000{}:0",
+            index
+        ))
+        .unwrap();
+        WeightedUtxo {
+            satisfaction_weight: P2WPKH_WITNESS_SIZE,
+            utxo: Utxo::Local(LocalUtxo {
+                outpoint,
+                txout: TxOut {
+                    value,
+                    script_pubkey: Script::new(),
+                },
+                keychain: KeychainKind::External,
+            }),
+        }
+    }
+
+    fn get_test_utxos() -> Vec<WeightedUtxo> {
+        vec![
+            utxo(100_000, 0),
+            utxo(FEE_AMOUNT as u64 - 40, 1),
+            utxo(200_000, 2),
+        ]
+    }
+
+    fn generate_random_utxos(rng: &mut StdRng, utxos_number: usize) -> Vec<WeightedUtxo> {
+        let mut res = Vec::new();
+        for _ in 0..utxos_number {
+            res.push(WeightedUtxo {
+                satisfaction_weight: P2WPKH_WITNESS_SIZE,
+                utxo: Utxo::Local(LocalUtxo {
+                    outpoint: OutPoint::from_str(
+                        "ebd9813ecebc57ff8f30797de7c205e3c7498ca950ea4341ee51a685ff2fa30a:0",
+                    )
+                    .unwrap(),
+                    txout: TxOut {
+                        value: rng.gen_range(0, 200000000),
+                        script_pubkey: Script::new(),
+                    },
+                    keychain: KeychainKind::External,
+                }),
+            });
+        }
+        res
+    }
+
+    fn generate_same_value_utxos(utxos_value: u64, utxos_number: usize) -> Vec<WeightedUtxo> {
+        let utxo = WeightedUtxo {
+            satisfaction_weight: P2WPKH_WITNESS_SIZE,
+            utxo: Utxo::Local(LocalUtxo {
+                outpoint: OutPoint::from_str(
+                    "ebd9813ecebc57ff8f30797de7c205e3c7498ca950ea4341ee51a685ff2fa30a:0",
+                )
+                .unwrap(),
+                txout: TxOut {
+                    value: utxos_value,
+                    script_pubkey: Script::new(),
+                },
+                keychain: KeychainKind::External,
+            }),
+        };
+        vec![utxo; utxos_number]
+    }
+
+    fn sum_random_utxos(mut rng: &mut StdRng, utxos: &mut Vec<WeightedUtxo>) -> u64 {
+        let utxos_picked_len = rng.gen_range(2, utxos.len() / 2);
+        utxos.shuffle(&mut rng);
+        utxos[..utxos_picked_len]
+            .iter()
+            .map(|u| u.utxo.txout().value)
+            .sum()
+    }
+
+    #[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,
+                FEE_AMOUNT,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 3);
+        assert_eq!(result.selected_amount(), 300_010);
+        assert_eq!(result.fee_amount, 254)
+    }
+
+    #[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,
+                FEE_AMOUNT,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 3);
+        assert_eq!(result.selected_amount(), 300_010);
+        assert_eq!(result.fee_amount, 254);
+    }
+
+    #[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,
+                FEE_AMOUNT,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 1);
+        assert_eq!(result.selected_amount(), 200_000);
+        assert_eq!(result.fee_amount, 118);
+    }
+
+    #[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,
+                FEE_AMOUNT,
+            )
+            .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,
+                FEE_AMOUNT,
+            )
+            .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,
+                FEE_AMOUNT,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 3);
+        assert_eq!(result.selected_amount(), 300_000);
+        assert_eq!(result.fee_amount, 254);
+    }
+
+    #[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,
+                FEE_AMOUNT,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 3);
+        assert_eq!(result.selected_amount(), 300_010);
+        assert_eq!(result.fee_amount, 254);
+    }
+
+    #[test]
+    fn test_bnb_coin_selection_optional_are_enough() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        let result = BranchAndBoundCoinSelection::default()
+            .coin_select(
+                &database,
+                vec![],
+                utxos,
+                FeeRate::from_sat_per_vb(1.0),
+                299756,
+                FEE_AMOUNT,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 3);
+        assert_eq!(result.selected_amount(), 300010);
+        assert_eq!(result.fee_amount, 254);
+    }
+
+    #[test]
+    fn test_bnb_coin_selection_required_not_enough() {
+        let utxos = get_test_utxos();
+        let database = MemoryDatabase::default();
+
+        let required = vec![utxos[0].clone()];
+        let mut optional = utxos[1..].to_vec();
+        optional.push(utxo(500_000, 3));
+
+        // Defensive assertions, for sanity and in case someone changes the test utxos vector.
+        let amount: u64 = required.iter().map(|u| u.utxo.txout().value).sum();
+        assert_eq!(amount, 100_000);
+        let amount: u64 = optional.iter().map(|u| u.utxo.txout().value).sum();
+        assert!(amount > 150_000);
+
+        let result = BranchAndBoundCoinSelection::default()
+            .coin_select(
+                &database,
+                required,
+                optional,
+                FeeRate::from_sat_per_vb(1.0),
+                150_000,
+                FEE_AMOUNT,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 3);
+        assert_eq!(result.selected_amount(), 300_010);
+        assert!((result.fee_amount as f32 - 254.0).abs() < f32::EPSILON);
+    }
+
+    #[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,
+                FEE_AMOUNT,
+            )
+            .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,
+                FEE_AMOUNT,
+            )
+            .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,
+                FeeRate::from_sat_per_vb(1.0),
+                99932, // first utxo's effective value
+                0,
+            )
+            .unwrap();
+
+        assert_eq!(result.selected.len(), 1);
+        assert_eq!(result.selected_amount(), 100_000);
+        let input_size = (TXIN_BASE_WEIGHT + P2WPKH_WITNESS_SIZE).vbytes();
+        let epsilon = 0.5;
+        assert!((1.0 - (result.fee_amount as f32 / input_size as f32)).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,
+                )
+                .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, fee_rate))
+            .collect();
+
+        let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value);
+
+        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,
+                FEE_AMOUNT,
+                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, fee_rate))
+            .collect();
+
+        let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value);
+
+        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,
+                FEE_AMOUNT,
+                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 utxos: Vec<_> = generate_same_value_utxos(50_000, 10)
+            .into_iter()
+            .map(|u| OutputGroup::new(u, fee_rate))
+            .collect();
+
+        let curr_value = 0;
+
+        let curr_available_value = utxos.iter().fold(0, |acc, x| acc + x.effective_value);
+
+        // 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 i64 + 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.selected_amount(), 100_000);
+        assert_eq!(result.fee_amount, 186);
+    }
+
+    // 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, fee_rate))
+                .collect();
+
+            let curr_value = 0;
+
+            let curr_available_value = optional_utxos
+                .iter()
+                .fold(0, |acc, x| acc + x.effective_value);
+
+            let target_amount =
+                optional_utxos[3].effective_value + optional_utxos[23].effective_value;
+
+            let result = BranchAndBoundCoinSelection::new(0)
+                .bnb(
+                    vec![],
+                    optional_utxos,
+                    curr_value,
+                    curr_available_value,
+                    target_amount,
+                    0,
+                    0.0,
+                )
+                .unwrap();
+            assert_eq!(result.selected_amount(), target_amount as u64);
+        }
+    }
+
+    #[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, fee_rate))
+            .collect();
+
+        let result = BranchAndBoundCoinSelection::default().single_random_draw(
+            vec![],
+            utxos,
+            0,
+            target_amount as i64,
+            FEE_AMOUNT,
+        );
+
+        assert!(result.selected_amount() > target_amount);
+        assert_eq!(result.fee_amount, (50 + result.selected.len() * 68) as u64);
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/export.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/export.rs.html new file mode 100644 index 0000000000..a78d0d922f --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/export.rs.html @@ -0,0 +1,706 @@ +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
+344
+345
+346
+347
+348
+349
+350
+351
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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 = 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 = 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::{ShInner, WshInner};
+use miniscript::{Descriptor, DescriptorPublicKey, ScriptContext, Terminal};
+
+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)
+    }
+}
+
+fn remove_checksum(s: String) -> String {
+    s.splitn(2, '#').next().map(String::from).unwrap()
+}
+
+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, 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()));
+        let descriptor = remove_checksum(descriptor);
+        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.confirmation_time.map(|c| c.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>| {
+            let descriptor =
+                d.to_string_with_secret(&wallet.change_signers.as_key_map(wallet.secp_ctx()));
+            remove_checksum(descriptor)
+        };
+        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")
+            }
+        }
+
+        // pkh(), wpkh(), sh(wpkh()) are always fine, as well as multi() and sortedmulti()
+        match Descriptor::<String>::from_str(descriptor).map_err(|_| "Invalid descriptor")? {
+            Descriptor::Pkh(_) | Descriptor::Wpkh(_) => Ok(()),
+            Descriptor::Sh(sh) => match sh.as_inner() {
+                ShInner::Wpkh(_) => Ok(()),
+                ShInner::SortedMulti(_) => Ok(()),
+                ShInner::Wsh(wsh) => match wsh.as_inner() {
+                    WshInner::SortedMulti(_) => Ok(()),
+                    WshInner::Ms(ms) => check_ms(&ms.node),
+                },
+                ShInner::Ms(ms) => check_ms(&ms.node),
+            },
+            Descriptor::Wsh(wsh) => match wsh.as_inner() {
+                WshInner::SortedMulti(_) => Ok(()),
+                WshInner::Ms(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::Wallet;
+    use crate::ConfirmationTime;
+
+    fn get_test_db() -> MemoryDatabase {
+        let mut db = MemoryDatabase::new();
+        db.set_tx(&TransactionDetails {
+            transaction: None,
+            txid: Txid::from_str(
+                "4ddff1fa33af17f377f62b72357b43107c19110a8009b36fb832af505efed98a",
+            )
+            .unwrap(),
+
+            received: 100_000,
+            sent: 0,
+            fee: Some(500),
+            confirmation_time: Some(ConfirmationTime {
+                timestamp: 12345678,
+                height: 5000,
+            }),
+            verified: true,
+        })
+        .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 = 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 =
+            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 = 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 = 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 = 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/latest/src/bdk/wallet/mod.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/mod.rs.html new file mode 100644 index 0000000000..e4602b959b --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/mod.rs.html @@ -0,0 +1,7940 @@ +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
+3412
+3413
+3414
+3415
+3416
+3417
+3418
+3419
+3420
+3421
+3422
+3423
+3424
+3425
+3426
+3427
+3428
+3429
+3430
+3431
+3432
+3433
+3434
+3435
+3436
+3437
+3438
+3439
+3440
+3441
+3442
+3443
+3444
+3445
+3446
+3447
+3448
+3449
+3450
+3451
+3452
+3453
+3454
+3455
+3456
+3457
+3458
+3459
+3460
+3461
+3462
+3463
+3464
+3465
+3466
+3467
+3468
+3469
+3470
+3471
+3472
+3473
+3474
+3475
+3476
+3477
+3478
+3479
+3480
+3481
+3482
+3483
+3484
+3485
+3486
+3487
+3488
+3489
+3490
+3491
+3492
+3493
+3494
+3495
+3496
+3497
+3498
+3499
+3500
+3501
+3502
+3503
+3504
+3505
+3506
+3507
+3508
+3509
+3510
+3511
+3512
+3513
+3514
+3515
+3516
+3517
+3518
+3519
+3520
+3521
+3522
+3523
+3524
+3525
+3526
+3527
+3528
+3529
+3530
+3531
+3532
+3533
+3534
+3535
+3536
+3537
+3538
+3539
+3540
+3541
+3542
+3543
+3544
+3545
+3546
+3547
+3548
+3549
+3550
+3551
+3552
+3553
+3554
+3555
+3556
+3557
+3558
+3559
+3560
+3561
+3562
+3563
+3564
+3565
+3566
+3567
+3568
+3569
+3570
+3571
+3572
+3573
+3574
+3575
+3576
+3577
+3578
+3579
+3580
+3581
+3582
+3583
+3584
+3585
+3586
+3587
+3588
+3589
+3590
+3591
+3592
+3593
+3594
+3595
+3596
+3597
+3598
+3599
+3600
+3601
+3602
+3603
+3604
+3605
+3606
+3607
+3608
+3609
+3610
+3611
+3612
+3613
+3614
+3615
+3616
+3617
+3618
+3619
+3620
+3621
+3622
+3623
+3624
+3625
+3626
+3627
+3628
+3629
+3630
+3631
+3632
+3633
+3634
+3635
+3636
+3637
+3638
+3639
+3640
+3641
+3642
+3643
+3644
+3645
+3646
+3647
+3648
+3649
+3650
+3651
+3652
+3653
+3654
+3655
+3656
+3657
+3658
+3659
+3660
+3661
+3662
+3663
+3664
+3665
+3666
+3667
+3668
+3669
+3670
+3671
+3672
+3673
+3674
+3675
+3676
+3677
+3678
+3679
+3680
+3681
+3682
+3683
+3684
+3685
+3686
+3687
+3688
+3689
+3690
+3691
+3692
+3693
+3694
+3695
+3696
+3697
+3698
+3699
+3700
+3701
+3702
+3703
+3704
+3705
+3706
+3707
+3708
+3709
+3710
+3711
+3712
+3713
+3714
+3715
+3716
+3717
+3718
+3719
+3720
+3721
+3722
+3723
+3724
+3725
+3726
+3727
+3728
+3729
+3730
+3731
+3732
+3733
+3734
+3735
+3736
+3737
+3738
+3739
+3740
+3741
+3742
+3743
+3744
+3745
+3746
+3747
+3748
+3749
+3750
+3751
+3752
+3753
+3754
+3755
+3756
+3757
+3758
+3759
+3760
+3761
+3762
+3763
+3764
+3765
+3766
+3767
+3768
+3769
+3770
+3771
+3772
+3773
+3774
+3775
+3776
+3777
+3778
+3779
+3780
+3781
+3782
+3783
+3784
+3785
+3786
+3787
+3788
+3789
+3790
+3791
+3792
+3793
+3794
+3795
+3796
+3797
+3798
+3799
+3800
+3801
+3802
+3803
+3804
+3805
+3806
+3807
+3808
+3809
+3810
+3811
+3812
+3813
+3814
+3815
+3816
+3817
+3818
+3819
+3820
+3821
+3822
+3823
+3824
+3825
+3826
+3827
+3828
+3829
+3830
+3831
+3832
+3833
+3834
+3835
+3836
+3837
+3838
+3839
+3840
+3841
+3842
+3843
+3844
+3845
+3846
+3847
+3848
+3849
+3850
+3851
+3852
+3853
+3854
+3855
+3856
+3857
+3858
+3859
+3860
+3861
+3862
+3863
+3864
+3865
+3866
+3867
+3868
+3869
+3870
+3871
+3872
+3873
+3874
+3875
+3876
+3877
+3878
+3879
+3880
+3881
+3882
+3883
+3884
+3885
+3886
+3887
+3888
+3889
+3890
+3891
+3892
+3893
+3894
+3895
+3896
+3897
+3898
+3899
+3900
+3901
+3902
+3903
+3904
+3905
+3906
+3907
+3908
+3909
+3910
+3911
+3912
+3913
+3914
+3915
+3916
+3917
+3918
+3919
+3920
+3921
+3922
+3923
+3924
+3925
+3926
+3927
+3928
+3929
+3930
+3931
+3932
+3933
+3934
+3935
+3936
+3937
+3938
+3939
+3940
+3941
+3942
+3943
+3944
+3945
+3946
+3947
+3948
+3949
+3950
+3951
+3952
+3953
+3954
+3955
+3956
+3957
+3958
+3959
+3960
+3961
+3962
+3963
+3964
+3965
+3966
+3967
+3968
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! Wallet
+//!
+//! This module defines the [`Wallet`] structure.
+
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::collections::{BTreeMap, HashSet};
+use std::fmt;
+use std::ops::{Deref, DerefMut};
+use std::str::FromStr;
+use std::sync::Arc;
+
+use bitcoin::secp256k1::Secp256k1;
+
+use bitcoin::consensus::encode::serialize;
+use bitcoin::util::base58;
+use bitcoin::util::psbt::raw::Key as PsbtKey;
+use bitcoin::util::psbt::Input;
+use bitcoin::util::psbt::PartiallySignedTransaction as Psbt;
+use bitcoin::{Address, Network, OutPoint, Script, SigHashType, Transaction, TxOut, Txid};
+
+use miniscript::descriptor::DescriptorTrait;
+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;
+#[cfg(feature = "verify")]
+#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
+pub mod verify;
+
+pub use utils::IsDust;
+
+use address_validator::AddressValidator;
+use coin_selection::DefaultCoinSelectionAlgorithm;
+use signer::{SignOptions, Signer, SignerOrdering, SignersContainer};
+use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxParams};
+use utils::{check_nlocktime, check_nsequence_rbf, After, Older, SecpCtx, DUST_LIMIT_SATOSHI};
+
+use crate::blockchain::{Blockchain, Progress};
+use crate::database::memory::MemoryDatabase;
+use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
+use crate::descriptor::derived::AsDerived;
+use crate::descriptor::policy::BuildSatisfaction;
+use crate::descriptor::{
+    get_checksum, into_wallet_descriptor_checked, DerivedDescriptor, DerivedDescriptorMeta,
+    DescriptorMeta, DescriptorScripts, ExtendedDescriptor, ExtractPolicy, IntoWalletDescriptor,
+    Policy, XKeyUtils,
+};
+use crate::error::Error;
+use crate::psbt::PsbtUtils;
+use crate::signer::SignerError;
+use crate::testutils;
+use crate::types::*;
+
+const CACHE_ADDR_BATCH_SIZE: u32 = 100;
+
+/// 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_address), [returning the balance](Wallet::get_balance),
+/// [creating transactions](Wallet::build_tx), etc.
+///
+/// A wallet can be either "online" if the [`blockchain`](crate::blockchain) type provided
+/// implements [`Blockchain`], or "offline" if it is the unit type `()`. Offline wallets only expose
+/// methods that don't need any interaction with the blockchain to work.
+#[derive(Debug)]
+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: B,
+    database: RefCell<D>,
+
+    secp: SecpCtx,
+}
+
+impl<D> Wallet<(), D>
+where
+    D: BatchDatabase,
+{
+    /// Create a new "offline" wallet
+    pub fn new_offline<E: IntoWalletDescriptor>(
+        descriptor: E,
+        change_descriptor: Option<E>,
+        network: Network,
+        database: D,
+    ) -> Result<Self, Error> {
+        Self::_new(descriptor, change_descriptor, network, database, (), None)
+    }
+}
+
+impl<B, D> Wallet<B, D>
+where
+    D: BatchDatabase,
+{
+    fn _new<E: IntoWalletDescriptor>(
+        descriptor: E,
+        change_descriptor: Option<E>,
+        network: Network,
+        mut database: D,
+        client: B,
+        current_height: Option<u32>,
+    ) -> Result<Self, Error> {
+        let secp = Secp256k1::new();
+
+        let (descriptor, keymap) = into_wallet_descriptor_checked(descriptor, &secp, 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) =
+                    into_wallet_descriptor_checked(desc, &secp, 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,
+            client,
+            database: RefCell::new(database),
+            secp,
+        })
+    }
+
+    /// Get the Bitcoin network the wallet is using.
+    pub fn network(&self) -> Network {
+        self.network
+    }
+}
+
+/// The address index selection strategy to use to derived an address from the wallet's external
+/// descriptor. See [`Wallet::get_address`]. If you're unsure which one to use use `WalletIndex::New`.
+#[derive(Debug)]
+pub enum AddressIndex {
+    /// Return a new address after incrementing the current descriptor index.
+    New,
+    /// Return the address for the current descriptor index if it has not been used in a received
+    /// transaction. Otherwise return a new address as with [`AddressIndex::New`].
+    ///
+    /// Use with caution, if the wallet has not yet detected an address has been used it could
+    /// return an already used address. This function is primarily meant for situations where the
+    /// caller is untrusted; for example when deriving donation addresses on-demand for a public
+    /// web page.
+    LastUnused,
+    /// Return the address for a specific descriptor index. Does not change the current descriptor
+    /// index used by `AddressIndex::New` and `AddressIndex::LastUsed`.
+    ///
+    /// Use with caution, if an index is given that is less than the current descriptor index
+    /// then the returned address may have already been used.
+    Peek(u32),
+    /// Return the address for a specific descriptor index and reset the current descriptor index
+    /// used by `AddressIndex::New` and `AddressIndex::LastUsed` to this value.
+    ///
+    /// Use with caution, if an index is given that is less than the current descriptor index
+    /// then the returned address and subsequent addresses returned by calls to `AddressIndex::New`
+    /// and `AddressIndex::LastUsed` may have already been used. Also if the index is reset to a
+    /// value earlier than the [`crate::blockchain::Blockchain`] stop_gap (default is 20) then a
+    /// larger stop_gap should be used to monitor for all possibly used addresses.
+    Reset(u32),
+}
+
+/// A derived address and the index it was found at
+/// For convenience this automatically derefs to `Address`
+#[derive(Debug, PartialEq)]
+pub struct AddressInfo {
+    /// Child index of this address
+    pub index: u32,
+    /// Address
+    pub address: Address,
+}
+
+impl Deref for AddressInfo {
+    type Target = Address;
+
+    fn deref(&self) -> &Self::Target {
+        &self.address
+    }
+}
+
+impl fmt::Display for AddressInfo {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.address)
+    }
+}
+
+// offline actions, always available
+impl<B, D> Wallet<B, D>
+where
+    D: BatchDatabase,
+{
+    // Return a newly derived address using the external descriptor
+    fn get_new_address(&self) -> Result<AddressInfo, Error> {
+        let incremented_index = self.fetch_and_increment_index(KeychainKind::External)?;
+
+        let address_result = self
+            .descriptor
+            .as_derived(incremented_index, &self.secp)
+            .address(self.network);
+
+        address_result
+            .map(|address| AddressInfo {
+                address,
+                index: incremented_index,
+            })
+            .map_err(|_| Error::ScriptDoesntHaveAddressForm)
+    }
+
+    // Return the the last previously derived address if it has not been used in a received
+    // transaction. Otherwise return a new address using [`Wallet::get_new_address`].
+    fn get_unused_address(&self) -> Result<AddressInfo, Error> {
+        let current_index = self.fetch_index(KeychainKind::External)?;
+
+        let derived_key = self.descriptor.as_derived(current_index, &self.secp);
+
+        let script_pubkey = derived_key.script_pubkey();
+
+        let found_used = self
+            .list_transactions(true)?
+            .iter()
+            .flat_map(|tx_details| tx_details.transaction.as_ref())
+            .flat_map(|tx| tx.output.iter())
+            .any(|o| o.script_pubkey == script_pubkey);
+
+        if found_used {
+            self.get_new_address()
+        } else {
+            derived_key
+                .address(self.network)
+                .map(|address| AddressInfo {
+                    address,
+                    index: current_index,
+                })
+                .map_err(|_| Error::ScriptDoesntHaveAddressForm)
+        }
+    }
+
+    // Return derived address for the external descriptor at a specific index
+    fn peek_address(&self, index: u32) -> Result<AddressInfo, Error> {
+        self.descriptor
+            .as_derived(index, &self.secp)
+            .address(self.network)
+            .map(|address| AddressInfo { index, address })
+            .map_err(|_| Error::ScriptDoesntHaveAddressForm)
+    }
+
+    // Return derived address for the external descriptor at a specific index and reset current
+    // address index
+    fn reset_address(&self, index: u32) -> Result<AddressInfo, Error> {
+        self.set_index(KeychainKind::External, index)?;
+
+        self.descriptor
+            .as_derived(index, &self.secp)
+            .address(self.network)
+            .map(|address| AddressInfo { index, address })
+            .map_err(|_| Error::ScriptDoesntHaveAddressForm)
+    }
+
+    /// Return a derived address using the external descriptor, see [`AddressIndex`] for
+    /// available address index selection strategies. If none of the keys in the descriptor are derivable
+    /// (ie. does not end with /*) then the same address will always be returned for any [`AddressIndex`].
+    pub fn get_address(&self, address_index: AddressIndex) -> Result<AddressInfo, Error> {
+        match address_index {
+            AddressIndex::New => self.get_new_address(),
+            AddressIndex::LastUnused => self.get_unused_address(),
+            AddressIndex::Peek(index) => self.peek_address(index),
+            AddressIndex::Reset(index) => self.reset_address(index),
+        }
+    }
+
+    /// 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<LocalUtxo>, Error> {
+        self.database.borrow().iter_utxos()
+    }
+
+    /// Returns the `UTXO` owned by this wallet corresponding to `outpoint` if it exists in the
+    /// wallet's database.
+    pub fn get_utxo(&self, outpoint: OutPoint) -> Result<Option<LocalUtxo>, Error> {
+        self.database.borrow().get_utxo(&outpoint)
+    }
+
+    /// 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,
+        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(signer.id(&self.secp), 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);
+    }
+
+    /// Start building a transaction.
+    ///
+    /// This returns a blank [`TxBuilder`] from which you can specify the parameters for the transaction.
+    ///
+    /// ## Example
+    ///
+    /// ```
+    /// # use std::str::FromStr;
+    /// # use bitcoin::*;
+    /// # use bdk::*;
+    /// # use bdk::database::*;
+    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+    /// # let wallet = doctest_wallet!();
+    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+    /// let (psbt, details) = {
+    ///    let mut builder =  wallet.build_tx();
+    ///    builder
+    ///        .add_recipient(to_address.script_pubkey(), 50_000);
+    ///    builder.finish()?
+    /// };
+    ///
+    /// // sign and broadcast ...
+    /// # Ok::<(), bdk::Error>(())
+    /// ```
+    ///
+    /// [`TxBuilder`]: crate::TxBuilder
+    pub fn build_tx(&self) -> TxBuilder<'_, B, D, DefaultCoinSelectionAlgorithm, CreateTx> {
+        TxBuilder {
+            wallet: self,
+            params: TxParams::default(),
+            coin_selection: DefaultCoinSelectionAlgorithm::default(),
+            phantom: core::marker::PhantomData,
+        }
+    }
+
+    pub(crate) fn create_tx<Cs: coin_selection::CoinSelectionAlgorithm<D>>(
+        &self,
+        coin_selection: Cs,
+        params: TxParams,
+    ) -> Result<(Psbt, TransactionDetails), Error> {
+        let external_policy = self
+            .descriptor
+            .extract_policy(&self.signers, BuildSatisfaction::None, &self.secp)?
+            .unwrap();
+        let internal_policy = self
+            .change_descriptor
+            .as_ref()
+            .map(|desc| {
+                Ok::<_, Error>(
+                    desc.extract_policy(&self.change_signers, BuildSatisfaction::None, &self.secp)?
+                        .unwrap(),
+                )
+            })
+            .transpose()?;
+
+        // The policy allows spending external outputs, but it requires a policy path that hasn't been
+        // provided
+        if params.change_policy != tx_builder::ChangeSpendPolicy::OnlyChange
+            && external_policy.requires_path()
+            && params.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 params.change_policy != tx_builder::ChangeSpendPolicy::ChangeForbidden
+                && internal_policy.requires_path()
+                && params.internal_policy_path.is_none()
+            {
+                return Err(Error::SpendingPolicyRequired(KeychainKind::Internal));
+            };
+        }
+
+        let external_requirements = external_policy.get_condition(
+            params
+                .external_policy_path
+                .as_ref()
+                .unwrap_or(&BTreeMap::new()),
+        )?;
+        let internal_requirements = internal_policy
+            .map(|policy| {
+                Ok::<_, Error>(
+                    policy.get_condition(
+                        params
+                            .internal_policy_path
+                            .as_ref()
+                            .unwrap_or(&BTreeMap::new()),
+                    )?,
+                )
+            })
+            .transpose()?;
+
+        let requirements =
+            external_requirements.merge(&internal_requirements.unwrap_or_default())?;
+        debug!("Policy requirements: {:?}", requirements);
+
+        let version = match params.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 params.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 (params.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 (fee_rate, mut fee_amount) = match params
+            .fee_policy
+            .as_ref()
+            .unwrap_or(&FeePolicy::FeeRate(FeeRate::default()))
+        {
+            //FIXME: see https://github.com/bitcoindevkit/bdk/issues/256
+            FeePolicy::FeeAmount(fee) => {
+                if let Some(previous_fee) = params.bumping_fee {
+                    if *fee < previous_fee.absolute {
+                        return Err(Error::FeeTooLow {
+                            required: previous_fee.absolute,
+                        });
+                    }
+                }
+                (FeeRate::from_sat_per_vb(0.0), *fee)
+            }
+            FeePolicy::FeeRate(rate) => {
+                if let Some(previous_fee) = params.bumping_fee {
+                    let required_feerate = FeeRate::from_sat_per_vb(previous_fee.rate + 1.0);
+                    if *rate < required_feerate {
+                        return Err(Error::FeeRateTooLow {
+                            required: required_feerate,
+                        });
+                    }
+                }
+                (*rate, 0)
+            }
+        };
+
+        let mut tx = Transaction {
+            version,
+            lock_time,
+            input: vec![],
+            output: vec![],
+        };
+
+        if params.manually_selected_only && params.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;
+
+        fee_amount += fee_rate.fee_wu(tx.get_weight());
+
+        let recipients = params.recipients.iter().map(|(r, v)| (r, *v));
+
+        for (index, (script_pubkey, value)) in recipients.enumerate() {
+            if value.is_dust() {
+                return Err(Error::OutputBelowDustLimit(index));
+            }
+
+            if self.is_mine(script_pubkey)? {
+                received += value;
+            }
+
+            let new_out = TxOut {
+                script_pubkey: script_pubkey.clone(),
+                value,
+            };
+            fee_amount += fee_rate.fee_vb(serialize(&new_out).len());
+
+            tx.output.push(new_out);
+
+            outgoing += value;
+        }
+
+        if params.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(
+            params.change_policy,
+            &params.unspendable,
+            params.utxos.clone(),
+            params.drain_wallet,
+            params.manually_selected_only,
+            params.bumping_fee.is_some(), // we mandate confirmed transactions if we're bumping the fee
+        )?;
+
+        let coin_selection = coin_selection.coin_select(
+            self.database.borrow().deref(),
+            required_utxos,
+            optional_utxos,
+            fee_rate,
+            outgoing,
+            fee_amount,
+        )?;
+        let mut fee_amount = coin_selection.fee_amount;
+
+        tx.input = coin_selection
+            .selected
+            .iter()
+            .map(|u| bitcoin::TxIn {
+                previous_output: u.outpoint(),
+                script_sig: Script::default(),
+                sequence: n_sequence,
+                witness: vec![],
+            })
+            .collect();
+
+        // prepare the drain output
+        let mut drain_output = {
+            let script_pubkey = match params.drain_to {
+                Some(ref drain_recipient) => drain_recipient.clone(),
+                None => self.get_change_address()?,
+            };
+
+            TxOut {
+                script_pubkey,
+                value: 0,
+            }
+        };
+
+        fee_amount += fee_rate.fee_vb(serialize(&drain_output).len());
+
+        let drain_val = (coin_selection.selected_amount() - outgoing).saturating_sub(fee_amount);
+
+        if tx.output.is_empty() {
+            if params.drain_to.is_some() {
+                if drain_val.is_dust() {
+                    return Err(Error::InsufficientFunds {
+                        needed: DUST_LIMIT_SATOSHI,
+                        available: drain_val,
+                    });
+                }
+            } else {
+                return Err(Error::NoRecipients);
+            }
+        }
+
+        if drain_val.is_dust() {
+            fee_amount += drain_val;
+        } else {
+            drain_output.value = drain_val;
+            if self.is_mine(&drain_output.script_pubkey)? {
+                received += drain_val;
+            }
+            tx.output.push(drain_output);
+        }
+
+        // sort input/outputs according to the chosen algorithm
+        params.ordering.sort_tx(&mut tx);
+
+        let txid = tx.txid();
+        let sent = coin_selection.local_selected_amount();
+        let psbt = self.complete_transaction(tx, coin_selection.selected, params)?;
+
+        let transaction_details = TransactionDetails {
+            transaction: None,
+            txid,
+            confirmation_time: None,
+            received,
+            sent,
+            fee: Some(fee_amount),
+            verified: true,
+        };
+
+        Ok((psbt, transaction_details))
+    }
+
+    /// Bump the fee of a transaction previously created with this wallet.
+    ///
+    /// Returns an error if the transaction is already confirmed or doesn't explicitly signal
+    /// *repalce by fee* (RBF). If the transaction can be fee bumped then it returns a [`TxBuilder`]
+    /// pre-populated with the inputs and outputs of the original transaction.
+    ///
+    /// ## Example
+    ///
+    /// ```no_run
+    /// # // TODO: remove norun -- bumping fee seems to need the tx in the wallet database first.
+    /// # use std::str::FromStr;
+    /// # use bitcoin::*;
+    /// # use bdk::*;
+    /// # use bdk::database::*;
+    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+    /// # let wallet = doctest_wallet!();
+    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+    /// let (mut psbt, _) = {
+    ///     let mut builder = wallet.build_tx();
+    ///     builder
+    ///         .add_recipient(to_address.script_pubkey(), 50_000)
+    ///         .enable_rbf();
+    ///     builder.finish()?
+    /// };
+    /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
+    /// let tx = psbt.extract_tx();
+    /// // broadcast tx but it's taking too long to confirm so we want to bump the fee
+    /// let (mut psbt, _) =  {
+    ///     let mut builder = wallet.build_fee_bump(tx.txid())?;
+    ///     builder
+    ///         .fee_rate(FeeRate::from_sat_per_vb(5.0));
+    ///     builder.finish()?
+    /// };
+    ///
+    /// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
+    /// let fee_bumped_tx = psbt.extract_tx();
+    /// // broadcast fee_bumped_tx to replace original
+    /// # 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 build_fee_bump(
+        &self,
+        txid: Txid,
+    ) -> Result<TxBuilder<'_, B, D, DefaultCoinSelectionAlgorithm, BumpFee>, 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.confirmation_time.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);
+        }
+
+        let feerate = FeeRate::from_wu(
+            details.fee.ok_or(Error::FeeRateUnavailable)?,
+            tx.get_weight(),
+        );
+
+        // remove the inputs from the tx and process them
+        let original_txin = tx.input.drain(..).collect::<Vec<_>>();
+        let original_utxos = original_txin
+            .iter()
+            .map(|txin| -> Result<_, 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()
+                            .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 = LocalUtxo {
+                    outpoint: txin.previous_output,
+                    txout,
+                    keychain,
+                };
+
+                Ok(WeightedUtxo {
+                    satisfaction_weight: weight,
+                    utxo: Utxo::Local(utxo),
+                })
+            })
+            .collect::<Result<Vec<_>, _>>()?;
+
+        if tx.output.len() > 1 {
+            let mut change_index = None;
+            for (index, txout) in tx.output.iter().enumerate() {
+                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_index = Some(index),
+                    _ => {}
+                }
+            }
+
+            if let Some(change_index) = change_index {
+                tx.output.remove(change_index);
+            }
+        }
+
+        let params = TxParams {
+            // TODO: figure out what rbf option should be?
+            version: Some(tx_builder::Version(tx.version)),
+            recipients: tx
+                .output
+                .into_iter()
+                .map(|txout| (txout.script_pubkey, txout.value))
+                .collect(),
+            utxos: original_utxos,
+            bumping_fee: Some(tx_builder::PreviousFee {
+                absolute: details.fee.ok_or(Error::FeeRateUnavailable)?,
+                rate: feerate.as_sat_vb(),
+            }),
+            ..Default::default()
+        };
+
+        Ok(TxBuilder {
+            wallet: self,
+            params,
+            coin_selection: DefaultCoinSelectionAlgorithm::default(),
+            phantom: core::marker::PhantomData,
+        })
+    }
+
+    /// Sign a transaction with all the wallet's signers, in the order specified by every signer's
+    /// [`SignerOrdering`]
+    ///
+    /// The [`SignOptions`] can be used to tweak the behavior of the software signers, and the way
+    /// the transaction is finalized at the end. Note that it can't be guaranteed that *every*
+    /// signers will follow the options, but the "software signers" (WIF keys and `xprv`) defined
+    /// in this library will.
+    ///
+    /// ## Example
+    ///
+    /// ```
+    /// # use std::str::FromStr;
+    /// # use bitcoin::*;
+    /// # use bdk::*;
+    /// # use bdk::database::*;
+    /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+    /// # let wallet = doctest_wallet!();
+    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+    /// let (mut psbt, _) = {
+    ///     let mut builder = wallet.build_tx();
+    ///     builder.add_recipient(to_address.script_pubkey(), 50_000);
+    ///     builder.finish()?
+    /// };
+    /// let  finalized = wallet.sign(&mut psbt, SignOptions::default())?;
+    /// assert!(finalized, "we should have signed all the inputs");
+    /// # Ok::<(), bdk::Error>(())
+    pub fn sign(&self, psbt: &mut Psbt, sign_options: SignOptions) -> Result<bool, Error> {
+        // this helps us doing our job later
+        self.add_input_hd_keypaths(psbt)?;
+
+        // If we aren't allowed to use `witness_utxo`, ensure that every input but finalized one
+        // has the `non_witness_utxo`
+        if !sign_options.trust_witness_utxo
+            && psbt
+                .inputs
+                .iter()
+                .filter(|i| i.final_script_witness.is_none() && i.final_script_sig.is_none())
+                .any(|i| i.non_witness_utxo.is_none())
+        {
+            return Err(Error::Signer(signer::SignerError::MissingNonWitnessUtxo));
+        }
+
+        // If the user hasn't explicitly opted-in, refuse to sign the transaction unless every input
+        // is using `SIGHASH_ALL`
+        if !sign_options.allow_all_sighashes
+            && !psbt
+                .inputs
+                .iter()
+                .all(|i| i.sighash_type.is_none() || i.sighash_type == Some(SigHashType::All))
+        {
+            return Err(Error::Signer(signer::SignerError::NonStandardSighash));
+        }
+
+        for signer in self
+            .signers
+            .signers()
+            .iter()
+            .chain(self.change_signers.signers().iter())
+        {
+            if signer.sign_whole_tx() {
+                signer.sign(psbt, None, &self.secp)?;
+            } else {
+                for index in 0..psbt.inputs.len() {
+                    signer.sign(psbt, Some(index), &self.secp)?;
+                }
+            }
+        }
+
+        // attempt to finalize
+        self.finalize_psbt(psbt, sign_options)
+    }
+
+    /// 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,
+                BuildSatisfaction::None,
+                &self.secp,
+            )?),
+            (KeychainKind::Internal, None) => Ok(None),
+            (KeychainKind::Internal, Some(desc)) => Ok(desc.extract_policy(
+                &self.change_signers,
+                BuildSatisfaction::None,
+                &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
+    ///
+    /// The [`SignOptions`] can be used to tweak the behavior of the finalizer.
+    pub fn finalize_psbt(&self, psbt: &mut Psbt, sign_options: SignOptions) -> Result<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
+                .get(n)
+                .ok_or(Error::Signer(SignerError::InputIndexOutOfRange))?;
+            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.confirmation_time.map(|c| c.height).unwrap_or(u32::MAX));
+            let current_height = sign_options.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 `bip32_derivation`,
+            //   `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();
+                    match desc.satisfy(
+                        &mut tmp_input,
+                        (
+                            PsbtInputSatisfier::new(psbt, n),
+                            After::new(current_height, false),
+                            Older::new(current_height, create_height, false),
+                        ),
+                    ) {
+                        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(finished)
+    }
+
+    /// Return the secp256k1 context used for all signing operations
+    pub fn secp_ctx(&self) -> &SecpCtx {
+        &self.secp
+    }
+
+    /// Returns the descriptor used to create adddresses for a particular `keychain`.
+    pub fn get_descriptor_for_keychain(&self, keychain: KeychainKind) -> &ExtendedDescriptor {
+        let (descriptor, _) = self._get_descriptor_for_keychain(keychain);
+        descriptor
+    }
+
+    // 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<DerivedDescriptor<'_>>, Error> {
+        Ok(self
+            .database
+            .borrow()
+            .get_path_from_script_pubkey(&txout.script_pubkey)?
+            .map(|(keychain, child)| (self.get_descriptor_for_keychain(keychain), child))
+            .map(|(desc, child)| desc.as_derived(child, &self.secp)))
+    }
+
+    fn get_change_address(&self) -> Result<Script, Error> {
+        let (desc, keychain) = self._get_descriptor_for_keychain(KeychainKind::Internal);
+        let index = self.fetch_and_increment_index(keychain)?;
+
+        Ok(desc.as_derived(index, &self.secp).script_pubkey())
+    }
+
+    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_deriveable() {
+            false => 0,
+            true => 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 derived_descriptor = descriptor.as_derived(index, &self.secp);
+
+        let hd_keypaths = derived_descriptor.get_hd_keypaths(&self.secp)?;
+        let script = derived_descriptor.script_pubkey();
+
+        for validator in &self.address_validators {
+            validator.validate(keychain, &hd_keypaths, &script)?;
+        }
+
+        Ok(index)
+    }
+
+    fn fetch_index(&self, keychain: KeychainKind) -> Result<u32, Error> {
+        let (descriptor, keychain) = self._get_descriptor_for_keychain(keychain);
+        let index = match descriptor.is_deriveable() {
+            false => Some(0),
+            true => self.database.borrow_mut().get_last_index(keychain)?,
+        };
+
+        if let Some(i) = index {
+            Ok(i)
+        } else {
+            self.fetch_and_increment_index(keychain)
+        }
+    }
+
+    fn set_index(&self, keychain: KeychainKind, index: u32) -> Result<(), Error> {
+        self.database.borrow_mut().set_last_index(keychain, index)?;
+        Ok(())
+    }
+
+    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_deriveable() {
+            if from > 0 {
+                return Ok(());
+            }
+
+            count = 1;
+        }
+
+        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.as_derived(i, &self.secp).script_pubkey(),
+                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<(LocalUtxo, usize)>, Error> {
+        Ok(self
+            .list_unspent()?
+            .into_iter()
+            .map(|utxo| {
+                let keychain = utxo.keychain;
+                (
+                    utxo,
+                    self.get_descriptor_for_keychain(keychain)
+                        .max_satisfaction_weight()
+                        .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: Vec<WeightedUtxo>,
+        must_use_all_available: bool,
+        manual_only: bool,
+        must_only_use_confirmed_tx: bool,
+    ) -> Result<(Vec<WeightedUtxo>, Vec<WeightedUtxo>), Error> {
+        //    must_spend <- manually selected utxos
+        //    may_spend  <- all other available utxos
+        let mut may_spend = self.get_available_utxos()?;
+
+        may_spend.retain(|may_spend| {
+            !manually_selected
+                .iter()
+                .any(|manually_selected| manually_selected.utxo.outpoint() == may_spend.0.outpoint)
+        });
+        let mut must_spend = manually_selected;
+
+        // 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();
+                may_spend
+                    .iter()
+                    .map(|u| {
+                        database
+                            .get_tx(&u.0.outpoint.txid, true)
+                            .map(|tx| match tx {
+                                None => false,
+                                Some(tx) => tx.confirmation_time.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
+        });
+
+        let mut may_spend = may_spend
+            .into_iter()
+            .map(|(local_utxo, satisfaction_weight)| WeightedUtxo {
+                satisfaction_weight,
+                utxo: Utxo::Local(local_utxo),
+            })
+            .collect();
+
+        if must_use_all_available {
+            must_spend.append(&mut may_spend);
+        }
+
+        Ok((must_spend, may_spend))
+    }
+
+    fn complete_transaction(
+        &self,
+        tx: Transaction,
+        selected: Vec<Utxo>,
+        params: TxParams,
+    ) -> Result<Psbt, Error> {
+        use bitcoin::util::psbt::serialize::Serialize;
+
+        let mut psbt = Psbt::from_unsigned_tx(tx)?;
+
+        if params.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 mut 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.remove(&input.previous_output) {
+                Some(utxo) => utxo,
+                None => continue,
+            };
+
+            match utxo {
+                Utxo::Local(utxo) => {
+                    *psbt_input =
+                        match self.get_psbt_input(utxo, params.sighash, params.only_witness_utxo) {
+                            Ok(psbt_input) => psbt_input,
+                            Err(e) => match e {
+                                Error::UnknownUtxo => Input {
+                                    sighash_type: params.sighash,
+                                    ..Input::default()
+                                },
+                                _ => return Err(e),
+                            },
+                        }
+                }
+                Utxo::Foreign {
+                    psbt_input: foreign_psbt_input,
+                    outpoint,
+                } => {
+                    if !params.only_witness_utxo && foreign_psbt_input.non_witness_utxo.is_none() {
+                        return Err(Error::Generic(format!(
+                            "Missing non_witness_utxo on foreign utxo {}",
+                            outpoint
+                        )));
+                    }
+                    *psbt_input = *foreign_psbt_input;
+                }
+            }
+        }
+
+        // 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);
+                let derived_descriptor = desc.as_derived(child, &self.secp);
+
+                psbt_output.bip32_derivation = derived_descriptor.get_hd_keypaths(&self.secp)?;
+                if params.include_output_redeem_witness_script {
+                    psbt_output.witness_script = derived_descriptor.psbt_witness_script();
+                    psbt_output.redeem_script = derived_descriptor.psbt_redeem_script();
+                };
+            }
+        }
+
+        Ok(psbt)
+    }
+
+    /// get the corresponding PSBT Input for a LocalUtxo
+    pub fn get_psbt_input(
+        &self,
+        utxo: LocalUtxo,
+        sighash_type: Option<SigHashType>,
+        only_witness_utxo: bool,
+    ) -> Result<Input, Error> {
+        // 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) = self
+            .database
+            .borrow()
+            .get_path_from_script_pubkey(&utxo.txout.script_pubkey)?
+            .ok_or(Error::UnknownUtxo)?;
+
+        let mut psbt_input = Input {
+            sighash_type,
+            ..Input::default()
+        };
+
+        let desc = self.get_descriptor_for_keychain(keychain);
+        let derived_descriptor = desc.as_derived(child, &self.secp);
+        psbt_input.bip32_derivation = derived_descriptor.get_hd_keypaths(&self.secp)?;
+
+        psbt_input.redeem_script = derived_descriptor.psbt_redeem_script();
+        psbt_input.witness_script = derived_descriptor.psbt_witness_script();
+
+        let prev_output = utxo.outpoint;
+        if let Some(prev_tx) = self.database.borrow().get_raw_tx(&prev_output.txid)? {
+            if desc.is_witness() {
+                psbt_input.witness_utxo = Some(prev_tx.output[prev_output.vout as usize].clone());
+            }
+            if !desc.is_witness() || !only_witness_utxo {
+                psbt_input.non_witness_utxo = Some(prev_tx);
+            }
+        }
+        Ok(psbt_input)
+    }
+
+    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
+                        .as_derived(child, &self.secp)
+                        .get_hd_keypaths(&self.secp)?;
+                    psbt_input.bip32_derivation.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: IntoWalletDescriptor>(
+        descriptor: E,
+        change_descriptor: Option<E>,
+        network: Network,
+        database: D,
+        client: B,
+    ) -> Result<Self, Error> {
+        let current_height = Some(maybe_await!(client.get_height())? as u32);
+        Self::_new(
+            descriptor,
+            change_descriptor,
+            network,
+            database,
+            client,
+            current_height,
+        )
+    }
+
+    /// 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_deriveable() {
+            false => 0,
+            true => max_address_param.unwrap_or(CACHE_ADDR_BATCH_SIZE),
+        };
+        debug!("max_address {}", max_address);
+        if self
+            .database
+            .borrow()
+            .get_script_pubkey_from_path(KeychainKind::External, max_address.saturating_sub(1))?
+            .is_none()
+        {
+            debug!("caching external addresses");
+            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_deriveable() {
+                false => 0,
+                true => 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()
+            {
+                debug!("caching internal addresses");
+                run_setup = true;
+                self.cache_addresses(KeychainKind::Internal, 0, max_address)?;
+            }
+        }
+
+        debug!("run_setup: {}", run_setup);
+        // 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
+                .setup(self.database.borrow_mut().deref_mut(), progress_update,))?;
+        } else {
+            maybe_await!(self
+                .client
+                .sync(self.database.borrow_mut().deref_mut(), progress_update,))?;
+        }
+
+        #[cfg(feature = "verify")]
+        {
+            debug!("Verifying transactions...");
+            for mut tx in self.database.borrow().iter_txs(true)? {
+                if !tx.verified {
+                    verify::verify_tx(
+                        tx.transaction.as_ref().ok_or(Error::TransactionNotFound)?,
+                        self.database.borrow().deref(),
+                        &self.client,
+                    )?;
+
+                    tx.verified = true;
+                    self.database.borrow_mut().set_tx(&tx)?;
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Return a reference to the internal blockchain client
+    pub fn client(&self) -> &B {
+        &self.client
+    }
+
+    /// Broadcast a transaction to the network
+    #[maybe_async]
+    pub fn broadcast(&self, tx: Transaction) -> Result<Txid, Error> {
+        maybe_await!(self.client.broadcast(&tx))?;
+
+        Ok(tx.txid())
+    }
+}
+
+/// Return a fake wallet that appears to be funded for testing.
+pub fn get_funded_wallet(
+    descriptor: &str,
+) -> (
+    Wallet<(), MemoryDatabase>,
+    (String, Option<String>),
+    bitcoin::Txid,
+) {
+    let descriptors = testutils!(@descriptors (descriptor));
+    let wallet = Wallet::new_offline(
+        &descriptors.0,
+        None,
+        Network::Regtest,
+        MemoryDatabase::new(),
+    )
+    .unwrap();
+
+    let funding_address_kix = 0;
+
+    let tx_meta = testutils! {
+            @tx ( (@external descriptors, funding_address_kix) => 50_000 ) (@confirmations 1)
+    };
+
+    wallet
+        .database
+        .borrow_mut()
+        .set_script_pubkey(
+            &bitcoin::Address::from_str(&tx_meta.output.get(0).unwrap().to_address)
+                .unwrap()
+                .script_pubkey(),
+            KeychainKind::External,
+            funding_address_kix,
+        )
+        .unwrap();
+    wallet
+        .database
+        .borrow_mut()
+        .set_last_index(KeychainKind::External, funding_address_kix)
+        .unwrap();
+
+    let txid = crate::populate_test_db!(wallet.database.borrow_mut(), tx_meta, Some(100));
+
+    (wallet, descriptors, txid)
+}
+
+#[cfg(test)]
+pub(crate) mod test {
+    use bitcoin::{util::psbt, Network};
+
+    use crate::database::Database;
+    use crate::types::KeychainKind;
+
+    use super::*;
+    use crate::signer::{SignOptions, SignerError};
+    use crate::wallet::AddressIndex::{LastUnused, New, Peek, Reset};
+
+    #[test]
+    fn test_cache_addresses_fixed() {
+        let db = MemoryDatabase::new();
+        let wallet = Wallet::new_offline(
+            "wpkh(L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6)",
+            None,
+            Network::Testnet,
+            db,
+        )
+        .unwrap();
+
+        assert_eq!(
+            wallet.get_address(New).unwrap().to_string(),
+            "tb1qj08ys4ct2hzzc2hcz6h2hgrvlmsjynaw43s835"
+        );
+        assert_eq!(
+            wallet.get_address(New).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 = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
+
+        assert_eq!(
+            wallet.get_address(New).unwrap().to_string(),
+            "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
+        );
+        assert_eq!(
+            wallet.get_address(New).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 = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)", None, Network::Testnet, db).unwrap();
+
+        assert_eq!(
+            wallet.get_address(New).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_address(New).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)))"
+    }
+
+    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 = FeeRate::from_wu($fees, tx.get_weight());
+            let fee_rate = $fee_rate;
+
+            if !dust_change {
+                assert!((tx_fee_rate - fee_rate).as_sat_vb().abs() < 0.5, "Expected fee rate of {:?}, the tx has {:?}", fee_rate, tx_fee_rate);
+            } else {
+                assert!(tx_fee_rate >= fee_rate, "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.build_tx().finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .manually_selected_only();
+        builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .version(0);
+        builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .version(1);
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_custom_version() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .version(42);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 25_000);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 25_000);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .nlocktime(630_000);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .nlocktime(630_000);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .nlocktime(50000);
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_no_rbf_csv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 25_000);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .enable_rbf();
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .enable_rbf_with_sequence(3);
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_no_rbf_cltv() {
+        let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 25_000);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .enable_rbf_with_sequence(0xFFFFFFFE);
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_custom_rbf_sequence() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .enable_rbf_with_sequence(0xDEADBEEF);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 25_000);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .do_not_spend_change();
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_drain_wallet_and_drain_to() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
+        assert_eq!(
+            psbt.global.unsigned_tx.output[0].value,
+            50_000 - details.fee.unwrap_or(0)
+        );
+    }
+
+    #[test]
+    fn test_create_tx_drain_wallet_and_drain_to_and_with_recipient() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+        let drain_addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 20_000)
+            .drain_to(drain_addr.script_pubkey())
+            .drain_wallet();
+        let (psbt, details) = builder.finish().unwrap();
+        dbg!(&psbt);
+        let outputs = psbt.global.unsigned_tx.output;
+
+        assert_eq!(outputs.len(), 2);
+        let main_output = outputs
+            .iter()
+            .find(|x| x.script_pubkey == addr.script_pubkey())
+            .unwrap();
+        let drain_output = outputs
+            .iter()
+            .find(|x| x.script_pubkey == drain_addr.script_pubkey())
+            .unwrap();
+        assert_eq!(main_output.value, 20_000,);
+        assert_eq!(drain_output.value, 30_000 - details.fee.unwrap_or(0));
+    }
+
+    #[test]
+    fn test_create_tx_default_fee_rate() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 25_000);
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), FeeRate::default(), @add_signature);
+    }
+
+    #[test]
+    fn test_create_tx_custom_fee_rate() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .fee_rate(FeeRate::from_sat_per_vb(5.0));
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), 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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .drain_wallet()
+            .fee_absolute(100);
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.fee.unwrap_or(0), 100);
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
+        assert_eq!(
+            psbt.global.unsigned_tx.output[0].value,
+            50_000 - details.fee.unwrap_or(0)
+        );
+    }
+
+    #[test]
+    fn test_create_tx_absolute_zero_fee() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .drain_wallet()
+            .fee_absolute(0);
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.fee.unwrap_or(0), 0);
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
+        assert_eq!(
+            psbt.global.unsigned_tx.output[0].value,
+            50_000 - details.fee.unwrap_or(0)
+        );
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_create_tx_absolute_high_fee() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .drain_wallet()
+            .fee_absolute(60_000);
+        let (_psbt, _details) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .ordering(TxOrdering::Untouched);
+        let (psbt, details) = builder.finish().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.fee.unwrap_or(0)
+        );
+    }
+
+    #[test]
+    fn test_create_tx_skip_change_dust() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 49_800);
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 1);
+        assert_eq!(psbt.global.unsigned_tx.output[0].value, 49_800);
+        assert_eq!(details.fee.unwrap_or(0), 200);
+    }
+
+    #[test]
+    #[should_panic(expected = "InsufficientFunds")]
+    fn test_create_tx_drain_to_dust_amount() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        // very high fee rate, so that the only output would be below dust
+        let mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .drain_wallet()
+            .fee_rate(FeeRate::from_sat_per_vb(453.0));
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    fn test_create_tx_ordering_respected() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 30_000)
+            .add_recipient(addr.script_pubkey(), 10_000)
+            .ordering(super::tx_builder::TxOrdering::Bip69Lexicographic);
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(psbt.global.unsigned_tx.output.len(), 3);
+        assert_eq!(
+            psbt.global.unsigned_tx.output[0].value,
+            10_000 - details.fee.unwrap_or(0)
+        );
+        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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 30_000);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 30_000)
+            .sighash(bitcoin::SigHashType::Single);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (psbt, _) = builder.finish().unwrap();
+
+        assert_eq!(psbt.inputs[0].bip32_derivation.len(), 1);
+        assert_eq!(
+            psbt.inputs[0].bip32_derivation.values().next().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_address(New).unwrap();
+
+        let addr = testutils!(@external descriptors, 5);
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (psbt, _) = builder.finish().unwrap();
+
+        assert_eq!(psbt.outputs[0].bip32_derivation.len(), 1);
+        assert_eq!(
+            psbt.outputs[0].bip32_derivation.values().next().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .only_witness_utxo()
+            .drain_wallet();
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (psbt, _) = builder.finish().unwrap();
+
+        assert!(psbt.inputs[0].witness_utxo.is_some());
+    }
+
+    #[test]
+    fn test_create_tx_both_non_witness_utxo_and_witness_utxo_default() {
+        let (wallet, _, _) =
+            get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))");
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (psbt, _) = builder.finish().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 = crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 30_000)
+            .add_utxo(OutPoint {
+                txid: small_output_txid,
+                vout: 0,
+            })
+            .unwrap();
+        let (psbt, details) = builder.finish().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 = crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 30_000)
+            .add_utxo(OutPoint {
+                txid: small_output_txid,
+                vout: 0,
+            })
+            .unwrap()
+            .manually_selected_only();
+        builder.finish().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();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 30_000);
+        builder.finish().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 mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 30_000)
+            .policy_path(path, KeychainKind::External);
+        let (psbt, _) = builder.finish().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 mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 30_000)
+            .policy_path(path, KeychainKind::External);
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .add_global_xpubs();
+        let (psbt, _) = builder.finish().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]
+    fn test_add_foreign_utxo() {
+        let (wallet1, _, _) = get_funded_wallet(get_test_wpkh());
+        let (wallet2, _, _) =
+            get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)");
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let utxo = wallet2.list_unspent().unwrap().remove(0);
+        let foreign_utxo_satisfaction = wallet2
+            .get_descriptor_for_keychain(KeychainKind::External)
+            .max_satisfaction_weight()
+            .unwrap();
+
+        let psbt_input = psbt::Input {
+            witness_utxo: Some(utxo.txout.clone()),
+            ..Default::default()
+        };
+
+        let mut builder = wallet1.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 60_000)
+            .only_witness_utxo()
+            .add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
+            .unwrap();
+        let (mut psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(
+            details.sent - details.received,
+            10_000 + details.fee.unwrap_or(0),
+            "we should have only net spent ~10_000"
+        );
+
+        assert!(
+            psbt.global
+                .unsigned_tx
+                .input
+                .iter()
+                .any(|input| input.previous_output == utxo.outpoint),
+            "foreign_utxo should be in there"
+        );
+
+        let finished = wallet1
+            .sign(
+                &mut psbt,
+                SignOptions {
+                    trust_witness_utxo: true,
+                    ..Default::default()
+                },
+            )
+            .unwrap();
+
+        assert!(
+            !finished,
+            "only one of the inputs should have been signed so far"
+        );
+
+        let finished = wallet2
+            .sign(
+                &mut psbt,
+                SignOptions {
+                    trust_witness_utxo: true,
+                    ..Default::default()
+                },
+            )
+            .unwrap();
+        assert!(finished, "all the inputs should have been signed now");
+    }
+
+    #[test]
+    #[should_panic(expected = "Generic(\"Foreign utxo missing witness_utxo or non_witness_utxo\")")]
+    fn test_add_foreign_utxo_invalid_psbt_input() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let mut builder = wallet.build_tx();
+        let outpoint = wallet.list_unspent().unwrap()[0].outpoint;
+        let foreign_utxo_satisfaction = wallet
+            .get_descriptor_for_keychain(KeychainKind::External)
+            .max_satisfaction_weight()
+            .unwrap();
+        builder
+            .add_foreign_utxo(outpoint, psbt::Input::default(), foreign_utxo_satisfaction)
+            .unwrap();
+    }
+
+    #[test]
+    fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() {
+        let (wallet1, _, txid1) = get_funded_wallet(get_test_wpkh());
+        let (wallet2, _, txid2) =
+            get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)");
+
+        let utxo2 = wallet2.list_unspent().unwrap().remove(0);
+        let tx1 = wallet1
+            .database
+            .borrow()
+            .get_tx(&txid1, true)
+            .unwrap()
+            .unwrap()
+            .transaction
+            .unwrap();
+        let tx2 = wallet2
+            .database
+            .borrow()
+            .get_tx(&txid2, true)
+            .unwrap()
+            .unwrap()
+            .transaction
+            .unwrap();
+
+        let satisfaction_weight = wallet2
+            .get_descriptor_for_keychain(KeychainKind::External)
+            .max_satisfaction_weight()
+            .unwrap();
+
+        let mut builder = wallet1.build_tx();
+        assert!(
+            builder
+                .add_foreign_utxo(
+                    utxo2.outpoint,
+                    psbt::Input {
+                        non_witness_utxo: Some(tx1),
+                        ..Default::default()
+                    },
+                    satisfaction_weight
+                )
+                .is_err(),
+            "should fail when outpoint doesn't match psbt_input"
+        );
+        assert!(
+            builder
+                .add_foreign_utxo(
+                    utxo2.outpoint,
+                    psbt::Input {
+                        non_witness_utxo: Some(tx2),
+                        ..Default::default()
+                    },
+                    satisfaction_weight
+                )
+                .is_ok(),
+            "shoulld be ok when outpoint does match psbt_input"
+        );
+    }
+
+    #[test]
+    fn test_add_foreign_utxo_only_witness_utxo() {
+        let (wallet1, _, _) = get_funded_wallet(get_test_wpkh());
+        let (wallet2, _, txid2) =
+            get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)");
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let utxo2 = wallet2.list_unspent().unwrap().remove(0);
+
+        let satisfaction_weight = wallet2
+            .get_descriptor_for_keychain(KeychainKind::External)
+            .max_satisfaction_weight()
+            .unwrap();
+
+        let mut builder = wallet1.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 60_000);
+
+        {
+            let mut builder = builder.clone();
+            let psbt_input = psbt::Input {
+                witness_utxo: Some(utxo2.txout.clone()),
+                ..Default::default()
+            };
+            builder
+                .add_foreign_utxo(utxo2.outpoint, psbt_input, satisfaction_weight)
+                .unwrap();
+            assert!(
+                builder.finish().is_err(),
+                "psbt_input with witness_utxo should fail with only witness_utxo"
+            );
+        }
+
+        {
+            let mut builder = builder.clone();
+            let psbt_input = psbt::Input {
+                witness_utxo: Some(utxo2.txout.clone()),
+                ..Default::default()
+            };
+            builder
+                .only_witness_utxo()
+                .add_foreign_utxo(utxo2.outpoint, psbt_input, satisfaction_weight)
+                .unwrap();
+            assert!(
+                builder.finish().is_ok(),
+                "psbt_input with just witness_utxo should succeed when `only_witness_utxo` is enabled"
+            );
+        }
+
+        {
+            let mut builder = builder.clone();
+            let tx2 = wallet2
+                .database
+                .borrow()
+                .get_tx(&txid2, true)
+                .unwrap()
+                .unwrap()
+                .transaction
+                .unwrap();
+            let psbt_input = psbt::Input {
+                non_witness_utxo: Some(tx2),
+                ..Default::default()
+            };
+            builder
+                .add_foreign_utxo(utxo2.outpoint, psbt_input, satisfaction_weight)
+                .unwrap();
+            assert!(
+                builder.finish().is_ok(),
+                "psbt_input with non_witness_utxo should succeed by default"
+            );
+        }
+    }
+
+    #[test]
+    fn test_get_psbt_input() {
+        // this should grab a known good utxo and set the input
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        for utxo in wallet.list_unspent().unwrap() {
+            let psbt_input = wallet.get_psbt_input(utxo, None, false).unwrap();
+            assert!(psbt_input.witness_utxo.is_some() || psbt_input.non_witness_utxo.is_some());
+        }
+    }
+
+    #[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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .add_global_xpubs();
+        builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .add_global_xpubs();
+        let (psbt, _) = builder.finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 25_000);
+        let (psbt, mut details) = builder.finish().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.build_fee_bump(txid).unwrap().finish().unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "TransactionConfirmed")]
+    fn test_bump_fee_confirmed_tx() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.add_recipient(addr.script_pubkey(), 25_000);
+        let (psbt, mut details) = builder.finish().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.confirmation_time = Some(ConfirmationTime {
+            timestamp: 12345678,
+            height: 42,
+        });
+        wallet.database.borrow_mut().set_tx(&details).unwrap();
+
+        wallet.build_fee_bump(txid).unwrap().finish().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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .enable_rbf();
+        let (psbt, mut details) = builder.finish().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();
+
+        let mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder.fee_rate(FeeRate::from_sat_per_vb(1.0));
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "FeeTooLow")]
+    fn test_bump_fee_low_abs() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .enable_rbf();
+        let (psbt, mut details) = builder.finish().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();
+
+        let mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder.fee_absolute(10);
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    #[should_panic(expected = "FeeTooLow")]
+    fn test_bump_fee_zero_abs() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .enable_rbf();
+        let (psbt, mut details) = builder.finish().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();
+
+        let mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder.fee_absolute(0);
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    fn test_bump_fee_reduce_change() {
+        let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder.fee_rate(FeeRate::from_sat_per_vb(2.5)).enable_rbf();
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.sent, original_details.sent);
+        assert_eq!(
+            details.received + details.fee.unwrap_or(0),
+            original_details.received + original_details.fee.unwrap_or(0)
+        );
+        assert!(details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0));
+
+        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.fee.unwrap_or(0), 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 mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 25_000)
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder.fee_absolute(200);
+        builder.enable_rbf();
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.sent, original_details.sent);
+        assert_eq!(
+            details.received + details.fee.unwrap_or(0),
+            original_details.received + original_details.fee.unwrap_or(0)
+        );
+        assert!(
+            details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0),
+            "{} > {}",
+            details.fee.unwrap_or(0),
+            original_details.fee.unwrap_or(0)
+        );
+
+        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.fee.unwrap_or(0), 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 mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .drain_wallet()
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder
+            .fee_rate(FeeRate::from_sat_per_vb(2.5))
+            .allow_shrinking(addr.script_pubkey())
+            .unwrap();
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.sent, original_details.sent);
+        assert!(details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0));
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.output.len(), 1);
+        assert_eq!(tx.output[0].value + details.fee.unwrap_or(0), details.sent);
+
+        assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), 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 mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .drain_wallet()
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder
+            .allow_shrinking(addr.script_pubkey())
+            .unwrap()
+            .fee_absolute(300);
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.sent, original_details.sent);
+        assert!(details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0));
+
+        let tx = &psbt.global.unsigned_tx;
+        assert_eq!(tx.output.len(), 1);
+        assert_eq!(tx.output[0].value + details.fee.unwrap_or(0), details.sent);
+
+        assert_eq!(details.fee.unwrap_or(0), 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 = crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            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 mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .add_utxo(outpoint)
+            .unwrap()
+            .manually_selected_only()
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder
+            .drain_wallet()
+            .allow_shrinking(addr.script_pubkey())
+            .unwrap()
+            .fee_rate(FeeRate::from_sat_per_vb(5.0));
+        let (_, details) = builder.finish().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. This fails because we've
+        // told the wallet it's not allowed to add more inputs AND it can't reduce the value of the
+        // existing output. In other words, bump_fee + manually_selected_only is always an error
+        // unless you've also set "allow_shrinking" OR there is a change output.
+        let incoming_txid = crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            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 mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .add_utxo(outpoint)
+            .unwrap()
+            .manually_selected_only()
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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);
+
+        let mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder
+            .manually_selected_only()
+            .fee_rate(FeeRate::from_sat_per_vb(255.0));
+        builder.finish().unwrap();
+    }
+
+    #[test]
+    fn test_bump_fee_add_input() {
+        let (wallet, descriptors, _) = get_funded_wallet(get_test_wpkh());
+        crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 45_000)
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder.fee_rate(FeeRate::from_sat_per_vb(50.0));
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fee.unwrap_or(0) + 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.fee.unwrap_or(0), 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());
+        crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 45_000)
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder.fee_absolute(6_000);
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fee.unwrap_or(0) + 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.fee.unwrap_or(0), 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 = crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        // initially make a tx without change by using `drain_to`
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .add_utxo(OutPoint {
+                txid: incoming_txid,
+                vout: 0,
+            })
+            .unwrap()
+            .manually_selected_only()
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 `allow_shrinking`. the wallet should add an
+        // extra input and a change output, and leave the original output untouched
+        let mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder.fee_rate(FeeRate::from_sat_per_vb(50.0));
+        let (psbt, details) = builder.finish().unwrap();
+
+        let original_send_all_amount = original_details.sent - original_details.fee.unwrap_or(0);
+        assert_eq!(details.sent, original_details.sent + 50_000);
+        assert_eq!(
+            details.received,
+            75_000 - original_send_all_amount - details.fee.unwrap_or(0)
+        );
+
+        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.fee.unwrap_or(0)
+        );
+
+        assert_fee_rate!(psbt.extract_tx(), details.fee.unwrap_or(0), 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());
+        crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 45_000)
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder.fee_rate(FeeRate::from_sat_per_vb(140.0));
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(
+            original_details.received,
+            5_000 - original_details.fee.unwrap_or(0)
+        );
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fee.unwrap_or(0), 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.fee.unwrap_or(0), 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 = crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 45_000)
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder
+            .add_utxo(OutPoint {
+                txid: incoming_txid,
+                vout: 0,
+            })
+            .unwrap()
+            .fee_rate(FeeRate::from_sat_per_vb(5.0));
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fee.unwrap_or(0) + 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.fee.unwrap_or(0), 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 = crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 45_000)
+            .enable_rbf();
+        let (psbt, mut original_details) = builder.finish().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 mut builder = wallet.build_fee_bump(txid).unwrap();
+        builder
+            .add_utxo(OutPoint {
+                txid: incoming_txid,
+                vout: 0,
+            })
+            .unwrap()
+            .fee_absolute(250);
+        let (psbt, details) = builder.finish().unwrap();
+
+        assert_eq!(details.sent, original_details.sent + 25_000);
+        assert_eq!(details.fee.unwrap_or(0) + 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.fee.unwrap_or(0), 250);
+    }
+
+    #[test]
+    fn test_sign_single_xprv() {
+        let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)");
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (mut psbt, _) = builder.finish().unwrap();
+
+        let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+        assert!(finalized);
+
+        let extracted = psbt.extract_tx();
+        assert_eq!(extracted.input[0].witness.len(), 2);
+    }
+
+    #[test]
+    fn test_sign_single_xprv_with_master_fingerprint_and_path() {
+        let (wallet, _, _) = get_funded_wallet("wpkh([d34db33f/84h/1h/0h]tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)");
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (mut psbt, _) = builder.finish().unwrap();
+
+        let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+        assert!(finalized);
+
+        let extracted = 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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (mut psbt, _) = builder.finish().unwrap();
+
+        let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+        assert!(finalized);
+
+        let extracted = 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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (mut psbt, _) = builder.finish().unwrap();
+
+        let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+        assert!(finalized);
+
+        let extracted = 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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (mut psbt, _) = builder.finish().unwrap();
+
+        let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+        assert!(finalized);
+
+        let extracted = 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_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder.drain_to(addr.script_pubkey()).drain_wallet();
+        let (mut psbt, _) = builder.finish().unwrap();
+
+        psbt.inputs[0].bip32_derivation.clear();
+        assert_eq!(psbt.inputs[0].bip32_derivation.len(), 0);
+
+        let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+        assert!(finalized);
+
+        let extracted = 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 mut builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 45_000)
+            .include_output_redeem_witness_script();
+        let (psbt, _) = builder.finish().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 builder = wallet.build_tx();
+        builder
+            .add_recipient(addr.script_pubkey(), 45_000)
+            .include_output_redeem_witness_script();
+        let (mut psbt, _) = builder.finish().unwrap();
+
+        // add another input to the psbt that is at least passable.
+        let dud_input = bitcoin::util::psbt::Input {
+            witness_utxo: Some(TxOut {
+                value: 100_000,
+                script_pubkey: miniscript::Descriptor::<bitcoin::PublicKey>::from_str(
+                    "wpkh(025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357)",
+                )
+                .unwrap()
+                .script_pubkey(),
+            }),
+            ..Default::default()
+        };
+
+        psbt.inputs.push(dud_input);
+        psbt.global.unsigned_tx.input.push(bitcoin::TxIn::default());
+        let is_final = wallet
+            .sign(
+                &mut psbt,
+                SignOptions {
+                    trust_witness_utxo: true,
+                    ..Default::default()
+                },
+            )
+            .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"
+        )
+    }
+
+    #[test]
+    fn test_sign_nonstandard_sighash() {
+        let sighash = SigHashType::NonePlusAnyoneCanPay;
+
+        let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)");
+        let addr = wallet.get_address(New).unwrap();
+        let mut builder = wallet.build_tx();
+        builder
+            .drain_to(addr.script_pubkey())
+            .sighash(sighash)
+            .drain_wallet();
+        let (mut psbt, _) = builder.finish().unwrap();
+
+        let result = wallet.sign(&mut psbt, Default::default());
+        assert!(
+            result.is_err(),
+            "Signing should have failed because the TX uses non-standard sighashes"
+        );
+        assert!(
+            matches!(
+                result.unwrap_err(),
+                Error::Signer(SignerError::NonStandardSighash)
+            ),
+            "Signing failed with the wrong error type"
+        );
+
+        // try again after opting-in
+        let result = wallet.sign(
+            &mut psbt,
+            SignOptions {
+                allow_all_sighashes: true,
+                ..Default::default()
+            },
+        );
+        assert!(result.is_ok(), "Signing should have worked");
+        assert!(
+            result.unwrap(),
+            "Should finalize the input since we can produce signatures"
+        );
+
+        let extracted = psbt.extract_tx();
+        assert_eq!(
+            *extracted.input[0].witness[0].last().unwrap(),
+            sighash.as_u32() as u8,
+            "The signature should have been made with the right sighash"
+        );
+    }
+
+    #[test]
+    fn test_unused_address() {
+        let db = MemoryDatabase::new();
+        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
+                                         None, Network::Testnet, db).unwrap();
+
+        assert_eq!(
+            wallet.get_address(LastUnused).unwrap().to_string(),
+            "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
+        );
+        assert_eq!(
+            wallet.get_address(LastUnused).unwrap().to_string(),
+            "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
+        );
+    }
+
+    #[test]
+    fn test_next_unused_address() {
+        let descriptor = "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)";
+        let descriptors = testutils!(@descriptors (descriptor));
+        let wallet = Wallet::new_offline(
+            &descriptors.0,
+            None,
+            Network::Testnet,
+            MemoryDatabase::new(),
+        )
+        .unwrap();
+
+        assert_eq!(
+            wallet.get_address(LastUnused).unwrap().to_string(),
+            "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
+        );
+
+        // use the above address
+        crate::populate_test_db!(
+            wallet.database.borrow_mut(),
+            testutils! (@tx ( (@external descriptors, 0) => 25_000 ) (@confirmations 1)),
+            Some(100),
+        );
+
+        assert_eq!(
+            wallet.get_address(LastUnused).unwrap().to_string(),
+            "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
+        );
+    }
+
+    #[test]
+    fn test_peek_address_at_index() {
+        let db = MemoryDatabase::new();
+        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
+                                         None, Network::Testnet, db).unwrap();
+
+        assert_eq!(
+            wallet.get_address(Peek(1)).unwrap().to_string(),
+            "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
+        );
+
+        assert_eq!(
+            wallet.get_address(Peek(0)).unwrap().to_string(),
+            "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
+        );
+
+        assert_eq!(
+            wallet.get_address(Peek(2)).unwrap().to_string(),
+            "tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2"
+        );
+
+        // current new address is not affected
+        assert_eq!(
+            wallet.get_address(New).unwrap().to_string(),
+            "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
+        );
+
+        assert_eq!(
+            wallet.get_address(New).unwrap().to_string(),
+            "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
+        );
+    }
+
+    #[test]
+    fn test_peek_address_at_index_not_derivable() {
+        let db = MemoryDatabase::new();
+        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/1)",
+                                         None, Network::Testnet, db).unwrap();
+
+        assert_eq!(
+            wallet.get_address(Peek(1)).unwrap().to_string(),
+            "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
+        );
+
+        assert_eq!(
+            wallet.get_address(Peek(0)).unwrap().to_string(),
+            "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
+        );
+
+        assert_eq!(
+            wallet.get_address(Peek(2)).unwrap().to_string(),
+            "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
+        );
+    }
+
+    #[test]
+    fn test_reset_address_index() {
+        let db = MemoryDatabase::new();
+        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
+                                         None, Network::Testnet, db).unwrap();
+
+        // new index 0
+        assert_eq!(
+            wallet.get_address(New).unwrap().to_string(),
+            "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a"
+        );
+
+        // new index 1
+        assert_eq!(
+            wallet.get_address(New).unwrap().to_string(),
+            "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
+        );
+
+        // new index 2
+        assert_eq!(
+            wallet.get_address(New).unwrap().to_string(),
+            "tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2"
+        );
+
+        //  reset index 1 again
+        assert_eq!(
+            wallet.get_address(Reset(1)).unwrap().to_string(),
+            "tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7"
+        );
+
+        // new index 2 again
+        assert_eq!(
+            wallet.get_address(New).unwrap().to_string(),
+            "tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2"
+        );
+    }
+
+    #[test]
+    fn test_returns_index_and_address() {
+        let db = MemoryDatabase::new();
+        let wallet = Wallet::new_offline("wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)",
+                                         None, Network::Testnet, db).unwrap();
+
+        // new index 0
+        assert_eq!(
+            wallet.get_address(New).unwrap(),
+            AddressInfo {
+                index: 0,
+                address: Address::from_str("tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a").unwrap(),
+            }
+        );
+
+        // new index 1
+        assert_eq!(
+            wallet.get_address(New).unwrap(),
+            AddressInfo {
+                index: 1,
+                address: Address::from_str("tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7").unwrap()
+            }
+        );
+
+        // peek index 25
+        assert_eq!(
+            wallet.get_address(Peek(25)).unwrap(),
+            AddressInfo {
+                index: 25,
+                address: Address::from_str("tb1qsp7qu0knx3sl6536dzs0703u2w2ag6ppl9d0c2").unwrap()
+            }
+        );
+
+        // new index 2
+        assert_eq!(
+            wallet.get_address(New).unwrap(),
+            AddressInfo {
+                index: 2,
+                address: Address::from_str("tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2").unwrap()
+            }
+        );
+
+        //  reset index 1 again
+        assert_eq!(
+            wallet.get_address(Reset(1)).unwrap(),
+            AddressInfo {
+                index: 1,
+                address: Address::from_str("tb1q4er7kxx6sssz3q7qp7zsqsdx4erceahhax77d7").unwrap()
+            }
+        );
+
+        // new index 2 again
+        assert_eq!(
+            wallet.get_address(New).unwrap(),
+            AddressInfo {
+                index: 2,
+                address: Address::from_str("tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2").unwrap()
+            }
+        );
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/signer.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/signer.rs.html new file mode 100644 index 0000000000..77838e7d8e --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/signer.rs.html @@ -0,0 +1,1536 @@ +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
+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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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 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
+//! #     }
+//! #     fn get_id(&self) -> SignerId {
+//! #         SignerId::Dummy(0)
+//! #     }
+//! # }
+//! #[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 id(&self, _secp: &Secp256k1<All>) -> SignerId {
+//!         self.device.get_id()
+//!     }
+//!
+//!     fn sign_whole_tx(&self) -> bool {
+//!         false
+//!     }
+//! }
+//!
+//! let custom_signer = CustomSigner::connect();
+//!
+//! let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
+//! let mut wallet = Wallet::new_offline(descriptor, None, Network::Testnet, MemoryDatabase::default())?;
+//! wallet.add_signer(
+//!     KeychainKind::External,
+//!     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::{ChildNumber, DerivationPath, 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),
+    /// Dummy identifier
+    Dummy(u64),
+}
+
+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,
+    /// The psbt contains a non-`SIGHASH_ALL` sighash in one of its input and the user hasn't
+    /// explicitly allowed them
+    ///
+    /// To enable signing transactions with non-standard sighashes set
+    /// [`SignOptions::allow_all_sighashes`] to `true`.
+    NonStandardSighash,
+}
+
+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 [`SignerId`] for this signer
+    ///
+    /// The [`SignerId`] can be used to lookup a signer in the [`Wallet`](crate::Wallet)'s signers map or to
+    /// compare two signers.
+    fn id(&self, secp: &SecpCtx) -> SignerId;
+
+    /// 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);
+        }
+
+        if psbt.inputs[input_index].final_script_sig.is_some()
+            || psbt.inputs[input_index].final_script_witness.is_some()
+        {
+            return Ok(());
+        }
+
+        let (public_key, full_path) = match psbt.inputs[input_index]
+            .bip32_derivation
+            .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 = match self.origin.clone() {
+            Some((_fingerprint, origin_path)) => {
+                let deriv_path = DerivationPath::from(
+                    &full_path.into_iter().cloned().collect::<Vec<ChildNumber>>()
+                        [origin_path.len()..],
+                );
+                self.xkey.derive_priv(secp, &deriv_path).unwrap()
+            }
+            None => self.xkey.derive_priv(secp, &full_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 id(&self, secp: &SecpCtx) -> SignerId {
+        SignerId::from(self.root_fingerprint(secp))
+    }
+
+    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() || input_index >= psbt.global.unsigned_tx.input.len() {
+            return Err(SignerError::InputIndexOutOfRange);
+        }
+
+        if psbt.inputs[input_index].final_script_sig.is_some()
+            || psbt.inputs[input_index].final_script_witness.is_some()
+        {
+            return Ok(());
+        }
+
+        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 id(&self, secp: &SecpCtx) -> SignerId {
+        SignerId::from(self.public_key(secp).to_pubkeyhash())
+    }
+
+    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(&secp).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()
+    }
+}
+
+/// Options for a software signer
+///
+/// Adjust the behavior of our software signers and the way a transaction is finalized
+#[derive(Debug, Clone)]
+pub struct SignOptions {
+    /// Whether the signer should trust the `witness_utxo`, if the `non_witness_utxo` hasn't been
+    /// provided
+    ///
+    /// Defaults to `false` to mitigate the "SegWit bug" which chould trick the wallet into
+    /// paying a fee larger than expected.
+    ///
+    /// Some wallets, especially if relatively old, might not provide the `non_witness_utxo` for
+    /// SegWit transactions in the PSBT they generate: in those cases setting this to `true`
+    /// should correctly produce a signature, at the expense of an increased trust in the creator
+    /// of the PSBT.
+    ///
+    /// For more details see: <https://blog.trezor.io/details-of-firmware-updates-for-trezor-one-version-1-9-1-and-trezor-model-t-version-2-3-1-1eba8f60f2dd>
+    pub trust_witness_utxo: bool,
+
+    /// Whether the wallet should assume a specific height has been reached when trying to finalize
+    /// a transaction
+    ///
+    /// The wallet will only "use" a timelock to satisfy the spending policy of an input if the
+    /// timelock height has already been reached. This option allows overriding the "current height" to let the
+    /// wallet use timelocks in the future to spend a coin.
+    pub assume_height: Option<u32>,
+
+    /// Whether the signer should use the `sighash_type` set in the PSBT when signing, no matter
+    /// what its value is
+    ///
+    /// Defaults to `false` which will only allow signing using `SIGHASH_ALL`.
+    pub allow_all_sighashes: bool,
+}
+
+impl Default for SignOptions {
+    fn default() -> Self {
+        SignOptions {
+            trust_witness_utxo: false,
+            assume_height: None,
+            allow_all_sighashes: false,
+        }
+    }
+}
+
+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() || input_index >= psbt.global.unsigned_tx.input.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() || input_index >= psbt.global.unsigned_tx.input.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);
+
+        // Always try first with the non-witness utxo
+        let utxo = if let Some(prev_tx) = &psbt_input.non_witness_utxo {
+            // Check the provided prev-tx
+            if prev_tx.txid() != tx_input.previous_output.txid {
+                return Err(SignerError::InvalidNonWitnessUtxo);
+            }
+
+            // The output should be present, if it's missing the `non_witness_utxo` is invalid
+            prev_tx
+                .output
+                .get(tx_input.previous_output.vout as usize)
+                .ok_or(SignerError::InvalidNonWitnessUtxo)?
+        } else if let Some(witness_utxo) = &psbt_input.witness_utxo {
+            // Fallback to the witness_utxo. If we aren't allowed to use it, signing should fail
+            // before we get to this point
+            witness_utxo
+        } else {
+            // Nothing has been provided
+            return Err(SignerError::MissingNonWitnessUtxo);
+        };
+        let value = utxo.value;
+
+        let script = match psbt_input.witness_script {
+            Some(ref witness_script) => witness_script.clone(),
+            None => {
+                if utxo.script_pubkey.is_v0_p2wpkh() {
+                    p2wpkh_script_code(&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::IntoWalletDescriptor;
+    use crate::keys::{DescriptorKey, IntoDescriptorKey};
+    use bitcoin::secp256k1::{All, Secp256k1};
+    use bitcoin::util::bip32;
+    use bitcoin::util::psbt::PartiallySignedTransaction;
+    use bitcoin::Network;
+    use miniscript::ScriptContext;
+    use std::str::FromStr;
+
+    fn is_equal(this: &Arc<dyn Signer>, that: &Arc<DummySigner>) -> bool {
+        let secp = Secp256k1::new();
+        this.id(&secp) == that.id(&secp)
+    }
+
+    // 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 secp = Secp256k1::new();
+
+        let (prvkey1, _, _) = setup_keys(TPRV0_STR);
+        let (prvkey2, _, _) = setup_keys(TPRV1_STR);
+        let desc = descriptor!(sh(multi(2, prvkey1, prvkey2))).unwrap();
+        let (_, keymap) = desc
+            .into_wallet_descriptor(&secp, 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 { number: 1 });
+        let signer2 = Arc::new(DummySigner { number: 2 });
+        let signer3 = Arc::new(DummySigner { number: 3 });
+
+        // Mixed order insertions verifies we are not inserting at head or tail.
+        signers.add_external(SignerId::Dummy(2), SignerOrdering(2), signer2.clone());
+        signers.add_external(SignerId::Dummy(1), SignerOrdering(1), signer1.clone());
+        signers.add_external(SignerId::Dummy(3), SignerOrdering(3), signer3.clone());
+
+        // Check that signers are sorted from lowest to highest ordering
+        let signers = signers.signers();
+
+        assert!(is_equal(signers[0], &signer1));
+        assert!(is_equal(signers[1], &signer2));
+        assert!(is_equal(signers[2], &signer3));
+    }
+
+    #[test]
+    fn find_signer_by_id() {
+        let mut signers = SignersContainer::new();
+        let signer1 = Arc::new(DummySigner { number: 1 });
+        let signer2 = Arc::new(DummySigner { number: 2 });
+        let signer3 = Arc::new(DummySigner { number: 3 });
+        let signer4 = Arc::new(DummySigner { number: 3 }); // Same ID as `signer3` but will use lower ordering.
+
+        let id1 = SignerId::Dummy(1);
+        let id2 = SignerId::Dummy(2);
+        let id3 = SignerId::Dummy(3);
+        let id_nonexistent = SignerId::Dummy(999);
+
+        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 is_equal(signer, &signer1)));
+        assert!(matches!(signers.find(id2), Some(signer) if is_equal(signer, &signer2)));
+        assert!(matches!(signers.find(id3.clone()), Some(signer) if is_equal(signer, &signer3)));
+
+        // 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 is_equal(signer, &signer4)));
+
+        // Can't find anything with ID that doesn't exist
+        assert!(matches!(signers.find(id_nonexistent), None));
+    }
+
+    #[derive(Debug, Clone, Copy)]
+    struct DummySigner {
+        number: u64,
+    }
+
+    impl Signer for DummySigner {
+        fn sign(
+            &self,
+            _psbt: &mut PartiallySignedTransaction,
+            _input_index: Option<usize>,
+            _secp: &SecpCtx,
+        ) -> Result<(), SignerError> {
+            Ok(())
+        }
+
+        fn id(&self, _secp: &SecpCtx) -> SignerId {
+            SignerId::Dummy(self.number)
+        }
+
+        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()).into_descriptor_key().unwrap();
+        let pubkey = (tpub, path).into_descriptor_key().unwrap();
+
+        (prvkey, pubkey, fingerprint)
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/time.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/time.rs.html new file mode 100644 index 0000000000..48832d0f43 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/time.rs.html @@ -0,0 +1,150 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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/latest/src/bdk/wallet/tx_builder.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/tx_builder.rs.html new file mode 100644 index 0000000000..732238dba1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/tx_builder.rs.html @@ -0,0 +1,1776 @@ +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
+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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+//! 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();
+//! # let wallet = doctest_wallet!();
+//! // create a TxBuilder from a wallet
+//! let mut tx_builder = wallet.build_tx();
+//!
+//! tx_builder
+//!     // Create a transaction with one output to `to_address` of 50_000 satoshi
+//!     .add_recipient(to_address.script_pubkey(), 50_000)
+//!     // With a custom fee rate of 5.0 satoshi/vbyte
+//!     .fee_rate(FeeRate::from_sat_per_vb(5.0))
+//!     // Only spend non-change outputs
+//!     .do_not_spend_change()
+//!     // Turn on RBF signaling
+//!     .enable_rbf();
+//! let (psbt, tx_details) = tx_builder.finish()?;
+//! # Ok::<(), bdk::Error>(())
+//! ```
+
+use std::collections::BTreeMap;
+use std::collections::HashSet;
+use std::default::Default;
+use std::marker::PhantomData;
+
+use bitcoin::util::psbt::{self, PartiallySignedTransaction as Psbt};
+use bitcoin::{OutPoint, Script, SigHashType, Transaction};
+
+use miniscript::descriptor::DescriptorTrait;
+
+use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm};
+use crate::{database::BatchDatabase, Error, Utxo, Wallet};
+use crate::{
+    types::{FeeRate, KeychainKind, LocalUtxo, WeightedUtxo},
+    TransactionDetails,
+};
+/// Context in which the [`TxBuilder`] is valid
+pub trait TxBuilderContext: std::fmt::Debug + Default + Clone {}
+
+/// Marker type to indicate the [`TxBuilder`] is being used to create a new transaction (as opposed
+/// to bumping the fee of an existing one).
+#[derive(Debug, Default, Clone)]
+pub struct CreateTx;
+impl TxBuilderContext for CreateTx {}
+
+/// Marker type to indicate the [`TxBuilder`] is being used to bump the fee of an existing transaction.
+#[derive(Debug, Default, Clone)]
+pub struct BumpFee;
+impl TxBuilderContext for BumpFee {}
+
+/// A transaction builder
+///
+/// A `TxBuilder` is created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. After
+/// assigning it, you set options on it until finally calling [`finish`] to consume the builder and
+/// generate the transaction.
+///
+/// Each option setting method on `TxBuilder` takes and returns `&mut self` so you can chain calls
+/// as in the following example:
+///
+/// ```
+/// # use bdk::*;
+/// # use bdk::wallet::tx_builder::*;
+/// # use bitcoin::*;
+/// # use core::str::FromStr;
+/// # let wallet = doctest_wallet!();
+/// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+/// # let addr2 = addr1.clone();
+/// // chaining
+/// let (psbt1, details) = {
+///     let mut builder = wallet.build_tx();
+///     builder
+///         .ordering(TxOrdering::Untouched)
+///         .add_recipient(addr1.script_pubkey(), 50_000)
+///         .add_recipient(addr2.script_pubkey(), 50_000);
+///     builder.finish()?
+/// };
+///
+/// // non-chaining
+/// let (psbt2, details) = {
+///     let mut builder = wallet.build_tx();
+///     builder.ordering(TxOrdering::Untouched);
+///     for addr in &[addr1, addr2] {
+///         builder.add_recipient(addr.script_pubkey(), 50_000);
+///     }
+///     builder.finish()?
+/// };
+///
+/// assert_eq!(
+///     psbt1.global.unsigned_tx.output[..2],
+///     psbt2.global.unsigned_tx.output[..2]
+/// );
+/// # Ok::<(), bdk::Error>(())
+/// ```
+///
+/// At the moment [`coin_selection`] is an exception to the rule as it consumes `self`.
+/// This means it is usually best to call [`coin_selection`] on the return value of `build_tx` before assigning it.
+///
+/// For further examples see [this module](super::tx_builder)'s documentation;
+///
+/// [`build_tx`]: Wallet::build_tx
+/// [`build_fee_bump`]: Wallet::build_fee_bump
+/// [`finish`]: Self::finish
+/// [`coin_selection`]: Self::coin_selection
+#[derive(Debug)]
+pub struct TxBuilder<'a, B, D, Cs, Ctx> {
+    pub(crate) wallet: &'a Wallet<B, D>,
+    pub(crate) params: TxParams,
+    pub(crate) coin_selection: Cs,
+    pub(crate) phantom: PhantomData<Ctx>,
+}
+
+/// The parameters for transaction creation sans coin selection algorithm.
+//TODO: TxParams should eventually be exposed publicly.
+#[derive(Default, Debug, Clone)]
+pub(crate) struct TxParams {
+    pub(crate) recipients: Vec<(Script, u64)>,
+    pub(crate) drain_wallet: bool,
+    pub(crate) drain_to: 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<WeightedUtxo>,
+    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) only_witness_utxo: bool,
+    pub(crate) add_global_xpubs: bool,
+    pub(crate) include_output_redeem_witness_script: bool,
+    pub(crate) bumping_fee: Option<PreviousFee>,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct PreviousFee {
+    pub absolute: u64,
+    pub rate: f32,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum FeePolicy {
+    FeeRate(FeeRate),
+    FeeAmount(u64),
+}
+
+impl std::default::Default for FeePolicy {
+    fn default() -> Self {
+        FeePolicy::FeeRate(FeeRate::default_min_relay_fee())
+    }
+}
+
+impl<'a, Cs: Clone, Ctx, B, D> Clone for TxBuilder<'a, B, D, Cs, Ctx> {
+    fn clone(&self) -> Self {
+        TxBuilder {
+            wallet: self.wallet,
+            params: self.params.clone(),
+            coin_selection: self.coin_selection.clone(),
+            phantom: PhantomData,
+        }
+    }
+}
+
+// methods supported by both contexts, for any CoinSelectionAlgorithm
+impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext>
+    TxBuilder<'a, B, D, Cs, Ctx>
+{
+    /// Set a custom fee rate
+    pub fn fee_rate(&mut self, fee_rate: FeeRate) -> &mut Self {
+        self.params.fee_policy = Some(FeePolicy::FeeRate(fee_rate));
+        self
+    }
+
+    /// Set an absolute fee
+    pub fn fee_absolute(&mut self, fee_amount: u64) -> &mut Self {
+        self.params.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 wallet = doctest_wallet!();
+    /// let mut path = BTreeMap::new();
+    /// path.insert("aabbccdd".to_string(), vec![0, 1]);
+    ///
+    /// let builder = wallet
+    ///     .build_tx()
+    ///     .add_recipient(to_address.script_pubkey(), 50_000)
+    ///     .policy_path(path, KeychainKind::External);
+    ///
+    /// # Ok::<(), bdk::Error>(())
+    /// ```
+    pub fn policy_path(
+        &mut self,
+        policy_path: BTreeMap<String, Vec<usize>>,
+        keychain: KeychainKind,
+    ) -> &mut Self {
+        let to_update = match keychain {
+            KeychainKind::Internal => &mut self.params.internal_policy_path,
+            KeychainKind::External => &mut self.params.external_policy_path,
+        };
+
+        *to_update = Some(policy_path);
+        self
+    }
+
+    /// Add the list of outpoints to the internal list of UTXOs that **must** be spent.
+    ///
+    /// If an error occurs while adding any of the UTXOs then none of them are added and the error is returned.
+    ///
+    /// 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_utxos(&mut self, outpoints: &[OutPoint]) -> Result<&mut Self, Error> {
+        let utxos = outpoints
+            .iter()
+            .map(|outpoint| self.wallet.get_utxo(*outpoint)?.ok_or(Error::UnknownUtxo))
+            .collect::<Result<Vec<_>, _>>()?;
+
+        for utxo in utxos {
+            let descriptor = self.wallet.get_descriptor_for_keychain(utxo.keychain);
+            let satisfaction_weight = descriptor.max_satisfaction_weight().unwrap();
+            self.params.utxos.push(WeightedUtxo {
+                satisfaction_weight,
+                utxo: Utxo::Local(utxo),
+            });
+        }
+
+        Ok(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, outpoint: OutPoint) -> Result<&mut Self, Error> {
+        self.add_utxos(&[outpoint])
+    }
+
+    /// Add a foreign UTXO i.e. a UTXO not owned by this wallet.
+    ///
+    /// At a minimum to add a foreign UTXO we need:
+    ///
+    /// 1. `outpoint`: To add it to the raw transaction.
+    /// 2. `psbt_input`: To know the value.
+    /// 3. `satisfaction_weight`: To know how much weight/vbytes the input will add to the transaction for fee calculation.
+    ///
+    /// There are several security concerns about adding foregin UTXOs that application
+    /// developers should consider. First, how do you know the value of the input is correct? If a
+    /// `non_witness_utxo` is provided in the `psbt_input` then this method implicitly verifies the
+    /// value by checking it against the transaction. If only a `witness_utxo` is provided then this
+    /// method doesn't verify the value but just takes it as a given -- it is up to you to check
+    /// that whoever sent you the `input_psbt` was not lying!
+    ///
+    /// Secondly, you must somehow provide `satisfaction_weight` of the input. Depending on your
+    /// application it may be important that this be known precisely. If not, a malicious
+    /// counterparty may fool you into putting in a value that is too low, giving the transaction a
+    /// lower than expected feerate. They could also fool you into putting a value that is too high
+    /// causing you to pay a fee that is too high. The party who is broadcasting the transaction can
+    /// of course check the real input weight matches the expected weight prior to broadcasting.
+    ///
+    /// To guarantee the `satisfaction_weight` is correct, you can require the party providing the
+    /// `psbt_input` provide a miniscript descriptor for the input so you can check it against the
+    /// `script_pubkey` and then ask it for the [`max_satisfaction_weight`].
+    ///
+    /// This is an **EXPERIMENTAL** feature, API and other major changes are expected.
+    ///
+    /// # Errors
+    ///
+    /// This method returns errors in the following circumstances:
+    ///
+    /// 1. The `psbt_input` does not contain a `witness_utxo` or `non_witness_utxo`.
+    /// 2. The data in `non_witness_utxo` does not match what is in `outpoint`.
+    ///
+    /// Note unless you set [`only_witness_utxo`] any `psbt_input` you pass to this method must
+    /// have `non_witness_utxo` set otherwise you will get an error when [`finish`] is called.
+    ///
+    /// [`only_witness_utxo`]: Self::only_witness_utxo
+    /// [`finish`]: Self::finish
+    /// [`max_satisfaction_weight`]: miniscript::Descriptor::max_satisfaction_weight
+    pub fn add_foreign_utxo(
+        &mut self,
+        outpoint: OutPoint,
+        psbt_input: psbt::Input,
+        satisfaction_weight: usize,
+    ) -> Result<&mut Self, Error> {
+        if psbt_input.witness_utxo.is_none() {
+            match psbt_input.non_witness_utxo.as_ref() {
+                Some(tx) => {
+                    if tx.txid() != outpoint.txid {
+                        return Err(Error::Generic(
+                            "Foreign utxo outpoint does not match PSBT input".into(),
+                        ));
+                    }
+                    if tx.output.len() <= outpoint.vout as usize {
+                        return Err(Error::InvalidOutpoint(outpoint));
+                    }
+                }
+                None => {
+                    return Err(Error::Generic(
+                        "Foreign utxo missing witness_utxo or non_witness_utxo".into(),
+                    ))
+                }
+            }
+        }
+
+        self.params.utxos.push(WeightedUtxo {
+            satisfaction_weight,
+            utxo: Utxo::Foreign {
+                outpoint,
+                psbt_input: Box::new(psbt_input),
+            },
+        });
+
+        Ok(self)
+    }
+
+    /// Only spend utxos added by [`add_utxo`].
+    ///
+    /// 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
+    pub fn manually_selected_only(&mut self) -> &mut Self {
+        self.params.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::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>) -> &mut Self {
+        self.params.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::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) -> &mut Self {
+        self.params.unspendable.insert(unspendable);
+        self
+    }
+
+    /// Sign with a specific sig hash
+    ///
+    /// **Use this option very carefully**
+    pub fn sighash(&mut self, sighash: SigHashType) -> &mut Self {
+        self.params.sighash = Some(sighash);
+        self
+    }
+
+    /// Choose the ordering for inputs and outputs of the transaction
+    pub fn ordering(&mut self, ordering: TxOrdering) -> &mut Self {
+        self.params.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) -> &mut Self {
+        self.params.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) -> &mut Self {
+        self.params.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) -> &mut Self {
+        self.params.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) -> &mut Self {
+        self.params.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) -> &mut Self {
+        self.params.change_policy = change_policy;
+        self
+    }
+
+    /// Only Fill-in the [`psbt::Input::witness_utxo`](bitcoin::util::psbt::Input::witness_utxo) field when spending from
+    /// SegWit descriptors.
+    ///
+    /// This reduces the size of the PSBT, but some signers might reject them due to the lack of
+    /// the `non_witness_utxo`.
+    pub fn only_witness_utxo(&mut self) -> &mut Self {
+        self.params.only_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) -> &mut Self {
+        self.params.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) -> &mut Self {
+        self.params.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) -> &mut Self {
+        self.params.drain_wallet = true;
+        self
+    }
+
+    /// Choose the coin selection algorithm
+    ///
+    /// Overrides the [`DefaultCoinSelectionAlgorithm`](super::coin_selection::DefaultCoinSelectionAlgorithm).
+    ///
+    /// Note that this function consumes the builder and returns it so it is usually best to put this as the first call on the builder.
+    pub fn coin_selection<P: CoinSelectionAlgorithm<D>>(
+        self,
+        coin_selection: P,
+    ) -> TxBuilder<'a, B, D, P, Ctx> {
+        TxBuilder {
+            wallet: self.wallet,
+            params: self.params,
+            coin_selection,
+            phantom: PhantomData,
+        }
+    }
+
+    /// Finish the building the transaction.
+    ///
+    /// Returns the [`BIP174`] "PSBT" and summary details about the transaction.
+    ///
+    /// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
+    pub fn finish(self) -> Result<(Psbt, TransactionDetails), Error> {
+        self.wallet.create_tx(self.coin_selection, self.params)
+    }
+
+    /// Enable signaling RBF
+    ///
+    /// This will use the default nSequence value of `0xFFFFFFFD`.
+    pub fn enable_rbf(&mut self) -> &mut Self {
+        self.params.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) -> &mut Self {
+        self.params.rbf = Some(RbfValue::Value(nsequence));
+        self
+    }
+}
+
+impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>> TxBuilder<'a, B, D, Cs, CreateTx> {
+    /// Replace the recipients already added with a new list
+    pub fn set_recipients(&mut self, recipients: Vec<(Script, u64)>) -> &mut Self {
+        self.params.recipients = recipients;
+        self
+    }
+
+    /// Add a recipient to the internal list
+    pub fn add_recipient(&mut self, script_pubkey: Script, amount: u64) -> &mut Self {
+        self.params.recipients.push((script_pubkey, amount));
+        self
+    }
+
+    /// Sets the address to *drain* excess coins to.
+    ///
+    /// Usually, when there are excess coins they are sent to a change address generated by the
+    /// wallet. This option replaces the usual change address with an arbitrary `script_pubkey` of
+    /// your choosing. Just as with a change output, if the drain output is not needed (the excess
+    /// coins are too small) it will not be included in the resulting transaction. The only
+    /// difference is that it is valid to use `drain_to` without setting any ordinary recipients
+    /// with [`add_recipient`] (but it is perfectly fine to add recipients as well).
+    ///
+    /// When bumping the fees of a transaction made with this option, you probably want to
+    /// use [`allow_shrinking`] to allow this output to be reduced to pay for the extra fees.
+    ///
+    /// # Example
+    ///
+    /// `drain_to` is very useful for draining all the coins in a wallet with [`drain_wallet`] to a
+    /// single address.
+    ///
+    /// ```
+    /// # use std::str::FromStr;
+    /// # use bitcoin::*;
+    /// # use bdk::*;
+    /// # use bdk::wallet::tx_builder::CreateTx;
+    /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
+    /// # let wallet = doctest_wallet!();
+    /// let mut tx_builder = wallet.build_tx();
+    ///
+    /// tx_builder
+    ///     // Spend all outputs in this wallet.
+    ///     .drain_wallet()
+    ///     // Send the excess (which is all the coins minus the fee) to this address.
+    ///     .drain_to(to_address.script_pubkey())
+    ///     .fee_rate(FeeRate::from_sat_per_vb(5.0))
+    ///     .enable_rbf();
+    /// let (psbt, tx_details) = tx_builder.finish()?;
+    /// # Ok::<(), bdk::Error>(())
+    /// ```
+    ///
+    /// [`allow_shrinking`]: Self::allow_shrinking
+    /// [`add_recipient`]: Self::add_recipient
+    /// [`drain_wallet`]: Self::drain_wallet
+    pub fn drain_to(&mut self, script_pubkey: Script) -> &mut Self {
+        self.params.drain_to = Some(script_pubkey);
+        self
+    }
+}
+
+// methods supported only by bump_fee
+impl<'a, B, D: BatchDatabase> TxBuilder<'a, B, D, DefaultCoinSelectionAlgorithm, BumpFee> {
+    /// Explicitly tells the wallet that it is allowed to reduce the fee of the output matching this
+    /// `script_pubkey` in order to bump the transaction fee. Without specifying this the wallet
+    /// will attempt to find a change output to shrink instead.
+    ///
+    /// **Note** that the output may shrink to below the dust limit and therefore be removed. If it is
+    /// preserved then it is currently not guaranteed to be in the same position as it was
+    /// originally.
+    ///
+    /// Returns an `Err` if `script_pubkey` can't be found among the recipients of the
+    /// transaction we are bumping.
+    pub fn allow_shrinking(&mut self, script_pubkey: Script) -> Result<&mut Self, Error> {
+        match self
+            .params
+            .recipients
+            .iter()
+            .position(|(recipient_script, _)| *recipient_script == script_pubkey)
+        {
+            Some(position) => {
+                self.params.recipients.remove(position);
+                self.params.drain_to = Some(script_pubkey);
+                Ok(self)
+            }
+            None => Err(Error::Generic(format!(
+                "{} was not in the original transaction",
+                script_pubkey
+            ))),
+        }
+    }
+}
+
+/// 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: &LocalUtxo) -> 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: &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;
+
+        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<LocalUtxo> {
+        vec![
+            LocalUtxo {
+                outpoint: OutPoint {
+                    txid: Default::default(),
+                    vout: 0,
+                },
+                txout: Default::default(),
+                keychain: KeychainKind::External,
+            },
+            LocalUtxo {
+                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))
+            .count();
+
+        assert_eq!(filtered, 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/latest/src/bdk/wallet/utils.rs.html b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/utils.rs.html new file mode 100644 index 0000000000..5154e583bb --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/src/bdk/wallet/utils.rs.html @@ -0,0 +1,536 @@ +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
+
// Bitcoin Dev Kit
+// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
+//
+// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
+use bitcoin::secp256k1::{All, Secp256k1};
+
+use miniscript::{MiniscriptKey, Satisfier, ToPublicKey};
+
+// De-facto standard "dust limit" (even though it should change based on the output type)
+pub 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<Pk: MiniscriptKey + ToPublicKey> Satisfier<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<Pk: MiniscriptKey + ToPublicKey> Satisfier<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 struct ChunksIterator<I: Iterator> {
+    iter: I,
+    size: usize,
+}
+
+#[cfg(any(feature = "electrum", feature = "esplora"))]
+impl<I: Iterator> ChunksIterator<I> {
+    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!(!result);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_lt_csv() {
+        let result = check_nsequence_rbf(4000, 5000);
+        assert!(!result);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_different_unit() {
+        let result = check_nsequence_rbf(SEQUENCE_LOCKTIME_TYPE_FLAG + 5000, 5000);
+        assert!(!result);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_mask() {
+        let result = check_nsequence_rbf(0x3f + 10_000, 5000);
+        assert!(result);
+    }
+
+    #[test]
+    fn test_check_nsequence_rbf_same_unit_blocks() {
+        let result = check_nsequence_rbf(10_000, 5000);
+        assert!(result);
+    }
+
+    #[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!(result);
+    }
+
+    #[test]
+    fn test_check_nlocktime_lt_cltv() {
+        let result = check_nlocktime(4000, 5000);
+        assert!(!result);
+    }
+
+    #[test]
+    fn test_check_nlocktime_different_unit() {
+        let result = check_nlocktime(BLOCKS_TIMELOCK_THRESHOLD + 5000, 5000);
+        assert!(!result);
+    }
+
+    #[test]
+    fn test_check_nlocktime_same_unit_blocks() {
+        let result = check_nlocktime(10_000, 5000);
+        assert!(result);
+    }
+
+    #[test]
+    fn test_check_nlocktime_same_unit_time() {
+        let result = check_nlocktime(
+            BLOCKS_TIMELOCK_THRESHOLD + 10_000,
+            BLOCKS_TIMELOCK_THRESHOLD + 5000,
+        );
+        assert!(result);
+    }
+}
+
+
+ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/storage.js b/static/docs-rs/bdk/nightly/latest/storage.js new file mode 100644 index 0000000000..6b16cbd83c --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/storage.js @@ -0,0 +1 @@ +var resourcesSuffix="";var darkThemes=["dark","ayu"];window.currentTheme=document.getElementById("themeStyle");window.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){for(i=length-1;i>=0;--i){if(func(arr[i])){return true}}}else{for(i=0;i=0){updateLocalStorage("rustdoc-preferred-dark-theme",localStoredTheme)}updateSystemTheme()}else{switchTheme(window.currentTheme,window.mainTheme,getSettingValue("theme")||"light",false)} \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/toggle-minus.svg b/static/docs-rs/bdk/nightly/latest/toggle-minus.svg new file mode 100644 index 0000000000..73154788a0 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/toggle-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/toggle-plus.svg b/static/docs-rs/bdk/nightly/latest/toggle-plus.svg new file mode 100644 index 0000000000..08b17033e1 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/toggle-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/docs-rs/bdk/nightly/latest/wheel.svg b/static/docs-rs/bdk/nightly/latest/wheel.svg new file mode 100644 index 0000000000..01da3b24c7 --- /dev/null +++ b/static/docs-rs/bdk/nightly/latest/wheel.svg @@ -0,0 +1 @@ + \ No newline at end of file