diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9005cff6..f8e9c971 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,7 +9,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions-rs/toolchain@v1 with: - toolchain: 1.70.0 + toolchain: 1.75.0 components: rustfmt, clippy override: true - name: rustfmt @@ -22,7 +22,7 @@ jobs: strategy: matrix: toolchain: - - 1.54 + - 1.63 - nightly os: - ubuntu-latest diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 412a5809..51767ece 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -66,7 +66,7 @@ query). ## Minimum Supported Rust Version -`lianad` should always compile and pass tests using **Rust 1.54**. The rationale behind this is +`lianad` should always compile and pass tests using **Rust 1.63**. The rationale behind this is support something reasonable, and preferably supported by all of: - [Guix](https://guix.gnu.org/) - Popular distributions' packages (especially Debian which is the most conservative) diff --git a/Cargo.lock b/Cargo.lock index 341f2d65..7d057c72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ "gimli", ] @@ -19,20 +19,27 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.7.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ - "getrandom", + "cfg-if", "once_cell", "version_check", + "zerocopy", ] [[package]] -name = "backtrace" -version = "0.3.67" +name = "allocator-api2" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "544a7f66f3407c6ed1285525418393891e0f31c2078a2d46aefb44ecef09b1b3" + +[[package]] +name = "backtrace" +version = "0.3.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ "addr2line", "cc", @@ -49,6 +56,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + [[package]] name = "bdk_coin_select" version = "0.1.1" @@ -57,9 +70,9 @@ checksum = "c0320167c3655e83f0415d52f39618902e449186ffc7dfb090f922f79675c316" [[package]] name = "bech32" -version = "0.9.1" +version = "0.10.0-beta" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" +checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" [[package]] name = "bip39" @@ -74,19 +87,29 @@ dependencies = [ [[package]] name = "bitcoin" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b36f4c848f6bd9ff208128f08751135846cc23ae57d66ab10a22efff1c675f3c" +checksum = "5973a027b341b462105675962214dfe3c938ad9afd395d84b28602608bdcec7b" dependencies = [ - "base64", + "base64 0.21.5", "bech32", - "bitcoin-private", - "bitcoin_hashes 0.12.0", + "bitcoin-internals", + "bitcoin_hashes 0.13.0", + "hex-conservative", "hex_lit", "secp256k1", "serde", ] +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" +dependencies = [ + "serde", +] + [[package]] name = "bitcoin-private" version = "0.1.0" @@ -106,6 +129,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d7066118b13d4b20b23645932dfb3a81ce7e29f95726c2036fa33cd7b092501" dependencies = [ "bitcoin-private", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", "serde", ] @@ -116,10 +149,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "cc" -version = "1.0.73" +name = "bitflags" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -138,20 +180,21 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04414300db88f70d74c5ff54e50f9e1d1737d9a5b90f53fcf2e95ca2a9ab554b" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", "windows-sys", ] [[package]] name = "fallible-iterator" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fallible-streaming-iterator" @@ -170,9 +213,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", @@ -187,22 +230,29 @@ checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ "ahash", + "allocator-api2", ] [[package]] name = "hashlink" -version = "0.7.0" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ "hashbrown", ] +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" + [[package]] name = "hex_lit" version = "0.1.1" @@ -211,17 +261,17 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jsonrpc" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34efde8d2422fb79ed56db1d3aea8fa5b583351d15a26770cdee2f88813dd702" +checksum = "a26d9104d516092f092d97448787505881fdb6518293b2d6500bf9c180c839dd" dependencies = [ - "base64", + "base64 0.13.1", "minreq", "serde", "serde_json", @@ -250,15 +300,26 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.147" +version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.1", + "libc", + "redox_syscall", +] [[package]] name = "libsqlite3-sys" -version = "0.24.2" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" dependencies = [ "cc", "pkg-config", @@ -267,44 +328,42 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miniscript" -version = "10.0.0" +version = "11.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eb102b66b2127a872dbcc73095b7b47aeb9d92f7b03c2b2298253ffc82c7594" +checksum = "86a23dd3ad145a980e231185d114399f25a0a307d2cd918010ddda6334323df9" dependencies = [ + "bech32", "bitcoin", - "bitcoin-private", + "bitcoin-internals", "serde", ] [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "minreq" -version = "2.8.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3de406eeb24aba36ed3829532fa01649129677186b44a49debec0ec574ca7da7" +checksum = "cb3371dfc7b772c540da1380123674a8e20583aca99907087d990ca58cf44203" dependencies = [ "log", "serde", @@ -313,39 +372,45 @@ dependencies = [ [[package]] name = "object" -version = "0.30.4" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.13.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "pkg-config" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "proc-macro2" -version = "1.0.64" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -361,65 +426,64 @@ dependencies = [ [[package]] name = "rdrand" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e233b642160555c1aa1ff7a78443c6139342f411b6fa6602af2ebbfee9e166bb" +checksum = "d92195228612ac8eed47adbc2ed0f04e513a4ccb98175b6f2bd04d963b533655" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", - "redox_syscall", + "libredox", "thiserror", ] [[package]] name = "rusqlite" -version = "0.27.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85127183a999f7db96d1a976a309eebbfb6ea3b0b400ddd8340190129de6eb7a" +checksum = "a78046161564f5e7cd9008aff3b2990b3850dc8e0349119b98e8f251e099f24d" dependencies = [ - "bitflags", + "bitflags 2.4.1", "fallible-iterator", "fallible-streaming-iterator", "hashlink", "libsqlite3-sys", - "memchr", "smallvec", ] [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "secp256k1" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" dependencies = [ "bitcoin_hashes 0.12.0", "secp256k1-sys", @@ -428,27 +492,27 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.8.1" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "4dd97a086ec737e30053fd5c46f097465d25bb81dd3608825f65298c4c98be83" dependencies = [ "cc", ] [[package]] name = "serde" -version = "1.0.147" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" dependencies = [ "proc-macro2", "quote", @@ -457,9 +521,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "6fbd975230bada99c8bb618e0c365c2eefa219158d5c6c29610fd09ff1833257" dependencies = [ "itoa", "ryu", @@ -468,15 +532,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "syn" -version = "1.0.102" +version = "2.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1" +checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" dependencies = [ "proc-macro2", "quote", @@ -485,18 +549,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", @@ -529,9 +593,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.2" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" @@ -562,18 +626,18 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -586,42 +650,62 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index 693b8b79..21c21949 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ nonblocking_shutdown = [] [dependencies] # For managing transactions (it re-exports the bitcoin crate) -miniscript = { version = "10.0", features = ["serde", "compiler", "base64"] } +miniscript = { version = "11.0", features = ["serde", "compiler", "base64"] } # Coin selection algorithms for spend transaction creation. bdk_coin_select = { version = "0.1.0" } @@ -50,10 +50,10 @@ backtrace = "0.3" # Pinned to this version because they keep breaking their MSRV in point releases... # FIXME: this is unfortunate, we don't receive the updates (sometimes critical) from SQLite. -rusqlite = { version = "0.27", features = ["bundled", "unlock_notify"] } +rusqlite = { version = "0.30", features = ["bundled", "unlock_notify"] } # To talk to bitcoind -jsonrpc = { version = "0.16", features = ["minreq_http"], default-features = false } +jsonrpc = { version = "0.17", features = ["minreq_http"], default-features = false } # Used for daemonization libc = { version = "0.2", optional = true } diff --git a/src/bitcoin/d/mod.rs b/src/bitcoin/d/mod.rs index 7aa3bc7c..a1b1317c 100644 --- a/src/bitcoin/d/mod.rs +++ b/src/bitcoin/d/mod.rs @@ -220,11 +220,12 @@ pub struct BitcoinD { macro_rules! params { ($($param:expr),* $(,)?) => { - [ + // FIXME: is there a way to avoid the allocation of an unnecessary Box? + Some(&*arg(Json::Array(vec![ $( - arg($param), + $param, )* - ] + ]))) }; } @@ -319,7 +320,7 @@ impl BitcoinD { } fn check_client(&self, client: &Client) -> Result<(), BitcoindError> { - if let Err(e) = self.make_request(client, "echo", &[]) { + if let Err(e) = self.make_request(client, "echo", None) { if e.is_warming_up() { log::info!("bitcoind is warming up. Retrying connection sanity check in 1 second."); thread::sleep(Duration::from_secs(1)); @@ -395,7 +396,7 @@ impl BitcoinD { &self, client: &Client, method: &str, - params: &[Box], + params: Option<&serde_json::value::RawValue>, retry: bool, ) -> Result { let req = client.build_request(method, params); @@ -410,7 +411,7 @@ impl BitcoinD { &self, client: &Client, method: &str, - params: &[Box], + params: Option<&serde_json::value::RawValue>, ) -> Result { self.make_request_inner(client, method, params, true) } @@ -420,7 +421,7 @@ impl BitcoinD { fn make_noreply_request( &self, method: &str, - params: &[Box], + params: Option<&serde_json::value::RawValue>, ) -> Result<(), BitcoindError> { match self.make_request_inner(&self.sendonly_client, method, params, false) { Ok(_) => Ok(()), @@ -438,12 +439,16 @@ impl BitcoinD { fn make_fallible_node_request( &self, method: &str, - params: &[Box], + params: Option<&serde_json::value::RawValue>, ) -> Result { self.make_request(&self.node_client, method, params) } - fn make_node_request(&self, method: &str, params: &[Box]) -> Json { + fn make_node_request( + &self, + method: &str, + params: Option<&serde_json::value::RawValue>, + ) -> Json { self.make_request(&self.node_client, method, params) .expect("We must not fail to make a request for more than a minute") } @@ -451,7 +456,7 @@ impl BitcoinD { fn make_wallet_request( &self, method: &str, - params: &[Box], + params: Option<&serde_json::value::RawValue>, ) -> Json { self.make_request(&self.watchonly_client, method, params) .expect("We must not fail to make a request for more than a minute") @@ -460,20 +465,20 @@ impl BitcoinD { fn make_faillible_wallet_request( &self, method: &str, - params: &[Box], + params: Option<&serde_json::value::RawValue>, ) -> Result { self.make_request(&self.watchonly_client, method, params) } fn get_bitcoind_version(&self) -> u64 { - self.make_node_request("getnetworkinfo", &[]) + self.make_node_request("getnetworkinfo", None) .get("version") .and_then(Json::as_u64) .expect("Missing or invalid 'version' in 'getnetworkinfo' result?") } fn get_network_bip70(&self) -> String { - self.make_node_request("getblockchaininfo", &[]) + self.make_node_request("getblockchaininfo", None) .get("chain") .and_then(Json::as_str) .expect("Missing or invalid 'chain' in 'getblockchaininfo' result?") @@ -481,7 +486,7 @@ impl BitcoinD { } fn list_wallets(&self) -> Vec { - self.make_node_request("listwallets", &[]) + self.make_node_request("listwallets", None) .as_array() .expect("API break, 'listwallets' didn't return an array.") .iter() @@ -524,7 +529,7 @@ impl BitcoinD { } fn unload_wallet(&self, wallet_path: String) -> Option { - let res = self.make_node_request("unloadwallet", ¶ms!(Json::String(wallet_path),)); + let res = self.make_node_request("unloadwallet", params!(Json::String(wallet_path),)); self.warning_from_res(&res) } @@ -534,7 +539,7 @@ impl BitcoinD { let res = self .make_fallible_node_request( "createwallet", - ¶ms!( + params!( Json::String(wallet_path), Json::Bool(true), // watchonly Json::Bool(true), // blank @@ -569,7 +574,7 @@ impl BitcoinD { }) .collect(); - let res = self.make_wallet_request("importdescriptors", ¶ms!(Json::Array(descriptors))); + let res = self.make_wallet_request("importdescriptors", params!(Json::Array(descriptors))); let all_succeeded = res .as_array() .map(|results| { @@ -586,7 +591,7 @@ impl BitcoinD { } fn list_descriptors(&self) -> Vec { - self.make_wallet_request("listdescriptors", &[]) + self.make_wallet_request("listdescriptors", None) .get("descriptors") .and_then(Json::as_array) .expect("Missing or invalid 'descriptors' field in 'listdescriptors' response") @@ -667,7 +672,7 @@ impl BitcoinD { } let res = self.make_fallible_node_request( "loadwallet", - ¶ms!(Json::String(self.watchonly_wallet_path.clone()),), + params!(Json::String(self.watchonly_wallet_path.clone()),), ); match res { Err(BitcoindError::Server(jsonrpc::Error::Rpc(ref e))) => { @@ -760,7 +765,7 @@ impl BitcoinD { } fn block_chain_info(&self) -> Json { - self.make_node_request("getblockchaininfo", &[]) + self.make_node_request("getblockchaininfo", None) } pub fn sync_progress(&self) -> SyncProgress { @@ -807,7 +812,7 @@ impl BitcoinD { pub fn get_block_hash(&self, height: i32) -> Option { Some( - self.make_fallible_node_request("getblockhash", ¶ms!(Json::Number(height.into()),)) + self.make_fallible_node_request("getblockhash", params!(Json::Number(height.into()),)) .ok()? .as_str() .and_then(|s| bitcoin::BlockHash::from_str(s).ok()) @@ -818,7 +823,7 @@ impl BitcoinD { pub fn list_since_block(&self, block_hash: &bitcoin::BlockHash) -> LSBlockRes { self.make_wallet_request( "listsinceblock", - ¶ms!( + params!( Json::String(block_hash.to_string()), Json::Number(1.into()), // Default for min_confirmations for the returned Json::Bool(true), // Whether to include watchonly @@ -833,7 +838,7 @@ impl BitcoinD { // TODO: Maybe assert we got a -5 error, and not any other kind of error? self.make_faillible_wallet_request( "gettransaction", - ¶ms!(Json::String(txid.to_string())), + params!(Json::String(txid.to_string())), ) .ok() .map(|res| res.into()) @@ -844,7 +849,7 @@ impl BitcoinD { // The result of gettxout is empty if the outpoint is spent. self.make_node_request( "gettxout", - ¶ms!( + params!( Json::String(op.txid.to_string()), Json::Number(op.vout.into()) ), @@ -864,7 +869,7 @@ impl BitcoinD { // unconfirmed, just use the tip. let req = self.make_wallet_request( "gettransaction", - ¶ms!(Json::String(spent_outpoint.txid.to_string())), + params!(Json::String(spent_outpoint.txid.to_string())), ); let list_since_height = match req.get("blockheight").and_then(Json::as_i64) { Some(h) => h as i32, @@ -872,7 +877,7 @@ impl BitcoinD { }; let block_hash = if let Ok(res) = self.make_fallible_node_request( "getblockhash", - ¶ms!(Json::Number((list_since_height - 1).into())), + params!(Json::Number((list_since_height - 1).into())), ) { res.as_str() .expect("'getblockhash' result isn't a string") @@ -887,7 +892,7 @@ impl BitcoinD { // TODO: merge this with the existing list_since_block method. let lsb_res = self.make_wallet_request( "listsinceblock", - ¶ms!( + params!( Json::String(block_hash), Json::Number(1.into()), // Default for min_confirmations for the returned Json::Bool(true), // Whether to include watchonly @@ -922,7 +927,7 @@ impl BitcoinD { let gettx_res = self.make_wallet_request( "gettransaction", - ¶ms!( + params!( Json::String(spending_txid.to_string()), Json::Bool(true), // watchonly Json::Bool(true) // verbose @@ -975,7 +980,7 @@ impl BitcoinD { pub fn get_block_stats(&self, blockhash: bitcoin::BlockHash) -> Option { let res = match self.make_fallible_node_request( "getblockheader", - ¶ms!(Json::String(blockhash.to_string()),), + params!(Json::String(blockhash.to_string()),), ) { Ok(res) => res, Err(e) => { @@ -1023,7 +1028,7 @@ impl BitcoinD { pub fn broadcast_tx(&self, tx: &bitcoin::Transaction) -> Result<(), BitcoindError> { self.make_fallible_node_request( "sendrawtransaction", - ¶ms!(bitcoin::consensus::encode::serialize_hex(tx)), + params!(bitcoin::consensus::encode::serialize_hex(tx).into()), )?; Ok(()) } @@ -1118,10 +1123,9 @@ impl BitcoinD { const NUM_RETRIES: usize = 10; let mut i = 0; loop { - if let Err(e) = self.make_noreply_request( - "importdescriptors", - ¶ms!(Json::Array(desc_json.clone())), - ) { + if let Err(e) = self + .make_noreply_request("importdescriptors", params!(Json::Array(desc_json.clone()))) + { log::error!( "Error when calling 'importdescriptors' for rescanning: {}", e @@ -1142,7 +1146,7 @@ impl BitcoinD { /// Get the progress of the ongoing rescan, if there is any. pub fn rescan_progress(&self) -> Option { - self.make_wallet_request("getwalletinfo", &[]) + self.make_wallet_request("getwalletinfo", None) .get("scanning") // If no rescan is ongoing, it will fail cause it would be 'false' .and_then(Json::as_object) @@ -1169,7 +1173,7 @@ impl BitcoinD { /// Returns `None` if it is not in the mempool. pub fn mempool_entry(&self, txid: &bitcoin::Txid) -> Option { match self - .make_fallible_node_request("getmempoolentry", ¶ms!(Json::String(txid.to_string()))) + .make_fallible_node_request("getmempoolentry", params!(Json::String(txid.to_string()))) { Ok(json) => Some(MempoolEntry::from(json)), Err(BitcoindError::Server(jsonrpc::Error::Rpc(jsonrpc::error::RpcError { @@ -1191,7 +1195,7 @@ impl BitcoinD { .iter() .map(|op| serde_json::json!({"txid": op.txid.to_string(), "vout": op.vout})) .collect(); - self.make_node_request("gettxspendingprevout", ¶ms!(prevouts)) + self.make_node_request("gettxspendingprevout", params!(prevouts)) .as_array() .expect("Always returns an array") .iter() @@ -1207,7 +1211,7 @@ impl BitcoinD { /// Stop bitcoind. pub fn stop(&self) { - self.make_node_request("stop", &[]); + self.make_node_request("stop", None); } } diff --git a/src/bitcoin/mod.rs b/src/bitcoin/mod.rs index 4ac4680d..60388c1e 100644 --- a/src/bitcoin/mod.rs +++ b/src/bitcoin/mod.rs @@ -9,7 +9,7 @@ use crate::{ bitcoin::d::{BitcoindError, CachedTxGetter, LSBlockEntry}, descriptors, }; -pub use d::{MempoolEntry, MempoolEntryFees, SyncProgress}; +pub use d::{MempoolEntry, SyncProgress}; use std::{fmt, sync}; diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 12343d37..9eb22449 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -24,12 +24,11 @@ use utils::{ use std::{ collections::{hash_map, HashMap, HashSet}, - convert::TryInto, fmt, sync, }; use miniscript::{ - bitcoin::{self, address, bip32, psbt::PartiallySignedTransaction as Psbt}, + bitcoin::{self, address, bip32, psbt::Psbt}, psbt::PsbtExt, }; use serde::{Deserialize, Serialize}; @@ -609,7 +608,8 @@ impl DaemonControl { // Then, broadcast it (or try to, we never know if we are not going to hit an // error at broadcast time). - let final_tx = spend_psbt.extract_tx(); + // These checks are already performed at Spend creation time. TODO: a belt-and-suspenders is still worth it though. + let final_tx = spend_psbt.extract_tx_unchecked_fee_rate(); self.bitcoin .broadcast_tx(&final_tx) .map_err(CommandError::TxBroadcast) @@ -729,7 +729,7 @@ impl DaemonControl { .expect("address already used in finalized transaction"); ( address.clone(), - bitcoin::Amount::from_sat(txo.value), + txo.value, db_conn.derivation_index_by_address(&address), ) }) @@ -960,7 +960,7 @@ impl DaemonControl { let current_height = self.bitcoin.chain_tip().height; let timelock = timelock.unwrap_or_else(|| self.config.main_descriptor.first_timelock_value()); - let height_delta: i32 = timelock.try_into().expect("Must fit, it's a u16"); + let height_delta: i32 = timelock.into(); let sweepable_coins: Vec<_> = db_conn .coins(&[CoinStatus::Confirmed], &[]) .into_values() @@ -1138,9 +1138,9 @@ mod tests { use bitcoin::{ bip32::{self, ChildNumber}, - blockdata::transaction::{TxIn, TxOut}, + blockdata::transaction::{TxIn, TxOut, Version as TxVersion}, locktime::absolute, - OutPoint, ScriptBuf, Sequence, Transaction, Txid, Witness, + Amount, OutPoint, ScriptBuf, Sequence, Transaction, Txid, Witness, }; use std::{collections::BTreeMap, str::FromStr}; @@ -1300,7 +1300,7 @@ mod tests { dummy_op.txid, ( bitcoin::Transaction { - version: 2, + version: TxVersion::TWO, lock_time: absolute::LockTime::Blocks(absolute::Height::ZERO), input: vec![], output: vec![], @@ -1371,18 +1371,24 @@ mod tests { assert_eq!(tx.output.len(), 2); assert_eq!( tx.output[0].script_pubkey, - dummy_addr.payload.script_pubkey() + dummy_addr.payload().script_pubkey() ); - assert_eq!(tx.output[0].value, dummy_value); + assert_eq!(tx.output[0].value.to_sat(), dummy_value); + + // NOTE: if you are wondering about the usefulness of these tests asserting arbitrary fixed + // values, that's a belt-and-suspenders check to make sure size and fee calculations do not + // change unexpectedly. For instance this specific test caught how a change in + // rust-bitcoin's serialization of transactions with no input silently affected our fee + // calculation. // Transaction is 1 in (P2WSH satisfaction), 2 outs. At 1sat/vb, it's 170 sats fees. // At 2sats/vb, it's twice that. - assert_eq!(tx.output[1].value, 89_830); + assert_eq!(tx.output[1].value.to_sat(), 89_830); let res = control .create_spend(&destinations, &[dummy_op], 2, None) .unwrap(); let tx = res.psbt.unsigned_tx; - assert_eq!(tx.output[1].value, 89_660); + assert_eq!(tx.output[1].value.to_sat(), 89_660); // A feerate of 555 won't trigger the sanity checks (they were previously not taking the // satisfaction size into account and overestimating the feerate). @@ -1414,7 +1420,7 @@ mod tests { // If we ask to create an output for an address from another network, it will fail. let invalid_addr = - bitcoin::Address::new(bitcoin::Network::Testnet, dummy_addr.payload.clone()); + bitcoin::Address::new(bitcoin::Network::Testnet, dummy_addr.payload().clone()); let invalid_destinations: HashMap, u64> = [(invalid_addr, dummy_value)].iter().cloned().collect(); assert!(matches!( @@ -1436,9 +1442,9 @@ mod tests { assert_eq!(tx.output.len(), 1); assert_eq!( tx.output[0].script_pubkey, - dummy_addr.payload.script_pubkey() + dummy_addr.payload().script_pubkey() ); - assert_eq!(tx.output[0].value, 95_000); + assert_eq!(tx.output[0].value.to_sat(), 95_000); // Now if we mark the coin as spent, we won't create another Spend transaction containing // it. @@ -1555,9 +1561,9 @@ mod tests { assert_eq!(tx_auto.output.len(), 2); assert_eq!( tx_auto.output[0].script_pubkey, - dummy_addr.payload.script_pubkey() + dummy_addr.payload().script_pubkey() ); - assert_eq!(tx_auto.output[0].value, 80_000); + assert_eq!(tx_auto.output[0].value, Amount::from_sat(80_000)); // Create a second transaction using manual coin selection. let res_manual = control @@ -1648,7 +1654,7 @@ mod tests { .unwrap(); let mut dummy_bitcoind = DummyBitcoind::new(); let dummy_tx = bitcoin::Transaction { - version: 2, + version: TxVersion::TWO, lock_time: absolute::LockTime::Blocks(absolute::Height::ZERO), input: vec![], output: vec![], @@ -1770,7 +1776,7 @@ mod tests { let mut dummy_bitcoind = DummyBitcoind::new(); // Transaction spends outpoint a. let dummy_tx_a = bitcoin::Transaction { - version: 2, + version: TxVersion::TWO, lock_time: absolute::LockTime::Blocks(absolute::Height::ZERO), input: vec![bitcoin::TxIn { previous_output: dummy_op_a, @@ -1845,7 +1851,7 @@ mod tests { ); let deposit1: Transaction = Transaction { - version: 1, + version: TxVersion::ONE, lock_time: absolute::LockTime::Blocks(absolute::Height::from_consensus(1).unwrap()), input: vec![TxIn { witness: Witness::new(), @@ -1855,12 +1861,12 @@ mod tests { }], output: vec![TxOut { script_pubkey: ScriptBuf::new(), - value: 100_000_000, + value: Amount::from_sat(100_000_000), }], }; let deposit2: Transaction = Transaction { - version: 1, + version: TxVersion::ONE, lock_time: absolute::LockTime::Blocks(absolute::Height::from_consensus(1).unwrap()), input: vec![TxIn { witness: Witness::new(), @@ -1870,12 +1876,12 @@ mod tests { }], output: vec![TxOut { script_pubkey: ScriptBuf::new(), - value: 2000, + value: Amount::from_sat(2000), }], }; let deposit3: Transaction = Transaction { - version: 1, + version: TxVersion::ONE, lock_time: absolute::LockTime::Blocks(absolute::Height::from_consensus(1).unwrap()), input: vec![TxIn { witness: Witness::new(), @@ -1885,12 +1891,12 @@ mod tests { }], output: vec![TxOut { script_pubkey: ScriptBuf::new(), - value: 3000, + value: Amount::from_sat(3000), }], }; let spend_tx: Transaction = Transaction { - version: 1, + version: TxVersion::ONE, lock_time: absolute::LockTime::Blocks(absolute::Height::from_consensus(1).unwrap()), input: vec![TxIn { witness: Witness::new(), @@ -1904,11 +1910,11 @@ mod tests { output: vec![ TxOut { script_pubkey: ScriptBuf::new(), - value: 4000, + value: Amount::from_sat(4000), }, TxOut { script_pubkey: ScriptBuf::new(), - value: 100_000_000 - 4000 - 1000, + value: Amount::from_sat(100_000_000 - 4000 - 1000), }, ], }; @@ -2072,7 +2078,7 @@ mod tests { ); let tx1: Transaction = Transaction { - version: 1, + version: TxVersion::ONE, lock_time: absolute::LockTime::Blocks(absolute::Height::from_consensus(1).unwrap()), input: vec![TxIn { witness: Witness::new(), @@ -2082,12 +2088,12 @@ mod tests { }], output: vec![TxOut { script_pubkey: ScriptBuf::new(), - value: 100_000_000, + value: Amount::from_sat(100_000_000), }], }; let tx2: Transaction = Transaction { - version: 1, + version: TxVersion::ONE, lock_time: absolute::LockTime::Blocks(absolute::Height::from_consensus(1).unwrap()), input: vec![TxIn { witness: Witness::new(), @@ -2097,12 +2103,12 @@ mod tests { }], output: vec![TxOut { script_pubkey: ScriptBuf::new(), - value: 2000, + value: Amount::from_sat(2000), }], }; let tx3: Transaction = Transaction { - version: 1, + version: TxVersion::ONE, lock_time: absolute::LockTime::Blocks(absolute::Height::from_consensus(1).unwrap()), input: vec![TxIn { witness: Witness::new(), @@ -2112,7 +2118,7 @@ mod tests { }], output: vec![TxOut { script_pubkey: ScriptBuf::new(), - value: 3000, + value: Amount::from_sat(3000), }], }; diff --git a/src/database/mod.rs b/src/database/mod.rs index 375d8ad0..9c2be7c6 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -20,7 +20,7 @@ use std::{ sync, }; -use miniscript::bitcoin::{self, bip32, psbt::PartiallySignedTransaction as Psbt, secp256k1}; +use miniscript::bitcoin::{self, bip32, psbt::Psbt, secp256k1}; pub trait DatabaseInterface: Send { fn connection(&self) -> Box; diff --git a/src/database/sqlite/mod.rs b/src/database/sqlite/mod.rs index b51b6a30..0433c42e 100644 --- a/src/database/sqlite/mod.rs +++ b/src/database/sqlite/mod.rs @@ -39,7 +39,7 @@ use miniscript::bitcoin::{ self, bip32, consensus::encode, hashes::{sha256, Hash}, - psbt::PartiallySignedTransaction as Psbt, + psbt::Psbt, secp256k1, }; @@ -973,7 +973,7 @@ CREATE TABLE spend_transactions ( }; conn.new_unspent_coins(&[coin_a]); // We can query by status and/or outpoint. - assert!(vec![ + assert!([ conn.coins(&[], &[]), conn.coins(&[CoinStatus::Unconfirmed], &[]), conn.coins(&[CoinStatus::Unconfirmed], &[outpoint_a]), @@ -1022,7 +1022,7 @@ CREATE TABLE spend_transactions ( }; conn.new_unspent_coins(&[coin_b]); // Both coins are unconfirmed. - assert!(vec![ + assert!([ conn.coins(&[], &[]), conn.coins(&[CoinStatus::Unconfirmed], &[]), conn.coins(&[CoinStatus::Unconfirmed], &[outpoint_a, outpoint_b]), @@ -1034,7 +1034,7 @@ CREATE TABLE spend_transactions ( && c[0].outpoint == coin_a.outpoint && c[1].outpoint == coin_b.outpoint)); // We can filter for just the first coin. - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Unconfirmed], &[outpoint_a]), conn.coins(&[], &[outpoint_a]), conn.db_coins(&[outpoint_a]) @@ -1042,7 +1042,7 @@ CREATE TABLE spend_transactions ( .iter() .all(|res| res.len() == 1 && res[0].outpoint == coin_a.outpoint)); // Or we can filter for just the second coin. - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Unconfirmed], &[outpoint_b]), conn.coins(&[], &[outpoint_b]), conn.db_coins(&[outpoint_b]) @@ -1062,7 +1062,7 @@ CREATE TABLE spend_transactions ( .is_empty()); // Now if we confirm one, it'll be marked as such. conn.confirm_coins(&[(coin_a.outpoint, 174500, 174500)]); - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Confirmed], &[]), conn.coins(&[CoinStatus::Confirmed], &[outpoint_a]), conn.coins(&[], &[outpoint_a]), @@ -1071,7 +1071,7 @@ CREATE TABLE spend_transactions ( .iter() .all(|res| res.len() == 1 && res[0].outpoint == coin_a.outpoint)); // We can get both confirmed and unconfirmed. - assert!(vec![ + assert!([ conn.coins(&[], &[]), conn.coins(&[CoinStatus::Unconfirmed, CoinStatus::Confirmed], &[]), conn.coins( @@ -1091,7 +1091,7 @@ CREATE TABLE spend_transactions ( coin_a.outpoint, bitcoin::Txid::from_slice(&[0; 32][..]).unwrap(), )]); - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Spending], &[]), conn.coins(&[CoinStatus::Spending], &[outpoint_a]), conn.coins(&[], &[outpoint_a]), @@ -1101,7 +1101,7 @@ CREATE TABLE spend_transactions ( .iter() .all(|res| res.len() == 1 && res[0].outpoint == coin_a.outpoint)); // The second coin is still unconfirmed. - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Unconfirmed], &[]), conn.coins(&[CoinStatus::Unconfirmed], &[outpoint_b]), conn.coins(&[], &[outpoint_b]), @@ -1118,7 +1118,7 @@ CREATE TABLE spend_transactions ( 3_000_000, )]); // The coin no longer has spending status. - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Spending], &[]), conn.coins(&[CoinStatus::Spending], &[outpoint_a]), conn.list_spending_coins(), @@ -1127,7 +1127,7 @@ CREATE TABLE spend_transactions ( .all(|res| res.is_empty())); // Both coins are still in DB. - assert!(vec![ + assert!([ conn.coins(&[], &[]), conn.coins(&[CoinStatus::Unconfirmed, CoinStatus::Spent], &[]), conn.coins( @@ -1174,7 +1174,7 @@ CREATE TABLE spend_transactions ( conn.new_unspent_coins(&[coin_c, coin_d]); // We can get all three unconfirmed coins with different status/outpoint filters. - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Unconfirmed], &[]), conn.coins( &[CoinStatus::Unconfirmed], @@ -1190,7 +1190,7 @@ CREATE TABLE spend_transactions ( && coin[2].outpoint == coin_d.outpoint)); // We can also get two of the three unconfirmed coins by filtering for their outpoints. - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Unconfirmed], &[outpoint_b, outpoint_c]), conn.coins(&[], &[outpoint_b, outpoint_c]), conn.db_coins(&[outpoint_b, outpoint_c]), @@ -1206,7 +1206,7 @@ CREATE TABLE spend_transactions ( bitcoin::Txid::from_slice(&[1; 32][..]).unwrap(), )]); // The coin shows as spending. - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Spending], &[]), conn.coins(&[CoinStatus::Spending], &[outpoint_b]), conn.coins(&[], &[outpoint_b]), @@ -1220,7 +1220,7 @@ CREATE TABLE spend_transactions ( conn.confirm_coins(&[(coin_c.outpoint, 175500, 175500)]); // We now only have one unconfirmed coin. - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Unconfirmed], &[]), conn.coins( &[CoinStatus::Unconfirmed], @@ -1233,7 +1233,7 @@ CREATE TABLE spend_transactions ( .all(|c| c.len() == 1 && c[0].outpoint == coin_d.outpoint)); // There is now one coin for each status. - assert!(vec![ + assert!([ conn.coins(&[CoinStatus::Unconfirmed], &[]), conn.coins(&[CoinStatus::Unconfirmed], &[outpoint_d]), conn.coins(&[CoinStatus::Confirmed], &[]), diff --git a/src/database/sqlite/schema.rs b/src/database/sqlite/schema.rs index 7ebb280b..6add975a 100644 --- a/src/database/sqlite/schema.rs +++ b/src/database/sqlite/schema.rs @@ -2,9 +2,7 @@ use crate::descriptors::LianaDescriptor; use std::{convert::TryFrom, str::FromStr}; -use miniscript::bitcoin::{ - self, address, bip32, consensus::encode, psbt::PartiallySignedTransaction as Psbt, -}; +use miniscript::bitcoin::{self, address, bip32, consensus::encode, psbt::Psbt}; pub const SCHEMA: &str = "\ CREATE TABLE version ( diff --git a/src/descriptors/analysis.rs b/src/descriptors/analysis.rs index b106a068..e840002d 100644 --- a/src/descriptors/analysis.rs +++ b/src/descriptors/analysis.rs @@ -72,7 +72,7 @@ fn is_single_key_or_multisig(policy: &SemanticPolicy, + keys_set: HashSet<(bip32::Xpub, descriptor::DerivPaths)>, } impl DescKeyChecker { @@ -109,7 +109,7 @@ impl DescKeyChecker { // without origin entirely. if let Some(ref origin) = xpub.origin { let der_paths = xpub.derivation_paths.paths(); - let first_der_path = der_paths.get(0).expect("Cannot be empty"); + let first_der_path = der_paths.first().expect("Cannot be empty"); // We also rule out xpubs with hardened derivation steps (non-normalized xpubs). let valid = xpub.wildcard == descriptor::Wildcard::Unhardened && der_paths.len() == 2 @@ -347,7 +347,9 @@ impl PathInfo { PathInfo::Single(key) => ConcretePolicy::Key(key), PathInfo::Multi(thresh, keys) => ConcretePolicy::Threshold( thresh, - keys.into_iter().map(ConcretePolicy::Key).collect(), + keys.into_iter() + .map(|key| ConcretePolicy::Key(key).into()) + .collect(), ), } } @@ -531,9 +533,9 @@ impl LianaPolicy { .fold(primary_keys, |tl_policy, (timelock, path_info)| { let timelock = ConcretePolicy::Older(Sequence::from_height(timelock)); let keys = path_info.into_ms_policy(); - let recovery_branch = ConcretePolicy::And(vec![keys, timelock]); + let recovery_branch = ConcretePolicy::And(vec![keys.into(), timelock.into()]); // We assume the larger the timelock the less likely a branch would be used. - ConcretePolicy::Or(vec![(99, tl_policy), (1, recovery_branch)]) + ConcretePolicy::Or(vec![(99, tl_policy.into()), (1, recovery_branch.into())]) }); tl_policy diff --git a/src/descriptors/mod.rs b/src/descriptors/mod.rs index b822ac82..06f46b79 100644 --- a/src/descriptors/mod.rs +++ b/src/descriptors/mod.rs @@ -786,10 +786,10 @@ mod tests { // NOTE: The specific value is asserted because this was tested against a regtest // transaction. let stack = vec![vec![0; 65], vec![0; 0], vec![0; 33], vec![0; 72]]; - let witness_size = bitcoin::VarInt(stack.len() as u64).len() + let witness_size = bitcoin::VarInt(stack.len() as u64).size() + stack .iter() - .map(|item| bitcoin::VarInt(item.len() as u64).len() + item.len()) + .map(|item| bitcoin::VarInt(item.len() as u64).size() + item.len()) .sum::(); assert_eq!( desc.spender_input_size(), diff --git a/src/jsonrpc/api.rs b/src/jsonrpc/api.rs index 403563cf..f99ee9ef 100644 --- a/src/jsonrpc/api.rs +++ b/src/jsonrpc/api.rs @@ -10,7 +10,7 @@ use std::{ str::FromStr, }; -use miniscript::bitcoin::{self, psbt::PartiallySignedTransaction as Psbt}; +use miniscript::bitcoin::{self, psbt::Psbt}; fn create_spend(control: &DaemonControl, params: Params) -> Result { let destinations = params diff --git a/src/signer.rs b/src/signer.rs index 495a6bb5..e074e233 100644 --- a/src/signer.rs +++ b/src/signer.rs @@ -58,7 +58,7 @@ pub const MNEMONICS_FOLDER_NAME: &str = "mnemonics"; /// A signer that keeps the key on the laptop. Based on BIP39. pub struct HotSigner { mnemonic: bip39::Mnemonic, - master_xpriv: bip32::ExtendedPrivKey, + master_xpriv: bip32::Xpriv, } // TODO: instead of copying them here we could have a util module with those helpers. @@ -103,8 +103,8 @@ impl HotSigner { network: bitcoin::Network, mnemonic: bip39::Mnemonic, ) -> Result { - let master_xpriv = bip32::ExtendedPrivKey::new_master(network, &mnemonic.to_seed("")) - .map_err(SignerError::Bip32)?; + let master_xpriv = + bip32::Xpriv::new_master(network, &mnemonic.to_seed("")).map_err(SignerError::Bip32)?; Ok(Self { mnemonic, master_xpriv, @@ -212,7 +212,7 @@ impl HotSigner { &self, der_path: &bip32::DerivationPath, secp: &secp256k1::Secp256k1, - ) -> bip32::ExtendedPrivKey { + ) -> bip32::Xpriv { self.master_xpriv .derive_priv(secp, der_path) .expect("Never fails") @@ -223,9 +223,9 @@ impl HotSigner { &self, der_path: &bip32::DerivationPath, secp: &secp256k1::Secp256k1, - ) -> bip32::ExtendedPubKey { + ) -> bip32::Xpub { let xpriv = self.xpriv_at(der_path, secp); - bip32::ExtendedPubKey::from_priv(secp, &xpriv) + bip32::Xpub::from_priv(secp, &xpriv) } /// Sign all inputs of the given PSBT. @@ -254,9 +254,9 @@ impl HotSigner { .value; let sig_type = sighash::EcdsaSighashType::All; let sighash = sighash_cache - .segwit_signature_hash(i, witscript, value, sig_type) + .p2wsh_signature_hash(i, witscript, value, sig_type) .map_err(|_| SignerError::InsanePsbt)?; - let sighash = secp256k1::Message::from_slice(sighash.as_byte_array()) + let sighash = secp256k1::Message::from_digest_slice(sighash.as_byte_array()) .expect("Sighash is always 32 bytes."); // Then provide a signature for all the keys they asked for. @@ -297,7 +297,7 @@ mod tests { use super::*; use crate::{descriptors, testutils::*}; use miniscript::{ - bitcoin::{locktime::absolute, psbt::Input as PsbtIn}, + bitcoin::{locktime::absolute, psbt::Input as PsbtIn, Amount}, descriptor::{DerivPaths, DescriptorMultiXKey, DescriptorPublicKey, Wildcard}, }; use std::collections::{BTreeMap, HashSet}; @@ -429,7 +429,7 @@ mod tests { let spent_coin_desc = desc.receive_descriptor().derive(42.into(), &secp); let mut dummy_psbt = Psbt { unsigned_tx: bitcoin::Transaction { - version: 2, + version: bitcoin::transaction::Version::TWO, lock_time: absolute::LockTime::Blocks(absolute::Height::ZERO), input: vec![bitcoin::TxIn { sequence: bitcoin::Sequence::ENABLE_RBF_NO_LOCKTIME, @@ -440,12 +440,12 @@ mod tests { ..bitcoin::TxIn::default() }], output: vec![bitcoin::TxOut { - value: 18_420, + value: Amount::from_sat(18_420), script_pubkey: bitcoin::Address::from_str( "bc1qvklensptw5lk7d470ds60pcpsr0psdpgyvwepv", ) .unwrap() - .payload + .payload() .script_pubkey(), }], }, @@ -457,7 +457,7 @@ mod tests { witness_script: Some(spent_coin_desc.witness_script()), bip32_derivation: spent_coin_desc.bip32_derivations(), witness_utxo: Some(bitcoin::TxOut { - value: 19_000, + value: Amount::from_sat(19_000), script_pubkey: spent_coin_desc.script_pubkey(), }), ..PsbtIn::default() @@ -479,10 +479,7 @@ mod tests { // We can add another external output to the transaction, we can still sign without issue. // The output can be insane, we don't check it. It doesn't even need an accompanying PSBT // output. - dummy_psbt - .unsigned_tx - .output - .push(bitcoin::TxOut::default()); + dummy_psbt.unsigned_tx.output.push(bitcoin::TxOut::NULL); let psbt = dummy_psbt.clone(); assert!(psbt.inputs[0].partial_sigs.is_empty()); let psbt = prim_signer_a.sign_psbt(psbt, &secp).unwrap(); @@ -499,7 +496,7 @@ mod tests { witness_script: Some(other_spent_coin_desc.witness_script()), bip32_derivation: other_spent_coin_desc.bip32_derivations(), witness_utxo: Some(bitcoin::TxOut { - value: 19_000, + value: Amount::from_sat(19_000), script_pubkey: other_spent_coin_desc.script_pubkey(), }), ..PsbtIn::default() diff --git a/src/spend.rs b/src/spend.rs index 9a308521..c139271f 100644 --- a/src/spend.rs +++ b/src/spend.rs @@ -23,7 +23,7 @@ pub const DUST_OUTPUT_SATS: u64 = 5_000; pub const LONG_TERM_FEERATE_VB: f32 = 10.0; /// Assume that paying more than 1BTC in fee is a bug. -pub const MAX_FEE: u64 = bitcoin::blockdata::constants::COIN_VALUE; +pub const MAX_FEE: bitcoin::Amount = bitcoin::Amount::ONE_BTC; /// Assume that paying more than 1000sat/vb in feerate is a bug. pub const MAX_FEERATE: u64 = 1_000; @@ -53,7 +53,7 @@ impl fmt::Display for SpendCreationError { Self::InvalidOutputValue(amount) => write!(f, "Invalid output value '{}'.", amount), Self::InsaneFees(info) => write!( f, - "We assume transactions with a fee larger than {} sats or a feerate larger than {} sats/vb are a mistake. \ + "We assume transactions with a fee larger than {} or a feerate larger than {} sats/vb are a mistake. \ The created transaction {}.", MAX_FEE, MAX_FEERATE, @@ -81,10 +81,7 @@ impl std::error::Error for SpendCreationError {} // Sanity check the value of a transaction output. fn check_output_value(value: bitcoin::Amount) -> Result<(), SpendCreationError> { - // NOTE: the network parameter isn't used upstream - if value.to_sat() > bitcoin::blockdata::constants::MAX_MONEY - || value.to_sat() < DUST_OUTPUT_SATS - { + if value > bitcoin::Amount::MAX_MONEY || value.to_sat() < DUST_OUTPUT_SATS { Err(SpendCreationError::InvalidOutputValue(value)) } else { Ok(()) @@ -118,15 +115,16 @@ fn sanity_check_psbt( .witness_utxo .as_ref() .ok_or_else(|| SpendCreationError::SanityCheckFailure(psbt.clone()))? - .value; + .value + .to_sat(); } // Compute the output value and check the absolute fee isn't insane. - let value_out: u64 = tx.output.iter().map(|o| o.value).sum(); + let value_out: u64 = tx.output.iter().map(|o| o.value.to_sat()).sum(); let abs_fee = value_in .checked_sub(value_out) .ok_or(SpendCreationError::InsaneFees(InsaneFeeInfo::NegativeFee))?; - if abs_fee > MAX_FEE { + if abs_fee > MAX_FEE.to_sat() { return Err(SpendCreationError::InsaneFees(InsaneFeeInfo::TooHighFee( abs_fee, ))); @@ -147,7 +145,7 @@ fn sanity_check_psbt( // Check for dust outputs for txo in psbt.unsigned_tx.output.iter() { - if txo.value < txo.script_pubkey.dust_value().to_sat() { + if txo.value < txo.script_pubkey.dust_value() { return Err(SpendCreationError::SanityCheckFailure(psbt.clone())); } } @@ -257,16 +255,25 @@ fn select_coins_for_spend( max_sat_weight: u32, must_have_change: bool, ) -> Result<(Vec, bitcoin::Amount), InsufficientFunds> { - let out_value_nochange = base_tx.output.iter().map(|o| o.value).sum(); + let out_value_nochange = base_tx.output.iter().map(|o| o.value.to_sat()).sum(); // Create the coin selector from the given candidates. NOTE: the coin selector keeps track // of the original ordering of candidates so we can select any mandatory candidates using their // original indices. - let base_weight: u32 = base_tx + let mut base_weight: u32 = base_tx .weight() .to_wu() .try_into() .expect("Transaction weight must fit in u32"); + // Starting with version 0.31, rust-bitcoin now accounts for the segwit marker when serializing + // transactions with no input. But BDK's coin selector does add the segwit marker cost to the + // transaction size upon selecting the first segwit coin. To avoid accounting twice for it, + // drop it from the base weight (but only when it was added). + // NOTE: make sure to reconsider this when updating rust-bitcoin!! Behaviour may change again + // who knows. + if base_tx.input.is_empty() { + base_weight = base_weight.saturating_sub(2); + } let max_input_weight = TXIN_BASE_WEIGHT + max_sat_weight; let candidates: Vec = candidate_coins .iter() @@ -293,12 +300,15 @@ fn select_coins_for_spend( let long_term_feerate = FeeRate::from_sat_per_vb(LONG_TERM_FEERATE_VB); let drain_weights = DrainWeights { output_weight: { + // We don't reuse the above base_weight.since 2 WU may have been substracted from it. + // See comment above for details. + let nochange_weight = base_tx.weight().to_wu(); let mut tx_with_change = base_tx; tx_with_change.output.push(change_txo); tx_with_change .weight() .to_wu() - .checked_sub(base_weight.into()) + .checked_sub(nochange_weight) .expect("base_weight can't be larger") .try_into() .expect("tx size must always fit in u32") @@ -481,7 +491,7 @@ pub fn create_spend( // Create transaction with no inputs and no outputs. let mut tx = bitcoin::Transaction { - version: 2, + version: bitcoin::transaction::Version::TWO, lock_time: LockTime::Blocks(Height::ZERO), // TODO: randomized anti fee sniping input: Vec::with_capacity(candidate_coins.iter().filter(|c| c.must_select).count()), output: Vec::with_capacity(destinations.len()), @@ -493,7 +503,7 @@ pub fn create_spend( check_output_value(*amount)?; tx.output.push(bitcoin::TxOut { - value: amount.to_sat(), + value: *amount, script_pubkey: address.addr.script_pubkey(), }); // If it's an address of ours, signal it as change to signing devices by adding the @@ -520,7 +530,7 @@ pub fn create_spend( // We need to get the size of a potential change output to select coins / determine whether // we should include one, so get the change address and create a dummy txo for this purpose. let mut change_txo = bitcoin::TxOut { - value: std::u64::MAX, + value: bitcoin::Amount::MAX, script_pubkey: change_addr.addr.script_pubkey(), }; // Now select the coins necessary using the provided candidates and determine whether @@ -537,8 +547,7 @@ pub fn create_spend( })?; fr } - .try_into() - .expect("u16 must fit in f32"); + .into(); let max_sat_wu = main_descriptor .max_sat_weight() .try_into() @@ -575,7 +584,7 @@ pub fn create_spend( }; // TODO: shuffle once we have Taproot - change_txo.value = change_amount.to_sat(); + change_txo.value = change_amount; tx.output.push(change_txo); psbt_outs.push(PsbtOut { bip32_derivation, @@ -600,7 +609,7 @@ pub fn create_spend( let coin_desc = derived_desc(secp, main_descriptor, cand); let witness_script = Some(coin_desc.witness_script()); let witness_utxo = Some(bitcoin::TxOut { - value: cand.amount.to_sat(), + value: cand.amount, script_pubkey: coin_desc.script_pubkey(), }); let non_witness_utxo = tx_getter.get_tx(&cand.outpoint.txid); diff --git a/src/testutils.rs b/src/testutils.rs index 3bd663b0..c175c156 100644 --- a/src/testutils.rs +++ b/src/testutils.rs @@ -13,9 +13,7 @@ use std::{ }; use miniscript::{ - bitcoin::{ - self, bip32, psbt::PartiallySignedTransaction as Psbt, secp256k1, Transaction, Txid, - }, + bitcoin::{self, bip32, psbt::Psbt, secp256k1, Transaction, Txid}, descriptor, };