Compare commits

...

131 Commits

Author SHA1 Message Date
merge-script
d70e9c5d13 Merge bitcoin/bitcoin#33557: [28.x] 28.3rc2
44d05b2fb2 doc: update release notes for 28.x (fanquake)
201221b750 doc: update manual pages for v28.3rc2 (fanquake)
e2e1138350 build: bump version to 28.3rc2 (fanquake)
9c911f7e2d build: fix depends Qt download link (fanquake)
ae8605825f contrib: fix using macdploy script without translations. (amisha)

Pull request description:

  Backports:
  * #33482
  * #33563

  Plus final changes for a `28.3rc2`.

ACKs for top commit:
  marcofleon:
    Nice, re ACK 44d05b2fb2
  stickies-v:
    re-ACK 44d05b2fb2

Tree-SHA512: 63d46b93fcc2201071328a0708d32ef7b9ce80348455ec059c11edf238003a6f0ec7bd018a76bf0d7ba90ab99dae5176dfa387f9ea1b791e1f8ef785d7c2f1f2
2025-10-13 12:30:28 +01:00
fanquake
44d05b2fb2 doc: update release notes for 28.x 2025-10-13 12:04:53 +01:00
fanquake
201221b750 doc: update manual pages for v28.3rc2 2025-10-07 14:53:26 +01:00
fanquake
e2e1138350 build: bump version to 28.3rc2 2025-10-07 14:53:26 +01:00
fanquake
9c911f7e2d build: fix depends Qt download link
Github-Pull: #33563
Rebased-From: abf4a6eeae
2025-10-07 14:53:26 +01:00
amisha
ae8605825f contrib: fix using macdploy script without translations.
QT translations are optional, but the script would error when
'translations_dir' falls back to its default value NULL.

This PR fixes it by moving the set-up of QT translations under
the check for 'translations_dir' presence.

Github-Pull: #33482
Rebased-From: 7b5261f7ef
2025-10-07 14:53:26 +01:00
merge-script
42c4c6b6dd Merge bitcoin/bitcoin#33561: [28.x] ci: Fix Qt 5.15 URL
2cd432dc6d [28.x] ci: Fix Qt 5.15 URL (Hennadii Stepanov)

Pull request description:

ACKs for top commit:
  fanquake:
    ACK 2cd432dc6d

Tree-SHA512: 762dcd7d08012a683d88b6f6437d7ffe31271abfa6a1a0be604746fad8473ba0ff6066880a8a6f56382f8da46f01fb3349440efef30990b1bab818521963496f
2025-10-07 14:52:44 +01:00
Hennadii Stepanov
2cd432dc6d [28.x] ci: Fix Qt 5.15 URL 2025-10-07 13:43:24 +01:00
merge-script
e9dd94abcc Merge bitcoin/bitcoin#33535: [28.x] More backports
06fe49dc88 doc: update release notes for 28.x (fanquake)
11da80fe6a test: add more TRUC reorg coverge (Greg Sanders)
05f4aa7662 Mempool: Do not enforce TRUC checks on reorg (Greg Sanders)
ffffdc4e97 fuzz: don't bypass_limits for most mempool harnesses (Greg Sanders)

Pull request description:

  Backports:
  * #33504

ACKs for top commit:
  darosior:
    utACK 06fe49dc88.
  dergoegge:
    ACK 06fe49dc88
  instagibbs:
    ACK 06fe49dc88

Tree-SHA512: 50495b75dec6dbbe24686cd7f1e832a79c841d29983d6be415783ba4ad3a1f7657459d491fc214de4d45f60467abc92f1daf75479f3db854fc6b3410368e67fc
2025-10-07 10:01:49 +01:00
fanquake
06fe49dc88 doc: update release notes for 28.x 2025-10-03 16:16:56 +01:00
Greg Sanders
11da80fe6a test: add more TRUC reorg coverge
Github-Pull: #33504
Rebased-From: 06df14ba75
2025-10-03 16:15:25 +01:00
Greg Sanders
05f4aa7662 Mempool: Do not enforce TRUC checks on reorg
Not enforcing TRUC topology on reorg was the intended
behavior, but the appropriate bypass argument was not
checked.

This mistake means we could potentially invalidate a long
chain of perfectly incentive-compatible transactions that
were made historically, including subsequent non-TRUC
transactions, all of which may have been very high feerate.

Lastly, it wastes CPU cycles doing topology checks since
this behavior cannot actually enforce the topology in
general for the reorg setting.

Github-Pull: #33504
Rebased-From: 26e71c237d
2025-10-03 15:50:24 +01:00
Greg Sanders
ffffdc4e97 fuzz: don't bypass_limits for most mempool harnesses
Using bypass_limits=true is essentially fuzzing part of a
reorg only, and results in TRUC invariants unable to be
checked. Remove most instances of bypassing limits, leaving
one harness able to do so.

Github-Pull: #33504
Rebased-From: bbe8e9063c
2025-10-03 15:49:17 +01:00
Ava Chow
ed730c5674 Merge bitcoin/bitcoin#33476: [28.x] backports + 28.3rc1
9968b15937 [doc] update bitcoin.conf example (glozow)
dcac36271f [doc] manpages for 28.3rc1 (glozow)
df7412803d [build] bump version to 28.3rc1 (glozow)
d3194cb8cd [doc] update release notes for 28.x (glozow)
18f6430b4a test: compare BDB dumps of test framework parser and wallet tool (Sebastian Falbesoner)
6ede736da1 test: complete BDB parser (handle internal/overflow pages, support all page sizes) (Sebastian Falbesoner)
66559d1a4a [policy] lower default minrelaytxfee and incrementalrelayfee to 100sat/kvB (glozow)
a02e0a401c [prep/test] make wallet_fundrawtransaction's minrelaytxfee assumption explicit (glozow)
f25fc092ab [prep/util] help MockMempoolMinFee handle more precise feerates (glozow)
4d809efeb9 [prep/test] replace magic number 1000 with respective feerate vars (glozow)
f7dde40c70 test: Add missing sync_mempools() to fill_mempool() (MarcoFalke)
a60281526b test: Refactor fill_mempool to extract send_batch helper (MarcoFalke)
08eeb0d342 [miner] lower default -blockmintxfee to 1sat/kvB (glozow)
b7ba016707 test: add `BulkTransaction` helper to unit test transaction utils (Sebastian Falbesoner)
27b775586e [doc] assert that default min relay feerate and incremental are the same (glozow)
e3273e03b1 [test] explicitly check default -minrelaytxfee and -incrementalrelayfee (glozow)
cf875f1559 [test] RBF rule 4 for various incrementalrelayfee settings (glozow)
308778b7b6 [test] check bypass of minrelay for various minrelaytxfee settings (glozow)
e779d59eca [test] check miner doesn't select 0fee transactions (glozow)

Pull request description:

  Includes backports of
  - #33106
  - #30125
  - #30948
  - #30784

ACKs for top commit:
  achow101:
    ACK 9968b15937
  stickies-v:
    re-ACK 9968b15937

Tree-SHA512: 1d4ec354a743ec3a894a44d2d9b98dc5169f515081071b887768afee1c42cefdaa6c5f595829dc9b579699bba3e4b4aa73a519d4c4ef8579375ad34513f26cd9
2025-10-01 10:42:26 -07:00
glozow
9968b15937 [doc] update bitcoin.conf example 2025-09-30 17:21:25 -04:00
glozow
dcac36271f [doc] manpages for 28.3rc1 2025-09-29 16:48:04 -04:00
glozow
df7412803d [build] bump version to 28.3rc1 2025-09-29 16:48:04 -04:00
glozow
d3194cb8cd [doc] update release notes for 28.x 2025-09-26 10:24:20 -04:00
Sebastian Falbesoner
18f6430b4a test: compare BDB dumps of test framework parser and wallet tool
Github-Pull: #30125
Rebased-From: d45eb3964f
2025-09-26 10:24:20 -04:00
Sebastian Falbesoner
6ede736da1 test: complete BDB parser (handle internal/overflow pages, support all page sizes)
This aims to complete our test framework BDB parser to reflect
our read-only BDB parser in the wallet codebase. This could be
useful both for making review of #26606 easier and to also possibly
improve our functional tests for the BDB parser by comparing with
an alternative implementation.

Github-Pull: #30125
Rebased-From: 01ddd9f646
2025-09-26 10:24:20 -04:00
glozow
66559d1a4a [policy] lower default minrelaytxfee and incrementalrelayfee to 100sat/kvB
Let's say an attacker wants to use/exhaust the network's bandwidth, and
has the choice between renting resources from a commercial provider and
getting the network to "spam" itself it by sending unconfirmed
transactions. We'd like the latter to be more expensive than the former.

The bandwidth for relaying a transaction across the network is roughly
its serialized size (plus relay overhead) x number of nodes. A 1000vB
transaction is 1000-4000B serialized. With 100k nodes, that's 0.1-0.4GB
If the going rate for commercial services is 10c/GB, that's like 1-4c per kvB
of transaction data, so a 1000vB transaction should pay at least $0.04.

At a price of 120k USD/BTC, 100sat is about $0.12. This price allows us
to tolerate a large decrease in the conversion rate or increase in the
number of nodes.

Github-Pull: #33106
Rebased-From: 6da5de58ca
2025-09-26 10:24:19 -04:00
glozow
a02e0a401c [prep/test] make wallet_fundrawtransaction's minrelaytxfee assumption explicit
Github-Pull: #33106
Rebased-From: 2e515d2897
2025-09-26 10:22:38 -04:00
glozow
f25fc092ab [prep/util] help MockMempoolMinFee handle more precise feerates
Use a virtual size of 1000 to keep precision when using a feerate
(which is rounded to the nearest satoshi per kvb) that isn't just an
integer.

Github-Pull: #33106
Rebased-From: 457cfb61b5
2025-09-26 10:22:38 -04:00
glozow
4d809efeb9 [prep/test] replace magic number 1000 with respective feerate vars
Github-Pull: #33106
Rebased-From: 3eab8b7240
2025-09-26 10:22:38 -04:00
MarcoFalke
f7dde40c70 test: Add missing sync_mempools() to fill_mempool()
Also disable the function, when it is not needed.

Github-Pull: #30948
Rebased-From: faf801515f
2025-09-26 10:22:38 -04:00
MarcoFalke
a60281526b test: Refactor fill_mempool to extract send_batch helper
This is needed for the next commit

Github-Pull: #30948
Rebased-From: fa48be6f02
2025-09-26 10:22:38 -04:00
glozow
08eeb0d342 [miner] lower default -blockmintxfee to 1sat/kvB
Back when we implemented coin age priority as a miner policy, miners
mempools might admit transactions paying very low fees, but then want to
set a higher fee for block inclusion. However, since coin age priority
was removed in v0.15, the block assembly policy is solely based on fees,
so we do not need to apply minimum feerate rules in multiple places. In
fact, the block assembly policy ignoring transactions that are added to
the mempool is likely undesirable as we waste resources accepting and
storing this transaction.

Instead, rely on mempool policy to enforce a minimum entry feerate to
the mempool (minrelaytxfee). Set the minimum block feerate to the
minimum non-zero amount (1sat/kvB) so it collects everything it finds in
mempool into the block.

Github-Pull: #33106
Rebased-From:  5f2df0ef78
2025-09-26 10:22:38 -04:00
Sebastian Falbesoner
b7ba016707 test: add BulkTransaction helper to unit test transaction utils
The padding method used matches the one used in MiniWallet,
`MiniWallet._bulk_tx`.

Github-Pull: #30784
Rebased-From: ed7d224666
2025-09-26 10:22:38 -04:00
glozow
27b775586e [doc] assert that default min relay feerate and incremental are the same
Github-Pull: #33106
Rebased-From: d6213d6aa1
2025-09-26 10:22:38 -04:00
glozow
e3273e03b1 [test] explicitly check default -minrelaytxfee and -incrementalrelayfee
Github-Pull: #33106
Rebased-From:  1fbee5d7b6
2025-09-26 10:22:38 -04:00
glozow
cf875f1559 [test] RBF rule 4 for various incrementalrelayfee settings
Github-Pull: #33106
Rebased-From: 72dc18467d
2025-09-26 10:22:38 -04:00
glozow
308778b7b6 [test] check bypass of minrelay for various minrelaytxfee settings
Github-Pull: #33106
Rebased-From: 85f498893f
2025-09-26 10:22:38 -04:00
glozow
e779d59eca [test] check miner doesn't select 0fee transactions
Github-Pull: #33106
Rebased-From: e5f896bb1f
2025-09-26 10:22:38 -04:00
Ava Chow
a0b5730f85 Merge bitcoin/bitcoin#33415: [28.x] More backports
a5e4fec494 doc: update release notes for 28.x (fanquake)
4598dfcfde doc: Remove wrong and redundant doxygen tag (MarcoFalke)
9e56d8889a net: Do not apply whitelist permission to onion inbounds (Martin Zumsande)
a381de750d Fix benchmark CSV output (Hennadii Stepanov)

Pull request description:

  Further backports for `28.x`:
  * #33236
  * #33340
  * #33395

ACKs for top commit:
  achow101:
    ACK a5e4fec494
  willcl-ark:
    ACK a5e4fec494

Tree-SHA512: eb00b395dea8a3e50e19683e824abd946d0e0ef5188cca3fddbc35a8e2ecc203cfc7a8f480e0fbf09cc48f660b1da324da4d777ec47346c52d230c5b93f536c3
2025-09-25 13:41:04 -07:00
fanquake
a5e4fec494 doc: update release notes for 28.x 2025-09-24 15:26:38 -04:00
MarcoFalke
4598dfcfde doc: Remove wrong and redundant doxygen tag
Remove it in feerate.

Fix it in the other places.

Github-Pull: #33236
Rebased-From: 966666de9a
2025-09-24 14:37:05 -04:00
Martin Zumsande
9e56d8889a net: Do not apply whitelist permission to onion inbounds
Tor inbound connections do not reveal the peer's actual network address.
Therefore do not apply whitelist permissions to them.

Co-authored-by: Vasil Dimov <vd@FreeBSD.org>

Github-Pull: #33395
Rebased-From: f563ce9081
2025-09-24 14:37:05 -04:00
Hennadii Stepanov
a381de750d Fix benchmark CSV output
The `SHA256AutoDetect` return output is used, among other use cases, to
name benchmarks. Using a comma breaks the CSV output.

This change replaces the comma with a semicolon, which fixes the issue.

Github-Pull: #33340
Rebased-From: 790b440197
2025-09-24 14:37:04 -04:00
merge-script
f9043af2ee Merge bitcoin/bitcoin#33406: Backport Cirrus runners to 28.x
ea4e0aa8c4 ci: Checkout latest merged pulls (MarcoFalke)
48761444e2 ci: reduce runner sizes on various jobs (will)
12eada012b ci: remove un-needed lint_run*.sh files (willcl-ark)
189bb39922 ci: fix annoying docker warning (will)
e4493b15df ci: add ccache hit-rate warning when < 75% (will)
a0b6e2ae6b doc: Detail configuration of hosted CI runners (will)
1bfe9f56c3 ci: dynamically match makejobs with cores (will)
abaa128095 ci: remove .cirrus.yml (will)
8ab684eeb7 ci: port win64-no_gui job (will)
99411458b4 ci: port lint (will)
4b3468389b ci: port msan-depends (will)
cf18a500d7 ci: port tsan-depends-gui (will)
49ff9d7e6e ci: port tidy (will)
c2c69cd6ec ci: port 32-bit-centos-dash-gui (will)
fa259b4e72 ci: port previous-releases-depends-debug (will)
96cd28f146 ci: port fuzzer-address-undefined-integer-nodepends (will)
0fc3fd1eb5 ci: port i686-multiprocess-DEBUG (will)
f61cb6be58 ci: port nowallet-libbitcoinkernel (will)
6237cd537d ci: port mac-cross-gui-notests (will)
8c9048f4fc ci: force reinstall of kernel headers in asan (will)
61bb5180d5 ci: update asan-lsan-ubsan (will)
bb455c9594 ci: port arm job (will)
5538ce4f32 ci: add job to determine runner type (will)
82cfddbc9a ci: add Cirrus cache host (will)
30efc95aec ci: have base install run in right dir (will)
f6ccd895df ci: use buildx in ci (will)
f8cb31d064 ci: add configure-docker action (will)
270191c3c0 ci: add REPO_USE_CIRRUS_RUNNERS (will)
8d6d70f555 ci: add caching actions (will)
d8ad667f94 ci: add configure environment action (will)

Pull request description:

  Backports https://github.com/bitcoin/bitcoin/pull/32989 to the 28.x branch

ACKs for top commit:
  maflcko:
    lgtm ACK ea4e0aa8c4 🥄

Tree-SHA512: aeb7f3f92f1e18d787a199258c06cff14a7352e3da1d0b546bb39a46ec988e65a4c68083c9ee38fe8a6a60e4ee5a2199c6d255973bff91f0f4aac34fea5fdb28
2025-09-24 13:46:09 -04:00
MarcoFalke
ea4e0aa8c4 ci: Checkout latest merged pulls
Github-Pull: #33303
Rebased-From: fa8f081af3
2025-09-19 08:41:22 +01:00
will
48761444e2 ci: reduce runner sizes on various jobs
Github Pull: #33319
Rebased-From: 5eeb2facbb

These jobs can use reduced runner size to avoid wasting CPU, as much of
the long-running part of the job is single-threaded.

Suggested in: https://github.com/bitcoin/bitcoin/pull/32989#discussion_r2321775620

Co-authored-by: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
2025-09-19 08:41:17 +01:00
willcl-ark
12eada012b ci: remove un-needed lint_run*.sh files
Github-Pull: #32989
Rebased-From: 3c5da69a23

ci/lint_run_all.sh: Only used in .cirrus.yml. Refer to test/lint/README.md on how to run locally.
2025-09-19 08:41:13 +01:00
will
189bb39922 ci: fix annoying docker warning
Github-Pull: #32989
Rebased-From: 2aa288efdd

Docker currently warns that we are missing a default value.

Set this to scratch which will error if an appropriate image tag is not
passed in to silence the warning.
2025-09-19 08:41:09 +01:00
will
e4493b15df ci: add ccache hit-rate warning when < 75%
Github-Pull: #32989
Rebased-From: dd1c5903e8

Print the ccache hit-rate for the job using a GitHub annotation if it
was below 75%.
2025-09-19 08:41:06 +01:00
will
a0b6e2ae6b doc: Detail configuration of hosted CI runners
Github-Pull: #32989
Rebased-From: f427284483
2025-09-19 08:41:02 +01:00
will
1bfe9f56c3 ci: dynamically match makejobs with cores
Github-Pull: #32989
Rebased-From: 3f339e99e0

Previously jobs were running on a large multi-core server where 10 jobs
as default made sense (or may even have been on the low side).

Using hosted runners with fixed (and lower) numbers of vCPUs we should
adapt compilation to match the number of cpus we have dynamically.

This is cross-platform compatible with macos and linux only.
2025-09-19 08:40:58 +01:00
will
abaa128095 ci: remove .cirrus.yml
Github-Pull: #32989
Rebased-From: 4393ffdd83

Removed as unused.
2025-09-19 08:40:55 +01:00
will
8ab684eeb7 ci: port win64-no_gui job 2025-09-19 08:40:51 +01:00
will
99411458b4 ci: port lint
Github-Pull: #32989
Rebased-From: bc41848d00

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:48 +01:00
will
4b3468389b ci: port msan-depends
Github-Pull: #32989
Rebased-From: d290a8e6ea

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:44 +01:00
will
cf18a500d7 ci: port tsan-depends-gui
Github-Pull: #32989
Rebased-From: 9bbae61e3b

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:41 +01:00
will
49ff9d7e6e ci: port tidy
Github-Pull: #32989
Rebased-From: bf7d536452

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:37 +01:00
will
c2c69cd6ec ci: port 32-bit-centos-dash-gui
Github-Pull: #32989
Rebased-From: 549074bc64

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:34 +01:00
will
fa259b4e72 ci: port previous-releases-depends-debug
Github-Pull: #32989
Rebased-From: 58e38c3a04

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:30 +01:00
will
96cd28f146 ci: port fuzzer-address-undefined-integer-nodepends
Github-Pull: #32989
Rebased-From: 341196d75c

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:27 +01:00
will
0fc3fd1eb5 ci: port i686-multiprocess-DEBUG
Github-Pull: #32989
Rebased-From: f2068f26c1

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:23 +01:00
will
f61cb6be58 ci: port nowallet-libbitcoinkernel
Github-Pull: #32989
Rebased-From: 2a00b12d73

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:20 +01:00
will
6237cd537d ci: port mac-cross-gui-notests
Github-Pull: #32989
Rebased-From: 9c2514de53

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:13 +01:00
will
8c9048f4fc ci: force reinstall of kernel headers in asan
Github-Pull: #32989
Rebased-From: 2c990d84a3

When using hosted runners in combination with cached docker images,
there is the possibility that the host runner image is updated,
rendering the linux-headers package (stored in the cached docker image)
incompatible.

Fix this by doing a re-install of the headers package in
03_test_script.sh.

If the underlying runner kernel has not changed thie has no effect, but
prevents the job from failing if it has.
2025-09-19 08:40:10 +01:00
will
61bb5180d5 ci: update asan-lsan-ubsan
Github-Pull: #32989
Rebased-From: 884251441b

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:06 +01:00
will
bb455c9594 ci: port arm job
Github-Pull: #32989
Rebased-From: f253031cb8

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:40:03 +01:00
will
5538ce4f32 ci: add job to determine runner type
Github-Pull: #32989
Rebased-From: cc1735d777

To remove multiple occurances of the respository name, against which we
compare `${{ github.repository }}` to check if we should use Cirrus
Runners, introduce a helper job which can check a single environment
variable and output this as an input to subsequent jobs.

Forks can maintain a trivial patch of their repo name against the
`REPO_USE_CIRRUS_RUNNERS` variable in ci.yml if they have Cirrus Runners
of their own, which will then enable cache actions and docker build
cache to use Cirrus Cache.

It's not possible to use `${{ env.USE_CIRRUS_RUNNERS }}` in the
`runs-on:` directive as the context is not supported by GitHub.

If it was, this job would no longer be necessary.
2025-09-19 08:39:59 +01:00
will
82cfddbc9a ci: add Cirrus cache host
Github-Pull: #32989
Rebased-From: 020069e6b7

Whilst the action cirruslabs/actions/cache will automatically set this
host, the docker `gha` build cache backend will not be aware of it.

Set the value here, which will later be used in the docker build args to
enable docker build cache on the cirrus cache.
2025-09-19 08:39:56 +01:00
will
30efc95aec ci: have base install run in right dir
Github-Pull: #32989
Rebased-From: 9c2b96e0d0

This sets the build dir at build time so that Apple SDK gets installed
in the correct/expected location for the runtime to find it.

Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
2025-09-19 08:39:52 +01:00
will
f6ccd895df ci: use buildx in ci
Github-Pull: #32989
Rebased-From: 94a0932547

