diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f1b13d..c1b88fc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added `Transaction::check` for context-free consensus validation of a transaction. Returns `TxCheckResult::Valid` on success or `TxCheckResult::Invalid(TxValidationResult)` on failure. - Added `TxValidationResult` enum with all transaction validation result variants. - Added `ChainParams::new_signet` and `ContextBuilder::signet` to configure a custom signet from a user-provided challenge. +- Added a `script_trace` module with `set_script_trace_callback`/`unset_script_trace_callback` for registering a global `ScriptTracer` (or closure) that receives per-opcode `ScriptTraceFrame`s during script execution. Gated behind the `script-trace` feature. +- Added `ScriptTraceFrame`, `ScriptTraceFrameKind`, and `SigVersion` types. +- Added `KernelError::ScriptTraceUnavailable`, returned by `set_script_trace_callback` if the kernel wasn't built with `ENABLE_SCRIPT_TRACE`. ### Changed - The `verify` function's `flags` parameter now uses `ScriptVerificationFlags` instead of `u32`, making the type explicit in the public API. diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock index 3ef88bea..9066ed82 100644 --- a/Cargo-minimal.lock +++ b/Cargo-minimal.lock @@ -46,7 +46,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -56,7 +56,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -139,8 +139,15 @@ dependencies = [ "hex", "libbitcoinkernel-sys", "log", + "serial_test", ] +[[package]] +name = "bitflags" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" + [[package]] name = "cc" version = "1.2.0" @@ -156,12 +163,29 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "dashmap" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0834a35a3fce649144119e18da2a4d8ed12ef3862f47183fd46f625d072d96c" +dependencies = [ + "cfg-if 1.0.0", + "num_cpus", + "parking_lot", +] + [[package]] name = "derive_arbitrary" version = "1.0.0" @@ -169,7 +193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df89dd0d075dea5cc5fdd6d5df6b8a61172a710b3efac1d6bdb9dd8b78f82c1a" dependencies = [ "proc-macro2", - "quote 1.0.0", + "quote 1.0.25", "syn 1.0.0", ] @@ -209,11 +233,108 @@ dependencies = [ "bitcoin", "bitcoinkernel", "env_logger", + "hex", "log", "secp256k1", "silentpayments", ] +[[package]] +name = "fslock" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31bbcaaf785e09a604b93b15b9ccb41cbf4716fa04c788748d157cb3134d717b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fa4cc29d25b0687b8570b0da86eac698dcb525110ad8b938fe6712baa711ec" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0cb59f15119671c94cd9cc543dc9a50b8d5edc468b4ff5f0bb8567f66c6b48a" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "hermit-abi" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" +dependencies = [ + "libc", +] + [[package]] name = "hex" version = "0.4.0" @@ -246,9 +367,9 @@ checksum = "91fd9dc2c587067de817fec4ad355e3818c3d893a78cab32a0a474c7a15bb8d5" [[package]] name = "lazy_static" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" +checksum = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" [[package]] name = "libbitcoinkernel-sys" @@ -257,6 +378,12 @@ dependencies = [ "cc", ] +[[package]] +name = "libc" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" + [[package]] name = "libfuzzer-sys" version = "0.4.0" @@ -267,13 +394,22 @@ dependencies = [ "cc", ] +[[package]] +name = "lock_api" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if", + "cfg-if 0.1.2", ] [[package]] @@ -288,13 +424,58 @@ version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51eab148f171aefad295f8cece636fc488b9b392ef544da31ea4b8ef6b9e9c39" +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2f4f894f3865f6c0e02810fc597300f34dc2510f66400da262d8ae10e75767d" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.29.0", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "proc-macro2" -version = "1.0.0" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f287c234c9b2d0308d692dee5c449c1a171167a6f8150f7cf2a49d8fd96967" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ - "unicode-xid 0.2.0", + "unicode-ident", ] [[package]] @@ -305,9 +486,9 @@ checksum = "9f0fc799e40f2a2c2be239825b30b686f1bd1d2e0e3d5e943b14c1380db49acf" [[package]] name = "quote" -version = "1.0.0" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab938ebe6f1c82426b5fb82eaf10c3e3028c53deaa3fbe38f5904b37cf4d767" +checksum = "5308e8208729c3e1504a6cfad0d5daacc4614c9a2e65d1ea312a34b5cb00fe84" dependencies = [ "proc-macro2", ] @@ -327,6 +508,15 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +[[package]] +name = "redox_syscall" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.3.0" @@ -354,6 +544,12 @@ dependencies = [ "libfuzzer-sys", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "secp256k1" version = "0.28.1" @@ -416,6 +612,32 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ad9342b3aaca7cb43c45c097dd008d4907070394bd0751a0aa8817e5a018d" +dependencies = [ + "dashmap", + "fslock", + "futures", + "lazy_static", + "log", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93fb4adc70021ac1b47f7d45e8cc4169baaa7ea58483bc5b721d19a26202212" +dependencies = [ + "proc-macro2", + "quote 1.0.25", + "syn 2.0.0", +] + [[package]] name = "shlex" version = "1.3.0" @@ -437,6 +659,18 @@ dependencies = [ "serde_json", ] +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + [[package]] name = "syn" version = "0.11.10" @@ -455,10 +689,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f8c8eab7d9f493cd89d4068085651d81ac7d39c56eb64f7158ea514b156e280" dependencies = [ "proc-macro2", - "quote 1.0.0", + "quote 1.0.25", "unicode-xid 0.2.0", ] +[[package]] +name = "syn" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cff13bb1732bccfe3b246f3fdb09edfd51c01d6f5299b7ccd9457c2e4e37774" +dependencies = [ + "proc-macro2", + "quote 1.0.25", + "unicode-ident", +] + [[package]] name = "synom" version = "0.11.0" @@ -477,6 +722,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + [[package]] name = "unicode-xid" version = "0.0.4" @@ -495,6 +746,41 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceb069ac8b2117d36924190469735767f0990833935ab430155e71a44bafe148" +dependencies = [ + "windows_aarch64_msvc 0.29.0", + "windows_i686_gnu 0.29.0", + "windows_i686_msvc 0.29.0", + "windows_x86_64_gnu 0.29.0", + "windows_x86_64_msvc 0.29.0", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -511,12 +797,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_x86_64_msvc 0.48.0", ] [[package]] @@ -525,24 +811,48 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" + [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_i686_gnu" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" + [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_msvc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" + [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_x86_64_gnu" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" + [[package]] name = "windows_x86_64_gnu" version = "0.48.0" @@ -555,6 +865,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_msvc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" + [[package]] name = "windows_x86_64_msvc" version = "0.48.0" diff --git a/Cargo-recent.lock b/Cargo-recent.lock index af29e4ce..5dab9a7b 100644 --- a/Cargo-recent.lock +++ b/Cargo-recent.lock @@ -125,13 +125,26 @@ dependencies = [ "hex", "libbitcoinkernel-sys", "log", + "serial_test", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + [[package]] name = "cc" -version = "1.2.62" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "jobserver", @@ -151,6 +164,37 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + [[package]] name = "derive_arbitrary" version = "1.4.2" @@ -164,9 +208,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" dependencies = [ "log", "regex", @@ -174,9 +218,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.10" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" dependencies = [ "anstream", "anstyle", @@ -192,6 +236,7 @@ dependencies = [ "bitcoin", "bitcoinkernel", "env_logger", + "hex", "log", "secp256k1", "silentpayments", @@ -203,16 +248,60 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + [[package]] name = "getrandom" -version = "0.3.4" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", "r-efi", - "wasip2", ] [[package]] @@ -247,10 +336,11 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.24" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" +checksum = "ccfe6121cbe750cf81efa362d85c0bde7ea298ec43092d3a193baca59cdbd634" dependencies = [ + "defmt", "jiff-static", "log", "portable-atomic", @@ -260,9 +350,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.24" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" +checksum = "e165e897f662d428f3cd3828a919dbe067c2d42bb1031eede74ef9d27ecdedd2" dependencies = [ "proc-macro2", "quote", @@ -271,9 +361,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ "getrandom", "libc", @@ -294,25 +384,40 @@ checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libfuzzer-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" dependencies = [ "arbitrary", "cc", ] +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -320,6 +425,35 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + [[package]] name = "portable-atomic" version = "1.13.1" @@ -346,18 +480,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.3.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" @@ -374,11 +508,20 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.0", +] + [[package]] name = "regex" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -399,9 +542,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rust-bitcoinkernel-fuzz" @@ -412,6 +555,12 @@ dependencies = [ "libfuzzer-sys", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "secp256k1" version = "0.28.2" @@ -464,9 +613,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "itoa", "memchr", @@ -475,11 +624,37 @@ dependencies = [ "zmij", ] +[[package]] +name = "serial_test" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d" +dependencies = [ + "fslock", + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "silentpayments" @@ -496,17 +671,49 @@ dependencies = [ "serde_json", ] +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "unicode-ident" version = "1.0.24" @@ -520,14 +727,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "wasip2" -version = "1.0.3+wasi-0.2.9" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "wit-bindgen", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-link" version = "0.2.1" @@ -543,12 +763,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "wit-bindgen" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" - [[package]] name = "zmij" version = "1.0.21" diff --git a/Cargo.toml b/Cargo.toml index 683a5ff5..72131605 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ libbitcoinkernel-sys = { path = "libbitcoinkernel-sys", version = "0.3.0" } hex = "0.4" env_logger = "0.11" log = "0.4" +serial_test = { version = "3", features = ["file_locks"] } [workspace] members = [ @@ -26,3 +27,6 @@ members = [ "fuzz", "libbitcoinkernel-sys" ] + +[features] +script-trace = ["libbitcoinkernel-sys/script-trace"] diff --git a/README.md b/README.md index a62c2315..d4be822f 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,10 @@ documentation directly via ## Examples Examples for the usage of the library can be found in the `examples/` directory -and the `tests`. For now, the example binary implements a bare-bones silent -payments scanner. +and the `tests`. The `silentpaymentscanner` binary implements a bare-bones +silent payments scanner, and the `scripttrace` binary demonstrates the +`script_trace` feature by printing a per-opcode execution trace while +verifying a transaction. ## Fuzzing diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 8fc0bf81..783af9e3 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -8,6 +8,10 @@ publish = false name = "silentpaymentscanner" path = "src/silentpaymentscanner.rs" +[[bin]] +name = "scripttrace" +path = "src/scripttrace.rs" + [dependencies] silentpayments = "0.1" bitcoin = "0.31" @@ -15,3 +19,7 @@ secp256k1 = "0.28" env_logger = "0.11" log = "0.4" bitcoinkernel = { path = ".." } +hex = "0.4" + +[features] +script-trace = ["bitcoinkernel/script-trace"] diff --git a/examples/README.md b/examples/README.md index c7f13e4e..9053ff3c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,6 +1,12 @@ -# Example +# Examples -The example binary implements a silent payments scanner. To run it: +The `silentpaymentscanner` binary implements a silent payments scanner. To run it: +``` +cargo run --bin silentpaymentscanner -- /path/to/.bitcoin/regtest +``` -cargo run -- /path/to/.bitcoin/regtest +The `scripttrace` binary demonstrates the `script_trace` feature, printing a per-opcode execution trace while verifying a transaction. To run it: +``` +cargo run --bin scripttrace --features script-trace +``` diff --git a/examples/src/scripttrace.rs b/examples/src/scripttrace.rs new file mode 100644 index 00000000..a0add9fb --- /dev/null +++ b/examples/src/scripttrace.rs @@ -0,0 +1,81 @@ +use bitcoin::opcodes::Opcode; +use bitcoinkernel::{ + set_script_trace_callback, unset_script_trace_callback, verify, KernelError, + PrecomputedTransactionData, ScriptPubkey, ScriptTraceFrame, ScriptTraceFrameKind, Transaction, + TxOut, VERIFY_ALL_PRE_TAPROOT, +}; + +fn main() { + set_script_trace_callback(|frame: ScriptTraceFrame| match frame.kind { + ScriptTraceFrameKind::Begin => { + println!( + "== begin: {} byte script, sig_version {:?} ==", + frame.script.len(), + frame.sig_version + ); + } + ScriptTraceFrameKind::Step => { + println!( + "[step {}] opcode=0x{:02x} ({:?}) exec={} op_count={} stack_depth={}", + frame.opcode_pos, + frame.opcode, + Opcode::from(frame.opcode), + frame.exec, + frame.op_count, + frame.stack.len(), + ); + for (i, item) in frame.stack.iter().enumerate() { + println!( + " stack[{i}]: {}", + if item.is_empty() { + "".into() + } else { + hex::encode(item) + } + ); + } + } + ScriptTraceFrameKind::End => { + println!("== end: script_error={} ==", frame.script_error); + } + }) + .expect("script tracing unavailable; rebuild with ENABLE_SCRIPT_TRACE"); + + // A plain old-style P2PKH spend. + verify_test( + "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933988ac", + "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", + 0, + 0, + ) + .expect("verification failed"); + + verify_test( + // last hash byte changed 39 -> 38, so OP_EQUALVERIFY will fail + "76a9144bfbaf6afb76cc5771bc6404810d1cc041a6933888ac", + "02000000013f7cebd65c27431a90bba7f796914fe8cc2ddfc3f2cbd6f7e5f2fc854534da95000000006b483045022100de1ac3bcdfb0332207c4a91f3832bd2c2915840165f876ab47c5f8996b971c3602201c6c053d750fadde599e6f5c4e1963df0f01fc0d97815e8157e3d59fe09ca30d012103699b464d1d8bc9e47d4fb1cdaa89a1c5783d68363c4dbc4b524ed3d857148617feffffff02836d3c01000000001976a914fc25d6d5c94003bf5b0c7b640a248e2c637fcfb088ac7ada8202000000001976a914fbed3d9b11183209a57999d54d59f67c019e756c88ac6acb0700", + 0, + 0, + ) + .expect_err("expected a script verification error"); + + unset_script_trace_callback(); +} + +fn verify_test(spent: &str, spending: &str, amount: i64, input: usize) -> Result<(), KernelError> { + let spent_script_pubkey = + ScriptPubkey::try_from(hex::decode(spent).unwrap().as_slice()).unwrap(); + + let spending_tx = Transaction::new(hex::decode(spending).unwrap().as_slice()).unwrap(); + + let tx_data = PrecomputedTransactionData::new(&spending_tx, &Vec::::new()).unwrap(); + + verify( + &spent_script_pubkey, + Some(amount), + &spending_tx, + input, + Some(VERIFY_ALL_PRE_TAPROOT), + &tx_data, + ) +} diff --git a/libbitcoinkernel-sys/CHANGELOG.md b/libbitcoinkernel-sys/CHANGELOG.md index 5ad65bb6..510afb32 100644 --- a/libbitcoinkernel-sys/CHANGELOG.md +++ b/libbitcoinkernel-sys/CHANGELOG.md @@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New `btck_tx_validation_state_create`, `btck_tx_validation_state_get_validation_mode`, `btck_tx_validation_state_get_tx_validation_result` and `btck_tx_validation_state_destroy` for managing and inspecting transaction validation state - New `btck_transaction_check` for context-free consensus validation of transactions (reachable results: `UNSET` on success, `CONSENSUS` on failure) - New `btck_chain_parameters_create_signet` for creating chain parameters for a custom signet from a user-provided challenge. +- New `btck_script_trace_register_callback` and `btck_script_trace_unregister_callback` for hooking into script execution tracing +- New `btck_ScriptTraceFrame` struct exposing per-opcode execution state (stack, altstack, script, opcode position, sig version, tapleaf hash, op count, script error) +- New `btck_ScriptTraceFrameKind` and `btck_sigVersion` types with named constants +- New `script-trace` Cargo feature (off by default) that passes `-DENABLE_SCRIPT_TRACE=ON` to CMake ### Changed - `btck_block_header_create` now asserts that the input buffer is non-null and exactly 80 bytes; previously non-null buffer of any length was accepted diff --git a/libbitcoinkernel-sys/Cargo.toml b/libbitcoinkernel-sys/Cargo.toml index 9449fb34..8d139b14 100644 --- a/libbitcoinkernel-sys/Cargo.toml +++ b/libbitcoinkernel-sys/Cargo.toml @@ -54,3 +54,6 @@ publish = true [build-dependencies] cc = "1.2" + +[features] +script-trace = [] diff --git a/libbitcoinkernel-sys/bitcoin/.github/workflows/ci.yml b/libbitcoinkernel-sys/bitcoin/.github/workflows/ci.yml index 34dd688e..bce9c603 100644 --- a/libbitcoinkernel-sys/bitcoin/.github/workflows/ci.yml +++ b/libbitcoinkernel-sys/bitcoin/.github/workflows/ci.yml @@ -463,6 +463,12 @@ jobs: timeout-minutes: 120 file-env: './ci/test/00_setup_env_mac_cross_intel.sh' + - name: 'NetBSD Cross' + warp-runner: 'warp-ubuntu-latest-x64-8x' + fallback-runner: 'ubuntu-latest' + timeout-minutes: 120 + file-env: './ci/test/00_setup_env_netbsd_cross.sh' + - name: 'FreeBSD Cross' warp-runner: 'warp-ubuntu-latest-x64-8x' fallback-runner: 'ubuntu-latest' diff --git a/libbitcoinkernel-sys/bitcoin/SECURITY.md b/libbitcoinkernel-sys/bitcoin/SECURITY.md index 5a63a762..17dedcd7 100644 --- a/libbitcoinkernel-sys/bitcoin/SECURITY.md +++ b/libbitcoinkernel-sys/bitcoin/SECURITY.md @@ -13,7 +13,6 @@ The following keys may be used to communicate sensitive information to developer | Name | Fingerprint | |------|-------------| -| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 | | Michael Ford | E777 299F C265 DD04 7930 70EB 944D 35F9 AC3D B76A | | Ava Chow | 1528 1230 0785 C964 44D3 334D 1756 5732 E08E 5E41 | | Niklas Gögge | 2CBB F208 E594 BF43 9B5F 276C 7465 CFFF 6793 242E | diff --git a/libbitcoinkernel-sys/bitcoin/ci/test/00_setup_env_netbsd_cross.sh b/libbitcoinkernel-sys/bitcoin/ci/test/00_setup_env_netbsd_cross.sh new file mode 100755 index 00000000..9fb4c18a --- /dev/null +++ b/libbitcoinkernel-sys/bitcoin/ci/test/00_setup_env_netbsd_cross.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# +# Copyright (c) The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or https://opensource.org/license/mit. + +export LC_ALL=C.UTF-8 + +export CONTAINER_NAME=ci_netbsd_cross +export CI_IMAGE_NAME_TAG="mirror.gcr.io/ubuntu:26.04" +export APT_LLVM_V="22" +export HOST=x86_64-unknown-netbsd +export NETBSD_VERSION=11.0_RC6 +export NETBSD_SDK_BASENAME="netbsd-${HOST}-${NETBSD_VERSION}" +export PACKAGES="clang-${APT_LLVM_V} llvm-${APT_LLVM_V} lld-${APT_LLVM_V}" +export SYSROOT="--sysroot=${DEPENDS_DIR}/SDKs/${NETBSD_SDK_BASENAME}" +export DEP_OPTS="build_CC=clang build_CXX=clang++ \ + CC='clang --target=${HOST} ${SYSROOT}' \ + CXX='clang++ --target=${HOST} ${SYSROOT} -stdlib=libstdc++' \ + LDFLAGS='-fuse-ld=lld -lgcc_s' \ + AR=llvm-ar-${APT_LLVM_V} \ + NM=llvm-nm-${APT_LLVM_V} \ + OBJCOPY=llvm-objcopy-${APT_LLVM_V} \ + OBJDUMP=llvm-objdump-${APT_LLVM_V} \ + RANLIB=llvm-ranlib-${APT_LLVM_V} \ + STRIP=llvm-strip-${APT_LLVM_V}" +export GOAL="install" +export BITCOIN_CONFIG="\ + --preset=dev-mode \ + -DBUILD_GUI=OFF \ + -DREDUCE_EXPORTS=ON \ + -DWITH_USDT=OFF \ +" +export RUN_UNIT_TESTS=false +export RUN_FUNCTIONAL_TESTS=false diff --git a/libbitcoinkernel-sys/bitcoin/ci/test/00_setup_env_openbsd_cross.sh b/libbitcoinkernel-sys/bitcoin/ci/test/00_setup_env_openbsd_cross.sh index 30d36213..1732aef3 100755 --- a/libbitcoinkernel-sys/bitcoin/ci/test/00_setup_env_openbsd_cross.sh +++ b/libbitcoinkernel-sys/bitcoin/ci/test/00_setup_env_openbsd_cross.sh @@ -14,7 +14,7 @@ export OPENBSD_VERSION=7.9 export OPENBSD_SDK_BASENAME="openbsd-${HOST}-${OPENBSD_VERSION}" export PACKAGES="clang-${APT_LLVM_V} llvm-${APT_LLVM_V} lld-${APT_LLVM_V}" export SYSROOT="--sysroot=${DEPENDS_DIR}/SDKs/${OPENBSD_SDK_BASENAME}" -export DEP_OPTS="build_CC=clang build_CXX=clang++ \ +export DEP_OPTS="NO_QT=1 build_CC=clang build_CXX=clang++ \ CC='clang --target=${HOST} ${SYSROOT}' \ CXX='clang++ --target=${HOST} ${SYSROOT} -stdlib=libc++' \ LDFLAGS='-fuse-ld=lld' \ diff --git a/libbitcoinkernel-sys/bitcoin/ci/test/01_base_install.sh b/libbitcoinkernel-sys/bitcoin/ci/test/01_base_install.sh index 652416b9..f619a088 100755 --- a/libbitcoinkernel-sys/bitcoin/ci/test/01_base_install.sh +++ b/libbitcoinkernel-sys/bitcoin/ci/test/01_base_install.sh @@ -118,6 +118,17 @@ if [ -n "$XCODE_VERSION" ] && [ ! -d "${DEPENDS_DIR}/SDKs/${OSX_SDK_BASENAME}" ] tar -C "${DEPENDS_DIR}/SDKs" -xf "$OSX_SDK_PATH" fi +if [ -n "$NETBSD_VERSION" ] && [ ! -d "${DEPENDS_DIR}/SDKs/${NETBSD_SDK_BASENAME}" ]; then + mkdir -p "${DEPENDS_DIR}/SDKs/${NETBSD_SDK_BASENAME}" + for NETBSD_SDK_FILENAME in base.tar.xz comp.tar.xz; do + NETBSD_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${NETBSD_SDK_FILENAME}" + if [ ! -f "$NETBSD_SDK_PATH" ]; then + ${CI_RETRY_EXE} curl --location --fail "https://cdn.netbsd.org/pub/NetBSD/NetBSD-${NETBSD_VERSION}/amd64/binary/sets/${NETBSD_SDK_FILENAME}" -o "$NETBSD_SDK_PATH" + fi + tar -C "${DEPENDS_DIR}/SDKs/${NETBSD_SDK_BASENAME}" -xf "$NETBSD_SDK_PATH" + done +fi + if [ -n "$FREEBSD_VERSION" ] && [ ! -d "${DEPENDS_DIR}/SDKs/${FREEBSD_SDK_BASENAME}" ]; then FREEBSD_SDK_FILENAME="base-${FREEBSD_VERSION}.txz" FREEBSD_SDK_PATH="${DEPENDS_DIR}/sdk-sources/${FREEBSD_SDK_FILENAME}" diff --git a/libbitcoinkernel-sys/bitcoin/contrib/seeds/README.md b/libbitcoinkernel-sys/bitcoin/contrib/seeds/README.md index 2eb68467..388ddd54 100644 --- a/libbitcoinkernel-sys/bitcoin/contrib/seeds/README.md +++ b/libbitcoinkernel-sys/bitcoin/contrib/seeds/README.md @@ -15,8 +15,7 @@ DNS seed, virtu's crawler, and asmap community AS map data. Run the following co from the `/contrib/seeds` directory: ``` -curl https://bitcoin.sipa.be/seeds.txt.gz | gzip -dc > seeds_main.txt -curl https://21.ninja/seeds.txt.gz | gzip -dc >> seeds_main.txt +curl https://21.ninja/seeds.txt.gz | gzip -dc > seeds_main.txt curl https://mainnet.achownodes.xyz/seeds.txt.gz | gzip -dc >> seeds_main.txt curl https://signet.achownodes.xyz/seeds.txt.gz | gzip -dc > seeds_signet.txt curl https://testnet.achownodes.xyz/seeds.txt.gz | gzip -dc > seeds_test.txt diff --git a/libbitcoinkernel-sys/bitcoin/depends/README.md b/libbitcoinkernel-sys/bitcoin/depends/README.md index b7d7d226..83ebf8e2 100644 --- a/libbitcoinkernel-sys/bitcoin/depends/README.md +++ b/libbitcoinkernel-sys/bitcoin/depends/README.md @@ -53,6 +53,10 @@ To build dependencies for the current arch+OS: pkg_add bash cmake curl gmake gtar +Skip the following packages if you don't intend to use the GUI and will build with [`NO_QT=1`](#dependency-options): + + pkg_add bison ninja + To build dependencies for the current arch+OS: gmake diff --git a/libbitcoinkernel-sys/bitcoin/depends/hosts/netbsd.mk b/libbitcoinkernel-sys/bitcoin/depends/hosts/netbsd.mk index 0e1256c3..df7a5ea9 100644 --- a/libbitcoinkernel-sys/bitcoin/depends/hosts/netbsd.mk +++ b/libbitcoinkernel-sys/bitcoin/depends/hosts/netbsd.mk @@ -1,5 +1,6 @@ netbsd_CFLAGS= netbsd_CXXFLAGS= +netbsd_LDFLAGS= ifneq ($(LTO),) netbsd_AR = $(host_toolchain)gcc-ar diff --git a/libbitcoinkernel-sys/bitcoin/depends/packages/freetype.mk b/libbitcoinkernel-sys/bitcoin/depends/packages/freetype.mk index b34edc60..74d5e42a 100644 --- a/libbitcoinkernel-sys/bitcoin/depends/packages/freetype.mk +++ b/libbitcoinkernel-sys/bitcoin/depends/packages/freetype.mk @@ -5,6 +5,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=f8db94d307e9c54961b39a1cc799a67d46681480696ed72ecf78d4473770f09b $(package)_build_subdir=build $(package)_patches += cmake_minimum.patch +$(package)_patches += openbsd_versioning.patch define $(package)_set_vars $(package)_config_opts := -DCMAKE_BUILD_TYPE=None -DBUILD_SHARED_LIBS=TRUE @@ -14,7 +15,8 @@ define $(package)_set_vars endef define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch + patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch && \ + patch -p1 < $($(package)_patch_dir)/openbsd_versioning.patch endef define $(package)_config_cmds diff --git a/libbitcoinkernel-sys/bitcoin/depends/packages/native_capnp.mk b/libbitcoinkernel-sys/bitcoin/depends/packages/native_capnp.mk index d65a8b97..f207421d 100644 --- a/libbitcoinkernel-sys/bitcoin/depends/packages/native_capnp.mk +++ b/libbitcoinkernel-sys/bitcoin/depends/packages/native_capnp.mk @@ -1,9 +1,9 @@ package=native_capnp -$(package)_version=1.4.0 +$(package)_version=1.5.0 $(package)_download_path=https://capnproto.org/ $(package)_download_file=capnproto-c++-$($(package)_version).tar.gz $(package)_file_name=capnproto-cxx-$($(package)_version).tar.gz -$(package)_sha256_hash=fa02378ad522b318916b9ad928d1372fc9abd43dd1f4f0392e50450f5c87828f +$(package)_sha256_hash=77dbc13ca82d9c87ddb4581dd49559d45b63096433d3dadea08b7f31b360a5ba define $(package)_set_vars $(package)_config_opts := -DBUILD_TESTING=OFF diff --git a/libbitcoinkernel-sys/bitcoin/depends/packages/packages.mk b/libbitcoinkernel-sys/bitcoin/depends/packages/packages.mk index a5384331..f50b45d0 100644 --- a/libbitcoinkernel-sys/bitcoin/depends/packages/packages.mk +++ b/libbitcoinkernel-sys/bitcoin/depends/packages/packages.mk @@ -4,11 +4,13 @@ boost_packages = boost qrencode_linux_packages = qrencode qrencode_freebsd_packages = qrencode +qrencode_openbsd_packages = qrencode qrencode_darwin_packages = qrencode qrencode_mingw32_packages = qrencode qt_linux_packages:=qt expat libxcb xcb_proto libXau xproto freetype fontconfig libxkbcommon libxcb_util libxcb_util_cursor libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm qt_freebsd_packages:=$(qt_linux_packages) +qt_openbsd_packages:=$(qt_linux_packages) qt_darwin_packages=qt qt_mingw32_packages=qt ifneq ($(host),$(build)) diff --git a/libbitcoinkernel-sys/bitcoin/depends/packages/qt.mk b/libbitcoinkernel-sys/bitcoin/depends/packages/qt.mk index 9b7cec34..500a2729 100644 --- a/libbitcoinkernel-sys/bitcoin/depends/packages/qt.mk +++ b/libbitcoinkernel-sys/bitcoin/depends/packages/qt.mk @@ -9,6 +9,7 @@ $(package)_dependencies := native_$(package) endif $(package)_linux_dependencies := freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_cursor libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm $(package)_freebsd_dependencies := $($(package)_linux_dependencies) +$(package)_openbsd_dependencies := $($(package)_linux_dependencies) $(package)_patches_path := $(qt_details_patches_path) $(package)_patches := cocoa_compat.patch $(package)_patches += dont_hardcode_pwd.patch @@ -26,6 +27,8 @@ $(package)_patches += fix-gcc16-sfinae-qbitarray.patch $(package)_patches += fix-gcc16-sfinae-qanystringview.patch $(package)_patches += fix-macos26-qyield.patch $(package)_patches += fix-qbytearray-include.patch +$(package)_patches += fix_openbsd_network_kernel.patch +$(package)_patches += fix_openbsd_plugin_qelfparser.patch $(package)_qttranslations_file_name=$(qt_details_qttranslations_file_name) $(package)_qttranslations_sha256_hash=$(qt_details_qttranslations_sha256_hash) @@ -158,6 +161,7 @@ $(package)_config_opts_linux += -ltcg endif $(package)_config_opts_freebsd := $$($(package)_config_opts_linux) $(package)_config_opts_freebsd += -no-feature-inotify +$(package)_config_opts_openbsd := $$($(package)_config_opts_linux) $(package)_config_opts_mingw32 := -no-dbus $(package)_config_opts_mingw32 += -no-feature-freetype @@ -208,7 +212,7 @@ $(package)_cmake_opts += -DCMAKE_DISABLE_FIND_PACKAGE_WrapSystemDoubleConversion $(package)_cmake_opts += -DCMAKE_DISABLE_FIND_PACKAGE_WrapSystemMd4c=TRUE $(package)_cmake_opts += -DCMAKE_DISABLE_FIND_PACKAGE_WrapZSTD=TRUE endif -ifeq ($(host_os),linux) +ifneq (,$(filter linux openbsd,$(host_os))) # The `-dbus-runtime` configure option does not work # https://qt-project.atlassian.net/browse/QTBUG-144864 $(package)_cmake_opts += -DINPUT_dbus=runtime @@ -284,7 +288,9 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/fix-gcc16-sfinae-qbitarray.patch && \ patch -p1 -i $($(package)_patch_dir)/fix-gcc16-sfinae-qanystringview.patch && \ patch -p1 -i $($(package)_patch_dir)/fix-macos26-qyield.patch && \ - patch -p1 -i $($(package)_patch_dir)/fix-qbytearray-include.patch + patch -p1 -i $($(package)_patch_dir)/fix-qbytearray-include.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_openbsd_network_kernel.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix_openbsd_plugin_qelfparser.patch endef ifeq ($(host),$(build)) $(package)_preprocess_cmds += && patch -p1 -i $($(package)_patch_dir)/qttools_skip_dependencies.patch diff --git a/libbitcoinkernel-sys/bitcoin/depends/patches/freetype/openbsd_versioning.patch b/libbitcoinkernel-sys/bitcoin/depends/patches/freetype/openbsd_versioning.patch new file mode 100644 index 00000000..ea5cffef --- /dev/null +++ b/libbitcoinkernel-sys/bitcoin/depends/patches/freetype/openbsd_versioning.patch @@ -0,0 +1,31 @@ +[cmake] Fix shared library versioning on OpenBSD. + +This emulates Libtool to make sure Libtool and CMake agree on the ABI +version. Specifically, for OpenBSD, `builds/unix/configure` defines +`version_type=sunos` and skips defining `soname_spec`. + +See upstream MR: https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/433. + +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -458,9 +458,17 @@ if (WIN32) + endif () + + if (BUILD_SHARED_LIBS) +- set_target_properties(freetype PROPERTIES +- VERSION ${LIBRARY_VERSION} +- SOVERSION ${LIBRARY_SOVERSION}) ++ if (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") ++ # For OpenBSD, libtool follows `sunos` version type. ++ set_target_properties(freetype PROPERTIES ++ # libtool does not define its internal `soname_spec` variable ++ # for OpenBSD. So skipping the SOVERSION option. ++ VERSION ${LIBTOOL_CURRENT}.${LIBTOOL_REVISION}) ++ else () ++ set_target_properties(freetype PROPERTIES ++ VERSION ${LIBRARY_VERSION} ++ SOVERSION ${LIBRARY_SOVERSION}) ++ endif () + endif () + + # Pick up ftconfig.h and ftoption.h generated above, first. diff --git a/libbitcoinkernel-sys/bitcoin/depends/patches/qt/fix_openbsd_network_kernel.patch b/libbitcoinkernel-sys/bitcoin/depends/patches/qt/fix_openbsd_network_kernel.patch new file mode 100644 index 00000000..2a5a4ac2 --- /dev/null +++ b/libbitcoinkernel-sys/bitcoin/depends/patches/qt/fix_openbsd_network_kernel.patch @@ -0,0 +1,31 @@ +Fix compiling on OpenBSD + +1. The `net/if_types.h` header does not define the `IFT_STF` symbol. +2. The `netinet6/in6_var.h` header defines some of the used symbols. + +For the reference, see: + - https://codeberg.org/OpenBSD/ports/src/commit/f8f1aedbe8aff550c69930b5d92b9c392e298382/x11/qt6/qtbase/patches/patch-src_network_kernel_qnetworkinterface_unix_cpp + + +--- a/qtbase/src/network/kernel/qnetworkinterface_unix.cpp ++++ b/qtbase/src/network/kernel/qnetworkinterface_unix.cpp +@@ -392,6 +392,9 @@ QT_BEGIN_INCLUDE_NAMESPACE + # include + # include + # include ++# ifdef Q_OS_OPENBSD ++# include ++# endif + #endif // QT_PLATFORM_UIKIT + QT_END_INCLUDE_NAMESPACE + +@@ -419,7 +422,9 @@ static QNetworkInterface::InterfaceType probeIfType(int socket, int iftype, stru + return QNetworkInterface::Ieee1394; + + case IFT_GIF: ++#ifndef Q_OS_OPENBSD + case IFT_STF: ++#endif + return QNetworkInterface::Virtual; + } + diff --git a/libbitcoinkernel-sys/bitcoin/depends/patches/qt/fix_openbsd_plugin_qelfparser.patch b/libbitcoinkernel-sys/bitcoin/depends/patches/qt/fix_openbsd_plugin_qelfparser.patch new file mode 100644 index 00000000..1b32e45f --- /dev/null +++ b/libbitcoinkernel-sys/bitcoin/depends/patches/qt/fix_openbsd_plugin_qelfparser.patch @@ -0,0 +1,20 @@ +Fix compiling on OpenBSD + +Avoid use of undeclared identifier `ELFOSABI_AIX`. + +For the reference, see: + - https://codeberg.org/OpenBSD/ports/src/commit/c5e4088b89277b96d840492f9961b1593182b99c/x11/qt6/qtbase/patches/patch-src_corelib_plugin_qelfparser_p_cpp + + +--- a/qtbase/src/corelib/plugin/qelfparser_p.cpp ++++ b/qtbase/src/corelib/plugin/qelfparser_p.cpp +@@ -341,7 +341,9 @@ Q_DECL_UNUSED Q_DECL_COLD_FUNCTION static QDebug &operator<<(QDebug &d, ElfHeade + case ELFOSABI_NETBSD: d << " (NetBSD"; break; + case ELFOSABI_LINUX: d << " (GNU/Linux"; break; + case ELFOSABI_SOLARIS: d << " (Solaris"; break; ++#ifndef Q_OS_OPENBSD + case ELFOSABI_AIX: d << " (AIX"; break; ++#endif + case ELFOSABI_IRIX: d << " (IRIX"; break; + case ELFOSABI_FREEBSD: d << " (FreeBSD"; break; + case ELFOSABI_OPENBSD: d << " (OpenBSD"; break; diff --git a/libbitcoinkernel-sys/bitcoin/depends/toolchain.cmake.in b/libbitcoinkernel-sys/bitcoin/depends/toolchain.cmake.in index 87189efa..9d9f9e49 100644 --- a/libbitcoinkernel-sys/bitcoin/depends/toolchain.cmake.in +++ b/libbitcoinkernel-sys/bitcoin/depends/toolchain.cmake.in @@ -117,7 +117,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT CMAKE_HOST_APPLE) endif() -if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD)$") +if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD|OpenBSD)$") # Customize pkg-config behavior for finding dependencies # of the xcb QPA platform plugin: # 1. Restrict search paths to the depends. diff --git a/libbitcoinkernel-sys/bitcoin/doc/build-freebsd.md b/libbitcoinkernel-sys/bitcoin/doc/build-freebsd.md index 436b57c9..ffb8ecfe 100644 --- a/libbitcoinkernel-sys/bitcoin/doc/build-freebsd.md +++ b/libbitcoinkernel-sys/bitcoin/doc/build-freebsd.md @@ -1,8 +1,8 @@ # FreeBSD Build Guide -**Updated for FreeBSD [15.0](https://www.freebsd.org/releases/15.0R/announce/)** +Bitcoin Core is supported on all [supported FreeBSD releases](https://www.freebsd.org/security/#sup). -This guide describes how to build bitcoind, command-line utilities, and GUI on FreeBSD. +This guide describes how to build bitcoind, command-line utilities, and GUI on the most recent production release. ## Preparation diff --git a/libbitcoinkernel-sys/bitcoin/doc/build-netbsd.md b/libbitcoinkernel-sys/bitcoin/doc/build-netbsd.md index c269d2a1..d4d031d3 100644 --- a/libbitcoinkernel-sys/bitcoin/doc/build-netbsd.md +++ b/libbitcoinkernel-sys/bitcoin/doc/build-netbsd.md @@ -1,8 +1,8 @@ # NetBSD Build Guide -**Updated for NetBSD [10.1](https://netbsd.org/releases/formal-10/NetBSD-10.1.html)** +Bitcoin Core is supported on all [supported NetBSD releases](https://www.netbsd.org/releases/). -This guide describes how to build bitcoind, command-line utilities, and GUI on NetBSD. +This guide describes how to build bitcoind, command-line utilities, and GUI on the latest release. ## Preparation diff --git a/libbitcoinkernel-sys/bitcoin/doc/build-openbsd.md b/libbitcoinkernel-sys/bitcoin/doc/build-openbsd.md index d64fd909..bcc2eba6 100644 --- a/libbitcoinkernel-sys/bitcoin/doc/build-openbsd.md +++ b/libbitcoinkernel-sys/bitcoin/doc/build-openbsd.md @@ -1,8 +1,8 @@ # OpenBSD Build Guide -**Updated for OpenBSD [7.8](https://www.openbsd.org/78.html)** +Bitcoin Core is supported on [the two most recent OpenBSD releases](https://www.openbsd.org/faq/faq5.html#Flavors). -This guide describes how to build bitcoind, command-line utilities, and GUI on OpenBSD. +This guide describes how to build bitcoind, command-line utilities, and GUI on the latest release. ## Preparation diff --git a/libbitcoinkernel-sys/bitcoin/doc/developer-notes.md b/libbitcoinkernel-sys/bitcoin/doc/developer-notes.md index 3edf5d34..0bc1bd25 100644 --- a/libbitcoinkernel-sys/bitcoin/doc/developer-notes.md +++ b/libbitcoinkernel-sys/bitcoin/doc/developer-notes.md @@ -40,10 +40,10 @@ code. - Class member variables have a `m_` prefix. - Global variables have a `g_` prefix. - Constant names are all uppercase, and use `_` to separate words. - - Enumerator constants may be `snake_case`, `PascalCase` or `ALL_CAPS`. - This is a more tolerant policy than the [C++ Core + - Enumerator constants may be `snake_case`, or `PascalCase`. They should not + be `ALL_CAPS`, according to the [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#renum-caps), - which recommend using `snake_case`. Please use what seems appropriate. + to avoid clashing with macros. - Class names, function names, and method names are UpperCamelCase (PascalCase). Do not prefix class names with `C`. See [Internal interface naming style](#internal-interface-naming-style) for an exception to this diff --git a/libbitcoinkernel-sys/bitcoin/doc/release-notes-35634.md b/libbitcoinkernel-sys/bitcoin/doc/release-notes-35634.md index ccbd7fd7..2398305b 100644 --- a/libbitcoinkernel-sys/bitcoin/doc/release-notes-35634.md +++ b/libbitcoinkernel-sys/bitcoin/doc/release-notes-35634.md @@ -1,9 +1,8 @@ Indexes ------- -- The transaction output spender index (`-txospenderindex`) now stores one byte - less per spender entry for newly indexed blocks. Existing indexes remain - compatible and no action is required. To apply the same saving to entries - indexed before upgrading, stop the node, delete the +- The transaction output spender index (`-txospenderindex`) now uses less disk + space. Existing indexes remain compatible and no action is required. To reclaim + the space for data indexed before upgrading, stop the node, delete the `/indexes/txospenderindex/` directory, and restart with - `-txospenderindex` enabled to rebuild it. + `-txospenderindex` enabled to rebuild it. (#35634, #35568) diff --git a/libbitcoinkernel-sys/bitcoin/doc/release-notes/release-notes-29.4.md b/libbitcoinkernel-sys/bitcoin/doc/release-notes/release-notes-29.4.md new file mode 100644 index 00000000..3ff905db --- /dev/null +++ b/libbitcoinkernel-sys/bitcoin/doc/release-notes/release-notes-29.4.md @@ -0,0 +1,107 @@ +Bitcoin Core version 29.4 is now available from: + + + +This release includes various bug fixes and performance +improvements, as well as updated translations. + +Please report bugs using the issue tracker at GitHub: + + + +To receive security and update notifications, please subscribe to: + + + +How to Upgrade +============== + +If you are running an older version, shut it down. Wait until it has completely +shut down (which might take a few minutes in some cases), then run the +installer (on Windows) or just copy over `/Applications/Bitcoin-Qt` (on macOS) +or `bitcoind`/`bitcoin-qt` (on Linux). + +Upgrading directly from a version of Bitcoin Core that has reached its EOL is +possible, but it might take some time if the data directory needs to be migrated. Old +wallet versions of Bitcoin Core are generally supported. + +Compatibility +============== + +Bitcoin Core is supported and tested on operating systems using the +Linux Kernel 3.17+, macOS 13+, and Windows 10+. Bitcoin +Core should also work on most other Unix-like systems but is not as +frequently tested on them. It is not recommended to use Bitcoin Core on +unsupported systems. + +Notable changes +=============== + +This release fixes an issue where the chainstate database would repeatedly +rewrite large portions of itself, causing excessive disk reads and writes +during normal operation. + +### Validation + +- #35209 validation: correct lifetime of precomputed tx data +- #35465 coins: compact chainstate regularly + +### Leveldb + +- #61(bitcoin-core/leveldb): Disable seek compaction + +### Net + +- #34093 netif: fix compilation warning in QueryDefaultGatewayImpl() + +### Wallet + +- #35228 wallet: use outpoint when estimating input size + +### Build + +- #34228 depends: Unset SOURCE_DATE_EPOCH in gen_id script +- #34848 cmake: Migrate away from deprecated SQLite3 target + +### Test + +- #34918 fuzz: [refactor] Remove unused g_setup pointers + +### Doc + +- #34510 doc: fix broken bpftrace installation link +- #34561 wallet: rpc: manpage: fix example missing `fee_rate` argument +- #34671 doc: Update Guix install for Debian/Ubuntu +- #35283 doc: mention -DWITH_ZMQ=ON in BSD build guides + +### CI + +- #35202 ci: restore sockets in i686, no IPC job +- #35378 ci: switch runners from cirrus to warpbuild +- #35408 ci: 35378 followups + +### Misc + +- #35175 multi_index: fix compilation failure with boost >= 1.91 + +Credits +======= + +Thanks to everyone who directly contributed to this release: + +- andrewtoth +- Cory Fields +- Daniel Pfeifer +- darosior +- fanquake +- Hennadii Stepanov +- jayvaliya +- junbyjun1238 +- Lőrinc +- MarcoFalke +- SomberNight +- ToRyVand +- willcl-ark + +As well as to everyone that helped with translations on +[Transifex](https://explore.transifex.com/bitcoin/bitcoin/). diff --git a/libbitcoinkernel-sys/bitcoin/src/bench/coin_selection.cpp b/libbitcoinkernel-sys/bitcoin/src/bench/coin_selection.cpp index 4f203fe8..5c54cafc 100644 --- a/libbitcoinkernel-sys/bitcoin/src/bench/coin_selection.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/bench/coin_selection.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -50,7 +50,7 @@ static void addCoin(const CAmount& nValue, std::vector(); - CWallet wallet(test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()); + CWallet wallet(test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()); std::vector> wtxs; LOCK(wallet.cs_wallet); diff --git a/libbitcoinkernel-sys/bitcoin/src/bench/wallet_balance.cpp b/libbitcoinkernel-sys/bitcoin/src/bench/wallet_balance.cpp index 958044e2..76d0fd39 100644 --- a/libbitcoinkernel-sys/bitcoin/src/bench/wallet_balance.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/bench/wallet_balance.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,7 @@ static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const b // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process. // The reason is 'generatetoaddress', which creates a chain with deterministic timestamps in the past. FakeNodeClock clock{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()}; - CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()}; + CWallet wallet{test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()}; { LOCK(wallet.cs_wallet); wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); diff --git a/libbitcoinkernel-sys/bitcoin/src/bench/wallet_create_tx.cpp b/libbitcoinkernel-sys/bitcoin/src/bench/wallet_create_tx.cpp index 394f21ce..b0140910 100644 --- a/libbitcoinkernel-sys/bitcoin/src/bench/wallet_create_tx.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/bench/wallet_create_tx.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,7 @@ using kernel::ChainstateRole; using wallet::CWallet; -using wallet::CreateMockableWalletDatabase; +using wallet::MakeInMemoryWalletDatabase; using wallet::WALLET_FLAG_DESCRIPTORS; struct TipBlock @@ -120,7 +121,7 @@ static void WalletCreateTx(benchmark::Bench& bench, const OutputType output_type // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process. FakeNodeClock clock{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()}; - CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()}; + CWallet wallet{test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()}; { LOCK(wallet.cs_wallet); wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); @@ -175,7 +176,7 @@ static void AvailableCoins(benchmark::Bench& bench, const std::vector(); // Set clock to genesis block, so the descriptors/keys creation time don't interfere with the blocks scanning process. FakeNodeClock clock{test_setup->m_node.chainman->GetParams().GenesisBlock().Time()}; - CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase()}; + CWallet wallet{test_setup->m_node.chain.get(), "", MakeInMemoryWalletDatabase()}; { LOCK(wallet.cs_wallet); wallet.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); diff --git a/libbitcoinkernel-sys/bitcoin/src/bench/wallet_encrypt.cpp b/libbitcoinkernel-sys/bitcoin/src/bench/wallet_encrypt.cpp index 81e64a28..7f6ff3af 100644 --- a/libbitcoinkernel-sys/bitcoin/src/bench/wallet_encrypt.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/bench/wallet_encrypt.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ static void WalletEncrypt(benchmark::Bench& bench, unsigned int key_count) TestUnloadWallet(std::move(wallet)); } - std::unique_ptr database = CreateMockableWalletDatabase(); + std::unique_ptr database = MakeInMemoryWalletDatabase(); wallet = TestCreateWallet(std::move(database), context, create_flags); { diff --git a/libbitcoinkernel-sys/bitcoin/src/bench/wallet_ismine.cpp b/libbitcoinkernel-sys/bitcoin/src/bench/wallet_ismine.cpp index 572a2717..4b059b34 100644 --- a/libbitcoinkernel-sys/bitcoin/src/bench/wallet_ismine.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/bench/wallet_ismine.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +38,7 @@ static void WalletIsMine(benchmark::Bench& bench, int num_combo = 0) // Setup the wallet // Loading the wallet will also create it uint64_t create_flags = WALLET_FLAG_DESCRIPTORS; - auto database = CreateMockableWalletDatabase(); + auto database = MakeInMemoryWalletDatabase(); auto wallet = TestCreateWallet(std::move(database), context, create_flags); // For a descriptor wallet, fill with num_combo combo descriptors with random keys diff --git a/libbitcoinkernel-sys/bitcoin/src/common/netif.cpp b/libbitcoinkernel-sys/bitcoin/src/common/netif.cpp index a30046c7..997db7d5 100644 --- a/libbitcoinkernel-sys/bitcoin/src/common/netif.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/common/netif.cpp @@ -14,13 +14,8 @@ #if defined(__linux__) #include #elif defined(__FreeBSD__) -#include -#if __FreeBSD_version >= 1400000 -// Workaround https://github.com/freebsd/freebsd-src/pull/1070. -#define typeof __typeof #include #include -#endif #elif defined(WIN32) #include #elif defined(__APPLE__) @@ -60,10 +55,8 @@ std::optional FromSockAddr(const struct sockaddr* addr, std::optional< return std::nullopt; } -// Linux and FreeBSD 14.0+. For FreeBSD 13.2 the code can be compiled but -// running it requires loading a special kernel module, otherwise socket(AF_NETLINK,...) -// will fail, so we skip that. -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 1400000) +// Linux and FreeBSD. +#if defined(__linux__) || defined(__FreeBSD__) // Good for responses containing ~ 10,000-15,000 routes. static constexpr ssize_t NETLINK_MAX_RESPONSE_SIZE{1'048'576}; diff --git a/libbitcoinkernel-sys/bitcoin/src/dbwrapper.cpp b/libbitcoinkernel-sys/bitcoin/src/dbwrapper.cpp index ffe6f267..ed914273 100644 --- a/libbitcoinkernel-sys/bitcoin/src/dbwrapper.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/dbwrapper.cpp @@ -136,12 +136,12 @@ static void SetMaxOpenFiles(leveldb::Options *options) { options->max_open_files, default_open_files); } -static leveldb::Options GetOptions(size_t nCacheSize) +static leveldb::Options GetOptions(size_t nCacheSize, bool bloom_filter) { leveldb::Options options; options.block_cache = leveldb::NewLRUCache(nCacheSize / 2); options.write_buffer_size = nCacheSize / 4; // up to two write buffers may be held in memory simultaneously - options.filter_policy = leveldb::NewBloomFilterPolicy(10); + options.filter_policy = bloom_filter ? leveldb::NewBloomFilterPolicy(10) : nullptr; options.compression = leveldb::kNoCompression; options.info_log = new CBitcoinLevelDBLogger(); if (leveldb::kMajorVersion > 1 || (leveldb::kMajorVersion == 1 && leveldb::kMinorVersion >= 16)) { @@ -225,7 +225,7 @@ CDBWrapper::CDBWrapper(const DBParams& params) DBContext().iteroptions.verify_checksums = true; DBContext().iteroptions.fill_cache = false; DBContext().syncoptions.sync = true; - DBContext().options = GetOptions(params.cache_bytes); + DBContext().options = GetOptions(params.cache_bytes, params.bloom_filter); DBContext().options.create_if_missing = true; DBContext().options.max_file_size = params.max_file_size; assert(!(params.testing_env && params.memory_only)); diff --git a/libbitcoinkernel-sys/bitcoin/src/dbwrapper.h b/libbitcoinkernel-sys/bitcoin/src/dbwrapper.h index 2c1f8039..1eb68a3b 100644 --- a/libbitcoinkernel-sys/bitcoin/src/dbwrapper.h +++ b/libbitcoinkernel-sys/bitcoin/src/dbwrapper.h @@ -50,6 +50,8 @@ struct DBParams { //! If true, store data obfuscated via simple XOR. If false, XOR with a //! zero'd byte array. bool obfuscate = false; + //! If true, build a LevelDB bloom filter to accelerate point lookups. + bool bloom_filter = true; //! Passed-through options. DBOptions options{}; //! If non-null, use this as the leveldb::Env instead of the default. diff --git a/libbitcoinkernel-sys/bitcoin/src/index/base.cpp b/libbitcoinkernel-sys/bitcoin/src/index/base.cpp index 906ed265..5820448b 100644 --- a/libbitcoinkernel-sys/bitcoin/src/index/base.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/index/base.cpp @@ -65,13 +65,14 @@ CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash) return locator; } -BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) : +BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate, bool f_bloom) : CDBWrapper{DBParams{ .path = path, .cache_bytes = n_cache_size, .memory_only = f_memory, .wipe_data = f_wipe, .obfuscate = f_obfuscate, + .bloom_filter = f_bloom, .options = [] { DBOptions options; node::ReadDatabaseArgs(gArgs, options); return options; }()}} {} @@ -273,12 +274,23 @@ void BaseIndex::Sync() } } -bool BaseIndex::Commit() +void BaseIndex::Commit() { // Don't commit anything if we haven't indexed any block yet // (this could happen if init is interrupted). bool ok = m_best_block_index != nullptr; if (ok) { + // Don't commit if the index best block is not an ancestor of the chainstate's last flushed + // block. Otherwise, after an unclean shutdown, the index could be + // persisted ahead of a chainstate it can no longer roll back to, which + // would corrupt indexes with state (e.g. coinstatsindex). + const CBlockIndex* index_tip = m_best_block_index.load(); + const CBlockIndex* last_flushed = WITH_LOCK(::cs_main, return m_chainstate->GetLastFlushedBlock()); + if (!last_flushed || last_flushed->GetAncestor(index_tip->nHeight) != index_tip) { + LogDebug(BCLog::COINDB, "Skipping commit, index is ahead of flushed chainstate (index height %d, last flush at height %d)", + index_tip->nHeight, last_flushed ? last_flushed->nHeight : -1); + return; + } CDBBatch batch(GetDB()); ok = CustomCommit(batch); if (ok) { @@ -288,9 +300,7 @@ bool BaseIndex::Commit() } if (!ok) { LogError("Failed to commit latest %s state", GetName()); - return false; } - return true; } bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip) diff --git a/libbitcoinkernel-sys/bitcoin/src/index/base.h b/libbitcoinkernel-sys/bitcoin/src/index/base.h index 6d7e86ec..73282a96 100644 --- a/libbitcoinkernel-sys/bitcoin/src/index/base.h +++ b/libbitcoinkernel-sys/bitcoin/src/index/base.h @@ -65,7 +65,7 @@ class BaseIndex : public CValidationInterface { public: DB(const fs::path& path, size_t n_cache_size, - bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false); + bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false, bool f_bloom = true); /// Read block locator of the chain that the index is in sync with. /// Note, the returned locator will be empty if no record exists. @@ -94,14 +94,10 @@ class BaseIndex : public CValidationInterface CThreadInterrupt m_interrupt; /// Write the current index state (eg. chain block locator and subclass-specific items) to disk. - /// - /// Recommendations for error handling: - /// If called on a successor of the previous committed best block in the index, the index can - /// continue processing without risk of corruption, though the index state will need to catch up - /// from further behind on reboot. If the new state is not a successor of the previous state (due - /// to a chain reorganization), the index must halt until Commit succeeds or else it could end up - /// getting corrupted. - bool Commit(); + /// Will skip the commit if no block has been indexed yet or if the index's best block is + /// ahead of the chainstate's last flushed block. This avoids persisting state an unclean shutdown + /// could not roll back from. A later call commits when the chainstate has flushed far enough. + void Commit(); /// Loop over disconnected blocks and call CustomRemove. bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip); diff --git a/libbitcoinkernel-sys/bitcoin/src/index/txospenderindex.cpp b/libbitcoinkernel-sys/bitcoin/src/index/txospenderindex.cpp index 50b9bfeb..304104df 100644 --- a/libbitcoinkernel-sys/bitcoin/src/index/txospenderindex.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/index/txospenderindex.cpp @@ -62,7 +62,7 @@ struct DBKey { }; TxoSpenderIndex::TxoSpenderIndex(std::unique_ptr chain, size_t n_cache_size, bool f_memory, bool f_wipe) - : BaseIndex(std::move(chain), "txospenderindex", "txospenderidx"), m_db{std::make_unique(gArgs.GetDataDirNet() / "indexes" / "txospenderindex" / "db", n_cache_size, f_memory, f_wipe)} + : BaseIndex(std::move(chain), "txospenderindex", "txospenderidx"), m_db{std::make_unique(gArgs.GetDataDirNet() / "indexes" / "txospenderindex" / "db", n_cache_size, f_memory, f_wipe, /*f_obfuscate=*/false, /*f_bloom=*/false)} { if (!m_db->Read("siphash_key", m_siphash_key)) { FastRandomContext rng(false); diff --git a/libbitcoinkernel-sys/bitcoin/src/interfaces/wallet.h b/libbitcoinkernel-sys/bitcoin/src/interfaces/wallet.h index d2116317..326361aa 100644 --- a/libbitcoinkernel-sys/bitcoin/src/interfaces/wallet.h +++ b/libbitcoinkernel-sys/bitcoin/src/interfaces/wallet.h @@ -59,9 +59,6 @@ struct WalletTxOut; struct WalletTxStatus; struct WalletMigrationResult; -using WalletOrderForm = std::vector>; -using WalletValueMap = std::map; - //! Interface for accessing a wallet. class Wallet { @@ -150,9 +147,7 @@ class Wallet std::optional change_pos) = 0; //! Commit transaction. - virtual void commitTransaction(CTransactionRef tx, - WalletValueMap value_map, - WalletOrderForm order_form) = 0; + virtual void commitTransaction(CTransactionRef tx, const std::vector& messages) = 0; //! Return whether transaction can be abandoned. virtual bool transactionCanBeAbandoned(const Txid& txid) = 0; @@ -198,7 +193,8 @@ class Wallet //! Get transaction details. virtual WalletTx getWalletTxDetails(const Txid& txid, WalletTxStatus& tx_status, - WalletOrderForm& order_form, + std::vector& messages, + std::vector& payment_requests, bool& in_mempool, int& num_blocks) = 0; @@ -392,7 +388,10 @@ struct WalletTx CAmount debit; CAmount change; int64_t time; - std::map value_map; + std::optional from; // Deprecated + std::optional message; // Deprecated + std::optional comment; + std::optional comment_to; bool is_coinbase; bool operator<(const WalletTx& a) const { return tx->GetHash() < a.tx->GetHash(); } diff --git a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/doc/usage.md b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/doc/usage.md index f387db4d..df103e9f 100644 --- a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/doc/usage.md +++ b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/doc/usage.md @@ -10,7 +10,7 @@ _libmultiprocess_ is a library and code generator that allows calling C++ class The `*.capnp` data definition files are consumed by the _libmultiprocess_ code generator and each `X.capnp` file generates `X.capnp.c++`, `X.capnp.h`, `X.capnp.proxy-client.c++`, `X.capnp.proxy-server.c++`, `X.capnp.proxy-types.c++`, `X.capnp.proxy-types.h`, and `X.capnp.proxy.h` output files. The generated files include `mp::ProxyClient` and `mp::ProxyServer` class specializations for all the interfaces in the `.capnp` files. These allow methods on C++ objects in one process to be called from other processes over IPC sockets. -The `ProxyServer` objects help translate IPC requests from a socket to method calls on a local object. The `ProxyServer` objects are just used internally by the `mp::ServeStream(loop, socket, wrapped_object)` and `mp::ListenConnections(loop, socket, wrapped_object)` functions, and aren't exposed externally. The `ProxyClient` classes are exposed, and returned from the `mp::ConnectStream(loop, socket)` function and meant to be used directly. The classes implement methods described in `.capnp` definitions, and whenever any method is called, a request with the method arguments is sent over the associated IPC connection, and the corresponding `wrapped_object` method on the other end of the connection is called, with the `ProxyClient` method blocking until it returns and forwarding back any return value to the `ProxyClient` method caller. +The `ProxyServer` objects help translate IPC requests from a socket to method calls on a local object. The `ProxyServer` objects are just used internally by the `mp::ServeStream(loop, socket, wrapped_object)` and `mp::ListenConnections(loop, socket, wrapped_object[, max_connections])` functions, and aren't exposed externally. The `ProxyClient` classes are exposed, and returned from the `mp::ConnectStream(loop, socket)` function and meant to be used directly. The classes implement methods described in `.capnp` definitions, and whenever any method is called, a request with the method arguments is sent over the associated IPC connection, and the corresponding `wrapped_object` method on the other end of the connection is called, with the `ProxyClient` method blocking until it returns and forwarding back any return value to the `ProxyClient` method caller. ## Example diff --git a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/doc/versions.md b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/doc/versions.md index 3cfa28e3..83b5cf53 100644 --- a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/doc/versions.md +++ b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/doc/versions.md @@ -7,8 +7,24 @@ Library versions are tracked with simple Versioning policy is described in the [version.h](../include/mp/version.h) include. -## v11 +## v12 - Current unstable version. +- Adds an optional per-listener `max_connections` parameter to `ListenConnections()` + so servers can stop accepting new connections when a local connection cap is reached, + and resume accepting after existing connections disconnect. + +## [v11.0](https://github.com/bitcoin-core/libmultiprocess/commits/v11.0) +- Adds `makePool` method on `ThreadMap` to support thread pool routing, allowing requests without a specific client thread to be dispatched to a pool using a shortest-queue strategy ([#283](https://github.com/bitcoin-core/libmultiprocess/pull/283)). +- Adds `std::unordered_set` support, a `BuildList` helper, and a `ReadList` helper to reduce duplication in list build and read handlers ([#277](https://github.com/bitcoin-core/libmultiprocess/pull/277), [#285](https://github.com/bitcoin-core/libmultiprocess/pull/285)). +- Adds support for translating C++ `std::optional` struct fields to pairs of `T` + `hasT :Bool` Cap'n Proto struct fields, allowing unset optional primitive fields to be represented ([#243](https://github.com/bitcoin-core/libmultiprocess/pull/243)). +- Produces more readable log output for Proxy object lifecycle events and IPC server-side failures ([#218](https://github.com/bitcoin-core/libmultiprocess/pull/218)). +- Handles exceptions thrown by `destroy` methods by logging instead of aborting ([#273](https://github.com/bitcoin-core/libmultiprocess/pull/273)). This can prevent server crashes when non-libmultiprocess clients disconnect without destroying objects, in the case where a server object owns client objects and the server destructor tries to call the disconnected client to free them ([#219](https://github.com/bitcoin-core/libmultiprocess/issues/219)). +- Handles unexpected exceptions thrown by callbacks (that should never happen) by logging errors instead of deadlocking ([#260](https://github.com/bitcoin-core/libmultiprocess/pull/260)). +- Fixes a rare mptest hang on musl builds caused by a lost wakeup bug in `Waiter` ([#295](https://github.com/bitcoin-core/libmultiprocess/pull/295)). +- Fixes a race condition in a log print detected by TSan ([#286](https://github.com/bitcoin-core/libmultiprocess/pull/286)). +- Build improvements: makes `target_capnp_sources` work correctly when libmultiprocess is used as a CMake subproject ([#289](https://github.com/bitcoin-core/libmultiprocess/pull/289)), adds `mp_headers` target for better lint tool support ([#291](https://github.com/bitcoin-core/libmultiprocess/pull/291)), and fixes compatibility with recent Nix and CMake 4.0 ([#238](https://github.com/bitcoin-core/libmultiprocess/pull/238)). +- Test, CI, documentation, and minor code improvements: design document corrections ([#278](https://github.com/bitcoin-core/libmultiprocess/pull/278)), field constant comments ([#279](https://github.com/bitcoin-core/libmultiprocess/pull/279)), clang-tidy fix ([#292](https://github.com/bitcoin-core/libmultiprocess/pull/292)), new smoke test for double-precision float values ([#294](https://github.com/bitcoin-core/libmultiprocess/pull/294)), new test for recursive async IPC calls ([#301](https://github.com/bitcoin-core/libmultiprocess/pull/301)), removal of libevent from Core CI builds ([#299](https://github.com/bitcoin-core/libmultiprocess/pull/299)), and rename of `EventLoop::m_num_clients` to `m_num_refs` ([#302](https://github.com/bitcoin-core/libmultiprocess/pull/302)). +- Used in Bitcoin Core master branch, pulled in by [#35661](https://github.com/bitcoin/bitcoin/pull/35661). ## [v10.0](https://github.com/bitcoin-core/libmultiprocess/commits/v10.0) - Increases spawn test timeout to avoid spurious failures. diff --git a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/include/mp/proxy-io.h b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/include/mp/proxy-io.h index 259696a0..ec9a1539 100644 --- a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/include/mp/proxy-io.h +++ b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/include/mp/proxy-io.h @@ -13,7 +13,9 @@ #include #include +#include #include +#include #include #include #include @@ -25,6 +27,7 @@ namespace mp { struct ThreadContext; +struct Listener; struct InvokeContext { @@ -360,6 +363,12 @@ class EventLoop //! Hook called on the worker thread just before returning results. std::function testing_hook_async_request_done; + + //! Hook called on the event loop thread when a client has connected. + std::function testing_hook_connected; + + //! Hook called on the event loop thread when a client has disconnected. + std::function testing_hook_disconnected; }; //! Single element task queue used to handle recursive capnp calls. (If the @@ -842,8 +851,8 @@ std::unique_ptr> ConnectStream(EventLoop& loop, int f //! handles requests from the stream by calling the init object. Embed the //! ProxyServer in a Connection object that is stored and erased if //! disconnected. This should be called from the event loop thread. -template -void _Serve(EventLoop& loop, kj::Own&& stream, InitImpl& init) +template +void _Serve(EventLoop& loop, kj::Own&& stream, InitImpl& init, OnDisconnect&& on_disconnect) { loop.m_incoming_connections.emplace_front(loop, kj::mv(stream), [&](Connection& connection) { // Disable deleter so proxy server object doesn't attempt to delete the @@ -853,23 +862,46 @@ void _Serve(EventLoop& loop, kj::Own&& stream, InitImpl& init }); auto it = loop.m_incoming_connections.begin(); MP_LOG(loop, Log::Info) << "IPC server: socket connected."; - it->onDisconnect([&loop, it] { + if (loop.testing_hook_connected) loop.testing_hook_connected(); + it->onDisconnect([&loop, it, on_disconnect = std::forward(on_disconnect)]() mutable { MP_LOG(loop, Log::Info) << "IPC server: socket disconnected."; loop.m_incoming_connections.erase(it); + on_disconnect(); + if (loop.testing_hook_disconnected) loop.testing_hook_disconnected(); }); } -//! Given connection receiver and an init object, handle incoming connections by -//! calling _Serve, to create ProxyServer objects and forward requests to the -//! init object. +struct Listener +{ + explicit Listener(kj::Own&& receiver, std::optional max_connections) + : m_receiver(kj::mv(receiver)), m_max_connections(max_connections) {} + + bool atCapacity() const + { + return m_max_connections && m_active_connections >= *m_max_connections; + } + + kj::Own m_receiver; + std::optional m_max_connections; + size_t m_active_connections{0}; +}; + template -void _Listen(EventLoop& loop, kj::Own&& listener, InitImpl& init) +void _Listen(const std::shared_ptr& listener, EventLoop& loop, InitImpl& init) { - auto* ptr = listener.get(); - loop.m_task_set->add(ptr->accept().then( - [&loop, &init, listener = kj::mv(listener)](kj::Own&& stream) mutable { - _Serve(loop, kj::mv(stream), init); - _Listen(loop, kj::mv(listener), init); + if (listener->atCapacity()) return; + + auto* receiver = listener->m_receiver.get(); + loop.m_task_set->add(receiver->accept().then( + [&loop, &init, listener](kj::Own&& stream) { + ++listener->m_active_connections; + _Serve(loop, kj::mv(stream), init, [&loop, &init, listener] { + const bool resume_accept{listener->atCapacity()}; + assert(listener->m_active_connections > 0); + --listener->m_active_connections; + if (resume_accept) _Listen(listener, loop, init); + }); + _Listen(listener, loop, init); })); } @@ -879,18 +911,22 @@ template void ServeStream(EventLoop& loop, int fd, InitImpl& init) { _Serve( - loop, loop.m_io_context.lowLevelProvider->wrapSocketFd(fd, kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP), init); + loop, + loop.m_io_context.lowLevelProvider->wrapSocketFd(fd, kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP), + init, + [] {}); } //! Given listening socket file descriptor and an init object, handle incoming //! connections and requests by calling methods on the Init object. template -void ListenConnections(EventLoop& loop, int fd, InitImpl& init) +void ListenConnections(EventLoop& loop, int fd, InitImpl& init, std::optional max_connections = std::nullopt) { loop.sync([&]() { - _Listen(loop, + auto listener{std::make_shared( loop.m_io_context.lowLevelProvider->wrapListenSocketFd(fd, kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP), - init); + max_connections)}; + _Listen(listener, loop, init); }); } diff --git a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/include/mp/version.h b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/include/mp/version.h index 423ed460..4587a288 100644 --- a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/include/mp/version.h +++ b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/include/mp/version.h @@ -24,7 +24,7 @@ //! pointing at the prior merge commit. The /doc/versions.md file should also be //! updated, noting any significant or incompatible changes made since the //! previous version. -#define MP_MAJOR_VERSION 11 +#define MP_MAJOR_VERSION 12 //! Minor version number. Should be incremented in stable branches after //! backporting changes. The /doc/versions.md file should also be updated to diff --git a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/test/CMakeLists.txt b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/test/CMakeLists.txt index 1f21ba44..13246293 100644 --- a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/test/CMakeLists.txt +++ b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/test/CMakeLists.txt @@ -26,6 +26,7 @@ if(BUILD_TESTING AND TARGET CapnProto::kj-test) ${MP_PROXY_HDRS} mp/test/foo-types.h mp/test/foo.h + mp/test/listen_tests.cpp mp/test/spawn_tests.cpp mp/test/test.cpp ) diff --git a/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/test/mp/test/listen_tests.cpp b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/test/mp/test/listen_tests.cpp new file mode 100644 index 00000000..4e579d99 --- /dev/null +++ b/libbitcoinkernel-sys/bitcoin/src/ipc/libmultiprocess/test/mp/test/listen_tests.cpp @@ -0,0 +1,294 @@ +// Copyright (c) The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // IWYU pragma: keep +#include +#include +#include +#include +#include +#include +#include + +namespace mp { +namespace test { +namespace { + +constexpr auto FAILURE_TIMEOUT = std::chrono::seconds{30}; + +//! Owns a temporary Unix-domain listening socket used by ListenSetup. Tests call +//! Connect() to create client socket FDs and release() to transfer the listening +//! FD to ListenConnections(). +class UnixListener +{ +public: + UnixListener() + { + std::string dir_template = (std::filesystem::temp_directory_path() / "mptest-listener-XXXXXX").string(); + char* dir = mkdtemp(dir_template.data()); + KJ_REQUIRE(dir != nullptr); + m_dir = dir; + m_path = m_dir + "/socket"; + + m_fd = socket(AF_UNIX, SOCK_STREAM, 0); + KJ_REQUIRE(m_fd >= 0); + + sockaddr_un addr{}; + addr.sun_family = AF_UNIX; + KJ_REQUIRE(m_path.size() < sizeof(addr.sun_path)); + std::strncpy(addr.sun_path, m_path.c_str(), sizeof(addr.sun_path) - 1); + KJ_REQUIRE(bind(m_fd, reinterpret_cast(&addr), sizeof(addr)) == 0); + KJ_REQUIRE(listen(m_fd, SOMAXCONN) == 0); + } + + ~UnixListener() + { + if (m_fd >= 0) close(m_fd); + if (!m_path.empty()) unlink(m_path.c_str()); + if (!m_dir.empty()) rmdir(m_dir.c_str()); + } + + int release() + { + assert(m_fd >= 0); + int fd = m_fd; + m_fd = -1; + return fd; + } + + int MakeConnectedSocket() const + { + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + KJ_REQUIRE(fd >= 0); + + sockaddr_un addr{}; + addr.sun_family = AF_UNIX; + KJ_REQUIRE(m_path.size() < sizeof(addr.sun_path)); + std::strncpy(addr.sun_path, m_path.c_str(), sizeof(addr.sun_path) - 1); + KJ_REQUIRE(connect(fd, reinterpret_cast(&addr), sizeof(addr)) == 0); + return fd; + } + +private: + int m_fd{-1}; + std::string m_dir; + std::string m_path; +}; + +//! Runs a client EventLoop on its own thread and connects one socket FD to the +//! server. The constructed ProxyClient can be used by the test thread to make +//! calls over that connection. +class ClientSetup +{ +public: + explicit ClientSetup(int fd) + : thread([this, fd] { + EventLoop loop("mptest-client", [](mp::LogMessage log) { + KJ_LOG(INFO, log.level, log.message); + if (log.level == mp::Log::Raise) throw std::runtime_error(log.message); + }); + client_promise.set_value(ConnectStream(loop, fd)); + loop.loop(); + }) + { + client = client_promise.get_future().get(); + } + + ~ClientSetup() + { + client.reset(); + thread.join(); + } + + std::promise>> client_promise; + std::unique_ptr> client; + + //! Thread variable should be after other struct members so the thread does + //! not start until the other members are initialized. + std::thread thread; +}; + +//! Runs a server EventLoop on its own thread, starts ListenConnections() on a +//! UnixListener socket, and records connection/disconnection counts through +//! EventLoop test hooks +class ListenSetup +{ +public: + explicit ListenSetup(std::optional max_connections = std::nullopt) + : thread([this, max_connections] { + EventLoop loop("mptest-server", [](mp::LogMessage log) { + KJ_LOG(INFO, log.level, log.message); + if (log.level == mp::Log::Raise) throw std::runtime_error(log.message); + }); + loop.testing_hook_disconnected = [&] { + Lock lock(counter_mutex); + ++disconnected_count; + counter_cv.notify_all(); + }; + loop.testing_hook_connected = [&] { + Lock lock(counter_mutex); + ++connected_count; + counter_cv.notify_all(); + }; + m_loop_ref.emplace(loop); + FooImplementation foo; + ListenConnections(loop, listener.release(), foo, max_connections); + ready_promise.set_value(); + loop.loop(); + }) + { + ready_promise.get_future().get(); + } + + ~ListenSetup() + { + m_loop_ref.reset(); + thread.join(); + } + + size_t ConnectedCount() + { + Lock lock(counter_mutex); + return connected_count; + } + + size_t DisconnectedCount() + { + Lock lock(counter_mutex); + return disconnected_count; + } + + void WaitForConnectedCount(size_t expected_count) + { + Lock lock(counter_mutex); + const auto deadline = std::chrono::steady_clock::now() + FAILURE_TIMEOUT; + const bool matched = counter_cv.wait_until(lock.m_lock, deadline, [&]() MP_REQUIRES(counter_mutex) { + return connected_count >= expected_count; + }); + KJ_REQUIRE(matched); + } + + void WaitForDisconnectedCount(size_t expected_count) + { + Lock lock(counter_mutex); + const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(5); + const bool matched = counter_cv.wait_until(lock.m_lock, deadline, [&]() MP_REQUIRES(counter_mutex) { + return disconnected_count >= expected_count; + }); + KJ_REQUIRE(matched); + } + + UnixListener listener; + std::promise ready_promise; + std::optional m_loop_ref; + Mutex counter_mutex; + std::condition_variable counter_cv; + size_t connected_count MP_GUARDED_BY(counter_mutex) {0}; + size_t disconnected_count MP_GUARDED_BY(counter_mutex) {0}; + //! Thread variable should be after other struct members so the thread does + //! not start until the other members are initialized. + std::thread thread; +}; + +KJ_TEST("ListenConnections accepts incoming connections") +{ + ListenSetup server; + KJ_EXPECT(server.ConnectedCount() == 0) + auto client = std::make_unique(server.listener.MakeConnectedSocket()); + + server.WaitForConnectedCount(1); + KJ_EXPECT(client->client->add(1, 2) == 3); +} + +KJ_TEST("ListenConnections enforces a local connection limit") +{ + // With max-connections=1, the second socket can connect to the kernel + // backlog, but ListenConnections should not accept or serve it until the + // first accepts clients disconnects. + + ListenSetup server(/*max_connections=*/1); + + KJ_EXPECT(server.ConnectedCount() == 0) + auto client1 = std::make_unique(server.listener.MakeConnectedSocket()); + server.WaitForConnectedCount(1); + + KJ_EXPECT(client1->client->add(1, 2) == 3); + + auto client2 = std::make_unique(server.listener.MakeConnectedSocket()); + // Without this sync, ConnectedCount() == 1 might pass even if + // max_connections was not enforced because the event loop has not accepted + // client2 yet. + (**server.m_loop_ref).sync([] {}); + + KJ_EXPECT(server.ConnectedCount() == 1); + KJ_EXPECT(server.DisconnectedCount() == 0); + client1.reset(); + server.WaitForDisconnectedCount(1); + server.WaitForConnectedCount(2); + + KJ_EXPECT(client2->client->add(2, 3) == 5); + + KJ_EXPECT(server.DisconnectedCount() == 1); + client2.reset(); + server.WaitForDisconnectedCount(2); + + KJ_EXPECT(server.DisconnectedCount() == 2); + auto client3 = std::make_unique(server.listener.MakeConnectedSocket()); + server.WaitForConnectedCount(3); + KJ_EXPECT(client3->client->add(3, 4) == 7); +} + +KJ_TEST("ListenConnections accepts multiple connections") +{ + // With max-connections=2, two clients should be accepted and usable at the + // same time, while a third waits until one active client disconnects. + + ListenSetup server(/*max_connections=*/2); + + KJ_EXPECT(server.ConnectedCount() == 0); + auto client1 = std::make_unique(server.listener.MakeConnectedSocket()); + auto client2 = std::make_unique(server.listener.MakeConnectedSocket()); + server.WaitForConnectedCount(2); + + KJ_EXPECT(client1->client->add(1, 2) == 3); + KJ_EXPECT(client2->client->add(2, 3) == 5); + + auto client3 = std::make_unique(server.listener.MakeConnectedSocket()); + // Without this sync, ConnectedCount() == 2 might pass even if + // max_connections was not enforced because the event loop has not accepted + // client3 yet. + (**server.m_loop_ref).sync([] {}); + + KJ_EXPECT(server.ConnectedCount() == 2); + KJ_EXPECT(server.DisconnectedCount() == 0); + client1.reset(); + server.WaitForDisconnectedCount(1); + server.WaitForConnectedCount(3); + + KJ_EXPECT(client3->client->add(3, 4) == 7); +} + +} // namespace +} // namespace test +} // namespace mp diff --git a/libbitcoinkernel-sys/bitcoin/src/ipc/test/fuzz/CMakeLists.txt b/libbitcoinkernel-sys/bitcoin/src/ipc/test/fuzz/CMakeLists.txt index 7af1477a..deefa801 100644 --- a/libbitcoinkernel-sys/bitcoin/src/ipc/test/fuzz/CMakeLists.txt +++ b/libbitcoinkernel-sys/bitcoin/src/ipc/test/fuzz/CMakeLists.txt @@ -3,4 +3,4 @@ # file COPYING or https://opensource.org/license/mit/. target_sources(fuzz PRIVATE ${PROJECT_SOURCE_DIR}/src/ipc/test/fuzz/ipc.cpp) -target_link_libraries(fuzz bitcoin_ipc_fuzz multiprocess) +target_link_libraries(fuzz bitcoin_ipc_fuzz Libmultiprocess::multiprocess) diff --git a/libbitcoinkernel-sys/bitcoin/src/kernel/CMakeLists.txt b/libbitcoinkernel-sys/bitcoin/src/kernel/CMakeLists.txt index d2a467f6..8b562aa7 100644 --- a/libbitcoinkernel-sys/bitcoin/src/kernel/CMakeLists.txt +++ b/libbitcoinkernel-sys/bitcoin/src/kernel/CMakeLists.txt @@ -119,6 +119,12 @@ if(bitcoinkernel_type STREQUAL "STATIC_LIBRARY") target_compile_definitions(bitcoinkernel PUBLIC BITCOINKERNEL_STATIC) endif() +option(ENABLE_SCRIPT_TRACE "Enable script execution trace hooks" OFF) +if(ENABLE_SCRIPT_TRACE) + target_sources(bitcoinkernel PRIVATE ../script/trace.cpp) + target_compile_definitions(bitcoinkernel PRIVATE ENABLE_SCRIPT_TRACE) +endif() + configure_file(${PROJECT_SOURCE_DIR}/libbitcoinkernel.pc.in ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc @ONLY) install(FILES ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" COMPONENT libbitcoinkernel) diff --git a/libbitcoinkernel-sys/bitcoin/src/kernel/bitcoinkernel.cpp b/libbitcoinkernel-sys/bitcoin/src/kernel/bitcoinkernel.cpp index 152f778b..acfb6884 100644 --- a/libbitcoinkernel-sys/bitcoin/src/kernel/bitcoinkernel.cpp +++ b/libbitcoinkernel-sys/bitcoin/src/kernel/bitcoinkernel.cpp @@ -24,6 +24,10 @@ #include #include