external/vendor: update bitcoin to v0.32.7
What changed, and why it matters
This commit updates the vendored rust-bitcoin library inside the BitBox02 firmware from version 0.32.2 to 0.32.7. It is a routine dependency refresh that pulls in several upstream bug fixes and small feature additions, such as support for testnet4 and pay-to-anchor outputs. The commit does not describe itself as a security fix, and the visible changes are mostly API cleanups and correctness improvements rather than patches for an active vulnerability.
Treat as a standard dependency maintenance update. Review the upstream rust-bitcoin 0.32.3 through 0.32.7 release notes for any security-relevant fixes, run the firmware's transaction signing tests, and verify that the renamed Taproot keypair methods in signtx.rs still produce valid signatures. No urgent security response is indicated by this commit alone.
Security signals we found
Dependency update from rust-bitcoin 0.32.2 to 0.32.7
Upstream fix for SIGHASH_SINGLE compatibility with Bitcoin Core
Upstream BIP32 maximum depth derivation hardening
Witness stack parsing improvements in upstream library
Pay-to-anchor (P2A) output support added upstream
No vendor security disclosure or CVE referenced in commit
Evidence from the diff
The diff is a bulk vendor update of external/vendor/bitcoin to rust-bitcoin 0.32.7. Notable upstream changes backported into this release include: fixing the SIGHASH_SINGLE bug check to match Bitcoin Core (is_single), BIP32 maximum-depth derivation error handling, witness stack getter fixes, Taproot signing helpers (XOnlyPublicKey retrieval), and pay-to-anchor (P2A) output support. The BitBox02-specific code in src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs is adjusted only to accommodate renamed/deprecated methods (to_inner -> to_keypair / as_keypair). No BitBox02-specific security bug is visible in the diff.
Changed components
external/vendor/bitcoin (vendored rust-bitcoin crate)src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rsInspect captured patch +1433 / −372
diff --git a/external/vendor/bitcoin/.cargo-checksum.json b/external/vendor/bitcoin/.cargo-checksum.json
index 249bce3..28f0e16 100644
--- a/external/vendor/bitcoin/.cargo-checksum.json
+++ b/external/vendor/bitcoin/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"CHANGELOG.md":"867d1a96e8301b727118922a94ec5d89be817c9de51e073f4dd23acc72d83325","Cargo.lock":"c63e61bd0e3971b7ba532f838194ce5cb905de9773143f2d71e79695a81d49dd","Cargo.toml":"3e7b65c3d6f37986dfd20b4e90504a46cbb5c7bdcf5cb0787ddfa1f51f60f38f","README.md":"eb9057d94fb4ca08152e6be85a059e1d63485ccfc96b2ebe9073464d6f23f7a9","build.rs":"a29d078d61bfcf077a55e664b112183adac2ad564a6005cc6e57a445da10fb59","examples/bip32.rs":"49c82b975d04102294dc194b333e35a69c20eb4743d6970f8c26a3d692e98bac","examples/ecdsa-psbt.rs":"98d5368155dc96803ce9cff7b4eab9bd51beb51add54067b17f89c91518a433e","examples/handshake.rs":"a8b1c32d81b62dcadea685e85430ce9df288cec25aebc830bbd35064e63f49a3","examples/sighash.rs":"3055863e1852b13553ea1177c2251bfa7d431bf3bb974ca6bdb18cd5f8f821a3","examples/sign-tx-segwit-v0.rs":"351f70425ca41b0f776a54ca32b8affb9e10707abff1cf0ca8e82da48c87f59c","examples/sign-tx-taproot.rs":"e252eb1f01924cf03f1b2f290be5c302af1c22f03af5d2dd5fc67de6230cff9d","examples/taproot-psbt.rs":"7849501225a07a1e4d1e6712c307ee659c411800963490003b711a5f9332bd9d","src/address/error.rs":"af148c26298c751fcbc6aa8afd1629320106a85e6e8ec5368c05b3a4d1c5b614","src/address/mod.rs":"e78b251b70e5fe0a5bff5a6fe22e817fd854117706b5fdf799c01f9f4e219d6d","src/bip152.rs":"84ec895ff157d25460a27424f4df4601ef6b3d18cf463525654f92b3c72f66fb","src/bip158.rs":"9ce19a4227439f2507bd59770aa1f33517abb45a7e48540d5b61c7b2c16d1e1c","src/bip32.rs":"275286033180cb780ffe5720debf5ce59afa477f022383e92f4a83a806055fe2","src/blockdata/block.rs":"12f5e89a717eaa5aaeaa2e7306235fdf2b7acef543a87089fca2d23233cdbf8c","src/blockdata/constants.rs":"f4655cd83bb26fd250103ad9d7de21163e0fa681f170d15b4249c143bbb5e120","src/blockdata/locktime/absolute.rs":"ca8b03b06d95cc0e21e16e13803463d3cd51f0890b52951b28b614696bc3c1c5","src/blockdata/locktime/mod.rs":"3a37e1e520ad6ddef2d029cc641f3e633da33edf40b84a63cf3a9a97e7a3d390","src/blockdata/locktime/relative.rs":"7ceaa7a7e0e729f737cf218b957ededa37901bc762320112e37223a704e5d2c6","src/blockdata/mod.rs":"a9721ed899b3efb15c2db6ad2ab4ba943bfae4401b3f679bacf232f2c9ac51fd","src/blockdata/opcodes.rs":"b14d7c78e9eb86a454331249d43aef9ef618055add9d2d268b58808bb1e16ba6","src/blockdata/script/borrowed.rs":"5384c60e43c0bdd1d05337c5812ab40182db8ee496970714d43c473042f7a001","src/blockdata/script/builder.rs":"b52ff2c139bcd19e4ddf8be81844a95c14bfe8255bd177ad2915cbe3a364a802","src/blockdata/script/instruction.rs":"08e194e981d778a3f786a62c545320e271c2c58cc6e12f7a56d7d29c54ba0d31","src/blockdata/script/mod.rs":"2f269664135c11ac1682bf1f01b2ff0b0a3cf8a027f68c2c8d2a9a47903a036e","src/blockdata/script/owned.rs":"b039c2be6cc8110361841b19bb69ab9c6d80a78614bfd984d0febfadefbe99ea","src/blockdata/script/push_bytes.rs":"b969753feed51b579d5c7f60aed201a82733b1a2ccf9079357a7ac89bea15854","src/blockdata/script/tests.rs":"b44d33e2ad8733eed890217c775c817c458d2c1b0b5bf650cc4d576c17dbce8f","src/blockdata/script/witness_program.rs":"044b726e459caa825ca3b4981d9bbf433976af862b6f7abe16e79e9dbd54d09b","src/blockdata/script/witness_version.rs":"27befeebb56b46d0e67da4c86af7556ce91e571b2f7220dc9842ef33bf75a6d6","src/blockdata/transaction.rs":"6f5035496a434c0111bac6e2308d981cf8734a7cdfb23b710e0f8f38173cf729","src/blockdata/witness.rs":"235ed961a9b9c19e0cc7f95716e62891e47058771e68b47a2529ce98d1de5448","src/consensus/encode.rs":"cc0ffa222c8a23b4df677a8593ab9b5d4de34ee2afb4bcd1747861b5c51a4f3a","src/consensus/mod.rs":"68b9861848837f16b3d9df0c17e0763fa8ffa3d36b5681944bf678c118f3b9d5","src/consensus/params.rs":"6405a6701e28cf7273edeb189096489d3198653b5762376d0a9827e31f68d32d","src/consensus/serde.rs":"2419548662071ccd7b35408f57078625208dbb3e50690f7b02dcee806e81326b","src/consensus/validation.rs":"242397674c8f79f27ae1c6848590b64650ab41124463dfed7a98a75bdf4f5e49","src/crypto/ecdsa.rs":"972d205b4b2b84abd203655faed1885aa9fc9337d0863f0789a45af45926d792","src/crypto/key.rs":"206813cccdc90f3e60ed9ac7a5e545fc30ab52c6146ff8feb0ef018e3c6d60c8","src/crypto/mod.rs":"49b9ad7d99c9ed4f346d12f8d59c4394de7e603253c5a8a3781b7e255cf50fc9","src/crypto/sighash.rs":"b17fcd551c7a8508949ffcd4745cc9b834211960c2e9010c061de74d927aebae","src/crypto/taproot.rs":"0e657b6edc304a9d5e63bf2b30351acc845d6d33bc02c6c40dd05b79bc97b148","src/error.rs":"f5d5223287d6738e7a546891c869cf19f5f3e4f4d5ba2333ceed7a8873d05838","src/hash_types.rs":"6eb1c61f9a6f7b3bbb1527294d4452ea95ccd34b43180d44212b0fbb5da27dc5","src/internal_macros.rs":"d06f8d89726a2f30b0bea005d0b323c94bd8bcc7b2f8a799af0a61f8af07eb51","src/lib.rs":"45dfa1ddaee3044468e537ee386ab70f0aca0dcd2389b9af7082ee52525c1c53","src/merkle_tree/block.rs":"0cdbe6471d49430d80701dddc6e6724adf623abc972b63c9517051d41dbefd66","src/merkle_tree/mod.rs":"053ed9969f5f9314c2e360858c1e96c5a507d253eeb8bf9e8ea49cba5f2244fa","src/network.rs":"bdfaf03890fee5af496a5da1538bfa7e5b8849ec4f0a30e07661f8612b2f13d1","src/p2p/address.rs":"35255f7dc8f5540814a57777ec1057aedce182f32aa7dc0b35490fcda8452f9d","src/p2p/message.rs":"86466d0305d085315719347e99f1bf4a5019ad2fe924c33619cd772a0e0fb7fc","src/p2p/message_blockdata.rs":"4958fe6e404c4452f14b8bfaba02cc6ec8b378d7cf7bdf5039b2f544ba1b1f74","src/p2p/message_bloom.rs":"038e77983b196836fdeb486cc70e5471b22ab99a5d3bf189ac29351938ce6fe7","src/p2p/message_compact_blocks.rs":"50969b9c33663d1e451810823a690da088037f45e4228d3c97468c2d056ddfad","src/p2p/message_filter.rs":"a989c370691d90645a17dfdd0e934ee2ef997e005b4827af83535262e439e4b0","src/p2p/message_network.rs":"c5227974be8316a53b2724cbca18e7ed3c3b8547db07ea94f16fc560e7e7fdac","src/p2p/mod.rs":"b13434037a729bc3dcd006de58338e552d7973b37e7cc904da7e5fe3444a58f9","src/policy.rs":"297f4606519f911ad485eb1c650412a5b805a189496f8a6d498ec861b941e14c","src/pow.rs":"bb191f0fabe57d9118f10f34981ecaa1ff076909e980f32da1e5e8be15ece139","src/psbt/error.rs":"4c86d438773acc195f35e0e94e1b96575e6d3f238931f3c856256fb6ca4d3d22","src/psbt/macros.rs":"9ead7254e590f7d7b09246a767672cf42a6e15d7db187f173ce8b162d0f22a50","src/psbt/map/global.rs":"f56dac9b0f42183e353ca56250adc3ff624b818a07c459fd371cfabb718643c0","src/psbt/map/input.rs":"3e5233a1458181e12a113dae2741d3615fa7f54f2c6606cb2a2c0135643e3ddb","src/psbt/map/mod.rs":"6b36b5e47683c3d8118825623e0ae4930552368008ffa9262c9d9f2865c7799c","src/psbt/map/output.rs":"cd3469bd0750591301c87821607590916531b4e615f377990955fb3c20b583b5","src/psbt/mod.rs":"3703e06e1fd2adf2395e79048ea9ad6dbbe4fc5632118f8d4a813b46baf1a3e8","src/psbt/raw.rs":"9a4eb432b2b2c2ec7c79dbca664d9f1ca4ab8e80fc0c8bf7b6a0ee8894e9a028","src/psbt/serialize.rs":"269fca1d01b3d3a283c60c20729538085c7ce2a4829790b5f51b24c91253a7e1","src/serde_utils.rs":"601ad184ed32c8ed2897664736ec33c1d6d2ef4b7c4529dc2f20ca42fae9b8e5","src/sign_message.rs":"dd6b9563aacc097c07ec10cfffd24b23143246dbeb0a0fd5ed6e71c01104b6d5","src/taproot/merkle_branch.rs":"c8a0f1a088dfd4c0b385886f6e4cb58e78736b89d384387b321876203093d7c0","src/taproot/mod.rs":"3376c6ceb5f5164f70712bc376354b295b78389a416a47e619e4f0a8a6a3e7ed","src/taproot/serialized_signature.rs":"bd69a38179816c0256c1bb44266d956eee5aad49ce5210459d7c7edfa50c3ef2","src/test_macros.rs":"e13805bced0ae5d97a4115018a48ac627facbcfd61c23c9132bb3c97e093ed69"},"package":"ea507acc1cd80fc084ace38544bbcf7ced7c2aa65b653b102de0ce718df668f6"}
\ No newline at end of file
+{"files":{"CHANGELOG.md":"6fea431cd1224bd3c8b031377254a0b013e4f674f5a423d9b28b74a3b3619560","Cargo.lock":"1cc56dfde9ef0ef9e97b41d1795fddc5acbef52e5031a9ddb61f93c52053ea6e","Cargo.toml":"329bb4a15a0b10b31adc61d48fd93cf5e70b3817670cb751f8c7fa5e26653bca","README.md":"eb9057d94fb4ca08152e6be85a059e1d63485ccfc96b2ebe9073464d6f23f7a9","build.rs":"a29d078d61bfcf077a55e664b112183adac2ad564a6005cc6e57a445da10fb59","examples/bip32.rs":"49c82b975d04102294dc194b333e35a69c20eb4743d6970f8c26a3d692e98bac","examples/ecdsa-psbt.rs":"7711a600e56f34ca9f71957113733ddf84b3d8766a9461e74dba91fa41f5e75a","examples/handshake.rs":"a8b1c32d81b62dcadea685e85430ce9df288cec25aebc830bbd35064e63f49a3","examples/sighash.rs":"3055863e1852b13553ea1177c2251bfa7d431bf3bb974ca6bdb18cd5f8f821a3","examples/sign-tx-segwit-v0.rs":"351f70425ca41b0f776a54ca32b8affb9e10707abff1cf0ca8e82da48c87f59c","examples/sign-tx-taproot.rs":"8498119fc98af41d3cf50190e762c138deb59f46addf4e5f0f3a9081651fa64d","examples/taproot-psbt.rs":"43d4317f717913eea8891b509d2d2c1e67b9fd9aad2768ab90c74db8dac7b0bb","src/address/error.rs":"af148c26298c751fcbc6aa8afd1629320106a85e6e8ec5368c05b3a4d1c5b614","src/address/mod.rs":"0de60785e2617cd979684f66749e873cb506443a0f841bcb138d38c1cf83d906","src/bip152.rs":"df1b43f9f581c2f0108d9a3658bef0f5aea182bc8d00d5297e2fd5516ea65cb5","src/bip158.rs":"a863a0ca2f7ec6cd0f8b64ee2f0b472623bb9d5fdca9f25d5f1b12f126005736","src/bip32.rs":"0d516ff3bf7a016c823569bf9578895e65d73f01bd06581bcf1bdae0ea323752","src/blockdata/block.rs":"527a6bbb2e9ea47acf1b8d030202020feb254df706800d69339dba0e55396885","src/blockdata/constants.rs":"feb77c2bf7aaad5b60fcc83dac3161389c4c53b9a822fa3b633af3e4e2577aac","src/blockdata/locktime/absolute.rs":"0fe9a8097cc6876177ef6fa21481a5e4965e9fa54d8e03fe65fdfdaeb1d9c3f2","src/blockdata/locktime/mod.rs":"3a37e1e520ad6ddef2d029cc641f3e633da33edf40b84a63cf3a9a97e7a3d390","src/blockdata/locktime/relative.rs":"7ceaa7a7e0e729f737cf218b957ededa37901bc762320112e37223a704e5d2c6","src/blockdata/mod.rs":"a9721ed899b3efb15c2db6ad2ab4ba943bfae4401b3f679bacf232f2c9ac51fd","src/blockdata/opcodes.rs":"b14d7c78e9eb86a454331249d43aef9ef618055add9d2d268b58808bb1e16ba6","src/blockdata/script/borrowed.rs":"c24c5832d5c3a7e619ce6205b056a60b7839c8b38bee3d2e7962cd39e950a3e6","src/blockdata/script/builder.rs":"b52ff2c139bcd19e4ddf8be81844a95c14bfe8255bd177ad2915cbe3a364a802","src/blockdata/script/instruction.rs":"08e194e981d778a3f786a62c545320e271c2c58cc6e12f7a56d7d29c54ba0d31","src/blockdata/script/mod.rs":"59f0bc87fc855bd2f9a9d6ffd026f22e8c4d78e641d1a56d3dc0522769a3126d","src/blockdata/script/owned.rs":"dfa38a250d4836768232bbd8db1a89c67fd17e05886dab682feeb6ded5dfee28","src/blockdata/script/push_bytes.rs":"f5fadb098d3d77249a82dd7e4dad851ac48e3bb20261df1d59858b83570c9a94","src/blockdata/script/tests.rs":"b44d33e2ad8733eed890217c775c817c458d2c1b0b5bf650cc4d576c17dbce8f","src/blockdata/script/witness_program.rs":"15700de082fa8822773e82b81a3a77fe7a3b2a24dfee4cc9d39e545f74727717","src/blockdata/script/witness_version.rs":"27befeebb56b46d0e67da4c86af7556ce91e571b2f7220dc9842ef33bf75a6d6","src/blockdata/transaction.rs":"2e5cd2614aa667a2cf9da4b87cfc7fd17fbf26fc610a1ba79c0dce6f2e70be8d","src/blockdata/witness.rs":"42c72e4d8c17ddc85fc9324df23dfcef2be78c7a8efb5c1bc31cb76b04e817e8","src/consensus/encode.rs":"7cec2f6d236f3413db09b3b0aaca0b50fc66e7582bd3b381e9141708ed140b04","src/consensus/mod.rs":"68b9861848837f16b3d9df0c17e0763fa8ffa3d36b5681944bf678c118f3b9d5","src/consensus/params.rs":"598e3a57fd88f26e8c51ada064586a1f76f1c7845f0798a0e2479925084b5b8a","src/consensus/serde.rs":"2419548662071ccd7b35408f57078625208dbb3e50690f7b02dcee806e81326b","src/consensus/validation.rs":"242397674c8f79f27ae1c6848590b64650ab41124463dfed7a98a75bdf4f5e49","src/crypto/ecdsa.rs":"972d205b4b2b84abd203655faed1885aa9fc9337d0863f0789a45af45926d792","src/crypto/key.rs":"d4d6fbbc98e0bea0d30de71a446b2f0d28babd630ded962248aa100c242e635d","src/crypto/mod.rs":"49b9ad7d99c9ed4f346d12f8d59c4394de7e603253c5a8a3781b7e255cf50fc9","src/crypto/sighash.rs":"1c85d0bc2b24bf84f10e3819f9930b202713cd12be2b1655d2543b65a46c8687","src/crypto/taproot.rs":"0e657b6edc304a9d5e63bf2b30351acc845d6d33bc02c6c40dd05b79bc97b148","src/error.rs":"f5d5223287d6738e7a546891c869cf19f5f3e4f4d5ba2333ceed7a8873d05838","src/hash_types.rs":"6eb1c61f9a6f7b3bbb1527294d4452ea95ccd34b43180d44212b0fbb5da27dc5","src/internal_macros.rs":"28c10be127a9eb5bdcabeedd7551d337d038509ab421e04eb27727f7d8ab3666","src/lib.rs":"326680ed40a36b8f01f84dc33c1b6ea7790cd889f69168dd54021f5931e468f7","src/merkle_tree/block.rs":"57c513bf54ae041675ca7f53edaa6cb99808df4826c5879119a248ce3ea87bce","src/merkle_tree/mod.rs":"053ed9969f5f9314c2e360858c1e96c5a507d253eeb8bf9e8ea49cba5f2244fa","src/network.rs":"69d4aefc060b9b3198de4763ba26163b76c2f8b81b5b5af66faaeb6673bd1fe2","src/p2p/address.rs":"f347f089e2578ca22a14d12ed54dee27ba133f1f6fae3794b4dc73b5634cc6a5","src/p2p/message.rs":"0926118843037a20e4f1faba569d9aa8f82b4fa471eaea4e779d45ee4fe934dc","src/p2p/message_blockdata.rs":"cc3173f66e8599c2917fc002a74b838fd4267bef21954f83d4b44020af7d2a75","src/p2p/message_bloom.rs":"8d6db7b03395c8f492f5875b1301a0f6df76ce75b6b6f4c9510129c65e172886","src/p2p/message_compact_blocks.rs":"50969b9c33663d1e451810823a690da088037f45e4228d3c97468c2d056ddfad","src/p2p/message_filter.rs":"a989c370691d90645a17dfdd0e934ee2ef997e005b4827af83535262e439e4b0","src/p2p/message_network.rs":"ed1890a9e9c99738a24beee9aab4772e69a7f391f6ed4d23e5d4e54b3307072c","src/p2p/mod.rs":"8c6e6c2a36bbae037089694eafd9d284112f5dbe5626ee63698f503e114503ff","src/policy.rs":"297f4606519f911ad485eb1c650412a5b805a189496f8a6d498ec861b941e14c","src/pow.rs":"fc61b03d8be8be29c3c4dae809c79864de3dfa9ec890971d5a2701916443c557","src/psbt/error.rs":"4c86d438773acc195f35e0e94e1b96575e6d3f238931f3c856256fb6ca4d3d22","src/psbt/macros.rs":"2039d9005c3a7db566ee9487b3e2afc8ffd32da156d716caa0c02a4f10d4f5a2","src/psbt/map/global.rs":"a0555d03e0e72429ee229b781fe0bcd3763587060545e81b26f7f9df3c44abd2","src/psbt/map/input.rs":"3057a10ec887cc0ee14aa228c7f9b71c2fc860ab6d2215d5f9f3a399ff798ad9","src/psbt/map/mod.rs":"6b36b5e47683c3d8118825623e0ae4930552368008ffa9262c9d9f2865c7799c","src/psbt/map/output.rs":"cd3469bd0750591301c87821607590916531b4e615f377990955fb3c20b583b5","src/psbt/mod.rs":"ec67c0593c2fab795d628304aa5e6eb16c01cab5a1c8986cf6f975fd43ff3257","src/psbt/raw.rs":"2de9e2692340a8992b7cb8c48de0a865a0170e0e15a3acfe55606b6bd0f5fd8e","src/psbt/serialize.rs":"405d55b2f9c5db3120c766e20c9743f49da055f9944fd59fe68af654d1632da2","src/serde_utils.rs":"601ad184ed32c8ed2897664736ec33c1d6d2ef4b7c4529dc2f20ca42fae9b8e5","src/sign_message.rs":"dd6b9563aacc097c07ec10cfffd24b23143246dbeb0a0fd5ed6e71c01104b6d5","src/taproot/merkle_branch.rs":"c8a0f1a088dfd4c0b385886f6e4cb58e78736b89d384387b321876203093d7c0","src/taproot/mod.rs":"bbee8329e9469bc2606884eaa34a5cfa843d5836f75833705c4821b954af4b16","src/taproot/serialized_signature.rs":"bd69a38179816c0256c1bb44266d956eee5aad49ce5210459d7c7edfa50c3ef2","src/test_macros.rs":"e13805bced0ae5d97a4115018a48ac627facbcfd61c23c9132bb3c97e093ed69"},"package":"0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945"}
\ No newline at end of file
diff --git a/external/vendor/bitcoin/CHANGELOG.md b/external/vendor/bitcoin/CHANGELOG.md
index 10f3755..caa0de7 100644
--- a/external/vendor/bitcoin/CHANGELOG.md
+++ b/external/vendor/bitcoin/CHANGELOG.md
@@ -1,3 +1,36 @@
+# 0.32.7 - 2025-07-30
+
+- Backport - Use `_u32` in `FeeRate` constructor instead of `_unchecked` [#4552](https://github.com/rust-bitcoin/rust-bitcoin/pull/4552)
+- Backport - Add support for pay to anchor outputs [#4691](https://github.com/rust-bitcoin/rust-bitcoin/pull/4691)
+- Backport - Remove `non_exhaustive` from `Network` [#4658](https://github.com/rust-bitcoin/rust-bitcoin/pull/4658)
+
+# 0.32.6 - 2025-05-06
+
+- Backport - Fix `is_invalid_use_of_sighash_single()` incompatibility with Bitcoin Core [#4122](https://github.com/rust-bitcoin/rust-bitcoin/pull/4122)
+- Backport - Backport witness fixes [#4101](https://github.com/rust-bitcoin/rust-bitcoin/pull/4101)
+- Backport - bip32: Return error when attempting to derive past maximum depth [#4434](https://github.com/rust-bitcoin/rust-bitcoin/pull/4434)
+- Backport - Add `XOnlyPublicKey` support for PSBT key retrieval and improve Taproot signing [#4443](https://github.com/rust-bitcoin/rust-bitcoin/pull/4443)
+- Backport - Add methods to retrieve inner types [#4450](https://github.com/rust-bitcoin/rust-bitcoin/pull/4450)
+
+# 0.32.5 - 2024-11-27
+
+- Backport - Re-export `bech32` crate [#3662](https://github.com/rust-bitcoin/rust-bitcoin/pull/3662)
+- Backport - Add API for extracting the inner payload of `RawNetworkMessage` [#3523](https://github.com/rust-bitcoin/rust-bitcoin/pull/3523)
+- Backport - Fix bug in witness stack getters [#3626](https://github.com/rust-bitcoin/rust-bitcoin/pull/3626)
+- Backport - address: Add `Address::into_unchecked` [#3655](https://github.com/rust-bitcoin/rust-bitcoin/pull/3655)
+
+# 0.32.4 - 2024-10-24
+
+- Bound decode methods on `Read`, rather than `BufRead` [#3173](https://github.com/rust-bitcoin/rust-bitcoin/pull/3173)
+- Backport - Some additional inspectors on `Script` and `Witness` [#2646](https://github.com/rust-bitcoin/rust-bitcoin/pull/2646)
+- Backport - Add difficulty adjustment calculation [#3494](https://github.com/rust-bitcoin/rust-bitcoin/pull/3494)
+- Backport - Add testnet 4 support [#3453](https://github.com/rust-bitcoin/rust-bitcoin/pull/3453)
+- Backport - CI: Copy main workflow from master [#3418](https://github.com/rust-bitcoin/rust-bitcoin/pull/3418)
+
+# 0.32.3 - 2024-09-27
+
+- Backport BIP-32 alias' without typo [#3252](https://github.com/rust-bitcoin/rust-bitcoin/pull/3252)
+
# 0.32.2 - 2024-06-07
- Fix a bug when parsing 256-bit numeric types [#2837](https://github.com/rust-bitcoin/rust-bitcoin/pull/2837)
diff --git a/external/vendor/bitcoin/Cargo.lock b/external/vendor/bitcoin/Cargo.lock
index 199e4ea..11f22c0 100644
--- a/external/vendor/bitcoin/Cargo.lock
+++ b/external/vendor/bitcoin/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "arrayvec"
-version = "0.7.4"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "base58ck"
@@ -41,7 +41,7 @@ dependencies = [
[[package]]
name = "bitcoin"
-version = "0.32.2"
+version = "0.32.7"
dependencies = [
"base58ck",
"base64",
@@ -72,15 +72,15 @@ dependencies = [
[[package]]
name = "bitcoin-io"
-version = "0.1.2"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "340e09e8399c7bd8912f495af6aa58bea0c9214773417ffaa8f6460f93aaee56"
+checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf"
[[package]]
name = "bitcoin-units"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb54da0b28892f3c52203a7191534033e051b6f4b52bc15480681b57b7e036f5"
+checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2"
dependencies = [
"bitcoin-internals",
"serde",
@@ -108,21 +108,24 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.99"
+version = "1.2.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
+checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2"
+dependencies = [
+ "shlex",
+]
[[package]]
name = "cfg-if"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "getrandom"
-version = "0.2.15"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
@@ -146,15 +149,21 @@ checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd"
[[package]]
name = "itoa"
-version = "1.0.11"
+version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "libc"
-version = "0.2.155"
+version = "0.2.174"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
+
+[[package]]
+name = "memchr"
+version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "ordered"
@@ -164,24 +173,27 @@ checksum = "7f0642533dea0bb58bd5cae31bafc1872429f0f12ac8c61fe2b4ba44f80b959b"
[[package]]
name = "ppv-lite86"
-version = "0.2.17"
+version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
[[package]]
name = "proc-macro2"
-version = "1.0.85"
+version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.36"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
@@ -218,15 +230,15 @@ dependencies = [
[[package]]
name = "ryu"
-version = "1.0.18"
+version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "secp256k1"
-version = "0.29.0"
+version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3"
+checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113"
dependencies = [
"bitcoin_hashes",
"rand",
@@ -236,27 +248,27 @@ dependencies = [
[[package]]
name = "secp256k1-sys"
-version = "0.10.0"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b"
+checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9"
dependencies = [
"cc",
]
[[package]]
name = "serde"
-version = "1.0.203"
+version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.203"
+version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
@@ -265,29 +277,36 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.117"
+version = "1.0.142"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
+checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
dependencies = [
"itoa",
+ "memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_test"
-version = "1.0.176"
+version = "1.0.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab"
+checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed"
dependencies = [
"serde",
]
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
[[package]]
name = "syn"
-version = "2.0.66"
+version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [
"proc-macro2",
"quote",
@@ -296,12 +315,32 @@ dependencies = [
[[package]]
name = "unicode-ident"
-version = "1.0.12"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/external/vendor/bitcoin/Cargo.toml b/external/vendor/bitcoin/Cargo.toml
index 7ffe1f9..1904bc3 100644
--- a/external/vendor/bitcoin/Cargo.toml
+++ b/external/vendor/bitcoin/Cargo.toml
@@ -13,12 +13,18 @@
edition = "2021"
rust-version = "1.56.1"
name = "bitcoin"
-version = "0.32.2"
+version = "0.32.7"
authors = ["Andrew Poelstra <apoelstra@wpsoftware.net>"]
+build = "build.rs"
exclude = [
"tests",
"contrib",
]
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
description = "General purpose library for using and interoperating with Bitcoin."
documentation = "https://docs.rs/bitcoin/"
readme = "README.md"
@@ -37,25 +43,71 @@ rustdoc-args = [
"docsrs",
]
+[features]
+bitcoinconsensus-std = [
+ "bitcoinconsensus/std",
+ "std",
+]
+default = [
+ "std",
+ "secp-recovery",
+]
+rand = ["secp256k1/rand"]
+rand-std = [
+ "secp256k1/rand-std",
+ "std",
+]
+secp-lowmemory = ["secp256k1/lowmemory"]
+secp-recovery = ["secp256k1/recovery"]
+serde = [
+ "actual-serde",
+ "hashes/serde",
+ "secp256k1/serde",
+ "internals/serde",
+ "units/serde",
+]
+std = [
+ "base58/std",
+ "bech32/std",
+ "hashes/std",
+ "hex/std",
+ "internals/std",
+ "io/std",
+ "secp256k1/std",
+ "units/std",
+]
+
+[lib]
+name = "bitcoin"
+path = "src/lib.rs"
+
[[example]]
name = "bip32"
+path = "examples/bip32.rs"
[[example]]
-name = "handshake"
+name = "ecdsa-psbt"
+path = "examples/ecdsa-psbt.rs"
required-features = [
"std",
- "rand-std",
+ "bitcoinconsensus",
]
[[example]]
-name = "ecdsa-psbt"
+name = "handshake"
+path = "examples/handshake.rs"
required-features = [
"std",
- "bitcoinconsensus",
+ "rand-std",
]
+[[example]]
+name = "sighash"
+path = "examples/sighash.rs"
+
[[example]]
name = "sign-tx-segwit-v0"
+path = "examples/sign-tx-segwit-v0.rs"
required-features = [
"std",
"rand-std",
@@ -63,6 +115,7 @@ required-features = [
[[example]]
name = "sign-tx-taproot"
+path = "examples/sign-tx-taproot.rs"
required-features = [
"std",
"rand-std",
@@ -70,15 +123,13 @@ required-features = [
[[example]]
name = "taproot-psbt"
+path = "examples/taproot-psbt.rs"
required-features = [
"std",
"rand-std",
"bitcoinconsensus",
]
-[[example]]
-name = "sighash"
-
[dependencies.actual-serde]
version = "1.0.103"
features = [
@@ -164,38 +215,16 @@ version = "1.0.0"
[dev-dependencies.serde_test]
version = "1.0.19"
-[features]
-bitcoinconsensus-std = [
- "bitcoinconsensus/std",
- "std",
-]
-default = [
- "std",
- "secp-recovery",
-]
-rand = ["secp256k1/rand"]
-rand-std = [
- "secp256k1/rand-std",
- "std",
-]
-secp-lowmemory = ["secp256k1/lowmemory"]
-secp-recovery = ["secp256k1/recovery"]
-serde = [
- "actual-serde",
- "hashes/serde",
- "secp256k1/serde",
- "internals/serde",
- "units/serde",
-]
-std = [
- "base58/std",
- "bech32/std",
- "hashes/std",
- "hex/std",
- "internals/std",
- "io/std",
- "secp256k1/std",
- "units/std",
-]
-
[target."cfg(mutate)".dev-dependencies]
+
+[lints.rust.unexpected_cfgs]
+level = "deny"
+priority = 0
+check-cfg = [
+ "cfg(bench)",
+ "cfg(fuzzing)",
+ "cfg(kani)",
+ "cfg(mutate)",
+ "cfg(rust_v_1_60)",
+ "cfg(rust_v_1_61)",
+]
diff --git a/external/vendor/bitcoin/examples/ecdsa-psbt.rs b/external/vendor/bitcoin/examples/ecdsa-psbt.rs
index 4de4cf6..cd68010 100644
--- a/external/vendor/bitcoin/examples/ecdsa-psbt.rs
+++ b/external/vendor/bitcoin/examples/ecdsa-psbt.rs
@@ -232,7 +232,7 @@ impl WatchOnly {
let sigs: Vec<_> = psbt.inputs[0].partial_sigs.values().collect();
let mut script_witness: Witness = Witness::new();
- script_witness.push(&sigs[0].to_vec());
+ script_witness.push(sigs[0].to_vec());
script_witness.push(self.input_xpub.to_pub().to_bytes());
psbt.inputs[0].final_script_witness = Some(script_witness);
diff --git a/external/vendor/bitcoin/examples/sign-tx-taproot.rs b/external/vendor/bitcoin/examples/sign-tx-taproot.rs
index 3221c56..9dae0b2 100644
--- a/external/vendor/bitcoin/examples/sign-tx-taproot.rs
+++ b/external/vendor/bitcoin/examples/sign-tx-taproot.rs
@@ -72,7 +72,7 @@ fn main() {
// Sign the sighash using the secp256k1 library (exported by rust-bitcoin).
let tweaked: TweakedKeypair = keypair.tap_tweak(&secp, None);
let msg = Message::from(sighash);
- let signature = secp.sign_schnorr(&msg, &tweaked.to_inner());
+ let signature = secp.sign_schnorr(&msg, tweaked.as_keypair());
// Update the witness stack.
let signature = bitcoin::taproot::Signature { signature, sighash_type };
diff --git a/external/vendor/bitcoin/examples/taproot-psbt.rs b/external/vendor/bitcoin/examples/taproot-psbt.rs
index b5db05a..62f9431 100644
--- a/external/vendor/bitcoin/examples/taproot-psbt.rs
+++ b/external/vendor/bitcoin/examples/taproot-psbt.rs
@@ -734,7 +734,7 @@ fn sign_psbt_taproot(
) {
let keypair = secp256k1::Keypair::from_seckey_slice(secp, secret_key.as_ref()).unwrap();
let keypair = match leaf_hash {
- None => keypair.tap_tweak(secp, psbt_input.tap_merkle_root).to_inner(),
+ None => keypair.tap_tweak(secp, psbt_input.tap_merkle_root).to_keypair(),
Some(_) => keypair, // no tweak for script spend
};
diff --git a/external/vendor/bitcoin/src/address/mod.rs b/external/vendor/bitcoin/src/address/mod.rs
index e74cda6..c05f32a 100644
--- a/external/vendor/bitcoin/src/address/mod.rs
+++ b/external/vendor/bitcoin/src/address/mod.rs
@@ -74,6 +74,8 @@ pub enum AddressType {
P2wsh,
/// Pay to taproot.
P2tr,
+ /// Pay to anchor.
+ P2a
}
impl fmt::Display for AddressType {
@@ -84,6 +86,7 @@ impl fmt::Display for AddressType {
AddressType::P2wpkh => "p2wpkh",
AddressType::P2wsh => "p2wsh",
AddressType::P2tr => "p2tr",
+ AddressType::P2a => "p2a",
})
}
}
@@ -97,6 +100,7 @@ impl FromStr for AddressType {
"p2wpkh" => Ok(AddressType::P2wpkh),
"p2wsh" => Ok(AddressType::P2wsh),
"p2tr" => Ok(AddressType::P2tr),
+ "p2a" => Ok(AddressType::P2a),
_ => Err(UnknownAddressTypeError(s.to_owned())),
}
}
@@ -190,7 +194,7 @@ impl fmt::Display for AddressInner {
pub enum KnownHrp {
/// The main Bitcoin network.
Mainnet,
- /// The test networks, testnet and signet.
+ /// The test networks, testnet (testnet3), testnet4, and signet.
Testnets,
/// The regtest network.
Regtest,
@@ -203,7 +207,7 @@ impl KnownHrp {
match network {
Bitcoin => Self::Mainnet,
- Testnet | Signet => Self::Testnets,
+ Testnet | Testnet4 | Signet => Self::Testnets,
Regtest => Self::Regtest,
}
}
@@ -319,8 +323,8 @@ pub enum AddressData {
/// ```
///
/// 2. `Debug` on `Address<NetworkUnchecked>` does not produce clean address but address wrapped by
-/// an indicator that its network has not been checked. This is to encourage programmer to properly
-/// check the network and use `Display` in user-facing context.
+/// an indicator that its network has not been checked. This is to encourage programmer to properly
+/// check the network and use `Display` in user-facing context.
///
/// ```
/// # use std::str::FromStr;
@@ -382,6 +386,9 @@ impl<V: NetworkValidation> Address<V> {
pub fn as_unchecked(&self) -> &Address<NetworkUnchecked> {
unsafe { &*(self as *const Address<V> as *const Address<NetworkUnchecked>) }
}
+
+ /// Marks the network of this address as unchecked.
+ pub fn into_unchecked(self) -> Address<NetworkUnchecked> { Address(self.0, PhantomData) }
}
/// Methods and functions that can be called only on `Address<NetworkChecked>`.
@@ -493,6 +500,8 @@ impl Address {
Some(AddressType::P2wsh)
} else if program.is_p2tr() {
Some(AddressType::P2tr)
+ } else if program.is_p2a() {
+ Some(AddressType::P2a)
} else {
None
},
@@ -704,7 +713,7 @@ impl Address<NetworkUnchecked> {
///
/// let address: Address<NetworkUnchecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap();
/// assert!(address.is_valid_for_network(Network::Bitcoin));
- /// assert_eq!(address.is_valid_for_network(Network::Testnet), false);
+ /// assert_eq!(address.is_valid_for_network(Network::Testnet4), false);
/// ```
pub fn is_valid_for_network(&self, n: Network) -> bool {
use AddressInner::*;
@@ -773,16 +782,7 @@ impl Address<NetworkUnchecked> {
/// For details about this mechanism, see section [*Parsing addresses*](Address#parsing-addresses)
/// on [`Address`].
#[inline]
- pub fn assume_checked(self) -> Address {
- use AddressInner::*;
-
- let inner = match self.0 {
- P2pkh { hash, network } => P2pkh { hash, network },
- P2sh { hash, network } => P2sh { hash, network },
- Segwit { program, hrp } => Segwit { program, hrp },
- };
- Address(inner, PhantomData)
- }
+ pub fn assume_checked(self) -> Address { Address(self.0, PhantomData) }
}
impl From<Address> for script::ScriptBuf {
@@ -1373,4 +1373,22 @@ mod tests {
}
}
}
+
+ #[test]
+ fn pay_to_anchor_address_regtest() {
+ // Verify that p2a uses the expected address for regtest.
+ // This test-vector is borrowed from the bitcoin source code.
+ let address_str = "bcrt1pfeesnyr2tx";
+
+ let script = ScriptBuf::new_p2a();
+ let address_unchecked = address_str.parse().unwrap();
+ let address = Address::from_script(&script, Network::Regtest).unwrap();
+ assert_eq!(address.as_unchecked(), &address_unchecked);
+ assert_eq!(address.to_string(), address_str);
+
+ // Verify that the address is considered standard
+ // and that the output type is P2a
+ assert!(address.is_spend_standard());
+ assert_eq!(address.address_type(), Some(AddressType::P2a));
+ }
}
diff --git a/external/vendor/bitcoin/src/bip152.rs b/external/vendor/bitcoin/src/bip152.rs
index 6372896..96d4687 100644
--- a/external/vendor/bitcoin/src/bip152.rs
+++ b/external/vendor/bitcoin/src/bip152.rs
@@ -11,7 +11,7 @@ use std::error;
use hashes::{sha256, siphash24, Hash};
use internals::impl_array_newtype;
-use io::{BufRead, Write};
+use io::{Read, Write};
use crate::consensus::encode::{self, Decodable, Encodable, VarInt};
use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding};
@@ -82,7 +82,7 @@ impl Encodable for PrefilledTransaction {
impl Decodable for PrefilledTransaction {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let idx = VarInt::consensus_decode(r)?.0;
let idx = u16::try_from(idx)
.map_err(|_| encode::Error::ParseFailed("BIP152 prefilled tx index out of bounds"))?;
@@ -138,11 +138,13 @@ impl Encodable for ShortId {
impl Decodable for ShortId {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<ShortId, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<ShortId, encode::Error> {
Ok(ShortId(Decodable::consensus_decode(r)?))
}
}
+/// A structure to relay a block header, short IDs, and a select few transactions.
+///
/// A [HeaderAndShortIds] structure is used to relay a block header, the short
/// transactions IDs used for matching already-available transactions, and a
/// select few transactions which we expect a peer may be missing.
@@ -274,7 +276,7 @@ impl Encodable for BlockTransactionsRequest {
}
impl Decodable for BlockTransactionsRequest {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(BlockTransactionsRequest {
block_hash: BlockHash::consensus_decode(r)?,
indexes: {
@@ -492,7 +494,7 @@ mod test {
fn test_getblocktx_panic_when_encoding_u64_max() {
serialize(&BlockTransactionsRequest {
block_hash: Hash::all_zeros(),
- indexes: vec![core::u64::MAX],
+ indexes: vec![u64::MAX],
});
}
}
diff --git a/external/vendor/bitcoin/src/bip158.rs b/external/vendor/bitcoin/src/bip158.rs
index 66bef77..62f4e77 100644
--- a/external/vendor/bitcoin/src/bip158.rs
+++ b/external/vendor/bitcoin/src/bip158.rs
@@ -43,7 +43,7 @@ use core::fmt::{self, Display, Formatter};
use hashes::{sha256d, siphash24, Hash};
use internals::write_err;
-use io::{BufRead, Write};
+use io::{Read, Write};
use crate::blockdata::block::{Block, BlockHash};
use crate::blockdata::script::Script;
@@ -247,7 +247,7 @@ impl BlockFilterReader {
where
I: Iterator,
I::Item: Borrow<[u8]>,
- R: BufRead + ?Sized,
+ R: Read + ?Sized,
{
self.reader.match_any(reader, query)
}
@@ -257,7 +257,7 @@ impl BlockFilterReader {
where
I: Iterator,
I::Item: Borrow<[u8]>,
- R: BufRead + ?Sized,
+ R: Read + ?Sized,
{
self.reader.match_all(reader, query)
}
@@ -280,7 +280,7 @@ impl GcsFilterReader {
where
I: Iterator,
I::Item: Borrow<[u8]>,
- R: BufRead + ?Sized,
+ R: Read + ?Sized,
{
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
// map hashes to [0, n_elements << grp]
@@ -323,7 +323,7 @@ impl GcsFilterReader {
where
I: Iterator,
I::Item: Borrow<[u8]>,
- R: BufRead + ?Sized,
+ R: Read + ?Sized,
{
let n_elements: VarInt = Decodable::consensus_decode(reader).unwrap_or(VarInt(0));
// map hashes to [0, n_elements << grp]
@@ -449,7 +449,7 @@ impl GcsFilter {
/// Golomb-Rice decodes a number from a bit stream (parameter 2^k).
fn golomb_rice_decode<R>(&self, reader: &mut BitStreamReader<R>) -> Result<u64, io::Error>
where
- R: BufRead + ?Sized,
+ R: Read + ?Sized,
{
let mut q = 0u64;
while reader.read(1)? == 1 {
@@ -472,7 +472,7 @@ pub struct BitStreamReader<'a, R: ?Sized> {
reader: &'a mut R,
}
-impl<'a, R: BufRead + ?Sized> BitStreamReader<'a, R> {
+impl<'a, R: Read + ?Sized> BitStreamReader<'a, R> {
/// Creates a new [`BitStreamReader`] that reads bitwise from a given `reader`.
pub fn new(reader: &'a mut R) -> BitStreamReader<'a, R> {
BitStreamReader { buffer: [0u8], reader, offset: 8 }
diff --git a/external/vendor/bitcoin/src/bip32.rs b/external/vendor/bitcoin/src/bip32.rs
index fa019ba..ebc0dde 100644
--- a/external/vendor/bitcoin/src/bip32.rs
+++ b/external/vendor/bitcoin/src/bip32.rs
@@ -31,10 +31,18 @@ const VERSION_BYTES_TESTNETS_PRIVATE: [u8; 4] = [0x04, 0x35, 0x83, 0x94];
/// The old name for xpub, extended public key.
#[deprecated(since = "0.31.0", note = "use xpub instead")]
+pub type ExtendedPubKey = Xpub;
+
+/// The old name for xpub, extended public key (with a released typo in it).
+#[deprecated(since = "0.31.0", note = "use xpub instead")]
pub type ExtendendPubKey = Xpub;
/// The old name for xpriv, extended public key.
#[deprecated(since = "0.31.0", note = "use xpriv instead")]
+pub type ExtendedPrivKey = Xpriv;
+
+/// The old name for xpriv, extended public key (with a released typo in it).
+#[deprecated(since = "0.31.0", note = "use xpriv instead")]
pub type ExtendendPrivKey = Xpriv;
/// A chain code
@@ -170,6 +178,9 @@ impl ChildNumber {
/// Returns the child number that is a single increment from this one.
pub fn increment(self) -> Result<ChildNumber, Error> {
+ // Bare addition in this function is okay, because we have an invariant that
+ // `index` is always within [0, 2^31 - 1]. FIXME this is not actually an
+ // invariant because the fields are public.
match self {
ChildNumber::Normal { index: idx } => ChildNumber::from_normal_idx(idx + 1),
ChildNumber::Hardened { index: idx } => ChildNumber::from_hardened_idx(idx + 1),
@@ -473,6 +484,10 @@ pub type KeySource = (Fingerprint, DerivationPath);
pub enum Error {
/// A pk->pk derivation was attempted on a hardened key
CannotDeriveFromHardenedKey,
+ /// Attempted to derive a child of depth 256 or higher.
+ ///
+ /// There is no way to encode such xkeys.
+ MaximumDepthExceeded,
/// A secp256k1 error occurred
Secp256k1(secp256k1::Error),
/// A child number was provided that was out of range
@@ -504,6 +519,7 @@ impl fmt::Display for Error {
match *self {
CannotDeriveFromHardenedKey =>
f.write_str("cannot derive hardened key from public key"),
+ MaximumDepthExceeded => f.write_str("cannot derive child of depth 256 or higher"),
Secp256k1(ref e) => write_err!(f, "secp256k1 error"; e),
InvalidChildNumber(ref n) =>
write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n),
@@ -532,6 +548,7 @@ impl std::error::Error for Error {
Hex(ref e) => Some(e),
InvalidBase58PayloadLength(ref e) => Some(e),
CannotDeriveFromHardenedKey
+ | MaximumDepthExceeded
| InvalidChildNumber(_)
| InvalidChildNumberFormat
| InvalidDerivationPathFormat
@@ -628,7 +645,7 @@ impl Xpriv {
Ok(Xpriv {
network: self.network,
- depth: self.depth + 1,
+ depth: self.depth.checked_add(1).ok_or(Error::MaximumDepthExceeded)?,
parent_fingerprint: self.fingerprint(secp),
child_number: i,
private_key: tweaked,
@@ -760,7 +777,7 @@ impl Xpub {
Ok(Xpub {
network: self.network,
- depth: self.depth + 1,
+ depth: self.depth.checked_add(1).ok_or(Error::MaximumDepthExceeded)?,
parent_fingerprint: self.fingerprint(),
child_number: i,
public_key: tweaked,
diff --git a/external/vendor/bitcoin/src/blockdata/block.rs b/external/vendor/bitcoin/src/blockdata/block.rs
index ebdbfa3..ec24abb 100644
--- a/external/vendor/bitcoin/src/blockdata/block.rs
+++ b/external/vendor/bitcoin/src/blockdata/block.rs
@@ -11,7 +11,7 @@
use core::fmt;
use hashes::{sha256d, Hash, HashEngine};
-use io::{BufRead, Write};
+use io::{Read, Write};
use super::Weight;
use crate::blockdata::script;
@@ -210,7 +210,7 @@ impl Encodable for Version {
}
impl Decodable for Version {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Decodable::consensus_decode(r).map(Version)
}
}
diff --git a/external/vendor/bitcoin/src/blockdata/constants.rs b/external/vendor/bitcoin/src/blockdata/constants.rs
index d59072b..4d98ba9 100644
--- a/external/vendor/bitcoin/src/blockdata/constants.rs
+++ b/external/vendor/bitcoin/src/blockdata/constants.rs
@@ -8,7 +8,6 @@
//!
use hashes::{sha256d, Hash};
-use hex_lit::hex;
use internals::impl_array_newtype;
use crate::blockdata::block::{self, Block};
@@ -51,8 +50,28 @@ pub const MAX_SCRIPTNUM_VALUE: u32 = 0x80000000; // 2^31
/// Number of blocks needed for an output from a coinbase transaction to be spendable.
pub const COINBASE_MATURITY: u32 = 100;
+// This is the 65 byte (uncompressed) pubkey used as the one-and-only output of the genesis transaction.
+//
+// ref: https://blockstream.info/tx/4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b?expand
+// Note output script includes a leading 0x41 and trailing 0xac (added below using the `script::Builder`).
+#[rustfmt::skip]
+const GENESIS_OUTPUT_PK: [u8; 65] = [
+ 0x04,
+ 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27,
+ 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10,
+ 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6,
+ 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6,
+ 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4,
+ 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde,
+ 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57,
+ 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f
+];
+
+#[rustfmt::skip]
+const TESTNET4_GENESIS_OUTPUT_PK: [u8; 33] = [0x00; 33];
+
/// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block.
-fn bitcoin_genesis_tx() -> Transaction {
+fn bitcoin_genesis_tx(params: &Params) -> Transaction {
// Base
let mut ret = Transaction {
version: transaction::Version::ONE,
@@ -61,23 +80,34 @@ fn bitcoin_genesis_tx() -> Transaction {
output: vec![],
};
- // Inputs
- let in_script = script::Builder::new()
- .push_int(486604799)
- .push_int_non_minimal(4)
- .push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks")
- .into_script();
+ let (in_script, out_script) = {
+ match params.network {
+ Network::Testnet4 => (
+ script::Builder::new()
+ .push_int(486604799)
+ .push_int_non_minimal(4)
+ .push_slice(b"03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e")
+ .into_script(),
+ script::Builder::new().push_slice(TESTNET4_GENESIS_OUTPUT_PK).push_opcode(OP_CHECKSIG).into_script(),
+
+ ),
+ _ => (
+ script::Builder::new()
+ .push_int(486604799)
+ .push_int_non_minimal(4)
+ .push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks")
+ .into_script(),
+ script::Builder::new().push_slice(GENESIS_OUTPUT_PK).push_opcode(OP_CHECKSIG).into_script(),
+ ),
+ }
+ };
+
ret.input.push(TxIn {
previous_output: OutPoint::null(),
script_sig: in_script,
sequence: Sequence::MAX,
witness: Witness::default(),
});
-
- // Outputs
- let script_bytes = hex!("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
- let out_script =
- script::Builder::new().push_slice(script_bytes).push_opcode(OP_CHECKSIG).into_script();
ret.output.push(TxOut { value: Amount::from_sat(50 * 100_000_000), script_pubkey: out_script });
// end
@@ -86,10 +116,12 @@ fn bitcoin_genesis_tx() -> Transaction {
/// Constructs and returns the genesis block.
pub fn genesis_block(params: impl AsRef<Params>) -> Block {
- let txdata = vec![bitcoin_genesis_tx()];
+ let params = params.as_ref();
+ let txdata = vec![bitcoin_genesis_tx(params)];
let hash: sha256d::Hash = txdata[0].compute_txid().into();
- let merkle_root = hash.into();
- match params.as_ref().network {
+ let merkle_root: crate::TxMerkleNode = hash.into();
+
+ match params.network {
Network::Bitcoin => Block {
header: block::Header {
version: block::Version::ONE,
@@ -112,6 +144,17 @@ pub fn genesis_block(params: impl AsRef<Params>) -> Block {
},
txdata,
},
+ Network::Testnet4 => Block {
+ header: block::Header {
+ version: block::Version::ONE,
+ prev_blockhash: Hash::all_zeros(),
+ merkle_root,
+ time: 1714777860,
+ bits: CompactTarget::from_consensus(0x1d00ffff),
+ nonce: 393743547,
+ },
+ txdata,
+ },
Network::Signet => Block {
header: block::Header {
version: block::Version::ONE,
@@ -150,11 +193,22 @@ impl ChainHash {
111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131,
101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0,
]);
- /// `ChainHash` for testnet bitcoin.
+ /// `ChainHash` for testnet3 bitcoin.
+ #[deprecated(since = "0.32.4", note = "Use TESTNET3 instead")]
pub const TESTNET: Self = Self([
67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151,
32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0,
]);
+ /// `ChainHash` for testnet3 bitcoin.
+ pub const TESTNET3: Self = Self([
+ 67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151,
+ 32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0,
+ ]);
+ /// `ChainHash` for testnet4 bitcoin.
+ pub const TESTNET4: Self = Self([
+ 67, 240, 139, 218, 176, 80, 227, 91, 86, 124, 134, 75, 145, 244, 127, 80, 174, 114, 90,
+ 226, 222, 83, 188, 251, 186, 242, 132, 218, 0, 0, 0, 0,
+ ]);
/// `ChainHash` for signet bitcoin.
pub const SIGNET: Self = Self([
246, 30, 238, 59, 99, 163, 128, 164, 119, 160, 99, 175, 50, 178, 187, 201, 124, 159, 249,
@@ -171,9 +225,13 @@ impl ChainHash {
/// See [BOLT 0](https://github.com/lightning/bolts/blob/ffeece3dab1c52efdb9b53ae476539320fa44938/00-introduction.md#chain_hash)
/// for specification.
pub fn using_genesis_block(params: impl AsRef<Params>) -> Self {
- let network = params.as_ref().network;
- let hashes = [Self::BITCOIN, Self::TESTNET, Self::SIGNET, Self::REGTEST];
- hashes[network as usize]
+ match params.as_ref().network {
+ Network::Bitcoin => Self::BITCOIN,
+ Network::Testnet => Self::TESTNET3,
+ Network::Testnet4 => Self::TESTNET4,
+ Network::Signet => Self::SIGNET,
+ Network::Regtest => Self::REGTEST,
+ }
}
/// Returns the hash of the `network` genesis block for use as a chain hash.
@@ -181,8 +239,13 @@ impl ChainHash {
/// See [BOLT 0](https://github.com/lightning/bolts/blob/ffeece3dab1c52efdb9b53ae476539320fa44938/00-introduction.md#chain_hash)
/// for specification.
pub const fn using_genesis_block_const(network: Network) -> Self {
- let hashes = [Self::BITCOIN, Self::TESTNET, Self::SIGNET, Self::REGTEST];
- hashes[network as usize]
+ match network {
+ Network::Bitcoin => Self::BITCOIN,
+ Network::Testnet => Self::TESTNET3,
+ Network::Testnet4 => Self::TESTNET4,
+ Network::Signet => Self::SIGNET,
+ Network::Regtest => Self::REGTEST,
+ }
}
/// Converts genesis block hash into `ChainHash`.
@@ -203,7 +266,7 @@ mod test {
#[test]
fn bitcoin_genesis_first_transaction() {
- let gen = bitcoin_genesis_tx();
+ let gen = bitcoin_genesis_tx(&Params::MAINNET);
assert_eq!(gen.version, transaction::Version::ONE);
assert_eq!(gen.input.len(), 1);
@@ -259,7 +322,7 @@ mod test {
#[test]
fn testnet_genesis_full_block() {
- let gen = genesis_block(¶ms::TESTNET);
+ let gen = genesis_block(¶ms::TESTNET3);
assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(
@@ -314,6 +377,7 @@ mod test {
match network {
Network::Bitcoin => {},
Network::Testnet => {},
+ Network::Testnet4 => {},
Network::Signet => {},
Network::Regtest => {},
_ => panic!("Update ChainHash::using_genesis_block and chain_hash_genesis_block with new variants"),
@@ -334,6 +398,7 @@ mod test {
chain_hash_genesis_block! {
mainnet_chain_hash_genesis_block, Network::Bitcoin;
testnet_chain_hash_genesis_block, Network::Testnet;
+ testnet4_chain_hash_genesis_block, Network::Testnet4;
signet_chain_hash_genesis_block, Network::Signet;
regtest_chain_hash_genesis_block, Network::Regtest;
}
diff --git a/external/vendor/bitcoin/src/blockdata/locktime/absolute.rs b/external/vendor/bitcoin/src/blockdata/locktime/absolute.rs
index 70d920f..074ca26 100644
--- a/external/vendor/bitcoin/src/blockdata/locktime/absolute.rs
+++ b/external/vendor/bitcoin/src/blockdata/locktime/absolute.rs
@@ -8,16 +8,18 @@
use core::cmp::Ordering;
use core::fmt;
+use core::str::FromStr;
-use io::{BufRead, Write};
+use io::{Read, Write};
#[cfg(all(test, mutate))]
use mutagen::mutate;
-use units::parse;
+use units::parse::{self, ParseIntError};
#[cfg(doc)]
use crate::absolute;
use crate::consensus::encode::{self, Decodable, Encodable};
use crate::error::{ContainsPrefixError, MissingPrefixError, PrefixedHexError, UnprefixedHexError};
+use crate::prelude::{Box, String};
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
@@ -284,7 +286,37 @@ impl LockTime {
}
}
-units::impl_parse_str_from_int_infallible!(LockTime, u32, from_consensus);
+impl FromStr for LockTime {
+ type Err = ParseIntError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ parse::int::<u32, &str>(s).map(LockTime::from_consensus)
+ }
+}
+
+impl TryFrom<&str> for LockTime {
+ type Error = ParseIntError;
+
+ fn try_from(s: &str) -> Result<Self, Self::Error> {
+ LockTime::from_str(s)
+ }
+}
+
+impl TryFrom<String> for LockTime {
+ type Error = ParseIntError;
+
+ fn try_from(s: String) -> Result<Self, Self::Error> {
+ LockTime::from_str(&s)
+ }
+}
+
+impl TryFrom<Box<str>> for LockTime {
+ type Error = ParseIntError;
+
+ fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
+ LockTime::from_str(&s)
+ }
+}
impl From<Height> for LockTime {
#[inline]
@@ -348,7 +380,7 @@ impl Encodable for LockTime {
impl Decodable for LockTime {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
u32::consensus_decode(r).map(LockTime::from_consensus)
}
}
diff --git a/external/vendor/bitcoin/src/blockdata/script/borrowed.rs b/external/vendor/bitcoin/src/blockdata/script/borrowed.rs
index f07858d..541d32b 100644
--- a/external/vendor/bitcoin/src/blockdata/script/borrowed.rs
+++ b/external/vendor/bitcoin/src/blockdata/script/borrowed.rs
@@ -394,6 +394,25 @@ impl Script {
}
}
+ /// Get redeemScript following BIP16 rules regarding P2SH spending.
+ ///
+ /// This does not guarantee that this represents a P2SH input [`Script`].
+ /// It merely gets the last push of the script. Use
+ /// [`Script::is_p2sh`](crate::blockdata::script::Script::is_p2sh) on the
+ /// scriptPubKey to check whether it is actually a P2SH script.
+ pub fn redeem_script(&self) -> Option<&Script> {
+ // Script must consist entirely of pushes.
+ if self.instructions().any(|i| i.is_err() || i.unwrap().push_bytes().is_none()) {
+ return None;
+ }
+
+ if let Some(Ok(Instruction::PushBytes(b))) = self.instructions().last() {
+ Some(Script::from_bytes(b.as_bytes()))
+ } else {
+ None
+ }
+ }
+
/// Returns the minimum value an output with this script should have in order to be
/// broadcastable on today’s Bitcoin network.
#[deprecated(since = "0.32.0", note = "use minimal_non_dust and friends")]
diff --git a/external/vendor/bitcoin/src/blockdata/script/mod.rs b/external/vendor/bitcoin/src/blockdata/script/mod.rs
index d0662d9..c4b235d 100644
--- a/external/vendor/bitcoin/src/blockdata/script/mod.rs
+++ b/external/vendor/bitcoin/src/blockdata/script/mod.rs
@@ -65,7 +65,7 @@ use core::fmt;
use core::ops::{Deref, DerefMut};
use hashes::{hash160, sha256};
-use io::{BufRead, Write};
+use io::{Read, Write};
use crate::blockdata::opcodes::all::*;
use crate::blockdata::opcodes::{self, Opcode};
@@ -591,7 +591,7 @@ impl Encodable for ScriptBuf {
impl Decodable for ScriptBuf {
#[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?))
diff --git a/external/vendor/bitcoin/src/blockdata/script/owned.rs b/external/vendor/bitcoin/src/blockdata/script/owned.rs
index d718948..829ead8 100644
--- a/external/vendor/bitcoin/src/blockdata/script/owned.rs
+++ b/external/vendor/bitcoin/src/blockdata/script/owned.rs
@@ -8,7 +8,7 @@ use secp256k1::{Secp256k1, Verification};
use crate::blockdata::opcodes::all::*;
use crate::blockdata::opcodes::{self, Opcode};
-use crate::blockdata::script::witness_program::WitnessProgram;
+use crate::blockdata::script::witness_program::{WitnessProgram, P2A_PROGRAM};
use crate::blockdata::script::witness_version::WitnessVersion;
use crate::blockdata::script::{
opcode_to_verify, Builder, Instruction, PushBytes, Script, ScriptHash, WScriptHash,
@@ -130,6 +130,11 @@ impl ScriptBuf {
ScriptBuf::new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize())
}
+ /// Generates pay to anchor output.
+ pub fn new_p2a() -> Self {
+ ScriptBuf::new_witness_program_unchecked(WitnessVersion::V1, P2A_PROGRAM)
+ }
+
/// Generates P2WSH-type of scriptPubkey with a given [`WitnessProgram`].
pub fn new_witness_program(witness_program: &WitnessProgram) -> Self {
Builder::new()
@@ -141,14 +146,15 @@ impl ScriptBuf {
/// Generates P2WSH-type of scriptPubkey with a given [`WitnessVersion`] and the program bytes.
/// Does not do any checks on version or program length.
///
- /// Convenience method used by `new_p2wpkh`, `new_p2wsh`, `new_p2tr`, and `new_p2tr_tweaked`.
+ /// Convenience method used by `new_p2wpkh`, `new_p2wsh`, `new_p2tr`, and `new_p2tr_tweaked`,
+ /// and `new_p2a`.
pub(crate) fn new_witness_program_unchecked<T: AsRef<PushBytes>>(
version: WitnessVersion,
program: T,
) -> Self {
let program = program.as_ref();
debug_assert!(program.len() >= 2 && program.len() <= 40);
- // In segwit v0, the program must be 20 or 32 bytes long.
+ // In SegWit v0, the program must be either 20 (P2WPKH) bytes or 32 (P2WSH) bytes long
debug_assert!(version != WitnessVersion::V0 || program.len() == 20 || program.len() == 32);
Builder::new().push_opcode(version.into()).push_slice(program).into_script()
}
diff --git a/external/vendor/bitcoin/src/blockdata/script/push_bytes.rs b/external/vendor/bitcoin/src/blockdata/script/push_bytes.rs
index 5b06671..e42e422 100644
--- a/external/vendor/bitcoin/src/blockdata/script/push_bytes.rs
+++ b/external/vendor/bitcoin/src/blockdata/script/push_bytes.rs
@@ -180,12 +180,12 @@ mod primitive {
}
}
- // Sizes up to 73 to support all pubkey and signature sizes
+ // Sizes up to 76 to support all pubkey and signature sizes
from_array! {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
- 71, 72, 73,
+ 71, 72, 73, 74, 75, 76
}
/// Owned, growable counterpart to `PushBytes`.
diff --git a/external/vendor/bitcoin/src/blockdata/script/witness_program.rs b/external/vendor/bitcoin/src/blockdata/script/witness_program.rs
index 9b76bec..2cf7101 100644
--- a/external/vendor/bitcoin/src/blockdata/script/witness_program.rs
+++ b/external/vendor/bitcoin/src/blockdata/script/witness_program.rs
@@ -24,6 +24,9 @@ pub const MIN_SIZE: usize = 2;
/// The maximum byte size of a segregated witness program.
pub const MAX_SIZE: usize = 40;
+/// The P2A program which is given by 0x4e73.
+pub(crate) const P2A_PROGRAM: [u8;2] = [78, 115];
+
/// The segregated witness program.
///
/// The segregated witness program is technically only the program bytes _excluding_ the witness
@@ -90,16 +93,23 @@ impl WitnessProgram {
merkle_root: Option<TapNodeHash>,
) -> Self {
let (output_key, _parity) = internal_key.tap_tweak(secp, merkle_root);
- let pubkey = output_key.to_inner().serialize();
+ let pubkey = output_key.as_x_only_public_key().serialize();
WitnessProgram::new_p2tr(pubkey)
}
/// Creates a pay to taproot address from a pre-tweaked output key.
pub fn p2tr_tweaked(output_key: TweakedPublicKey) -> Self {
- let pubkey = output_key.to_inner().serialize();
+ let pubkey = output_key.as_x_only_public_key().serialize();
WitnessProgram::new_p2tr(pubkey)
}
+ internals::const_tools::cond_const! {
+ /// Constructs a new pay to anchor address
+ pub const(in rust_v_1_61 = "1.61") fn p2a() -> Self {
+ WitnessProgram { version: WitnessVersion::V1, program: ArrayVec::from_slice(&P2A_PROGRAM)}
+ }
+ }
+
/// Returns the witness program version.
pub fn version(&self) -> WitnessVersion { self.version }
@@ -123,6 +133,11 @@ impl WitnessProgram {
/// Returns true if this witness program is for a P2TR output.
pub fn is_p2tr(&self) -> bool { self.version == WitnessVersion::V1 && self.program.len() == 32 }
+
+ /// Returns true if this is a pay to anchor output.
+ pub fn is_p2a(&self) -> bool {
+ self.version == WitnessVersion::V1 && self.program == P2A_PROGRAM
+ }
}
/// Witness program error.
diff --git a/external/vendor/bitcoin/src/blockdata/transaction.rs b/external/vendor/bitcoin/src/blockdata/transaction.rs
index b4633ed..1e11ac6 100644
--- a/external/vendor/bitcoin/src/blockdata/transaction.rs
+++ b/external/vendor/bitcoin/src/blockdata/transaction.rs
@@ -11,12 +11,13 @@
//! This module provides the structures and functions needed to support transactions.
//!
-use core::{cmp, fmt, str};
+use core::{cmp, fmt};
+use core::str::FromStr;
use hashes::{sha256d, Hash};
use internals::write_err;
-use io::{BufRead, Write};
-use units::parse;
+use io::{Read, Write};
+use units::parse::{self, ParseIntError};
use super::Weight;
use crate::blockdata::locktime::absolute::{self, Height, Time};
@@ -527,7 +528,37 @@ impl fmt::Debug for Sequence {
}
}
-units::impl_parse_str_from_int_infallible!(Sequence, u32, from_consensus);
+impl FromStr for Sequence {
+ type Err = ParseIntError;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ parse::int::<u32, &str>(s).map(Sequence::from_consensus)
+ }
+}
+
+impl TryFrom<&str> for Sequence {
+ type Error = ParseIntError;
+
+ fn try_from(s: &str) -> Result<Self, Self::Error> {
+ Sequence::from_str(s)
+ }
+}
+
+impl TryFrom<String> for Sequence {
+ type Error = ParseIntError;
+
+ fn try_from(s: String) -> Result<Self, Self::Error> {
+ Sequence::from_str(&s)
+ }
+}
+
+impl TryFrom<Box<str>> for Sequence {
+ type Error = ParseIntError;
+
+ fn try_from(s: Box<str>) -> Result<Self, Self::Error> {
+ Sequence::from_str(&s)
+ }
+}
/// Bitcoin transaction output.
///
@@ -1151,7 +1182,7 @@ impl Encodable for Version {
}
impl Decodable for Version {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Decodable::consensus_decode(r).map(Version)
}
}
@@ -1169,7 +1200,7 @@ impl Encodable for OutPoint {
}
}
impl Decodable for OutPoint {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(OutPoint {
txid: Decodable::consensus_decode(r)?,
vout: Decodable::consensus_decode(r)?,
@@ -1188,7 +1219,7 @@ impl Encodable for TxIn {
}
impl Decodable for TxIn {
#[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
Ok(TxIn {
@@ -1207,7 +1238,7 @@ impl Encodable for Sequence {
}
impl Decodable for Sequence {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Decodable::consensus_decode(r).map(Sequence)
}
}
@@ -1237,7 +1268,7 @@ impl Encodable for Transaction {
}
impl Decodable for Transaction {
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let version = Version::consensus_decode_from_finite_reader(r)?;
diff --git a/external/vendor/bitcoin/src/blockdata/witness.rs b/external/vendor/bitcoin/src/blockdata/witness.rs
index d617f98..77f426d 100644
--- a/external/vendor/bitcoin/src/blockdata/witness.rs
+++ b/external/vendor/bitcoin/src/blockdata/witness.rs
@@ -8,13 +8,13 @@
use core::fmt;
use core::ops::Index;
-use io::{BufRead, Write};
+use io::{Read, Write};
use crate::consensus::encode::{Error, MAX_VEC_SIZE};
use crate::consensus::{Decodable, Encodable, WriteExt};
use crate::crypto::ecdsa;
use crate::prelude::*;
-use crate::taproot::{self, TAPROOT_ANNEX_PREFIX};
+use crate::taproot::{self, LeafScript, LeafVersion, TAPROOT_ANNEX_PREFIX, TAPROOT_CONTROL_BASE_SIZE, TAPROOT_LEAF_MASK};
use crate::{Script, VarInt};
/// The Witness is the data used to unlock bitcoin since the [segwit upgrade].
@@ -124,7 +124,7 @@ pub struct Iter<'a> {
}
impl Decodable for Witness {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
let witness_elements = VarInt::consensus_decode(r)?.0 as usize;
// Minimum size of witness element is 1 byte, so if the count is
// greater than MAX_VEC_SIZE we must return an error.
@@ -380,38 +380,93 @@ impl Witness {
}
}
+ /// Returns the third-to-last element in the witness, if any.
+ pub fn third_to_last(&self) -> Option<&[u8]> {
+ if self.witness_elements <= 2 {
+ None
+ } else {
+ self.nth(self.witness_elements - 3)
+ }
+ }
+
/// Return the nth element in the witness, if any
pub fn nth(&self, index: usize) -> Option<&[u8]> {
let pos = decode_cursor(&self.content, self.indices_start, index)?;
self.element_at(pos)
}
- /// Get Tapscript following BIP341 rules regarding accounting for an annex.
+ /// Get leaf script following BIP341 rules regarding accounting for an annex.
+ ///
+ /// This method is broken: it's called `tapscript` but it's actually returning a leaf script.
+ /// We're not going to fix it because someone might be relying on it thinking leaf script and
+ /// tapscript are the same thing (they are not). Instead, this is deprecated and will be
+ /// removed in the next breaking release. You need to use `taproot_leaf_script` and if you
+ /// intended to use it as leaf script, just access the `script` field of the returned type. If
+ /// you intended tapscript specifically you have to check the version first and bail if it's not
+ /// `LeafVersion::TapScript`.
///
/// This does not guarantee that this represents a P2TR [`Witness`]. It
/// merely gets the second to last or third to last element depending on
- /// the first byte of the last element being equal to 0x50. See
- /// [Script::is_p2tr](crate::blockdata::script::Script::is_p2tr) to
- /// check whether this is actually a Taproot witness.
+ /// the first byte of the last element being equal to 0x50.
+ ///
+ /// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness.
+ #[deprecated = "use `taproot_leaf_script` and check leaf version, if applicable"]
pub fn tapscript(&self) -> Option<&Script> {
- let len = self.len();
- self.last()
- .map(|last_elem| {
- // From BIP341:
- // If there are at least two witness elements, and the first byte of
- // the last element is 0x50, this last element is called annex a
- // and is removed from the witness stack.
- if len >= 2 && last_elem.first() == Some(&TAPROOT_ANNEX_PREFIX) {
- // account for the extra item removed from the end
- 3
- } else {
- // otherwise script is 2nd from last
- 2
- }
- })
- .filter(|&script_pos_from_last| len >= script_pos_from_last)
- .and_then(|script_pos_from_last| self.nth(len - script_pos_from_last))
- .map(Script::from_bytes)
+ match P2TrSpend::from_witness(self) {
+ // Note: the method is named "tapscript" but historically it was actually returning
+ // leaf script. This is broken but we now keep the behavior the same to not subtly
+ // break someone.
+ Some(P2TrSpend::Script { leaf_script, .. }) => Some(leaf_script),
+ _ => None,
+ }
+ }
+
+ /// Returns the leaf script with its version but without the merkle proof.
+ ///
+ /// This does not guarantee that this represents a P2TR [`Witness`]. It
+ /// merely gets the second to last or third to last element depending on
+ /// the first byte of the last element being equal to 0x50 and the associated
+ /// version.
+ pub fn taproot_leaf_script(&self) -> Option<LeafScript<&Script>> {
+ match P2TrSpend::from_witness(self) {
+ Some(P2TrSpend::Script { leaf_script, control_block, .. }) if control_block.len() >= TAPROOT_CONTROL_BASE_SIZE => {
+ let version = LeafVersion::from_consensus(control_block[0] & TAPROOT_LEAF_MASK).ok()?;
+ Some(LeafScript { version, script: leaf_script, })
+ },
+ _ => None,
+ }
+ }
+
+ /// Get the taproot control block following BIP341 rules.
+ ///
+ /// This does not guarantee that this represents a P2TR [`Witness`]. It
+ /// merely gets the last or second to last element depending on the first
+ /// byte of the last element being equal to 0x50.
+ ///
+ /// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness.
+ pub fn taproot_control_block(&self) -> Option<&[u8]> {
+ match P2TrSpend::from_witness(self) {
+ Some(P2TrSpend::Script { control_block, .. }) => Some(control_block),
+ _ => None,
+ }
+ }
+
+ /// Get the taproot annex following BIP341 rules.
+ ///
+ /// This does not guarantee that this represents a P2TR [`Witness`].
+ ///
+ /// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness.
+ pub fn taproot_annex(&self) -> Option<&[u8]> {
+ P2TrSpend::from_witness(self)?.annex()
+ }
+
+ /// Get the p2wsh witness script following BIP141 rules.
+ ///
+ /// This does not guarantee that this represents a P2WS [`Witness`]. See
+ /// [Script::is_p2wsh](crate::blockdata::script::Script::is_p2wsh) to
+ /// check whether this is actually a P2WSH witness.
+ pub fn witness_script(&self) -> Option<&Script> {
+ self.last().map(Script::from_bytes)
}
}
@@ -421,6 +476,88 @@ impl Index<usize> for Witness {
fn index(&self, index: usize) -> &Self::Output { self.nth(index).expect("Out of Bounds") }
}
+/// Represents a possible Taproot spend.
+///
+/// Taproot can be spent as key spend or script spend and, depending on which it is, different data
+/// is in the witness. This type helps representing that data more cleanly when parsing the witness
+/// because there are a lot of conditions that make reasoning hard. It's better to parse it at one
+/// place and pass it along.
+///
+/// This type is so far private but it could be published eventually. The design is geared towards
+/// it but it's not fully finished.
+enum P2TrSpend<'a> {
+ Key {
+ // This field is technically present in witness in case of key spend but none of our code
+ // uses it yet. Rather than deleting it, it's kept here commented as documentation and as
+ // an easy way to add it if anything needs it - by just uncommenting.
+ // signature: &'a [u8],
+ annex: Option<&'a [u8]>,
+ },
+ Script {
+ leaf_script: &'a Script,
+ control_block: &'a [u8],
+ annex: Option<&'a [u8]>,
+ },
+}
+
+impl<'a> P2TrSpend<'a> {
+ /// Parses `Witness` to determine what kind of taproot spend this is.
+ ///
+ /// Note: this assumes `witness` is a taproot spend. The function cannot figure it out for sure
+ /// (without knowing the output), so it doesn't attempt to check anything other than what is
+ /// required for the program to not crash.
+ ///
+ /// In other words, if the caller is certain that the witness is a valid p2tr spend (e.g.
+ /// obtained from Bitcoin Core) then it's OK to unwrap this but not vice versa - `Some` does
+ /// not imply correctness.
+ fn from_witness(witness: &'a Witness) -> Option<Self> {
+ // BIP341 says:
+ // If there are at least two witness elements, and the first byte of
+ // the last element is 0x50, this last element is called annex a
+ // and is removed from the witness stack.
+ //
+ // However here we're not removing anything, so we have to adjust the numbers to account
+ // for the fact that annex is still there.
+ match witness.len() {
+ 0 => None,
+ 1 => Some(P2TrSpend::Key { /* signature: witness.last().expect("len > 0") ,*/ annex: None }),
+ 2 if witness.last().expect("len > 0").starts_with(&[TAPROOT_ANNEX_PREFIX]) => {
+ let spend = P2TrSpend::Key {
+ // signature: witness.second_to_last().expect("len > 1"),
+ annex: witness.last(),
+ };
+ Some(spend)
+ },
+ // 2 => this is script spend without annex - same as when there are 3+ elements and the
+ // last one does NOT start with TAPROOT_ANNEX_PREFIX. This is handled in the catchall
+ // arm.
+ 3.. if witness.last().expect("len > 0").starts_with(&[TAPROOT_ANNEX_PREFIX]) => {
+ let spend = P2TrSpend::Script {
+ leaf_script: Script::from_bytes(witness.third_to_last().expect("len > 2")),
+ control_block: witness.second_to_last().expect("len > 1"),
+ annex: witness.last(),
+ };
+ Some(spend)
+ },
+ _ => {
+ let spend = P2TrSpend::Script {
+ leaf_script: Script::from_bytes(witness.second_to_last().expect("len > 1")),
+ control_block: witness.last().expect("len > 0"),
+ annex: None,
+ };
+ Some(spend)
+ },
+ }
+ }
+
+ fn annex(&self) -> Option<&'a [u8]> {
+ match self {
+ P2TrSpend::Key { annex, .. } => *annex,
+ P2TrSpend::Script { annex, .. } => *annex,
+ }
+ }
+}
+
impl<'a> Iterator for Iter<'a> {
type Item = &'a [u8];
@@ -702,22 +839,125 @@ mod test {
let witness_serialized: Vec<u8> = serialize(&witness_vec);
let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
- let witness = Witness {
- content: append_u32_vec(witness_serialized[1..].to_vec(), &[0, 5]),
- witness_elements: 2,
- indices_start: 7,
- };
- let witness_annex = Witness {
- content: append_u32_vec(witness_serialized_annex[1..].to_vec(), &[0, 5, 7]),
- witness_elements: 3,
- indices_start: 9,
- };
+ let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
+ let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
// With or without annex, the tapscript should be returned.
assert_eq!(witness.tapscript(), Some(Script::from_bytes(&tapscript[..])));
assert_eq!(witness_annex.tapscript(), Some(Script::from_bytes(&tapscript[..])));
}
+ #[test]
+ fn test_get_tapscript_from_keypath() {
+ let signature = hex!("deadbeef");
+ // annex starting with 0x50 causes the branching logic.
+ let annex = hex!("50");
+
+ let witness_vec = vec![signature.clone()];
+ let witness_vec_annex = vec![signature.clone(), annex];
+
+ let witness_serialized: Vec<u8> = serialize(&witness_vec);
+ let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
+
+ let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
+ let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
+
+ // With or without annex, no tapscript should be returned.
+ assert_eq!(witness.tapscript(), None);
+ assert_eq!(witness_annex.tapscript(), None);
+ }
+
+ #[test]
+ fn get_taproot_leaf_script() {
+ let tapscript = hex!("deadbeef");
+ let control_block = hex!("c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ // annex starting with 0x50 causes the branching logic.
+ let annex = hex!("50");
+
+ let witness_vec = vec![tapscript.clone(), control_block.clone()];
+ let witness_vec_annex = vec![tapscript.clone(), control_block, annex];
+
+ let witness_serialized: Vec<u8> = serialize(&witness_vec);
+ let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
+
+ let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
+ let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
+
+ let expected_leaf_script = LeafScript {
+ version: LeafVersion::TapScript,
+ script: Script::from_bytes(&tapscript),
+ };
+
+ // With or without annex, the tapscript should be returned.
+ assert_eq!(witness.taproot_leaf_script().unwrap(), expected_leaf_script);
+ assert_eq!(witness_annex.taproot_leaf_script().unwrap(), expected_leaf_script);
+ }
+
+ #[test]
+ fn test_get_control_block() {
+ let tapscript = hex!("deadbeef");
+ let control_block = hex!("02");
+ // annex starting with 0x50 causes the branching logic.
+ let annex = hex!("50");
+ let signature = vec![0xff; 64];
+
+ let witness_vec = vec![tapscript.clone(), control_block.clone()];
+ let witness_vec_annex = vec![tapscript.clone(), control_block.clone(), annex.clone()];
+ let witness_vec_key_spend_annex = vec![signature, annex];
+
+ let witness_serialized: Vec<u8> = serialize(&witness_vec);
+ let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
+ let witness_serialized_key_spend_annex: Vec<u8> = serialize(&witness_vec_key_spend_annex);
+
+ let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
+ let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
+ let witness_key_spend_annex = deserialize::<Witness>(&witness_serialized_key_spend_annex[..]).unwrap();
+
+ // With or without annex, the tapscript should be returned.
+ assert_eq!(witness.taproot_control_block(), Some(&control_block[..]));
+ assert_eq!(witness_annex.taproot_control_block(), Some(&control_block[..]));
+ assert!(witness_key_spend_annex.taproot_control_block().is_none())
+ }
+
+ #[test]
+ fn test_get_annex() {
+ let tapscript = hex!("deadbeef");
+ let control_block = hex!("02");
+ // annex starting with 0x50 causes the branching logic.
+ let annex = hex!("50");
+
+ let witness_vec = vec![tapscript.clone(), control_block.clone()];
+ let witness_vec_annex = vec![tapscript.clone(), control_block.clone(), annex.clone()];
+
+ let witness_serialized: Vec<u8> = serialize(&witness_vec);
+ let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
+
+ let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
+ let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
+
+ // With or without annex, the tapscript should be returned.
+ assert_eq!(witness.taproot_annex(), None);
+ assert_eq!(witness_annex.taproot_annex(), Some(&annex[..]));
+
+ // Now for keyspend
+ let signature = hex!("deadbeef");
+ // annex starting with 0x50 causes the branching logic.
+ let annex = hex!("50");
+
+ let witness_vec = vec![signature.clone()];
+ let witness_vec_annex = vec![signature.clone(), annex.clone()];
+
+ let witness_serialized: Vec<u8> = serialize(&witness_vec);
+ let witness_serialized_annex: Vec<u8> = serialize(&witness_vec_annex);
+
+ let witness = deserialize::<Witness>(&witness_serialized[..]).unwrap();
+ let witness_annex = deserialize::<Witness>(&witness_serialized_annex[..]).unwrap();
+
+ // With or without annex, the tapscript should be returned.
+ assert_eq!(witness.taproot_annex(), None);
+ assert_eq!(witness_annex.taproot_annex(), Some(&annex[..]));
+ }
+
#[test]
fn test_tx() {
const S: &str = "02000000000102b44f26b275b8ad7b81146ba3dbecd081f9c1ea0dc05b97516f56045cfcd3df030100000000ffffffff1cb4749ae827c0b75f3d0a31e63efc8c71b47b5e3634a4c698cd53661cab09170100000000ffffffff020b3a0500000000001976a9143ea74de92762212c96f4dd66c4d72a4deb20b75788ac630500000000000016001493a8dfd1f0b6a600ab01df52b138cda0b82bb7080248304502210084622878c94f4c356ce49c8e33a063ec90f6ee9c0208540888cfab056cd1fca9022014e8dbfdfa46d318c6887afd92dcfa54510e057565e091d64d2ee3a66488f82c0121026e181ffb98ebfe5a64c983073398ea4bcd1548e7b971b4c175346a25a1c12e950247304402203ef00489a0d549114977df2820fab02df75bebb374f5eee9e615107121658cfa02204751f2d1784f8e841bff6d3bcf2396af2f1a5537c0e4397224873fbd3bfbe9cf012102ae6aa498ce2dd204e9180e71b4fb1260fe3d1a95c8025b34e56a9adf5f278af200000000";
diff --git a/external/vendor/bitcoin/src/consensus/encode.rs b/external/vendor/bitcoin/src/consensus/encode.rs
index 63b0cc8..b885e93 100644
--- a/external/vendor/bitcoin/src/consensus/encode.rs
+++ b/external/vendor/bitcoin/src/consensus/encode.rs
@@ -15,12 +15,12 @@
//! typically big-endian decimals, etc.)
//!
-use core::{fmt, mem, u32};
+use core::{fmt, mem};
use hashes::{sha256, sha256d, Hash};
use hex::error::{InvalidCharError, OddLengthStringError};
use internals::write_err;
-use io::{BufRead, Cursor, Read, Write};
+use io::{Cursor, Read, Write};
use crate::bip152::{PrefilledTransaction, ShortId};
use crate::bip158::{FilterHash, FilterHeader};
@@ -350,7 +350,7 @@ pub trait Decodable: Sized {
/// avoid creating redundant `Take` wrappers. Failure to do so might result only in a tiny
/// performance hit.
#[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
reader: &mut R,
) -> Result<Self, Error> {
// This method is always strictly less general than, `consensus_decode`, so it's safe and
@@ -368,7 +368,7 @@ pub trait Decodable: Sized {
/// for types that override [`Self::consensus_decode_from_finite_reader`]
/// instead.
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(reader: &mut R) -> Result<Self, Error> {
+ fn consensus_decode<R: Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
Self::consensus_decode_from_finite_reader(&mut reader.take(MAX_VEC_SIZE as u64))
}
}
@@ -406,7 +406,7 @@ macro_rules! impl_int_encodable {
($ty:ident, $meth_dec:ident, $meth_enc:ident) => {
impl Decodable for $ty {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(
+ fn consensus_decode<R: Read + ?Sized>(
r: &mut R,
) -> core::result::Result<Self, Error> {
ReadExt::$meth_dec(r)
@@ -494,7 +494,7 @@ impl Encodable for VarInt {
impl Decodable for VarInt {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
let n = ReadExt::read_u8(r)?;
match n {
0xFF => {
@@ -536,7 +536,7 @@ impl Encodable for bool {
impl Decodable for bool {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<bool, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<bool, Error> {
ReadExt::read_bool(r)
}
}
@@ -553,7 +553,7 @@ impl Encodable for String {
impl Decodable for String {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<String, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<String, Error> {
String::from_utf8(Decodable::consensus_decode(r)?)
.map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
}
@@ -571,7 +571,7 @@ impl Encodable for Cow<'static, str> {
impl Decodable for Cow<'static, str> {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Cow<'static, str>, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Cow<'static, str>, Error> {
String::from_utf8(Decodable::consensus_decode(r)?)
.map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
.map(Cow::Owned)
@@ -593,7 +593,7 @@ macro_rules! impl_array {
impl Decodable for [u8; $size] {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(
+ fn consensus_decode<R: Read + ?Sized>(
r: &mut R,
) -> core::result::Result<Self, Error> {
let mut ret = [0; $size];
@@ -616,7 +616,7 @@ impl_array!(33);
impl Decodable for [u16; 8] {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
let mut res = [0; 8];
for item in &mut res {
*item = Decodable::consensus_decode(r)?;
@@ -654,7 +654,7 @@ macro_rules! impl_vec {
impl Decodable for Vec<$type> {
#[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
r: &mut R,
) -> core::result::Result<Self, Error> {
let len = VarInt::consensus_decode_from_finite_reader(r)?.0;
@@ -744,7 +744,7 @@ impl Encodable for Vec<u8> {
impl Decodable for Vec<u8> {
#[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
let len = VarInt::consensus_decode(r)?.0 as usize;
// most real-world vec of bytes data, wouldn't be larger than 128KiB
let opts = ReadBytesFromFiniteReaderOpts { len, chunk_size: 128 * 1024 };
@@ -761,7 +761,7 @@ impl Encodable for Box<[u8]> {
impl Decodable for Box<[u8]> {
#[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
<Vec<u8>>::consensus_decode_from_finite_reader(r).map(From::from)
}
}
@@ -786,7 +786,7 @@ impl Encodable for CheckedData {
impl Decodable for CheckedData {
#[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
let len = u32::consensus_decode_from_finite_reader(r)? as usize;
let checksum = <[u8; 4]>::consensus_decode_from_finite_reader(r)?;
@@ -846,7 +846,7 @@ macro_rules! tuple_encode {
impl<$($x: Decodable),*> Decodable for ($($x),*) {
#[inline]
#[allow(non_snake_case)]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> core::result::Result<Self, Error> {
Ok(($({let $x = Decodable::consensus_decode(r)?; $x }),*))
}
}
@@ -868,7 +868,7 @@ impl Encodable for sha256d::Hash {
}
impl Decodable for sha256d::Hash {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
}
}
@@ -880,7 +880,7 @@ impl Encodable for sha256::Hash {
}
impl Decodable for sha256::Hash {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
}
}
@@ -892,7 +892,7 @@ impl Encodable for TapLeafHash {
}
impl Decodable for TapLeafHash {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Self::from_byte_array(<<Self as Hash>::Bytes>::consensus_decode(r)?))
}
}
diff --git a/external/vendor/bitcoin/src/consensus/params.rs b/external/vendor/bitcoin/src/consensus/params.rs
index 64d3aac..93a36c2 100644
--- a/external/vendor/bitcoin/src/consensus/params.rs
+++ b/external/vendor/bitcoin/src/consensus/params.rs
@@ -3,7 +3,7 @@
//! Bitcoin consensus parameters.
//!
//! This module provides a predefined set of parameters for different Bitcoin
-//! chains (such as mainnet, testnet).
+//! chains (such as mainnet, testnet, testnet4).
//!
use crate::network::Network;
@@ -64,8 +64,13 @@ pub struct Params {
///
/// [using-statics-or-consts]: <https://doc.rust-lang.org/reference/items/static-items.html#using-statics-or-consts>
pub static MAINNET: Params = Params::MAINNET;
-/// The testnet parameters.
-pub static TESTNET: Params = Params::TESTNET;
+/// The testnet3 parameters.
+#[deprecated(since = "0.32.4", note = "Use TESTNET3 instead")]
+pub static TESTNET: Params = Params::TESTNET3;
+/// The testnet3 parameters.
+pub static TESTNET3: Params = Params::TESTNET3;
+/// The testnet4 parameters.
+pub static TESTNET4: Params = Params::TESTNET4;
/// The signet parameters.
pub static SIGNET: Params = Params::SIGNET;
/// The regtest parameters.
@@ -93,7 +98,8 @@ impl Params {
no_pow_retargeting: false,
};
- /// The testnet parameters.
+ /// The testnet3 parameters.
+ #[deprecated(since = "0.32.4", note = "Use TESTNET3 instead")]
pub const TESTNET: Params = Params {
network: Network::Testnet,
bip16_time: 1333238400, // Apr 1 2012
@@ -110,6 +116,40 @@ impl Params {
no_pow_retargeting: false,
};
+ /// The testnet3 parameters.
+ pub const TESTNET3: Params = Params {
+ network: Network::Testnet,
+ bip16_time: 1333238400, // Apr 1 2012
+ bip34_height: 21111, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8
+ bip65_height: 581885, // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
+ bip66_height: 330776, // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
+ rule_change_activation_threshold: 1512, // 75%
+ miner_confirmation_window: 2016,
+ pow_limit: Target::MAX_ATTAINABLE_TESTNET,
+ max_attainable_target: Target::MAX_ATTAINABLE_TESTNET,
+ pow_target_spacing: 10 * 60, // 10 minutes.
+ pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks.
+ allow_min_difficulty_blocks: true,
+ no_pow_retargeting: false,
+ };
+
+ /// The testnet4 parameters.
+ pub const TESTNET4: Params = Params {
+ network: Network::Testnet4,
+ bip16_time: 1333238400, // Apr 1 2012
+ bip34_height: 1,
+ bip65_height: 1,
+ bip66_height: 1,
+ rule_change_activation_threshold: 1512, // 75%
+ miner_confirmation_window: 2016,
+ pow_limit: Target::MAX_ATTAINABLE_TESTNET,
+ max_attainable_target: Target::MAX_ATTAINABLE_TESTNET,
+ pow_target_spacing: 10 * 60, // 10 minutes.
+ pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks.
+ allow_min_difficulty_blocks: true,
+ no_pow_retargeting: false,
+ };
+
/// The signet parameters.
pub const SIGNET: Params = Params {
network: Network::Signet,
@@ -144,11 +184,12 @@ impl Params {
no_pow_retargeting: true,
};
- /// Creates parameters set for the given network. /// Creates parameters set for the given network.
+ /// Creates parameters set for the given network.
pub const fn new(network: Network) -> Self {
match network {
Network::Bitcoin => Params::MAINNET,
- Network::Testnet => Params::TESTNET,
+ Network::Testnet => Params::TESTNET3,
+ Network::Testnet4 => Params::TESTNET4,
Network::Signet => Params::SIGNET,
Network::Regtest => Params::REGTEST,
}
@@ -181,12 +222,5 @@ impl AsRef<Params> for Params {
}
impl AsRef<Params> for Network {
- fn as_ref(&self) -> &Params {
- match *self {
- Network::Bitcoin => &MAINNET,
- Network::Testnet => &TESTNET,
- Network::Signet => &SIGNET,
- Network::Regtest => ®TEST,
- }
- }
+ fn as_ref(&self) -> &Params { Self::params(*self) }
}
diff --git a/external/vendor/bitcoin/src/crypto/key.rs b/external/vendor/bitcoin/src/crypto/key.rs
index 5d8abc6..3ac16a5 100644
--- a/external/vendor/bitcoin/src/crypto/key.rs
+++ b/external/vendor/bitcoin/src/crypto/key.rs
@@ -496,6 +496,20 @@ impl PrivateKey {
inner: secp256k1::SecretKey::from_slice(&data[1..33])?,
})
}
+
+ /// Returns a new private key with the negated secret value.
+ ///
+ /// The resulting key corresponds to the same x-only public key (identical x-coordinate)
+ /// but with the opposite y-coordinate parity. This is useful for ensuring compatibility
+ /// with specific public key formats and BIP-340 requirements.
+ #[inline]
+ pub fn negate(&self) -> Self {
+ PrivateKey {
+ compressed: self.compressed,
+ network: self.network,
+ inner: self.inner.negate(),
+ }
+ }
}
impl fmt::Display for PrivateKey {
@@ -803,9 +817,11 @@ impl TapTweak for UntweakedKeypair {
/// * p is the internal private key
/// * H is the hash function
/// * c is the commitment data
+ ///
/// The public key is generated from a private key by multiplying with generator point, Q = qG.
///
/// # Returns
+ ///
/// The tweaked key and its parity.
fn tap_tweak<C: Verification>(
self,
@@ -839,9 +855,18 @@ impl TweakedPublicKey {
TweakedPublicKey(key)
}
- /// Returns the underlying public key.
+ #[doc(hidden)]
+ #[deprecated(since="0.32.6", note="use to_x_only_public_key() instead")]
pub fn to_inner(self) -> XOnlyPublicKey { self.0 }
+ /// Returns the underlying x-only public key.
+ #[inline]
+ pub fn to_x_only_public_key(self) -> XOnlyPublicKey { self.0 }
+
+ /// Returns a reference to the underlying x-only public key.
+ #[inline]
+ pub fn as_x_only_public_key(&self) -> &XOnlyPublicKey { &self.0 }
+
/// Serialize the key as a byte-encoded pair of values. In compressed form
/// the y-coordinate is represented by only a single bit, as x determines
/// it up to one bit.
@@ -858,9 +883,17 @@ impl TweakedKeypair {
#[inline]
pub fn dangerous_assume_tweaked(pair: Keypair) -> TweakedKeypair { TweakedKeypair(pair) }
+ #[doc(hidden)]
+ #[deprecated(since="0.32.6", note="use to_keypair() instead")]
+ pub fn to_inner(self) -> Keypair { self.0 }
+
/// Returns the underlying key pair.
#[inline]
- pub fn to_inner(self) -> Keypair { self.0 }
+ pub fn to_keypair(self) -> Keypair { self.0 }
+
+ /// Returns a reference to the underlying key pair.
+ #[inline]
+ pub fn as_keypair(&self) -> &Keypair { &self.0 }
/// Returns the [`TweakedPublicKey`] and its [`Parity`] for this [`TweakedKeypair`].
#[inline]
@@ -1521,12 +1554,12 @@ mod tests {
}
#[test]
- #[cfg(all(not(feature = "std"), feature = "no-std"))]
+ #[cfg(not(feature = "std"))]
fn private_key_debug_is_obfuscated() {
let sk =
PrivateKey::from_str("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap();
// Why is this not shortened? In rust-secp256k1/src/secret it is printed with "#{:016x}"?
- let want = "PrivateKey { compressed: true, network: Testnet, inner: SecretKey(#7217ac58fbad8880a91032107b82cb6c5422544b426c350ee005cf509f3dbf7b) }";
+ let want = "PrivateKey { compressed: true, network: Test, inner: SecretKey(#7217ac58fbad8880a91032107b82cb6c5422544b426c350ee005cf509f3dbf7b) }";
let got = format!("{:?}", sk);
assert_eq!(got, want)
}
diff --git a/external/vendor/bitcoin/src/crypto/sighash.rs b/external/vendor/bitcoin/src/crypto/sighash.rs
index b786c98..294dac7 100644
--- a/external/vendor/bitcoin/src/crypto/sighash.rs
+++ b/external/vendor/bitcoin/src/crypto/sighash.rs
@@ -400,6 +400,16 @@ impl EcdsaSighashType {
}
}
+ /// Checks if the sighash type is [`Self::Single`] or [`Self::SinglePlusAnyoneCanPay`].
+ ///
+ /// This matches Bitcoin Core's behavior where SIGHASH_SINGLE bug check is based on the base
+ /// type (after masking with 0x1f), regardless of the ANYONECANPAY flag.
+ ///
+ /// See: <https://github.com/bitcoin/bitcoin/blob/e486597/src/script/interpreter.cpp#L1618-L1619>
+ pub fn is_single(&self) -> bool {
+ matches!(self, Self::Single | Self::SinglePlusAnyoneCanPay)
+ }
+
/// Creates a [`EcdsaSighashType`] from a raw `u32`.
///
/// **Note**: this replicates consensus behaviour, for current standardness rules correctness
@@ -879,8 +889,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
/// # Warning
///
/// - Does NOT attempt to support OP_CODESEPARATOR. In general this would require evaluating
- /// `script_pubkey` to determine which separators get evaluated and which don't, which we don't
- /// have the information to determine.
+ /// `script_pubkey` to determine which separators get evaluated and which don't, which we don't
+ /// have the information to determine.
/// - Does NOT handle the sighash single bug (see "Return type" section)
///
/// # Returns
@@ -1316,7 +1326,7 @@ impl std::error::Error for AnnexError {
fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, outputs_len: usize) -> bool {
let ty = EcdsaSighashType::from_consensus(sighash);
- ty == EcdsaSighashType::Single && input_index >= outputs_len
+ ty.is_single() && input_index >= outputs_len
}
/// Result of [`SighashCache::legacy_encode_signing_data_to`].
@@ -1453,8 +1463,6 @@ mod tests {
#[test]
fn sighash_single_bug() {
- const SIGHASH_SINGLE: u32 = 3;
-
// We need a tx with more inputs than outputs.
let tx = Transaction {
version: transaction::Version::ONE,
@@ -1465,10 +1473,16 @@ mod tests {
let script = ScriptBuf::new();
let cache = SighashCache::new(&tx);
- let got = cache.legacy_signature_hash(1, &script, SIGHASH_SINGLE).expect("sighash");
- let want = LegacySighash::from_slice(&UINT256_ONE).unwrap();
+ let sighash_single = 3;
+ let got = cache.legacy_signature_hash(1, &script, sighash_single).expect("sighash");
+ let want = LegacySighash::from_byte_array(UINT256_ONE);
+ assert_eq!(got, want);
- assert_eq!(got, want)
+ // https://github.com/rust-bitcoin/rust-bitcoin/issues/4112
+ let sighash_single = 131;
+ let got = cache.legacy_signature_hash(1, &script, sighash_single).expect("sighash");
+ let want = LegacySighash::from_byte_array(UINT256_ONE);
+ assert_eq!(got, want);
}
#[test]
diff --git a/external/vendor/bitcoin/src/internal_macros.rs b/external/vendor/bitcoin/src/internal_macros.rs
index b8d2069..840a9d4 100644
--- a/external/vendor/bitcoin/src/internal_macros.rs
+++ b/external/vendor/bitcoin/src/internal_macros.rs
@@ -22,7 +22,7 @@ macro_rules! impl_consensus_encoding {
impl $crate::consensus::Decodable for $thing {
#[inline]
- fn consensus_decode_from_finite_reader<R: $crate::io::BufRead + ?Sized>(
+ fn consensus_decode_from_finite_reader<R: $crate::io::Read + ?Sized>(
r: &mut R,
) -> core::result::Result<$thing, $crate::consensus::encode::Error> {
Ok($thing {
@@ -31,7 +31,7 @@ macro_rules! impl_consensus_encoding {
}
#[inline]
- fn consensus_decode<R: $crate::io::BufRead + ?Sized>(
+ fn consensus_decode<R: $crate::io::Read + ?Sized>(
r: &mut R,
) -> core::result::Result<$thing, $crate::consensus::encode::Error> {
let mut r = r.take($crate::consensus::encode::MAX_VEC_SIZE as u64);
@@ -198,7 +198,7 @@ macro_rules! impl_hashencode {
}
impl $crate::consensus::Decodable for $hashtype {
- fn consensus_decode<R: $crate::io::BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self, $crate::consensus::encode::Error> {
+ fn consensus_decode<R: $crate::io::Read + ?Sized>(r: &mut R) -> core::result::Result<Self, $crate::consensus::encode::Error> {
use $crate::hashes::Hash;
Ok(Self::from_byte_array(<<$hashtype as $crate::hashes::Hash>::Bytes>::consensus_decode(r)?))
}
diff --git a/external/vendor/bitcoin/src/lib.rs b/external/vendor/bitcoin/src/lib.rs
index 3d10ba6..d6d99c2 100644
--- a/external/vendor/bitcoin/src/lib.rs
+++ b/external/vendor/bitcoin/src/lib.rs
@@ -41,6 +41,8 @@
#![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134
#![allow(clippy::manual_range_contains)] // More readable than clippy's format.
#![allow(clippy::needless_borrows_for_generic_args)] // https://github.com/rust-lang/rust-clippy/issues/12454
+// For 0.32.x releases only.
+#![allow(deprecated)]
// Disable 16-bit support at least for now as we can't guarantee it yet.
#[cfg(target_pointer_width = "16")]
@@ -62,6 +64,9 @@ pub extern crate base64;
/// Bitcoin base58 encoding and decoding.
pub extern crate base58;
+/// Re-export the `bech32` crate.
+pub extern crate bech32;
+
/// Rust implementation of cryptographic hash function algorithms.
pub extern crate hashes;
@@ -171,7 +176,7 @@ pub mod amount {
//! We refer to the documentation on the types for more information.
use crate::consensus::{encode, Decodable, Encodable};
- use crate::io::{BufRead, Write};
+ use crate::io::{Read, Write};
#[rustfmt::skip] // Keep public re-exports separate.
#[doc(inline)]
@@ -183,7 +188,7 @@ pub mod amount {
impl Decodable for Amount {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(Amount::from_sat(Decodable::consensus_decode(r)?))
}
}
diff --git a/external/vendor/bitcoin/src/merkle_tree/block.rs b/external/vendor/bitcoin/src/merkle_tree/block.rs
index 59c6496..4c3d2af 100644
--- a/external/vendor/bitcoin/src/merkle_tree/block.rs
+++ b/external/vendor/bitcoin/src/merkle_tree/block.rs
@@ -41,7 +41,7 @@
use core::fmt;
use hashes::Hash;
-use io::{BufRead, Write};
+use io::{Read, Write};
use self::MerkleBlockError::*;
use crate::blockdata::block::{self, Block, TxMerkleNode};
@@ -151,7 +151,7 @@ impl Encodable for MerkleBlock {
}
impl Decodable for MerkleBlock {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(MerkleBlock {
header: Decodable::consensus_decode(r)?,
txn: Decodable::consensus_decode(r)?,
@@ -191,6 +191,7 @@ impl Decodable for MerkleBlock {
/// - uint256[] hashes in depth-first order (<= 32*N bytes)
/// - varint number of bytes of flag bits (1-3 bytes)
/// - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits)
+///
/// The size constraints follow from this.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct PartialMerkleTree {
@@ -452,7 +453,7 @@ impl Encodable for PartialMerkleTree {
}
impl Decodable for PartialMerkleTree {
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let num_transactions: u32 = Decodable::consensus_decode(r)?;
diff --git a/external/vendor/bitcoin/src/network.rs b/external/vendor/bitcoin/src/network.rs
index 10fae60..8df48b0 100644
--- a/external/vendor/bitcoin/src/network.rs
+++ b/external/vendor/bitcoin/src/network.rs
@@ -53,22 +53,34 @@ impl From<Network> for NetworkKind {
match n {
Bitcoin => NetworkKind::Main,
- Testnet | Signet | Regtest => NetworkKind::Test,
+ Testnet | Testnet4 | Signet | Regtest => NetworkKind::Test,
}
}
}
/// The cryptocurrency network to act on.
+///
+/// This is an exhaustive enum, meaning that we cannot add any future networks without defining a
+/// new, incompatible version of this type. If you are using this type directly and wish to support the
+/// new network, this will be a breaking change to your APIs and likely require changes in your code.
+///
+/// If you are concerned about forward compatibility, consider using `T: Into<Params>` instead of
+/// this type as a parameter to functions in your public API, or directly using the `Params` type.
+// For extensive discussion on the usage of `non_exhaustive` please see:
+// https://github.com/rust-bitcoin/rust-bitcoin/issues/2225
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
-#[non_exhaustive]
pub enum Network {
/// Mainnet Bitcoin.
Bitcoin,
- /// Bitcoin's testnet network.
+ /// Bitcoin's testnet network. (In future versions this will be combined
+ /// into a single variant containing the version)
Testnet,
+ /// Bitcoin's testnet4 network. (In future versions this will be combined
+ /// into a single variant containing the version)
+ Testnet4,
/// Bitcoin's signet network.
Signet,
/// Bitcoin's regtest network.
@@ -115,7 +127,9 @@ impl Network {
pub fn to_core_arg(self) -> &'static str {
match self {
Network::Bitcoin => "main",
+ // For user-side compatibility, testnet3 is retained as test
Network::Testnet => "test",
+ Network::Testnet4 => "testnet4",
Network::Signet => "signet",
Network::Regtest => "regtest",
}
@@ -136,6 +150,7 @@ impl Network {
let network = match core_arg {
"main" => Bitcoin,
"test" => Testnet,
+ "testnet4" => Testnet4,
"signet" => Signet,
"regtest" => Regtest,
_ => return Err(ParseNetworkError(core_arg.to_owned())),
@@ -172,13 +187,25 @@ impl Network {
/// Returns the associated network parameters.
pub const fn params(self) -> &'static Params {
- const PARAMS: [Params; 4] = [
- Params::new(Network::Bitcoin),
- Params::new(Network::Testnet),
- Params::new(Network::Signet),
- Params::new(Network::Regtest),
- ];
- &PARAMS[self as usize]
+ match self {
+ Network::Bitcoin => &Params::BITCOIN,
+ Network::Testnet => &Params::TESTNET3,
+ Network::Testnet4 => &Params::TESTNET4,
+ Network::Signet => &Params::SIGNET,
+ Network::Regtest => &Params::REGTEST,
+ }
+ }
+
+ /// Returns a string representation of the `Network` enum variant.
+ /// This is useful for displaying the network type as a string.
+ const fn as_display_str(self) -> &'static str {
+ match self {
+ Network::Bitcoin => "bitcoin",
+ Network::Testnet => "testnet",
+ Network::Testnet4 => "testnet4",
+ Network::Signet => "signet",
+ Network::Regtest => "regtest",
+ }
}
}
@@ -209,7 +236,7 @@ pub mod as_core_arg {
Network::from_core_arg(s).map_err(|_| {
E::invalid_value(
serde::de::Unexpected::Str(s),
- &"bitcoin network encoded as a string (either main, test, signet or regtest)",
+ &"bitcoin network encoded as a string (either main, test, testnet4, signet or regtest)",
)
})
}
@@ -217,7 +244,7 @@ pub mod as_core_arg {
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
formatter,
- "bitcoin network encoded as a string (either main, test, signet or regtest)"
+ "bitcoin network encoded as a string (either main, test, testnet4, signet or regtest)"
)
}
}
@@ -247,30 +274,21 @@ impl FromStr for Network {
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
- use Network::*;
-
- let network = match s {
- "bitcoin" => Bitcoin,
- "testnet" => Testnet,
- "signet" => Signet,
- "regtest" => Regtest,
- _ => return Err(ParseNetworkError(s.to_owned())),
- };
- Ok(network)
+ match s {
+ "bitcoin" => Ok(Network::Bitcoin),
+ // For user-side compatibility, testnet3 is retained as testnet
+ "testnet" => Ok(Network::Testnet),
+ "testnet4" => Ok(Network::Testnet4),
+ "signet" => Ok(Network::Signet),
+ "regtest" => Ok(Network::Regtest),
+ _ => Err(ParseNetworkError(s.to_owned())),
+ }
}
}
impl fmt::Display for Network {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
- use Network::*;
-
- let s = match *self {
- Bitcoin => "bitcoin",
- Testnet => "testnet",
- Signet => "signet",
- Regtest => "regtest",
- };
- write!(f, "{}", s)
+ write!(f, "{}", self.as_display_str())
}
}
@@ -297,7 +315,8 @@ impl TryFrom<ChainHash> for Network {
match chain_hash {
// Note: any new network entries must be matched against here.
ChainHash::BITCOIN => Ok(Network::Bitcoin),
- ChainHash::TESTNET => Ok(Network::Testnet),
+ ChainHash::TESTNET3 => Ok(Network::Testnet),
+ ChainHash::TESTNET4 => Ok(Network::Testnet4),
ChainHash::SIGNET => Ok(Network::Signet),
ChainHash::REGTEST => Ok(Network::Regtest),
_ => Err(UnknownChainHashError(chain_hash)),
@@ -314,12 +333,26 @@ mod tests {
#[test]
fn serialize_test() {
assert_eq!(serialize(&Network::Bitcoin.magic()), &[0xf9, 0xbe, 0xb4, 0xd9]);
- assert_eq!(serialize(&Network::Testnet.magic()), &[0x0b, 0x11, 0x09, 0x07]);
+ assert_eq!(
+ serialize(&Network::Testnet.magic()),
+ &[0x0b, 0x11, 0x09, 0x07]
+ );
+ assert_eq!(
+ serialize(&Network::Testnet4.magic()),
+ &[0x1c, 0x16, 0x3f, 0x28]
+ );
assert_eq!(serialize(&Network::Signet.magic()), &[0x0a, 0x03, 0xcf, 0x40]);
assert_eq!(serialize(&Network::Regtest.magic()), &[0xfa, 0xbf, 0xb5, 0xda]);
assert_eq!(deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), Some(Network::Bitcoin.magic()));
- assert_eq!(deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), Some(Network::Testnet.magic()));
+ assert_eq!(
+ deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(),
+ Some(Network::Testnet.magic())
+ );
+ assert_eq!(
+ deserialize(&[0x1c, 0x16, 0x3f, 0x28]).ok(),
+ Some(Network::Testnet4.magic())
+ );
assert_eq!(deserialize(&[0x0a, 0x03, 0xcf, 0x40]).ok(), Some(Network::Signet.magic()));
assert_eq!(deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), Some(Network::Regtest.magic()));
}
@@ -328,11 +361,13 @@ mod tests {
fn string_test() {
assert_eq!(Network::Bitcoin.to_string(), "bitcoin");
assert_eq!(Network::Testnet.to_string(), "testnet");
+ assert_eq!(Network::Testnet4.to_string(), "testnet4");
assert_eq!(Network::Regtest.to_string(), "regtest");
assert_eq!(Network::Signet.to_string(), "signet");
assert_eq!("bitcoin".parse::<Network>().unwrap(), Network::Bitcoin);
assert_eq!("testnet".parse::<Network>().unwrap(), Network::Testnet);
+ assert_eq!("testnet4".parse::<Network>().unwrap(), Network::Testnet4);
assert_eq!("regtest".parse::<Network>().unwrap(), Network::Regtest);
assert_eq!("signet".parse::<Network>().unwrap(), Network::Signet);
assert!("fakenet".parse::<Network>().is_err());
@@ -386,6 +421,7 @@ mod tests {
let tests = vec![
(Bitcoin, "bitcoin"),
(Testnet, "testnet"),
+ (Testnet4, "testnet4"),
(Signet, "signet"),
(Regtest, "regtest"),
];
@@ -407,6 +443,7 @@ mod tests {
let expected_pairs = [
(Network::Bitcoin, "main"),
(Network::Testnet, "test"),
+ (Network::Testnet4, "testnet4"),
(Network::Regtest, "regtest"),
(Network::Signet, "signet"),
];
diff --git a/external/vendor/bitcoin/src/p2p/address.rs b/external/vendor/bitcoin/src/p2p/address.rs
index a0a381c..3f2a815 100644
--- a/external/vendor/bitcoin/src/p2p/address.rs
+++ b/external/vendor/bitcoin/src/p2p/address.rs
@@ -9,7 +9,7 @@
use core::{fmt, iter};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
-use io::{BufRead, Read, Write};
+use io::{Read, Write};
use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, VarInt, WriteExt};
use crate::p2p::ServiceFlags;
@@ -74,7 +74,7 @@ impl Encodable for Address {
impl Decodable for Address {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(Address {
services: Decodable::consensus_decode(r)?,
address: read_be_address(r)?,
@@ -166,7 +166,7 @@ impl Encodable for AddrV2 {
}
impl Decodable for AddrV2 {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let network_id = u8::consensus_decode(r)?;
let len = VarInt::consensus_decode(r)?.0;
if len > 512 {
@@ -284,7 +284,7 @@ impl Encodable for AddrV2Message {
}
impl Decodable for AddrV2Message {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(AddrV2Message {
time: Decodable::consensus_decode(r)?,
services: ServiceFlags::from(VarInt::consensus_decode(r)?.0),
diff --git a/external/vendor/bitcoin/src/p2p/message.rs b/external/vendor/bitcoin/src/p2p/message.rs
index 567d07b..11e10ca 100644
--- a/external/vendor/bitcoin/src/p2p/message.rs
+++ b/external/vendor/bitcoin/src/p2p/message.rs
@@ -9,7 +9,7 @@
use core::{fmt, iter};
use hashes::{sha256d, Hash};
-use io::{BufRead, Write};
+use io::{Read, Write};
use crate::blockdata::{block, transaction};
use crate::consensus::encode::{self, CheckedData, Decodable, Encodable, VarInt};
@@ -110,7 +110,7 @@ impl Encodable for CommandString {
impl Decodable for CommandString {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let rawbytes: [u8; 12] = Decodable::consensus_decode(r)?;
let rv = iter::FromIterator::from_iter(rawbytes.iter().filter_map(|&u| {
if u > 0 {
@@ -311,6 +311,11 @@ impl RawNetworkMessage {
Self { magic, payload, payload_len, checksum }
}
+ /// Consumes the [RawNetworkMessage] instance and returns the inner payload.
+ pub fn into_payload(self) -> NetworkMessage {
+ self.payload
+ }
+
/// The actual message data
pub fn payload(&self) -> &NetworkMessage { &self.payload }
@@ -404,7 +409,7 @@ struct HeaderDeserializationWrapper(Vec<block::Header>);
impl Decodable for HeaderDeserializationWrapper {
#[inline]
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let len = VarInt::consensus_decode(r)?.0;
@@ -423,13 +428,13 @@ impl Decodable for HeaderDeserializationWrapper {
}
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
}
}
impl Decodable for RawNetworkMessage {
- fn consensus_decode_from_finite_reader<R: BufRead + ?Sized>(
+ fn consensus_decode_from_finite_reader<R: Read + ?Sized>(
r: &mut R,
) -> Result<Self, encode::Error> {
let magic = Decodable::consensus_decode_from_finite_reader(r)?;
@@ -528,7 +533,7 @@ impl Decodable for RawNetworkMessage {
}
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Self::consensus_decode_from_finite_reader(&mut r.take(MAX_MSG_SIZE as u64))
}
}
diff --git a/external/vendor/bitcoin/src/p2p/message_blockdata.rs b/external/vendor/bitcoin/src/p2p/message_blockdata.rs
index 8719572..83c1d15 100644
--- a/external/vendor/bitcoin/src/p2p/message_blockdata.rs
+++ b/external/vendor/bitcoin/src/p2p/message_blockdata.rs
@@ -7,7 +7,7 @@
//!
use hashes::{sha256d, Hash as _};
-use io::{BufRead, Write};
+use io::{Read, Write};
use crate::blockdata::block::BlockHash;
use crate::blockdata::transaction::{Txid, Wtxid};
@@ -82,7 +82,7 @@ impl Encodable for Inventory {
impl Decodable for Inventory {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let inv_type: u32 = Decodable::consensus_decode(r)?;
Ok(match inv_type {
0 => Inventory::Error,
diff --git a/external/vendor/bitcoin/src/p2p/message_bloom.rs b/external/vendor/bitcoin/src/p2p/message_bloom.rs
index cb04fca..3e89c93 100644
--- a/external/vendor/bitcoin/src/p2p/message_bloom.rs
+++ b/external/vendor/bitcoin/src/p2p/message_bloom.rs
@@ -5,7 +5,7 @@
//! This module describes BIP37 Connection Bloom filtering network messages.
//!
-use io::{BufRead, Write};
+use io::{Read, Write};
use crate::consensus::{encode, Decodable, Encodable, ReadExt};
use crate::internal_macros::impl_consensus_encoding;
@@ -48,7 +48,7 @@ impl Encodable for BloomFlags {
}
impl Decodable for BloomFlags {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(match r.read_u8()? {
0 => BloomFlags::None,
1 => BloomFlags::All,
diff --git a/external/vendor/bitcoin/src/p2p/message_network.rs b/external/vendor/bitcoin/src/p2p/message_network.rs
index 606536e..a3dbc40 100644
--- a/external/vendor/bitcoin/src/p2p/message_network.rs
+++ b/external/vendor/bitcoin/src/p2p/message_network.rs
@@ -7,7 +7,7 @@
//!
use hashes::sha256d;
-use io::{BufRead, Write};
+use io::{Read, Write};
use crate::consensus::{encode, Decodable, Encodable, ReadExt};
use crate::internal_macros::impl_consensus_encoding;
@@ -117,7 +117,7 @@ impl Encodable for RejectReason {
}
impl Decodable for RejectReason {
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(match r.read_u8()? {
0x01 => RejectReason::Malformed,
0x10 => RejectReason::Invalid,
diff --git a/external/vendor/bitcoin/src/p2p/mod.rs b/external/vendor/bitcoin/src/p2p/mod.rs
index 8a3147c..988dc0d 100644
--- a/external/vendor/bitcoin/src/p2p/mod.rs
+++ b/external/vendor/bitcoin/src/p2p/mod.rs
@@ -25,12 +25,12 @@ use core::{fmt, ops};
use hex::FromHex;
use internals::{debug_from_display, write_err};
-use io::{BufRead, Write};
+use io::{Read, Write};
use crate::consensus::encode::{self, Decodable, Encodable};
use crate::consensus::Params;
use crate::prelude::*;
-use crate::Network;
+use crate::network::Network;
#[rustfmt::skip]
#[doc(inline)]
@@ -204,7 +204,7 @@ impl Encodable for ServiceFlags {
impl Decodable for ServiceFlags {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
Ok(ServiceFlags(Decodable::consensus_decode(r)?))
}
}
@@ -215,8 +215,13 @@ pub struct Magic([u8; 4]);
impl Magic {
/// Bitcoin mainnet network magic bytes.
pub const BITCOIN: Self = Self([0xF9, 0xBE, 0xB4, 0xD9]);
- /// Bitcoin testnet network magic bytes.
+ /// Bitcoin testnet3 network magic bytes.
+ #[deprecated(since = "0.32.4", note = "Use TESTNET3 instead")]
pub const TESTNET: Self = Self([0x0B, 0x11, 0x09, 0x07]);
+ /// Bitcoin testnet3 network magic bytes.
+ pub const TESTNET3: Self = Self([0x0B, 0x11, 0x09, 0x07]);
+ /// Bitcoin testnet4 network magic bytes.
+ pub const TESTNET4: Self = Self([0x1c, 0x16, 0x3f, 0x28]);
/// Bitcoin signet network magic bytes.
pub const SIGNET: Self = Self([0x0A, 0x03, 0xCF, 0x40]);
/// Bitcoin regtest network magic bytes.
@@ -250,7 +255,8 @@ impl From<Network> for Magic {
match network {
// Note: new network entries must explicitly be matched in `try_from` below.
Network::Bitcoin => Magic::BITCOIN,
- Network::Testnet => Magic::TESTNET,
+ Network::Testnet => Magic::TESTNET3,
+ Network::Testnet4 => Magic::TESTNET4,
Network::Signet => Magic::SIGNET,
Network::Regtest => Magic::REGTEST,
}
@@ -264,7 +270,8 @@ impl TryFrom<Magic> for Network {
match magic {
// Note: any new network entries must be matched against here.
Magic::BITCOIN => Ok(Network::Bitcoin),
- Magic::TESTNET => Ok(Network::Testnet),
+ Magic::TESTNET3 => Ok(Network::Testnet),
+ Magic::TESTNET4 => Ok(Network::Testnet4),
Magic::SIGNET => Ok(Network::Signet),
Magic::REGTEST => Ok(Network::Regtest),
_ => Err(UnknownMagicError(magic)),
@@ -301,7 +308,7 @@ impl Encodable for Magic {
}
impl Decodable for Magic {
- fn consensus_decode<R: BufRead + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(reader: &mut R) -> Result<Self, encode::Error> {
Ok(Magic(Decodable::consensus_decode(reader)?))
}
}
@@ -424,6 +431,7 @@ mod tests {
let known_network_magic_strs = [
("f9beb4d9", Network::Bitcoin),
("0b110907", Network::Testnet),
+ ("1c163f28", Network::Testnet4),
("fabfb5da", Network::Regtest),
("0a03cf40", Network::Signet),
];
diff --git a/external/vendor/bitcoin/src/pow.rs b/external/vendor/bitcoin/src/pow.rs
index 4392a3b..d4cb696 100644
--- a/external/vendor/bitcoin/src/pow.rs
+++ b/external/vendor/bitcoin/src/pow.rs
@@ -10,11 +10,12 @@ use core::cmp;
use core::fmt::{self, LowerHex, UpperHex};
use core::ops::{Add, Div, Mul, Not, Rem, Shl, Shr, Sub};
-use io::{BufRead, Write};
+use io::{Read, Write};
#[cfg(all(test, mutate))]
use mutagen::mutate;
use units::parse;
+use crate::block::Header;
use crate::blockdata::block::BlockHash;
use crate::consensus::encode::{self, Decodable, Encodable};
use crate::consensus::Params;
@@ -364,6 +365,82 @@ impl CompactTarget {
Ok(Self::from_consensus(lock_time))
}
+ /// Computes the [`CompactTarget`] from a difficulty adjustment.
+ ///
+ /// ref: <https://github.com/bitcoin/bitcoin/blob/0503cbea9aab47ec0a87d34611e5453158727169/src/pow.cpp>
+ ///
+ /// Given the previous Target, represented as a [`CompactTarget`], the difficulty is adjusted
+ /// by taking the timespan between them, and multipling the current [`CompactTarget`] by a factor
+ /// of the net timespan and expected timespan. The [`CompactTarget`] may not adjust by more than
+ /// a factor of 4, or adjust beyond the maximum threshold for the network.
+ ///
+ /// # Note
+ ///
+ /// Under the consensus rules, the difference in the number of blocks between the headers does
+ /// not equate to the `difficulty_adjustment_interval` of [`Params`]. This is due to an off-by-one
+ /// error, and, the expected number of blocks in between headers is `difficulty_adjustment_interval - 1`
+ /// when calculating the difficulty adjustment.
+ ///
+ /// Take the example of the first difficulty adjustment. Block 2016 introduces a new [`CompactTarget`],
+ /// which takes the net timespan between Block 2015 and Block 0, and recomputes the difficulty.
+ ///
+ /// # Returns
+ ///
+ /// The expected [`CompactTarget`] recalculation.
+ pub fn from_next_work_required(
+ last: CompactTarget,
+ timespan: u64,
+ params: impl AsRef<Params>,
+ ) -> CompactTarget {
+ let params = params.as_ref();
+ if params.no_pow_retargeting {
+ return last;
+ }
+ // Comments relate to the `pow.cpp` file from Core.
+ // ref: <https://github.com/bitcoin/bitcoin/blob/0503cbea9aab47ec0a87d34611e5453158727169/src/pow.cpp>
+ let min_timespan = params.pow_target_timespan >> 2; // Lines 56/57
+ let max_timespan = params.pow_target_timespan << 2; // Lines 58/59
+ let actual_timespan = timespan.clamp(min_timespan, max_timespan);
+ let prev_target: Target = last.into();
+ let maximum_retarget = prev_target.max_transition_threshold(params); // bnPowLimit
+ let retarget = prev_target.0; // bnNew
+ let retarget = retarget.mul(actual_timespan.into());
+ let retarget = retarget.div(params.pow_target_timespan.into());
+ let retarget = Target(retarget);
+ if retarget.ge(&maximum_retarget) {
+ return maximum_retarget.to_compact_lossy();
+ }
+ retarget.to_compact_lossy()
+ }
+
+ /// Computes the [`CompactTarget`] from a difficulty adjustment,
+ /// assuming these are the relevant block headers.
+ ///
+ /// Given two headers, representing the start and end of a difficulty adjustment epoch,
+ /// compute the [`CompactTarget`] based on the net time between them and the current
+ /// [`CompactTarget`].
+ ///
+ /// # Note
+ ///
+ /// See [`CompactTarget::from_next_work_required`]
+ ///
+ /// For example, to successfully compute the first difficulty adjustment on the Bitcoin network,
+ /// one would pass the header for Block 2015 as `current` and the header for Block 0 as
+ /// `last_epoch_boundary`.
+ ///
+ /// # Returns
+ ///
+ /// The expected [`CompactTarget`] recalculation.
+ pub fn from_header_difficulty_adjustment(
+ last_epoch_boundary: Header,
+ current: Header,
+ params: impl AsRef<Params>,
+ ) -> CompactTarget {
+ let timespan = current.time - last_epoch_boundary.time;
+ let bits = current.bits;
+ CompactTarget::from_next_work_required(bits, timespan.into(), params)
+ }
+
/// Creates a [`CompactTarget`] from a consensus encoded `u32`.
pub fn from_consensus(bits: u32) -> Self { Self(bits) }
@@ -384,7 +461,7 @@ impl Encodable for CompactTarget {
impl Decodable for CompactTarget {
#[inline]
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
u32::consensus_decode(r).map(CompactTarget)
}
}
@@ -1695,6 +1772,113 @@ mod tests {
assert_eq!(format!("{:08X}", CompactTarget(0x01d0f456)), "01D0F456");
}
+ #[test]
+ fn compact_target_from_upwards_difficulty_adjustment() {
+ let params = Params::new(crate::Network::Signet);
+ let starting_bits = CompactTarget::from_consensus(503543726); // Genesis compact target on Signet
+ let start_time: u64 = 1598918400; // Genesis block unix time
+ let end_time: u64 = 1599332177; // Block 2015 unix time
+ let timespan = end_time - start_time; // Faster than expected
+ let adjustment = CompactTarget::from_next_work_required(starting_bits, timespan, ¶ms);
+ let adjustment_bits = CompactTarget::from_consensus(503394215); // Block 2016 compact target
+ assert_eq!(adjustment, adjustment_bits);
+ }
+
+ #[test]
+ fn compact_target_from_downwards_difficulty_adjustment() {
+ let params = Params::new(crate::Network::Signet);
+ let starting_bits = CompactTarget::from_consensus(503394215); // Block 2016 compact target
+ let start_time: u64 = 1599332844; // Block 2016 unix time
+ let end_time: u64 = 1600591200; // Block 4031 unix time
+ let timespan = end_time - start_time; // Slower than expected
+ let adjustment = CompactTarget::from_next_work_required(starting_bits, timespan, ¶ms);
+ let adjustment_bits = CompactTarget::from_consensus(503397348); // Block 4032 compact target
+ assert_eq!(adjustment, adjustment_bits);
+ }
+
+ #[test]
+ fn compact_target_from_upwards_difficulty_adjustment_using_headers() {
+ use crate::{block::Version, constants::genesis_block, TxMerkleNode};
+ use hashes::Hash;
+ let params = Params::new(crate::Network::Signet);
+ let epoch_start = genesis_block(¶ms).header;
+ // Block 2015, the only information used are `bits` and `time`
+ let current = Header {
+ version: Version::ONE,
+ prev_blockhash: BlockHash::all_zeros(),
+ merkle_root: TxMerkleNode::all_zeros(),
+ time: 1599332177,
+ bits: epoch_start.bits,
+ nonce: epoch_start.nonce
+ };
+ let adjustment = CompactTarget::from_header_difficulty_adjustment(epoch_start, current, params);
+ let adjustment_bits = CompactTarget::from_consensus(503394215); // Block 2016 compact target
+ assert_eq!(adjustment, adjustment_bits);
+ }
+
+ #[test]
+ fn compact_target_from_downwards_difficulty_adjustment_using_headers() {
+ use crate::{block::Version, TxMerkleNode};
+ use hashes::Hash;
+ let params = Params::new(crate::Network::Signet);
+ let starting_bits = CompactTarget::from_consensus(503394215); // Block 2016 compact target
+ // Block 2016, the only information used is `time`
+ let epoch_start = Header {
+ version: Version::ONE,
+ prev_blockhash: BlockHash::all_zeros(),
+ merkle_root: TxMerkleNode::all_zeros(),
+ time: 1599332844,
+ bits: starting_bits,
+ nonce: 0
+ };
+ // Block 4031, the only information used are `bits` and `time`
+ let current = Header {
+ version: Version::ONE,
+ prev_blockhash: BlockHash::all_zeros(),
+ merkle_root: TxMerkleNode::all_zeros(),
+ time: 1600591200,
+ bits: starting_bits,
+ nonce: 0
+ };
+ let adjustment = CompactTarget::from_header_difficulty_adjustment(epoch_start, current, params);
+ let adjustment_bits = CompactTarget::from_consensus(503397348); // Block 4032 compact target
+ assert_eq!(adjustment, adjustment_bits);
+ }
+
+ #[test]
+ fn compact_target_from_maximum_upward_difficulty_adjustment() {
+ let params = Params::new(crate::Network::Signet);
+ let starting_bits = CompactTarget::from_consensus(503403001);
+ let timespan = (0.2 * params.pow_target_timespan as f64) as u64;
+ let got = CompactTarget::from_next_work_required(starting_bits, timespan, params);
+ let want = Target::from_compact(starting_bits)
+ .min_transition_threshold()
+ .to_compact_lossy();
+ assert_eq!(got, want);
+ }
+
+ #[test]
+ fn compact_target_from_minimum_downward_difficulty_adjustment() {
+ let params = Params::new(crate::Network::Signet);
+ let starting_bits = CompactTarget::from_consensus(403403001); // High difficulty for Signet
+ let timespan = 5 * params.pow_target_timespan; // Really slow.
+ let got = CompactTarget::from_next_work_required(starting_bits, timespan, ¶ms);
+ let want = Target::from_compact(starting_bits)
+ .max_transition_threshold(params)
+ .to_compact_lossy();
+ assert_eq!(got, want);
+ }
+
+ #[test]
+ fn compact_target_from_adjustment_is_max_target() {
+ let params = Params::new(crate::Network::Signet);
+ let starting_bits = CompactTarget::from_consensus(503543726); // Genesis compact target on Signet
+ let timespan = 5 * params.pow_target_timespan; // Really slow.
+ let got = CompactTarget::from_next_work_required(starting_bits, timespan, ¶ms);
+ let want = params.max_attainable_target.to_compact_lossy();
+ assert_eq!(got, want);
+ }
+
#[test]
fn target_from_compact() {
// (nBits, target)
diff --git a/external/vendor/bitcoin/src/psbt/macros.rs b/external/vendor/bitcoin/src/psbt/macros.rs
index 556c83a..0b498bf 100644
--- a/external/vendor/bitcoin/src/psbt/macros.rs
+++ b/external/vendor/bitcoin/src/psbt/macros.rs
@@ -56,7 +56,7 @@ macro_rules! impl_psbtmap_deserialize {
macro_rules! impl_psbtmap_decoding {
($thing:ty) => {
impl $thing {
- pub(crate) fn decode<R: $crate::io::BufRead + ?Sized>(
+ pub(crate) fn decode<R: $crate::io::Read + ?Sized>(
r: &mut R,
) -> core::result::Result<Self, $crate::psbt::Error> {
let mut rv: Self = core::default::Default::default();
diff --git a/external/vendor/bitcoin/src/psbt/map/global.rs b/external/vendor/bitcoin/src/psbt/map/global.rs
index f3334c1..7803df2 100644
--- a/external/vendor/bitcoin/src/psbt/map/global.rs
+++ b/external/vendor/bitcoin/src/psbt/map/global.rs
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: CC0-1.0
-use io::{BufRead, Cursor, Read};
+use io::{Cursor, Read};
use crate::bip32::{ChildNumber, DerivationPath, Fingerprint, Xpub};
use crate::blockdata::transaction::Transaction;
@@ -70,7 +70,7 @@ impl Map for Psbt {
}
impl Psbt {
- pub(crate) fn decode_global<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ pub(crate) fn decode_global<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
let mut r = r.take(MAX_VEC_SIZE as u64);
let mut tx: Option<Transaction> = None;
let mut version: Option<u32> = None;
diff --git a/external/vendor/bitcoin/src/psbt/map/input.rs b/external/vendor/bitcoin/src/psbt/map/input.rs
index 6c722f2..56c4bff 100644
--- a/external/vendor/bitcoin/src/psbt/map/input.rs
+++ b/external/vendor/bitcoin/src/psbt/map/input.rs
@@ -132,10 +132,12 @@ pub struct Input {
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
}
-/// A Signature hash type for the corresponding input. As of taproot upgrade, the signature hash
-/// type can be either [`EcdsaSighashType`] or [`TapSighashType`] but it is not possible to know
-/// directly which signature hash type the user is dealing with. Therefore, the user is responsible
-/// for converting to/from [`PsbtSighashType`] from/to the desired signature hash type they need.
+/// A Signature hash type for the corresponding input.
+///
+/// As of taproot upgrade, the signature hash type can be either [`EcdsaSighashType`] or
+/// [`TapSighashType`] but it is not possible to know directly which signature hash type the user is
+/// dealing with. Therefore, the user is responsible for converting to/from [`PsbtSighashType`]
+/// from/to the desired signature hash type they need.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
diff --git a/external/vendor/bitcoin/src/psbt/mod.rs b/external/vendor/bitcoin/src/psbt/mod.rs
index 3d428fd..4089087 100644
--- a/external/vendor/bitcoin/src/psbt/mod.rs
+++ b/external/vendor/bitcoin/src/psbt/mod.rs
@@ -21,7 +21,7 @@ use std::collections::{HashMap, HashSet};
use internals::write_err;
use secp256k1::{Keypair, Message, Secp256k1, Signing, Verification};
-use crate::bip32::{self, KeySource, Xpriv, Xpub};
+use crate::bip32::{self, DerivationPath, KeySource, Xpriv, Xpub};
use crate::blockdata::transaction::{self, Transaction, TxOut};
use crate::crypto::key::{PrivateKey, PublicKey};
use crate::crypto::{ecdsa, taproot};
@@ -423,6 +423,8 @@ impl Psbt {
k.get_key(KeyRequest::Bip32(key_source.clone()), secp)
{
secret_key
+ } else if let Ok(Some(sk)) = k.get_key(KeyRequest::XOnlyPubkey(xonly), secp) {
+ sk
} else {
continue;
};
@@ -442,7 +444,7 @@ impl Psbt {
let (msg, sighash_type) = self.sighash_taproot(input_index, cache, None)?;
let key_pair = Keypair::from_secret_key(secp, &sk.inner)
.tap_tweak(secp, input.tap_merkle_root)
- .to_inner();
+ .to_keypair();
#[cfg(feature = "rand-std")]
let signature = secp.sign_schnorr(&msg, &key_pair);
@@ -730,6 +732,8 @@ pub enum KeyRequest {
Pubkey(PublicKey),
/// Request a private key using BIP-32 fingerprint and derivation path.
Bip32(KeySource),
+ /// Request a private key using the associated x-only public key.
+ XOnlyPubkey(XOnlyPublicKey),
}
/// Trait to get a private key from a key request, key is then used to sign an input.
@@ -760,10 +764,18 @@ impl GetKey for Xpriv {
) -> Result<Option<PrivateKey>, Self::Error> {
match key_request {
KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported),
+ KeyRequest::XOnlyPubkey(_) => Err(GetKeyError::NotSupported),
KeyRequest::Bip32((fingerprint, path)) => {
let key = if self.fingerprint(secp) == fingerprint {
let k = self.derive_priv(secp, &path)?;
Some(k.to_priv())
+ } else if self.parent_fingerprint == fingerprint
+ && !path.is_empty()
+ && path[0] == self.child_number
+ {
+ let path = DerivationPath::from_iter(path.into_iter().skip(1).copied());
+ let k = self.derive_priv(secp, &path)?;
+ Some(k.to_priv())
} else {
None
};
@@ -803,18 +815,11 @@ impl GetKey for $set<Xpriv> {
key_request: KeyRequest,
secp: &Secp256k1<C>
) -> Result<Option<PrivateKey>, Self::Error> {
- match key_request {
- KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported),
- KeyRequest::Bip32((fingerprint, path)) => {
- for xpriv in self.iter() {
- if xpriv.parent_fingerprint == fingerprint {
- let k = xpriv.derive_priv(secp, &path)?;
- return Ok(Some(k.to_priv()));
- }
- }
- Ok(None)
- }
- }
+ // OK to stop at the first error because Xpriv::get_key() can only fail
+ // if this isn't a KeyRequest::Bip32, which would fail for all Xprivs.
+ self.iter()
+ .find_map(|xpriv| xpriv.get_key(key_request.clone(), secp).transpose())
+ .transpose()
}
}}}
impl_get_key_for_set!(BTreeSet);
@@ -822,7 +827,7 @@ impl_get_key_for_set!(BTreeSet);
impl_get_key_for_set!(HashSet);
#[rustfmt::skip]
-macro_rules! impl_get_key_for_map {
+macro_rules! impl_get_key_for_pubkey_map {
($map:ident) => {
impl GetKey for $map<PublicKey, PrivateKey> {
@@ -835,13 +840,67 @@ impl GetKey for $map<PublicKey, PrivateKey> {
) -> Result<Option<PrivateKey>, Self::Error> {
match key_request {
KeyRequest::Pubkey(pk) => Ok(self.get(&pk).cloned()),
+ KeyRequest::XOnlyPubkey(xonly) => {
+ let pubkey_even = PublicKey::new(xonly.public_key(secp256k1::Parity::Even));
+ let key = self.get(&pubkey_even).cloned();
+
+ if key.is_some() {
+ return Ok(key);
+ }
+
+ let pubkey_odd = PublicKey::new(xonly.public_key(secp256k1::Parity::Odd));
+ if let Some(priv_key) = self.get(&pubkey_odd).copied() {
+ let negated_priv_key = priv_key.negate();
+ return Ok(Some(negated_priv_key));
+ }
+
+ Ok(None)
+ },
+ KeyRequest::Bip32(_) => Err(GetKeyError::NotSupported),
+ }
+ }
+}}}
+impl_get_key_for_pubkey_map!(BTreeMap);
+#[cfg(feature = "std")]
+impl_get_key_for_pubkey_map!(HashMap);
+
+#[rustfmt::skip]
+macro_rules! impl_get_key_for_xonly_map {
+ ($map:ident) => {
+
+impl GetKey for $map<XOnlyPublicKey, PrivateKey> {
+ type Error = GetKeyError;
+
+ fn get_key<C: Signing>(
+ &self,
+ key_request: KeyRequest,
+ secp: &Secp256k1<C>,
+ ) -> Result<Option<PrivateKey>, Self::Error> {
+ match key_request {
+ KeyRequest::XOnlyPubkey(xonly) => Ok(self.get(&xonly).cloned()),
+ KeyRequest::Pubkey(pk) => {
+ let (xonly, parity) = pk.inner.x_only_public_key();
+
+ if let Some(mut priv_key) = self.get(&XOnlyPublicKey::from(xonly)).cloned() {
+ let computed_pk = priv_key.public_key(&secp);
+ let (_, computed_parity) = computed_pk.inner.x_only_public_key();
+
+ if computed_parity != parity {
+ priv_key = priv_key.negate();
+ }
+
+ return Ok(Some(priv_key));
+ }
+
+ Ok(None)
+ },
KeyRequest::Bip32(_) => Err(GetKeyError::NotSupported),
}
}
}}}
-impl_get_key_for_map!(BTreeMap);
+impl_get_key_for_xonly_map!(BTreeMap);
#[cfg(feature = "std")]
-impl_get_key_for_map!(HashMap);
+impl_get_key_for_xonly_map!(HashMap);
/// Errors when getting a key.
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -1208,7 +1267,14 @@ mod tests {
use hashes::{hash160, ripemd160, sha256, Hash};
use hex::{test_hex_unwrap as hex, FromHex};
#[cfg(feature = "rand-std")]
- use secp256k1::{All, SecretKey};
+ use {
+ crate::bip32::{DerivationPath, Fingerprint},
+ crate::key::WPubkeyHash,
+ crate::locktime,
+ crate::witness_version::WitnessVersion,
+ crate::WitnessProgram,
+ secp256k1::{All, SecretKey},
+ };
use super::*;
use crate::bip32::ChildNumber;
@@ -2138,7 +2204,43 @@ mod tests {
}
#[test]
- fn test_fee() {
+ #[cfg(feature = "rand-std")]
+ fn pubkey_map_get_key_negates_odd_parity_keys() {
+ use crate::psbt::{GetKey, KeyRequest};
+
+ let (mut priv_key, mut pk, secp) = gen_keys();
+ let (xonly, parity) = pk.inner.x_only_public_key();
+
+ let mut pubkey_map: HashMap<PublicKey, PrivateKey> = HashMap::new();
+
+ if parity == secp256k1::Parity::Even {
+ priv_key = PrivateKey {
+ compressed: priv_key.compressed,
+ network: priv_key.network,
+ inner: priv_key.inner.negate(),
+ };
+ pk = priv_key.public_key(&secp);
+ }
+
+ pubkey_map.insert(pk, priv_key);
+
+ let req_result = pubkey_map.get_key(KeyRequest::XOnlyPubkey(xonly), &secp).unwrap();
+
+ let retrieved_key = req_result.unwrap();
+
+ let retrieved_pub_key = retrieved_key.public_key(&secp);
+ let (retrieved_xonly, retrieved_parity) = retrieved_pub_key.inner.x_only_public_key();
+
+ assert_eq!(xonly, retrieved_xonly);
+ assert_eq!(
+ retrieved_parity,
+ secp256k1::Parity::Even,
+ "Key should be normalized to have even parity, even when original had odd parity"
+ );
+ }
+
+ #[test]
+ fn fee() {
let output_0_val = Amount::from_sat(99_999_699);
let output_1_val = Amount::from_sat(100_000_000);
let prev_output_val = Amount::from_sat(200_000_000);
@@ -2248,11 +2350,73 @@ mod tests {
#[test]
#[cfg(feature = "rand-std")]
- fn sign_psbt() {
- use crate::bip32::{DerivationPath, Fingerprint};
- use crate::witness_version::WitnessVersion;
- use crate::{WPubkeyHash, WitnessProgram};
+ fn hashmap_can_sign_taproot() {
+ let (priv_key, pk, secp) = gen_keys();
+ let internal_key: XOnlyPublicKey = pk.inner.into();
+
+ let tx = Transaction {
+ version: transaction::Version::TWO,
+ lock_time: locktime::absolute::LockTime::ZERO,
+ input: vec![TxIn::default()],
+ output: vec![TxOut { value: Amount::ZERO, script_pubkey: ScriptBuf::new() }],
+ };
+
+ let mut psbt = Psbt::from_unsigned_tx(tx).unwrap();
+ psbt.inputs[0].tap_internal_key = Some(internal_key);
+ psbt.inputs[0].witness_utxo = Some(transaction::TxOut {
+ value: Amount::from_sat(10),
+ script_pubkey: ScriptBuf::new_p2tr(&secp, internal_key, None),
+ });
+
+ let mut key_map: HashMap<PublicKey, PrivateKey> = HashMap::new();
+ key_map.insert(pk, priv_key);
+ let key_source = (Fingerprint::default(), DerivationPath::default());
+ let mut tap_key_origins = std::collections::BTreeMap::new();
+ tap_key_origins.insert(internal_key, (vec![], key_source));
+ psbt.inputs[0].tap_key_origins = tap_key_origins;
+
+ let signing_keys = psbt.sign(&key_map, &secp).unwrap();
+ assert_eq!(signing_keys.len(), 1);
+ assert_eq!(signing_keys[&0], SigningKeys::Schnorr(vec![internal_key]));
+ }
+
+ #[test]
+ #[cfg(feature = "rand-std")]
+ fn xonly_hashmap_can_sign_taproot() {
+ let (priv_key, pk, secp) = gen_keys();
+ let internal_key: XOnlyPublicKey = pk.inner.into();
+
+ let tx = Transaction {
+ version: transaction::Version::TWO,
+ lock_time: locktime::absolute::LockTime::ZERO,
+ input: vec![TxIn::default()],
+ output: vec![TxOut { value: Amount::ZERO, script_pubkey: ScriptBuf::new() }],
+ };
+
+ let mut psbt = Psbt::from_unsigned_tx(tx).unwrap();
+ psbt.inputs[0].tap_internal_key = Some(internal_key);
+ psbt.inputs[0].witness_utxo = Some(transaction::TxOut {
+ value: Amount::from_sat(10),
+ script_pubkey: ScriptBuf::new_p2tr(&secp, internal_key, None),
+ });
+
+ let mut xonly_key_map: HashMap<XOnlyPublicKey, PrivateKey> = HashMap::new();
+ xonly_key_map.insert(internal_key, priv_key);
+
+ let key_source = (Fingerprint::default(), DerivationPath::default());
+ let mut tap_key_origins = std::collections::BTreeMap::new();
+ tap_key_origins.insert(internal_key, (vec![], key_source));
+ psbt.inputs[0].tap_key_origins = tap_key_origins;
+
+ let signing_keys = psbt.sign(&xonly_key_map, &secp).unwrap();
+ assert_eq!(signing_keys.len(), 1);
+ assert_eq!(signing_keys[&0], SigningKeys::Schnorr(vec![internal_key]));
+ }
+
+ #[test]
+ #[cfg(feature = "rand-std")]
+ fn sign_psbt() {
let unsigned_tx = Transaction {
version: transaction::Version::TWO,
lock_time: absolute::LockTime::ZERO,
diff --git a/external/vendor/bitcoin/src/psbt/raw.rs b/external/vendor/bitcoin/src/psbt/raw.rs
index 9f9c64f..4800078 100644
--- a/external/vendor/bitcoin/src/psbt/raw.rs
+++ b/external/vendor/bitcoin/src/psbt/raw.rs
@@ -8,7 +8,7 @@
use core::fmt;
-use io::{BufRead, Write};
+use io::{Read, Write};
use super::serialize::{Deserialize, Serialize};
use crate::consensus::encode::{
@@ -74,7 +74,7 @@ impl fmt::Display for Key {
}
impl Key {
- pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ pub(crate) fn decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
let VarInt(byte_size): VarInt = Decodable::consensus_decode(r)?;
if byte_size == 0 {
@@ -137,7 +137,7 @@ impl Deserialize for Pair {
}
impl Pair {
- pub(crate) fn decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, Error> {
+ pub(crate) fn decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
Ok(Pair { key: Key::decode(r)?, value: Decodable::consensus_decode(r)? })
}
}
@@ -159,7 +159,7 @@ impl<Subtype> Decodable for ProprietaryKey<Subtype>
where
Subtype: Copy + From<u8> + Into<u8>,
{
- fn consensus_decode<R: BufRead + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
+ fn consensus_decode<R: Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
let prefix = Vec::<u8>::consensus_decode(r)?;
let subtype = Subtype::from(r.read_u8()?);
diff --git a/external/vendor/bitcoin/src/psbt/serialize.rs b/external/vendor/bitcoin/src/psbt/serialize.rs
index f9e0564..77fb251 100644
--- a/external/vendor/bitcoin/src/psbt/serialize.rs
+++ b/external/vendor/bitcoin/src/psbt/serialize.rs
@@ -7,6 +7,7 @@
//!
use hashes::{hash160, ripemd160, sha256, sha256d, Hash};
+use hex::DisplayHex;
use secp256k1::XOnlyPublicKey;
use super::map::{Input, Map, Output, PsbtSighashType};
@@ -17,7 +18,8 @@ use crate::blockdata::witness::Witness;
use crate::consensus::encode::{self, deserialize_partial, serialize, Decodable, Encodable};
use crate::crypto::key::PublicKey;
use crate::crypto::{ecdsa, taproot};
-use crate::prelude::*;
+use crate::io::Write;
+use crate::prelude::{String, Vec};
use crate::psbt::{Error, Psbt};
use crate::taproot::{
ControlBlock, LeafVersion, TapLeafHash, TapNodeHash, TapTree, TaprootBuilder,
@@ -43,40 +45,57 @@ impl Psbt {
/// Serialize as raw binary data
pub fn serialize(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
+ self.serialize_to_writer(&mut buf).expect("Writing to Vec can't fail");
+ buf
+ }
- // <magic>
- buf.extend_from_slice(b"psbt");
+ /// Serialize the PSBT into a writer.
+ pub fn serialize_to_writer(&self, w: &mut impl Write) -> io::Result<usize> {
+ let mut written_len = 0;
- buf.push(0xff_u8);
+ fn write_all(w: &mut impl Write, data: &[u8]) -> io::Result<usize> {
+ w.write_all(data).map(|_| data.len())
+ }
- buf.extend(self.serialize_map());
+ // magic
+ written_len += write_all(w, b"psbt")?;
+ // separator
+ written_len += write_all(w, &[0xff])?;
+
+ written_len += write_all(w, &self.serialize_map())?;
for i in &self.inputs {
- buf.extend(i.serialize_map());
+ written_len += write_all(w, &i.serialize_map())?;
}
for i in &self.outputs {
- buf.extend(i.serialize_map());
+ written_len += write_all(w, &i.serialize_map())?;
}
- buf
+ Ok(written_len)
}
/// Deserialize a value from raw binary data.
- pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
+ pub fn deserialize(mut bytes: &[u8]) -> Result<Self, Error> {
+ Self::deserialize_from_reader(&mut bytes)
+ }
+
+ /// Deserialize a value from raw binary data read from a `BufRead` object.
+ pub fn deserialize_from_reader<R: io::BufRead>(r: &mut R) -> Result<Self, Error> {
const MAGIC_BYTES: &[u8] = b"psbt";
- if bytes.get(0..MAGIC_BYTES.len()) != Some(MAGIC_BYTES) {
+
+ let magic: [u8; 4] = Decodable::consensus_decode(r)?;
+ if magic != MAGIC_BYTES {
return Err(Error::InvalidMagic);
}
const PSBT_SERPARATOR: u8 = 0xff_u8;
- if bytes.get(MAGIC_BYTES.len()) != Some(&PSBT_SERPARATOR) {
+ let separator: u8 = Decodable::consensus_decode(r)?;
+ if separator != PSBT_SERPARATOR {
return Err(Error::InvalidSeparator);
}
- let mut d = bytes.get(5..).ok_or(Error::NoMorePairs)?;
-
- let mut global = Psbt::decode_global(&mut d)?;
+ let mut global = Psbt::decode_global(r)?;
global.unsigned_tx_checks()?;
let inputs: Vec<Input> = {
@@ -85,7 +104,7 @@ impl Psbt {
let mut inputs: Vec<Input> = Vec::with_capacity(inputs_len);
for _ in 0..inputs_len {
- inputs.push(Input::decode(&mut d)?);
+ inputs.push(Input::decode(r)?);
}
inputs
@@ -97,7 +116,7 @@ impl Psbt {
let mut outputs: Vec<Output> = Vec::with_capacity(outputs_len);
for _ in 0..outputs_len {
- outputs.push(Output::decode(&mut d)?);
+ outputs.push(Output::decode(r)?);
}
outputs
diff --git a/external/vendor/bitcoin/src/taproot/mod.rs b/external/vendor/bitcoin/src/taproot/mod.rs
index 60ce28e..54576c5 100644
--- a/external/vendor/bitcoin/src/taproot/mod.rs
+++ b/external/vendor/bitcoin/src/taproot/mod.rs
@@ -158,7 +158,16 @@ pub const TAPROOT_CONTROL_BASE_SIZE: usize = 33;
pub const TAPROOT_CONTROL_MAX_SIZE: usize =
TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT;
-// type alias for versioned tap script corresponding merkle proof
+/// The leaf script with its version.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub struct LeafScript<S> {
+ /// The version of the script.
+ pub version: LeafVersion,
+ /// The script, usually `ScriptBuf` or `&Script`.
+ pub script: S,
+}
+
+// type alias for versioned tap script corresponding Merkle proof
type ScriptMerkleProofMap = BTreeMap<(ScriptBuf, LeafVersion), BTreeSet<TaprootMerkleBranch>>;
/// Represents taproot spending information.
@@ -1547,7 +1556,7 @@ mod test {
let control_block =
ControlBlock::decode(&Vec::<u8>::from_hex(control_block_hex).unwrap()).unwrap();
assert_eq!(control_block_hex, control_block.serialize().to_lower_hex_string());
- assert!(control_block.verify_taproot_commitment(secp, out_pk.to_inner(), &script));
+ assert!(control_block.verify_taproot_commitment(secp, out_pk.to_x_only_public_key(), &script));
}
#[test]
@@ -1654,7 +1663,7 @@ mod test {
let ctrl_block = tree_info.control_block(&ver_script).unwrap();
assert!(ctrl_block.verify_taproot_commitment(
&secp,
- output_key.to_inner(),
+ output_key.to_x_only_public_key(),
&ver_script.0
))
}
@@ -1729,7 +1738,7 @@ mod test {
let ctrl_block = tree_info.control_block(&ver_script).unwrap();
assert!(ctrl_block.verify_taproot_commitment(
&secp,
- output_key.to_inner(),
+ output_key.to_x_only_public_key(),
&ver_script.0
))
}
@@ -1845,7 +1854,7 @@ mod test {
let addr = Address::p2tr(secp, internal_key, merkle_root, KnownHrp::Mainnet);
let spk = addr.script_pubkey();
- assert_eq!(expected_output_key, output_key.to_inner());
+ assert_eq!(expected_output_key, output_key.to_x_only_public_key());
assert_eq!(expected_tweak, tweak);
assert_eq!(expected_addr, addr);
assert_eq!(expected_spk, spk);
diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock
index 8afb8c9..e631847 100644
--- a/src/rust/Cargo.lock
+++ b/src/rust/Cargo.lock
@@ -179,9 +179,9 @@ dependencies = [
[[package]]
name = "bitcoin"
-version = "0.32.2"
+version = "0.32.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea507acc1cd80fc084ace38544bbcf7ced7c2aa65b653b102de0ce718df668f6"
+checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945"
dependencies = [
"base58ck",
"bech32",
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index f844e0b..6fb74c5 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -32,7 +32,7 @@ resolver = "2"
bech32 = { version = "0.11.0", default-features = false }
# The secp-recovery feature is currently only needed in tests to make use of `RecoverableSignature`.
# Attempting to enable it conditionally only for tests somehow leads to linking errors (duplicate secp256k1 symbols).
-bitcoin = { version = "0.32.2", default-features = false, features = ["secp-recovery"] }
+bitcoin = { version = "0.32.7", default-features = false, features = ["secp-recovery"] }
# Replace with upstream once https://github.com/rust-bitcoin/rust-bip39/pull/76 is merged and released.
bip39 = { git = "https://github.com/benma/rust-bip39.git", branch = "bb02", default-features = false, features = ["zeroize"] }
hex = { version = "0.4", default-features = false, features = ["alloc"] }
diff --git a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
index b2344ea..c7f8d37 100644
--- a/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
+++ b/src/rust/bitbox02-rust/src/hww/api/bitcoin/signtx.rs
@@ -796,7 +796,7 @@ async fn _process(
// provide the key path spend private key, which means the internal key plus the tap
// tweak.
let private_key = if is_taproot(script_config_account) {
- keypair.tap_tweak(SECP256K1, None).to_inner().secret_key()
+ keypair.tap_tweak(SECP256K1, None).to_keypair().secret_key()
} else {
keypair.secret_key()
};
Why this scored 45/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.