This rebase also includes part of e87429a2d0
adding `$DOCKER_BUILD_CACHE_ARG \` to the `docker build` command.

Using buildx is required to properly load the correct driver, for use
with registry caching. Neither build, nor BUILDKIT=1 currently do this
properly.

Use of `docker buildx build` is compatible with podman.
2025-09-19 08:39:49 +01:00
will
f8cb31d064 ci: add configure-docker action
Github-Pull: #32989
Rebased-From: fdf64e5532

Another action to reduce boilerplate in the main ci.yml file.

This action will set up a docker builder compatible with caching build
layers to a container registry using the `gha` build driver.

It will then configure the docker build cache args.
2025-09-19 08:39:45 +01:00
will
270191c3c0 ci: add REPO_USE_CIRRUS_RUNNERS
Github-Pull: #32989
Rebased-From: 33ba073df7

If set, Cirrus runners will be used on pushes to, and pull requests
against, this repository.

Forks can set this if they have their own cirrus runners.
2025-09-19 08:39:42 +01:00
will
8d6d70f555 ci: add caching actions
Github-Pull: #32989
Rebased-From: b232b0fa5e

Add "Restore" and "Save" caching actions.

These actions reduce boilerplate in the main ci.yml configuration file.

These actions are implemented so that caches will be saved on `push`
only.

When a pull request is opened it will cache hit on the caches from the
lastest push, or in the case of depends will hit on any matching depends
hash, falling back to partial matches.

Depends caches are hashed using
`$(git ls-tree HEAD depends "ci/test/$FILE_ENV" | sha256sum | cut -d' ' -f1)`
and this hash is passed in as an input to the actions. This means we
direct cache hit in cases where depends would not be re-built, otherwise
falling back to a partial match.

Previous releases cache is hashed similarly to depends, but using the
test/get_previous_releases.py file.

The cirruslabs cache action will fallback transparently to GitHub's
cache in the case that the job is not being run on a Cirrus Runner,
making these compatible with running on forks (on free GH hardware).
2025-09-19 08:39:38 +01:00
will
d8ad667f94 ci: add configure environment action
Github-Pull: #32989
Rebased-From: b8fcc9fcbc
2025-09-19 08:39:21 +01:00
merge-script
6e62b70532 Merge bitcoin/bitcoin#33143: [28.x] Backports
9f1b89a1c7 doc: update release notes for 28.x (fanquake)
2a46f220ca rpc: fix getpeerinfo ping duration unit docs (0xb10c)

Pull request description:

  Backports:
  * #33133

ACKs for top commit:
  willcl-ark:
    ACK 9f1b89a1c7

Tree-SHA512: 98bc82c1925a1a5d163677d13351d6cd5f6df4652b0ea2a400a7c574563cdb7accbba19a059b8612991bd392de1f9b20769fa88e13f8f579db0289c27cf92921
2025-08-15 17:14:19 +01:00
fanquake
9f1b89a1c7 doc: update release notes for 28.x 2025-08-06 11:58:00 +01:00
0xb10c
2a46f220ca rpc: fix getpeerinfo ping duration unit docs
The getpeerinfo docs incorrectly specified the ping durations as
milliseconds. This was incorrectly changed in a3789c700b
(released in v25; master since Sept. 2022). The correct duration unit
is seconds.

Also, remove the documentation of the getpeerinfo RPC response from the
ping RPC since it's incomplete. Better to just reference the getpeerinfo
RPC and it's documenation for this.

Github-Pull: #33133
Rebased-From: 1252eeb997
2025-08-06 11:51:28 +01:00
merge-script
5492e1be3b Merge bitcoin/bitcoin#33076: [28.x] Backports
4d145f9f20 doc: update release notes for 28.x (fanquake)
8782e6ce38 guix: warn SOURCE_DATE_EPOCH set in guix-codesign (will)
c09d82f0dd doc/zmq: fix unix socket path example (Roman Zeyde)
41fa1e0ee5 test: Log KeyboardInterrupt as exception (MarcoFalke)
a828e64b7d test: Do not pass tests on unhandled exceptions (MarcoFalke)

Pull request description:

  Backports:
  * #33001
  * #33070
  * #33073

ACKs for top commit:
  willcl-ark:
    ACK 4d145f9f20
  marcofleon:
    lgtm ACK 4d145f9f20

Tree-SHA512: de269749423b2e112881cfc0126256d46d646ea7ab9f7f5766361d10866ca4d132605deb8a22ba00714a1f3732a792ae69deb062132276bd21d5d616c1130b2b
2025-07-30 15:31:12 +01:00
fanquake
4d145f9f20 doc: update release notes for 28.x 2025-07-29 16:52:54 +01:00
will
8782e6ce38 guix: warn SOURCE_DATE_EPOCH set in guix-codesign
Currently there is a warning for this in guix-build, but we also need
one in guix-codesign, otherwise the codesigned hashes are not
reproducible.

Move common functionality into prelude and call the function in both
guix actions.

Github-Pull: #33073
Rebased-From: 1bed0f734b
2025-07-29 16:51:57 +01:00
Roman Zeyde
c09d82f0dd doc/zmq: fix unix socket path example
Following 75a5c8258e/doc/release-notes/release-notes-28.0.md (L105)

Github-Pull: #33070
Rebased-From: e83699a626
2025-07-28 10:35:35 +01:00
MarcoFalke
41fa1e0ee5 test: Log KeyboardInterrupt as exception
log.exception is more verbose and useful to debug timeouts.

Also, log stderr for CalledProcessError to make debugging easier.

Github-Pull: #33001
Rebased-From: faa3e68411
2025-07-24 15:22:55 +01:00
MarcoFalke
a828e64b7d test: Do not pass tests on unhandled exceptions
This adds a missing catch for BaseException (e.g. SystemExit), which
would otherwise be silently ignored.

Also, remove the redundant other catches, which are just calling
log.exception with a redundant log message.

Github-Pull: #33001
Rebased-From: fa30b34026
2025-07-24 15:22:19 +01:00
merge-script
a6d0159518 Merge bitcoin/bitcoin#32969: [28.x] Backports
a9a71b840d doc: update release notes for 28.x (fanquake)
792ee20318 depends: Force `CMAKE_EXPORT_NO_PACKAGE_REGISTRY=TRUE` (Hennadii Stepanov)

Pull request description:

  Backports:
  * #32943

ACKs for top commit:
  marcofleon:
    ACK a9a71b840d

Tree-SHA512: b04c495a33b280bfe22361fda527541fd0c570ebdd656f925762ceed3a468ab296ab137c0c5dfb0e2e43f4603df81f45ebf878554fc990956d13f482d47f0c79
2025-07-23 16:54:08 +01:00
fanquake
a9a71b840d doc: update release notes for 28.x 2025-07-14 13:37:48 +01:00
Hennadii Stepanov
792ee20318 depends: Force CMAKE_EXPORT_NO_PACKAGE_REGISTRY=TRUE
When using CMake policies 3.14 and below, the `export(PACKAGE)` command
by default populates the user package registry, which is stored outside
the build tree. Setting the `CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable
disables this side effect.

In CMake 3.15 and later, this behavior is disabled by default, and the
variable has no effect.

Github-Pull: #32943
Rebased-From: 44f3bae300
2025-07-14 13:36:17 +01:00
merge-script
3c56d36bec Merge bitcoin/bitcoin#32811: [28.x] Backports
44b07b2d5a doc: update release notes for 28.x (fanquake)
c77e250a98 guix: warn and abort when SOURCE_DATE_EPOCH is set (will)
d19a8e0c06 doc: taproot became always active in v24.0 (Sjors Provoost)
907772d709 doc: fix transifex 404s (fanquake)
d235d5b77d test: Fix list index out of range error in feature_bip68_sequence.py (zaidmstrr)

Pull request description:

  Backports:
  * #32678
  * #32765
  * #32776
  * #32777

ACKs for top commit:
  hebasto:
    ACK 44b07b2d5a.

Tree-SHA512: 01a3987e222622c16583dae91b1efe4428110ff2d852da13ca34ba3270d40e678dd41d3ec53b89bda260efda706e89f4ee2c1c8bb6cc0d157e5145de001f5526
2025-07-03 17:35:18 +01:00
fanquake
44b07b2d5a doc: update release notes for 28.x 2025-06-27 15:07:44 +01:00
will
c77e250a98 guix: warn and abort when SOURCE_DATE_EPOCH is set
Current behaviour will by-default use SOURCE_DATE_EPOCH from the
environment without warning. This breaks the default reproducibility
from a guix build.

Warn when and exit when this variable is set, and
FORCE_SOURCE_DATE_EPOCH is unset.

Github-Pull: #32678
Rebased-From: 5c4a0f8009
2025-06-27 15:06:28 +01:00
Sjors Provoost
d19a8e0c06 doc: taproot became always active in v24.0
Github-Pull: #32776
Rebased-From: 8ee8a951c2
2025-06-23 12:38:50 +01:00
fanquake
907772d709 doc: fix transifex 404s
Github-Pull: #32777
Rebased-From: 53a996f122
2025-06-23 12:37:11 +01:00
zaidmstrr
d235d5b77d test: Fix list index out of range error in feature_bip68_sequence.py
Github-Pull: #32765
Rebased-From: e285e691b7
2025-06-23 12:34:58 +01:00
merge-script
e44d72b648 Merge bitcoin/bitcoin#32766: [28.x] Finalize 28.2
7135d7536c docs: Release notes for 28.2 (Ava Chow)
90f78c74a0 docs: Regenerate manpages for 28.2 (Ava Chow)
3cd4fdb008 build: Bump to 28.2 (Ava Chow)

Pull request description:

  Version bump for 28.2 final

ACKs for top commit:
  theStack:
    ACK 7135d7536c
  fanquake:
    ACK 7135d7536c

Tree-SHA512: 30ae17b4db16d13fcc99fa47f3927e38b337af19cb10fd64823100794d9d1333292449eedd2011aa59c8adad83c049752f04d143766f170dca24353717405055
2025-06-19 10:17:57 +01:00
Ava Chow
7135d7536c docs: Release notes for 28.2 2025-06-18 16:00:44 -07:00
Ava Chow
90f78c74a0 docs: Regenerate manpages for 28.2 2025-06-17 11:07:23 -07:00
Ava Chow
3cd4fdb008 build: Bump to 28.2 2025-06-17 10:56:31 -07:00
merge-script
e5a9e2435f Merge bitcoin/bitcoin#32735: [28.x] More backports
2437d93989 doc: update 28.x release notes (fanquake)
a6aca67214 build: patch cmake min version on freetype (josibake)
9082498589 contrib: Sign all Windows binaries too (Ava Chow)

Pull request description:

  This backports
  * 3656b828dc - Which was missed in #32563, see https://github.com/bitcoin/bitcoin/pull/32563#issuecomment-2960237938.
  * #32693

ACKs for top commit:
  willcl-ark:
    ACK 2437d93989

Tree-SHA512: 3fcc04f22355372fd34581c068c3a02c2b19543f4a2a9058953b6f60debb36a597d74405decbe8451291431aa5bab2060f4545b9f6c1e3b0a8cc3e8aca17fdc5
2025-06-17 13:11:33 +01:00
fanquake
2437d93989 doc: update 28.x release notes 2025-06-13 12:33:24 +01:00
josibake
a6aca67214 build: patch cmake min version on freetype
Patch cmake_minimum_required version for freetype, using the version from
https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/352/diffs

This fixes a failure when building with CMake 4, where compatibility
with CMake versions < 3.5 has been removed (see https://cmake.org/cmake/help/latest/release/4.0.html#deprecated-and-removed-features)

Github-Pull: #32693
Rebased-From: d7c37906e7
2025-06-13 12:32:38 +01:00
Ava Chow
9082498589 contrib: Sign all Windows binaries too
Github-Pull: #31407
Rebased-From: 3656b828dc
2025-06-13 12:32:38 +01:00
glozow
cb13264169 Merge bitcoin/bitcoin#32684: [28.x] 28.2rc2
fb62393277 doc: update manual pages for 28.2rc2 (fanquake)
c2b2942415 build: bump version to 28.2rc2 (fanquake)
b64faa54c2 doc: update release notes for rc2 (fanquake)
a6cbd33d1a depends: use "mkdir -p" when installing xproto (fanquake)

Pull request description:

  Backports #32568.
  Bumps to `rc2`.
  #32563 & #32639 haved landed since `rc1`.

ACKs for top commit:
  glozow:
    ACK fb62393277
  willcl-ark:
    ACK fb62393277

Tree-SHA512: 4fc210c2baa6876e9efb62150f295c22d9ef8104812c26c64daf20fc82a002dedf96e5593a49df1b84aa60793a7220c90c5ed06d7dfd1eee972ac9963c188a51
2025-06-09 11:18:10 -04:00
fanquake
fb62393277 doc: update manual pages for 28.2rc2 2025-06-07 11:59:32 +02:00
fanquake
c2b2942415 build: bump version to 28.2rc2 2025-06-07 11:59:32 +02:00
fanquake
b64faa54c2 doc: update release notes for rc2 2025-06-07 11:59:27 +02:00
fanquake
a6cbd33d1a depends: use "mkdir -p" when installing xproto
It looks like the mkdir detection in xproto is broken on Alpine. Ensure
we always use `mkdir -p`.

Fixes #32494.

Github-Pull: #32568
Rebased-From: df9ebbf659
2025-06-05 15:43:16 +02:00
merge-script
7f1da76269 Merge bitcoin/bitcoin#32563: [28.x] Backport #31407
b1f694fce2 doc: update release-notes.md (fanquake)
52f09633d0 doc: remove note about macOS self-signing (fanquake)
744b1c8581 guix: Apply all codesignatures to Windows binaries (Ava Chow)
812cadefa2 guix: Apply codesignatures to all MacOS binaries (Ava Chow)
c60055c637 contrib: Sign and notarize all MacOS binaries (Ava Chow)
0bd5cb7ac4 guix: Update signapple (Ava Chow)
2b279a2138 build: Include all Windows binaries for codesigning (Ava Chow)
ac2b6083ba build: Include all MacOS binaries for codesigning (Ava Chow)
2c21db657f guix: Rename Windows unsigned binaries to unsigned.zip (Ava Chow)
9f0ee1cc9b guix: Rename MacOS binaries to unsigned.tar.gz (Ava Chow)
00b401c648 guix: Rename unsigned.tar.gz to codesigning.tar.gz (Ava Chow)

Pull request description:

  Backports #31407 + #32003.

ACKs for top commit:
  pinheadmz:
    ACK b1f694fce2

Tree-SHA512: f0ca9427eb367039b4eb0c8740e66c72520413ed43f66a0ffa60d44c36426f8a31f45a1b974b5e6a591b8bf9d9e125140934d9e0ce3a8f5aaaf01c12d7fd62bd
2025-06-05 15:36:19 +02:00
fanquake
b1f694fce2 doc: update release-notes.md 2025-06-02 10:13:31 +01:00
fanquake
52f09633d0 doc: remove note about macOS self-signing
Followup to #31407.

Github-Pull: #32003
Rebased-From: c873ab6f23
2025-06-02 10:13:31 +01:00
Ava Chow
744b1c8581 guix: Apply all codesignatures to Windows binaries
Github-Pull: #31407
Rebased-From: e181bda061
2025-06-02 10:13:30 +01:00
Ava Chow
812cadefa2 guix: Apply codesignatures to all MacOS binaries
Github-Pull: #31407
Rebased-From: aafbd23fd9
2025-06-02 10:13:30 +01:00
Ava Chow
c60055c637 contrib: Sign and notarize all MacOS binaries
Signapple has been updated to sign individual binaries, and notarize app
bundles and binaries. When codesigning, all individual binaries will be
codesigned, and both the app bundle and individual binaries will be
notarized.

Github-Pull: #31407
Rebased-From: 31d325464d
2025-06-02 10:13:30 +01:00
Ava Chow
0bd5cb7ac4 guix: Update signapple
Github-Pull: #31407
Rebased-From: 710d5b5149
2025-06-02 10:13:30 +01:00
Ava Chow
2b279a2138 build: Include all Windows binaries for codesigning
Github-Pull: #31407
Rebased-From: e8b3c44da6
2025-06-02 10:13:30 +01:00
Ava Chow
ac2b6083ba build: Include all MacOS binaries for codesigning
Github-Pull: #31407
Rebased-From: dd4ec840ee
2025-06-02 10:13:25 +01:00
Ava Chow
2c21db657f guix: Rename Windows unsigned binaries to unsigned.zip
As codesigned binaries will be published, the unsigned ones should be
clearly marked as such.

Github-Pull: #31407
Rebased-From: 4e5c9ceb9d
2025-05-30 11:28:25 +01:00
Ava Chow
9f0ee1cc9b guix: Rename MacOS binaries to unsigned.tar.gz
The MacOS binaries are unsigned and therefore also unusable on MacOS.
Indicate as such by naming the tarball "unsigned".

Github-Pull: #31407
Rebased-From: d9d49cd533
2025-05-30 11:28:25 +01:00
Ava Chow
00b401c648 guix: Rename unsigned.tar.gz to codesigning.tar.gz
The tarballs used for codesigning are more than merely unsigned, they
also contain scripts and other data for codesigning. Rename them to
codesigning.tar.gz to distinguish from tarballs containing actually just
the unsigned binaries.

Github-Pull: #31407
Rebased-From: c214e5268f
2025-05-30 11:28:24 +01:00
merge-script
59c19a5416 Merge bitcoin/bitcoin#32639: [28.x] Backport guix: accomodate migration to codeberg
5c2ba9f583 guix: accomodate migration to codeberg (fanquake)

Pull request description:

  See https://guix.gnu.org/blog/2025/migrating-to-codeberg/.

  When interacting with the old repo you may now also see:
  ```bash
  warning: redirecting to https://codeberg.org/guix/guix/
  ```

  Github-Pull: #32439
  Rebased-From: c8d9baae94

ACKs for top commit:
  hebasto:
    ACK 5c2ba9f583.

Tree-SHA512: ce43bdaf8bba3fb6c3db2794f25aeaf60557a1151c45903cbfe8e63345f1a9b0f6255d6055b5505556942f569a1683703999e7ed1d59698bdcd4e64edbb3405e
2025-05-30 11:09:23 +01:00
fanquake
5c2ba9f583 guix: accomodate migration to codeberg
See https://guix.gnu.org/blog/2025/migrating-to-codeberg/.

When interacting with the old repo you may now also see:
```bash
warning: redirecting to https://codeberg.org/guix/guix/
```

Github-Pull: #32439
Rebased-From: c8d9baae94
2025-05-29 13:14:53 +01:00
merge-script
ac637458ef Merge bitcoin/bitcoin#32480: [28.x] 28.2rc1
186e3f1fb6 doc: update manual pages for 28.2rc1 (fanquake)
bbfb994fc1 build: bump version to 28.2rc1 (fanquake)
fdc629fa73 doc: update release notes for 28.2rc1 (fanquake)

Pull request description:

  Final changes for `v28.2rc1`.

ACKs for top commit:
  willcl-ark:
    ACK 186e3f1fb6

Tree-SHA512: 56c192c9bfb7b2d69b7b039d8e024c18ba39dffed42dbd120f15644cac134e008333ec73ac6ef501db2f2a0f3b125b3003650c4209fa26d0ecb8b566d417374e
2025-05-16 18:09:51 +01:00
fanquake
186e3f1fb6 doc: update manual pages for 28.2rc1 2025-05-13 14:41:46 +01:00
fanquake
bbfb994fc1 build: bump version to 28.2rc1 2025-05-13 14:41:46 +01:00
fanquake
fdc629fa73 doc: update release notes for 28.2rc1 2025-05-13 14:41:42 +01:00
merge-script
a124b91339 Merge bitcoin/bitcoin#32299: [28.x] Backports
812e637521 doc: update release notes for 28.x (fanquake)
2ccdfa424c scripted-diff: Use bpf_cflags (MarcoFalke)
3df2624ee9 test: Add imports for util bpf_cflags (MarcoFalke)
e65676216c build: use make < 3.82 syntax for define directive (Sjors Provoost)
2d6c14efba refactor: Remove spurious virtual from final ~CZMQNotificationInterface (MarcoFalke)
9b15b20cb1 test: Handle empty string returned by CLI as None in RPC tests (Brandon Odiwuor)

Pull request description:

  Backports:

  - #32070
  - #32187
  - #32286
  - #32336

ACKs for top commit:
  willcl-ark:
    ACK 812e637521

Tree-SHA512: b5c9c6b70588658310fd2d79dbd2d1148d8650e020daa9ac8ea2d3380c1e95a92e554b43b0dfd989308a729c5226e1f1ddb13cb1bb56dc5be571e4fc2f2795d6
2025-05-13 14:02:32 +01:00
fanquake
812e637521 doc: update release notes for 28.x 2025-05-13 12:55:59 +01:00
MarcoFalke
2ccdfa424c scripted-diff: Use bpf_cflags
-BEGIN VERIFY SCRIPT-

 ren() { sed --regexp-extended -i "s/$1/$2/g" $( git grep --extended-regexp -l "$1" ) ; }

 ren 'cflags=\["-Wno-error=implicit-function-declaration"\]' 'cflags=bpf_cflags()'

-END VERIFY SCRIPT-

Github-Pull: #32336
Rebased-From: facb9b327b
2025-04-24 16:25:47 +01:00
MarcoFalke
3df2624ee9 test: Add imports for util bpf_cflags
This is required for the next commit.

Github-Pull: #32336
Rebased-From: fa0c1baaf8
2025-04-24 15:22:24 +01:00
Sjors Provoost
e65676216c build: use make < 3.82 syntax for define directive
From the GNU make 3.82 release announcement:

* The 'define' make directive now allows a variable assignment operator
  after the variable name, to allow for simple, conditional, or appending
  multi-line variable assignment.

macOS ships with 3.81. This caused the multiprocess config options
to be ignored.

Fixes #32068

Co-authored-by: Ryan Ofsky <ryan@ofsky.org>

Github-Pull: #32070
Rebased-From: 9157d9e449
2025-04-17 15:18:34 +01:00
MarcoFalke
2d6c14efba refactor: Remove spurious virtual from final ~CZMQNotificationInterface
Github-Pull: #32187
Rebased-From: fa69c42fdf
2025-04-17 15:14:39 +01:00
Brandon Odiwuor
9b15b20cb1 test: Handle empty string returned by CLI as None in RPC tests 2025-04-17 13:08:38 +01:00
glozow
dbc450c1b5 Merge bitcoin/bitcoin#31648: [28.x] Backports
e57359c7dd doc: Update release notes (fanquake)
51fbcba682 depends: Fix compiling `libevent` package on NetBSD (Hennadii Stepanov)
2829588882 tracing: Rename the `MIN` macro to `_TRACEPOINT_TEST_MIN` in log_raw_p2p_msgs (0xb10c)
f676da82fa depends: Fix spacing issue (Hennadii Stepanov)
4e7dd0ac20 doc: upgrade license to 2025. (Kay)

Pull request description:

  Backports:
  * https://github.com/bitcoin/bitcoin/pull/31500
  * https://github.com/bitcoin/bitcoin/pull/31611
  * https://github.com/bitcoin/bitcoin/pull/31623
  * https://github.com/bitcoin/bitcoin/pull/31627

ACKs for top commit:
  stickies-v:
    ACK e57359c7dd
  willcl-ark:
    ACK e57359c7dd

Tree-SHA512: 2ddc7e5cf1b84846b5b066509074a475bdce6ba70938c5100c985b1135ae0662568654c4053aeddb4a022c7c2c38c49f6ed42f9cc2ff68a3057236202fae141c
2025-03-05 12:34:27 -05:00
fanquake
e57359c7dd doc: Update release notes 2025-03-05 13:49:49 +00:00
Hennadii Stepanov
51fbcba682 depends: Fix compiling libevent package on NetBSD
Github-Pull: #31500
Rebased-From: f89f16846e
2025-03-05 13:48:47 +00:00
0xb10c
2829588882 tracing: Rename the MIN macro to _TRACEPOINT_TEST_MIN in log_raw_p2p_msgs
Inspired by: 00c1dbd26d (#31419)

Github-Pull: #31623
Rebased-From: f93f0c9396
2025-01-10 17:10:38 +00:00
Hennadii Stepanov
f676da82fa depends: Fix spacing issue
This change resolves an issue where a missing space caused the value of
the `build_AR` variable to be concatenated with the "NM=" string. This
resulted in subsequent calls to `${AR}` and `${NM}` failing.

Github-Pull: #31627
Rebased-From: 8a46286da6
2025-01-10 17:10:38 +00:00
Kay
4e7dd0ac20 doc: upgrade license to 2025.
Github-Pull: #31611
Rebased-From: b537a2c02a
2025-01-10 17:10:38 +00:00
94 changed files with 1256 additions and 704 deletions

View File

@@ -1,217 +0,0 @@
env: # Global defaults
CIRRUS_CLONE_DEPTH: 1
PACKAGE_MANAGER_INSTALL: "apt-get update && apt-get install -y"
MAKEJOBS: "-j10"
TEST_RUNNER_PORT_MIN: "14000" # Must be larger than 12321, which is used for the http cache. See https://cirrus-ci.org/guide/writing-tasks/#http-cache
CI_FAILFAST_TEST_LEAVE_DANGLING: "1" # Cirrus CI does not care about dangling processes and setting this variable avoids killing the CI script itself on error
CCACHE_MAXSIZE: "200M"
CCACHE_DIR: "/tmp/ccache_dir"
CCACHE_NOHASHDIR: "1" # Debug info might contain a stale path if the build dir changes, but this is fine
# A self-hosted machine(s) can be used via Cirrus CI. It can be configured with
# multiple users to run tasks in parallel. No sudo permission is required.
#
# https://cirrus-ci.org/guide/persistent-workers/
#
# Generally, a persistent worker must run Ubuntu 23.04+ or Debian 12+.
#
# The following specific types should exist, with the following requirements:
# - small: For an x86_64 machine, recommended to have 2 CPUs and 8 GB of memory.
# - medium: For an x86_64 machine, recommended to have 4 CPUs and 16 GB of memory.
# - arm64: For an aarch64 machine, recommended to have 2 CPUs and 8 GB of memory.
#
# CI jobs for the latter configuration can be run on x86_64 hardware
# by installing qemu-user-static, which works out of the box with
# podman or docker. Background: https://stackoverflow.com/a/72890225/313633
#
# The above machine types are matched to each task by their label. Refer to the
# Cirrus CI docs for more details.
#
# When a contributor maintains a fork of the repo, any pull request they make
# to their own fork, or to the main repository, will trigger two CI runs:
# one for the branch push and one for the pull request.
# This can be avoided by setting SKIP_BRANCH_PUSH=true as a custom env variable
# in Cirrus repository settings, accessible from
# https://cirrus-ci.com/github/my-organization/my-repository
#
# On machines that are persisted between CI jobs, RESTART_CI_DOCKER_BEFORE_RUN=1
# ensures that previous containers and artifacts are cleared before each run.
# This requires installing Podman instead of Docker.
#
# Futhermore:
# - apt-get is required due to PACKAGE_MANAGER_INSTALL
# - podman-docker-4.1+ is required due to the bugfix in 4.1
# (https://github.com/bitcoin/bitcoin/pull/21652#issuecomment-1657098200)
# - The ./ci/ dependencies (with cirrus-cli) should be installed. One-liner example
# for a single user setup with sudo permission:
#
# ```
# apt update && apt install git screen python3 bash podman-docker curl -y && curl -L -o cirrus "https://github.com/cirruslabs/cirrus-cli/releases/latest/download/cirrus-linux-$(dpkg --print-architecture)" && mv cirrus /usr/local/bin/cirrus && chmod +x /usr/local/bin/cirrus
# ```
#
# - There are no strict requirements on the hardware. Having fewer CPU threads
# than recommended merely causes the CI script to run slower.
# To avoid rare and intermittent OOM due to short memory usage spikes,
# it is recommended to add (and persist) swap:
#
# ```
# fallocate -l 16G /swapfile_ci && chmod 600 /swapfile_ci && mkswap /swapfile_ci && swapon /swapfile_ci && ( echo '/swapfile_ci none swap sw 0 0' | tee -a /etc/fstab )
# ```
#
# - To register the persistent worker, open a `screen` session and run:
#
# ```
# RESTART_CI_DOCKER_BEFORE_RUN=1 screen cirrus worker run --labels type=todo_fill_in_type --token todo_fill_in_token
# ```
# https://cirrus-ci.org/guide/tips-and-tricks/#sharing-configuration-between-tasks
filter_template: &FILTER_TEMPLATE
# Allow forks to specify SKIP_BRANCH_PUSH=true and skip CI runs when a branch is pushed,
# but still run CI when a PR is created.
# https://cirrus-ci.org/guide/writing-tasks/#conditional-task-execution
skip: $SKIP_BRANCH_PUSH == "true" && $CIRRUS_PR == ""
stateful: false # https://cirrus-ci.org/guide/writing-tasks/#stateful-tasks
base_template: &BASE_TEMPLATE
<< : *FILTER_TEMPLATE
merge_base_script:
# Unconditionally install git (used in fingerprint_script).
- git --version || bash -c "$PACKAGE_MANAGER_INSTALL git"
- if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
- git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge"
- git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts
# Also, the merge commit is used to lint COMMIT_RANGE="HEAD~..HEAD"
main_template: &MAIN_TEMPLATE
timeout_in: 120m # https://cirrus-ci.org/faq/#instance-timed-out
ci_script:
- ./ci/test_run_all.sh
global_task_template: &GLOBAL_TASK_TEMPLATE
<< : *BASE_TEMPLATE
<< : *MAIN_TEMPLATE
compute_credits_template: &CREDITS_TEMPLATE
# https://cirrus-ci.org/pricing/#compute-credits
# Only use credits for pull requests to the main repo
use_compute_credits: $CIRRUS_REPO_FULL_NAME == 'bitcoin/bitcoin' && $CIRRUS_PR != ""
task:
name: 'lint'
<< : *BASE_TEMPLATE
container:
image: debian:bookworm
cpu: 1
memory: 1G
# For faster CI feedback, immediately schedule the linters
<< : *CREDITS_TEMPLATE
test_runner_cache:
folder: "/lint_test_runner"
fingerprint_script: echo $CIRRUS_TASK_NAME $(git rev-parse HEAD:test/lint/test_runner)
python_cache:
folder: "/python_build"
fingerprint_script: cat .python-version /etc/os-release
unshallow_script:
- git fetch --unshallow --no-tags
lint_script:
- ./ci/lint_run_all.sh
task:
name: 'tidy'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: medium
env:
FILE_ENV: "./ci/test/00_setup_env_native_tidy.sh"
task:
name: 'ARM, unit tests, no functional tests'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: arm64 # Use arm64 worker to sidestep qemu and avoid a slow CI: https://github.com/bitcoin/bitcoin/pull/28087#issuecomment-1649399453
env:
FILE_ENV: "./ci/test/00_setup_env_arm.sh"
task:
name: 'Win64, unit tests, no gui tests, no functional tests'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: small
env:
FILE_ENV: "./ci/test/00_setup_env_win64.sh"
task:
name: '32-bit CentOS, dash, gui'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: small
env:
FILE_ENV: "./ci/test/00_setup_env_i686_centos.sh"
task:
name: 'previous releases, depends DEBUG'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: small
env:
FILE_ENV: "./ci/test/00_setup_env_native_previous_releases.sh"
task:
name: 'TSan, depends, gui'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: medium
env:
FILE_ENV: "./ci/test/00_setup_env_native_tsan.sh"
task:
name: 'MSan, depends'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: small
timeout_in: 300m # Use longer timeout for the *rare* case where a full build (llvm + msan + depends + ...) needs to be done.
env:
FILE_ENV: "./ci/test/00_setup_env_native_msan.sh"
task:
name: 'fuzzer,address,undefined,integer, no depends'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: medium
env:
FILE_ENV: "./ci/test/00_setup_env_native_fuzz.sh"
task:
name: 'multiprocess, i686, DEBUG'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: medium
env:
FILE_ENV: "./ci/test/00_setup_env_i686_multiprocess.sh"
task:
name: 'no wallet, libbitcoinkernel'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: small
env:
FILE_ENV: "./ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh"
task:
name: 'macOS-cross, gui, no tests'
<< : *GLOBAL_TASK_TEMPLATE
persistent_worker:
labels:
type: small
env:
FILE_ENV: "./ci/test/00_setup_env_mac_cross.sh"

View File

@@ -0,0 +1,52 @@
name: 'Configure Docker'
description: 'Set up Docker build driver and configure build cache args'
inputs:
use-cirrus:
description: 'Use cirrus cache'
required: true
runs:
using: 'composite'
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
# Use host network to allow access to cirrus gha cache running on the host
driver-opts: |
network=host
# This is required to allow buildkit to access the actions cache
- name: Expose actions cache variables
uses: actions/github-script@v6
with:
script: |
core.exportVariable('ACTIONS_CACHE_URL', process.env['ACTIONS_CACHE_URL'])
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env['ACTIONS_RUNTIME_TOKEN'])
- name: Construct docker build cache args
shell: bash
run: |
# Configure docker build cache backend
#
# On forks the gha cache will work but will use Github's cache backend.
# Docker will check for variables $ACTIONS_CACHE_URL, $ACTIONS_RESULTS_URL and $ACTIONS_RUNTIME_TOKEN
# which are set automatically when running on GitHub infra: https://docs.docker.com/build/cache/backends/gha/#synopsis
# Use cirrus cache host
if [[ ${{ inputs.use-cirrus }} == 'true' ]]; then
url_args="url=${CIRRUS_CACHE_HOST},url_v2=${CIRRUS_CACHE_HOST}"
else
url_args=""
fi
# Always optimistically --cachefrom in case a cache blob exists
args=(--cache-from "type=gha${url_args:+,${url_args}},scope=${CONTAINER_NAME}")
# If this is a push to the default branch, also add --cacheto to save the cache
if [[ ${{ github.event_name }} == "push" && ${{ github.ref_name }} == ${{ github.event.repository.default_branch }} ]]; then
args+=(--cache-to "type=gha${url_args:+,${url_args}},mode=max,ignore-error=true,scope=${CONTAINER_NAME}")
fi
# Always `--load` into docker images (needed when using the `docker-container` build driver).
args+=(--load)
echo "DOCKER_BUILD_CACHE_ARG=${args[*]}" >> $GITHUB_ENV

View File

@@ -0,0 +1,27 @@
name: 'Configure environment'
description: 'Configure CI, cache and container name environment variables'
runs:
using: 'composite'
steps:
- name: Set CI and cache directories
shell: bash
run: |
echo "BASE_ROOT_DIR=${{ runner.temp }}" >> "$GITHUB_ENV"
echo "BASE_BUILD_DIR=${{ runner.temp }}/build" >> "$GITHUB_ENV"
echo "CCACHE_DIR=${{ runner.temp }}/ccache_dir" >> $GITHUB_ENV
echo "DEPENDS_DIR=${{ runner.temp }}/depends" >> "$GITHUB_ENV"
echo "BASE_CACHE=${{ runner.temp }}/depends/built" >> $GITHUB_ENV
echo "SOURCES_PATH=${{ runner.temp }}/depends/sources" >> $GITHUB_ENV
echo "PREVIOUS_RELEASES_DIR=${{ runner.temp }}/previous_releases" >> $GITHUB_ENV
- name: Set cache hashes
shell: bash
run: |
echo "DEPENDS_HASH=$(git ls-tree HEAD depends "ci/test/$FILE_ENV" | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
echo "PREVIOUS_RELEASES_HASH=$(git ls-tree HEAD test/get_previous_releases.py | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
- name: Get container name
shell: bash
run: |
source $FILE_ENV
echo "CONTAINER_NAME=$CONTAINER_NAME" >> "$GITHUB_ENV"

View File

@@ -0,0 +1,47 @@
name: 'Restore Caches'
description: 'Restore ccache, depends sources, and built depends caches'
runs:
using: 'composite'
steps:
- name: Restore Ccache cache
id: ccache-cache
uses: cirruslabs/cache/restore@v4
with:
path: ${{ env.CCACHE_DIR }}
key: ccache-${{ env.CONTAINER_NAME }}-${{ github.run_id }}
restore-keys: |
ccache-${{ env.CONTAINER_NAME }}-
- name: Restore depends sources cache
id: depends-sources
uses: cirruslabs/cache/restore@v4
with:
path: ${{ env.SOURCES_PATH }}
key: depends-sources-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
restore-keys: |
depends-sources-${{ env.CONTAINER_NAME }}-
- name: Restore built depends cache
id: depends-built
uses: cirruslabs/cache/restore@v4
with:
path: ${{ env.BASE_CACHE }}
key: depends-built-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
restore-keys: |
depends-built-${{ env.CONTAINER_NAME }}-
- name: Restore previous releases cache
id: previous-releases
uses: cirruslabs/cache/restore@v4
with:
path: ${{ env.PREVIOUS_RELEASES_DIR }}
key: previous-releases-${{ env.CONTAINER_NAME }}-${{ env.PREVIOUS_RELEASES_HASH }}
restore-keys: |
previous-releases-${{ env.CONTAINER_NAME }}-
- name: export cache hits
shell: bash
run: |
echo "depends-sources-cache-hit=${{ steps.depends-sources.outputs.cache-hit }}" >> $GITHUB_ENV
echo "depends-built-cache-hit=${{ steps.depends-built.outputs.cache-hit }}" >> $GITHUB_ENV
echo "previous-releases-cache-hit=${{ steps.previous-releases.outputs.cache-hit }}" >> $GITHUB_ENV

39
.github/actions/save-caches/action.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: 'Save Caches'
description: 'Save ccache, depends sources, and built depends caches'
runs:
using: 'composite'
steps:
- name: debug cache hit inputs
shell: bash
run: |
echo "depends sources direct cache hit to primary key: ${{ env.depends-sources-cache-hit }}"
echo "depends built direct cache hit to primary key: ${{ env.depends-built-cache-hit }}"
echo "previous releases direct cache hit to primary key: ${{ env.previous-releases-cache-hit }}"
- name: Save Ccache cache
uses: cirruslabs/cache/save@v4
if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) }}
with:
path: ${{ env.CCACHE_DIR }}
key: ccache-${{ env.CONTAINER_NAME }}-${{ github.run_id }}
- name: Save depends sources cache
uses: cirruslabs/cache/save@v4
if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) && (env.depends-sources-cache-hit != 'true') }}
with:
path: ${{ env.SOURCES_PATH }}
key: depends-sources-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
- name: Save built depends cache
uses: cirruslabs/cache/save@v4
if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) && (env.depends-built-cache-hit != 'true' )}}
with:
path: ${{ env.BASE_CACHE }}
key: depends-built-${{ env.CONTAINER_NAME }}-${{ env.DEPENDS_HASH }}
- name: Save previous releases cache
uses: cirruslabs/cache/save@v4
if: ${{ (github.event_name == 'push') && (github.ref_name == github.event.repository.default_branch) && (env.previous-releases-cache-hit != 'true' )}}
with:
path: ${{ env.PREVIOUS_RELEASES_DIR }}
key: previous-releases-${{ env.CONTAINER_NAME }}-${{ env.PREVIOUS_RELEASES_HASH }}

