Compare commits
57 Commits
release/0.
...
release/0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1f844a5b6 | ||
|
|
a3e45358de | ||
|
|
07e79f6e8a | ||
|
|
d94b8f87a3 | ||
|
|
71e0472dc9 | ||
|
|
f7944e871b | ||
|
|
2fea1761c1 | ||
|
|
fa27ae210f | ||
|
|
46fa41470e | ||
|
|
8ebe7f0ea5 | ||
|
|
eb85390846 | ||
|
|
dc83db273a | ||
|
|
201bd6ee02 | ||
|
|
396ffb42f9 | ||
|
|
9cf62ce874 | ||
|
|
9c6b98d98b | ||
|
|
e33a6a12c1 | ||
|
|
12ae1c3479 | ||
|
|
fdde0e691e | ||
|
|
1cbd47b988 | ||
|
|
e0183ed5c7 | ||
|
|
dae900cc59 | ||
|
|
4c2042ab01 | ||
|
|
2f0ca206f3 | ||
|
|
ac7c1bd97b | ||
|
|
d9a102afa9 | ||
|
|
7c1dcd8a72 | ||
|
|
1fbfeabd77 | ||
|
|
9a918f285d | ||
|
|
a7183f34ef | ||
|
|
bda416df0a | ||
|
|
a838c2bacc | ||
|
|
d2a094aa4c | ||
|
|
bdb2a53597 | ||
|
|
97ad0f1b4f | ||
|
|
2b5e177ab2 | ||
|
|
bfe29c4ef6 | ||
|
|
e35601bb19 | ||
|
|
24df438607 | ||
|
|
cb3b8cf21b | ||
|
|
0e6add0cfb | ||
|
|
343e97da0e | ||
|
|
ba8ce7233d | ||
|
|
35184e6908 | ||
|
|
824b00c9e0 | ||
|
|
79cab93d49 | ||
|
|
2afc9faa08 | ||
|
|
0e99d02fbe | ||
|
|
3a0a1e6d4a | ||
|
|
2057c35468 | ||
|
|
5eaa3b0916 | ||
|
|
4ad0f54c30 | ||
|
|
eeff3b5049 | ||
|
|
5e352489a0 | ||
|
|
fa5a5c8c05 | ||
|
|
7fe5a30424 | ||
|
|
a82b2155e9 |
23
.github/workflows/cont_integration.yml
vendored
23
.github/workflows/cont_integration.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- stable
|
||||
- 1.50.0 # STABLE
|
||||
- 1.45.0 # MSRV
|
||||
features:
|
||||
- default
|
||||
@@ -76,13 +76,14 @@ jobs:
|
||||
test-electrum:
|
||||
name: Test electrum
|
||||
runs-on: ubuntu-16.04
|
||||
container: bitcoindevkit/electrs
|
||||
container: bitcoindevkit/electrs:0.2.0
|
||||
env:
|
||||
MAGICAL_RPC_AUTH: USER_PASS
|
||||
MAGICAL_RPC_USER: admin
|
||||
MAGICAL_RPC_PASS: passw
|
||||
MAGICAL_RPC_URL: 127.0.0.1:18443
|
||||
MAGICAL_ELECTRUM_URL: tcp://127.0.0.1:60401
|
||||
BDK_RPC_AUTH: USER_PASS
|
||||
BDK_RPC_USER: admin
|
||||
BDK_RPC_PASS: passw
|
||||
BDK_RPC_URL: 127.0.0.1:18443
|
||||
BDK_RPC_WALLET: bdk-test
|
||||
BDK_ELECTRUM_URL: tcp://127.0.0.1:60401
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@@ -97,7 +98,7 @@ jobs:
|
||||
- name: Install rustup
|
||||
run: curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||
- name: Set default toolchain
|
||||
run: $HOME/.cargo/bin/rustup default stable
|
||||
run: $HOME/.cargo/bin/rustup default 1.50.0 # STABLE
|
||||
- name: Set profile
|
||||
run: $HOME/.cargo/bin/rustup set profile minimal
|
||||
- name: Update toolchain
|
||||
@@ -128,9 +129,9 @@ jobs:
|
||||
- run: wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - || exit 1
|
||||
- run: sudo apt-add-repository "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" || exit 1
|
||||
- run: sudo apt-get update || exit 1
|
||||
- run: sudo apt-get install -y clang-10 libc6-dev-i386 || exit 1
|
||||
- run: sudo apt-get install -y libclang-common-10-dev clang-10 libc6-dev-i386 || exit 1
|
||||
- name: Set default toolchain
|
||||
run: rustup default stable
|
||||
run: rustup default 1.50.0 # STABLE
|
||||
- name: Set profile
|
||||
run: rustup set profile minimal
|
||||
- name: Add target wasm32
|
||||
@@ -147,7 +148,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Set default toolchain
|
||||
run: rustup default stable
|
||||
run: rustup default 1.50.0 # STABLE
|
||||
- name: Set profile
|
||||
run: rustup set profile minimal
|
||||
- name: Add clippy
|
||||
|
||||
27
CHANGELOG.md
27
CHANGELOG.md
@@ -6,6 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.5.1] - [v0.5.0]
|
||||
|
||||
### Misc
|
||||
#### Changed
|
||||
- Pin `hyper` to `=0.14.4` to make it compile on Rust 1.45
|
||||
|
||||
## [v0.5.0] - [v0.4.0]
|
||||
|
||||
### Misc
|
||||
#### Changed
|
||||
- Updated `electrum-client` to version `0.7`
|
||||
|
||||
### Wallet
|
||||
#### Changed
|
||||
- `FeeRate` constructors `from_sat_per_vb` and `default_min_relay_fee` are now `const` functions
|
||||
|
||||
## [v0.4.0] - [v0.3.0]
|
||||
|
||||
### Keys
|
||||
@@ -50,7 +66,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
type to mark for a missing client.
|
||||
- Upgrade `tokio` to `1.0`.
|
||||
|
||||
#### Transaction Creation Overhaul
|
||||
### Transaction Creation Overhaul
|
||||
|
||||
The `TxBuilder` is now created from the `build_tx` or `build_fee_bump` functions on wallet and the
|
||||
final transaction is created by calling `finish` on the builder.
|
||||
@@ -61,6 +77,13 @@ final transaction is created by calling `finish` on the builder.
|
||||
- Added `Wallet::get_utxo`
|
||||
- Added `Wallet::get_descriptor_for_keychain`
|
||||
|
||||
### `add_foreign_utxo`
|
||||
|
||||
- Renamed `UTXO` to `LocalUtxo`
|
||||
- Added `WeightedUtxo` to replace floating `(UTXO, usize)`.
|
||||
- Added `Utxo` enum to incorporate both local utxos and foreign utxos
|
||||
- Added `TxBuilder::add_foreign_utxo` which allows adding a utxo external to the wallet.
|
||||
|
||||
### CLI
|
||||
#### Changed
|
||||
- Remove `cli.rs` module, `cli-utils` feature and `repl.rs` example; moved to new [`bdk-cli`](https://github.com/bitcoindevkit/bdk-cli) repository
|
||||
@@ -275,3 +298,5 @@ final transaction is created by calling `finish` on the builder.
|
||||
[v0.2.0]: https://github.com/bitcoindevkit/bdk/compare/0.1.0-beta.1...v0.2.0
|
||||
[v0.3.0]: https://github.com/bitcoindevkit/bdk/compare/v0.2.0...v0.3.0
|
||||
[v0.4.0]: https://github.com/bitcoindevkit/bdk/compare/v0.3.0...v0.4.0
|
||||
[v0.5.0]: https://github.com/bitcoindevkit/bdk/compare/v0.4.0...v0.5.0
|
||||
[v0.5.1]: https://github.com/bitcoindevkit/bdk/compare/v0.5.0...v0.5.1
|
||||
|
||||
14
Cargo.toml
14
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bdk"
|
||||
version = "0.4.1-dev"
|
||||
version = "0.5.2-dev"
|
||||
edition = "2018"
|
||||
authors = ["Alekos Filini <alekos.filini@gmail.com>", "Riccardo Casatta <riccardo@casatta.it>"]
|
||||
homepage = "https://bitcoindevkit.org"
|
||||
@@ -9,10 +9,10 @@ documentation = "https://docs.rs/bdk"
|
||||
description = "A modern, lightweight, descriptor-based wallet library"
|
||||
keywords = ["bitcoin", "wallet", "descriptor", "psbt"]
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
bdk-macros = "^0.3"
|
||||
bdk-macros = "^0.4"
|
||||
log = "^0.4"
|
||||
miniscript = "5.1"
|
||||
bitcoin = { version = "^0.26", features = ["use-serde"] }
|
||||
@@ -22,7 +22,7 @@ rand = "^0.7"
|
||||
|
||||
# Optional dependencies
|
||||
sled = { version = "0.34", optional = true }
|
||||
electrum-client = { version = "0.6", optional = true }
|
||||
electrum-client = { version = "0.7", optional = true }
|
||||
reqwest = { version = "0.11", optional = true, features = ["json"] }
|
||||
futures = { version = "0.3", optional = true }
|
||||
async-trait = { version = "0.1", optional = true }
|
||||
@@ -35,6 +35,8 @@ tiny-bip39 = { version = "^0.8", optional = true }
|
||||
# Platform-specific dependencies
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
tokio = { version = "1", features = ["rt"] }
|
||||
# pin hyper version to prevent update to socket2 0.4.0 which isn't supported for MSRV 1.45.0
|
||||
hyper = { version = "=0.14.4" }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
async-trait = "0.1"
|
||||
@@ -59,8 +61,8 @@ test-electrum = ["electrum"]
|
||||
test-md-docs = ["electrum"]
|
||||
|
||||
[dev-dependencies]
|
||||
bdk-testutils = "^0.3"
|
||||
bdk-testutils-macros = "^0.3"
|
||||
bdk-testutils = "0.4"
|
||||
bdk-testutils-macros = "0.4"
|
||||
serial_test = "0.4"
|
||||
lazy_static = "1.4"
|
||||
env_logger = "0.7"
|
||||
|
||||
29
LICENSE
29
LICENSE
@@ -1,21 +1,14 @@
|
||||
MIT License
|
||||
This software is licensed under [Apache 2.0](LICENSE-APACHE) or
|
||||
[MIT](LICENSE-MIT), at your option.
|
||||
|
||||
Copyright (c) 2020 Magical Bitcoin
|
||||
Some files retain their own copyright notice, however, for full authorship
|
||||
information, see version control history.
|
||||
|
||||
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:
|
||||
Except as otherwise noted in individual files, all files in this repository are
|
||||
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.
|
||||
|
||||
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.
|
||||
You may not use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of this software or any files in this repository except in
|
||||
accordance with one or both of these licenses.
|
||||
201
LICENSE-APACHE
Normal file
201
LICENSE-APACHE
Normal file
@@ -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.
|
||||
16
LICENSE-MIT
Normal file
16
LICENSE-MIT
Normal file
@@ -0,0 +1,16 @@
|
||||
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.
|
||||
19
README.md
19
README.md
@@ -9,7 +9,7 @@
|
||||
|
||||
<p>
|
||||
<a href="https://crates.io/crates/bdk"><img alt="Crate Info" src="https://img.shields.io/crates/v/bdk.svg"/></a>
|
||||
<a href="https://github.com/bitcoindevkit/bdk/blob/master/LICENSE"><img alt="MIT Licensed" src="https://img.shields.io/badge/license-MIT-blue.svg"/></a>
|
||||
<a href="https://github.com/bitcoindevkit/bdk/blob/master/LICENSE"><img alt="MIT or Apache-2.0 Licensed" src="https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg"/></a>
|
||||
<a href="https://github.com/bitcoindevkit/bdk/actions?query=workflow%3ACI"><img alt="CI Status" src="https://github.com/bitcoindevkit/bdk/workflows/CI/badge.svg"></a>
|
||||
<a href="https://codecov.io/gh/bitcoindevkit/bdk"><img src="https://codecov.io/gh/bitcoindevkit/bdk/branch/master/graph/badge.svg"/></a>
|
||||
<a href="https://docs.rs/bdk"><img alt="API Docs" src="https://img.shields.io/badge/docs.rs-bdk-green"/></a>
|
||||
@@ -148,3 +148,20 @@ fn main() -> Result<(), bdk::Error> {
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
* Apache License, Version 2.0
|
||||
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||
* MIT license
|
||||
([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||
|
||||
at your option.
|
||||
|
||||
## Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
echo "Starting bitcoin node."
|
||||
/root/bitcoind -regtest -server -daemon -fallbackfee=0.0002 -rpcuser=admin -rpcpassword=passw -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0
|
||||
/root/bitcoind -regtest -server -daemon -fallbackfee=0.0002 -rpcuser=$BDK_RPC_USER -rpcpassword=$BDK_RPC_PASS -rpcallowip=0.0.0.0/0 -rpcbind=0.0.0.0 -blockfilterindex=1 -peerblockfilters=1
|
||||
|
||||
echo "Waiting for bitcoin node."
|
||||
until /root/bitcoin-cli -regtest -rpcuser=admin -rpcpassword=passw getblockchaininfo; do
|
||||
until /root/bitcoin-cli -regtest -rpcuser=$BDK_RPC_USER -rpcpassword=$BDK_RPC_PASS getblockchaininfo; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
/root/bitcoin-cli -regtest -rpcuser=$BDK_RPC_USER -rpcpassword=$BDK_RPC_PASS createwallet $BDK_RPC_WALLET
|
||||
echo "Generating 150 bitcoin blocks."
|
||||
ADDR=$(/root/bitcoin-cli -regtest -rpcuser=admin -rpcpassword=passw getnewaddress)
|
||||
/root/bitcoin-cli -regtest -rpcuser=admin -rpcpassword=passw generatetoaddress 150 $ADDR
|
||||
ADDR=$(/root/bitcoin-cli -regtest -rpcuser=$BDK_RPC_USER -rpcpassword=$BDK_RPC_PASS -rpcwallet=$BDK_RPC_WALLET getnewaddress)
|
||||
/root/bitcoin-cli -regtest -rpcuser=$BDK_RPC_USER -rpcpassword=$BDK_RPC_PASS generatetoaddress 150 $ADDR
|
||||
|
||||
echo "Starting electrs node."
|
||||
nohup /root/electrs --network regtest --jsonrpc-import &
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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::sync::Arc;
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// 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 bdk::blockchain::compact_filters::*;
|
||||
use bdk::blockchain::noop_progress;
|
||||
use bdk::database::MemoryDatabase;
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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.
|
||||
|
||||
extern crate bdk;
|
||||
extern crate bitcoin;
|
||||
@@ -97,7 +84,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
let network = matches
|
||||
.value_of("network")
|
||||
.and_then(|n| Some(Network::from_str(n)))
|
||||
.map(|n| Network::from_str(n))
|
||||
.transpose()
|
||||
.unwrap()
|
||||
.unwrap_or(Network::Testnet);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bdk-macros"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
authors = ["Alekos Filini <alekos.filini@gmail.com>"]
|
||||
edition = "2018"
|
||||
homepage = "https://bitcoindevkit.org"
|
||||
@@ -8,7 +8,7 @@ repository = "https://github.com/bitcoindevkit/bdk"
|
||||
documentation = "https://docs.rs/bdk-macros"
|
||||
description = "Supporting macros for `bdk`"
|
||||
keywords = ["bdk"]
|
||||
license = "MIT"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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.
|
||||
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
|
||||
31
scripts/cargo-check.sh
Executable file
31
scripts/cargo-check.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Run various invocations of cargo check
|
||||
|
||||
features=( "default" "compiler" "electrum" "esplora" "compact_filters" "key-value-db" "async-interface" "all-keys" "keys-bip39" )
|
||||
toolchains=( "+stable" "+1.45" "+nightly" )
|
||||
|
||||
main() {
|
||||
check_src
|
||||
check_all_targets
|
||||
}
|
||||
|
||||
# Check with all features, with various toolchains.
|
||||
check_src() {
|
||||
for toolchain in "${toolchains[@]}"; do
|
||||
cmd="cargo $toolchain clippy --all-targets --no-default-features"
|
||||
|
||||
for feature in "${features[@]}"; do
|
||||
touch_files
|
||||
$cmd --features "$feature"
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
# Touch files to prevent cached warnings from not showing up.
|
||||
touch_files() {
|
||||
touch $(find . -name *.rs)
|
||||
}
|
||||
|
||||
main
|
||||
exit 0
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -83,7 +70,7 @@ mod sync;
|
||||
use super::{Blockchain, Capability, ConfigurableBlockchain, Progress};
|
||||
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
|
||||
use crate::error::Error;
|
||||
use crate::types::{KeychainKind, TransactionDetails, UTXO};
|
||||
use crate::types::{KeychainKind, LocalUtxo, TransactionDetails};
|
||||
use crate::FeeRate;
|
||||
|
||||
use peer::*;
|
||||
@@ -194,7 +181,7 @@ impl CompactFiltersBlockchain {
|
||||
database.get_path_from_script_pubkey(&output.script_pubkey)?
|
||||
{
|
||||
debug!("{} output #{} is mine, adding utxo", tx.txid(), i);
|
||||
updates.set_utxo(&UTXO {
|
||||
updates.set_utxo(&LocalUtxo {
|
||||
outpoint: OutPoint::new(tx.txid(), i as u32),
|
||||
txout: output.clone(),
|
||||
keychain,
|
||||
@@ -239,6 +226,7 @@ impl Blockchain for CompactFiltersBlockchain {
|
||||
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,
|
||||
_stop_gap: Option<usize>, // TODO: move to electrum and esplora only
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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};
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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;
|
||||
@@ -46,6 +33,8 @@ use bitcoin::BlockHash;
|
||||
use bitcoin::BlockHeader;
|
||||
use bitcoin::Network;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::CompactFiltersError;
|
||||
|
||||
lazy_static! {
|
||||
@@ -119,7 +108,7 @@ where
|
||||
}
|
||||
|
||||
fn deserialize(data: &[u8]) -> Result<Self, CompactFiltersError> {
|
||||
Ok(deserialize(data).map_err(|_| CompactFiltersError::DataCorruption)?)
|
||||
deserialize(data).map_err(|_| CompactFiltersError::DataCorruption)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,15 +425,14 @@ impl ChainStore<Full> {
|
||||
|
||||
let key = StoreEntry::BlockHeaderIndex(Some(*block_hash)).get_key();
|
||||
let data = read_store.get_pinned_cf(cf_handle, key)?;
|
||||
Ok(data
|
||||
.map(|data| {
|
||||
Ok::<_, CompactFiltersError>(usize::from_be_bytes(
|
||||
data.as_ref()
|
||||
.try_into()
|
||||
.map_err(|_| CompactFiltersError::DataCorruption)?,
|
||||
))
|
||||
})
|
||||
.transpose()?)
|
||||
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> {
|
||||
@@ -453,13 +441,12 @@ impl ChainStore<Full> {
|
||||
|
||||
let key = StoreEntry::BlockHeader(Some(height)).get_key();
|
||||
let data = read_store.get_pinned_cf(cf_handle, key)?;
|
||||
Ok(data
|
||||
.map(|data| {
|
||||
let (header, _): (BlockHeader, Uint256) =
|
||||
deserialize(&data).map_err(|_| CompactFiltersError::DataCorruption)?;
|
||||
Ok::<_, CompactFiltersError>(header.block_hash())
|
||||
})
|
||||
.transpose()?)
|
||||
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> {
|
||||
@@ -475,10 +462,10 @@ impl ChainStore<Full> {
|
||||
let key = StoreEntry::Block(Some(height)).get_key();
|
||||
let opt_block = read_store.get_pinned(key)?;
|
||||
|
||||
Ok(opt_block
|
||||
opt_block
|
||||
.map(|data| deserialize(&data))
|
||||
.transpose()
|
||||
.map_err(|_| CompactFiltersError::DataCorruption)?)
|
||||
.map_err(|_| CompactFiltersError::DataCorruption)
|
||||
}
|
||||
|
||||
pub fn delete_blocks_until(&self, height: usize) -> Result<(), CompactFiltersError> {
|
||||
@@ -565,14 +552,14 @@ impl<T: StoreType> ChainStore<T> {
|
||||
let prefix = StoreEntry::BlockHeader(None).get_key();
|
||||
let iterator = read_store.prefix_iterator_cf(cf_handle, prefix);
|
||||
|
||||
Ok(iterator
|
||||
iterator
|
||||
.last()
|
||||
.map(|(_, v)| -> Result<_, CompactFiltersError> {
|
||||
let (header, _): (BlockHeader, Uint256) = SerializeDb::deserialize(&v)?;
|
||||
|
||||
Ok(header.block_hash())
|
||||
})
|
||||
.transpose()?)
|
||||
.transpose()
|
||||
}
|
||||
|
||||
pub fn apply(
|
||||
@@ -716,11 +703,11 @@ impl CFStore {
|
||||
|
||||
// FIXME: we have to filter manually because rocksdb sometimes returns stuff that doesn't
|
||||
// have the right prefix
|
||||
Ok(iterator
|
||||
iterator
|
||||
.filter(|(k, _)| k.starts_with(&prefix))
|
||||
.skip(1)
|
||||
.map(|(_, data)| Ok::<_, CompactFiltersError>(BundleEntry::deserialize(&data)?.1))
|
||||
.collect::<Result<_, _>>()?)
|
||||
.collect::<Result<_, _>>()
|
||||
}
|
||||
|
||||
pub fn replace_checkpoints(
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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};
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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};
|
||||
|
||||
@@ -34,7 +21,7 @@ use bitcoin::{BlockHeader, OutPoint, Script, Transaction, Txid};
|
||||
use super::*;
|
||||
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils};
|
||||
use crate::error::Error;
|
||||
use crate::types::{KeychainKind, TransactionDetails, UTXO};
|
||||
use crate::types::{KeychainKind, LocalUtxo, TransactionDetails};
|
||||
use crate::wallet::time::Instant;
|
||||
use crate::wallet::utils::ChunksIterator;
|
||||
|
||||
@@ -353,7 +340,7 @@ fn save_transaction_details_and_utxos<D: BatchDatabase>(
|
||||
// this output is ours, we have a path to derive it
|
||||
if let Some((keychain, _child)) = db.get_path_from_script_pubkey(&output.script_pubkey)? {
|
||||
debug!("{} output #{} is mine, adding utxo", txid, i);
|
||||
updates.set_utxo(&UTXO {
|
||||
updates.set_utxo(&LocalUtxo {
|
||||
outpoint: OutPoint::new(tx.txid(), i as u32),
|
||||
txout: output.clone(),
|
||||
keychain,
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -133,7 +120,7 @@ impl BatchOperations for AnyDatabase {
|
||||
child
|
||||
)
|
||||
}
|
||||
fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error> {
|
||||
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> {
|
||||
@@ -165,7 +152,7 @@ impl BatchOperations for AnyDatabase {
|
||||
) -> Result<Option<(KeychainKind, u32)>, Error> {
|
||||
impl_inner_method!(AnyDatabase, self, del_path_from_script_pubkey, script)
|
||||
}
|
||||
fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
|
||||
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> {
|
||||
@@ -201,7 +188,7 @@ impl Database for AnyDatabase {
|
||||
fn iter_script_pubkeys(&self, keychain: Option<KeychainKind>) -> Result<Vec<Script>, Error> {
|
||||
impl_inner_method!(AnyDatabase, self, iter_script_pubkeys, keychain)
|
||||
}
|
||||
fn iter_utxos(&self) -> Result<Vec<UTXO>, Error> {
|
||||
fn iter_utxos(&self) -> Result<Vec<LocalUtxo>, Error> {
|
||||
impl_inner_method!(AnyDatabase, self, iter_utxos)
|
||||
}
|
||||
fn iter_raw_txs(&self) -> Result<Vec<Transaction>, Error> {
|
||||
@@ -230,7 +217,7 @@ impl Database for AnyDatabase {
|
||||
) -> Result<Option<(KeychainKind, u32)>, Error> {
|
||||
impl_inner_method!(AnyDatabase, self, get_path_from_script_pubkey, script)
|
||||
}
|
||||
fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
|
||||
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> {
|
||||
@@ -257,7 +244,7 @@ impl BatchOperations for AnyBatch {
|
||||
) -> Result<(), Error> {
|
||||
impl_inner_method!(AnyBatch, self, set_script_pubkey, script, keychain, child)
|
||||
}
|
||||
fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error> {
|
||||
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> {
|
||||
@@ -283,7 +270,7 @@ impl BatchOperations for AnyBatch {
|
||||
) -> Result<Option<(KeychainKind, u32)>, Error> {
|
||||
impl_inner_method!(AnyBatch, self, del_path_from_script_pubkey, script)
|
||||
}
|
||||
fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
|
||||
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> {
|
||||
@@ -312,24 +299,17 @@ impl BatchDatabase for AnyDatabase {
|
||||
}
|
||||
}
|
||||
fn commit_batch(&mut self, batch: Self::Batch) -> Result<(), Error> {
|
||||
// TODO: refactor once `move_ref_pattern` is stable
|
||||
#[allow(irrefutable_let_patterns)]
|
||||
match self {
|
||||
AnyDatabase::Memory(db) => {
|
||||
if let AnyBatch::Memory(batch) = batch {
|
||||
db.commit_batch(batch)
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
AnyDatabase::Memory(db) => match batch {
|
||||
AnyBatch::Memory(batch) => db.commit_batch(batch),
|
||||
#[cfg(feature = "key-value-db")]
|
||||
_ => unimplemented!("Sled batch shouldn't be used with Memory db."),
|
||||
},
|
||||
#[cfg(feature = "key-value-db")]
|
||||
AnyDatabase::Sled(db) => {
|
||||
if let AnyBatch::Sled(batch) = batch {
|
||||
db.commit_batch(batch)
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
AnyDatabase::Sled(db) => match batch {
|
||||
AnyBatch::Sled(batch) => db.commit_batch(batch),
|
||||
_ => unimplemented!("Memory batch shouldn't be used with Sled db."),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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;
|
||||
|
||||
@@ -51,7 +38,7 @@ macro_rules! impl_batch_operations {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error> {
|
||||
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,
|
||||
@@ -120,7 +107,7 @@ macro_rules! impl_batch_operations {
|
||||
}
|
||||
}
|
||||
|
||||
fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
|
||||
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);
|
||||
@@ -132,7 +119,7 @@ macro_rules! impl_batch_operations {
|
||||
let txout = serde_json::from_value(val["t"].take())?;
|
||||
let keychain = serde_json::from_value(val["i"].take())?;
|
||||
|
||||
Ok(Some(UTXO { outpoint: outpoint.clone(), txout, keychain }))
|
||||
Ok(Some(LocalUtxo { outpoint: outpoint.clone(), txout, keychain }))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,7 +221,7 @@ impl Database for Tree {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn iter_utxos(&self) -> Result<Vec<UTXO>, Error> {
|
||||
fn iter_utxos(&self) -> Result<Vec<LocalUtxo>, Error> {
|
||||
let key = MapKey::UTXO(None).as_map_key();
|
||||
self.scan_prefix(key)
|
||||
.map(|x| -> Result<_, Error> {
|
||||
@@ -245,7 +232,7 @@ impl Database for Tree {
|
||||
let txout = serde_json::from_value(val["t"].take())?;
|
||||
let keychain = serde_json::from_value(val["i"].take())?;
|
||||
|
||||
Ok(UTXO {
|
||||
Ok(LocalUtxo {
|
||||
outpoint,
|
||||
txout,
|
||||
keychain,
|
||||
@@ -305,7 +292,7 @@ impl Database for Tree {
|
||||
.transpose()
|
||||
}
|
||||
|
||||
fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
|
||||
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> {
|
||||
@@ -313,7 +300,7 @@ impl Database for Tree {
|
||||
let txout = serde_json::from_value(val["t"].take())?;
|
||||
let keychain = serde_json::from_value(val["i"].take())?;
|
||||
|
||||
Ok(UTXO {
|
||||
Ok(LocalUtxo {
|
||||
outpoint: *outpoint,
|
||||
txout,
|
||||
keychain,
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -157,7 +144,7 @@ impl BatchOperations for MemoryDatabase {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_utxo(&mut self, utxo: &UTXO) -> Result<(), Error> {
|
||||
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)));
|
||||
@@ -223,7 +210,7 @@ impl BatchOperations for MemoryDatabase {
|
||||
}
|
||||
}
|
||||
}
|
||||
fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
|
||||
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);
|
||||
@@ -232,7 +219,7 @@ impl BatchOperations for MemoryDatabase {
|
||||
None => Ok(None),
|
||||
Some(b) => {
|
||||
let (txout, keychain) = b.downcast_ref().cloned().unwrap();
|
||||
Ok(Some(UTXO {
|
||||
Ok(Some(LocalUtxo {
|
||||
outpoint: *outpoint,
|
||||
txout,
|
||||
keychain,
|
||||
@@ -316,14 +303,14 @@ impl Database for MemoryDatabase {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn iter_utxos(&self) -> Result<Vec<UTXO>, Error> {
|
||||
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(UTXO {
|
||||
Ok(LocalUtxo {
|
||||
outpoint,
|
||||
txout,
|
||||
keychain,
|
||||
@@ -382,11 +369,11 @@ impl Database for MemoryDatabase {
|
||||
}))
|
||||
}
|
||||
|
||||
fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error> {
|
||||
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();
|
||||
UTXO {
|
||||
LocalUtxo {
|
||||
outpoint: *outpoint,
|
||||
txout,
|
||||
keychain,
|
||||
@@ -502,7 +489,7 @@ macro_rules! populate_test_db {
|
||||
|
||||
db.set_tx(&tx_details).unwrap();
|
||||
for (vout, out) in tx.output.iter().enumerate() {
|
||||
db.set_utxo(&UTXO {
|
||||
db.set_utxo(&LocalUtxo {
|
||||
txout: out.clone(),
|
||||
outpoint: OutPoint {
|
||||
txid,
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -64,8 +51,8 @@ pub trait BatchOperations {
|
||||
keychain: KeychainKind,
|
||||
child: u32,
|
||||
) -> Result<(), Error>;
|
||||
/// Store a [`UTXO`]
|
||||
fn set_utxo(&mut self, utxo: &UTXO) -> 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
|
||||
@@ -85,8 +72,8 @@ pub trait BatchOperations {
|
||||
&mut self,
|
||||
script: &Script,
|
||||
) -> Result<Option<(KeychainKind, u32)>, Error>;
|
||||
/// Delete a [`UTXO`] given its [`OutPoint`]
|
||||
fn del_utxo(&mut self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error>;
|
||||
/// Delete a [`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
|
||||
@@ -116,8 +103,8 @@ pub trait Database: BatchOperations {
|
||||
|
||||
/// Return the list of script_pubkeys
|
||||
fn iter_script_pubkeys(&self, keychain: Option<KeychainKind>) -> Result<Vec<Script>, Error>;
|
||||
/// Return the list of [`UTXO`]s
|
||||
fn iter_utxos(&self) -> Result<Vec<UTXO>, Error>;
|
||||
/// Return the list of [`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
|
||||
@@ -134,8 +121,8 @@ pub trait Database: BatchOperations {
|
||||
&self,
|
||||
script: &Script,
|
||||
) -> Result<Option<(KeychainKind, u32)>, Error>;
|
||||
/// Fetch a [`UTXO`] given its [`OutPoint`]
|
||||
fn get_utxo(&self, outpoint: &OutPoint) -> Result<Option<UTXO>, Error>;
|
||||
/// Fetch a [`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
|
||||
@@ -227,7 +214,7 @@ pub mod test {
|
||||
);
|
||||
assert_eq!(
|
||||
tree.get_path_from_script_pubkey(&script).unwrap(),
|
||||
Some((keychain, path.clone()))
|
||||
Some((keychain, path))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -256,7 +243,7 @@ pub mod test {
|
||||
);
|
||||
assert_eq!(
|
||||
tree.get_path_from_script_pubkey(&script).unwrap(),
|
||||
Some((keychain, path.clone()))
|
||||
Some((keychain, path))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -298,7 +285,7 @@ pub mod test {
|
||||
value: 133742,
|
||||
script_pubkey: script,
|
||||
};
|
||||
let utxo = UTXO {
|
||||
let utxo = LocalUtxo {
|
||||
txout,
|
||||
outpoint,
|
||||
keychain: KeychainKind::External,
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
|
||||
@@ -228,10 +215,11 @@ macro_rules! impl_sortedmulti {
|
||||
use $crate::keys::IntoDescriptorKey;
|
||||
let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
|
||||
|
||||
let mut keys = vec![];
|
||||
$(
|
||||
keys.push($key.into_descriptor_key());
|
||||
)*
|
||||
let keys = vec![
|
||||
$(
|
||||
$key.into_descriptor_key(),
|
||||
)*
|
||||
];
|
||||
|
||||
keys.into_iter().collect::<Result<Vec<_>, _>>()
|
||||
.map_err($crate::descriptor::DescriptorError::Key)
|
||||
@@ -656,10 +644,11 @@ macro_rules! fragment {
|
||||
use $crate::keys::IntoDescriptorKey;
|
||||
let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
|
||||
|
||||
let mut keys = vec![];
|
||||
$(
|
||||
keys.push($key.into_descriptor_key());
|
||||
)*
|
||||
let keys = vec![
|
||||
$(
|
||||
$key.into_descriptor_key(),
|
||||
)*
|
||||
];
|
||||
|
||||
keys.into_iter().collect::<Result<Vec<_>, _>>()
|
||||
.map_err($crate::descriptor::DescriptorError::Key)
|
||||
@@ -968,7 +957,7 @@ mod test {
|
||||
fn test_valid_networks() {
|
||||
let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
|
||||
let path = bip32::DerivationPath::from_str("m/0").unwrap();
|
||||
let desc_key = (xprv, path.clone()).into_descriptor_key().unwrap();
|
||||
let desc_key = (xprv, path).into_descriptor_key().unwrap();
|
||||
|
||||
let (_desc, _key_map, valid_networks) = descriptor!(pkh(desc_key)).unwrap();
|
||||
assert_eq!(
|
||||
@@ -978,7 +967,7 @@ mod test {
|
||||
|
||||
let xprv = bip32::ExtendedPrivKey::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap();
|
||||
let path = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap();
|
||||
let desc_key = (xprv, path.clone()).into_descriptor_key().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());
|
||||
@@ -1005,12 +994,9 @@ mod test {
|
||||
descriptor!(sh(wsh(multi(2, desc_key1, desc_key2, desc_key3)))).unwrap();
|
||||
assert_eq!(key_map.len(), 3);
|
||||
|
||||
let desc_key1: DescriptorKey<Segwitv0> =
|
||||
(xprv1, path1.clone()).into_descriptor_key().unwrap();
|
||||
let desc_key2: DescriptorKey<Segwitv0> =
|
||||
(xprv2, path2.clone()).into_descriptor_key().unwrap();
|
||||
let desc_key3: DescriptorKey<Segwitv0> =
|
||||
(xprv3, path3.clone()).into_descriptor_key().unwrap();
|
||||
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();
|
||||
@@ -1026,7 +1012,7 @@ mod test {
|
||||
// this compiles
|
||||
let xprv = bip32::ExtendedPrivKey::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
|
||||
let path = bip32::DerivationPath::from_str("m/0").unwrap();
|
||||
let desc_key: DescriptorKey<Legacy> = (xprv, path.clone()).into_descriptor_key().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");
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
|
||||
@@ -33,6 +20,8 @@ pub enum Error {
|
||||
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),
|
||||
|
||||
@@ -1,33 +1,20 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::ops::Deref;
|
||||
|
||||
use bitcoin::util::bip32::{
|
||||
@@ -225,6 +212,24 @@ pub(crate) fn into_wallet_descriptor_checked<T: IntoWalletDescriptor>(
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -783,5 +788,14 @@ mod test {
|
||||
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
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -938,7 +925,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint)
|
||||
matches!(&policy.item, Signature(pk_or_f) if pk_or_f.fingerprint.unwrap() == fingerprint)
|
||||
);
|
||||
assert!(matches!(&policy.contribution, Satisfaction::None));
|
||||
|
||||
@@ -953,7 +940,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint)
|
||||
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)
|
||||
@@ -1039,8 +1026,8 @@ mod test {
|
||||
|
||||
assert!(
|
||||
matches!(&policy.item, Multisig { keys, threshold } if threshold == &1
|
||||
&& &keys[0].fingerprint.unwrap() == &fingerprint0
|
||||
&& &keys[1].fingerprint.unwrap() == &fingerprint1)
|
||||
&& keys[0].fingerprint.unwrap() == fingerprint0
|
||||
&& keys[1].fingerprint.unwrap() == fingerprint1)
|
||||
);
|
||||
assert!(
|
||||
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &2
|
||||
@@ -1071,8 +1058,8 @@ mod test {
|
||||
|
||||
assert!(
|
||||
matches!(&policy.item, Multisig { keys, threshold } if threshold == &2
|
||||
&& &keys[0].fingerprint.unwrap() == &fingerprint0
|
||||
&& &keys[1].fingerprint.unwrap() == &fingerprint1)
|
||||
&& keys[0].fingerprint.unwrap() == fingerprint0
|
||||
&& keys[1].fingerprint.unwrap() == fingerprint1)
|
||||
);
|
||||
|
||||
assert!(
|
||||
@@ -1103,7 +1090,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint)
|
||||
matches!(&policy.item, Signature(pk_or_f) if pk_or_f.fingerprint.unwrap() == fingerprint)
|
||||
);
|
||||
assert!(matches!(&policy.contribution, Satisfaction::None));
|
||||
|
||||
@@ -1119,7 +1106,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
matches!(&policy.item, Signature(pk_or_f) if &pk_or_f.fingerprint.unwrap() == &fingerprint)
|
||||
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)
|
||||
@@ -1147,8 +1134,8 @@ mod test {
|
||||
|
||||
assert!(
|
||||
matches!(&policy.item, Multisig { keys, threshold } if threshold == &1
|
||||
&& &keys[0].fingerprint.unwrap() == &fingerprint0
|
||||
&& &keys[1].fingerprint.unwrap() == &fingerprint1)
|
||||
&& keys[0].fingerprint.unwrap() == fingerprint0
|
||||
&& keys[1].fingerprint.unwrap() == fingerprint1)
|
||||
);
|
||||
assert!(
|
||||
matches!(&policy.contribution, Satisfaction::PartialComplete { n, m, items, conditions, .. } if n == &2
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -75,7 +62,7 @@ impl<T: DescriptorTemplate> IntoWalletDescriptor for T {
|
||||
secp: &SecpCtx,
|
||||
network: Network,
|
||||
) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
|
||||
Ok(self.build()?.into_wallet_descriptor(secp, network)?)
|
||||
self.build()?.into_wallet_descriptor(secp, network)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +95,7 @@ pub struct P2PKH<K: IntoDescriptorKey<Legacy>>(pub K);
|
||||
|
||||
impl<K: IntoDescriptorKey<Legacy>> DescriptorTemplate for P2PKH<K> {
|
||||
fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
|
||||
Ok(descriptor!(pkh(self.0))?)
|
||||
descriptor!(pkh(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +129,7 @@ pub struct P2WPKH_P2SH<K: IntoDescriptorKey<Segwitv0>>(pub K);
|
||||
|
||||
impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH_P2SH<K> {
|
||||
fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
|
||||
Ok(descriptor!(sh(wpkh(self.0)))?)
|
||||
descriptor!(sh(wpkh(self.0)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +162,7 @@ pub struct P2WPKH<K: IntoDescriptorKey<Segwitv0>>(pub K);
|
||||
|
||||
impl<K: IntoDescriptorKey<Segwitv0>> DescriptorTemplate for P2WPKH<K> {
|
||||
fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
|
||||
Ok(descriptor!(wpkh(self.0))?)
|
||||
descriptor!(wpkh(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +197,7 @@ pub struct BIP44<K: DerivableKey<Legacy>>(pub K, pub KeychainKind);
|
||||
|
||||
impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44<K> {
|
||||
fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
|
||||
Ok(P2PKH(legacy::make_bipxx_private(44, self.0, self.1)?).build()?)
|
||||
P2PKH(legacy::make_bipxx_private(44, self.0, self.1)?).build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +236,7 @@ pub struct BIP44Public<K: DerivableKey<Legacy>>(pub K, pub bip32::Fingerprint, p
|
||||
|
||||
impl<K: DerivableKey<Legacy>> DescriptorTemplate for BIP44Public<K> {
|
||||
fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
|
||||
Ok(P2PKH(legacy::make_bipxx_public(44, self.0, self.1, self.2)?).build()?)
|
||||
P2PKH(legacy::make_bipxx_public(44, self.0, self.1, self.2)?).build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +271,7 @@ pub struct BIP49<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
|
||||
|
||||
impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49<K> {
|
||||
fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
|
||||
Ok(P2WPKH_P2SH(segwit_v0::make_bipxx_private(49, self.0, self.1)?).build()?)
|
||||
P2WPKH_P2SH(segwit_v0::make_bipxx_private(49, self.0, self.1)?).build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,7 +310,7 @@ pub struct BIP49Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint,
|
||||
|
||||
impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP49Public<K> {
|
||||
fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
|
||||
Ok(P2WPKH_P2SH(segwit_v0::make_bipxx_public(49, self.0, self.1, self.2)?).build()?)
|
||||
P2WPKH_P2SH(segwit_v0::make_bipxx_public(49, self.0, self.1, self.2)?).build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +345,7 @@ pub struct BIP84<K: DerivableKey<Segwitv0>>(pub K, pub KeychainKind);
|
||||
|
||||
impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84<K> {
|
||||
fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
|
||||
Ok(P2WPKH(segwit_v0::make_bipxx_private(84, self.0, self.1)?).build()?)
|
||||
P2WPKH(segwit_v0::make_bipxx_private(84, self.0, self.1)?).build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,7 +384,7 @@ pub struct BIP84Public<K: DerivableKey<Segwitv0>>(pub K, pub bip32::Fingerprint,
|
||||
|
||||
impl<K: DerivableKey<Segwitv0>> DescriptorTemplate for BIP84Public<K> {
|
||||
fn build(self) -> Result<DescriptorTemplateOut, DescriptorError> {
|
||||
Ok(P2WPKH(segwit_v0::make_bipxx_public(84, self.0, self.1, self.2)?).build()?)
|
||||
P2WPKH(segwit_v0::make_bipxx_public(84, self.0, self.1, self.2)?).build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,11 +427,11 @@ macro_rules! expand_make_bipxx {
|
||||
KeychainKind::Internal => vec![bip32::ChildNumber::from_normal_idx(1)?].into(),
|
||||
};
|
||||
|
||||
let mut source_path = Vec::with_capacity(3);
|
||||
source_path.push(bip32::ChildNumber::from_hardened_idx(bip)?);
|
||||
source_path.push(bip32::ChildNumber::from_hardened_idx(0)?);
|
||||
source_path.push(bip32::ChildNumber::from_hardened_idx(0)?);
|
||||
let source_path: bip32::DerivationPath = source_path.into();
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
// 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.
|
||||
|
||||
#[doc(include = "../README.md")]
|
||||
#[cfg(doctest)]
|
||||
pub struct ReadmeDoctests;
|
||||
|
||||
29
src/error.rs
29
src/error.rs
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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;
|
||||
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
|
||||
@@ -733,7 +720,7 @@ fn expand_multi_keys<Pk: IntoDescriptorKey<Ctx>, Ctx: ScriptContext>(
|
||||
) -> Result<(Vec<DescriptorPublicKey>, KeyMap, ValidNetworks), KeyError> {
|
||||
let (pks, key_maps_networks): (Vec<_>, Vec<_>) = pks
|
||||
.into_iter()
|
||||
.map(|key| Ok::<_, KeyError>(key.into_descriptor_key()?.extract(secp)?))
|
||||
.map(|key| key.into_descriptor_key()?.extract(secp))
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.into_iter()
|
||||
.map(|(a, b, c)| (a, (b, c)))
|
||||
|
||||
32
src/lib.rs
32
src/lib.rs
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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)]
|
||||
@@ -56,7 +43,7 @@
|
||||
//! interact with the bitcoin P2P network.
|
||||
//!
|
||||
//! ```toml
|
||||
//! bdk = "0.4.0"
|
||||
//! bdk = "0.5.0"
|
||||
//! ```
|
||||
//!
|
||||
//! ## Sync the balance of a descriptor
|
||||
@@ -225,7 +212,6 @@ extern crate async_trait;
|
||||
extern crate bdk_macros;
|
||||
|
||||
#[cfg(feature = "compact_filters")]
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
#[cfg(feature = "electrum")]
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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;
|
||||
|
||||
110
src/types.rs
110
src/types.rs
@@ -1,31 +1,18 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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 bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut};
|
||||
use bitcoin::hash_types::Txid;
|
||||
use bitcoin::{hash_types::Txid, util::psbt};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -69,12 +56,12 @@ impl FeeRate {
|
||||
}
|
||||
|
||||
/// Create a new instance of [`FeeRate`] given a float fee rate in satoshi/vbyte
|
||||
pub fn from_sat_per_vb(sat_per_vb: f32) -> Self {
|
||||
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 fn default_min_relay_fee() -> Self {
|
||||
pub const fn default_min_relay_fee() -> Self {
|
||||
FeeRate(1.0)
|
||||
}
|
||||
|
||||
@@ -90,9 +77,11 @@ impl std::default::Default for FeeRate {
|
||||
}
|
||||
}
|
||||
|
||||
/// A wallet unspent output
|
||||
/// An unspent output owned by a [`Wallet`].
|
||||
///
|
||||
/// [`Wallet`]: crate::Wallet
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct UTXO {
|
||||
pub struct LocalUtxo {
|
||||
/// Reference to a transaction output
|
||||
pub outpoint: OutPoint,
|
||||
/// Transaction output
|
||||
@@ -101,6 +90,64 @@ pub struct UTXO {
|
||||
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 {
|
||||
@@ -119,3 +166,14 @@ pub struct TransactionDetails {
|
||||
/// Confirmed in block height, `None` means unconfirmed
|
||||
pub height: Option<u32>,
|
||||
}
|
||||
|
||||
#[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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -50,8 +37,8 @@
|
||||
//! fn coin_select(
|
||||
//! &self,
|
||||
//! database: &D,
|
||||
//! required_utxos: Vec<(UTXO, usize)>,
|
||||
//! optional_utxos: Vec<(UTXO, usize)>,
|
||||
//! required_utxos: Vec<WeightedUtxo>,
|
||||
//! optional_utxos: Vec<WeightedUtxo>,
|
||||
//! fee_rate: FeeRate,
|
||||
//! amount_needed: u64,
|
||||
//! fee_amount: f32,
|
||||
@@ -60,11 +47,10 @@
|
||||
//! let mut additional_weight = 0;
|
||||
//! let all_utxos_selected = required_utxos
|
||||
//! .into_iter().chain(optional_utxos)
|
||||
//! .scan((&mut selected_amount, &mut additional_weight), |(selected_amount, additional_weight), (utxo, weight)| {
|
||||
//! **selected_amount += utxo.txout.value;
|
||||
//! **additional_weight += TXIN_BASE_WEIGHT + weight;
|
||||
//!
|
||||
//! Some(utxo)
|
||||
//! .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 = additional_weight as f32 * fee_rate.as_sat_vb() / 4.0;
|
||||
@@ -75,7 +61,6 @@
|
||||
//!
|
||||
//! Ok(CoinSelectionResult {
|
||||
//! selected: all_utxos_selected,
|
||||
//! selected_amount,
|
||||
//! fee_amount: fee_amount + additional_fees,
|
||||
//! })
|
||||
//! }
|
||||
@@ -97,9 +82,9 @@
|
||||
//! # Ok::<(), bdk::Error>(())
|
||||
//! ```
|
||||
|
||||
use crate::database::Database;
|
||||
use crate::error::Error;
|
||||
use crate::types::{FeeRate, UTXO};
|
||||
use crate::types::FeeRate;
|
||||
use crate::{database::Database, WeightedUtxo};
|
||||
use crate::{error::Error, Utxo};
|
||||
|
||||
use rand::seq::SliceRandom;
|
||||
#[cfg(not(test))]
|
||||
@@ -122,13 +107,29 @@ pub(crate) const TXIN_BASE_WEIGHT: usize = (32 + 4 + 4 + 1) * 4;
|
||||
#[derive(Debug)]
|
||||
pub struct CoinSelectionResult {
|
||||
/// List of outputs selected for use as inputs
|
||||
pub selected: Vec<UTXO>,
|
||||
/// Sum of the selected inputs' value
|
||||
pub selected_amount: u64,
|
||||
pub selected: Vec<Utxo>,
|
||||
/// Total fee amount in satoshi
|
||||
pub fee_amount: f32,
|
||||
}
|
||||
|
||||
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
|
||||
@@ -151,8 +152,8 @@ pub trait CoinSelectionAlgorithm<D: Database>: std::fmt::Debug {
|
||||
fn coin_select(
|
||||
&self,
|
||||
database: &D,
|
||||
required_utxos: Vec<(UTXO, usize)>,
|
||||
optional_utxos: Vec<(UTXO, usize)>,
|
||||
required_utxos: Vec<WeightedUtxo>,
|
||||
optional_utxos: Vec<WeightedUtxo>,
|
||||
fee_rate: FeeRate,
|
||||
amount_needed: u64,
|
||||
fee_amount: f32,
|
||||
@@ -163,15 +164,15 @@ pub trait CoinSelectionAlgorithm<D: Database>: std::fmt::Debug {
|
||||
///
|
||||
/// 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)]
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct LargestFirstCoinSelection;
|
||||
|
||||
impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection {
|
||||
fn coin_select(
|
||||
&self,
|
||||
_database: &D,
|
||||
required_utxos: Vec<(UTXO, usize)>,
|
||||
mut optional_utxos: Vec<(UTXO, usize)>,
|
||||
required_utxos: Vec<WeightedUtxo>,
|
||||
mut optional_utxos: Vec<WeightedUtxo>,
|
||||
fee_rate: FeeRate,
|
||||
amount_needed: u64,
|
||||
mut fee_amount: f32,
|
||||
@@ -188,7 +189,7 @@ impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection {
|
||||
// We put the "required UTXOs" first and make sure the optional UTXOs are sorted,
|
||||
// initially smallest to largest, before being reversed with `.rev()`.
|
||||
let utxos = {
|
||||
optional_utxos.sort_unstable_by_key(|(utxo, _)| utxo.txout.value);
|
||||
optional_utxos.sort_unstable_by_key(|wu| wu.utxo.txout().value);
|
||||
required_utxos
|
||||
.into_iter()
|
||||
.map(|utxo| (true, utxo))
|
||||
@@ -201,18 +202,19 @@ impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection {
|
||||
let selected = utxos
|
||||
.scan(
|
||||
(&mut selected_amount, &mut fee_amount),
|
||||
|(selected_amount, fee_amount), (must_use, (utxo, weight))| {
|
||||
|(selected_amount, fee_amount), (must_use, weighted_utxo)| {
|
||||
if must_use || **selected_amount < amount_needed + (fee_amount.ceil() as u64) {
|
||||
**fee_amount += calc_fee_bytes(TXIN_BASE_WEIGHT + weight);
|
||||
**selected_amount += utxo.txout.value;
|
||||
**fee_amount +=
|
||||
calc_fee_bytes(TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight);
|
||||
**selected_amount += weighted_utxo.utxo.txout().value;
|
||||
|
||||
log::debug!(
|
||||
"Selected {}, updated fee_amount = `{}`",
|
||||
utxo.outpoint,
|
||||
weighted_utxo.utxo.outpoint(),
|
||||
fee_amount
|
||||
);
|
||||
|
||||
Some(utxo)
|
||||
Some(weighted_utxo.utxo)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -231,7 +233,6 @@ impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection {
|
||||
Ok(CoinSelectionResult {
|
||||
selected,
|
||||
fee_amount,
|
||||
selected_amount,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -239,9 +240,7 @@ impl<D: Database> CoinSelectionAlgorithm<D> for LargestFirstCoinSelection {
|
||||
#[derive(Debug, Clone)]
|
||||
// Adds fee information to an UTXO.
|
||||
struct OutputGroup {
|
||||
utxo: UTXO,
|
||||
// weight needed to satisfy the UTXO, as described in `Descriptor::max_satisfaction_weight`
|
||||
satisfaction_weight: usize,
|
||||
weighted_utxo: WeightedUtxo,
|
||||
// Amount of fees for spending a certain utxo, calculated using a certain FeeRate
|
||||
fee: f32,
|
||||
// The effective value of the UTXO, i.e., the utxo value minus the fee for spending it
|
||||
@@ -249,12 +248,12 @@ struct OutputGroup {
|
||||
}
|
||||
|
||||
impl OutputGroup {
|
||||
fn new(utxo: UTXO, satisfaction_weight: usize, fee_rate: FeeRate) -> Self {
|
||||
let fee = (TXIN_BASE_WEIGHT + satisfaction_weight) as f32 / 4.0 * fee_rate.as_sat_vb();
|
||||
let effective_value = utxo.txout.value as i64 - fee.ceil() as i64;
|
||||
fn new(weighted_utxo: WeightedUtxo, fee_rate: FeeRate) -> Self {
|
||||
let fee = (TXIN_BASE_WEIGHT + weighted_utxo.satisfaction_weight) as f32 / 4.0
|
||||
* fee_rate.as_sat_vb();
|
||||
let effective_value = weighted_utxo.utxo.txout().value as i64 - fee.ceil() as i64;
|
||||
OutputGroup {
|
||||
utxo,
|
||||
satisfaction_weight,
|
||||
weighted_utxo,
|
||||
effective_value,
|
||||
fee,
|
||||
}
|
||||
@@ -291,8 +290,8 @@ impl<D: Database> CoinSelectionAlgorithm<D> for BranchAndBoundCoinSelection {
|
||||
fn coin_select(
|
||||
&self,
|
||||
_database: &D,
|
||||
required_utxos: Vec<(UTXO, usize)>,
|
||||
optional_utxos: Vec<(UTXO, usize)>,
|
||||
required_utxos: Vec<WeightedUtxo>,
|
||||
optional_utxos: Vec<WeightedUtxo>,
|
||||
fee_rate: FeeRate,
|
||||
amount_needed: u64,
|
||||
fee_amount: f32,
|
||||
@@ -300,7 +299,7 @@ impl<D: Database> CoinSelectionAlgorithm<D> for BranchAndBoundCoinSelection {
|
||||
// Mapping every (UTXO, usize) to an output group
|
||||
let required_utxos: Vec<OutputGroup> = required_utxos
|
||||
.into_iter()
|
||||
.map(|u| OutputGroup::new(u.0, u.1, fee_rate))
|
||||
.map(|u| OutputGroup::new(u, fee_rate))
|
||||
.collect();
|
||||
|
||||
// Mapping every (UTXO, usize) to an output group.
|
||||
@@ -308,7 +307,7 @@ impl<D: Database> CoinSelectionAlgorithm<D> for BranchAndBoundCoinSelection {
|
||||
// adding them is more than their value
|
||||
let optional_utxos: Vec<OutputGroup> = optional_utxos
|
||||
.into_iter()
|
||||
.map(|u| OutputGroup::new(u.0, u.1, fee_rate))
|
||||
.map(|u| OutputGroup::new(u, fee_rate))
|
||||
.filter(|u| u.effective_value > 0)
|
||||
.collect();
|
||||
|
||||
@@ -507,14 +506,12 @@ impl BranchAndBoundCoinSelection {
|
||||
fee_amount += selected_utxos.iter().map(|u| u.fee).sum::<f32>();
|
||||
let selected = selected_utxos
|
||||
.into_iter()
|
||||
.map(|u| u.utxo)
|
||||
.map(|u| u.weighted_utxo.utxo)
|
||||
.collect::<Vec<_>>();
|
||||
let selected_amount = selected.iter().map(|u| u.txout.value).sum();
|
||||
|
||||
CoinSelectionResult {
|
||||
selected,
|
||||
fee_amount,
|
||||
selected_amount,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -535,10 +532,11 @@ mod test {
|
||||
|
||||
const P2WPKH_WITNESS_SIZE: usize = 73 + 33 + 2;
|
||||
|
||||
fn get_test_utxos() -> Vec<(UTXO, usize)> {
|
||||
fn get_test_utxos() -> Vec<WeightedUtxo> {
|
||||
vec![
|
||||
(
|
||||
UTXO {
|
||||
WeightedUtxo {
|
||||
satisfaction_weight: P2WPKH_WITNESS_SIZE,
|
||||
utxo: Utxo::Local(LocalUtxo {
|
||||
outpoint: OutPoint::from_str(
|
||||
"ebd9813ecebc57ff8f30797de7c205e3c7498ca950ea4341ee51a685ff2fa30a:0",
|
||||
)
|
||||
@@ -548,11 +546,11 @@ mod test {
|
||||
script_pubkey: Script::new(),
|
||||
},
|
||||
keychain: KeychainKind::External,
|
||||
},
|
||||
P2WPKH_WITNESS_SIZE,
|
||||
),
|
||||
(
|
||||
UTXO {
|
||||
}),
|
||||
},
|
||||
WeightedUtxo {
|
||||
satisfaction_weight: P2WPKH_WITNESS_SIZE,
|
||||
utxo: Utxo::Local(LocalUtxo {
|
||||
outpoint: OutPoint::from_str(
|
||||
"65d92ddff6b6dc72c89624a6491997714b90f6004f928d875bc0fd53f264fa85:0",
|
||||
)
|
||||
@@ -562,17 +560,17 @@ mod test {
|
||||
script_pubkey: Script::new(),
|
||||
},
|
||||
keychain: KeychainKind::Internal,
|
||||
},
|
||||
P2WPKH_WITNESS_SIZE,
|
||||
),
|
||||
}),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn generate_random_utxos(rng: &mut StdRng, utxos_number: usize) -> Vec<(UTXO, usize)> {
|
||||
fn generate_random_utxos(rng: &mut StdRng, utxos_number: usize) -> Vec<WeightedUtxo> {
|
||||
let mut res = Vec::new();
|
||||
for _ in 0..utxos_number {
|
||||
res.push((
|
||||
UTXO {
|
||||
res.push(WeightedUtxo {
|
||||
satisfaction_weight: P2WPKH_WITNESS_SIZE,
|
||||
utxo: Utxo::Local(LocalUtxo {
|
||||
outpoint: OutPoint::from_str(
|
||||
"ebd9813ecebc57ff8f30797de7c205e3c7498ca950ea4341ee51a685ff2fa30a:0",
|
||||
)
|
||||
@@ -582,16 +580,16 @@ mod test {
|
||||
script_pubkey: Script::new(),
|
||||
},
|
||||
keychain: KeychainKind::External,
|
||||
},
|
||||
P2WPKH_WITNESS_SIZE,
|
||||
));
|
||||
}),
|
||||
});
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn generate_same_value_utxos(utxos_value: u64, utxos_number: usize) -> Vec<(UTXO, usize)> {
|
||||
let utxo = (
|
||||
UTXO {
|
||||
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",
|
||||
)
|
||||
@@ -601,18 +599,18 @@ mod test {
|
||||
script_pubkey: Script::new(),
|
||||
},
|
||||
keychain: KeychainKind::External,
|
||||
},
|
||||
P2WPKH_WITNESS_SIZE,
|
||||
);
|
||||
}),
|
||||
};
|
||||
vec![utxo; utxos_number]
|
||||
}
|
||||
|
||||
fn sum_random_utxos(mut rng: &mut StdRng, utxos: &mut Vec<(UTXO, usize)>) -> u64 {
|
||||
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()
|
||||
.fold(0, |acc, x| acc + x.0.txout.value)
|
||||
.map(|u| u.utxo.txout().value)
|
||||
.sum()
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -632,7 +630,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.selected.len(), 2);
|
||||
assert_eq!(result.selected_amount, 300_000);
|
||||
assert_eq!(result.selected_amount(), 300_000);
|
||||
assert_eq!(result.fee_amount, 186.0);
|
||||
}
|
||||
|
||||
@@ -653,7 +651,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.selected.len(), 2);
|
||||
assert_eq!(result.selected_amount, 300_000);
|
||||
assert_eq!(result.selected_amount(), 300_000);
|
||||
assert_eq!(result.fee_amount, 186.0);
|
||||
}
|
||||
|
||||
@@ -674,7 +672,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.selected.len(), 1);
|
||||
assert_eq!(result.selected_amount, 200_000);
|
||||
assert_eq!(result.selected_amount(), 200_000);
|
||||
assert_eq!(result.fee_amount, 118.0);
|
||||
}
|
||||
|
||||
@@ -734,7 +732,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.selected.len(), 3);
|
||||
assert_eq!(result.selected_amount, 300_000);
|
||||
assert_eq!(result.selected_amount(), 300_000);
|
||||
assert_eq!(result.fee_amount, 254.0);
|
||||
}
|
||||
|
||||
@@ -755,7 +753,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.selected.len(), 2);
|
||||
assert_eq!(result.selected_amount, 300_000);
|
||||
assert_eq!(result.selected_amount(), 300_000);
|
||||
assert_eq!(result.fee_amount, 186.0);
|
||||
}
|
||||
|
||||
@@ -804,7 +802,7 @@ mod test {
|
||||
.coin_select(
|
||||
&database,
|
||||
vec![],
|
||||
utxos.clone(),
|
||||
utxos,
|
||||
FeeRate::from_sat_per_vb(1.0),
|
||||
99932, // first utxo's effective value
|
||||
0.0,
|
||||
@@ -812,7 +810,7 @@ mod test {
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.selected.len(), 1);
|
||||
assert_eq!(result.selected_amount, 100_000);
|
||||
assert_eq!(result.selected_amount(), 100_000);
|
||||
let input_size = (TXIN_BASE_WEIGHT as f32) / 4.0 + P2WPKH_WITNESS_SIZE as f32 / 4.0;
|
||||
let epsilon = 0.5;
|
||||
assert!((1.0 - (result.fee_amount / input_size)).abs() < epsilon);
|
||||
@@ -837,7 +835,7 @@ mod test {
|
||||
0.0,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(result.selected_amount, target_amount);
|
||||
assert_eq!(result.selected_amount(), target_amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,7 +845,7 @@ mod test {
|
||||
let fee_rate = FeeRate::from_sat_per_vb(10.0);
|
||||
let utxos: Vec<OutputGroup> = get_test_utxos()
|
||||
.into_iter()
|
||||
.map(|u| OutputGroup::new(u.0, u.1, fee_rate))
|
||||
.map(|u| OutputGroup::new(u, fee_rate))
|
||||
.collect();
|
||||
|
||||
let curr_available_value = utxos
|
||||
@@ -875,7 +873,7 @@ mod test {
|
||||
let fee_rate = FeeRate::from_sat_per_vb(10.0);
|
||||
let utxos: Vec<OutputGroup> = generate_same_value_utxos(100_000, 100_000)
|
||||
.into_iter()
|
||||
.map(|u| OutputGroup::new(u.0, u.1, fee_rate))
|
||||
.map(|u| OutputGroup::new(u, fee_rate))
|
||||
.collect();
|
||||
|
||||
let curr_available_value = utxos
|
||||
@@ -908,7 +906,7 @@ mod test {
|
||||
|
||||
let utxos: Vec<_> = generate_same_value_utxos(50_000, 10)
|
||||
.into_iter()
|
||||
.map(|u| OutputGroup::new(u.0, u.1, fee_rate))
|
||||
.map(|u| OutputGroup::new(u, fee_rate))
|
||||
.collect();
|
||||
|
||||
let curr_value = 0;
|
||||
@@ -933,7 +931,7 @@ mod test {
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(result.fee_amount, 186.0);
|
||||
assert_eq!(result.selected_amount, 100_000);
|
||||
assert_eq!(result.selected_amount(), 100_000);
|
||||
}
|
||||
|
||||
// TODO: bnb() function should be optimized, and this test should be done with more utxos
|
||||
@@ -946,7 +944,7 @@ mod test {
|
||||
for _ in 0..200 {
|
||||
let optional_utxos: Vec<_> = generate_random_utxos(&mut rng, 40)
|
||||
.into_iter()
|
||||
.map(|u| OutputGroup::new(u.0, u.1, fee_rate))
|
||||
.map(|u| OutputGroup::new(u, fee_rate))
|
||||
.collect();
|
||||
|
||||
let curr_value = 0;
|
||||
@@ -969,7 +967,7 @@ mod test {
|
||||
0.0,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(result.selected_amount, target_amount);
|
||||
assert_eq!(result.selected_amount(), target_amount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -983,7 +981,7 @@ mod test {
|
||||
let fee_rate = FeeRate::from_sat_per_vb(1.0);
|
||||
let utxos: Vec<OutputGroup> = utxos
|
||||
.into_iter()
|
||||
.map(|u| OutputGroup::new(u.0, u.1, fee_rate))
|
||||
.map(|u| OutputGroup::new(u, fee_rate))
|
||||
.collect();
|
||||
|
||||
let result = BranchAndBoundCoinSelection::default().single_random_draw(
|
||||
@@ -994,7 +992,7 @@ mod test {
|
||||
50.0,
|
||||
);
|
||||
|
||||
assert!(result.selected_amount > target_amount);
|
||||
assert!(result.selected_amount() > target_amount);
|
||||
assert_eq!(
|
||||
result.fee_amount,
|
||||
50.0 + result.selected.len() as f32 * 68.0
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -199,13 +186,13 @@ where
|
||||
///
|
||||
/// Note that this methods only operate on the internal database, which first needs to be
|
||||
/// [`Wallet::sync`] manually.
|
||||
pub fn list_unspent(&self) -> Result<Vec<UTXO>, Error> {
|
||||
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<UTXO>, Error> {
|
||||
pub fn get_utxo(&self, outpoint: OutPoint) -> Result<Option<LocalUtxo>, Error> {
|
||||
self.database.borrow().get_utxo(&outpoint)
|
||||
}
|
||||
|
||||
@@ -513,11 +500,7 @@ where
|
||||
params.bumping_fee.is_some(), // we mandate confirmed transactions if we're bumping the fee
|
||||
)?;
|
||||
|
||||
let coin_selection::CoinSelectionResult {
|
||||
selected,
|
||||
selected_amount,
|
||||
mut fee_amount,
|
||||
} = coin_selection.coin_select(
|
||||
let coin_selection = coin_selection.coin_select(
|
||||
self.database.borrow().deref(),
|
||||
required_utxos,
|
||||
optional_utxos,
|
||||
@@ -525,10 +508,13 @@ where
|
||||
outgoing,
|
||||
fee_amount,
|
||||
)?;
|
||||
tx.input = selected
|
||||
let mut fee_amount = coin_selection.fee_amount;
|
||||
|
||||
tx.input = coin_selection
|
||||
.selected
|
||||
.iter()
|
||||
.map(|u| bitcoin::TxIn {
|
||||
previous_output: u.outpoint,
|
||||
previous_output: u.outpoint(),
|
||||
script_sig: Script::default(),
|
||||
sequence: n_sequence,
|
||||
witness: vec![],
|
||||
@@ -550,9 +536,8 @@ where
|
||||
Some(change_output)
|
||||
}
|
||||
};
|
||||
|
||||
let mut fee_amount = fee_amount.ceil() as u64;
|
||||
let change_val = (selected_amount - outgoing).saturating_sub(fee_amount);
|
||||
let change_val = (coin_selection.selected_amount() - outgoing).saturating_sub(fee_amount);
|
||||
|
||||
match change_output {
|
||||
None if change_val.is_dust() => {
|
||||
@@ -588,14 +573,15 @@ where
|
||||
params.ordering.sort_tx(&mut tx);
|
||||
|
||||
let txid = tx.txid();
|
||||
let psbt = self.complete_transaction(tx, selected, params)?;
|
||||
let sent = coin_selection.local_selected_amount();
|
||||
let psbt = self.complete_transaction(tx, coin_selection.selected, params)?;
|
||||
|
||||
let transaction_details = TransactionDetails {
|
||||
transaction: None,
|
||||
txid,
|
||||
timestamp: time::get_timestamp(),
|
||||
received,
|
||||
sent: selected_amount,
|
||||
sent,
|
||||
fees: fee_amount,
|
||||
height: None,
|
||||
};
|
||||
@@ -699,13 +685,16 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let utxo = UTXO {
|
||||
let utxo = LocalUtxo {
|
||||
outpoint: txin.previous_output,
|
||||
txout,
|
||||
keychain,
|
||||
};
|
||||
|
||||
Ok((utxo, weight))
|
||||
Ok(WeightedUtxo {
|
||||
satisfaction_weight: weight,
|
||||
utxo: Utxo::Local(utxo),
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
@@ -1016,7 +1005,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_available_utxos(&self) -> Result<Vec<(UTXO, usize)>, Error> {
|
||||
fn get_available_utxos(&self) -> Result<Vec<(LocalUtxo, usize)>, Error> {
|
||||
Ok(self
|
||||
.list_unspent()?
|
||||
.into_iter()
|
||||
@@ -1039,18 +1028,18 @@ where
|
||||
&self,
|
||||
change_policy: tx_builder::ChangeSpendPolicy,
|
||||
unspendable: &HashSet<OutPoint>,
|
||||
manually_selected: Vec<(UTXO, usize)>,
|
||||
manually_selected: Vec<WeightedUtxo>,
|
||||
must_use_all_available: bool,
|
||||
manual_only: bool,
|
||||
must_only_use_confirmed_tx: bool,
|
||||
) -> Result<(Vec<(UTXO, usize)>, Vec<(UTXO, usize)>), Error> {
|
||||
) -> 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()
|
||||
.find(|manually_selected| manually_selected.0.outpoint == may_spend.0.outpoint)
|
||||
.find(|manually_selected| manually_selected.utxo.outpoint() == may_spend.0.outpoint)
|
||||
.is_none()
|
||||
});
|
||||
let mut must_spend = manually_selected;
|
||||
@@ -1088,6 +1077,14 @@ where
|
||||
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);
|
||||
}
|
||||
@@ -1098,7 +1095,7 @@ where
|
||||
fn complete_transaction(
|
||||
&self,
|
||||
tx: Transaction,
|
||||
selected: Vec<UTXO>,
|
||||
selected: Vec<Utxo>,
|
||||
params: TxParams,
|
||||
) -> Result<PSBT, Error> {
|
||||
use bitcoin::util::psbt::serialize::Serialize;
|
||||
@@ -1131,9 +1128,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
let lookup_output = selected
|
||||
let mut lookup_output = selected
|
||||
.into_iter()
|
||||
.map(|utxo| (utxo.outpoint, utxo))
|
||||
.map(|utxo| (utxo.outpoint(), utxo))
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
// add metadata for the inputs
|
||||
@@ -1142,7 +1139,7 @@ where
|
||||
.iter_mut()
|
||||
.zip(psbt.global.unsigned_tx.input.iter())
|
||||
{
|
||||
let utxo = match lookup_output.get(&input.previous_output) {
|
||||
let utxo = match lookup_output.remove(&input.previous_output) {
|
||||
Some(utxo) => utxo,
|
||||
None => continue,
|
||||
};
|
||||
@@ -1153,32 +1150,50 @@ where
|
||||
psbt_input.sighash_type = Some(sighash_type);
|
||||
}
|
||||
|
||||
// Try to find the prev_script in our db to figure out if this is internal or external,
|
||||
// and the derivation index
|
||||
let (keychain, child) = match self
|
||||
.database
|
||||
.borrow()
|
||||
.get_path_from_script_pubkey(&utxo.txout.script_pubkey)?
|
||||
{
|
||||
Some(x) => x,
|
||||
None => continue,
|
||||
};
|
||||
match utxo {
|
||||
Utxo::Local(utxo) => {
|
||||
// Try to find the prev_script in our db to figure out if this is internal or external,
|
||||
// and the derivation index
|
||||
let (keychain, child) = match self
|
||||
.database
|
||||
.borrow()
|
||||
.get_path_from_script_pubkey(&utxo.txout.script_pubkey)?
|
||||
{
|
||||
Some(x) => x,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let (desc, _) = self._get_descriptor_for_keychain(keychain);
|
||||
let derived_descriptor = desc.as_derived(child, &self.secp);
|
||||
psbt_input.bip32_derivation = derived_descriptor.get_hd_keypaths(&self.secp)?;
|
||||
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();
|
||||
psbt_input.redeem_script = derived_descriptor.psbt_redeem_script();
|
||||
psbt_input.witness_script = derived_descriptor.psbt_witness_script();
|
||||
|
||||
let prev_output = input.previous_output;
|
||||
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());
|
||||
let prev_output = input.previous_output;
|
||||
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() || params.force_non_witness_utxo {
|
||||
psbt_input.non_witness_utxo = Some(prev_tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
if !desc.is_witness() || params.force_non_witness_utxo {
|
||||
psbt_input.non_witness_utxo = Some(prev_tx);
|
||||
Utxo::Foreign {
|
||||
psbt_input: foreign_psbt_input,
|
||||
outpoint,
|
||||
} => {
|
||||
if params.force_non_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1348,7 +1363,7 @@ where
|
||||
mod test {
|
||||
use std::str::FromStr;
|
||||
|
||||
use bitcoin::Network;
|
||||
use bitcoin::{util::psbt, Network};
|
||||
|
||||
use crate::database::memory::MemoryDatabase;
|
||||
use crate::database::Database;
|
||||
@@ -1942,7 +1957,7 @@ mod test {
|
||||
|
||||
assert_eq!(psbt.inputs[0].bip32_derivation.len(), 1);
|
||||
assert_eq!(
|
||||
psbt.inputs[0].bip32_derivation.values().nth(0).unwrap(),
|
||||
psbt.inputs[0].bip32_derivation.values().next().unwrap(),
|
||||
&(
|
||||
Fingerprint::from_str("d34db33f").unwrap(),
|
||||
DerivationPath::from_str("m/44'/0'/0'/0/0").unwrap()
|
||||
@@ -1968,7 +1983,7 @@ mod test {
|
||||
|
||||
assert_eq!(psbt.outputs[0].bip32_derivation.len(), 1);
|
||||
assert_eq!(
|
||||
psbt.outputs[0].bip32_derivation.values().nth(0).unwrap(),
|
||||
psbt.outputs[0].bip32_derivation.values().next().unwrap(),
|
||||
&(
|
||||
Fingerprint::from_str("d34db33f").unwrap(),
|
||||
DerivationPath::from_str("m/44'/0'/0'/0/5").unwrap()
|
||||
@@ -2237,6 +2252,187 @@ mod test {
|
||||
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)
|
||||
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
|
||||
.unwrap();
|
||||
let (psbt, details) = builder.finish().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
details.sent - details.received,
|
||||
10_000 + details.fees,
|
||||
"we should have only net spent ~10_000"
|
||||
);
|
||||
|
||||
assert!(
|
||||
psbt.global
|
||||
.unsigned_tx
|
||||
.input
|
||||
.iter()
|
||||
.find(|input| input.previous_output == utxo.outpoint)
|
||||
.is_some(),
|
||||
"foreign_utxo should be in there"
|
||||
);
|
||||
|
||||
let (psbt, finished) = wallet1.sign(psbt, None).unwrap();
|
||||
|
||||
assert!(
|
||||
!finished,
|
||||
"only one of the inputs should have been signed so far"
|
||||
);
|
||||
|
||||
let (_, finished) = wallet2.sign(psbt, None).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_force_non_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)
|
||||
.force_non_witness_utxo();
|
||||
|
||||
{
|
||||
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 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 with force_non_witness_utxo"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(
|
||||
expected = "MissingKeyOrigin(\"tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3\")"
|
||||
@@ -3120,6 +3316,23 @@ mod test {
|
||||
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_new_address().unwrap();
|
||||
let mut builder = wallet.build_tx();
|
||||
builder
|
||||
.set_single_recipient(addr.script_pubkey())
|
||||
.drain_wallet();
|
||||
let (psbt, _) = builder.finish().unwrap();
|
||||
|
||||
let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap();
|
||||
assert_eq!(finalized, true);
|
||||
|
||||
let extracted = signed_psbt.extract_tx();
|
||||
assert_eq!(extracted.input[0].witness.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sign_single_xprv_bip44_path() {
|
||||
let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/44'/0'/0'/0/*)");
|
||||
@@ -3220,15 +3433,18 @@ mod test {
|
||||
let (mut psbt, _) = builder.finish().unwrap();
|
||||
|
||||
// add another input to the psbt that is at least passable.
|
||||
let mut dud_input = bitcoin::util::psbt::Input::default();
|
||||
dud_input.witness_utxo = Some(TxOut {
|
||||
value: 100_000,
|
||||
script_pubkey: miniscript::Descriptor::<bitcoin::PublicKey>::from_str(
|
||||
"wpkh(025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357)",
|
||||
)
|
||||
.unwrap()
|
||||
.script_pubkey(),
|
||||
});
|
||||
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 (psbt, is_final) = wallet.sign(psbt, None).unwrap();
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -105,7 +92,7 @@ use bitcoin::blockdata::opcodes;
|
||||
use bitcoin::blockdata::script::Builder as ScriptBuilder;
|
||||
use bitcoin::hashes::{hash160, Hash};
|
||||
use bitcoin::secp256k1::{Message, Secp256k1};
|
||||
use bitcoin::util::bip32::{ExtendedPrivKey, Fingerprint};
|
||||
use bitcoin::util::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey, Fingerprint};
|
||||
use bitcoin::util::{bip143, psbt};
|
||||
use bitcoin::{PrivateKey, Script, SigHash, SigHashType};
|
||||
|
||||
@@ -219,7 +206,7 @@ impl Signer for DescriptorXKey<ExtendedPrivKey> {
|
||||
return Err(SignerError::InputIndexOutOfRange);
|
||||
}
|
||||
|
||||
let (public_key, deriv_path) = match psbt.inputs[input_index]
|
||||
let (public_key, full_path) = match psbt.inputs[input_index]
|
||||
.bip32_derivation
|
||||
.iter()
|
||||
.filter_map(|(pk, &(fingerprint, ref path))| {
|
||||
@@ -235,7 +222,17 @@ impl Signer for DescriptorXKey<ExtendedPrivKey> {
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
let derived_key = self.xkey.derive_priv(&secp, &deriv_path).unwrap();
|
||||
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 {
|
||||
@@ -569,6 +566,11 @@ mod signers_container_tests {
|
||||
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.
|
||||
@@ -593,73 +595,58 @@ mod signers_container_tests {
|
||||
#[test]
|
||||
fn signers_sorted_by_ordering() {
|
||||
let mut signers = SignersContainer::new();
|
||||
let signer1 = Arc::new(DummySigner);
|
||||
let signer2 = Arc::new(DummySigner);
|
||||
let signer3 = Arc::new(DummySigner);
|
||||
let signer1 = Arc::new(DummySigner { number: 1 });
|
||||
let signer2 = Arc::new(DummySigner { number: 2 });
|
||||
let signer3 = Arc::new(DummySigner { number: 3 });
|
||||
|
||||
signers.add_external(
|
||||
SignerId::Fingerprint(b"cafe"[..].into()),
|
||||
SignerOrdering(1),
|
||||
signer1.clone(),
|
||||
);
|
||||
signers.add_external(
|
||||
SignerId::Fingerprint(b"babe"[..].into()),
|
||||
SignerOrdering(2),
|
||||
signer2.clone(),
|
||||
);
|
||||
signers.add_external(
|
||||
SignerId::Fingerprint(b"feed"[..].into()),
|
||||
SignerOrdering(3),
|
||||
signer3.clone(),
|
||||
);
|
||||
// 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_eq!(Arc::as_ptr(signers[0]), Arc::as_ptr(&signer1));
|
||||
assert_eq!(Arc::as_ptr(signers[1]), Arc::as_ptr(&signer2));
|
||||
assert_eq!(Arc::as_ptr(signers[2]), Arc::as_ptr(&signer3));
|
||||
|
||||
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<dyn Signer> = Arc::new(DummySigner);
|
||||
let signer2: Arc<dyn Signer> = Arc::new(DummySigner);
|
||||
let signer3: Arc<dyn Signer> = Arc::new(DummySigner);
|
||||
let signer4: Arc<dyn Signer> = Arc::new(DummySigner);
|
||||
let 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::Fingerprint(b"cafe"[..].into());
|
||||
let id2 = SignerId::Fingerprint(b"babe"[..].into());
|
||||
let id3 = SignerId::Fingerprint(b"feed"[..].into());
|
||||
let id_nonexistent = SignerId::Fingerprint(b"fefe"[..].into());
|
||||
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 Arc::as_ptr(&signer1) == Arc::as_ptr(signer))
|
||||
);
|
||||
assert!(
|
||||
matches!(signers.find(id2), Some(signer) if Arc::as_ptr(&signer2) == Arc::as_ptr(signer))
|
||||
);
|
||||
assert!(
|
||||
matches!(signers.find(id3.clone()), Some(signer) if Arc::as_ptr(&signer3) == Arc::as_ptr(signer))
|
||||
);
|
||||
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 Arc::as_ptr(&signer4) == Arc::as_ptr(signer))
|
||||
);
|
||||
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)]
|
||||
struct DummySigner;
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct DummySigner {
|
||||
number: u64,
|
||||
}
|
||||
|
||||
impl Signer for DummySigner {
|
||||
fn sign(
|
||||
&self,
|
||||
@@ -671,7 +658,7 @@ mod signers_container_tests {
|
||||
}
|
||||
|
||||
fn id(&self, _secp: &SecpCtx) -> SignerId {
|
||||
SignerId::Dummy(42)
|
||||
SignerId::Dummy(self.number)
|
||||
}
|
||||
|
||||
fn sign_whole_tx(&self) -> bool {
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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
|
||||
//!
|
||||
@@ -54,15 +41,15 @@ use std::collections::HashSet;
|
||||
use std::default::Default;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use bitcoin::util::psbt::PartiallySignedTransaction as PSBT;
|
||||
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, Wallet};
|
||||
use crate::{database::BatchDatabase, Error, Utxo, Wallet};
|
||||
use crate::{
|
||||
types::{FeeRate, KeychainKind, UTXO},
|
||||
types::{FeeRate, KeychainKind, LocalUtxo, WeightedUtxo},
|
||||
TransactionDetails,
|
||||
};
|
||||
/// Context in which the [`TxBuilder`] is valid
|
||||
@@ -129,7 +116,7 @@ impl TxBuilderContext for BumpFee {}
|
||||
/// [`build_fee_bump`]: Wallet::build_fee_bump
|
||||
/// [`finish`]: Self::finish
|
||||
/// [`coin_selection`]: Self::coin_selection
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct TxBuilder<'a, B, D, Cs, Ctx> {
|
||||
pub(crate) wallet: &'a Wallet<B, D>,
|
||||
// params and coin_selection are Options not becasue they are optionally set (they are always
|
||||
@@ -150,7 +137,7 @@ pub(crate) struct TxParams {
|
||||
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<(UTXO, usize)>,
|
||||
pub(crate) utxos: Vec<WeightedUtxo>,
|
||||
pub(crate) unspendable: HashSet<OutPoint>,
|
||||
pub(crate) manually_selected_only: bool,
|
||||
pub(crate) sighash: Option<SigHashType>,
|
||||
@@ -183,6 +170,17 @@ impl std::default::Default for FeePolicy {
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
@@ -286,7 +284,10 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderConte
|
||||
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((utxo, satisfaction_weight));
|
||||
self.params.utxos.push(WeightedUtxo {
|
||||
satisfaction_weight,
|
||||
utxo: Utxo::Local(utxo),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
@@ -300,6 +301,84 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderConte
|
||||
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 if you set [`force_non_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.
|
||||
///
|
||||
/// [`force_non_witness_utxo`]: Self::force_non_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
|
||||
@@ -618,7 +697,7 @@ impl Default for ChangeSpendPolicy {
|
||||
}
|
||||
|
||||
impl ChangeSpendPolicy {
|
||||
pub(crate) fn is_satisfied_by(&self, utxo: &UTXO) -> bool {
|
||||
pub(crate) fn is_satisfied_by(&self, utxo: &LocalUtxo) -> bool {
|
||||
match self {
|
||||
ChangeSpendPolicy::ChangeAllowed => true,
|
||||
ChangeSpendPolicy::OnlyChange => utxo.keychain == KeychainKind::Internal,
|
||||
@@ -629,12 +708,12 @@ impl ChangeSpendPolicy {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
const ORDERING_TEST_TX: &'static str = "0200000003c26f3eb7932f7acddc5ddd26602b77e7516079b03090a16e2c2f54\
|
||||
85d1fd600f0100000000ffffffffc26f3eb7932f7acddc5ddd26602b77e75160\
|
||||
79b03090a16e2c2f5485d1fd600f0000000000ffffffff571fb3e02278217852\
|
||||
dd5d299947e2b7354a639adc32ec1fa7b82cfb5dec530e0500000000ffffffff\
|
||||
03e80300000000000002aaeee80300000000000001aa200300000000000001ff\
|
||||
00000000";
|
||||
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())
|
||||
@@ -678,7 +757,7 @@ mod test {
|
||||
use std::str::FromStr;
|
||||
|
||||
let original_tx = ordering_test_tx!();
|
||||
let mut tx = original_tx.clone();
|
||||
let mut tx = original_tx;
|
||||
|
||||
TxOrdering::BIP69Lexicographic.sort_tx(&mut tx);
|
||||
|
||||
@@ -709,9 +788,9 @@ mod test {
|
||||
assert_eq!(tx.output[2].script_pubkey, From::from(vec![0xAA, 0xEE]));
|
||||
}
|
||||
|
||||
fn get_test_utxos() -> Vec<UTXO> {
|
||||
fn get_test_utxos() -> Vec<LocalUtxo> {
|
||||
vec![
|
||||
UTXO {
|
||||
LocalUtxo {
|
||||
outpoint: OutPoint {
|
||||
txid: Default::default(),
|
||||
vout: 0,
|
||||
@@ -719,7 +798,7 @@ mod test {
|
||||
txout: Default::default(),
|
||||
keychain: KeychainKind::External,
|
||||
},
|
||||
UTXO {
|
||||
LocalUtxo {
|
||||
outpoint: OutPoint {
|
||||
txid: Default::default(),
|
||||
vout: 1,
|
||||
@@ -736,9 +815,9 @@ mod test {
|
||||
let filtered = get_test_utxos()
|
||||
.into_iter()
|
||||
.filter(|u| change_spend_policy.is_satisfied_by(u))
|
||||
.collect::<Vec<_>>();
|
||||
.count();
|
||||
|
||||
assert_eq!(filtered.len(), 2);
|
||||
assert_eq!(filtered, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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};
|
||||
|
||||
@@ -156,8 +143,8 @@ pub struct ChunksIterator<I: Iterator> {
|
||||
size: usize,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "electrum", feature = "esplora"))]
|
||||
impl<I: Iterator> ChunksIterator<I> {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(iter: I, size: usize) -> Self {
|
||||
ChunksIterator { iter, size }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bdk-testutils-macros"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
authors = ["Alekos Filini <alekos.filini@gmail.com>"]
|
||||
edition = "2018"
|
||||
homepage = "https://bitcoindevkit.org"
|
||||
@@ -8,7 +8,7 @@ repository = "https://github.com/bitcoindevkit/bdk"
|
||||
documentation = "https://docs.rs/bdk-testutils-macros"
|
||||
description = "Supporting testing macros for `bdk`"
|
||||
keywords = ["bdk"]
|
||||
license = "MIT"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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.
|
||||
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bdk-testutils"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
authors = ["Alekos Filini <alekos.filini@gmail.com>"]
|
||||
edition = "2018"
|
||||
homepage = "https://bitcoindevkit.org"
|
||||
@@ -8,7 +8,7 @@ repository = "https://github.com/bitcoindevkit/bdk"
|
||||
documentation = "https://docs.rs/bdk-testutils"
|
||||
description = "Supporting testing utilities for `bdk`"
|
||||
keywords = ["bdk"]
|
||||
license = "MIT"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[lib]
|
||||
name = "testutils"
|
||||
|
||||
@@ -1,26 +1,13 @@
|
||||
// Magical Bitcoin Library
|
||||
// Written in 2020 by
|
||||
// Alekos Filini <alekos.filini@gmail.com>
|
||||
// Bitcoin Dev Kit
|
||||
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
|
||||
//
|
||||
// Copyright (c) 2020 Magical Bitcoin
|
||||
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
|
||||
//
|
||||
// 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.
|
||||
// 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.
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
@@ -53,20 +40,20 @@ pub use electrum_client::{Client as ElectrumClient, ElectrumApi};
|
||||
|
||||
// TODO: we currently only support env vars, we could also parse a toml file
|
||||
fn get_auth() -> Auth {
|
||||
match env::var("MAGICAL_RPC_AUTH").as_ref().map(String::as_ref) {
|
||||
match env::var("BDK_RPC_AUTH").as_ref().map(String::as_ref) {
|
||||
Ok("USER_PASS") => Auth::UserPass(
|
||||
env::var("MAGICAL_RPC_USER").unwrap(),
|
||||
env::var("MAGICAL_RPC_PASS").unwrap(),
|
||||
env::var("BDK_RPC_USER").unwrap(),
|
||||
env::var("BDK_RPC_PASS").unwrap(),
|
||||
),
|
||||
_ => Auth::CookieFile(PathBuf::from(
|
||||
env::var("MAGICAL_RPC_COOKIEFILE")
|
||||
.unwrap_or("/home/user/.bitcoin/regtest/.cookie".to_string()),
|
||||
env::var("BDK_RPC_COOKIEFILE")
|
||||
.unwrap_or_else(|_| "/home/user/.bitcoin/regtest/.cookie".to_string()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_electrum_url() -> String {
|
||||
env::var("MAGICAL_ELECTRUM_URL").unwrap_or("tcp://127.0.0.1:50001".to_string())
|
||||
env::var("BDK_ELECTRUM_URL").unwrap_or_else(|_| "tcp://127.0.0.1:50001".to_string())
|
||||
}
|
||||
|
||||
pub struct TestClient {
|
||||
@@ -311,8 +298,10 @@ where
|
||||
|
||||
impl TestClient {
|
||||
pub fn new() -> Self {
|
||||
let url = env::var("MAGICAL_RPC_URL").unwrap_or("127.0.0.1:18443".to_string());
|
||||
let client = RpcClient::new(format!("http://{}", url), get_auth()).unwrap();
|
||||
let url = env::var("BDK_RPC_URL").unwrap_or_else(|_| "127.0.0.1:18443".to_string());
|
||||
let wallet = env::var("BDK_RPC_WALLET").unwrap_or_else(|_| "bdk-test".to_string());
|
||||
let client =
|
||||
RpcClient::new(format!("http://{}/wallet/{}", url, wallet), get_auth()).unwrap();
|
||||
let electrum = ElectrumClient::new(&get_electrum_url()).unwrap();
|
||||
|
||||
TestClient { client, electrum }
|
||||
@@ -347,7 +336,7 @@ impl TestClient {
|
||||
|
||||
pub fn receive(&mut self, meta_tx: TestIncomingTx) -> Txid {
|
||||
assert!(
|
||||
meta_tx.output.len() > 0,
|
||||
!meta_tx.output.is_empty(),
|
||||
"can't create a transaction with no outputs"
|
||||
);
|
||||
|
||||
@@ -360,7 +349,7 @@ impl TestClient {
|
||||
}
|
||||
|
||||
if self.get_balance(None, None).unwrap() < Amount::from_sat(required_balance) {
|
||||
panic!("Insufficient funds in bitcoind. Plase generate a few blocks with: `bitcoin-cli generatetoaddress 10 {}`", self.get_new_address(None, None).unwrap());
|
||||
panic!("Insufficient funds in bitcoind. Please generate a few blocks with: `bitcoin-cli generatetoaddress 10 {}`", self.get_new_address(None, None).unwrap());
|
||||
}
|
||||
|
||||
// FIXME: core can't create a tx with two outputs to the same address
|
||||
|
||||
Reference in New Issue
Block a user