View File

@@ -19,9 +19,26 @@ concurrency:
env:
CI_FAILFAST_TEST_LEAVE_DANGLING: 1 # GHA does not care about dangling processes and setting this variable avoids killing the CI script itself on error
MAKEJOBS: '-j10'
CIRRUS_CACHE_HOST: http://127.0.0.1:12321/ # When using Cirrus Runners this host can be used by the docker `gha` build cache type.
REPO_USE_CIRRUS_RUNNERS: 'bitcoin/bitcoin' # Use cirrus runners and cache for this repo, instead of falling back to the slow GHA runners
jobs:
runners:
name: 'determine runners'
runs-on: ubuntu-latest
outputs:
use-cirrus-runners: ${{ steps.runners.outputs.use-cirrus-runners }}
steps:
- id: runners
run: |
if [[ "${REPO_USE_CIRRUS_RUNNERS}" == "${{ github.repository }}" ]]; then
echo "use-cirrus-runners=true" >> "$GITHUB_OUTPUT"
echo "::notice title=Runner Selection::Using Cirrus Runners"
else
echo "use-cirrus-runners=false" >> "$GITHUB_OUTPUT"
echo "::notice title=Runner Selection::Using GitHub-hosted runners"
fi
test-each-commit:
name: 'test each commit'
runs-on: ubuntu-24.04
@@ -91,8 +108,12 @@ jobs:
BASE_ROOT_DIR: ${{ github.workspace }}
steps:
- name: Checkout
uses: actions/checkout@v4
- &CHECKOUT
name: Checkout
uses: actions/checkout@v5
with:
# Ensure the latest merged pull request state is used, even on re-runs.
ref: &CHECKOUT_REF_TMPL ${{ github.event_name == 'pull_request' && github.ref || '' }}
- name: Clang version
run: |
@@ -143,13 +164,12 @@ jobs:
CI_CCACHE_VERSION: '4.7.5'
CI_QT_CONF: '-release -silent -opensource -confirm-license -opengl desktop -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -nomake examples -nomake tests -nomake tools -no-angle -no-dbus -no-gif -no-gtk -no-ico -no-icu -no-libjpeg -no-libudev -no-sql-sqlite -no-sql-odbc -no-sqlite -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip doc -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquickcontrols -skip qtquickcontrols2 -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtsvg -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebglplugin -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-bearermanagement -no-feature-printdialog -no-feature-printer -no-feature-printpreviewdialog -no-feature-printpreviewwidget -no-feature-sql -no-feature-sqlmodel -no-feature-textbrowser -no-feature-textmarkdownwriter -no-feature-textodfwriter -no-feature-xml'
CI_QT_DIR: 'qt-everywhere-src-5.15.11'
CI_QT_URL: 'https://download.qt.io/official_releases/qt/5.15/5.15.11/single/qt-everywhere-opensource-src-5.15.11.zip'
CI_QT_URL: 'https://download.qt.io/archive/qt/5.15/5.15.11/single/qt-everywhere-opensource-src-5.15.11.zip'
PYTHONUTF8: 1
TEST_RUNNER_TIMEOUT_FACTOR: 40
steps:
- name: Checkout
uses: actions/checkout@v4
- *CHECKOUT
- name: Configure Developer Command Prompt for Microsoft Visual C++
# Using microsoft/setup-msbuild is not enough.
@@ -311,45 +331,154 @@ jobs:
shell: cmd
run: py -3 test\fuzz\test_runner.py --par %NUMBER_OF_PROCESSORS% --loglevel DEBUG %RUNNER_TEMP%\qa-assets\fuzz_seed_corpus
asan-lsan-ubsan-integer-no-depends-usdt:
name: 'ASan + LSan + UBSan + integer, no depends, USDT'
runs-on: ubuntu-24.04 # has to match container in ci/test/00_setup_env_native_asan.sh for tracing tools
# No need to run on the read-only mirror, unless it is a PR.
if: github.repository != 'bitcoin-core/gui' || github.event_name == 'pull_request'
timeout-minutes: 120
- name: CI script
run: ./ci/test_run_all.sh
ci-matrix:
name: ${{ matrix.name }}
needs: runners
runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && matrix.cirrus-runner || matrix.fallback-runner }}
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
timeout-minutes: ${{ matrix.timeout-minutes }}
env:
FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
DANGER_CI_ON_HOST_CACHE_FOLDERS: 1
DANGER_CI_ON_HOST_FOLDERS: 1
FILE_ENV: ${{ matrix.file-env }}
strategy:
fail-fast: false
matrix:
include:
- name: 'ARM, unit tests, no functional tests'
cirrus-runner: 'ubuntu-24.04-arm' # Cirrus' Arm runners are Apple (with virtual Linux aarch64), which doesn't support 32-bit mode
fallback-runner: 'ubuntu-24.04-arm'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_arm.sh'
- name: 'Win64, unit tests, no gui tests, no functional tests'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_win64.sh'
- name: 'ASan + LSan + UBSan + integer, no depends, USDT'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md' # has to match container in ci/test/00_setup_env_native_asan.sh for tracing tools
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_asan.sh'
- name: 'macOS-cross, gui, no tests'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_mac_cross.sh'
- name: 'No wallet, libbitcoinkernel'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh'
- name: 'i686, multiprocess, DEBUG'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_i686_multiprocess.sh'
- name: 'fuzzer,address,undefined,integer, no depends'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 240
file-env: './ci/test/00_setup_env_native_fuzz.sh'
- name: 'previous releases, depends DEBUG'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_previous_releases.sh'
- name: '32bit CentOS, dash, gui'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_i686_centos.sh'
- name: 'tidy'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_tidy.sh'
- name: 'TSan, depends, gui'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-md'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_tsan.sh'
- name: 'MSan, depends'
cirrus-runner: 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-lg'
fallback-runner: 'ubuntu-24.04'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_native_msan.sh'
steps:
- name: Checkout
uses: actions/checkout@v4
- *CHECKOUT
- name: Set Ccache directory
run: echo "CCACHE_DIR=${RUNNER_TEMP}/ccache_dir" >> "$GITHUB_ENV"
- name: Configure environment
uses: ./.github/actions/configure-environment
- name: Set base root directory
run: echo "BASE_ROOT_DIR=${RUNNER_TEMP}" >> "$GITHUB_ENV"
- name: Restore caches
id: restore-cache
uses: ./.github/actions/restore-caches
- name: Restore Ccache cache
id: ccache-cache
uses: actions/cache/restore@v4
- name: Configure Docker
uses: ./.github/actions/configure-docker
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ github.job }}-ccache-${{ github.run_id }}
restore-keys: ${{ github.job }}-ccache-
use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }}
- name: Enable bpfcc script
if: ${{ env.CONTAINER_NAME == 'ci_native_asan' }}
# In the image build step, no external environment variables are available,
# so any settings will need to be written to the settings env file:
run: sed -i "s|\${INSTALL_BCC_TRACING_TOOLS}|true|g" ./ci/test/00_setup_env_native_asan.sh
- name: Set mmap_rnd_bits
if: ${{ env.CONTAINER_NAME == 'ci_native_tsan' || env.CONTAINER_NAME == 'ci_native_msan' }}
# Prevents crashes due to high ASLR entropy
run: sudo sysctl -w vm.mmap_rnd_bits=28
- name: CI script
run: ./ci/test_run_all.sh
- name: Save Ccache cache
uses: actions/cache/save@v4
if: github.event_name != 'pull_request' && steps.ccache-cache.outputs.cache-hit != 'true'
- name: Save caches
uses: ./.github/actions/save-caches
lint:
name: 'lint'
needs: runners
runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-xs' || 'ubuntu-24.04' }}
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
timeout-minutes: 20
env:
CONTAINER_NAME: "bitcoin-linter"
steps:
- name: Checkout
uses: actions/checkout@v5
with:
path: ${{ env.CCACHE_DIR }}
# https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache
key: ${{ github.job }}-ccache-${{ github.run_id }}
ref: *CHECKOUT_REF_TMPL
fetch-depth: 0
- name: Configure Docker
uses: ./.github/actions/configure-docker
with:
use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }}
- name: CI script
run: |
set -o xtrace
docker buildx build -t "$CONTAINER_NAME" $DOCKER_BUILD_CACHE_ARG --file "./ci/lint_imagefile" .
CIRRUS_PR_FLAG=""
if [ "${{ github.event_name }}" = "pull_request" ]; then
CIRRUS_PR_FLAG="-e CIRRUS_PR=1"
fi
docker run --rm $CIRRUS_PR_FLAG -v "$(pwd)":/bitcoin "$CONTAINER_NAME"

View File

@@ -1,7 +1,7 @@
The MIT License (MIT)
Copyright (c) 2009-2024 The Bitcoin Core developers
Copyright (c) 2009-2024 Bitcoin Developers
Copyright (c) 2009-2025 The Bitcoin Core developers
Copyright (c) 2009-2025 Bitcoin Developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -69,7 +69,7 @@ Translations
------------
Changes to translations as well as new translations can be submitted to
[Bitcoin Core's Transifex page](https://www.transifex.com/bitcoin/bitcoin/).
[Bitcoin Core's Transifex page](https://explore.transifex.com/bitcoin/bitcoin/).
Translations are periodically pulled from Transifex and merged into the git repository. See the
[translation process](doc/translation_process.md) for details on how this works.

View File

@@ -32,7 +32,7 @@ Qt
---------------------
To build Bitcoin Core with the GUI, a static build of Qt is required.
1. Download a single ZIP archive of Qt source code from https://download.qt.io/official_releases/qt/ (e.g., [`qt-everywhere-opensource-src-5.15.11.zip`](https://download.qt.io/official_releases/qt/5.15/5.15.11/single/qt-everywhere-opensource-src-5.15.11.zip)), and expand it into a dedicated folder. The following instructions assume that this folder is `C:\dev\qt-source`.
1. Download a single ZIP archive of Qt source code from https://download.qt.io/archive/qt/ (e.g., [`qt-everywhere-opensource-src-5.15.11.zip`](https://download.qt.io/archive/qt/5.15/5.15.11/single/qt-everywhere-opensource-src-5.15.11.zip)), and expand it into a dedicated folder. The following instructions assume that this folder is `C:\dev\qt-source`.
> 💡 **Tip:** If you use the default path with "Extract All" for the Qt source code zip file, and end up with something like `C:\dev\qt-everywhere-opensource-src-5.15.11\qt-everywhere-src-5.15.11`, you are likely to encounter a "path too long" error when building. To fix the problem move the source files to a shorter path such as the recommended `C:\dev\qt-source`.

View File

@@ -1,8 +1,8 @@
## CI Scripts
# CI Scripts
This directory contains scripts for each build step in each build stage.
### Running a Stage Locally
## Running a Stage Locally
Be aware that the tests will be built and run in-place, so please run at your own risk.
If the repository is not a fresh git clone, you might have to clean files from previous builds or test runs first.
@@ -27,7 +27,7 @@ with a specific configuration,
env -i HOME="$HOME" PATH="$PATH" USER="$USER" bash -c 'FILE_ENV="./ci/test/00_setup_env_arm.sh" ./ci/test_run_all.sh'
```
### Configurations
## Configurations
The test files (`FILE_ENV`) are constructed to test a wide range of
configurations, rather than a single pass/fail. This helps to catch build
@@ -49,8 +49,32 @@ env -i HOME="$HOME" PATH="$PATH" USER="$USER" bash -c 'MAKEJOBS="-j1" FILE_ENV="
The files starting with `0n` (`n` greater than 0) are the scripts that are run
in order.
### Cache
## Cache
In order to avoid rebuilding all dependencies for each build, the binaries are
cached and reused when possible. Changes in the dependency-generator will
trigger cache-invalidation and rebuilds as necessary.
## Configuring a repository for CI
### Primary repository
To configure the primary repository, follow these steps:
1. Register with [Cirrus Runners](https://cirrus-runners.app/) and purchase runners.
2. Install the Cirrus Runners GitHub app against the GitHub organization.
3. Enable organisation-level runners to be used in public repositories:
1. `Org settings -> Actions -> Runner Groups -> Default -> Allow public repos`
4. Permit the following actions to run:
1. cirruslabs/cache/restore@\*
1. cirruslabs/cache/save@\*
1. docker/setup-buildx-action@\*
1. actions/github-script@\*
### Forked repositories
When used in a fork the CI will run on GitHub's free hosted runners by default.
In this case, due to GitHub's 10GB-per-repo cache size limitations caches will be frequently evicted and missed, but the workflows will run (slowly).
It is also possible to use your own Cirrus Runners in your own fork with an appropriate patch to the `REPO_USE_CIRRUS_RUNNERS` variable in ../.github/workflows/ci.yml
NB that Cirrus Runners only work at an organisation level, therefore in order to use your own Cirrus Runners, *the fork must be within your own organisation*.

View File

@@ -1,17 +0,0 @@
#!/usr/bin/env bash
#
# Copyright (c) 2019-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C.UTF-8
# Only used in .cirrus.yml. Refer to test/lint/README.md on how to run locally.
cp "./ci/retry/retry" "/ci_retry"
cp "./.python-version" "/.python-version"
mkdir --parents "/test/lint"
cp --recursive "./test/lint/test_runner" "/test/lint/"
set -o errexit; source ./ci/lint/04_install.sh
set -o errexit
./ci/lint/06_script.sh

View File

@@ -35,7 +35,7 @@ fi
echo "Fallback to default values in env (if not yet set)"
# The number of parallel jobs to pass down to make and test_runner.py
export MAKEJOBS=${MAKEJOBS:--j4}
export MAKEJOBS=${MAKEJOBS:--j$(if command -v nproc > /dev/null 2>&1; then nproc; else sysctl -n hw.logicalcpu; fi)}
# Whether to prefer BusyBox over GNU utilities
export USE_BUSY_BOX=${USE_BUSY_BOX:-false}

View File

@@ -9,6 +9,7 @@ export LC_ALL=C.UTF-8
export HOST=x86_64-apple-darwin
# Homebrew's python@3.12 is marked as externally managed (PEP 668).
# Therefore, `--break-system-packages` is needed.
export CONTAINER_NAME="ci_mac_native" # macos does not use a container, but the env var is needed for logging
export PIP_PACKAGES="--break-system-packages zmq"
export GOAL="install"
export BITCOIN_CONFIG="--with-gui --with-miniupnpc --with-natpmp --enable-reduce-exports"

View File

@@ -17,11 +17,16 @@ if [ -z "$DANGER_RUN_CI_ON_HOST" ]; then
docker run --rm "${CI_IMAGE_NAME_TAG}" bash -c "env | grep --extended-regexp '^(HOME|PATH|USER)='" | tee --append "/tmp/env-$USER-$CONTAINER_NAME"
echo "Creating $CI_IMAGE_NAME_TAG container to run in"
DOCKER_BUILDKIT=1 docker build \
# Use buildx unconditionally
# Using buildx is required to properly load the correct driver, for use with registry caching. Neither build, nor BUILDKIT=1 currently do this properly
# shellcheck disable=SC2086
docker buildx build \
--file "${BASE_READ_ONLY_DIR}/ci/test_imagefile" \
--build-arg "CI_IMAGE_NAME_TAG=${CI_IMAGE_NAME_TAG}" \
--build-arg "FILE_ENV=${FILE_ENV}" \
--build-arg "BASE_ROOT_DIR=${BASE_ROOT_DIR}" \
--label="${CI_IMAGE_LABEL}" \
$DOCKER_BUILD_CACHE_ARG \
--tag="${CONTAINER_NAME}" \
"${BASE_READ_ONLY_DIR}"

View File

@@ -25,6 +25,14 @@ fi
echo "Free disk space:"
df -h
# We force an install of linux-headers again here via $PACKAGES to fix any
# kernel mismatch between a cached docker image and the underlying host.
# This can happen occasionally on hosted runners if the runner image is updated.
if [[ "$CONTAINER_NAME" == "ci_native_asan" ]]; then
$CI_RETRY_EXE apt-get update
${CI_RETRY_EXE} bash -c "apt-get install --no-install-recommends --no-upgrade -y $PACKAGES"
fi
# What host to compile for. See also ./depends/README.md
# Tests that need cross-compilation export the appropriate HOST.
# Tests that run natively guess the host
@@ -137,6 +145,12 @@ fi
bash -c "${MAYBE_BEAR} ${MAYBE_TOKEN} make $MAKEJOBS $GOAL" || ( echo "Build failure. Verbose build follows." && make "$GOAL" V=1 ; false )
bash -c "${PRINT_CCACHE_STATISTICS}"
if [ "$CI" = "true" ]; then
hit_rate=$(ccache -s | grep "Hits:" | head -1 | sed 's/.*(\(.*\)%).*/\1/')
if [ "${hit_rate%.*}" -lt 75 ]; then
echo "::notice title=low ccache hitrate::Ccache hit-rate in $CONTAINER_NAME was $hit_rate%"
fi
fi
du -sh "${DEPENDS_DIR}"/*/
du -sh "${PREVIOUS_RELEASES_DIR}"

View File

@@ -4,12 +4,16 @@
# See ci/README.md for usage.
ARG CI_IMAGE_NAME_TAG
# We never want scratch, but default arg silences a Warning
ARG CI_IMAGE_NAME_TAG=scratch
FROM ${CI_IMAGE_NAME_TAG}
ARG FILE_ENV
ENV FILE_ENV=${FILE_ENV}
ARG BASE_ROOT_DIR
ENV BASE_ROOT_DIR=${BASE_ROOT_DIR}
COPY ./ci/retry/retry /usr/bin/retry
COPY ./ci/test/00_setup_env.sh ./${FILE_ENV} ./ci/test/01_base_install.sh /ci_container_base/ci/test/

View File

@@ -1,10 +1,10 @@
AC_PREREQ([2.69])
define(_CLIENT_VERSION_MAJOR, 28)
define(_CLIENT_VERSION_MINOR, 1)
define(_CLIENT_VERSION_MINOR, 3)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_RC, 2)
define(_CLIENT_VERSION_IS_RELEASE, true)
define(_COPYRIGHT_YEAR, 2024)
define(_COPYRIGHT_YEAR, 2025)
define(_COPYRIGHT_HOLDERS,[The %s developers])
define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitcoin Core]])
AC_INIT([Bitcoin Core],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_BUILD)m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/bitcoin/bitcoin/issues],[bitcoin],[https://bitcoincore.org/])

View File

@@ -5,7 +5,7 @@ Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com>
Source: https://github.com/bitcoin/bitcoin
Files: *
Copyright: 2009-2024, Bitcoin Core Developers
Copyright: 2009-2025, Bitcoin Core Developers
License: Expat
Comment: The Bitcoin Core Developers encompasses all contributors to the
project, listed in the release notes or the git log.

View File

@@ -319,7 +319,7 @@ Source: https://logs.guix.gnu.org/guix/2020-11-12.log#232527
Start by cloning Guix:
```
git clone https://git.savannah.gnu.org/git/guix.git
git clone https://codeberg.org/guix/guix.git
cd guix
```
@@ -607,7 +607,7 @@ checklist.
```
Generation 38 Feb 22 2021 16:39:31 (current)
guix f350df4
repository URL: https://git.savannah.gnu.org/git/guix.git
repository URL: https://codeberg.org/guix/guix.git
branch: version-1.2.0
commit: f350df405fbcd5b9e27e6b6aa500da7f101f41e7
```
@@ -760,8 +760,8 @@ Please see the following links for more details:
- An upstream coreutils bug has been filed: [debbugs#47940](https://debbugs.gnu.org/cgi/bugreport.cgi?bug=47940)
- A Guix bug detailing the underlying problem has been filed: [guix-issues#47935](https://issues.guix.gnu.org/47935), [guix-issues#49985](https://issues.guix.gnu.org/49985#5)
- A commit to skip this test in Guix has been merged into the core-updates branch:
[savannah/guix@6ba1058](https://git.savannah.gnu.org/cgit/guix.git/commit/?id=6ba1058df0c4ce5611c2367531ae5c3cdc729ab4)
- A commit to skip this test is included since Guix 1.4.0:
[codeberg/guix@6ba1058](https://codeberg.org/guix/guix/commit/6ba1058df0c4ce5611c2367531ae5c3cdc729ab4)
[install-script]: #options-1-and-2-using-the-official-shell-installer-script-or-binary-tarball

View File

@@ -69,6 +69,12 @@ fi
mkdir -p "$VERSION_BASE"
################
# SOURCE_DATE_EPOCH should not unintentionally be set
################
check_source_date_epoch
################
# Build directories should not exist
################

View File

@@ -67,6 +67,12 @@ EOF
exit 1
fi
################
# SOURCE_DATE_EPOCH should not unintentionally be set
################
check_source_date_epoch
################
# The codesignature git worktree should not be dirty
################
@@ -137,7 +143,7 @@ fi
################
# Unsigned tarballs SHOULD exist
# Codesigning tarballs SHOULD exist
################
# Usage: outdir_for_host HOST SUFFIX
@@ -149,13 +155,13 @@ outdir_for_host() {
}
unsigned_tarball_for_host() {
codesigning_tarball_for_host() {
case "$1" in
*mingw*)
echo "$(outdir_for_host "$1")/${DISTNAME}-win64-unsigned.tar.gz"
echo "$(outdir_for_host "$1")/${DISTNAME}-win64-codesigning.tar.gz"
;;
*darwin*)
echo "$(outdir_for_host "$1")/${DISTNAME}-${1}-unsigned.tar.gz"
echo "$(outdir_for_host "$1")/${DISTNAME}-${1}-codesigning.tar.gz"
;;
*)
exit 1
@@ -164,22 +170,22 @@ unsigned_tarball_for_host() {
}
# Accumulate a list of build directories that already exist...
hosts_unsigned_tarball_missing=""
hosts_codesigning_tarball_missing=""
for host in $HOSTS; do
if [ ! -e "$(unsigned_tarball_for_host "$host")" ]; then
hosts_unsigned_tarball_missing+=" ${host}"
if [ ! -e "$(codesigning_tarball_for_host "$host")" ]; then
hosts_codesigning_tarball_missing+=" ${host}"
fi
done
if [ -n "$hosts_unsigned_tarball_missing" ]; then
if [ -n "$hosts_codesigning_tarball_missing" ]; then
# ...so that we can print them out nicely in an error message
cat << EOF
ERR: Unsigned tarballs do not exist
ERR: Codesigning tarballs do not exist
...
EOF
for host in $hosts_unsigned_tarball_missing; do
echo " ${host} '$(unsigned_tarball_for_host "$host")'"
for host in $hosts_codesigning_tarball_missing; do
echo " ${host} '$(codesigning_tarball_for_host "$host")'"
done
exit 1
fi
@@ -371,7 +377,7 @@ EOF
OUTDIR="$(OUTDIR_BASE=/outdir-base && outdir_for_host "$HOST" codesigned)" \
DIST_ARCHIVE_BASE=/outdir-base/dist-archive \
DETACHED_SIGS_REPO=/detached-sigs \
UNSIGNED_TARBALL="$(OUTDIR_BASE=/outdir-base && unsigned_tarball_for_host "$HOST")" \
CODESIGNING_TARBALL="$(OUTDIR_BASE=/outdir-base && codesigning_tarball_for_host "$HOST")" \
bash -c "cd /bitcoin && bash contrib/guix/libexec/codesign.sh"
)

View File

@@ -289,24 +289,6 @@ mkdir -p "$DISTSRC"
;;
esac
case "$HOST" in
*darwin*)
make deploydir ${V:+V=1}
mkdir -p "unsigned-app-${HOST}"
cp --target-directory="unsigned-app-${HOST}" \
contrib/macdeploy/detached-sig-create.sh
mv --target-directory="unsigned-app-${HOST}" dist
(
cd "unsigned-app-${HOST}"
find . -print0 \
| sort --zero-terminated \
| tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
| gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" && exit 1 )
)
make deploy ${V:+V=1} OSX_ZIP="${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip"
;;
esac
(
cd installed
@@ -339,7 +321,7 @@ mkdir -p "$DISTSRC"
cp -r "${DISTSRC}/share/rpcauth" "${DISTNAME}/share/"
# Finally, deterministically produce {non-,}debug binary tarballs ready
# Deterministically produce {non-,}debug binary tarballs ready
# for release
case "$HOST" in
*mingw*)
@@ -347,8 +329,8 @@ mkdir -p "$DISTSRC"
| xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
find "${DISTNAME}" -not -name "*.dbg" \
| sort \
| zip -X@ "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip" && exit 1 )
| zip -X@ "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}-unsigned.zip" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}-unsigned.zip" && exit 1 )
find "${DISTNAME}" -name "*.dbg" -print0 \
| xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
find "${DISTNAME}" -name "*.dbg" \
@@ -372,12 +354,13 @@ mkdir -p "$DISTSRC"
find "${DISTNAME}" -print0 \
| sort --zero-terminated \
| tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
| gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" && exit 1 )
| gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.tar.gz" && exit 1 )
;;
esac
) # $DISTSRC/installed
# Finally make tarballs for codesigning
case "$HOST" in
*mingw*)
cp -rf --target-directory=. contrib/windeploy
@@ -385,13 +368,33 @@ mkdir -p "$DISTSRC"
cd ./windeploy
mkdir -p unsigned
cp --target-directory=unsigned/ "${OUTDIR}/${DISTNAME}-win64-setup-unsigned.exe"
cp -r --target-directory=unsigned/ "${INSTALLPATH}"
find unsigned/ -name "*.dbg" -print0 \
| xargs -0r rm
find . -print0 \
| sort --zero-terminated \
| tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
| gzip -9n > "${OUTDIR}/${DISTNAME}-win64-unsigned.tar.gz" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-win64-unsigned.tar.gz" && exit 1 )
| gzip -9n > "${OUTDIR}/${DISTNAME}-win64-codesigning.tar.gz" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-win64-codesigning.tar.gz" && exit 1 )
)
;;
*darwin*)
make deploydir ${V:+V=1}
mkdir -p "unsigned-app-${HOST}"
cp --target-directory="unsigned-app-${HOST}" \
contrib/macdeploy/detached-sig-create.sh
mv --target-directory="unsigned-app-${HOST}" dist
cp -r --target-directory="unsigned-app-${HOST}" "${INSTALLPATH}"
(
cd "unsigned-app-${HOST}"
find . -print0 \
| sort --zero-terminated \
| tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
| gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}-codesigning.tar.gz" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}-codesigning.tar.gz" && exit 1 )
)
make deploy ${V:+V=1} OSX_ZIP="${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip"
;;
esac
) # $DISTSRC

View File

@@ -4,6 +4,9 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C
set -e -o pipefail
# Environment variables for determinism
export TAR_OPTIONS="--owner=0 --group=0 --numeric-owner --mtime='@${SOURCE_DATE_EPOCH}' --sort=name"
export TZ=UTC
# Although Guix _does_ set umask when building its own packages (in our case,
@@ -27,7 +30,7 @@ fi
# Check that required environment variables are set
cat << EOF
Required environment variables as seen inside the container:
UNSIGNED_TARBALL: ${UNSIGNED_TARBALL:?not set}
CODESIGNING_TARBALL: ${CODESIGNING_TARBALL:?not set}
DETACHED_SIGS_REPO: ${DETACHED_SIGS_REPO:?not set}
DIST_ARCHIVE_BASE: ${DIST_ARCHIVE_BASE:?not set}
DISTNAME: ${DISTNAME:?not set}
@@ -63,27 +66,54 @@ mkdir -p "$DISTSRC"
(
cd "$DISTSRC"
tar -xf "$UNSIGNED_TARBALL"
tar -xf "$CODESIGNING_TARBALL"
mkdir -p codesignatures
tar -C codesignatures -xf "$CODESIGNATURE_GIT_ARCHIVE"
case "$HOST" in
*mingw*)
find "$PWD" -name "*-unsigned.exe" | while read -r infile; do
infile_base="$(basename "$infile")"
# Codesigned *-unsigned.exe and output to OUTDIR
# Apply detached codesignatures
WORKDIR=".tmp"
mkdir -p ${WORKDIR}
cp -r --target-directory="${WORKDIR}" "unsigned/${DISTNAME}"
find "${WORKDIR}/${DISTNAME}" -name "*.exe" -type f -exec rm {} \;
find unsigned/ -name "*.exe" -type f | while read -r bin
do
bin_base="$(realpath --relative-to=unsigned/ "${bin}")"
mkdir -p "${WORKDIR}/$(dirname "${bin_base}")"
osslsigncode attach-signature \
-in "$infile" \
-out "${OUTDIR}/${infile_base/-unsigned}" \
-in "${bin}" \
-out "${WORKDIR}/${bin_base/-unsigned}" \
-CAfile "$GUIX_ENVIRONMENT/etc/ssl/certs/ca-certificates.crt" \
-sigin codesignatures/win/"$infile_base".pem
-sigin codesignatures/win/"${bin_base}".pem
done
# Move installer to outdir
cd "${WORKDIR}"
find . -name "*setup.exe" -print0 \
| xargs -0r mv --target-directory="${OUTDIR}"
# Make .zip from binaries
find "${DISTNAME}" -print0 \
| xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
find "${DISTNAME}" \
| sort \
| zip -X@ "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST//x86_64-w64-mingw32/win64}.zip" && exit 1 )
;;
*darwin*)
# Apply detached codesignatures to dist/ (in-place)
signapple apply dist/Bitcoin-Qt.app codesignatures/osx/dist
case "$HOST" in
arm64*) ARCH="arm64" ;;
x86_64*) ARCH="x86_64" ;;
esac
# Apply detached codesignatures (in-place)
signapple apply dist/Bitcoin-Qt.app codesignatures/osx/"${HOST}"/dist/Bitcoin-Qt.app
find "${DISTNAME}" -wholename "*/bin/*" -type f | while read -r bin
do
signapple apply "${bin}" "codesignatures/osx/${HOST}/${bin}.${ARCH}sign"
done
# Make a .zip from dist/
cd dist/
@@ -91,6 +121,14 @@ mkdir -p "$DISTSRC"
| xargs -0r touch --no-dereference --date="@${SOURCE_DATE_EPOCH}"
find . | sort \
| zip -X@ "${OUTDIR}/${DISTNAME}-${HOST}.zip"
cd ..
# Make a .tar.gz from bins
find "${DISTNAME}" -print0 \
| sort --zero-terminated \
| tar --create --no-recursion --mode='u+rw,go+r-w,a+X' --null --files-from=- \
| gzip -9n > "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" \
|| ( rm -f "${OUTDIR}/${DISTNAME}-${HOST}.tar.gz" && exit 1 )
;;
*)
exit 1
@@ -105,7 +143,7 @@ mv --no-target-directory "$OUTDIR" "$ACTUAL_OUTDIR" \
(
cd /outdir-base
{
echo "$UNSIGNED_TARBALL"
echo "$CODESIGNING_TARBALL"
echo "$CODESIGNATURE_GIT_ARCHIVE"
find "$ACTUAL_OUTDIR" -type f
} | xargs realpath --relative-base="$PWD" \

View File

@@ -21,6 +21,26 @@ check_tools() {
done
}
################
# SOURCE_DATE_EPOCH should not unintentionally be set
################
check_source_date_epoch() {
if [ -n "$SOURCE_DATE_EPOCH" ] && [ -z "$FORCE_SOURCE_DATE_EPOCH" ]; then
cat << EOF
ERR: Environment variable SOURCE_DATE_EPOCH is set which may break reproducibility.
Aborting...
Hint: You may want to:
1. Unset this variable: \`unset SOURCE_DATE_EPOCH\` before rebuilding
2. Set the 'FORCE_SOURCE_DATE_EPOCH' environment variable if you insist on
using your own epoch
EOF
exit 1
fi
}
check_tools cat env readlink dirname basename git
################
@@ -50,7 +70,7 @@ fi
# across time.
time-machine() {
# shellcheck disable=SC2086
guix time-machine --url=https://git.savannah.gnu.org/git/guix.git \
guix time-machine --url=https://codeberg.org/guix/guix.git \
--commit=7bf1d7aeaffba15c4f680f93ae88fbef25427252 \
--cores="$JOBS" \
--keep-failed \

View File

@@ -17,13 +17,14 @@
(gnu packages moreutils)
(gnu packages pkg-config)
((gnu packages python) #:select (python-minimal))
((gnu packages python-build) #:select (python-tomli))
((gnu packages python-build) #:select (python-tomli python-poetry-core))
((gnu packages python-crypto) #:select (python-asn1crypto))
((gnu packages tls) #:select (openssl))
((gnu packages version-control) #:select (git-minimal))
(guix build-system cmake)
(guix build-system gnu)
(guix build-system python)
(guix build-system pyproject)
(guix build-system trivial)
(guix download)
(guix gexp)
@@ -393,10 +394,10 @@ specific moment in time, whitelisting and revocation checks.")
(license license:expat))))
(define-public python-signapple
(let ((commit "62155712e7417aba07565c9780a80e452823ae6a"))
(let ((commit "85bfcecc33d2773bc09bc318cec0614af2c8e287"))
(package
(name "python-signapple")
(version (git-version "0.1" "1" commit))
(version (git-version "0.2.0" "1" commit))
(source
(origin
(method git-fetch)
@@ -406,13 +407,14 @@ specific moment in time, whitelisting and revocation checks.")
(file-name (git-file-name name commit))
(sha256
(base32
"1nm6rm4h4m7kbq729si4cm8rzild62mk4ni8xr5zja7l33fhv3gb"))))
(build-system python-build-system)
"17yqjll8nw83q6dhgqhkl7w502z5vy9sln8m6mlx0f1c10isg8yg"))))
(build-system pyproject-build-system)
(propagated-inputs
(list python-asn1crypto
python-oscrypto
python-certvalidator
python-elfesteem))
(native-inputs (list python-poetry-core))
;; There are no tests, but attempting to run python setup.py test leads to
;; problems, just disable the test
(arguments '(#:tests? #f))

View File

@@ -6,26 +6,57 @@
export LC_ALL=C
set -e
ROOTDIR=dist
BUNDLE="${ROOTDIR}/Bitcoin-Qt.app"
BINARY="${BUNDLE}/Contents/MacOS/Bitcoin-Qt"
SIGNAPPLE=signapple
TEMPDIR=sign.temp
ARCH=$(${SIGNAPPLE} info ${BINARY} | head -n 1 | cut -d " " -f 1)
OUT="signature-osx-${ARCH}.tar.gz"
OUTROOT=osx/dist
if [ -z "$1" ]; then
echo "usage: $0 <signapple args>"
echo "example: $0 <path to key>"
BUNDLE_ROOT=dist
BUNDLE_NAME="Bitcoin-Qt.app"
UNSIGNED_BUNDLE="${BUNDLE_ROOT}/${BUNDLE_NAME}"
UNSIGNED_BINARY="${UNSIGNED_BUNDLE}/Contents/MacOS/Bitcoin-Qt"
ARCH=$(${SIGNAPPLE} info ${UNSIGNED_BINARY} | head -n 1 | cut -d " " -f 1)
OUTDIR="osx/${ARCH}-apple-darwin"
OUTROOT="${TEMPDIR}/${OUTDIR}"
OUT="signature-osx-${ARCH}.tar.gz"
if [ "$#" -ne 3 ]; then
echo "usage: $0 <path to key> <path to app store connect key> <apple developer team uuid>"
exit 1
fi
rm -rf ${TEMPDIR}
mkdir -p ${TEMPDIR}
${SIGNAPPLE} sign -f --detach "${TEMPDIR}/${OUTROOT}" "$@" "${BUNDLE}" --hardened-runtime
stty -echo
printf "Enter the passphrase for %s: " "$1"
read cs_key_pass
printf "\n"
printf "Enter the passphrase for %s: " "$2"
read api_key_pass
printf "\n"
stty echo
tar -C "${TEMPDIR}" -czf "${OUT}" .
# Sign and notarize app bundle
${SIGNAPPLE} sign -f --hardened-runtime --detach "${OUTROOT}/${BUNDLE_ROOT}" --passphrase "${cs_key_pass}" "$1" "${UNSIGNED_BUNDLE}"
${SIGNAPPLE} apply "${UNSIGNED_BUNDLE}" "${OUTROOT}/${BUNDLE_ROOT}/${BUNDLE_NAME}"
${SIGNAPPLE} notarize --detach "${OUTROOT}/${BUNDLE_ROOT}" --passphrase "${api_key_pass}" "$2" "$3" "${UNSIGNED_BUNDLE}"
# Sign each binary
find . -maxdepth 3 -wholename "*/bin/*" -type f -exec realpath --relative-to=. {} \; | while read -r bin
do
bin_dir=$(dirname "${bin}")
bin_name=$(basename "${bin}")
${SIGNAPPLE} sign -f --hardened-runtime --detach "${OUTROOT}/${bin_dir}" --passphrase "${cs_key_pass}" "$1" "${bin}"
${SIGNAPPLE} apply "${bin}" "${OUTROOT}/${bin_dir}/${bin_name}.${ARCH}sign"
done
# Notarize the binaries
# Binaries cannot have stapled notarizations so this does not actually generate any output
binaries_dir=$(dirname "$(find . -maxdepth 2 -wholename '*/bin' -type d -exec realpath --relative-to=. {} \;)")
${SIGNAPPLE} notarize --passphrase "${api_key_pass}" "$2" "$3" "${binaries_dir}"
tar -C "${TEMPDIR}" -czf "${OUT}" "${OUTDIR}"
rm -rf "${TEMPDIR}"
echo "Created ${OUT}"

View File

@@ -465,18 +465,18 @@ if config.translations_dir:
sys.stderr.write(f"Error: Could not find translation dir \"{config.translations_dir[0]}\"\n")
sys.exit(1)
print("+ Adding Qt translations +")
print("+ Adding Qt translations +")
translations = Path(config.translations_dir[0])
translations = Path(config.translations_dir[0])
regex = re.compile('qt_[a-z]*(.qm|_[A-Z]*.qm)')
regex = re.compile('qt_[a-z]*(.qm|_[A-Z]*.qm)')
lang_files = [x for x in translations.iterdir() if regex.match(x.name)]
lang_files = [x for x in translations.iterdir() if regex.match(x.name)]
for file in lang_files:
if verbose:
print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name))
shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name))
for file in lang_files:
if verbose:
print(file.as_posix(), "->", os.path.join(applicationBundle.resourcesPath, file.name))
shutil.copy2(file.as_posix(), os.path.join(applicationBundle.resourcesPath, file.name))
# ------------------------------------------------

View File

@@ -41,7 +41,8 @@ from bcc import BPF, USDT
program = """
#include <uapi/linux/ptrace.h>
#define MIN(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
// A min() macro. Prefixed with _TRACEPOINT_TEST to avoid collision with other MIN macros.
#define _TRACEPOINT_TEST_MIN(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
// Maximum possible allocation size
// from include/linux/percpu.h in the Linux kernel
@@ -88,7 +89,7 @@ int trace_inbound_message(struct pt_regs *ctx) {
bpf_usdt_readarg_p(3, ctx, &msg->peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH);
bpf_usdt_readarg_p(4, ctx, &msg->msg_type, MAX_MSG_TYPE_LENGTH);
bpf_usdt_readarg(5, ctx, &msg->msg_size);
bpf_usdt_readarg_p(6, ctx, &msg->msg, MIN(msg->msg_size, MAX_MSG_DATA_LENGTH));
bpf_usdt_readarg_p(6, ctx, &msg->msg, _TRACEPOINT_TEST_MIN(msg->msg_size, MAX_MSG_DATA_LENGTH));
inbound_messages.perf_submit(ctx, msg, sizeof(*msg));
return 0;
@@ -108,7 +109,7 @@ int trace_outbound_message(struct pt_regs *ctx) {
bpf_usdt_readarg_p(3, ctx, &msg->peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH);
bpf_usdt_readarg_p(4, ctx, &msg->msg_type, MAX_MSG_TYPE_LENGTH);
bpf_usdt_readarg(5, ctx, &msg->msg_size);
bpf_usdt_readarg_p(6, ctx, &msg->msg, MIN(msg->msg_size, MAX_MSG_DATA_LENGTH));
bpf_usdt_readarg_p(6, ctx, &msg->msg, _TRACEPOINT_TEST_MIN(msg->msg_size, MAX_MSG_DATA_LENGTH));
outbound_messages.perf_submit(ctx, msg, sizeof(*msg));
return 0;

View File

@@ -8,9 +8,9 @@ if [ -z "$OSSLSIGNCODE" ]; then
OSSLSIGNCODE=osslsigncode
fi
if [ -z "$1" ]; then
echo "usage: $0 <osslcodesign args>"
echo "example: $0 -key codesign.key"
if [ "$#" -ne 1 ]; then
echo "usage: $0 <path to key>"
echo "example: $0 codesign.key"
exit 1
fi
@@ -22,12 +22,22 @@ OUTSUBDIR="${OUTDIR}/win"
TIMESERVER=http://timestamp.comodoca.com
CERTFILE="win-codesign.cert"
stty -echo
printf "Enter the passphrase for %s: " "$1"
read cs_key_pass
printf "\n"
stty echo
mkdir -p "${OUTSUBDIR}"
# shellcheck disable=SC2046
basename -a $(ls -1 "${SRCDIR}"/*-unsigned.exe) | while read UNSIGNED; do
echo Signing "${UNSIGNED}"
"${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -h sha256 -in "${SRCDIR}/${UNSIGNED}" -out "${WORKDIR}/${UNSIGNED}" "$@"
"${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${UNSIGNED}" -out "${OUTSUBDIR}/${UNSIGNED}.pem" && rm "${WORKDIR}/${UNSIGNED}"
find ${SRCDIR} -wholename "*.exe" -type f -exec realpath --relative-to=. {} \; | while read -r bin
do
echo Signing "${bin}"
bin_base="$(realpath --relative-to=${SRCDIR} "${bin}")"
mkdir -p "$(dirname ${WORKDIR}/"${bin_base}")"
"${OSSLSIGNCODE}" sign -certs "${CERTFILE}" -t "${TIMESERVER}" -h sha256 -in "${bin}" -out "${WORKDIR}/${bin_base}" -key "$1" -pass "${cs_key_pass}"
mkdir -p "$(dirname ${OUTSUBDIR}/"${bin_base}")"
"${OSSLSIGNCODE}" extract-signature -pem -in "${WORKDIR}/${bin_base}" -out "${OUTSUBDIR}/${bin_base}.pem" && rm "${WORKDIR}/${bin_base}"
done
rm -f "${OUT}"

View File

@@ -143,7 +143,7 @@ include packages/packages.mk
# 2. Before including packages/*.mk (excluding packages/packages.mk), since
# they rely on the build_id variables
#
build_id:=$(shell env CC='$(build_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(build_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(build_AR) 'NM='$(build_NM)' RANLIB='$(build_RANLIB)' STRIP='$(build_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' NO_HARDEN='$(NO_HARDEN)' ./gen_id '$(BUILD_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))')
build_id:=$(shell env CC='$(build_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(build_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(build_AR)' NM='$(build_NM)' RANLIB='$(build_RANLIB)' STRIP='$(build_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' NO_HARDEN='$(NO_HARDEN)' ./gen_id '$(BUILD_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))')
$(host_arch)_$(host_os)_id:=$(shell env CC='$(host_CC)' C_STANDARD='$(C_STANDARD)' CXX='$(host_CXX)' CXX_STANDARD='$(CXX_STANDARD)' AR='$(host_AR)' NM='$(host_NM)' RANLIB='$(host_RANLIB)' STRIP='$(host_STRIP)' SHA256SUM='$(build_SHA256SUM)' DEBUG='$(DEBUG)' LTO='$(LTO)' NO_HARDEN='$(NO_HARDEN)' ./gen_id '$(HOST_ID_SALT)' 'GUIX_ENVIRONMENT=$(realpath $(GUIX_ENVIRONMENT))')
boost_packages_$(NO_BOOST) = $(boost_packages)

View File

@@ -186,6 +186,7 @@ $(1)_cmake=env CC="$$($(1)_cc)" \
-DCMAKE_INSTALL_LIBDIR=lib/ \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DCMAKE_VERBOSE_MAKEFILE:BOOL=$(V) \
-DCMAKE_EXPORT_NO_PACKAGE_REGISTRY:BOOL=TRUE \
$$($(1)_config_opts)
ifeq ($($(1)_type),build)
$(1)_cmake += -DCMAKE_INSTALL_RPATH:PATH="$$($($(1)_type)_prefix)/lib"

View File

@@ -5,7 +5,7 @@ $(package)_download_file=$(native_$(package)_download_file)
$(package)_file_name=$(native_$(package)_file_name)
$(package)_sha256_hash=$(native_$(package)_sha256_hash)
define $(package)_set_vars :=
define $(package)_set_vars
$(package)_config_opts := -DBUILD_TESTING=OFF
$(package)_config_opts += -DWITH_OPENSSL=OFF
$(package)_config_opts += -DWITH_ZLIB=OFF

View File

@@ -4,6 +4,7 @@ $(package)_download_path=https://download.savannah.gnu.org/releases/$(package)
$(package)_file_name=$(package)-$($(package)_version).tar.xz
$(package)_sha256_hash=8bee39bd3968c4804b70614a0a3ad597299ad0e824bc8aad5ce8aaf48067bde7
$(package)_build_subdir=build
$(package)_patches += cmake_minimum.patch
define $(package)_set_vars
$(package)_config_opts := -DCMAKE_BUILD_TYPE=None -DBUILD_SHARED_LIBS=TRUE
@@ -12,6 +13,10 @@ define $(package)_set_vars
$(package)_config_opts += -DCMAKE_DISABLE_FIND_PACKAGE_BrotliDec=TRUE
endef
define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/cmake_minimum.patch
endef
define $(package)_config_cmds
$($(package)_cmake) -S .. -B .
endef

View File

@@ -5,6 +5,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb
$(package)_patches=cmake_fixups.patch
$(package)_patches+=fix_mingw_link.patch
$(package)_patches += netbsd_fixup.patch
$(package)_build_subdir=build
# When building for Windows, we set _WIN32_WINNT to target the same Windows
@@ -24,7 +25,8 @@ endef
define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/cmake_fixups.patch && \
patch -p1 < $($(package)_patch_dir)/fix_mingw_link.patch
patch -p1 < $($(package)_patch_dir)/fix_mingw_link.patch && \
patch -p1 < $($(package)_patch_dir)/netbsd_fixup.patch
endef
define $(package)_config_cmds

View File

@@ -8,7 +8,7 @@ ifneq ($(host),$(build))
$(package)_dependencies += native_capnp
endif
define $(package)_set_vars :=
define $(package)_set_vars
ifneq ($(host),$(build))
$(package)_config_opts := -DCAPNP_EXECUTABLE="$$(native_capnp_prefixbin)/capnp"
$(package)_config_opts += -DCAPNPC_CXX_EXECUTABLE="$$(native_capnp_prefixbin)/capnpc-c++"

View File

@@ -1,6 +1,6 @@
package=qt
$(package)_version=5.15.14
$(package)_download_path=https://download.qt.io/official_releases/qt/5.15/$($(package)_version)/submodules
$(package)_download_path=https://download.qt.io/archive/qt/5.15/$($(package)_version)/submodules
$(package)_suffix=everywhere-opensource-src-$($(package)_version).tar.xz
$(package)_file_name=qtbase-$($(package)_suffix)
$(package)_sha256_hash=500d3b390048e9538c28b5f523dfea6936f9c2e10d24ab46580ff57d430b98be

View File

@@ -21,6 +21,8 @@ define $(package)_build_cmds
$(MAKE)
endef
# mkdir detection is broken on Alpine. Set MKDIRPROG to ensure we always
# use "mkdir -p", and avoid parallelism issues during install.
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
$(MAKE) MKDIRPROG="mkdir -p" DESTDIR=$($(package)_staging_dir) install
endef

View File

@@ -0,0 +1,13 @@
build: set minimum required CMake to 3.12
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -97,7 +97,7 @@
# FreeType explicitly marks the API to be exported and relies on the compiler
# to hide all other symbols. CMake supports a C_VISBILITY_PRESET property
# starting with 2.8.12.
-cmake_minimum_required(VERSION 2.8.12)
+cmake_minimum_required(VERSION 3.12)
if (NOT CMAKE_VERSION VERSION_LESS 3.3)
# Allow symbol visibility settings also on static libraries. CMake < 3.3

View File

@@ -0,0 +1,23 @@
Improve portability on NetBSD
According to GCC documentation, "the various `-std` options disable
certain keywords".
This change adheres to GCC's recommendation by replacing the `typeof`
keyword with its alternative, `__typeof__`.
See https://github.com/libevent/libevent/commit/1759485e9a59147a47a674f5132fcfe764e7748c.
--- a/kqueue.c
+++ b/kqueue.c
@@ -52,8 +52,8 @@
* intptr_t, whereas others define it as void*. There doesn't seem to be an
* easy way to tell them apart via autoconf, so we need to use OS macros. */
#if defined(__NetBSD__)
-#define PTR_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(x))
-#define INT_TO_UDATA(x) ((typeof(((struct kevent *)0)->udata))(intptr_t)(x))
+#define PTR_TO_UDATA(x) ((__typeof__(((struct kevent *)0)->udata))(x))
+#define INT_TO_UDATA(x) ((__typeof__(((struct kevent *)0)->udata))(intptr_t)(x))
#elif defined(EVENT__HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__) && !defined(__CloudABI__)
#define PTR_TO_UDATA(x) ((intptr_t)(x))
#define INT_TO_UDATA(x) ((intptr_t)(x))

View File

@@ -59,7 +59,8 @@ BIPs that are implemented by Bitcoin Core:
Validation rules for Taproot (including Schnorr signatures and Tapscript
leaves) are implemented as of **v0.21.0** ([PR 19953](https://github.com/bitcoin/bitcoin/pull/19953)),
with mainnet activation as of **v0.21.1** ([PR 21377](https://github.com/bitcoin/bitcoin/pull/21377),
[PR 21686](https://github.com/bitcoin/bitcoin/pull/21686)).
[PR 21686](https://github.com/bitcoin/bitcoin/pull/21686)),
always active as of **v24.0** ([PR 23536](https://github.com/bitcoin/bitcoin/pull/23536)).
* [`BIP 350`](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki): Addresses for native v1+ segregated Witness outputs use Bech32m instead of Bech32 as of **v22.0** ([PR 20861](https://github.com/bitcoin/bitcoin/pull/20861)).
* [`BIP 371`](https://github.com/bitcoin/bips/blob/master/bip-0371.mediawiki): Taproot fields for PSBT as of **v24.0** ([PR 22558](https://github.com/bitcoin/bitcoin/pull/22558)).
* [`BIP 379`](https://github.com/bitcoin/bips/blob/master/bip-0379.md): Miniscript was partially implemented in **v24.0** ([PR 24148](https://github.com/bitcoin/bitcoin/pull/24148)), and fully implemented as of **v26.0** ([PR 27255](https://github.com/bitcoin/bitcoin/pull/27255)).

View File

@@ -30,7 +30,7 @@ You can find installation instructions in the `build-*.md` file for your platfor
| [Fontconfig](../depends/packages/fontconfig.mk) | [link](https://www.freedesktop.org/wiki/Software/fontconfig/) | [2.12.6](https://github.com/bitcoin/bitcoin/pull/23495) | 2.6 | Yes |
| [FreeType](../depends/packages/freetype.mk) | [link](https://freetype.org) | [2.11.0](https://github.com/bitcoin/bitcoin/commit/01544dd78ccc0b0474571da854e27adef97137fb) | 2.3.0 | Yes |
| [qrencode](../depends/packages/qrencode.mk) | [link](https://fukuchi.org/works/qrencode/) | [4.1.1](https://github.com/bitcoin/bitcoin/pull/27312) | | No |
| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/official_releases/qt/) | [5.15.14](https://github.com/bitcoin/bitcoin/pull/30198) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No |
| [Qt](../depends/packages/qt.mk) | [link](https://download.qt.io/archive/qt/) | [5.15.14](https://github.com/bitcoin/bitcoin/pull/30198) | [5.11.3](https://github.com/bitcoin/bitcoin/pull/24132) | No |
### Networking
| Dependency | Releases | Version used | Minimum required | Runtime |

View File

@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-CLI "1" "December 2024" "bitcoin-cli v28.1.0" "User Commands"
.TH BITCOIN-CLI "1" "October 2025" "bitcoin-cli v28.3.0rc2" "User Commands"
.SH NAME
bitcoin-cli \- manual page for bitcoin-cli v28.1.0
bitcoin-cli \- manual page for bitcoin-cli v28.3.0rc2
.SH SYNOPSIS
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,<command> \/\fR[\fI\,params\/\fR] \fI\,Send command to Bitcoin Core\/\fR
@@ -15,7 +15,7 @@ bitcoin-cli \- manual page for bitcoin-cli v28.1.0
.B bitcoin-cli
[\fI\,options\/\fR] \fI\,help <command> Get help for a command\/\fR
.SH DESCRIPTION
Bitcoin Core RPC client version v28.1.0
Bitcoin Core RPC client version v28.3.0rc2
.SH OPTIONS
.HP
\-?
@@ -176,7 +176,7 @@ Consider moving to testnet4 now by using \fB\-testnet4\fR.
.IP
Use the testnet4 chain. Equivalent to \fB\-chain\fR=\fI\,testnet4\/\fR.
.SH COPYRIGHT
Copyright (C) 2009-2024 The Bitcoin Core developers
Copyright (C) 2009-2025 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org/> for further information about the software.

View File

@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-QT "1" "December 2024" "bitcoin-qt v28.1.0" "User Commands"
.TH BITCOIN-QT "1" "October 2025" "bitcoin-qt v28.3.0rc2" "User Commands"
.SH NAME
bitcoin-qt \- manual page for bitcoin-qt v28.1.0
bitcoin-qt \- manual page for bitcoin-qt v28.3.0rc2
.SH SYNOPSIS
.B bitcoin-qt
[\fI\,command-line options\/\fR] [\fI\,URI\/\fR]
.SH DESCRIPTION
Bitcoin Core version v28.1.0
Bitcoin Core version v28.3.0rc2
.PP
Optional URI is a Bitcoin address in BIP21 URI format.
.SH OPTIONS
@@ -705,7 +705,7 @@ replaceability signaling (default: 1)
\fB\-minrelaytxfee=\fR<amt>
.IP
Fees (in BTC/kvB) smaller than this are considered zero fee for
relaying, mining and transaction creation (default: 0.00001)
relaying, mining and transaction creation (default: 0.000001)
.HP
\fB\-permitbaremultisig\fR
.IP
@@ -732,7 +732,7 @@ Set maximum BIP141 block weight (default: 3996000)
\fB\-blockmintxfee=\fR<amt>
.IP
Set lowest fee rate (in BTC/kvB) for transactions to be included in
block creation. (default: 0.00001)
block creation. (default: 0.00000001)
.PP
RPC server options:
.HP
@@ -836,7 +836,7 @@ Reset all settings changed in the GUI
.IP
Show splash screen on startup (default: 1)
.SH COPYRIGHT
Copyright (C) 2009-2024 The Bitcoin Core developers
Copyright (C) 2009-2025 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org/> for further information about the software.

View File

@@ -1,7 +1,7 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-TX "1" "December 2024" "bitcoin-tx v28.1.0" "User Commands"
.TH BITCOIN-TX "1" "October 2025" "bitcoin-tx v28.3.0rc2" "User Commands"
.SH NAME
bitcoin-tx \- manual page for bitcoin-tx v28.1.0
bitcoin-tx \- manual page for bitcoin-tx v28.3.0rc2
.SH SYNOPSIS
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,<hex-tx> \/\fR[\fI\,commands\/\fR] \fI\,Update hex-encoded bitcoin transaction\/\fR
@@ -9,7 +9,7 @@ bitcoin-tx \- manual page for bitcoin-tx v28.1.0
.B bitcoin-tx
[\fI\,options\/\fR] \fI\,-create \/\fR[\fI\,commands\/\fR] \fI\,Create hex-encoded bitcoin transaction\/\fR
.SH DESCRIPTION
Bitcoin Core bitcoin\-tx utility version v28.1.0
Bitcoin Core bitcoin\-tx utility version v28.3.0rc2
.SH OPTIONS
.HP
\-?
@@ -142,7 +142,7 @@ set=NAME:JSON\-STRING
.IP
Set register NAME to given JSON\-STRING
.SH COPYRIGHT
Copyright (C) 2009-2024 The Bitcoin Core developers
Copyright (C) 2009-2025 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org/> for further information about the software.

View File

@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-UTIL "1" "December 2024" "bitcoin-util v28.1.0" "User Commands"
.TH BITCOIN-UTIL "1" "October 2025" "bitcoin-util v28.3.0rc2" "User Commands"
.SH NAME
bitcoin-util \- manual page for bitcoin-util v28.1.0
bitcoin-util \- manual page for bitcoin-util v28.3.0rc2
.SH SYNOPSIS
.B bitcoin-util
[\fI\,options\/\fR] [\fI\,commands\/\fR] \fI\,Do stuff\/\fR
.SH DESCRIPTION
Bitcoin Core bitcoin\-util utility version v28.1.0
Bitcoin Core bitcoin\-util utility version v28.3.0rc2
.SH OPTIONS
.HP
\-?
@@ -60,7 +60,7 @@ grind
.IP
Perform proof of work on hex header string
.SH COPYRIGHT
Copyright (C) 2009-2024 The Bitcoin Core developers
Copyright (C) 2009-2025 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org/> for further information about the software.

View File

@@ -1,9 +1,9 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIN-WALLET "1" "December 2024" "bitcoin-wallet v28.1.0" "User Commands"
.TH BITCOIN-WALLET "1" "October 2025" "bitcoin-wallet v28.3.0rc2" "User Commands"
.SH NAME
bitcoin-wallet \- manual page for bitcoin-wallet v28.1.0
bitcoin-wallet \- manual page for bitcoin-wallet v28.3.0rc2
.SH DESCRIPTION
Bitcoin Core bitcoin\-wallet version v28.1.0
Bitcoin Core bitcoin\-wallet version v28.3.0rc2
.PP
bitcoin\-wallet is an offline tool for creating and interacting with Bitcoin Core wallet files.
By default bitcoin\-wallet will act on wallets in the default mainnet wallet directory in the datadir.
@@ -121,7 +121,7 @@ salvage
Attempt to recover private keys from a corrupt wallet. Warning:
\&'salvage' is experimental.
.SH COPYRIGHT
Copyright (C) 2009-2024 The Bitcoin Core developers
Copyright (C) 2009-2025 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org/> for further information about the software.

View File

@@ -1,12 +1,12 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH BITCOIND "1" "December 2024" "bitcoind v28.1.0" "User Commands"
.TH BITCOIND "1" "October 2025" "bitcoind v28.3.0rc2" "User Commands"
.SH NAME
bitcoind \- manual page for bitcoind v28.1.0
bitcoind \- manual page for bitcoind v28.3.0rc2
.SH SYNOPSIS
.B bitcoind
[\fI\,options\/\fR] \fI\,Start Bitcoin Core\/\fR
.SH DESCRIPTION
Bitcoin Core version v28.1.0
Bitcoin Core version v28.3.0rc2
.SH OPTIONS
.HP
\-?
@@ -703,7 +703,7 @@ replaceability signaling (default: 1)
\fB\-minrelaytxfee=\fR<amt>
.IP
Fees (in BTC/kvB) smaller than this are considered zero fee for
relaying, mining and transaction creation (default: 0.00001)
relaying, mining and transaction creation (default: 0.000001)
.HP
\fB\-permitbaremultisig\fR
.IP
@@ -730,7 +730,7 @@ Set maximum BIP141 block weight (default: 3996000)
\fB\-blockmintxfee=\fR<amt>
.IP
Set lowest fee rate (in BTC/kvB) for transactions to be included in
block creation. (default: 0.00001)
block creation. (default: 0.00000001)
.PP
RPC server options:
.HP
@@ -812,7 +812,7 @@ subject to empty whitelists.
.IP
Accept command line and JSON\-RPC commands
.SH COPYRIGHT
Copyright (C) 2009-2024 The Bitcoin Core developers
Copyright (C) 2009-2025 The Bitcoin Core developers
Please contribute if you find Bitcoin Core useful. Visit
<https://bitcoincore.org/> for further information about the software.

View File

@@ -1,8 +1,8 @@
Bitcoin Core version 28.1 is now available from:
Bitcoin Core version 28.3rc2 is now available from:
<https://bitcoincore.org/bin/bitcoin-core-28.1>
<https://bitcoincore.org/bin/bitcoin-core-28.3/test.rc2/>
This release includes new features, various bug fixes and performance
This release includes various bug fixes and performance
improvements, as well as updated translations.
Please report bugs using the issue tracker at GitHub:
@@ -25,13 +25,6 @@ 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.
Running Bitcoin Core binaries on macOS requires self signing.
```
cd /path/to/bitcoin-28.x/bin
xattr -d com.apple.quarantine bitcoin-cli bitcoin-qt bitcoin-tx bitcoin-util bitcoin-wallet bitcoind test_bitcoin
codesign -s - bitcoin-cli bitcoin-qt bitcoin-tx bitcoin-util bitcoin-wallet bitcoind test_bitcoin
```
Compatibility
==============
@@ -44,64 +37,72 @@ unsupported systems.
Notable changes
===============
### Mempool & Policy
The minimum block feerate (`-blockmintxfee`) has been changed to 1 satoshi per kvB. It can still be changed using the
configuration option.
- The default minimum relay feerate (`-minrelaytxfee`) and incremental relay feerate (`-incrementalrelayfee`) have been
changed to 100 satoshis per kvB. They can still be changed using their respective configuration options, but it is
recommended to change both together if you decide to do so.
- Other minimum feerates (e.g. the dust feerate, the minimum returned by the fee estimator, and all feerates used by
the wallet) remain unchanged. The mempool minimum feerate still changes in response to high volume.
- Note that unless these lower defaults are widely adopted across the network, transactions created with lower fee
rates are not guaranteed to propagate or confirm. The wallet feerates remain unchanged; `-mintxfee` must be changed
before attempting to create transactions with lower feerates using the wallet.
- #33106 policy: lower the default blockmintxfee, incrementalrelayfee, minrelaytxfee
- #33504 mempool: Do not enforce TRUC checks on reorg
### P2P
- When the `-port` configuration option is used, the default onion listening port will now
be derived to be that port + 1 instead of being set to a fixed value (8334 on mainnet).
This re-allows setups with multiple local nodes using different `-port` and not using `-bind`,
which would lead to a startup failure in v28.0 due to a port collision.
Note that a `HiddenServicePort` manually configured in `torrc` may need adjustment if used in
connection with the `-port` option.
For example, if you are using `-port=5555` with a non-standard value and not using `-bind=...=onion`,
previously Bitcoin Core would listen for incoming Tor connections on `127.0.0.1:8334`.
Now it would listen on `127.0.0.1:5556` (`-port` plus one). If you configured the hidden service manually
in torrc now you have to change it from `HiddenServicePort 8333 127.0.0.1:8334` to `HiddenServicePort 8333
127.0.0.1:5556`, or configure bitcoind with `-bind=127.0.0.1:8334=onion` to get the previous behavior.
(#31223)
- #30568 addrman: change internal id counting to int64_t
### Key
- #31166 key: clear out secret data in DecodeExtKey
### Build
- #31013 depends: For mingw cross compile use `-gcc-posix` to prevent library conflict
- #31502 depends: Fix CXXFLAGS on NetBSD
- #33395 net: do not apply whitelist permissions to onion inbounds
### Test
- #31016 test: add missing sync to feature_fee_estimation.py
- #31448 fuzz: add cstdlib to FuzzedDataProvider
- #31419 test: fix MIN macro redefinition
- #31563 rpc: Extend scope of validation mutex in generateblock
- #32765 test: Fix list index out of range error in feature_bip68_sequence.py
- #33001 test: Do not pass tests on unhandled exceptions
- #30125 test: improve BDB parser (handle internal/overflow pages, support all page sizes)
- #30948 test: Add missing sync_mempools() to fill_mempool()
- #30784 test: add BulkTransaction helper to unit test transaction utils
### Build
- #32678 guix: warn and abort when SOURCE_DATE_EPOCH is set
- #32943 depends: Force CMAKE_EXPORT_NO_PACKAGE_REGISTRY=TRUE
- #33073 guix: warn SOURCE_DATE_EPOCH set in guix-codesign
- #33563 build: fix depends Qt download link
### Doc
- #31007 doc: add testnet4 section header for config file
### CI
- #30961 ci: add LLVM_SYMBOLIZER_PATH to Valgrind fuzz job
- #32776 doc: taproot became always active in v24.0
- #32777 doc: fix Transifex 404s
- #33070 doc/zmq: fix unix socket path example
- #33133 rpc: fix getpeerinfo ping duration unit docs
- #33236 doc: Remove wrong and redundant doxygen tag
### Misc
- #31267 refactor: Drop deprecated space in `operator""_mst`
- #31431 util: use explicit cast in MultiIntBitSet::Fill()
- #33340 Fix benchmark CSV output
- #33482 contrib: fix macOS deployment with no translations
Credits
=======
Thanks to everyone who directly contributed to this release:
- 0xB10C
- amisha
- fanquake
- glozow
- Hennadii Stepanov
- laanwj
- MarcoFalke
- Martin Zumsande
- Marnix
- Sebastian Falbesoner
Thanks to everyone who directly contributed to this release:
- romanz
- Sjors Provoost
- theStack
- Vasil Dimov
- willcl-ark
- zaidmstrr
As well as to everyone that helped with translations on
[Transifex](https://www.transifex.com/bitcoin/bitcoin/).
[Transifex](https://explore.transifex.com/bitcoin/bitcoin/).

View File

@@ -55,10 +55,10 @@ Release Process
- Clear the release notes and move them to the wiki (see "Write the release notes" below).
- Translations on Transifex:
- Pull translations from Transifex into the master branch.
- Create [a new resource](https://www.transifex.com/bitcoin/bitcoin/content/) named after the major version with the slug `qt-translation-<RRR>x`, where `RRR` is the major branch number padded with zeros. Use `src/qt/locale/bitcoin_en.xlf` to create it.
- Create [a new resource](https://app.transifex.com/bitcoin/bitcoin/content/) named after the major version with the slug `qt-translation-<RRR>x`, where `RRR` is the major branch number padded with zeros. Use `src/qt/locale/bitcoin_en.xlf` to create it.
- In the project workflow settings, ensure that [Translation Memory Fill-up](https://help.transifex.com/en/articles/6224817-setting-up-translation-memory-fill-up) is enabled and that [Translation Memory Context Matching](https://help.transifex.com/en/articles/6224753-translation-memory-with-context) is disabled.
- Update the Transifex slug in [`.tx/config`](/.tx/config) to the slug of the resource created in the first step. This identifies which resource the translations will be synchronized from.
- Make an announcement that translators can start translating for the new version. You can use one of the [previous announcements](https://www.transifex.com/bitcoin/communication/) as a template.
- Make an announcement that translators can start translating for the new version. You can use one of the [previous announcements](https://app.transifex.com/bitcoin/communication/) as a template.
- Change the auto-update URL for the resource to `master`, e.g. `https://raw.githubusercontent.com/bitcoin/bitcoin/master/src/qt/locale/bitcoin_en.xlf`. (Do this only after the previous steps, to prevent an auto-update from interfering.)
#### After branch-off (on the major release branch)
@@ -164,8 +164,8 @@ Then open a Pull Request to the [guix.sigs repository](https://github.com/bitcoi
In the `guix-build-${VERSION}/output/x86_64-apple-darwin` and `guix-build-${VERSION}/output/arm64-apple-darwin` directories:
tar xf bitcoin-osx-unsigned.tar.gz
./detached-sig-create.sh /path/to/codesign.p12
tar xf bitcoin-${VERSION}-${ARCH}-apple-darwin-codesigning.tar.gz
./detached-sig-create.sh /path/to/codesign.p12 /path/to/AuthKey_foo.p8 uuid
Enter the keychain password and authorize the signature
signature-osx.tar.gz will be created
@@ -173,8 +173,8 @@ In the `guix-build-${VERSION}/output/x86_64-apple-darwin` and `guix-build-${VERS
In the `guix-build-${VERSION}/output/x86_64-w64-mingw32` directory:
tar xf bitcoin-win-unsigned.tar.gz
./detached-sig-create.sh -key /path/to/codesign.key
tar xf bitcoin-${VERSION}-win64-codesigning.tar.gz
./detached-sig-create.sh /path/to/codesign.key
Enter the passphrase for the key when prompted
signature-win.tar.gz will be created

View File

@@ -41,7 +41,7 @@ git commit
### Creating a Transifex account
Visit the [Transifex Signup](https://www.transifex.com/signup/) page to create an account. Take note of your username and password, as they will be required to configure the command-line tool.
You can find the Bitcoin translation project at [https://www.transifex.com/bitcoin/bitcoin/](https://www.transifex.com/bitcoin/bitcoin/).
You can find the Bitcoin translation project at [https://explore.transifex.com/bitcoin/bitcoin/](https://explore.transifex.com/bitcoin/bitcoin/).
### Installing the Transifex client command-line tool
The client is used to fetch updated translations. Please check installation instructions and any other details at https://developers.transifex.com/docs/cli.

View File

@@ -85,7 +85,7 @@ For instance:
$ bitcoind -zmqpubhashtx=tcp://127.0.0.1:28332 \
-zmqpubhashtx=tcp://192.168.1.2:28332 \
-zmqpubhashblock="tcp://[::1]:28333" \
-zmqpubrawtx=ipc:///tmp/bitcoind.tx.raw \
-zmqpubrawtx=unix:/tmp/bitcoind.tx.raw \
-zmqpubhashtxhwm=10000
Each PUB notification has a topic and body, where the header

View File

@@ -591,7 +591,7 @@
#mempoolfullrbf=1
# Fees (in BTC/kvB) smaller than this are considered zero fee for
# relaying, mining and transaction creation (default: 0.00001)
# relaying, mining and transaction creation (default: 0.000001)
#minrelaytxfee=<amt>
# Relay transactions creating non-P2SH multisig outputs (default: 1)
@@ -615,7 +615,7 @@
#blockmaxweight=<n>
# Set lowest fee rate (in BTC/kvB) for transactions to be included in
# block creation. (default: 0.00001)
# block creation. (default: 0.00000001)
#blockmintxfee=<amt>

View File

@@ -627,7 +627,7 @@ std::string SHA256AutoDetect(sha256_implementation::UseImplementation use_implem
Transform = sha256_x86_shani::Transform;
TransformD64 = TransformD64Wrapper<sha256_x86_shani::Transform>;
TransformD64_2way = sha256d64_x86_shani::Transform_2way;
ret = "x86_shani(1way,2way)";
ret = "x86_shani(1way;2way)";
have_sse4 = false; // Disable SSE4/AVX2;
have_avx2 = false;
}
@@ -641,14 +641,14 @@ std::string SHA256AutoDetect(sha256_implementation::UseImplementation use_implem
#endif
#if defined(ENABLE_SSE41)
TransformD64_4way = sha256d64_sse41::Transform_4way;
ret += ",sse41(4way)";
ret += ";sse41(4way)";
#endif
}
#if defined(ENABLE_AVX2)
if (have_avx2 && have_avx && enabled_avx) {
TransformD64_8way = sha256d64_avx2::Transform_8way;
ret += ",avx2(8way)";
ret += ";avx2(8way)";
}
#endif
#endif // defined(HAVE_GETCPUID)
@@ -682,7 +682,7 @@ std::string SHA256AutoDetect(sha256_implementation::UseImplementation use_implem
Transform = sha256_arm_shani::Transform;
TransformD64 = TransformD64Wrapper<sha256_arm_shani::Transform>;
TransformD64_2way = sha256d64_arm_shani::Transform_2way;
ret = "arm_shani(1way,2way)";
ret = "arm_shani(1way;2way)";
}
#endif
#endif // DISABLE_OPTIMIZED_SHA256

View File

@@ -557,9 +557,9 @@ void CNode::CloseSocketDisconnect()
m_i2p_sam_session.reset();
}
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr, const std::vector<NetWhitelistPermissions>& ranges) const {
void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr, const std::vector<NetWhitelistPermissions>& ranges) const {
for (const auto& subnet : ranges) {
if (subnet.m_subnet.Match(addr)) {
if (addr.has_value() && subnet.m_subnet.Match(addr.value())) {
NetPermissions::AddFlag(flags, subnet.m_flags);
}
}
@@ -1731,7 +1731,11 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
{
int nInbound = 0;
AddWhitelistPermissionFlags(permission_flags, addr, vWhitelistedRangeIncoming);
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
// Tor inbound connections do not reveal the peer's actual network address.
// Therefore do not apply address-based whitelist permissions to them.
AddWhitelistPermissionFlags(permission_flags, inbound_onion ? std::optional<CNetAddr>{} : addr, vWhitelistedRangeIncoming);
{
LOCK(m_nodes_mutex);
@@ -1786,7 +1790,6 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
NodeId id = GetNewNodeId();
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
const bool inbound_onion = std::find(m_onion_binds.begin(), m_onion_binds.end(), addr_bind) != m_onion_binds.end();
// The V2Transport transparently falls back to V1 behavior when an incoming V1 connection is
// detected, so use it whenever we signal NODE_P2P_V2.
ServiceFlags local_services = GetLocalServices();

View File

@@ -1345,7 +1345,7 @@ private:
bool AttemptToEvictConnection();
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr, const std::vector<NetWhitelistPermissions>& ranges) const;
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr, const std::vector<NetWhitelistPermissions>& ranges) const;
void DeleteNode(CNode* pnode);

View File

@@ -56,6 +56,7 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& argsman, const CChainP
}
}
static_assert(DEFAULT_MIN_RELAY_TX_FEE == DEFAULT_INCREMENTAL_RELAY_FEE);
if (argsman.IsArgSet("-minrelaytxfee")) {
if (std::optional<CAmount> min_relay_feerate = ParseMoney(argsman.GetArg("-minrelaytxfee", ""))) {
// High fee check is done afterward in CWallet::Create()

View File

@@ -45,8 +45,6 @@ public:
/**
* Construct a fee rate from a fee in satoshis and a vsize in vB.
*
* param@[in] nFeePaid The fee paid by a transaction, in satoshis
* param@[in] num_bytes The vsize of a transaction, in vbytes
*/
CFeeRate(const CAmount& nFeePaid, uint32_t num_bytes);

View File

@@ -22,7 +22,7 @@ class CScript;
/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{MAX_BLOCK_WEIGHT - 4000};
/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/
static constexpr unsigned int DEFAULT_BLOCK_MIN_TX_FEE{1000};
static constexpr unsigned int DEFAULT_BLOCK_MIN_TX_FEE{1};
/** The maximum weight for transactions we're willing to relay/mine */
static constexpr int32_t MAX_STANDARD_TX_WEIGHT{400000};
/** The minimum non-witness size for transactions we're willing to relay/mine: one larger than 64 */
@@ -32,7 +32,7 @@ static constexpr unsigned int MAX_P2SH_SIGOPS{15};
/** The maximum number of sigops we're willing to relay/mine in a single tx */
static constexpr unsigned int MAX_STANDARD_TX_SIGOPS_COST{MAX_BLOCK_SIGOPS_COST/5};
/** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or replacement **/
static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{1000};
static constexpr unsigned int DEFAULT_INCREMENTAL_RELAY_FEE{100};
/** Default for -bytespersigop */
static constexpr unsigned int DEFAULT_BYTES_PER_SIGOP{20};
/** Default for -permitbaremultisig */
@@ -54,7 +54,7 @@ static constexpr unsigned int MAX_STANDARD_SCRIPTSIG_SIZE{1650};
* outputs below the new threshold */
static constexpr unsigned int DUST_RELAY_TX_FEE{3000};
/** Default for -minrelaytxfee, minimum relay fee for transactions */
static constexpr unsigned int DEFAULT_MIN_RELAY_TX_FEE{1000};
static constexpr unsigned int DEFAULT_MIN_RELAY_TX_FEE{100};
/** Default for -limitancestorcount, max number of in-mempool ancestors */
static constexpr unsigned int DEFAULT_ANCESTOR_LIMIT{25};
/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */

View File

@@ -80,7 +80,7 @@ static RPCHelpMan ping()
{
return RPCHelpMan{"ping",
"\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
"Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
"Results are provided in getpeerinfo.\n"
"Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n",
{},
RPCResult{RPCResult::Type::NONE, "", ""},
@@ -145,9 +145,9 @@ static RPCHelpMan getpeerinfo()
{RPCResult::Type::NUM, "bytesrecv", "The total bytes received"},
{RPCResult::Type::NUM_TIME, "conntime", "The " + UNIX_EPOCH_TIME + " of the connection"},
{RPCResult::Type::NUM, "timeoffset", "The time offset in seconds"},
{RPCResult::Type::NUM, "pingtime", /*optional=*/true, "The last ping time in milliseconds (ms), if any"},
{RPCResult::Type::NUM, "minping", /*optional=*/true, "The minimum observed ping time in milliseconds (ms), if any"},
{RPCResult::Type::NUM, "pingwait", /*optional=*/true, "The duration in milliseconds (ms) of an outstanding ping (if non-zero)"},
{RPCResult::Type::NUM, "pingtime", /*optional=*/true, "The last ping time in seconds, if any"},
{RPCResult::Type::NUM, "minping", /*optional=*/true, "The minimum observed ping time in seconds, if any"},
{RPCResult::Type::NUM, "pingwait", /*optional=*/true, "The duration in seconds of an outstanding ping (if non-zero)"},
{RPCResult::Type::NUM, "version", "The peer version, such as 70001"},
{RPCResult::Type::STR, "subver", "The string version"},
{RPCResult::Type::BOOL, "inbound", "Inbound (true) or Outbound (false)"},

View File

@@ -292,7 +292,6 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
std::set<CTransactionRef> added;
auto txr = std::make_shared<TransactionsDelta>(removed, added);
node.validation_signals->RegisterSharedValidationInterface(txr);
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
// Make sure ProcessNewPackage on one transaction works.
// The result is not guaranteed to be the same as what is returned by ATMP.
@@ -307,7 +306,7 @@ FUZZ_TARGET(tx_pool_standard, .init = initialize_tx_pool)
it->second.m_result_type == MempoolAcceptResult::ResultType::INVALID);
}
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false));
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), /*bypass_limits=*/false, /*test_accept=*/false));
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
node.validation_signals->SyncWithValidationInterfaceQueue();
node.validation_signals->UnregisterSharedValidationInterface(txr);
@@ -389,6 +388,9 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
chainstate.SetMempool(&tx_pool);
// If we ever bypass limits, do not do TRUC invariants checks
bool ever_bypassed_limits{false};
LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 300)
{
const auto mut_tx = ConsumeTransaction(fuzzed_data_provider, txids);
@@ -407,13 +409,17 @@ FUZZ_TARGET(tx_pool, .init = initialize_tx_pool)
tx_pool.PrioritiseTransaction(txid.ToUint256(), delta);
}
const bool bypass_limits{fuzzed_data_provider.ConsumeBool()};
ever_bypassed_limits |= bypass_limits;
const auto tx = MakeTransactionRef(mut_tx);
const bool bypass_limits = fuzzed_data_provider.ConsumeBool();
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, tx, GetTime(), bypass_limits, /*test_accept=*/false));
const bool accepted = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
if (accepted) {
txids.push_back(tx->GetHash());
CheckMempoolTRUCInvariants(tx_pool);
if (!ever_bypassed_limits) {
CheckMempoolTRUCInvariants(tx_pool);
}
}
}
Finish(fuzzed_data_provider, tx_pool, chainstate);

View File

@@ -443,7 +443,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN;
pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1));
pool.addUnchecked(entry.Fee(1000LL).FromTx(tx1));
CMutableTransaction tx2 = CMutableTransaction();
tx2.vin.resize(1);
@@ -451,7 +451,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx2.vout.resize(1);
tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
tx2.vout[0].nValue = 10 * COIN;
pool.addUnchecked(entry.Fee(5000LL).FromTx(tx2));
pool.addUnchecked(entry.Fee(500LL).FromTx(tx2));
pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
BOOST_CHECK(pool.exists(GenTxid::Txid(tx1.GetHash())));
@@ -469,7 +469,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx3.vout.resize(1);
tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
tx3.vout[0].nValue = 10 * COIN;
pool.addUnchecked(entry.Fee(20000LL).FromTx(tx3));
pool.addUnchecked(entry.Fee(2000LL).FromTx(tx3));
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx1.GetHash())));
@@ -481,8 +481,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash())));
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx3.GetHash())));
CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)));
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
CFeeRate maxFeeRateRemoved(2500, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)));
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE);
CMutableTransaction tx4 = CMutableTransaction();
tx4.vin.resize(2);
@@ -532,10 +532,10 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
tx7.vout[1].nValue = 10 * COIN;
pool.addUnchecked(entry.Fee(7000LL).FromTx(tx4));
pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
pool.addUnchecked(entry.Fee(1100LL).FromTx(tx6));
pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
pool.addUnchecked(entry.Fee(700LL).FromTx(tx4));
pool.addUnchecked(entry.Fee(100LL).FromTx(tx5));
pool.addUnchecked(entry.Fee(110LL).FromTx(tx6));
pool.addUnchecked(entry.Fee(900LL).FromTx(tx7));
// we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that
pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
@@ -544,8 +544,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash())));
if (!pool.exists(GenTxid::Txid(tx5.GetHash())))
pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
pool.addUnchecked(entry.Fee(100LL).FromTx(tx5));
pool.addUnchecked(entry.Fee(900LL).FromTx(tx7));
pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
BOOST_CHECK(pool.exists(GenTxid::Txid(tx4.GetHash())));
@@ -553,34 +553,34 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash())));
BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash())));
pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
pool.addUnchecked(entry.Fee(100LL).FromTx(tx5));
pool.addUnchecked(entry.Fee(900LL).FromTx(tx7));
std::vector<CTransactionRef> vtx;
SetMockTime(42);
SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE);
// ... we should keep the same min fee until we get a block
pool.removeForBlock(vtx, 1);
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/2.0));
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/2.0));
// ... then feerate should drop 1/2 each halflife
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2);
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/4.0));
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/4.0));
// ... with a 1/2 halflife when mempool is < 1/2 its target size
SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/8.0));
BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + DEFAULT_INCREMENTAL_RELAY_FEE)/8.0));
// ... with a 1/4 halflife when mempool is < 1/4 its target size
SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 1000);
// ... but feerate should never drop below 1000
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), DEFAULT_INCREMENTAL_RELAY_FEE);
// ... but feerate should never drop below DEFAULT_INCREMENTAL_RELAY_FEE
SetMockTime(42 + 8*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);
// ... unless it has gone all the way to 0 (after getting past 1000/2)
// ... unless it has gone all the way to 0 (after getting past DEFAULT_INCREMENTAL_RELAY_FEE/2)
}
inline CTransactionRef make_tx(std::vector<CAmount>&& output_values, std::vector<CTransactionRef>&& inputs=std::vector<CTransactionRef>(), std::vector<uint32_t>&& input_indices=std::vector<uint32_t>())

View File

@@ -11,6 +11,7 @@
#include <node/miner.h>
#include <policy/policy.h>
#include <test/util/random.h>
#include <test/util/transaction_utils.h>
#include <test/util/txmempool.h>
#include <txmempool.h>
#include <uint256.h>
@@ -183,6 +184,9 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
tx.vout.resize(2);
tx.vout[0].nValue = 5000000000LL - 100000000;
tx.vout[1].nValue = 100000000; // 1BTC output
// Increase size to avoid rounding errors: when the feerate is extremely small (i.e. 1sat/kvB), evaluating the fee
// at a smaller transaction size gives us a rounded value of 0.
BulkTransaction(tx, 4000);
Txid hashFreeTx2 = tx.GetHash();
tx_mempool.addUnchecked(entry.Fee(0).SpendsCoinbase(true).FromTx(tx));

View File

@@ -238,10 +238,10 @@ BOOST_FIXTURE_TEST_CASE(rbf_helper_functions, TestChain100Setup)
BOOST_CHECK(PaysForRBF(high_fee, high_fee - 1, 1, CFeeRate(0), unused_txid).has_value());
BOOST_CHECK(PaysForRBF(high_fee + 1, high_fee, 1, CFeeRate(0), unused_txid).has_value());
// Additional fees must cover the replacement's vsize at incremental relay fee
BOOST_CHECK(PaysForRBF(high_fee, high_fee + 1, 2, incremental_relay_feerate, unused_txid).has_value());
BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, incremental_relay_feerate, unused_txid) == std::nullopt);
BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 2, higher_relay_feerate, unused_txid).has_value());
BOOST_CHECK(PaysForRBF(high_fee, high_fee + 4, 2, higher_relay_feerate, unused_txid) == std::nullopt);
BOOST_CHECK(PaysForRBF(high_fee, high_fee + 1, 11, incremental_relay_feerate, unused_txid).has_value());
BOOST_CHECK(PaysForRBF(high_fee, high_fee + 1, 10, incremental_relay_feerate, unused_txid) == std::nullopt);
BOOST_CHECK(PaysForRBF(high_fee, high_fee + 2, 11, higher_relay_feerate, unused_txid).has_value());
BOOST_CHECK(PaysForRBF(high_fee, high_fee + 4, 20, higher_relay_feerate, unused_txid) == std::nullopt);
BOOST_CHECK(PaysForRBF(low_fee, high_fee, 99999999, incremental_relay_feerate, unused_txid).has_value());
BOOST_CHECK(PaysForRBF(low_fee, high_fee + 99999999, 99999999, incremental_relay_feerate, unused_txid) == std::nullopt);

View File

@@ -41,6 +41,7 @@
#include <streams.h>
#include <test/util/net.h>
#include <test/util/random.h>
#include <test/util/transaction_utils.h>
#include <test/util/txmempool.h>
#include <txdb.h>
#include <txmempool.h>
@@ -582,6 +583,9 @@ void TestChain100Setup::MockMempoolMinFee(const CFeeRate& target_feerate)
CMutableTransaction mtx = CMutableTransaction();
mtx.vin.emplace_back(COutPoint{Txid::FromUint256(g_insecure_rand_ctx.rand256()), 0});
mtx.vout.emplace_back(1 * COIN, GetScriptForDestination(WitnessV0ScriptHash(CScript() << OP_TRUE)));
// Set a large size so that the fee evaluated at target_feerate (which is usually in sats/kvB) is an integer.
// Otherwise, GetMinFee() may end up slightly different from target_feerate.
BulkTransaction(mtx, 4000);
const auto tx{MakeTransactionRef(mtx)};
LockPoints lp;
// The new mempool min feerate is equal to the removed package's feerate + incremental feerate.

View File

@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <coins.h>
#include <consensus/validation.h>
#include <script/signingprovider.h>
#include <test/util/transaction_utils.h>
@@ -69,3 +70,23 @@ std::vector<CMutableTransaction> SetupDummyInputs(FillableSigningProvider& keyst
return dummyTransactions;
}
void BulkTransaction(CMutableTransaction& tx, int32_t target_weight)
{
tx.vout.emplace_back(0, CScript() << OP_RETURN);
auto unpadded_weight{GetTransactionWeight(CTransaction(tx))};
assert(target_weight >= unpadded_weight);
// determine number of needed padding bytes by converting weight difference to vbytes
auto dummy_vbytes = (target_weight - unpadded_weight + (WITNESS_SCALE_FACTOR - 1)) / WITNESS_SCALE_FACTOR;
// compensate for the increase of the compact-size encoded script length
// (note that the length encoding of the unpadded output script needs one byte)
dummy_vbytes -= GetSizeOfCompactSize(dummy_vbytes) - 1;
// pad transaction by repeatedly appending a dummy opcode to the output script
tx.vout[0].scriptPubKey.insert(tx.vout[0].scriptPubKey.end(), dummy_vbytes, OP_1);
// actual weight should be at most 3 higher than target weight
assert(GetTransactionWeight(CTransaction(tx)) >= target_weight);
assert(GetTransactionWeight(CTransaction(tx)) <= target_weight + 3);
}

View File

@@ -26,4 +26,8 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CSc
// the second nValues[2] and nValues[3] outputs paid to a TxoutType::PUBKEYHASH.
std::vector<CMutableTransaction> SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet, const std::array<CAmount,4>& nValues);
// bulk transaction to reach a certain target weight,
// by appending a single output with padded output script
void BulkTransaction(CMutableTransaction& tx, int32_t target_weight);
#endif // BITCOIN_TEST_UTIL_TRANSACTION_UTILS_H

View File

@@ -1039,26 +1039,28 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
// Even though just checking direct mempool parents for inheritance would be sufficient, we
// check using the full ancestor set here because it's more convenient to use what we have
// already calculated.
if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
// Single transaction contexts only.
if (args.m_allow_sibling_eviction && err->second != nullptr) {
// We should only be considering where replacement is considered valid as well.
Assume(args.m_allow_replacement);
if (!args.m_bypass_limits) {
if (const auto err{SingleTRUCChecks(ws.m_ptx, ws.m_ancestors, ws.m_conflicts, ws.m_vsize)}) {
// Single transaction contexts only.
if (args.m_allow_sibling_eviction && err->second != nullptr) {
// We should only be considering where replacement is considered valid as well.
Assume(args.m_allow_replacement);
// Potential sibling eviction. Add the sibling to our list of mempool conflicts to be
// included in RBF checks.
ws.m_conflicts.insert(err->second->GetHash());
// Adding the sibling to m_iters_conflicting here means that it doesn't count towards
// RBF Carve Out above. This is correct, since removing to-be-replaced transactions from
// the descendant count is done separately in SingleTRUCChecks for TRUC transactions.
ws.m_iters_conflicting.insert(m_pool.GetIter(err->second->GetHash()).value());
ws.m_sibling_eviction = true;
// The sibling will be treated as part of the to-be-replaced set in ReplacementChecks.
// Note that we are not checking whether it opts in to replaceability via BIP125 or TRUC
// (which is normally done in PreChecks). However, the only way a TRUC transaction can
// have a non-TRUC and non-BIP125 descendant is due to a reorg.
} else {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first);
// Potential sibling eviction. Add the sibling to our list of mempool conflicts to be
// included in RBF checks.
ws.m_conflicts.insert(err->second->GetHash());
// Adding the sibling to m_iters_conflicting here means that it doesn't count towards
// RBF Carve Out above. This is correct, since removing to-be-replaced transactions from
// the descendant count is done separately in SingleTRUCChecks for TRUC transactions.
ws.m_iters_conflicting.insert(m_pool.GetIter(err->second->GetHash()).value());
ws.m_sibling_eviction = true;
// The sibling will be treated as part of the to-be-replaced set in ReplacementChecks.
// Note that we are not checking whether it opts in to replaceability via BIP125 or TRUC
// (which is normally done in PreChecks). However, the only way a TRUC transaction can
// have a non-TRUC and non-BIP125 descendant is due to a reorg.
} else {
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "TRUC-violation", err->first);
}
}
}

View File

@@ -590,15 +590,15 @@ util::Result<SelectionResult> SelectCoinsSRD(const std::vector<OutputGroup>& utx
/** Find a subset of the OutputGroups that is at least as large as, but as close as possible to, the
* target amount; solve subset sum.
* param@[in] groups OutputGroups to choose from, sorted by value in descending order.
* param@[in] nTotalLower Total (effective) value of the UTXOs in groups.
* param@[in] nTargetValue Subset sum target, not including change.
* param@[out] vfBest Boolean vector representing the subset chosen that is closest to
* @param[in] groups OutputGroups to choose from, sorted by value in descending order.
* @param[in] nTotalLower Total (effective) value of the UTXOs in groups.
* @param[in] nTargetValue Subset sum target, not including change.
* @param[out] vfBest Boolean vector representing the subset chosen that is closest to
* nTargetValue, with indices corresponding to groups. If the ith
* entry is true, that means the ith group in groups was selected.
* param@[out] nBest Total amount of subset chosen that is closest to nTargetValue.
* paramp[in] max_selection_weight The maximum allowed weight for a selection result to be valid.
* param@[in] iterations Maximum number of tries.
* @param[out] nBest Total amount of subset chosen that is closest to nTargetValue.
* @param[in] max_selection_weight The maximum allowed weight for a selection result to be valid.
* @param[in] iterations Maximum number of tries.
*/
static void ApproximateBestSubset(FastRandomContext& insecure_rand, const std::vector<OutputGroup>& groups,
const CAmount& nTotalLower, const CAmount& nTargetValue,

View File

@@ -123,14 +123,14 @@ FilteredOutputGroups GroupOutputs(const CWallet& wallet,
* the solution (according to the waste metric) will be chosen. If a valid input cannot be found from any
* single OutputType, fallback to running `ChooseSelectionResult()` over all available coins.
*
* param@[in] chain The chain interface to get information on unconfirmed UTXOs bump fees
* param@[in] nTargetValue The target value
* param@[in] groups The grouped outputs mapped by coin eligibility filters
* param@[in] coin_selection_params Parameters for the coin selection
* param@[in] allow_mixed_output_types Relax restriction that SelectionResults must be of the same OutputType
* @param[in] chain The chain interface to get information on bump fees for unconfirmed UTXOs
* @param[in] nTargetValue The target value
* @param[in] groups The grouped outputs mapped by coin eligibility filters
* @param[in] coin_selection_params Parameters for the coin selection
* @param[in] allow_mixed_output_types Relax restriction that SelectionResults must be of the same OutputType
* returns If successful, a SelectionResult containing the input set
* If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds")
* or (2) an specific error message if there was something particularly wrong (e.g. a selection
* or (2) a specific error message if there was something particularly wrong (e.g. a selection
* result that surpassed the tx max weight size).
*/
util::Result<SelectionResult> AttemptSelection(interfaces::Chain& chain, const CAmount& nTargetValue, OutputGroupTypeMap& groups,
@@ -141,13 +141,13 @@ util::Result<SelectionResult> AttemptSelection(interfaces::Chain& chain, const C
* Multiple coin selection algorithms will be run and the input set that produces the least waste
* (according to the waste metric) will be chosen.
*
* param@[in] chain The chain interface to get information on unconfirmed UTXOs bump fees
* param@[in] nTargetValue The target value
* param@[in] groups The struct containing the outputs grouped by script and divided by (1) positive only outputs and (2) all outputs (positive + negative).
* param@[in] coin_selection_params Parameters for the coin selection
* @param[in] chain The chain interface to get information on bump fees for unconfirmed UTXOs
* @param[in] nTargetValue The target value
* @param[in] groups The struct containing the outputs grouped by script and divided by (1) positive only outputs and (2) all outputs (positive + negative).
* @param[in] coin_selection_params Parameters for the coin selection
* returns If successful, a SelectionResult containing the input set
* If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds")
* or (2) an specific error message if there was something particularly wrong (e.g. a selection
* or (2) a specific error message if there was something particularly wrong (e.g. a selection
* result that surpassed the tx max weight size).
*/
util::Result<SelectionResult> ChooseSelectionResult(interfaces::Chain& chain, const CAmount& nTargetValue, Groups& groups, const CoinSelectionParams& coin_selection_params);
@@ -181,10 +181,10 @@ util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const
/**
* Select a set of coins such that nTargetValue is met; never select unconfirmed coins if they are not ours
* param@[in] wallet The wallet which provides data necessary to spend the selected coins
* param@[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
* param@[in] nTargetValue The target value
* param@[in] coin_selection_params Parameters for this coin selection such as feerates, whether to avoid partial spends,
* @param[in] wallet The wallet which provides data necessary to spend the selected coins
* @param[in] available_coins The struct of coins, organized by OutputType, available for selection prior to filtering
* @param[in] nTargetValue The target value
* @param[in] coin_selection_params Parameters for this coin selection such as feerates, whether to avoid partial spends,
* and whether to subtract the fee from the outputs.
* returns If successful, a SelectionResult containing the selected coins
* If failed, returns (1) an empty error message if the target was not reached (general "Insufficient funds")

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2015-2022 The Bitcoin Core developers
// Copyright (c) 2015-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -22,7 +22,7 @@ struct NewMempoolTransactionInfo;
class CZMQNotificationInterface final : public CValidationInterface
{
public:
virtual ~CZMQNotificationInterface();
~CZMQNotificationInterface();
std::list<const CZMQAbstractNotifier*> GetActiveNotifiers() const;

View File

@@ -148,8 +148,10 @@ class BIP68Test(BitcoinTestFramework):
# between height/time locking). Small random chance of making the locks
# all pass.
for _ in range(400):
available_utxos = len(utxos)
# Randomly choose up to 10 inputs
num_inputs = random.randint(1, 10)
num_inputs = random.randint(1, min(10, available_utxos))
random.shuffle(utxos)
# Track whether any sequence locks used should fail

View File

@@ -14,7 +14,10 @@ from test_framework.messages import (
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_greater_than,
assert_greater_than_or_equal,
assert_raises_rpc_error,
get_fee,
)
from test_framework.wallet import MiniWallet
from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
@@ -87,6 +90,9 @@ class ReplaceByFeeTest(BitcoinTestFramework):
self.log.info("Running test full replace by fee...")
self.test_fullrbf()
self.log.info("Running test incremental relay feerates...")
self.test_incremental_relay_feerates()
self.log.info("Passed")
def make_utxo(self, node, amount, *, confirmed=True, scriptPubKey=None):
@@ -697,10 +703,42 @@ class ReplaceByFeeTest(BitcoinTestFramework):
# Higher fee, higher feerate, different txid, but the replacement does not provide a relay
# fee conforming to node's `incrementalrelayfee` policy of 1000 sat per KB.
assert_equal(self.nodes[0].getmempoolinfo()["incrementalrelayfee"], Decimal("0.00001"))
assert_equal(self.nodes[0].getmempoolinfo()["incrementalrelayfee"], Decimal("0.000001"))
tx.vout[0].nValue -= 1
assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx.serialize().hex())
def test_incremental_relay_feerates(self):
self.log.info("Test that incremental relay fee is applied correctly in RBF for various settings...")
node = self.nodes[0]
for incremental_setting in (0, 5, 10, 50, 100, 234, 1000, 5000, 21000):
incremental_setting_decimal = incremental_setting / Decimal(COIN)
self.log.info(f"-> Test -incrementalrelayfee={incremental_setting_decimal:.8f}sat/kvB...")
self.restart_node(0, extra_args=[f"-incrementalrelayfee={incremental_setting_decimal:.8f}", "-datacarriersize=5000", "-persistmempool=0"])
# When incremental relay feerate is higher than min relay feerate, min relay feerate is automatically increased.
min_relay_feerate = node.getmempoolinfo()["minrelaytxfee"]
assert_greater_than_or_equal(min_relay_feerate, incremental_setting_decimal)
low_feerate = min_relay_feerate * 2
confirmed_utxo = self.wallet.get_utxo(confirmed_only=True)
replacee_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo, fee_rate=low_feerate, target_weight=20000)
node.sendrawtransaction(replacee_tx['hex'])
replacement_placeholder_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo)
replacement_expected_size = replacement_placeholder_tx['tx'].get_vsize()
replacement_required_fee = get_fee(replacement_expected_size, incremental_setting_decimal) + replacee_tx['fee']
# Should always be required to pay additional fees
if incremental_setting > 0:
assert_greater_than(replacement_required_fee, replacee_tx['fee'])
# 1 satoshi shy of the required fee
failed_replacement_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo, fee=replacement_required_fee - Decimal("0.00000001"))
assert_raises_rpc_error(-26, "insufficient fee", node.sendrawtransaction, failed_replacement_tx['hex'])
replacement_tx = self.wallet.create_self_transfer(utxo_to_spend=confirmed_utxo, fee=replacement_required_fee)
node.sendrawtransaction(replacement_tx['hex'])
def test_fullrbf(self):
confirmed_utxo = self.make_utxo(self.nodes[0], int(2 * COIN))

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2022 The Bitcoin Core developers
# Copyright (c) 2022-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,6 +17,7 @@ from test_framework.util import (
assert_equal,
assert_greater_than,
assert_raises_rpc_error,
bpf_cflags,
)
coinselection_tracepoints_program = """
@@ -166,7 +167,7 @@ class CoinSelectionTracepointTest(BitcoinTestFramework):
ctx.enable_probe(probe="coin_selection:normal_create_tx_internal", fn_name="trace_normal_create_tx")
ctx.enable_probe(probe="coin_selection:attempting_aps_create_tx", fn_name="trace_attempt_aps")
ctx.enable_probe(probe="coin_selection:aps_create_tx_internal", fn_name="trace_aps_create_tx")
self.bpf = BPF(text=coinselection_tracepoints_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
self.bpf = BPF(text=coinselection_tracepoints_program, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
self.log.info("Prepare wallets")
self.generate(self.nodes[0], 101)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2022 The Bitcoin Core developers
# Copyright (c) 2022-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -19,7 +19,10 @@ from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import COIN, DEFAULT_MEMPOOL_EXPIRY_HOURS
from test_framework.p2p import P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.util import (
assert_equal,
bpf_cflags,
)
from test_framework.wallet import MiniWallet
MEMPOOL_TRACEPOINTS_PROGRAM = """
@@ -144,7 +147,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
node = self.nodes[0]
ctx = USDT(pid=node.process.pid)
ctx.enable_probe(probe="mempool:added", fn_name="trace_added")
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
def handle_added_event(_, data, __):
events.append(bpf["added_events"].event(data))
@@ -181,7 +184,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
node = self.nodes[0]
ctx = USDT(pid=node.process.pid)
ctx.enable_probe(probe="mempool:removed", fn_name="trace_removed")
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
def handle_removed_event(_, data, __):
events.append(bpf["removed_events"].event(data))
@@ -227,7 +230,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
node = self.nodes[0]
ctx = USDT(pid=node.process.pid)
ctx.enable_probe(probe="mempool:replaced", fn_name="trace_replaced")
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
def handle_replaced_event(_, data, __):
events.append(bpf["replaced_events"].event(data))
@@ -278,7 +281,7 @@ class MempoolTracepointTest(BitcoinTestFramework):
self.log.info("Hooking into mempool:rejected tracepoint...")
ctx = USDT(pid=node.process.pid)
ctx.enable_probe(probe="mempool:rejected", fn_name="trace_rejected")
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
def handle_rejected_event(_, data, __):
events.append(bpf["rejected_events"].event(data))

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2022 The Bitcoin Core developers
# Copyright (c) 2022-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,7 +17,10 @@ except ImportError:
from test_framework.messages import msg_version
from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.util import (
assert_equal,
bpf_cflags,
)
# Tor v3 addresses are 62 chars + 6 chars for the port (':12345').
MAX_PEER_ADDR_LENGTH = 68
@@ -115,7 +118,7 @@ class NetTracepointTest(BitcoinTestFramework):
fn_name="trace_inbound_message")
ctx.enable_probe(probe="net:outbound_message",
fn_name="trace_outbound_message")
bpf = BPF(text=net_tracepoints_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
bpf = BPF(text=net_tracepoints_program, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
EXPECTED_INOUTBOUND_VERSION_MSG = 1
checked_inbound_version_msg = 0

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2022 The Bitcoin Core developers
# Copyright (c) 2022-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -15,7 +15,10 @@ except ImportError:
pass
from test_framework.messages import COIN
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.util import (
assert_equal,
bpf_cflags,
)
from test_framework.wallet import MiniWallet
utxocache_changes_program = """
@@ -175,7 +178,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="utxocache:uncache",
fn_name="trace_utxocache_uncache")
bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
# The handle_* function is a ctypes callback function called from C. When
# we assert in the handle_* function, the AssertError doesn't propagate
@@ -244,7 +247,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
ctx.enable_probe(probe="utxocache:add", fn_name="trace_utxocache_add")
ctx.enable_probe(probe="utxocache:spent",
fn_name="trace_utxocache_spent")
bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
# The handle_* function is a ctypes callback function called from C. When
# we assert in the handle_* function, the AssertError doesn't propagate
@@ -333,7 +336,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="utxocache:flush",
fn_name="trace_utxocache_flush")
bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
# The handle_* function is a ctypes callback function called from C. When
# we assert in the handle_* function, the AssertError doesn't propagate
@@ -390,7 +393,7 @@ class UTXOCacheTracepointTest(BitcoinTestFramework):
ctx = USDT(pid=self.nodes[0].process.pid)
ctx.enable_probe(probe="utxocache:flush",
fn_name="trace_utxocache_flush")
bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
self.log.info(f"prune blockchain to trigger a flush for pruning")

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# Copyright (c) 2022 The Bitcoin Core developers
# Copyright (c) 2022-present The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,8 +17,10 @@ except ImportError:
from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
from test_framework.util import (
assert_equal,
bpf_cflags,
)
validation_blockconnected_program = """
#include <uapi/linux/ptrace.h>
@@ -94,7 +96,7 @@ class ValidationTracepointTest(BitcoinTestFramework):
ctx.enable_probe(probe="validation:block_connected",
fn_name="trace_block_connected")
bpf = BPF(text=validation_blockconnected_program,
usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
usdt_contexts=[ctx], debug=0, cflags=bpf_cflags())
def handle_blockconnected(_, data, __):
event = ctypes.cast(data, ctypes.POINTER(Block)).contents

View File

@@ -9,6 +9,10 @@ from decimal import Decimal
import math
from test_framework.test_framework import BitcoinTestFramework
from test_framework.mempool_util import (
DEFAULT_MIN_RELAY_TX_FEE,
DEFAULT_INCREMENTAL_RELAY_FEE,
)
from test_framework.messages import (
MAX_BIP125_RBF_SEQUENCE,
COIN,
@@ -80,6 +84,11 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
assert_equal(node.getblockcount(), 200)
assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
self.log.info("Check default settings")
# Settings are listed in BTC/kvB
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN)
assert_equal(node.getmempoolinfo()['incrementalrelayfee'], Decimal(DEFAULT_INCREMENTAL_RELAY_FEE) / COIN)
self.log.info('Should not accept garbage to testmempoolaccept')
assert_raises_rpc_error(-3, 'JSON value of type string is not of expected type array', lambda: node.testmempoolaccept(rawtxs='ff00baar'))
assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=['ff22']*26))

View File

@@ -92,8 +92,7 @@ class MempoolLimitTest(BitcoinTestFramework):
self.restart_node(0, extra_args=self.extra_args[0])
# Restarting the node resets mempool minimum feerate
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['minrelaytxfee'], node.getmempoolinfo()["mempoolminfee"])
fill_mempool(self, node)
current_info = node.getmempoolinfo()
@@ -122,7 +121,7 @@ class MempoolLimitTest(BitcoinTestFramework):
# coin is no longer available, but the cache could still contains the tx.
cpfp_parent = self.wallet.create_self_transfer(
utxo_to_spend=mempool_evicted_tx["new_utxo"],
fee_rate=mempoolmin_feerate - Decimal('0.00001'),
fee_rate=mempoolmin_feerate / 2,
confirmed_only=True)
package_hex.append(cpfp_parent["hex"])
parent_utxos.append(cpfp_parent["new_utxo"])
@@ -154,7 +153,7 @@ class MempoolLimitTest(BitcoinTestFramework):
# Specific number of satoshis to fit within a small window. The parent_cpfp + child package needs to be
# - When there is mid-package eviction, high enough feerate to meet the new mempoolminfee
# - When there is no mid-package eviction, low enough feerate to be evicted immediately after submission.
magic_satoshis = 1200
magic_satoshis = 120
cpfp_satoshis = int(cpfp_fee * COIN) + magic_satoshis
child = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=cpfp_satoshis)
@@ -182,8 +181,7 @@ class MempoolLimitTest(BitcoinTestFramework):
self.restart_node(0, extra_args=self.extra_args[0])
# Restarting the node resets mempool minimum feerate
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['minrelaytxfee'], node.getmempoolinfo()["mempoolminfee"])
fill_mempool(self, node)
current_info = node.getmempoolinfo()
@@ -208,7 +206,7 @@ class MempoolLimitTest(BitcoinTestFramework):
# coin is no longer available, but the cache could still contain the tx.
cpfp_parent = self.wallet.create_self_transfer(
utxo_to_spend=replaced_tx["new_utxo"],
fee_rate=mempoolmin_feerate - Decimal('0.00001'),
fee_rate=mempoolmin_feerate - Decimal('0.000001'),
confirmed_only=True)
self.wallet.rescan_utxos()
@@ -256,8 +254,7 @@ class MempoolLimitTest(BitcoinTestFramework):
relayfee = node.getnetworkinfo()['relayfee']
self.log.info('Check that mempoolminfee is minrelaytxfee')
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['minrelaytxfee'], node.getmempoolinfo()["mempoolminfee"])
fill_mempool(self, node)
@@ -314,9 +311,9 @@ class MempoolLimitTest(BitcoinTestFramework):
target_weight_each = 200000
assert_greater_than(target_weight_each * 2, node.getmempoolinfo()["maxmempool"] - node.getmempoolinfo()["bytes"])
# Should be a true CPFP: parent's feerate is just below mempool min feerate
parent_feerate = mempoolmin_feerate - Decimal("0.000001") # 0.1 sats/vbyte below min feerate
parent_feerate = mempoolmin_feerate - Decimal("0.0000001") # 0.01 sats/vbyte below min feerate
# Parent + child is above mempool minimum feerate
child_feerate = (worst_feerate_btcvb * 1000) - Decimal("0.000001") # 0.1 sats/vbyte below worst feerate
child_feerate = (worst_feerate_btcvb * 1000) - Decimal("0.0000001") # 0.01 sats/vbyte below worst feerate
# However, when eviction is triggered, these transactions should be at the bottom.
# This assertion assumes parent and child are the same size.
miniwallet.rescan_utxos()

View File

@@ -170,13 +170,13 @@ class PackageRBFTest(BitcoinTestFramework):
self.log.info("Check replacement pays for incremental bandwidth")
_, placeholder_txns3 = self.create_simple_package(coin)
package_3_size = sum([tx.get_vsize() for tx in placeholder_txns3])
incremental_sats_required = Decimal(package_3_size) / COIN
incremental_sats_short = incremental_sats_required - Decimal("0.00000001")
incremental_sats_required = (Decimal(package_3_size * 0.1) / COIN).quantize(Decimal("0.00000001"))
incremental_sats_short = incremental_sats_required - Decimal("0.00000005")
# Recreate the package with slightly higher fee once we know the size of the new package, but still short of required fee
failure_package_hex3, failure_package_txns3 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE + incremental_sats_short)
assert_equal(package_3_size, sum([tx.get_vsize() for tx in failure_package_txns3]))
pkg_results3 = node.submitpackage(failure_package_hex3)
assert_equal(f"package RBF failed: insufficient anti-DoS fees, rejecting replacement {failure_package_txns3[1].rehash()}, not enough additional fees to relay; {incremental_sats_short} < {incremental_sats_required}", pkg_results3["package_msg"])
assert_equal(f"package RBF failed: insufficient anti-DoS fees, rejecting replacement {failure_package_txns3[1].rehash()}, not enough additional fees to relay; {incremental_sats_short:.8f} < {incremental_sats_required:.8f}", pkg_results3["package_msg"])
self.assert_mempool_contents(expected=package_txns1)
success_package_hex3, success_package_txns3 = self.create_simple_package(coin, parent_fee=DEFAULT_FEE, child_fee=DEFAULT_CHILD_FEE + incremental_sats_required)
@@ -554,7 +554,7 @@ class PackageRBFTest(BitcoinTestFramework):
self.generate(node, 1)
def test_child_conflicts_parent_mempool_ancestor(self):
fill_mempool(self, self.nodes[0])
fill_mempool(self, self.nodes[0], tx_sync_fun=self.no_op)
# Reset coins since we filled the mempool with current coins
self.coins = self.wallet.get_utxos(mark_as_spent=False, confirmed_only=True)
@@ -570,12 +570,13 @@ class PackageRBFTest(BitcoinTestFramework):
)
node.sendrawtransaction(grandparent_result["hex"])
minrelayfeerate = node.getnetworkinfo()["relayfee"]
# Now make package of two descendants that looks
# like a cpfp where the parent can't get in on its own
self.ctr += 1
parent_result = self.wallet.create_self_transfer(
fee_rate=Decimal('0.00001000'),
fee_rate=minrelayfeerate,
utxo_to_spend=grandparent_result["new_utxo"],
sequence=MAX_BIP125_RBF_SEQUENCE - self.ctr,
)

View File

@@ -14,6 +14,7 @@ from test_framework.util import (
assert_greater_than,
assert_greater_than_or_equal,
assert_raises_rpc_error,
get_fee,
)
from test_framework.wallet import (
COIN,
@@ -190,23 +191,36 @@ class MempoolTRUC(BitcoinTestFramework):
def test_truc_reorg(self):
node = self.nodes[0]
self.log.info("Test that, during a reorg, TRUC rules are not enforced")
tx_v2_block = self.wallet.send_self_transfer(from_node=node, version=2)
tx_v3_block = self.wallet.send_self_transfer(from_node=node, version=3)
tx_v3_block2 = self.wallet.send_self_transfer(from_node=node, version=3)
self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"]])
self.check_mempool([])
# Testing 2<-3 versions allowed
tx_v2_block = self.wallet.create_self_transfer(version=2)
# Testing 3<-2 versions allowed
tx_v3_block = self.wallet.create_self_transfer(version=3)
# Testing overly-large child size
tx_v3_block2 = self.wallet.create_self_transfer(version=3)
# Also create a linear chain of 3 TRUC transactions that will be directly mined, followed by one v2 in-mempool after block is made
tx_chain_1 = self.wallet.create_self_transfer(version=3)
tx_chain_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_chain_1["new_utxo"], version=3)
tx_chain_3 = self.wallet.create_self_transfer(utxo_to_spend=tx_chain_2["new_utxo"], version=3)
tx_to_mine = [tx_v3_block["hex"], tx_v2_block["hex"], tx_v3_block2["hex"], tx_chain_1["hex"], tx_chain_2["hex"], tx_chain_3["hex"]]
block = self.generateblock(node, output="raw(42)", transactions=tx_to_mine)
block = self.generate(node, 1)
self.check_mempool([])
tx_v2_from_v3 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block["new_utxo"], version=2)
tx_v3_from_v2 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v2_block["new_utxo"], version=3)
tx_v3_child_large = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block2["new_utxo"], target_weight=5000, version=3)
assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], 1000)
self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]])
node.invalidateblock(block[0])
self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]])
# This is needed because generate() will create the exact same block again.
node.reconsiderblock(block[0])
tx_chain_4 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_chain_3["new_utxo"], version=2)
self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"], tx_chain_4["txid"]])
# Reorg should have all block transactions re-accepted, ignoring TRUC enforcement
node.invalidateblock(block["hash"])
self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"], tx_chain_1["txid"], tx_chain_2["txid"], tx_chain_3["txid"], tx_chain_4["txid"]])
@cleanup(extra_args=["-limitdescendantsize=10", "-datacarriersize=40000"])
def test_nondefault_package_limits(self):
@@ -621,12 +635,57 @@ class MempoolTRUC(BitcoinTestFramework):
)
self.check_mempool([tx_with_multi_children["txid"], tx_with_sibling3_rbf["txid"], tx_with_sibling2["txid"]])
@cleanup(extra_args=None)
def test_minrelay_in_package_combos(self):
node = self.nodes[0]
self.log.info("Test that only TRUC transactions can be under minrelaytxfee for various settings...")
for minrelay_setting in (0, 5, 10, 100, 500, 1000, 5000, 333333, 2500000):
self.log.info(f"-> Test -minrelaytxfee={minrelay_setting}sat/kvB...")
setting_decimal = minrelay_setting / Decimal(COIN)
self.restart_node(0, extra_args=[f"-minrelaytxfee={setting_decimal:.8f}", "-persistmempool=0"])
minrelayfeerate = node.getmempoolinfo()["minrelaytxfee"]
high_feerate = minrelayfeerate * 50
tx_v3_0fee_parent = self.wallet.create_self_transfer(fee=0, fee_rate=0, confirmed_only=True, version=3)
tx_v3_child = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_0fee_parent["new_utxo"], fee_rate=high_feerate, version=3)
total_v3_fee = tx_v3_child["fee"] + tx_v3_0fee_parent["fee"]
total_v3_size = tx_v3_child["tx"].get_vsize() + tx_v3_0fee_parent["tx"].get_vsize()
assert_greater_than_or_equal(total_v3_fee, get_fee(total_v3_size, minrelayfeerate))
if minrelayfeerate > 0:
assert_greater_than(get_fee(tx_v3_0fee_parent["tx"].get_vsize(), minrelayfeerate), 0)
# Always need to pay at least 1 satoshi for entry, even if minimum feerate is very low
assert_greater_than(total_v3_fee, 0)
tx_v2_0fee_parent = self.wallet.create_self_transfer(fee=0, fee_rate=0, confirmed_only=True, version=2)
tx_v2_child = self.wallet.create_self_transfer(utxo_to_spend=tx_v2_0fee_parent["new_utxo"], fee_rate=high_feerate, version=2)
total_v2_fee = tx_v2_child["fee"] + tx_v2_0fee_parent["fee"]
total_v2_size = tx_v2_child["tx"].get_vsize() + tx_v2_0fee_parent["tx"].get_vsize()
assert_greater_than_or_equal(total_v2_fee, get_fee(total_v2_size, minrelayfeerate))
if minrelayfeerate > 0:
assert_greater_than(get_fee(tx_v2_0fee_parent["tx"].get_vsize(), minrelayfeerate), 0)
# Always need to pay at least 1 satoshi for entry, even if minimum feerate is very low
assert_greater_than(total_v2_fee, 0)
result_truc = node.submitpackage([tx_v3_0fee_parent["hex"], tx_v3_child["hex"]], maxfeerate=0)
assert_equal(result_truc["package_msg"], "success")
result_non_truc = node.submitpackage([tx_v2_0fee_parent["hex"], tx_v2_child["hex"]], maxfeerate=0)
if minrelayfeerate > 0:
assert_equal(result_non_truc["package_msg"], "transaction failed")
min_fee_parent = int(get_fee(tx_v2_0fee_parent["tx"].get_vsize(), minrelayfeerate) * COIN)
assert_equal(result_non_truc["tx-results"][tx_v2_0fee_parent["wtxid"]]["error"], f"min relay fee not met, 0 < {min_fee_parent}")
self.check_mempool([tx_v3_0fee_parent["txid"], tx_v3_child["txid"]])
else:
assert_equal(result_non_truc["package_msg"], "success")
self.check_mempool([tx_v2_0fee_parent["txid"], tx_v2_child["txid"], tx_v3_0fee_parent["txid"], tx_v3_child["txid"]])
def run_test(self):
self.log.info("Generate blocks to create UTXOs")
node = self.nodes[0]
self.wallet = MiniWallet(node)
self.generate(self.wallet, 120)
self.generate(self.wallet, 200)
self.test_truc_max_vsize()
self.test_truc_acceptance()
self.test_truc_replacement()
@@ -641,6 +700,7 @@ class MempoolTRUC(BitcoinTestFramework):
self.test_reorg_2child_rbf()
self.test_truc_sibling_eviction()
self.test_reorg_sibling_eviction_1p2c()
self.test_minrelay_in_package_combos()
if __name__ == "__main__":

View File

@@ -28,6 +28,7 @@ from test_framework.p2p import P2PDataStore
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_greater_than,
assert_greater_than_or_equal,
assert_raises_rpc_error,
get_fee,
@@ -40,7 +41,7 @@ MAX_FUTURE_BLOCK_TIME = 2 * 3600
MAX_TIMEWARP = 600
VERSIONBITS_TOP_BITS = 0x20000000
VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT = 28
DEFAULT_BLOCK_MIN_TX_FEE = 1000 # default `-blockmintxfee` setting [sat/kvB]
DEFAULT_BLOCK_MIN_TX_FEE = 1 # default `-blockmintxfee` setting [sat/kvB]
def assert_template(node, block, expect, rehash=True):
@@ -86,7 +87,7 @@ class MiningTest(BitcoinTestFramework):
node = self.nodes[0]
# test default (no parameter), zero and a bunch of arbitrary blockmintxfee rates [sat/kvB]
for blockmintxfee_sat_kvb in (DEFAULT_BLOCK_MIN_TX_FEE, 0, 50, 100, 500, 2500, 5000, 21000, 333333, 2500000):
for blockmintxfee_sat_kvb in (DEFAULT_BLOCK_MIN_TX_FEE, 0, 5, 10, 50, 100, 500, 1000, 2500, 5000, 21000, 333333, 2500000):
blockmintxfee_btc_kvb = blockmintxfee_sat_kvb / Decimal(COIN)
if blockmintxfee_sat_kvb == DEFAULT_BLOCK_MIN_TX_FEE:
self.log.info(f"-> Default -blockmintxfee setting ({blockmintxfee_sat_kvb} sat/kvB)...")
@@ -97,19 +98,27 @@ class MiningTest(BitcoinTestFramework):
self.wallet.rescan_utxos() # to avoid spending outputs of txs that are not in mempool anymore after restart
# submit one tx with exactly the blockmintxfee rate, and one slightly below
tx_with_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb)
tx_with_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb, confirmed_only=True)
assert_equal(tx_with_min_feerate["fee"], get_fee(tx_with_min_feerate["tx"].get_vsize(), blockmintxfee_btc_kvb))
if blockmintxfee_btc_kvb > 0:
if blockmintxfee_sat_kvb > 5:
lowerfee_btc_kvb = blockmintxfee_btc_kvb - Decimal(10)/COIN # 0.01 sat/vbyte lower
tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=lowerfee_btc_kvb)
tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=lowerfee_btc_kvb, confirmed_only=True)
assert_equal(tx_below_min_feerate["fee"], get_fee(tx_below_min_feerate["tx"].get_vsize(), lowerfee_btc_kvb))
else: # go below zero fee by using modified fees
tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb)
tx_below_min_feerate = self.wallet.send_self_transfer(from_node=node, fee_rate=blockmintxfee_btc_kvb, confirmed_only=True)
node.prioritisetransaction(tx_below_min_feerate["txid"], 0, -1)
# check that tx below specified fee-rate is neither in template nor in the actual block
block_template = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
block_template_txids = [tx['txid'] for tx in block_template['transactions']]
# Unless blockmintxfee is 0, the template shouldn't contain free transactions.
# Note that the real block assembler uses package feerates, but we didn't create dependent transactions so it's ok to use base feerate.
if blockmintxfee_btc_kvb > 0:
for txid in block_template_txids:
tx = node.getmempoolentry(txid)
assert_greater_than(tx['fees']['base'], 0)
self.generate(self.wallet, 1, sync_fun=self.no_op)
block = node.getblock(node.getbestblockhash(), verbosity=2)
block_txids = [tx['txid'] for tx in block['tx']]

View File

@@ -13,9 +13,11 @@ from decimal import Decimal
from math import ceil
from test_framework.mempool_util import (
DEFAULT_MIN_RELAY_TX_FEE,
fill_mempool,
)
from test_framework.messages import (
COIN,
msg_tx,
)
from test_framework.p2p import (
@@ -31,9 +33,6 @@ from test_framework.wallet import (
MiniWalletMode,
)
# 1sat/vB feerate denominated in BTC/KvB
FEERATE_1SAT_VB = Decimal("0.00001000")
class PackageRelayTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
@@ -49,17 +48,14 @@ class PackageRelayTest(BitcoinTestFramework):
def raise_network_minfee(self):
fill_mempool(self, self.nodes[0])
self.log.debug("Wait for the network to sync mempools")
self.sync_mempools()
self.log.debug("Check that all nodes' mempool minimum feerates are above min relay feerate")
for node in self.nodes:
assert_equal(node.getmempoolinfo()['minrelaytxfee'], FEERATE_1SAT_VB)
assert_greater_than(node.getmempoolinfo()['mempoolminfee'], FEERATE_1SAT_VB)
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN)
assert_greater_than(node.getmempoolinfo()['mempoolminfee'], Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN)
def create_basic_1p1c(self, wallet):
low_fee_parent = wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB, confirmed_only=True)
high_fee_child = wallet.create_self_transfer(utxo_to_spend=low_fee_parent["new_utxo"], fee_rate=999*FEERATE_1SAT_VB)
low_fee_parent = wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN, confirmed_only=True)
high_fee_child = wallet.create_self_transfer(utxo_to_spend=low_fee_parent["new_utxo"], fee_rate=999*Decimal(DEFAULT_MIN_RELAY_TX_FEE)/ COIN)
package_hex_basic = [low_fee_parent["hex"], high_fee_child["hex"]]
return package_hex_basic, low_fee_parent["tx"], high_fee_child["tx"]
@@ -90,8 +86,8 @@ class PackageRelayTest(BitcoinTestFramework):
return [low_fee_parent_2outs["hex"], high_fee_child_2outs["hex"]], low_fee_parent_2outs["tx"], high_fee_child_2outs["tx"]
def create_package_2p1c(self, wallet):
parent1 = wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB*10, confirmed_only=True)
parent2 = wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB*20, confirmed_only=True)
parent1 = wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN * 10, confirmed_only=True)
parent2 = wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN * 20, confirmed_only=True)
child = wallet.create_self_transfer_multi(
utxos_to_spend=[parent1["new_utxo"], parent2["new_utxo"]],
fee_per_output=999*parent1["tx"].get_vsize(),

View File

@@ -28,8 +28,8 @@ from test_framework.p2p import (
)
from test_framework.test_framework import BitcoinTestFramework
MAX_FEE_FILTER = Decimal(9170997) / COIN
NORMAL_FEE_FILTER = Decimal(100) / COIN
MAX_FEE_FILTER = Decimal(9936506) / COIN
NORMAL_FEE_FILTER = Decimal(10) / COIN
class P2PIBDTxRelayTest(BitcoinTestFramework):
@@ -37,8 +37,8 @@ class P2PIBDTxRelayTest(BitcoinTestFramework):
self.setup_clean_chain = True
self.num_nodes = 2
self.extra_args = [
["-minrelaytxfee={}".format(NORMAL_FEE_FILTER)],
["-minrelaytxfee={}".format(NORMAL_FEE_FILTER)],
["-minrelaytxfee={:.8f}".format(NORMAL_FEE_FILTER)],
["-minrelaytxfee={:.8f}".format(NORMAL_FEE_FILTER)],
]
def run_test(self):

View File

@@ -9,10 +9,12 @@ Test opportunistic 1p1c package submission logic.
from decimal import Decimal
import time
from test_framework.mempool_util import (
DEFAULT_MIN_RELAY_TX_FEE,
fill_mempool,
)
from test_framework.messages import (
CInv,
COIN,
CTxInWitness,
MAX_BIP125_RBF_SEQUENCE,
MSG_WTX,
@@ -65,13 +67,13 @@ class PackageRelayTest(BitcoinTestFramework):
self.supports_cli = False
def create_tx_below_mempoolminfee(self, wallet):
"""Create a 1-input 1sat/vB transaction using a confirmed UTXO. Decrement and use
"""Create a 1-input 0.1sat/vB transaction using a confirmed UTXO. Decrement and use
self.sequence so that subsequent calls to this function result in unique transactions."""
self.sequence -= 1
assert_greater_than(self.nodes[0].getmempoolinfo()["mempoolminfee"], FEERATE_1SAT_VB)
assert_greater_than(self.nodes[0].getmempoolinfo()["mempoolminfee"], Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN)
return wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB, sequence=self.sequence, confirmed_only=True)
return wallet.create_self_transfer(fee_rate=Decimal(DEFAULT_MIN_RELAY_TX_FEE) / COIN, sequence=self.sequence, confirmed_only=True)
@cleanup
def test_basic_child_then_parent(self):

View File

@@ -250,7 +250,7 @@ class TxDownloadTest(BitcoinTestFramework):
def test_rejects_filter_reset(self):
self.log.info('Check that rejected tx is not requested again')
node = self.nodes[0]
fill_mempool(self, node)
fill_mempool(self, node, tx_sync_fun=self.no_op)
self.wallet.rescan_utxos()
mempoolminfee = node.getmempoolinfo()['mempoolminfee']
peer = node.add_p2p_connection(TestP2PConn())

View File

@@ -6,20 +6,18 @@
Utilities for working directly with the wallet's BDB database file
This is specific to the configuration of BDB used in this project:
- pagesize: 4096 bytes
- Outer database contains single subdatabase named 'main'
- btree
- btree leaf pages
- btree internal, leaf and overflow pages
Each key-value pair is two entries in a btree leaf. The first is the key, the one that follows
Each key-value pair is two entries in a btree leaf, which optionally refers to overflow pages
if the data doesn't fit into a single page. The first entry is the key, the one that follows
is the value. And so on. Note that the entry data is itself not in the correct order. Instead
entry offsets are stored in the correct order and those offsets are needed to then retrieve
the data itself.
the data itself. Note that this implementation currently only supports reading databases that
are in the same endianness as the host.
Page format can be found in BDB source code dbinc/db_page.h
This only implements the deserialization of btree metadata pages and normal btree pages. Overflow
pages are not implemented but may be needed in the future if dealing with wallets with large
transactions.
`db_dump -da wallet.dat` is useful to see the data in a wallet.dat BDB file
"""
@@ -27,23 +25,36 @@ transactions.
import struct
# Important constants
PAGESIZE = 4096
PAGE_HEADER_SIZE = 26
OUTER_META_PAGE = 0
INNER_META_PAGE = 2
# Page type values
BTREE_INTERNAL = 3
BTREE_LEAF = 5
OVERFLOW_DATA = 7
BTREE_META = 9
# Record type values
RECORD_KEYDATA = 1
RECORD_OVERFLOW_DATA = 3
# Some magic numbers for sanity checking
BTREE_MAGIC = 0x053162
DB_VERSION = 9
SUBDATABASE_NAME = b'main'
# Deserializes a leaf page into a dict.
# Btree internal pages have the same header, for those, return None.
# For the btree leaf pages, deserialize them and put all the data into a dict
def dump_leaf_page(data):
# Deserializes an internal, leaf or overflow page into a dict.
# In addition to the common page header fields, the result contains an 'entries'
# array of dicts with the following fields, depending on the page type:
# internal page [BTREE_INTERNAL]:
# - 'page_num': referenced page number (used to find further pages to process)
# leaf page [BTREE_LEAF]:
# - 'record_type': record type, must be RECORD_KEYDATA or RECORD_OVERFLOW_DATA
# - 'data': binary data (key or value payload), if record type is RECORD_KEYDATA
# - 'page_num': referenced overflow page number, if record type is RECORD_OVERFLOW_DATA
# overflow page [OVERFLOW_DATA]:
# - 'data': binary data (part of key or value payload)
def dump_page(data):
page_info = {}
page_header = data[0:26]
_, pgno, prev_pgno, next_pgno, entries, hf_offset, level, pg_type = struct.unpack('QIIIHHBB', page_header)
@@ -56,20 +67,35 @@ def dump_leaf_page(data):
page_info['entry_offsets'] = struct.unpack('{}H'.format(entries), data[26:26 + entries * 2])
page_info['entries'] = []
if pg_type == BTREE_INTERNAL:
# Skip internal pages. These are the internal nodes of the btree and don't contain anything relevant to us
return None
assert pg_type in (BTREE_INTERNAL, BTREE_LEAF, OVERFLOW_DATA)
assert pg_type == BTREE_LEAF, 'A non-btree leaf page has been encountered while dumping leaves'
if pg_type == OVERFLOW_DATA:
assert entries == 1
page_info['entries'].append({'data': data[26:26 + hf_offset]})
return page_info
for i in range(0, entries):
entry = {}
offset = page_info['entry_offsets'][i]
entry = {'offset': offset}
page_data_header = data[offset:offset + 3]
e_len, pg_type = struct.unpack('HB', page_data_header)
entry['len'] = e_len
entry['pg_type'] = pg_type
entry['data'] = data[offset + 3:offset + 3 + e_len]
record_header = data[offset:offset + 3]
offset += 3
e_len, record_type = struct.unpack('HB', record_header)
if pg_type == BTREE_INTERNAL:
assert record_type == RECORD_KEYDATA
internal_record_data = data[offset:offset + 9]
_, page_num, _ = struct.unpack('=BII', internal_record_data)
entry['page_num'] = page_num
elif pg_type == BTREE_LEAF:
assert record_type in (RECORD_KEYDATA, RECORD_OVERFLOW_DATA)
entry['record_type'] = record_type
if record_type == RECORD_KEYDATA:
entry['data'] = data[offset:offset + e_len]
elif record_type == RECORD_OVERFLOW_DATA:
overflow_record_data = data[offset:offset + 9]
_, page_num, _ = struct.unpack('=BII', overflow_record_data)
entry['page_num'] = page_num
page_info['entries'].append(entry)
return page_info
@@ -115,16 +141,27 @@ def dump_meta_page(page):
return metadata
# Given the dict from dump_leaf_page, get the key-value pairs and put them into a dict
def extract_kv_pairs(page_data):
def extract_kv_pairs(page_data, pages):
out = {}
last_key = None
for i, entry in enumerate(page_data['entries']):
data = b''
if entry['record_type'] == RECORD_KEYDATA:
data = entry['data']
elif entry['record_type'] == RECORD_OVERFLOW_DATA:
next_page = entry['page_num']
while next_page != 0:
opage = pages[next_page]
opage_info = dump_page(opage)
data += opage_info['entries'][0]['data']
next_page = opage_info['next_pgno']
# By virtue of these all being pairs, even number entries are keys, and odd are values
if i % 2 == 0:
out[entry['data']] = b''
last_key = entry['data']
last_key = data
else:
out[last_key] = entry['data']
out[last_key] = data
return out
# Extract the key-value pairs of the BDB file given in filename
@@ -132,20 +169,42 @@ def dump_bdb_kv(filename):
# Read in the BDB file and start deserializing it
pages = []
with open(filename, 'rb') as f:
data = f.read(PAGESIZE)
# Determine pagesize first
data = f.read(PAGE_HEADER_SIZE)
pagesize = struct.unpack('I', data[20:24])[0]
assert pagesize in (512, 1024, 2048, 4096, 8192, 16384, 32768, 65536)
# Read rest of first page
data += f.read(pagesize - PAGE_HEADER_SIZE)
assert len(data) == pagesize
# Read all remaining pages
while len(data) > 0:
pages.append(data)
data = f.read(PAGESIZE)
data = f.read(pagesize)
# Sanity check the meta pages
dump_meta_page(pages[OUTER_META_PAGE])
dump_meta_page(pages[INNER_META_PAGE])
# Sanity check the meta pages, read root page
outer_meta_info = dump_meta_page(pages[OUTER_META_PAGE])
root_page_info = dump_page(pages[outer_meta_info['root']])
assert root_page_info['pg_type'] == BTREE_LEAF
assert len(root_page_info['entries']) == 2
assert root_page_info['entries'][0]['data'] == SUBDATABASE_NAME
assert len(root_page_info['entries'][1]['data']) == 4
inner_meta_page = int.from_bytes(root_page_info['entries'][1]['data'], 'big')
inner_meta_info = dump_meta_page(pages[inner_meta_page])
# Fetch the kv pairs from the leaf pages
# Fetch the kv pairs from the pages
kv = {}
for i in range(3, len(pages)):
info = dump_leaf_page(pages[i])
if info is not None:
info_kv = extract_kv_pairs(info)
pages_to_process = [inner_meta_info['root']]
while len(pages_to_process) > 0:
curr_page_no = pages_to_process.pop()
assert curr_page_no <= outer_meta_info['last_pgno']
info = dump_page(pages[curr_page_no])
assert info['pg_type'] in (BTREE_INTERNAL, BTREE_LEAF)
if info['pg_type'] == BTREE_INTERNAL:
for entry in info['entries']:
pages_to_process.append(entry['page_num'])
elif info['pg_type'] == BTREE_LEAF:
info_kv = extract_kv_pairs(info, pages)
kv = {**kv, **info_kv}
return kv

View File

@@ -3,7 +3,6 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Helpful routines for mempool testing."""
from decimal import Decimal
from .blocktools import (
COINBASE_MATURITY,
@@ -18,24 +17,23 @@ from .wallet import (
MiniWallet,
)
# Default for -minrelaytxfee in sat/kvB
DEFAULT_MIN_RELAY_TX_FEE = 100
# Default for -incrementalrelayfee in sat/kvB
DEFAULT_INCREMENTAL_RELAY_FEE = 100
def fill_mempool(test_framework, node):
def fill_mempool(test_framework, node, *, tx_sync_fun=None):
"""Fill mempool until eviction.
Allows for simpler testing of scenarios with floating mempoolminfee > minrelay
Requires -datacarriersize=100000 and
-maxmempool=5.
It will not ensure mempools become synced as it
is based on a single node and assumes -minrelaytxfee
is 1 sat/vbyte.
Requires -datacarriersize=100000 and -maxmempool=5 and assumes -minrelaytxfee
is 100 sat/kvB.
To avoid unintentional tx dependencies, the mempool filling txs are created with a
tagged ephemeral miniwallet instance.
"""
test_framework.log.info("Fill the mempool until eviction is triggered and the mempoolminfee rises")
txouts = gen_return_txouts()
relayfee = node.getnetworkinfo()['relayfee']
assert_equal(relayfee, Decimal('0.00001000'))
minrelayfee = node.getnetworkinfo()['relayfee']
tx_batch_size = 1
num_of_batches = 75
@@ -55,20 +53,27 @@ def fill_mempool(test_framework, node):
test_framework.log.debug("Create a mempool tx that will be evicted")
tx_to_be_evicted_id = ephemeral_miniwallet.send_self_transfer(
from_node=node, utxo_to_spend=confirmed_utxos.pop(0), fee_rate=relayfee)["txid"]
from_node=node, utxo_to_spend=confirmed_utxos.pop(0), fee_rate=minrelayfee)["txid"]
def send_batch(fee):
utxos = confirmed_utxos[:tx_batch_size]
create_lots_of_big_transactions(ephemeral_miniwallet, node, fee, tx_batch_size, txouts, utxos)
del confirmed_utxos[:tx_batch_size]
# Increase the tx fee rate to give the subsequent transactions a higher priority in the mempool
# The tx has an approx. vsize of 65k, i.e. multiplying the previous fee rate (in sats/kvB)
# by 130 should result in a fee that corresponds to 2x of that fee rate
base_fee = relayfee * 130
base_fee = minrelayfee * 130
batch_fees = [(i + 1) * base_fee for i in range(num_of_batches)]
test_framework.log.debug("Fill up the mempool with txs with higher fee rate")
with node.assert_debug_log(["rolling minimum fee bumped"]):
for batch_of_txid in range(num_of_batches):
fee = (batch_of_txid + 1) * base_fee
utxos = confirmed_utxos[:tx_batch_size]
create_lots_of_big_transactions(ephemeral_miniwallet, node, fee, tx_batch_size, txouts, utxos)
del confirmed_utxos[:tx_batch_size]
for fee in batch_fees[:-3]:
send_batch(fee)
tx_sync_fun() if tx_sync_fun else test_framework.sync_mempools() # sync before any eviction
assert_equal(node.getmempoolinfo()["mempoolminfee"], minrelayfee)
for fee in batch_fees[-3:]:
send_batch(fee)
tx_sync_fun() if tx_sync_fun else test_framework.sync_mempools() # sync after all evictions
test_framework.log.debug("The tx should be evicted by now")
# The number of transactions created should be greater than the ones present in the mempool
@@ -77,5 +82,5 @@ def fill_mempool(test_framework, node):
assert tx_to_be_evicted_id not in node.getrawmempool()
test_framework.log.debug("Check that mempoolminfee is larger than minrelaytxfee")
assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
assert_greater_than(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))
assert_equal(node.getmempoolinfo()['minrelaytxfee'], minrelayfee)
assert_greater_than(node.getmempoolinfo()['mempoolminfee'], minrelayfee)

View File

@@ -130,26 +130,14 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
try:
self.setup()
self.run_test()
except JSONRPCException:
self.log.exception("JSONRPC error")
self.success = TestStatus.FAILED
except SkipTest as e:
self.log.warning("Test Skipped: %s" % e.message)
self.success = TestStatus.SKIPPED
except AssertionError:
self.log.exception("Assertion failed")
self.success = TestStatus.FAILED
except KeyError:
self.log.exception("Key error")
self.success = TestStatus.FAILED
except subprocess.CalledProcessError as e:
self.log.exception("Called Process failed with '{}'".format(e.output))
self.log.exception(f"Called Process failed with stdout='{e.stdout}'; stderr='{e.stderr}';")
self.success = TestStatus.FAILED
except Exception:
self.log.exception("Unexpected exception caught during testing")
self.success = TestStatus.FAILED
except KeyboardInterrupt:
self.log.warning("Exiting after keyboard interrupt")
except BaseException:
self.log.exception("Unexpected exception")
self.success = TestStatus.FAILED
finally:
exit_code = self.shutdown()

View File

@@ -914,6 +914,8 @@ class TestNodeCLI():
# Ignore cli_stdout, raise with cli_stderr
raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr)
try:
if not cli_stdout.strip():
return None
return json.loads(cli_stdout, parse_float=decimal.Decimal)
except (json.JSONDecodeError, decimal.InvalidOperation):
return cli_stdout.rstrip("\n")

View File

@@ -301,6 +301,13 @@ def wait_until_helper_internal(predicate, *, attempts=float('inf'), timeout=floa
raise RuntimeError('Unreachable')
def bpf_cflags():
return [
"-Wno-error=implicit-function-declaration",
"-Wno-duplicate-decl-specifier", # https://github.com/bitcoin/bitcoin/issues/32322
]
def sha256sum_file(filename):
h = hashlib.sha256()
with open(filename, 'rb') as f:

View File

@@ -6,18 +6,23 @@
import os
import platform
import random
import stat
import string
import subprocess
import textwrap
from collections import OrderedDict
from test_framework.bdb import dump_bdb_kv
from test_framework.messages import ser_string
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
assert_greater_than,
sha256sum_file,
)
from test_framework.wallet import getnewdestination
class ToolWalletTest(BitcoinTestFramework):
@@ -545,6 +550,44 @@ class ToolWalletTest(BitcoinTestFramework):
self.stop_node(0)
self.assert_tool_output("The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n", "-wallet=unclean_lsn", f"-dumpfile={wallet_dump}", "dump")
def test_compare_legacy_dump_with_framework_bdb_parser(self):
self.log.info("Verify that legacy wallet database dump matches the one from the test framework's BDB parser")
wallet_name = "bdb_ro_test"
self.start_node(0)
# add some really large labels (above twice the largest valid page size) to create BDB overflow pages
self.nodes[0].createwallet(wallet_name)
wallet_rpc = self.nodes[0].get_wallet_rpc(wallet_name)
generated_labels = {}
for i in range(10):
address = getnewdestination()[2]
large_label = ''.join([random.choice(string.ascii_letters) for _ in range(150000)])
wallet_rpc.setlabel(address, large_label)
generated_labels[address] = large_label
# fill the keypool to create BDB internal pages
wallet_rpc.keypoolrefill(1000)
self.stop_node(0)
wallet_dumpfile = self.nodes[0].datadir_path / "bdb_ro_test.dump"
self.assert_tool_output("The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n", "-wallet={}".format(wallet_name), "-dumpfile={}".format(wallet_dumpfile), "dump")
expected_dump = self.read_dump(wallet_dumpfile)
# remove extra entries from wallet tool dump that are not actual key/value pairs from the database
del expected_dump['BITCOIN_CORE_WALLET_DUMP']
del expected_dump['format']
del expected_dump['checksum']
bdb_ro_parser_dump_raw = dump_bdb_kv(self.nodes[0].wallets_path / wallet_name / "wallet.dat")
bdb_ro_parser_dump = OrderedDict()
assert any([len(bytes.fromhex(value)) >= 150000 for value in expected_dump.values()])
for key, value in sorted(bdb_ro_parser_dump_raw.items()):
bdb_ro_parser_dump[key.hex()] = value.hex()
assert_equal(bdb_ro_parser_dump, expected_dump)
# check that all labels were created with the correct address
for address, label in generated_labels.items():
key_bytes = b'\x04name' + ser_string(address.encode())
assert key_bytes in bdb_ro_parser_dump_raw
assert_equal(bdb_ro_parser_dump_raw[key_bytes], ser_string(label.encode()))
def run_test(self):
self.wallet_path = self.nodes[0].wallets_path / self.default_wallet_name / self.wallet_data_filename
self.test_invalid_tool_commands_and_args()
@@ -561,6 +604,9 @@ class ToolWalletTest(BitcoinTestFramework):
self.test_dump_createfromdump()
self.test_chainless_conflicts()
self.test_dump_very_large_records()
if not self.options.descriptors and self.is_bdb_compiled() and not self.options.swap_bdb_endian:
self.test_compare_legacy_dump_with_framework_bdb_parser()
if __name__ == '__main__':
ToolWalletTest(__file__).main()

View File

@@ -534,7 +534,7 @@ def test_dust_to_fee(self, rbf_node, dest_address):
def test_settxfee(self, rbf_node, dest_address):
self.log.info('Test settxfee')
assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee", rbf_node.settxfee, Decimal('0.000005'))
assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee", rbf_node.settxfee, Decimal('0.0000005'))
assert_raises_rpc_error(-8, "txfee cannot be less than wallet min fee", rbf_node.settxfee, Decimal('0.000015'))
# check that bumpfee reacts correctly to the use of settxfee (paytxfee)
rbfid = spend_one_input(rbf_node, dest_address)
@@ -846,7 +846,7 @@ def test_bumpfee_with_feerate_ignores_walletincrementalrelayfee(self, rbf_node,
# Ensure you can not fee bump if the fee_rate is more than original fee_rate but the total fee from new fee_rate is
# less than (original fee + incrementalrelayfee)
assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 2.8})
assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 2.05})
# You can fee bump as long as the new fee set from fee_rate is at least (original fee + incrementalrelayfee)
rbf_node.bumpfee(tx["txid"], {"fee_rate": 3})

View File

@@ -44,6 +44,9 @@ class RawTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 4
self.extra_args = [[
"-minrelaytxfee=0.00001000",
] for i in range(self.num_nodes)]
self.setup_clean_chain = True
# whitelist peers to speed up tx relay / mempool sync
self.noban_tx_relay = True