Compare commits

...

167 Commits

Author SHA1 Message Date
TheCharlatan 4fce466d1a
kernel: Fix bitcoin-chainstate for windows
And turn it on in the CI.
2025-10-08 18:59:46 +02:00
TheCharlatan 1db7bde6d2
kernel: Add Purpose section to header documentation 2025-10-08 18:59:45 +02:00
TheCharlatan 2db540a173
kernel: Allowing reducing exports
Now that an API has been defined, remove the override for symbol
visibility of the library. It is now possible to build the library with
reduced exports.
2025-10-08 18:59:44 +02:00
TheCharlatan 79d3f30ebe
kernel: Add pure kernel bitcoin-chainstate
Re-write the bitcoin-chainstate utility by only using the kernel C++ API
header instead of internal Bitcoin Core code.
2025-10-08 18:59:43 +02:00
TheCharlatan 7918a4d17d
Kernel: Add functions for working with outpoints
This introduces the transaction outpoint, input and id types. This now
allows a user to retrieve a transaction output from a prior transaction
that a transaction outpoint is pointing to.

This is exercised in the tests by verifying the script of every
transaction in the test chain.
2025-10-08 18:59:42 +02:00
TheCharlatan 00000cb55a
kernel: Add block hash type and block tree utility functions to C header
Introduce btck_BlockHash as a type-safe identifier for a block. Adds
functions to retrieve block tree entries by hash or height, get block
hashes and heights from entries. access the genesis block, and check if
blocks are in the active chain.
2025-10-08 18:59:42 +02:00
TheCharlatan d9d040fd16
kernel: Add function to read block undo data from disk to C header
This adds functions for reading the undo data from disk with a retrieved
block tree entry. The undo data of a block contains all the spent
script pubkeys of all the transactions in a block. For ease of
understanding the undo data is renamed to spent outputs with seperate
data structures exposed for a block's and a transaction's spent outputs.

In normal operations undo data is used during re-orgs. This data might
also be useful for building external indexes, or to scan for silent
payment transactions.

Internally the block undo data contains a vector of transaction undo
data which contains a vector of the coins consumed. The coins are all
int the order of the transaction inputs of the consuming transactions.
Each coin can be used to retrieve a transaction output and in turn a
script pubkey and amount.

This translates to the three-level hierarchy the api provides: Block
spent outputs contain transaction spent outputs, which contain
individual coins. Each coin includes the associated output, the height
of the block is contained in, and whether it is from a coinbase
transaction.
2025-10-08 18:59:41 +02:00
TheCharlatan 3a2b8d855d
kernel: Add functions to read block from disk to C header
This adds functions for reading a block from disk with a retrieved block
tree entry. External services that wish to build their own index, or
analyze blocks can use this to retrieve block data.

The block tree can now be traversed from the tip backwards. This is
guaranteed to work, since the chainstate maintains an internal block
tree index in memory and every block (besides the genesis) has an
ancestor.

The user can use this function to iterate through all blocks in the
chain (starting from the tip). The tip is retrieved from a separate
`Chain` object, which allows distinguishing whether entries are
currently in the best chain. Once the block tree entry for the genesis
block is reached a nullptr is returned if the user attempts to get the
previous entry.
2025-10-08 18:59:40 +02:00
TheCharlatan e3d4d2461e
kernel: Add function for copying block data to C header
This adds a function for streaming bytes into a user-owned data
structure.

Use it in the tests for verifying the implementation of the validation
interface's `BlockChecked` method.
2025-10-08 18:59:39 +02:00
TheCharlatan fbbec31efc
kernel: Add functions for the block validation state to C header
These allow for the interpretation of the data in a `BlockChecked`
validation interface callback. The validation state passed through
`BlockChecked` is the source of truth for the validity of a block (the
mode). It is
also useful to get richer information in case a block failed to
validate (the result).
2025-10-08 18:59:38 +02:00
TheCharlatan 403fb9b120
kernel: Add validation interface to C header
This adds the infrastructure required to process validation events. For
now the external validation interface only has support for the
`BlockChecked` , `NewPoWValidBlock`, `BlockConnected`, and
`BlockDisconnected` callback. Support for the other internal
validation interface methods can be added in the future.

The validation interface follows an architecture for defining its
callbacks and ownership that is similar to the notifications.

The task runner is created internally with a context, which itself
internally creates a unique ValidationSignals object. When the user
creates a new chainstate manager the validation signals are internally
passed to the chainstate manager through the context.

The callbacks block any further validation execution when they are
called. It is up to the user to either multiplex them, or use them
otherwise in a multithreaded mechanism to make processing the validation
events non-blocking.

A validation interface can register for validation events with a
context. Internally the passed in validation interface is registerd with
the validation signals of a context.
2025-10-08 18:59:37 +02:00
TheCharlatan 8d9088c5db
kernel: Add interrupt function to C header
Calling interrupt can halt long-running functions associated with
objects that were created through the passed-in context.
2025-10-08 18:59:36 +02:00
TheCharlatan 0459e9ac29
kernel: Add import blocks function to C header
Add `btck_import_blocks` to import block data and rebuild indexes. The
function can either reindex all existing block files if the indexes were
previously wiped through the chainstate load options, or import blocks
from a single specified file path.
2025-10-08 18:59:35 +02:00
TheCharlatan 41f81149c8
kernel: Add chainstate load options for in-memory dbs in C header
This allows a user to run the kernel without creating on-disk files for
the block tree and chainstate indexes. This is potentially useful in
scenarios where the user needs to do some ephemeral validation
operations.

One specific use case is when linearizing the blocks on disk. The block
files store blocks out of order, so a program may utilize the library
and its header to read the blocks with one chainstate manager, and then
write them back in order, and without orphans, with another chainstate
maanger. To save disk resources and if the indexes are not required once
done, it may be beneficial to keep the indexes in memory for the
chainstate manager that writes the blocks back again.
2025-10-08 18:59:34 +02:00
TheCharlatan 57a2b40476
kernel: Add options for reindexing in C header
Adds options for wiping the chainstate and block tree indexes to the
chainstate load options. In combination and once the
`*_import_blocks(...)` function is added in a later commit, this
triggers a reindex. For now, it just wipes the existing data.
2025-10-08 18:59:33 +02:00
TheCharlatan 42c106df05
kernel: Add block validation to C header
The added function allows the user process and validate a given block
with the chainstate manager. The *_process_block(...) function does some
preliminary checks on the block before passing it to
`ProcessNewBlock(...)`. These are similar to the checks in the
`submitblock()` rpc.

Richer processing of the block validation result will be made available
in the following commits through the validation interface.

The commits also adds a utility for deserializing a `CBlock`
(`kernel_block_create()`) that may then be passed to the library for
processing.

The tests exercise the function for both mainnet and regtest. The
commit also adds the data of 206 regtest blocks (some blocks also
contain transactions).
2025-10-08 18:59:32 +02:00
TheCharlatan 6b1ee82417
kernel: Add chainstate loading when instantiating a ChainstateManager
The library will now internally load the chainstate when a new
ChainstateManager is instantiated.

Options for controlling details of loading the chainstate will be added
over the next few commits.
2025-10-08 18:59:32 +02:00
TheCharlatan 783db175aa
kernel: Add chainstate manager option for setting worker threads
Re-use the same pattern used for the context options. This allows users
to set the number of threads used in the validation thread pool.
2025-10-08 18:59:31 +02:00
TheCharlatan dee984def6
kernel: Add chainstate manager object to C header
This is the main driver class for anything validation related, so expose
it here.

Creating the chainstate manager options will currently also trigger the
creation of their respectively configured directories.

The chainstate manager and block manager options are consolidated into a
single object. The kernel might eventually introduce a separate block
manager object for the purposes of being a light-weight block store
reader.

The chainstate manager will associate with the context with which it was
created for the duration of its lifetime. It is only valid if that
context remains in memory too.

The tests now also create dedicated temporary directories. This is
similar to the behaviour in the existing unit test framework.

Co-authored-by: stickies-v <stickies-v@protonmail.com>
2025-10-08 18:59:30 +02:00
TheCharlatan 96651a3f86
kernel: Add notifications context option to C header
The notifications are used for notifying on connected blocks and on
warning and fatal error conditions.

The user of the C header may define callbacks that gets passed to the
internal notification object in the
`kernel_NotificationInterfaceCallbacks` struct.

Each of the callbacks take a `user_data` argument that gets populated
from the `user_data` value in the struct. It can be used to recreate the
structure containing the callbacks on the user's side, or to give the
callbacks additional contextual information.
2025-10-08 18:59:29 +02:00
TheCharlatan 86cd091d74
kernel: Add chain params context option to C header
As a first option, add the chainparams. For now these can only be
instantiated with default values. In future they may be expanded to take
their own options for regtest and signet configurations.

This commit also introduces a unique pattern for setting the option
values when calling the `*_set(...)` function.
2025-10-08 18:59:28 +02:00
TheCharlatan cc89fcc6da
kernel: Add kernel library context object
The context introduced here holds the objects that will be required for
running validation tasks, such as the chosen chain parameters, callbacks
for validation events, and interrupt handling. These will be used by the
chainstate manager introduced in subsequent commits.

This commit also introduces conventions for defining option objects. A
common pattern throughout the C header will be:
```
options = object_option_create();
object = object_create(options);
```
This allows for more consistent usage of a "builder pattern" for
objects where options can be configured independently from
instantiation.
2025-10-08 18:59:27 +02:00
TheCharlatan 4a0f6ba7a7
kernel: Add logging to kernel library C header
Exposing logging in the kernel library allows users to follow
operations. Users of the C header can use
`kernel_logging_connection_create(...)` to pass a callback function to
Bitcoin Core's internal logger. Additionally the level and category can
be globally configured.

By default, the logger buffers messages until
`kernel_loggin_connection_create(...)` is called. If the user does not
want any logging messages, it is recommended that
`kernel_disable_logging()` is called, which permanently disables the
logging and any buffering of messages.
2025-10-08 18:58:37 +02:00
TheCharlatan fcb0590623
kernel: Introduce initial kernel C header API
As a first step, implement the equivalent of what was implemented in the
now deprecated libbitcoinconsensus header. Also add a test binary to
exercise the header and library.

Unlike the deprecated libbitcoinconsensus the kernel library can now use
the hardware-accelerated sha256 implementations thanks for its
statically-initialzed context. The functions kept around for
backwards-compatibility in the libbitcoinconsensus header are not ported
over. As a new header, it should not be burdened by previous
implementations. Also add a new error code for handling invalid flag
combinations, which would otherwise cause a crash.

The macros used in the new C header were adapted from the libsecp256k1
header.

To make use of the C header from C++ code, a C++ header is also
introduced for wrapping the C header. This makes it safer and easier to
use from C++ code.

Co-authored-by: stickies-v <stickies-v@protonmail.com>
2025-10-08 18:58:29 +02:00
Ava Chow b510893d00
Merge bitcoin/bitcoin#33494: depends: Update URL for `qrencode` package source tarball
93a70a42d3 depends: Update URL for `qrencode` package source tarball (Hennadii Stepanov)
6de8051263 depends: Use hash instead of file name for package download stamp (Hennadii Stepanov)
46135d90ea depends: Drop redundant check for downloaded file (Hennadii Stepanov)
771978952a depends: Fix `$(package)_fetched` target (Hennadii Stepanov)

Pull request description:

  The https://fukuchi.org/ homepage no longer links to the source tarball, and previously available files appear to have been removed. The homepage now instructs users to download source tarballs from the GitHub [releases](https://github.com/fukuchi/libqrencode/releases) page instead.

  The diff between the source trees is immaterial:
  ```diff
  --- old
  +++ new
  @@ -1,19 +1,16 @@
   27e7deccd2925c94e4190ee64794a051199f215f145f76fd664cdebedbbf8a35  acinclude.m4
  -e1e35b1309482f699a9700a2065a0bce09c2108dd1f78ba7bfbe0f7f0bdcd2e6  aclocal.m4
   a9308eec78790720dbcd5452ab8f241b5f1c6939ccf3389917b8e78cb2b58c9e  autogen.sh
   aa36725d577048f0370dc7415a1acb578fbdfb531c1b384a836d9360a81f6f5c  bitstream.c
   3feaacd7d096834fc5956215598564ec287ad443185c4433c3f8007cc53ceaa6  bitstream.h
   21bd5a34c90d3d6ee540ceb48c3d5aea5f21bd6b829ef3112db832af0bd423d8  ChangeLog
   f8a7a94c9622fab721df47e8121533ebfcb79885aca01ecec2fff00dfb84caef  cmake/FindIconv.cmake
   6345e7eecb92473f361a8eb98dd373aa09cae79a43408cf4b42b00b411c9c197  CMakeLists.txt
  -031d560570eab2eda57c2f9ee9952445002f8bf4a23965fcaf43bbc2c61590e2  config.h.in
  -d2f42cc5771b69f2d2ecd4b31509864ae2b18b25c823986390bb372ee07030fa  configure
   02867a8ea08206c84d5f4c05f41a15c639291091e3dfac27f3a9029d8f5d3028  configure.ac
   a9bdde5616ecdd1e980b44f360600ee8783b1f99b8cc83a2beb163a0a390e861  COPYING
   76c41754bccbf69a60fb7833776637c60b86f59104705c0a5cea9ee3a2968f3d  Doxyfile
   36d84f714cf28397b02d6c44860106a7cb858fc6d25239a2698a72fa5136e5c3  libqrencode.pc.in
   f0ce93a7e1b1f0fab87dd071ec3c8dd80a567d778dfc5930d9f375d676ecb9a0  Makefile.am
  -507c2385fb49c5724e8e3dfca97feb24cbdd4e651f3f0bfa62524e60088091a0  Makefile.in
  +dcb782b1b382328c0bce9194944bdcc65a6035d8e9f89e39436ed2e55ae8b969  makeREADME.sh
   6046d347c6c564fc13a24dc0a15a09a83023e00a4e0d0f23029a81f86ac4d024  mask.c
   9f853cee7d72191a8dbf018b7a86c0f0b6ca661e27a51fab677af911f2ff9e7e  mask.h
   a4e17b68d8db573e152132ebcbdc837b55415c12027f81232662db645faf79f0  mmask.c
  @@ -30,7 +27,7 @@
   6e9ff66002b4a839c6e78bcd6a55342d9eb8b289273fa838441b27ee9969e293  qrinput.h
   68831e02ee1ba602b1937328abec000e616c4472d9dc40067dd45ab7072df172  qrspec.c
   a2a9a5af4d62015e82b48b8316aea2b70031dcdc1ed2b829c0102ea5dc02aca2  qrspec.h
  -8730d006f1d45b90dc0ef9a20e4119420f15b37a09483c929baa4225e21f7900  README
  +a56773b55989ea5cae8a43f2d845ce0afa9576a26170937fbe36a69fee953cd4  README.md
   ace480f2e16001e276c73a5e965c282915ad81e2c28cce3ef574b5a8db7210e8  rsecc.c
   c731ebe26d58d5e5df3b2d694de0fb1c4ae80a36cf0559c49b04e989dee8b182  rsecc.h
   8ed1af4414b5628845519581c82bf51ba2b4dee1f8352c1fd01b50afcd0a0ed7  split.c
  @@ -46,7 +43,6 @@
   e26b20198a7393b3c060891876fa45edb81488aef9df6d6cf45893a605e5e5e4  tests/decoder.h
   adabfbddb0f25de2e2cae970195fcfdf11ad1fa66ce64e237d83f821346f64c4  tests/frame
   23c283a3d3b5f1bbb3108603ebf05d7a95951ba86a288e09140eab612a5eb258  tests/Makefile.am
  -c8b819bf7f00c979ab0b6f0d0fb10289d2006bc6acda1737d2f1c383a60e1e66  tests/Makefile.in
   ebd71b937d4d39f382f8c57f362a01f11fd617b66dbdf6f1a3c4897c8c42e235  tests/prof_qrencode.c
   d4adcb234d4c31473cd9ffedd1bfa9645ba336d426640ba5893dfe6e75db171d  tests/pthread_qrencode.c
   62298641504b0a2c1d199cd7f656cb376959200169042de76f7c5950d2d42395  tests/rscode.c
  @@ -63,6 +59,7 @@
   cf5792cbfb92ba46f7f5f14b98f00813b0e7e4f5e7c790c6a28793774474bf26  tests/test_monkey.c
   3a2c58346d57f6bb2a634d6febf3c65ac524259a2d789657f8d60c678bf8d658  tests/test_mqrspec.c
   b9d8c569ba36a2258cb1ad0d1f85ce4fb2935fad519e902bade59aa9772321aa  tests/test_qrencode.c
  +785fe14a6f8bc096b20ec271771fb09f22f29eb4f9d729f5b40d6b4cc824ce36  tests/test_qrenc.sh
   d0eee6eddf98ee4595c07f7da40c7de548651bf839b26995756e94db2599451f  tests/test_qrinput.c
   ace7885e435ef77cc127da0ac23c724498aaa8d80d53b908063f79c9f0b7acce  tests/test_qrspec.c
   fde9c2735ce94be51e1b0bbffe65415aa3afd2da5bd4c0e2c5e50e1a2f1ea3f7  tests/test_rs.c
  @@ -71,12 +68,4 @@
   6f35c0e1235b31d0068c4ab175d8110c736e60df0309d4be7b3e57dd62d316f6  tests/URI_testset.inc
   6be3983fc397cd5dade1dd219ad6cbe7977f416410b1509984006ecec51605b5  tests/view_qrcode.c
   92b5be1ca2239399232d51503715c848dae9bf3db71b1f03157bfa9779826910  TODO
  -c8af04e62bad4ab75dafd22119026e5e3943f385bdcbe7731a4938102453754c  use/compile
  -1d9048b0ac9d4d1dfce7aa4e3a0b59ccfd32db2f7693814aa6f4c778560f5669  use/config.guess
   b522487f9c47661d321367d133f3d41247dd16d435f2d4b9c643dee95bf65eee  use/config.rpath
  -5bf0da2576ebb21ab60a9d9291a85b40af0e956a9eafb709ca8b20dcb105f4ee  use/config.sub
  -732bcd6b9e23f241e015d71b0a3a862104053aba20718c1f56b292cee7e29371  use/depcomp
  -608b76d735bb2ec2bcb1271644c3d5e7a428fb8d2338e114e8a48ebf91ccfd23  use/install-sh
  -2304d53af1f63b76a11651efdd18578adf2bda1ffc2c257100cba374b55f284b  use/ltmain.sh
  -f038345dab184e538098d22a8edc423762da66a90ebe269f23bfef85287cd30c  use/missing
  -7c1ae35455771ae32050c2ed109e3d297160b6d1a2f70b0278cf6968e5e7e98c  use/test-driver
  ```

  ---

  **UPDATE 2025-09-30**

  A few commits have been added:

  1. The first commit fixes the `$(package)_fetched` target, which erroneously succeeds on the second run after a failure on the master branch:
  ```
  $ gmake -C depends clean-all
  $ gmake -C depends qrencode_fetched FALLBACK_DOWNLOAD_PATH="https://fallback.invalid"
  $ gmake -C depends qrencode_fetched FALLBACK_DOWNLOAD_PATH="https://fallback.invalid"
  $ echo $?
  0
  ```
  With the first commit applied:
  ```
  $ gmake -C depends clean-all
  $ gmake -C depends qrencode_fetched FALLBACK_DOWNLOAD_PATH="https://fallback.invalid"
  $ gmake -C depends qrencode_fetched FALLBACK_DOWNLOAD_PATH="https://fallback.invalid"
  $ echo $?
  2
  ```

  2. The second and third commits allow the depends build subsystem to detect when the source tarball content has been modified and needs to be re-downloaded, even if the file name remains the same.

ACKs for top commit:
  m3dwards:
    ACK 93a70a42d3
  achow101:
    ACK 93a70a42d3
  vasild:
    ACK 93a70a42d3
  janb84:
    ACK 93a70a42d3

Tree-SHA512: 38b7c029070426196c747fc45c9d00bae534eeeb2d9cd9f221580fce8380f4f8aecb6c48b2563e322edd8c9534f5dd42d8f4e110ada42bb83568cf2dcfb7dc22
2025-10-07 16:57:58 -07:00
Hennadii Stepanov ec5841888d
Merge bitcoin/bitcoin#32513: ci: remove 3rd party js from windows dll gha job
156927903d ci: Check windows manifests for all executables (Max Edwards)
e1a1b14c93 ci: use a more generic way of finding mt.exe (Max Edwards)
7ae0497eef ci: remove 3rd party js from windows dll gha job (Max Edwards)

Pull request description:

  The windows job uses the external dependency `ilammy/msvc-dev-cmd` which runs javascript. We use this to put various tools on the path such as `MSBuild.exe` and `mt.exe`. We can remove this dependency and use `vswhere.exe` directly to find these tools and create a "[Developer command prompt](https://github.com/microsoft/vswhere/wiki/Start-Developer-Command-Prompt#using-powershell)" as someone would on their dev machine.

  While in this area of the code, this PR also runs some additional manifest checks on the windows binaries.

  Fixes: #32508

ACKs for top commit:
  davidgumberg:
    crACK 156927903d
  hebasto:
    ACK 156927903d.

Tree-SHA512: df640dff27579a1c95daddc5a5ba8fd655bbd0a6f2aff74d0f63439c7185c0b18a90abfee3f1f032fe833cd19b822ef71812f44b24c4c044222e46d01c271864
2025-10-08 00:44:05 +01:00
Ava Chow d735e2e9b3
Merge bitcoin/bitcoin#32998: Bump SCRIPT_VERIFY flags to 64 bit
652424ad16 test: additional test coverage for script_verify_flags (Anthony Towns)
417437eb01 script/verify_flags: extend script_verify_flags to 64 bits (Anthony Towns)
3cbbcb66ef script/interpreter: make script_verify_flag_name an ordinary enum (Anthony Towns)
bddcadee82 script/verify_flags: make script_verify_flags type safe (Anthony Towns)
a5ead122fe script/interpreter: introduce script_verify_flags typename (Anthony Towns)
4577fb2b1e rpc: have getdeploymentinfo report script verify flags (Anthony Towns)
a3986935f0 validation: export GetBlockScriptFlags() (Anthony Towns)
5db8cd2d37 Move mapFlagNames and FormatScriptFlags logic to script/interpreter.h (Anthony Towns)

Pull request description:

  We currently use 21 of 32 possible bits for `SCRIPT_VERIFY_*` flags, with open PRs that may use 8 more (#29247, #31989, #32247, #32453). The mutinynet fork that has included many experimental soft fork features is [already reusing bits here](d4a86277ed/src/script/interpreter.h (L175-L195)). Therefore, bump this to 64 bits.

  In order to make it easier to update this logic in future, this PR also introduces a dedicated type for the script flags, and disables implicit conversion between that type and the underlying integer type. To make verifying that this change doesn't cause flags to disappear, this PR also resurrects the changes from #28806 so that the script flags that are consensus enforced on each block can be queried via getdeploymentinfo.

ACKs for top commit:
  instagibbs:
    reACK 652424ad16
  achow101:
    ACK 652424ad16
  darosior:
    ACK 652424ad16
  theStack:
    Code-review ACK 652424ad16 🎏

Tree-SHA512: 7b30152196cdfdef8b9700b571b7d7d4e94d28fbc5c26ea7532788037efc02e4b1d8de392b0b20507badfdc26f5c125f8356a479604a9149b8aae23a7cf5549f
2025-10-07 14:51:22 -07:00
Ava Chow de1dc6b47b
Merge bitcoin/bitcoin#33515: Improve LastCommonAncestor performance + add tests
3635d62f5a chain: make use of pskip in LastCommonAncestor (optimization) (Pieter Wuille)
2e09d66fbb tests: add unit tests for CBlockIndex::GetAncestor and LastCommonAncestor (Pieter Wuille)

Pull request description:

  In theory, the `LastCommonAncestor` function in chain.cpp can take $\mathcal{O}(n)$ time, walking over the entire chain, if the forking point is very early, which could take ~milliseconds. I expect this to be very rare in normal occurrences, but it seems nontrivial to reason about worst cases as it's accessible from several places in net_processing.

  This PR modifies the algorithm to make use of the `CBlockIndex::pskip` skip pointers to find the forking point in sublinear time (a simulation shows that for heights up to $34 \cdot 4^k - 2$ and $k \geq 8$, no more than $k^2 + 10k + 13$ steps are ever needed), in a way that should be nearly free - at worst the same number of memory accesses should be made, with a tiny increase in computation.

  As it appears we didn't really have tests for this function, unit tests are added for that function as well as `CBlockIndex::GetAncestor()`.

  This is inspired by https://github.com/bitcoin/bitcoin/pull/32180#discussion_r2394877881

ACKs for top commit:
  optout21:
    ACK 3635d62f5a
  achow101:
    ACK 3635d62f5a
  vasild:
    ACK 3635d62f5a
  mzumsande:
    Code Review ACK 3635d62f5a
  furszy:
    ACK 3635d62f5a
  stratospher:
    ACK 3635d62f5a.

Tree-SHA512: f9b7dea1e34c1cc1ec1da3fb9e90c4acbf4aaf0f04768844f538201efa6b11eeeefc97b720509e78c21878977192e2c4031fd8974151667e2e756247002b8164
2025-10-07 13:54:25 -07:00
merge-script 919e6d01e9
Merge bitcoin/bitcoin#33489: build: Drop support for EOL macOS 13
1aaaaa078b fuzz: Drop unused workaround after Apple-Clang bump (MarcoFalke)
fadad7a494 Drop support for EOL macOS 13 (MarcoFalke)

Pull request description:

  Now that macOS 13 is EOL (https://en.wikipedia.org/wiki/MacOS_Ventura), it seems odd to still support it.

  (macOS Ventura 13.7.8 received its final security update on 20 Aug 2025: https://support.apple.com/en-us/100100)

  This patch will only be released in version 31.x, another 6 months out from now.

  So:

  * Update the depends build and release note template to drop EOL macOS 13.
  * As a result, update the earliest Xcode to version 16 in CI.
  * Also, bump the macOS CI runner to version 15, to avoid issues when version 14 will be at its EOL in about 1 year.

  This also allows to drop a small workaround in the fuzz tests and unlocks libcpp hardening (https://github.com/bitcoin/bitcoin/pull/33462)

ACKs for top commit:
  stickies-v:
    re-ACK 1aaaaa078b
  l0rinc:
    code review ACK 1aaaaa078b
  hodlinator:
    re-ACK 1aaaaa078b
  hebasto:
    ACK 1aaaaa078b.

Tree-SHA512: 6d247a8432ef8ea8c6ff2a221472b278f8344346b172980299507f9898bb9e8e16480c128b1f4ca692bcbcc393da2b2fd6895ac5f118bc09e0f30f910529d20c
2025-10-06 12:48:00 -04:00
merge-script 452ea59281
Merge bitcoin/bitcoin#33454: net: support overriding the proxy selection in ConnectNode()
c76de2eea1 net: support overriding the proxy selection in ConnectNode() (Vasil Dimov)

Pull request description:

  Normally `ConnectNode()` would choose whether to use a proxy and which one. Make it possible to override this from the callers and same for `OpenNetworkConnection()` - pass down the proxy to `ConnectNode()`.

  Document both functions.

  This is useful if we want to open connections to IPv4 or IPv6 peers through the Tor SOCKS5 proxy.

  Also have `OpenNetworkConnection()` return whether the connection succeeded or not. This can be used when the caller needs to keep track of how many (successful) connections were opened.

  ---

  This is part of [#29415 Broadcast own transactions only via short-lived Tor or I2P connections](https://github.com/bitcoin/bitcoin/pull/29415). Putting it in its own PR to reduce the size of #29415 and because it does not depend on the other commits from there.

ACKs for top commit:
  stratospher:
    ACK c76de2e.
  optout21:
    ACK c76de2eea1
  mzumsande:
    Code Review ACK c76de2eea1
  andrewtoth:
    ACK c76de2eea1

Tree-SHA512: 1d266e4280cdb1d0599971fa8b5da58b1b7451635be46abb15c0b823a1e18cf6e7bcba4a365ad198e6fd1afee4097d81a54253fa680c8b386ca6b9d68d795ff0
2025-10-06 12:43:14 -04:00
merge-script a33bd767a3
Merge bitcoin/bitcoin#33464: p2p: Use network-dependent timers for inbound inv scheduling
0f7d4ee4e8 p2p: Use different inbound inv timer per network (Martin Zumsande)
94db966a3b net: use generic network key for addrcache (Martin Zumsande)

Pull request description:

  Currently, `NextInvToInbounds` schedules  each round of `inv` at the same time for all inbound peers. It's being done this way because with a separate timer per peer (like it's done for outbounds), an attacker could do multiple connections to learn about the time a transaction arrived. (#13298).

  However, having a single timer for inbounds of all networks is also an obvious fingerprinting vector: Connecting to a suspected pair of privacy-network and clearnet addresses and observing the `inv` pattern makes it trivial to confirm or refute that they are the same node.

  This PR changes it such that a separate timer is used for each network.
  It uses the existing method  from `getaddr` caching and generalizes it to be saved in a new field `m_network_key` in `CNode` which will be used for both `getaddr` caching and `inv` scheduling, and can also be used for any future anti-fingerprinting measures.

ACKs for top commit:
  sipa:
    utACK 0f7d4ee4e8
  stratospher:
    reACK 0f7d4ee.
  naiyoma:
    Tested ACK 0f7d4ee4e8
  danielabrozzoni:
    reACK 0f7d4ee4e8

Tree-SHA512: e197c3005b2522051db432948874320b74c23e01e66988ee1ee11917dac0923f58c1252fa47da24e68b08d7a355d8e5e0a3ccdfa6e4324cb901f21dfa880cd9c
2025-10-03 23:45:17 +01:00
merge-script 2578da69f4
Merge bitcoin/bitcoin#33485: test: set par=2 in default config for functional test framework
dda5228e02 test: set par=2 in default config for functional test framework (Andrew Toth)

Pull request description:

  Depending on the host machine, a default `par` value can spawn up to 15 script verification threads for each node. Running the functional test suite with default `par` can exhaust file descriptors or hit other resource limits when many threads are spawned. These threads are mostly idle and the same code paths are executed with a value of `par=2`. Limit this to 2 for functional tests that do not override the default option.

ACKs for top commit:
  maflcko:
    lgtm ACK dda5228e02
  pablomartin4btc:
    ACK dda5228e02
  l0rinc:
    Code review ACK dda5228e02
  theStack:
    ACK dda5228e02

Tree-SHA512: 4459972330ff50ac7391141db6382579de09d84e68959eaeb5f20972bb9daf9aac1bd68355028ded9ee65e838c12dbd53e6f3bb6cdc375d269f666c19a19eaec
2025-10-03 22:36:34 +01:00
merge-script 25dbe4bc86
Merge bitcoin/bitcoin#33533: test: addrman: check isTerrible when time is more than 10min in the future
8e47ed6906 test: addrman: check isTerrible when time is more than 10min in the future (brunoerg)

Pull request description:

  This PR adds test coverage to kill the following mutant (https://corecheck.dev/mutation/src/addrman.cpp#L76):
  ```diff
  diff --git a/src/addrman.cpp b/src/addrman.cpp
  index 9c3a24db90..0ffd349315 100644
  --- a/src/addrman.cpp
  +++ b/src/addrman.cpp
  @@ -73,7 +73,7 @@ bool AddrInfo::IsTerrible(NodeSeconds now) const
       }

       if (nTime > now + 10min) { // came in a flying DeLorean
  -        return true;
  +        return false;
       }
  ```

  When the `nTime` is set 10 minutes in the future the addr should be marked as terrible.

ACKs for top commit:
  Crypt-iQ:
    crACK 8e47ed6906
  danielabrozzoni:
    tACK 8e47ed6906
  marcofleon:
    Nice, code review ACK 8e47ed6906

Tree-SHA512: b53b3aa234a73ec7808cb1555916ac64dd707f230ec290a1712493ece8e274a060e16d862b31df0f744804ebd3c0c2825c49becb7d3040cc358e48c4002524cb
2025-10-03 20:20:46 +01:00
merge-script cfb0d74698
Merge bitcoin/bitcoin#33121: test: fix p2p_leak_tx.py
14ae71f323 test: make notfound_on_unannounced more reliable (David Gumberg)
99bc552980 test: fix (w)txid confusion in p2p_leak_tx.py (Martin Zumsande)
576dd97cb9 test: increase timeout in p2p_leak_tx.py (Martin Zumsande)

Pull request description:

  This fixes two issues with `p2p_leak_tx.py`:

  1.) #33090: As far as I can see, this is just the randomness of `NextInvToInbounds`/ `rand_exp_duration`, which has a probability of `e^-(60s/5s) = 6.14×10^−6` to result in a period > 60s (our waiting time), so that the test would fail every 160k runs... Doubling the timeout should be sufficient to lower the probability drastically.

  2.) The subtest `test_notfound_on_unannounced_tx` has some (w)txid confusion: we send a `MSG_TX`-type getdata with a `wtxid` in it, which necessarily always results in a NOTFOUND. Fixed this, and change the subtest to be more deterministic based on `mocktime`.

ACKs for top commit:
  stratospher:
    ACK 14ae71f. nice restructuring using mocktime!
  davidgumberg:
    reACK 14ae71f323
  vasild:
    ACK 14ae71f323

Tree-SHA512: be5a4ca7bf56f82b6fa04d90ef9312dc2e6f8ff7ddf70b39d979dc42fbdd823157109b8b5dc46eb7f81ac1e816f40e6966b3c8a7d384aadee01e2189c20d3e3a
2025-10-03 20:06:50 +01:00
merge-script 86eaa4d6cd
Merge bitcoin/bitcoin#33482: contrib: fix macOS deployment with no translations
7b5261f7ef contrib: fix using macdploy script without translations. (amisha)

Pull request description:

  **Description**
  From what I deciphered reading the line https://github.com/bitcoin/bitcoin/blob/master/contrib/macdeploy/macdeployqtplus#L390 is that qt translations are optional to have hence we should be able to build without it but the case where the flag translations_dir falls back to its default Null value it raises this error.

  The config comments also mentioned that adding translation file is optional.

  ```
  ./macdeployqtplus --help
  usage: macdeployqtplus [-h] [-verbose [VERBOSE]] [-no-plugins] [-no-strip] [-translations-dir path] [-zip zip] app-bundle

  Improved version of macdeployqt. Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .zip file. Note, that the "dist" folder will be deleted before deploying on each run. Optionally, Qt translation files
  (.qm) can be added to the bundle.
  ```

  **Steps to reproduce**
  So I was following the general steps to set up app on macos however I didn't download any qt translations presuming it was optional from the comment linkedin in PR, so to reproduce if you have translation directories in place ull need to delete them and then try to build the file, otherwise don't download it at all and try to build it. It should fail on that flag as translations dir was never downloaded.

  **Approach taken**
  I have moved the code which adds language files under the if statement that first checks if the value of the flag is not Null before referencing it.

ACKs for top commit:
  ismaelsadeeq:
    ACK 7b5261f7ef

Tree-SHA512: 8d51b17569e42c9feb95e1be17b1551c708a05eb44b82c74db0b25e07006b4ee223d64484f8bdb2ee1420f6e571686561ae1c09bd3362f77dcbb507bc5085f86
2025-10-03 15:40:38 +01:00
merge-script 007900ee9b
Merge bitcoin/bitcoin#33434: depends: static libxcb-cursor
eca50854e1 depends: static libxcb_cursor (fanquake)

Pull request description:

  Remove the runtime requirement of `libxcb-cursor`. This library is no-longer present on modern Ubuntu.
  Fixes #33432.
  Also related to #32097.

ACKs for top commit:
  davidgumberg:
    Addendum ACK eca50854e1
  willcl-ark:
    Code review ACK eca50854e1

Tree-SHA512: d545a03baf5030de64874b79add87b6ef5f95eb5ca31aa66007ee03554103d2eda5e56dfd4395d0a12e24b2e489457e4f19ed9e6d390351c72a0da630f03cc42
2025-10-03 15:26:20 +01:00
brunoerg 8e47ed6906 test: addrman: check isTerrible when time is more than 10min in the future 2025-10-03 10:24:29 -03:00
Pieter Wuille 3635d62f5a chain: make use of pskip in LastCommonAncestor (optimization)
By using the pskip pointer, which regularly allows jumping back much faster
than pprev, the forking point between two CBlockIndex entries can be found
much faster.

A simulation shows that no more than 136 steps are needed to jump anywhere
within the first 2^20 block heights, and on average 65 jumps for uniform
forking points around that height.
2025-10-02 10:34:12 -04:00
Pieter Wuille 2e09d66fbb tests: add unit tests for CBlockIndex::GetAncestor and LastCommonAncestor 2025-10-02 10:34:09 -04:00
Max Edwards 156927903d ci: Check windows manifests for all executables
The other executables have manifests and these should be checked in
addition to bitcoind. Skipping fuzz.exe, bench_bitcoin.exe and
test_bitcoin-qt.exe as they do not have manifests.
2025-10-02 15:13:29 +01:00
Max Edwards e1a1b14c93 ci: use a more generic way of finding mt.exe
This sets up a vs developer command prompt and should hopefully should
be more resilient to upstream changes

Co-authored-by: David Gumberg <davidzgumberg@gmail.com>
2025-10-02 15:13:26 +01:00
merge-script 1ed00a0d39
Merge bitcoin/bitcoin#33504: Mempool: Do not enforce TRUC checks on reorg
06df14ba75 test: add more TRUC reorg coverge (Greg Sanders)
26e71c237d Mempool: Do not enforce TRUC checks on reorg (Greg Sanders)
bbe8e9063c fuzz: don't bypass_limits for most mempool harnesses (Greg Sanders)

Pull request description:

  This was the intended behavior but our tests didn't cover the scenario where in-block transactions themselves violate TRUC topological constraints.

  The behavior in master will potentially lead to many erroneous evictions during a reorg, where evicted TRUC packages may be very high feerate and make sense to mine all together in the next block and are well within the normal anti-DoS chain limits.

  This issue exists since the merge of https://github.com/bitcoin/bitcoin/pull/28948/files#diff-97c3a52bc5fad452d82670a7fd291800bae20c7bc35bb82686c2c0a4ea7b5b98R956

ACKs for top commit:
  sdaftuar:
    ACK 06df14ba75
  glozow:
    ACK 06df14ba75
  ismaelsadeeq:
    Code review ACK 06df14ba75

Tree-SHA512: bdb6e4dd622ed8b0b11866263fff559fcca6e0ca1c56a884cca9ac4572f0026528a63a9f4c8a0660df2f5efe0766310a30e5df1d6c560f31e4324ea5d4b3c1a8
2025-10-02 13:22:22 +01:00
Vasil Dimov c76de2eea1
net: support overriding the proxy selection in ConnectNode()
Normally `ConnectNode()` would choose whether to use a proxy and which
one. Make it possible to override this from the callers and same for
`OpenNetworkConnection()` - pass down the proxy to `ConnectNode()`.

Document both functions.

This is useful if we want to open connections to IPv4 or IPv6 peers
through the Tor SOCKS5 proxy.

Also have `OpenNetworkConnection()` return whether the connection
succeeded or not. This can be used when the caller needs to keep track
of how many (successful) connections were opened.
2025-10-02 08:39:26 +02:00
Ava Chow 75353a0163
Merge bitcoin/bitcoin#32326: net: improve the interface around FindNode() and avoid a recursive mutex lock
87e7f37918 doc: clarify peer address in getpeerinfo and addnode RPC help (Vasil Dimov)
2a4450ccbb net: change FindNode() to not return a node and rename it (Vasil Dimov)
4268abae1a net: avoid recursive m_nodes_mutex lock in DisconnectNode() (Vasil Dimov)
3a4d1a25cf net: merge AlreadyConnectedToAddress() and FindNode(CNetAddr) (Vasil Dimov)

Pull request description:

  `CConnman::FindNode()` would lock `m_nodes_mutex`, find the node in `m_nodes`, release the mutex and return the node. The current code is safe but it is a dangerous interface where a caller may end up using the node returned from `FindNode()` without owning `m_nodes_mutex` and without having that node's reference count incremented.

  Change `FindNode()` to return a boolean since all but one of its callers used its return value to check whether a node exists and did not do anything else with the return value.

  Remove a recursive lock on `m_nodes_mutex`.

  Rename `FindNode()` to better describe what it does.

ACKs for top commit:
  achow101:
    ACK 87e7f37918
  furszy:
    Code review ACK 87e7f37918
  hodlinator:
    re-ACK 87e7f37918

Tree-SHA512: 44fb64cd1226eca124ed1f447b4a1ebc42cc5c9e8561fc91949bbeaeaa7fa16fcfd664e85ce142e5abe62cb64197c178ca4ca93b3b3217b913e3c498d0b7d1c9
2025-10-01 14:17:22 -07:00
Vasil Dimov 87e7f37918
doc: clarify peer address in getpeerinfo and addnode RPC help
The returned value in `getpeerinfo/addr` could be a hostname as well as
an IP address and the `:port` part could be missing. It is displayed
from `CNode::m_addr_name` which could have been set from RPC `addnode`
where the argument is allowed to be a hostname and an optional port.
2025-10-01 16:39:56 +02:00
Vasil Dimov 2a4450ccbb
net: change FindNode() to not return a node and rename it
All callers of `CConnman::FindNode()` use its return value `CNode*` only
as a boolean null/notnull. So change that method to return `bool`.

This removes the dangerous pattern of handling a `CNode` object (the
return value of `FindNode()`) without holding `CConnman::m_nodes_mutex`
and without having that object's reference count incremented for the
duration of the usage.

Also rename the method to better describe what it does.
2025-10-01 16:39:56 +02:00
Vasil Dimov 4268abae1a
net: avoid recursive m_nodes_mutex lock in DisconnectNode()
Have `CConnman::DisconnectNode()` iterate `m_nodes` itself instead of
using `FindNode()`. This avoids recursive mutex lock and drops the only
caller of `FindNode()` which used the return value for something else
than a boolean found/notfound.
2025-10-01 16:39:55 +02:00
Hennadii Stepanov acc7f2a433
Merge bitcoin/bitcoin#33401: ci: Remove bash -c from cmake invocation using eval
50194029e7 ci: Remove bash -c from cmake invocation using eval (Brandon Odiwuor)

Pull request description:

  Follow up to https://github.com/bitcoin/bitcoin/pull/32970

  https://github.com/bitcoin/bitcoin/pull/32970#r2213730157

  > Does `cmake -S ...` still need to be wrapped in `bash -c "..."`?

  https://github.com/bitcoin/bitcoin/pull/32970#r2213741192
  > It is not trivial to replace. Maybe the `eval` hack from below can be used:
  >
  > ```shell
  >   # parses TEST_RUNNER_EXTRA as an array which allows for multiple arguments such as TEST_RUNNER_EXTRA='--exclude "rpc_bind.py --ipv6"'
  >
  >   eval "TEST_RUNNER_EXTRA=($TEST_RUNNER_EXTRA)"
  > ```
  >however, I haven't tried this yet.

  https://github.com/bitcoin/bitcoin/pull/32970#r2213801696
  > Yeah, the eval hack should work:
  >
  > ```
  > $ export T="-DREDUCE_EXPORTS=ON -DCMAKE_CXX_FLAGS='-Wno-psabi     -Wno-error=maybe-uninitialized'";  eval "T=($T)"; for i in "${T[@]}"; do  echo "_${i}_" ; done
  > _-DREDUCE_EXPORTS=ON_
  > _-DCMAKE_CXX_FLAGS=-Wno-psabi     -Wno-error=maybe-uninitialized_
  > ```
  >
  > (can be done in a follow-up)

  This replaces the `bash -c` wrapper with an eval-based array parsing to preserve spaces in flag values (e.g., in CMAKE_CXX_FLAGS), allowing ShellCheck to lint the cmake command

ACKs for top commit:
  maflcko:
    lgtm ACK 50194029e7
  hebasto:
    ACK 50194029e7.

Tree-SHA512: 6fd22569e2c719a8d13805f18e1e7e3b8eb57d0a6307f2e7175988b25750eafb7c8260796c8e7350db67d622dbe97e6af7bab8ee52187bb8e8eeae3740a47c01
2025-10-01 11:36:10 +01:00
MarcoFalke 1aaaaa078b
fuzz: Drop unused workaround after Apple-Clang bump 2025-10-01 08:09:34 +02:00
MarcoFalke fadad7a494
Drop support for EOL macOS 13 2025-10-01 08:09:30 +02:00
Brandon Odiwuor 50194029e7 ci: Remove bash -c from cmake invocation using eval 2025-10-01 08:58:17 +03:00
Ava Chow f41f97240c
Merge bitcoin/bitcoin#28584: Fuzz: extend CConnman tests
0802398e74 fuzz: make it possible to mock (fuzz) CThreadInterrupt (Vasil Dimov)
6d9e5d130d fuzz: add CConnman::SocketHandler() to the tests (Vasil Dimov)
3265df63a4 fuzz: add CConnman::InitBinds() to the tests (Vasil Dimov)
91cbf4dbd8 fuzz: add CConnman::CreateNodeFromAcceptedSocket() to the tests (Vasil Dimov)
50da7432ec fuzz: add CConnman::OpenNetworkConnection() to the tests (Vasil Dimov)
e6a917c8f8 fuzz: add Fuzzed NetEventsInterface and use it in connman tests (Vasil Dimov)
e883b37768 fuzz: set the output argument of FuzzedSock::Accept() (Vasil Dimov)

Pull request description:

  Extend `CConnman` fuzz tests to also exercise the methods `OpenNetworkConnection()`, `CreateNodeFromAcceptedSocket()`, `InitBinds()` and `SocketHandler()`.

  Previously fuzzing those methods would have resulted in real socket functions being called in the operating system which is undesirable during fuzzing. Now that https://github.com/bitcoin/bitcoin/pull/21878 is complete all those are mocked to a fuzzed socket and a fuzzed DNS resolver (see how `CreateSock` and `g_dns_lookup` are replaced in the first commit).

ACKs for top commit:
  achow101:
    ACK 0802398e74
  jonatack:
    Review re-ACK 0802398e74
  dergoegge:
    Code review ACK 0802398e74

Tree-SHA512: a717d4e79f42bacf2b029c821fdc265e10e4e5c41af77cd4cb452cc5720ec83c62789d5b3dfafd39a22cc8c0500b18169aa7864d497dded729a32ab863dd6c4d
2025-09-30 15:59:09 -07:00
Ava Chow cc4a2cc6bd
Merge bitcoin/bitcoin#33453: docs: Undeprecate datacarrier and datacarriersize configuration options
451ba9ada4 datacarrier: Undeprecate configuration option (Anthony Towns)

Pull request description:

  Removes the deprecation for the `datacarrier` and `datacarriersize` options by reverting commit 0b4048c733 from https://github.com/bitcoin/bitcoin/pull/32406

  **Many current Bitcoin Core users want to continue using this option**
  This statement is based on public postings from many Bitcoin Core users and not a formal survey. AJ Towns’ observation from [#32406](0b4048c733 (r2084024874)) that “_for now there seem to be a bunch of users who like the option_” has only become more apparent in the months since.

  **The deprecation intent is unclear to users**
  This echo’s Ava Chow’s comment from #32714 that “_IMO we should not have removal warnings if there is no current plan to actually remove them._” In months since that comment, partially due to increased feedback from Bitcoin Core users wanting to keep this option, there is even less likelihood of a near term plan to remove these options. That leaves Bitcoin Core users in an unclear situation: the option could be removed in the next version or perhaps never. Removing the deprecation gives clarity for their planning purposes. Deprecating the option in the future, preferably with a removal schedule to better inform users, would still be possible.

  **Minimal downsides to removing deprecation**
  As a best practice, Bitcoin Core has avoided an option when the developers cannot articulate when they should be used. There is non-zero maintenance cost to keeping this code around (although leaving the options deprecated for a long time has the same effect). “Don’t offer users footguns” is also a good principle, but with this option, there seems to be only small impacts that can quickly be remedied by changing the option value by Bitcoin Core users. There already exist in Bitcoin Core more potentially-user-harmful options/values than what datacarrier might cause.

ACKs for top commit:
  ajtowns:
    ACK 451ba9ada4
  darosior:
    That said, certain users care strongly about using those options. In these conditions, i do not see the project removing the option anytime soon. Therefore i think it's technically incorrect (and confusing) to mark it as deprecated. utACK 451ba9ada4 on removing the deprecation.
  instagibbs:
    crACK 451ba9ada4
  Raimo33:
    ACK 451ba9ada4
  Ademan:
    utACK 451ba9a
  ryanofsky:
    Code review ACK 451ba9ada4
  marcofleon:
    ACK 451ba9ada4
  achow101:
    ACK 451ba9ada4
  moonsettler:
    ACK 451ba9ada4
  ismaelsadeeq:
    utACK 451ba9ada4 🛰️
  jonatack:
    ACK 451ba9ada4
  Zero-1729:
    crACK 451ba9ada4
  vasild:
    ACK 451ba9ada4

Tree-SHA512: b83fc509f5dd820976596e1ae9fb69a22ada567e0e0ac88da5fc5e940a46d8894b40cc70c3eff2cbdabd4da5ec913f0d18c1632fc906f210b308855868410699
2025-09-30 15:23:20 -07:00
Ava Chow 7502d4e940
Merge bitcoin/bitcoin#33260: test: Use extra_port() helper in feature_bind_extra.py
fabc2615af test: Use extra_port() helper in feature_bind_extra.py (MarcoFalke)

Pull request description:

  This is a refactor for self-validating and self-documenting code.

  Currently, the test assumes that extra ports are available and just increments them without checking. However, this may not be the case when the test is modified to use more ports. In this case, the tests may fail intermittently and the failure is hard to debug.

  Fix this confusion, by calling `p2p_port` each time. This ensures the required `assert n <= MAX_NODES` is checked each time.

  Closes https://github.com/bitcoin/bitcoin/issues/33250

ACKs for top commit:
  achow101:
    ACK fabc2615af
  janb84:
    crACK fabc2615af
  w0xlt:
    ACK fabc2615af

Tree-SHA512: 1eff00be7f43104ae8a66e79fbf64075ec22bb20f392ac1e4c8a7dd694d4f1760aa44ea54ab7b1f2b947ab018851ab3c10d3c717714c0bee4d8d24617594c2bb
2025-09-30 13:30:36 -07:00
David Gumberg 14ae71f323 test: make notfound_on_unannounced more reliable
By using mocktime, we will always hit both the notfound
branch and the tx sent branch.
The previous version didn't achieve that due to timing
issues.

Co-authored-by: Martin Zumsande <mzumsande@gmail.com>
2025-09-30 15:57:31 -04:00
Martin Zumsande 99bc552980 test: fix (w)txid confusion in p2p_leak_tx.py
Before, we'd send a MSG_TX with a wtxid in it, which
would always result in a notfound answer
2025-09-30 15:57:31 -04:00
Martin Zumsande 576dd97cb9 test: increase timeout in p2p_leak_tx.py
With a low but not negligible probability in the order
of 10^-6 the exponential timer NextInvToInBounds can lead
to an interval >60s, making the test fail.
Also uses mocktime to speed up the test and fixes a
non-matching on_inv override.

Co-authored-by: Vasil Dimov <vd@FreeBSD.org>
2025-09-30 15:56:17 -04:00
Ava Chow 8f73d95221
Merge bitcoin/bitcoin#33299: wallet: reduce unconditional logging during load
fc861332b3 wallet, log: reduce unconditional logging during load (furszy)

Pull request description:

  Currently the unconditional log during init with a default wallet happens three times:
  ```
  2025-09-03T19:57:16Z init message: Verifying wallet(s)…
  2025-09-03T19:57:16Z Using SQLite Version 3.45.1
  2025-09-03T19:57:16Z Using wallet XXX/.bitcoin/regtest
  2025-09-03T19:57:16Z Using SQLite Version 3.45.1
  2025-09-03T19:57:16Z Using wallet XXX/.bitcoin/regtest
  (...)
  2025-09-03T19:57:16Z Using SQLite Version 3.45.1
  2025-09-03T19:57:16Z Using wallet XXX/.bitcoin/regtest
  2025-09-03T19:57:16Z init message: Loading wallet…
  ```
  For non-default wallets it's logged two times.

  That seems a bit too much, so just log the SQLite version just one, and remove the log for the full path of the wallet, since it's already clear from other logs which wallet is being loaded.

ACKs for top commit:
  achow101:
    ACK fc861332b3
  furszy:
    utACK fc861332b3
  stickies-v:
    ACK fc861332b3

Tree-SHA512: ca45c8ede985e6feab0cb93d718a6d633691276ca6e5f13f6471759f11dee98b312e1c802a7fb42c7fa859b6edc44a8c54b9e2ca389655cf028aebf2dabe51f6
2025-09-30 11:01:27 -07:00
Martin Zumsande 0f7d4ee4e8 p2p: Use different inbound inv timer per network
Currently nodes schedule their invs to all inbound peers at the same time.
It is trivial to make use this timing pattern for fingerprinting
identities on different networks. Using a separate timers for each network will
make the fingerprinting harder.
2025-09-30 11:17:17 -04:00
Hennadii Stepanov 93a70a42d3
depends: Update URL for `qrencode` package source tarball
The https://fukuchi.org/ homepage no longer links to the source tarball,
and previously available files appear to have been removed. The homepage
now instructs users to download source tarballs from the GitHub releases
page instead.

The diff between the source trees is immaterial.
2025-09-30 11:26:47 +01:00
Hennadii Stepanov 6de8051263
depends: Use hash instead of file name for package download stamp
The package version is still included for convenience.
2025-09-30 11:26:29 +01:00
Hennadii Stepanov 46135d90ea
depends: Drop redundant check for downloaded file
The `fetch_file` commands are invoked for the `$($(package)_fetched)`
target, so the existence of the download stamp has already been tested.
2025-09-30 11:22:50 +01:00
Hennadii Stepanov 771978952a
depends: Fix `$(package)_fetched` target
Ensure the download timestamp is created only after a successful
download.
2025-09-30 11:20:12 +01:00
Hennadii Stepanov 25212dfdb4
Merge bitcoin/bitcoin#33487: ci: use latest versions of lint deps
d4f47f9771 ci: use latest versions of lint deps (fanquake)

Pull request description:

  Some of the versions used here are > 2 years old. i.e `mypy`. Use the latest avilable versions, except for LIEF, which is generally changed with Guix.

  Side note. I can't remember the last time one of these tools (mypy, ruff, vulture) actually caught an issue in the lint job.

ACKs for top commit:
  maflcko:
    lgtm ACK d4f47f9771
  janb84:
    lgtm ACK d4f47f9771
  hebasto:
    ACK d4f47f9771, I have reviewed the code and it looks OK.

Tree-SHA512: 8b312535c9fea8e76d58f517ada6d6ea7a119c5e03c8cb84a41b5b6ca80dfaaff65a81478bdc1a5acf734cfb0bc66a8b3ba5400db8973c43ca913b07568abfe4
2025-09-30 08:17:14 +01:00
Greg Sanders 06df14ba75 test: add more TRUC reorg coverge 2025-09-29 16:25:54 -04:00
Greg Sanders 26e71c237d 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.
2025-09-29 16:25:54 -04:00
Greg Sanders bbe8e9063c 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.
2025-09-29 16:25:54 -04:00
fanquake d4f47f9771
ci: use latest versions of lint deps
Some of the versions used here are > 2 years old. i.e mypy. Use the
latest avilable versions, except for LIEF, which is generally changed
with Guix.
2025-09-29 14:47:41 -04:00
furszy fc861332b3 wallet, log: reduce unconditional logging during load
The removed statements were logged up to two or three times for each loaded
wallet. The SQLite version only needs to be logged once.
The full wallet path is dropped, since the existing unconditional
logging while loading wallets is sufficient (also reduces anonymization
efforts in case of sharing logs).

Co-authored-by: Martin Zumsande <mzumsande@gmail.com>
2025-09-29 13:59:44 -04:00
Vasil Dimov 3a4d1a25cf
net: merge AlreadyConnectedToAddress() and FindNode(CNetAddr)
`CConnman::AlreadyConnectedToAddress()` is the only caller of
`CConnman::FindNode(CNetAddr)`, so merge the two in one function.

The unit test that checked whether `AlreadyConnectedToAddress()` ignores
the port is now unnecessary because now the function takes a `CNetAddr`
argument. It has no access to the port.
2025-09-29 12:51:52 +02:00
merge-script d8fe258cd6
Merge bitcoin/bitcoin#33484: doc: rpc: fix case typo in `finalizepsbt` help (final_scriptwitness)
ff05bebcc4 doc: rpc: fix case typo in `finalizepsbt` help (final_scriptwitness) (Sebastian Falbesoner)

Pull request description:

  The lower-case spelling matches the `decodepsbt` result field:
  200150beba/src/rpc/rawtransaction.cpp (L871)
  200150beba/src/rpc/rawtransaction.cpp (L1253)

ACKs for top commit:
  l0rinc:
    ACK ff05bebcc4
  rkrux:
    Ah crACK ff05bebcc4

Tree-SHA512: c0a0e29e95fed3fcee4df4f3fc87b32774d76bebadcda5aa010bc45142727536d6a71e4c0e70564db8bdb734e8647c80953793ac9ecd6c434345e972f8d9b7b0
2025-09-28 18:12:44 -04:00
Andrew Toth dda5228e02 test: set par=2 in default config for functional test framework
Depending on the host machine, a default `par` value can spawn up to 15 script verification threads for each node.
Running the functional test suite with default `par` can exhaust file descriptors or hit other resource limits when many threads are spawned.
These threads are mostly idle and the same code paths are executed with a value of `par=2`.
Limit this to 2 for functional tests that do not override the default option.

Co-authored-by: maflcko <6399679+maflcko@users.noreply.github.com>
2025-09-27 16:31:01 -04:00
Sebastian Falbesoner ff05bebcc4 doc: rpc: fix case typo in `finalizepsbt` help (final_scriptwitness) 2025-09-26 19:27:55 +02:00
merge-script 200150beba
Merge bitcoin/bitcoin#33313: test/refactor: use test deque to avoid quadratic iteration
75e6984ec8 test/refactor: use test deque to avoid quadratic iteration (Lőrinc)

Pull request description:

  Extracted from https://github.com/bitcoin/bitcoin/pull/33141#discussion_r2323012972.

  -----

  In Python, [list `pop(0)` is linear](https://docs.python.org/3/tutorial/datastructures.html#using-lists-as-queues), so consuming all items in the test results in quadratic iteration.

  Switching to `collections.deque` with `popleft()` expresses FIFO intent and avoids the O(n^2) path.
  Behavior is unchanged - for a few hundred items the perf impact is likely negligible.

ACKs for top commit:
  maflcko:
    lgtm ACK 75e6984ec8
  theStack:
    re-ACK 75e6984ec8
  enirox001:
    reACK 75e6984
  w0xlt:
    reACK 75e6984ec8

Tree-SHA512: 290f6aeeb33d8b12b7acbbfede7ce0bef1c831a7ab9efc9c3a08c049986572e289cdece0844db908cf198395f574575ce4073c268033bf6dbaadc3828c96c1d8
2025-09-26 11:50:15 -04:00
merge-script 7e08445449
Merge bitcoin/bitcoin#33399: key: use static context for libsecp256k1 calls where applicable
1ff9e92948 key: use static context for libsecp256k1 calls where applicable (Sebastian Falbesoner)

Pull request description:

  The dynamically created [signing context](2d6a0c4649/src/key.cpp (L19)) for libsecp256k1 calls is only needed for functions that involve generator point multiplication with a secret key, i.e. different variants of public key creation and signing. The API docs hint to those by stating "[(not secp256k1_context_static)](b475654302/include/secp256k1.h (L645))" for the context parameter. In our case that applies to the following calls:
  - `secp256k1_ec_pubkey_create`
  - `secp256k1_keypair_create`
  - `secp256k1_ellswift_create`
  - `secp256k1_ecdsa_sign`
  - `secp256k1_ecdsa_sign_recoverable`
  - `secp256k1_schnorrsig_sign32`
  - `ec_seckey_export_der` (not a direct secp256k1 function, but calls `secp256k1_ec_pubkey_create` inside)

  For all the other secp256k1 calls we can simply use the static context. This is done for consistency to other calls that already use `secp256k1_context_static`, and also to reduce dependencies on the global signing context variable. Looked closer at this in the course of reviewing #29675, where some functions used the signing context that didn't need to, avoiding a move to another module (see https://github.com/bitcoin/bitcoin/pull/29675#discussion_r2333831377).

ACKs for top commit:
  Eunovo:
    ACK 1ff9e92948
  furszy:
    ACK 1ff9e92948
  rkrux:
    crACK 1ff9e92948

Tree-SHA512: f091efa56c358057828f3455d4ca9ce40ec0d35f3e38ab147fe3928bb5dbf7ffbc27dbf97b71937828ab95ea4e9be5f96d89a2d29e2aa18df4542aae1b33e258
2025-09-26 11:44:29 -04:00
amisha 7b5261f7ef 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.
2025-09-26 10:09:30 +05:30
Ava Chow 65e909dfdd
Merge bitcoin/bitcoin#33430: rpc: addpeeraddress: throw on invalid IP
316a0c5132 rpc: addpeeraddress: throw on invalid IP (John Moffett)

Pull request description:

  Right now we return an opaque `{"success" : false}` in `addpeeraddress` for an empty or invalid IP. This changes it to throw `RPC_CLIENT_INVALID_IP_OR_SUBNET` with the error message `Invalid IP address`. Tests updated to match.

ACKs for top commit:
  sipa:
    utACK 316a0c5132
  achow101:
    ACK 316a0c5132
  vasild:
    ACK 316a0c5132
  pablomartin4btc:
    tACK 316a0c5132

Tree-SHA512: 79a8ce127d0a24b2eb1f31bc3294b895d0c6424032a6b49168259e0e94aff69723d067adf1b4dc3c9b79e597531e5b65e4b8fc5a8e21fba0b81f99168de12b96
2025-09-25 15:42:12 -07:00
Ava Chow 31b29f8eb6
Merge bitcoin/bitcoin#33229: multiprocess: Don't require bitcoin -m argument when IPC options are used
453b0fa286 bitcoin: Make wrapper not require -m (Ryan Ofsky)
29e836fae6 test: add tool_bitcoin to test bitcoin wrapper behavior (Ryan Ofsky)
0972f55040 init: add exe name to bitcoind, bitcoin-node -version output to be able to distinguish these in tests (Ryan Ofsky)

Pull request description:

  This change makes the `bitcoin` command respect IPC command line options and _bitcoin.conf_ settings, so IPC listening can be enabled by just running `bitcoin node -ipcbind=unix` or `bitcoin node` with `ipcbind=unix` in the configuration file, and there is no longer a need to specify a multiprocess `-m` option like `bitcoin -m node [...]`

  sipa and theuni in #31802 pointed out that users shouldn't be exposed to multiprocess implementation details just to use IPC features, so current need to specify the `bitcoin -m` option in conjunction with `-ipcbind` could be seen as a design mistake and not just a usage inconvenience.

  This PR also adds a dedicated functional test for the `bitcoin` wrapper command and to make sure it calls the right binaries and test the new functionality.

  ---

  This PR is part of the [process separation project](https://github.com/bitcoin/bitcoin/issues/28722).

ACKs for top commit:
  Sjors:
    re-ACK 453b0fa286
  achow101:
    ACK 453b0fa286
  TheCharlatan:
    Re-ACK 453b0fa286

Tree-SHA512: 9e49cb7e183fd220fa7a4e8ac68cef55f3cb2ccec40ad2a9d3e3f31db64c4953db8337f8caf7fce877bc97002ae97568dcf47ee269a06ca1f503f119bfe392c1
2025-09-25 14:36:40 -07:00
merge-script e62e0a12b3
Merge bitcoin/bitcoin#33230: cli: Handle arguments that can be either JSON or string
df67bb6fd8 test: Remove convert_to_json_for_cli (Ava Chow)
44a493e150 cli: Allow arguments to be both strings and json (Ava Chow)

Pull request description:

  There are some RPCs where the argument can be either JSON that needs to be parsed, or a string that we can pass straight through. However, `bitcoin-cli` would always parse those arguments as JSON which makes for some cumbersome argument passing when using those RPCs. Notably, `hash_or_height` in `getblockstats` and `gettxoutsetinfo` do this, and results in a more cumbersome command of `bitcoin-cli getblockstats '"<hash>"'`. Otherwise, using a normal invocation of `bitcoin-cli getblockstats <hash>` results in `error: Error parsing JSON`. This PR marks those particular options as also being a string so that when `bitcoin-cli` fails to parse the argument as JSON, it will assume that the argument is a string and pass it straight through.

ACKs for top commit:
  ryanofsky:
    Code review ACK df67bb6fd8, just rebased since last review. I do still think it would be good to improve the test (https://github.com/bitcoin/bitcoin/pull/33230#discussion_r2369570345)
  rkrux:
    Light code review, lgtm ACK df67bb6fd8
  mzumsande:
    Code Review ACK df67bb6fd8

Tree-SHA512: 6c488570fbb24d0cf10508416c56accfc7af5163b7a7187d22d78c812424a9e3ecc95906d3e295fbf6af54bf80903aa448fd879dd6a9944ba8b4d1a33eb29ef2
2025-09-25 15:50:56 -04:00
Max Edwards 7ae0497eef ci: remove 3rd party js from windows dll gha job
We can use vswhere.exe directly to create a vs developer
prompt and so can remove this third party dependency.

Co-authored-by: David Gumberg <davidzgumberg@gmail.com>
2025-09-25 18:12:02 +01:00
merge-script 05d984b1a4
Merge bitcoin/bitcoin#33475: bugfix: miner: fix `addPackageTxs` unsigned integer overflow
b807dfcdc5 miner: fix `addPackageTxs` unsigned integer overflow (ismaelsadeeq)

Pull request description:

  This PR fixes an unsigned integer overflow in the `addPackageTxs` method of the `BlockAssembler`.

  The overflow is a rare edge case that might occur on master when a miner reserves 2000 WU and wants to create an block to be empty.

  i.e, by starting with `-blockmaxweight=2000`, `-blockreservedweight=2000`, or just `blockmaxweight=2000`, and then calling the mining interface `createNewBlock` with `blockReservedWeight` set to `2000`.

  Instead of bailing out after going through transactions equivalent to `MAX_CONSECUTIVE_FAILURES`, the loop never breaks until all mempool transactions are visited.

  See https://github.com/bitcoin/bitcoin/pull/33421#issuecomment-3324859282

  The fix avoids the overflow by using addition instead adding `BLOCK_FULL_ENOUGH_WEIGHT_DELTA` to the block weight and comparing it with `m_options.nBlockMaxWeight`.

  Another alternative that preserves the same structure is to use `static_cast`. See c9530cf35d.

  This fix can be tested by cherry-picking the commits from #33421 without the static cast fix and running:

  ```bash
  echo "AQAAAAAAA
  AAnJycnAAAAAAAAAAAAAAAAAA" | base64 --decode > miner.crash

  FUZZ=block_template_cache ./build_fuzz/bin/fuzz miner.crash
  ```

  ---

  This is part of a larger inconsistency in how size/weight is represented in the codebase. It may be worth defining a dedicated type for size/weight.

ACKs for top commit:
  glozow:
    nice, utACK b807dfcdc5
  furszy:
    Code ACK b807dfcdc5

Tree-SHA512: c1d2f7e500f9b0624a4c22a146921a1644017065e6c94d0c5027486392321f5de26c61751a24765e025e45b34c535adfd6d0e2ac809dea6846b99f37d13043c9
2025-09-25 08:18:20 -04:00
ismaelsadeeq b807dfcdc5
miner: fix `addPackageTxs` unsigned integer overflow 2025-09-24 17:10:51 +02:00
merge-script d41b503ae1
Merge bitcoin/bitcoin#33446: rpc: fix getblock(header) returns target for tip
bf7996cbc3 rpc: fix getblock(header) returns target for tip (Sjors Provoost)
4c3c1f42cf test: add block 2016 to mock mainnet (Sjors Provoost)

Pull request description:

  A `target` field was added to the `getblock` and `getblockheader` RPC calls in #31583, but it mistakingly always used the tip value.

  This PR fixes it to return the target for the given block. Because regtest does not have difficulty adjustment, the mainnet test is expanded to cover the fix.

  A preliminary commit deals with mining block 2016 that's needed for the test. It also:
  - renames the `create_coinbase` `retarget_period` argument to `halving_period`. Before #31583 this was hardcoded for regtest where these values are the same.
  - drops unused `fees` argument from `mine` helper
  - expands the CPU miner instructions for generating the alternative mainnet chain

  Fixes #33440

ACKs for top commit:
  sipa:
    utACK bf7996cbc3
  luke-jr:
    crACK bf7996cbc3
  TheCharlatan:
    ACK bf7996cbc3
  ismaelsadeeq:
    Code review ACK bf7996cbc3

Tree-SHA512: 2a2e11efd91f4aaccf9d2ec4dff9fd82c366b8a7e797ce5981dca2e6f08028f69154f4e6a27aef20d78b0e6c3304416789267c2fad42d7aa5072f8537d0c8b0d
2025-09-24 10:08:10 -04:00
merge-script 5ae8edbc30
Merge bitcoin/bitcoin#33158: macdeploy: avoid use of `Bitcoin Core` in Linux cross build
8e434a8499 macdeploy: rename macOS output to bitcoin-macos-app.zip (fanquake)
05353d9cf0 macdeploy: combine appname & -zip arguments (fanquake)

Pull request description:

  Output `bitcoin-macos-app.zip`, similar to what we do for Windows: `bitcoin-win64-setup.exe`.

ACKs for top commit:
  hodlinator:
    re-ACK 8e434a8499
  willcl-ark:
    ACK 8e434a8499

Tree-SHA512: e762c9866630c4f8c577027ee9492d74a5c7f4b194df73876d702703b9100c356a30986c2f209ba3f3e2d483017f5e61596a2a7cdfae0a684f8dc244420cd108
2025-09-24 09:59:45 -04:00
Ava Chow df67bb6fd8 test: Remove convert_to_json_for_cli 2025-09-23 12:58:00 -07:00
Ava Chow 44a493e150 cli: Allow arguments to be both strings and json 2025-09-23 12:57:34 -07:00
merge-script ad4a49090d
Merge bitcoin/bitcoin#33408: msvc: Update vcpkg manifest
ef20c2d11d build, msvc: Update vcpkg manifest baseline (Hennadii Stepanov)

Pull request description:

  This PR updates the vcpkg manifest baseline from the ["2025.03.19 Release"](https://github.com/microsoft/vcpkg/releases/tag/2025.03.19) to the ["2025.08.27 Release"](https://github.com/microsoft/vcpkg/releases/tag/2025.08.27), with the following package
  changes:
   - `boost`: 1.87.0 --> 1.88.0
   - `qtbase`: 6.8.2#1 -> 6.9.1
   - `qttools`: 6.8.2 -> 6.9.1
   - `sqlite3`: 3.49.1 --> 3.50.4

  The previous update was made in https://github.com/bitcoin/bitcoin/pull/32213.

ACKs for top commit:
  hodlinator:
    ACK ef20c2d11d

Tree-SHA512: 3c95fea911e1481b3536958d83dcaa52012abdff350cd08c21b30b3df61a501b2f3272e879882820bb59456066e9270de820bcb47810d3d1b8e8a1267d987d90
2025-09-23 15:54:39 -04:00
merge-script dd61f08fd5
Merge bitcoin/bitcoin#33031: wallet: Set descriptor cache upgraded flag for migrated wallets
88b0647f02 wallet: Always write last hardened cache flag in migrated wallets (Ava Chow)
8a08eef645 tests: Check that the last hardened cache upgrade occurs (Ava Chow)

Pull request description:

  #32597 set the descriptor cache upgraded flag for newly created wallets, but migrated wallets still did not have the flag set when they are migrated. For consistency, and to avoid an unnecessary upgrade, we should be setting this flag for migrated wallets.

  The flag would end up being set anyways at the end of migration when the wallet is reloaded as it would perform the automatic upgrade at that time. However, this is unnecessary and we should just set it from the get go.

  This PR also adds a couple tests to verify that the flag is being set, and that the upgrade is being performed.

ACKs for top commit:
  cedwies:
    re-ACK 88b0647
  rkrux:
    lgtm ACK 88b0647f02
  pablomartin4btc:
    ACK 88b0647f02

Tree-SHA512: 7d0850db0ae38eedd1e6a3bfaa548c6c612182291059fb1a47279a4c4984ee7914ecd02d8c7e427ef67bf9f5e67cbc57a7ae4412fad539e1bf3e05c512a60d69
2025-09-23 15:27:17 -04:00
merge-script 350692e561
Merge bitcoin/bitcoin#33388: test: don't throw from the destructor of DebugLogHelper
2427939935 test: forbid copying of DebugLogHelper (Daniel Pfeifer)
d6aa266d43 test: don't throw from the destructor of DebugLogHelper (Vasil Dimov)

Pull request description:

  Throwing an exception from the destructor of a class is a bad practice because the destructor will be called when an object of that type is alive on the stack and another exception is thrown, which will result in "exception during the exception". This would terminate the program without any messages.

  Instead print the message to the standard error output and call `std::abort()`.

  ---

  This change is part of https://github.com/bitcoin/bitcoin/pull/26812. It is an improvement on its own, so creating a separate PR for it following the discussion at https://github.com/bitcoin/bitcoin/pull/32604#discussion_r2345091587. Getting it in will reduce the size of #26812.

ACKs for top commit:
  Crypt-iQ:
    crACK 2427939
  l0rinc:
    Code review reACK 2427939935
  optout21:
    crACK 2427939935
  furszy:
    utACK 2427939935

Tree-SHA512: 918c1e40d2db4ded6213cd78a18490ad10a9f43c0533df64bdf09f0b216715415030e444712981e4407c32ebf552fbb0e3cce718e048df10c2b8937caf015564
2025-09-23 15:01:52 -04:00
Martin Zumsande 94db966a3b net: use generic network key for addrcache
The generic key can also be used in other places
where behavior between different network identities should
be uncorrelated to avoid fingerprinting.
This also changes RANDOMIZER_ID - since it is not
being persisted to disk, there are no compatibility issues.
2025-09-23 10:56:44 -04:00
fanquake eca50854e1
depends: static libxcb_cursor
Modern Ubuntu isn't shipping with this library installed by default.
Staticly link it to remove the need for end-users to install it.

Closes #33432.
2025-09-23 10:43:55 -04:00
merge-script 89144eb473
Merge bitcoin/bitcoin#33448: net/rpc: Report inv information for debugging
2738b63e02 test: validate behaviour of getpeerinfo last_inv_sequence and inv_to_send (Anthony Towns)
77b2ebb811 rpc/net: report per-peer last_inv_sequence (Anthony Towns)
adefb51c54 rpc/net: add per-peer inv_to_send sizes (Anthony Towns)

Pull request description:

  Adds per-peer entries to `getpeerinfo` for the size of the inv_to_send queue and the mempool sequence number as at the last INV. Can be helpful for debugging tx relay performance and privacy/fingerprinting issues.

ACKs for top commit:
  sipa:
    utACK 2738b63e02
  instagibbs:
    ACK 2738b63e02

Tree-SHA512: e3c9c52e8e38b099d405a177ffba6783c5821cc5ce1432b98218843e00906986ce2141dcd5b04a67006c328211a672e519fa3390e012688499bfc9ac99767599
2025-09-23 10:29:23 -04:00
merge-script eaa1a3cd0b
Merge bitcoin/bitcoin#33425: ci: remove Clang build from msan fuzz job
b77137a564 ci: link against -lstdc++ in native fuzz with msan job (fanquake)

Pull request description:

  Remove the Clang build from msan fuzz by using the apt install LLVM / Clang, and just linking against `-lstdc++`.

ACKs for top commit:
  maflcko:
    lgtm ACK b77137a564

Tree-SHA512: dc32b22a93196120a343d91265db3f42f6dc00afc887929986987ea62f2513580c855e98d088f037adb4c2e62358f98e47b914a412ef9c1069037917a36c0b03
2025-09-23 10:09:57 -04:00
fanquake b77137a564
ci: link against -lstdc++ in native fuzz with msan job 2025-09-23 09:53:58 -04:00
merge-script a86e1a6e32
Merge bitcoin/bitcoin#33427: rpc: Always return per-wtxid entries in submitpackage tx-results
cad9a7fd73 rpc: Always return per-wtxid entries in submitpackage tx-results (John Moffett)

Pull request description:

  Follow-up to #28848

  When `submitpackage` produced no per-transaction result for a member, the RPC set `"error": "unevaluated"` but then continued without inserting the entry into `tx-results`, making it impossible for callers to know which `wtxids` were unevaluated.

  This inserts the error result before continuing, updates help text, and adjusts functional tests to expect entries for all submitted `wtxids`.

ACKs for top commit:
  instagibbs:
    ACK cad9a7fd73
  glozow:
    ACK cad9a7fd73

Tree-SHA512: 8df5c9b3d1f17aaf0311c38f028ae4b55d4c52a660f85171f105c4f65d130b14ab00698ac5d7c27403a0c37fff391c154c3ad44cc99ba4d549d9c30751b8360f
2025-09-23 09:36:18 -04:00
merge-script 6861dadfcb
Merge bitcoin/bitcoin#33459: doc: remove unrelated `bitcoin-wallet` binary from `libbitcoin_ipc` description
fbde8d9a81 doc: remove unrelated `bitcoin-wallet` binary from `libbitcoin_ipc` description (Sebastian Falbesoner)

Pull request description:

  `bitcoin-wallet` as-is is merely an offline wallet inspection tool (introduced more than 9 years ago in PR #13926) that doesn't have any relation with IPC/multiprocess, so remove it from the list of binaries that use `libbitcoin_ipc`.

ACKs for top commit:
  pablomartin4btc:
    ACK fbde8d9a81

Tree-SHA512: e11720d35596575cd9785b9b00e6b11e46ba4c8aad6fe98e952d4aa4310f9e5c719dd2f177da8b5c3abefc831cbace0e1a0620f428d847f9bdcf7252a8889641
2025-09-23 09:11:15 -04:00
merge-script 3b3ab3a50a
Merge bitcoin/bitcoin#33302: ci: disable cirrus cache in 32bit arm job
00c253d494 ci: disable cirrus cache in 32bit arm job (will)
ff18b6bbaf ci: refactor docker action to return provider str (will)

Pull request description:

  Add an optional matrix field allowing opt-out of configuring cirrus GHA cache when not using cirrus runners.

  This is not needed for the cirruslabs/[save|restore]-cache actions, as they automatically fallback based on runner type.

  Addresses https://github.com/bitcoin/bitcoin/issues/31965#issuecomment-3252638785

ACKs for top commit:
  m3dwards:
    ACK 00c253d494

Tree-SHA512: 4c79deec2b0018f62a982b2d1051c78e94e242a1b8faf5db037353b05b707827dafded56c9b5ffbc861fcadac5a90571077e6ab69410975f7a2f40c755630a8e
2025-09-23 09:05:50 -04:00
Anthony Towns 2738b63e02 test: validate behaviour of getpeerinfo last_inv_sequence and inv_to_send
Co-Authored-By: MarcoFalke <*~=`'#}+{/-|&$^_@721217.xyz>
2025-09-23 14:58:01 +10:00
Sebastian Falbesoner fbde8d9a81 doc: remove unrelated `bitcoin-wallet` binary from `libbitcoin_ipc` description
`bitcoin-wallet` as-is is merely an offline wallet inspection tool
(introduced more than 9 years ago in PR #13926) that doesn't have any
relation with IPC/multiprocess, so remove it from the list of binaries
that use `libbitcoin_ipc`.
2025-09-22 21:07:41 +02:00
Hennadii Stepanov 34fefb6335
Merge bitcoin/bitcoin#33435: system: improve handling around GetTotalRAM()
56791b5829 test: split out `system_ram_tests` to signal when total ram cannot be determined (Lőrinc)
337a6e7386 system: improve handling around GetTotalRAM() (Vasil Dimov)

Pull request description:

  1. Fix unused variable warning (https://github.com/bitcoin/bitcoin/pull/33333#discussion_r2362493046)
  2. Enable `GetTotalRAM()` on other platforms where it was tested to work.
  3. Skip the `GetTotalRAM()` unit test on unsupported platforms.

  Prior discussion: https://github.com/bitcoin/bitcoin/pull/33333#discussion_r2362493046

ACKs for top commit:
  l0rinc:
    ACK 56791b5829
  hebasto:
    ACK 56791b5829.

Tree-SHA512: bc419aa55edad77473dbcf810f02d02fa0c45a6355a93d17f7881051117b753c584296ab3840893270ecdc9bb2bee0fe4e070607c6560b794e97a25da733c47d
2025-09-22 17:00:50 +01:00
Lőrinc 56791b5829
test: split out `system_ram_tests` to signal when total ram cannot be determined
when `GetTotalRAM` returns an `std::nullopt` now we're getting:
```
The following tests did not run:
        106 - system_ram_tests (Skipped)
```
2025-09-22 12:25:45 +02:00
Vasil Dimov 337a6e7386
system: improve handling around GetTotalRAM()
This patch achieves two things:
1. Fix unused variable warning (https://github.com/bitcoin/bitcoin/pull/33333#discussion_r2362493046)
2. Enable GetTotalRAM() on other platforms where it was tested to work.

Co-authored-by: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com>
2025-09-22 12:24:49 +02:00
Anthony Towns 451ba9ada4
datacarrier: Undeprecate configuration option
Reverts commit 0b4048c733
2025-09-22 02:47:02 -05:00
Anthony Towns 77b2ebb811 rpc/net: report per-peer last_inv_sequence 2025-09-22 10:46:26 +10:00
Sjors Provoost bf7996cbc3
rpc: fix getblock(header) returns target for tip
A target field was added to the getblock and getblockheader RPC calls in bitcoin#31583, but it mistakingly always used the tip value.

Because regtest does not have difficulty adjustment, a test is added for mainnet instead.
2025-09-20 21:36:39 +02:00
Sjors Provoost 4c3c1f42cf
test: add block 2016 to mock mainnet
The next commit requires an additional mainnet block which changes the difficulty.

Also fix a few minor mistakes in the test (suite):
- rename the create_coinbase retarger_period argument to halving_period. Before bitcoin#31583 this was hardcoded for regtest where these values are the same.
- drop unused fees argument from mine helper

Finally the CPU miner instructions for generating the alternative mainnet chain are expanded.
2025-09-20 21:36:39 +02:00
merge-script 953544d028
Merge bitcoin/bitcoin#33429: fuzz: reduce iterations in slow targets
6a33970fef fuzz: Reduce iterations in slow targets (marcofleon)

Pull request description:

  The `mini_miner`, `txdownloadman`, `txdownloadman_impl`, and `tx_pool_standard` fuzz targets are all slow-running targets. Fix this by reducing the iteration count in the `LIMITED_WHILE` loops.

  This should help decrease the run time of the fuzz CI jobs. See https://github.com/bitcoin/bitcoin/pull/33425.

  Addresses https://github.com/bitcoin/bitcoin/issues/32870 as well.

ACKs for top commit:
  Crypt-iQ:
    crACK 6a33970fef
  dergoegge:
    utACK 6a33970fef
  enirox001:
    Concept ACK 6a33970
  brunoerg:
    ACK 6a33970fef

Tree-SHA512: d03d687507f497e587f7199866266298ca67d9843985dc96d1c957a6fbffb3c6cd5144a4876c471b84c84318295b0438908c745f3a4ac0254dca3e72655ecc14
2025-09-20 14:53:31 +01:00
Hennadii Stepanov df101c97c2
Merge bitcoin/bitcoin#33422: build: Remove lingering Windows registry & shortcuts (#32132 follow-up)
79752b9c0b build(windows): Remove lingering registry entries and shortcuts upon install (Hodlinator)

Pull request description:

  ### Problem

  Prior to fb2b05b125 / #32132 we installed using paths with an extra " (64-bit)"-suffix. Installing a version including that commit on top of a version that does not results in 2 entries in the "Installed apps" list. Both of them end up running the same `C:\Program Files\Bitcoin\uninstall.exe`. However, only one of the entries is removed by the uninstaller. The left over registry entry will now point to an executable that no longer exists and fail to work.

  Removing the left over "Installed apps"  entry on master currently requires the user to manually remove the Windows Registry entries (or run the correct old/new installer to ensure the uninstaller exists again).

  ### Solution

  This PR automates removal of old entries (& shortcuts) when installing the new version.

  ### Disclaimer

  Not an NSIS expert - confirmed that added deletion commands work without causing any visible errors both when prior items exist and when they don't.

ACKs for top commit:
  achow101:
    ACK 79752b9c0b
  hebasto:
    ACK 79752b9c0b.

Tree-SHA512: d23bd2e8f035ca93c3bd6187b3e5545c89c541b51d7b2b91b79bae1ebe328cd08c38b57e75a39bb376771fc85a537fe1d628903b9eadd32d04c3eb976c2e6d87
2025-09-19 22:49:43 +01:00
merge-script 56c6daa64f
Merge bitcoin/bitcoin#28592: p2p: Increase tx relay rate
b81f37031c p2p: Increase tx relay rate (Anthony Towns)

Pull request description:

  In the presence of smaller transactions on the network, blocks can sustain a higher relay rate than 7tx/second. In this event, the per-peer inventory queues can grow too large.

  This commit bumps the rate up to 14 tx/s (for inbound peers), increasing the safety margin by a factor of 2.

  Outbound peers continue to receive relayed transactions at 2.5x the rate of inbound peers, for a rate of 35tx/second.

ACKs for top commit:
  sipa:
    ACK b81f37031c
  achow101:
    ACK b81f37031c
  darosior:
    utACK b81f37031c.
  glozow:
    utACK b81f37031c

Tree-SHA512: 854ea0824d5f4c629f1dceb9ee61cc9226c8f0d4d26664737e68db917f65341d4800362ab55ed32673db920b2b59aa116b4cb9ee063367b2e43c94a904b41c08
2025-09-19 17:53:45 +01:00
Hodlinator 79752b9c0b
build(windows): Remove lingering registry entries and shortcuts upon install
Prior releases installed using these paths. Especially annoying was that the lingering registry entry for the uninstaller would show up as "Bitcoin Core (64-bit)" besides the current "Bitcoin Core" entry in the list of installed programs, and whichever was uninstalled last would fail to work as they would default to the same install directory.
2025-09-19 16:40:58 +02:00
John Moffett cad9a7fd73 rpc: Always return per-wtxid entries in submitpackage tx-results
When submitpackage produced no per-transaction result for a member,
the RPC previously set "error": "unevaluated" but then continued
without inserting the entry into tx-results, making it impossible for
callers to know which wtxids were unevaluated.

Insert the placeholder result before continuing, update help text, and
adjust functional tests to expect entries for all submitted wtxids.
2025-09-19 10:29:00 -04:00
marcofleon 6a33970fef fuzz: Reduce iterations in slow targets 2025-09-19 15:13:15 +01:00
merge-script edb871cba2
Merge bitcoin/bitcoin#33412: Update libmultiprocess subtree to fix intermittent mptest hang
535fa0ad0d Squashed 'src/ipc/libmultiprocess/' changes from 13424cf2ecc1..47d79db8a552 (Ryan Ofsky)

Pull request description:

  Includes:

  - https://github.com/bitcoin-core/libmultiprocess/pull/207
  - https://github.com/bitcoin-core/libmultiprocess/pull/208
  - https://github.com/bitcoin-core/libmultiprocess/pull/211
  - https://github.com/bitcoin-core/libmultiprocess/pull/201

  The last change fixes the test hang reported https://github.com/bitcoin/bitcoin/issues/33244

  The changes can be verified by running `test/lint/git-subtree-check.sh src/ipc/libmultiprocess` as described in [developer notes](https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#subtrees) and [lint instructions](https://github.com/bitcoin/bitcoin/tree/master/test/lint#git-subtree-checksh)

ACKs for top commit:
  Sjors:
    ACK c49a43591f
  TheCharlatan:
    ACK c49a43591f

Tree-SHA512: e87e92caee20693d969308a9250804ffdea4d6fb84a23a2399c3ee43419e6dceb46a224e2410d35a5690dea14b5af9e94017a8f2ca733fa27781154ef8377e6d
2025-09-19 10:54:01 +01:00
Daniel Pfeifer 2427939935
test: forbid copying of DebugLogHelper 2025-09-19 11:27:44 +02:00
Vasil Dimov d6aa266d43
test: don't throw from the destructor of DebugLogHelper
Throwing an exception from the destructor of a class is a bad practice,
avoid that and instead print the message to the standard error output
and call `std::abort()`.
2025-09-19 11:27:40 +02:00
Ava Chow eaf2c46475
Merge bitcoin/bitcoin#33378: Remove unnecessary casts when calling socket operations
67f632b6de net: remove unnecessary casts in socket operations (Matthew Zipkin)

Pull request description:

  During review of https://github.com/bitcoin/bitcoin/pull/32747 several casting operations were questioned in existing code that had been copied or moved. That lead me to find a few other similar casts in the codebase.

  It turns out that since the `Sock` class wraps syscalls with its own internal casting (see https://github.com/bitcoin/bitcoin/pull/24357 and https://github.com/bitcoin/bitcoin/pull/20788 written in 2020-2022) we no longer need to cast the arguments when calling these functions. The original argument-casts are old and were cleaned up a bit in https://github.com/bitcoin/bitcoin/pull/12855 written in 2018.

  The casting is only needed for windows compatibility, where those syscalls require a data argument to be of type `char*` specifically:

  https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-getsockopt

  ```
  int getsockopt(
    [in]      SOCKET s,
    [in]      int    level,
    [in]      int    optname,
    [out]     char   *optval,
    [in, out] int    *optlen
  );
  ```

  but on POSIX the argument is `void*`:

  https://www.man7.org/linux/man-pages/man2/getsockopt.2.html

  ```
         int getsockopt(socklen *restrict optlen;
                        int sockfd, int level, int optname,
                        void optval[_Nullable restrict *optlen],
                        socklen_t *restrict optlen);
  ```

ACKs for top commit:
  Raimo33:
    ACK 67f632b6de
  achow101:
    ACK 67f632b6de
  hodlinator:
    ACK 67f632b6de
  vasild:
    ACK 67f632b6de
  davidgumberg:
    ACK 67f632b6de

Tree-SHA512: c326d7242698b8d4d019f630fb6281398da2773c4e5aad1e3bba093a012c2119ad8815f42bd009e61a9a90db9b8e6ed5c75174aac059c9df83dd3aa5618a9ba6
2025-09-18 13:53:51 -07:00
Ava Chow 5aec516b2c
Merge bitcoin/bitcoin#33333: coins: warn on oversized `-dbcache`
168360f4ae coins: warn on oversized -dbcache (Lőrinc)
6c720459be system: add helper for fetching total system memory (Lőrinc)

Pull request description:

  ### Summary

  Oversized allocations can cause out-of-memory errors or [heavy swapping](https://github.com/getumbrel/umbrel-os/issues/64#issuecomment-663637321), [grinding the system to a halt](https://x.com/murchandamus/status/1964432335849607224).

  ### Fix

  Added a minimal system helper to query total physical RAM on [Linux/macOS/Windows](https://stackoverflow.com/a/2513561) (on unsupported platforms we just disable this warning completely).
  The added test checks if the value is roughly correct by checking if the CI platforms are returning any value and if the value is at least 1 GB (as a simple property test checking if the unit size is correct, e.g. doesn't return megabytes or bits).

  ### Details

  `LogOversizedDbCache()` now emits a startup warning if the configured `-dbcache` exceeds a cap derived from system RAM, using the same parsing/clamping as cache sizing via `CalculateDbCacheBytes()`. This isn't meant as a recommended setting, rather a likely upper limit.

  Note that we're not modifying the set value, just issuing a warning.
  Also note that the 75% calculation is rounded for the last two numbers since we have to divide first before multiplying, otherwise we wouldn't stay inside `size_t` on 32-bit systems - and this was simpler than casting back and forth.

  We could have chosen the remaining free memory for the warning (e.g. warn if free memory is less than 1 GiB), but this is just a heuristic, we assumed that on systems with a lot of memory, other processes are also running, while memory constrained ones run only Core.

  ### Cap

  If total RAM < 2 GiB, cap is `DEFAULT_DB_CACHE` (`450 MiB`), otherwise it's 75% of total RAM.
  The threshold is chosen to be close to values commonly used in [raspiblitz](https://github.com/raspiblitz/raspiblitz/blob/dev/home.admin/_provision.setup.sh#L98-L115) for common setups:

  | Total RAM | `dbcache` (MiB) | raspiblitz % | proposed cap (MiB) |
  |----------:|----------------:|-------------:|-------------------:|
  |     1 GiB |             512 |        50.0% |               450* |
  |     2 GiB |            1536 |        75.0% |               1536 |
  |     4 GiB |            2560 |        62.5% |               3072 |
  |     8 GiB |            4096 |        50.0% |               6144 |
  |    16 GiB |            4096 |        25.0% |              12288 |
  |    32 GiB |            4096 |        12.5% |              24576 |

  [Umbrel issues](https://github.com/getumbrel/umbrel-os/issues/64#issuecomment-663816367) also mention 75% being the upper limit.

  ### Reproducer

  Starting `bitcoind` on an 8 GiB rpi4b with a dbcache of 7 GiB:
  > ./build/bin/bitcoind -dbcache=7000

  warns now as follows:
  ```
  2025-09-07T17:24:29Z [warning] A 7000 MiB dbcache may be too large for a system memory of only 7800 MiB.
  Warning: A 7000 MiB dbcache may be too large for a system memory of only 7800 MiB.
  2025-09-07T17:24:29Z Cache configuration:
  2025-09-07T17:24:29Z * Using 2.0 MiB for block index database
  2025-09-07T17:24:29Z * Using 8.0 MiB for chain state database
  2025-09-07T17:24:29Z * Using 6990.0 MiB for in-memory UTXO set (plus up to 286.1 MiB of unused mempool space)
  ```

  ### Manual testing

  Besides the [godbolt](https://godbolt.org/z/ec81Tjvrj) reproducers for the new total memory method, we also tested the warnings manually on:
  - [x] Apple M4 Max, macOS 15.6.1
  - [x] Intel Core i9-9900K, Ubuntu 24.04.2 LTS
  - [x] Raspberry Pi 4 Model B, Armbian Linux 6.12.22-current-bcm2711
  - [x] Intel Xeon x64, Windows 11 Home Version 24H2, OS Build 26100.4351

ACKs for top commit:
  achow101:
    ACK 168360f4ae
  w0xlt:
    reACK 168360f4ae
  hodlinator:
    re-ACK 168360f4ae
  danielabrozzoni:
    reACK 168360f4ae

Tree-SHA512: aa0c9b1034d55a6a4212685a19715d8cd89668ab7c33c688711a15559e6ad81aa65f3cd8b488c91385306e1e16cd9eeefa8f659ba90ef19ce9c7a2e64f8b561a
2025-09-18 11:42:02 -07:00
John Moffett 316a0c5132 rpc: addpeeraddress: throw on invalid IP
Throw RPC_CLIENT_INVALID_IP_OR_SUBNET when LookupHost(addr, false) fails
in addpeeraddress. This aligns with setban/addconnection and avoids the
opaque {"success": false} result for input errors. The JSON {success,
error?} object remains for addrman outcomes only. Update test to match.
2025-09-18 14:29:50 -04:00
merge-script 74fa028da1
Merge bitcoin/bitcoin#33420: test: Avoid interface_ipc.py Duplicate ID errors
e9c52272eb test: Avoid interface_ipc.py Duplicate ID errors (Ryan Ofsky)

Pull request description:

  This change should fix issue https://github.com/bitcoin/bitcoin/issues/33417 reported by zaidmstrr. It's possible to reproduce the `mp/proxy.capnp:0: failed: Duplicate ID @0xcc316e3f71a040fb` error by installing libmultiprocess system-wide, or to one of the locations listed in the python test's `imports` list before the local libmultiprocess subtree, and then running the test.

ACKs for top commit:
  zaidmstrr:
    Tested ACK [e9c5227](e9c52272eb)

Tree-SHA512: 5df7fe767989b91245ce96f7c43b6767b7af49ec6c7007175e462341ffd69e161f21632697804060ce286b3e102a8d141a57a53f7e0e32299ef9a3a69ca8794a
2025-09-18 11:34:44 +01:00
Lőrinc 168360f4ae coins: warn on oversized -dbcache
Oversized allocations can cause out-of-memory errors or [heavy swapping](https://github.com/getumbrel/umbrel-os/issues/64#issuecomment-663637321), [grinding the system to a halt](https://x.com/murchandamus/status/1964432335849607224).

`LogOversizedDbCache()` now emits a startup warning if the configured `-dbcache` exceeds a cap derived from system RAM, using the same parsing/clamping as cache sizing via CalculateDbCacheBytes(). This isn't meant as a recommended setting, rather a likely upper limit.

Note that we're not modifying the set value, just issuing a warning.
Also note that the 75% calculation is rounded for the last two numbers since we have to divide first before multiplying, otherwise we wouldn't stay inside size_t on 32-bit systems - and this was simpler than casting back and forth.

We could have chosen the remaining free memory for the warning (e.g. warn if free memory is less than 1 GiB), but this is just a heuristic, we assumed that on systems with a lot of memory, other processes are also running, while memory constrained ones run only Core.

If total RAM < 2 GiB, cap is `DEFAULT_DB_CACHE` (`450 MiB`), otherwise it's 75% of total RAM.
The threshold is chosen to be close to values commonly used in [raspiblitz](https://github.com/raspiblitz/raspiblitz/blob/dev/home.admin/_provision.setup.sh#L98-L115) for common setups:

| Total RAM | `dbcache` (MiB) | raspiblitz % | proposed cap (MiB) |
|----------:|----------------:|-------------:|-------------------:|
|     1 GiB |             512 |        50.0% |               450* |
|     2 GiB |            1536 |        75.0% |               1536 |
|     4 GiB |            2560 |        62.5% |               3072 |
|     8 GiB |            4096 |        50.0% |               6144 |
|    16 GiB |            4096 |        25.0% |              12288 |
|    32 GiB |            4096 |        12.5% |              24576 |

[Umbrel issues](https://github.com/getumbrel/umbrel-os/issues/64#issuecomment-663816367) also mention 75% being the upper limit.

Starting `bitcoind` on an 8 GiB rpi4b with a dbcache of 7 GiB:
> ./build/bin/bitcoind -dbcache=7000

warns now as follows:
```
2025-09-07T17:24:29Z [warning] A 7000 MiB dbcache may be too large for a system memory of only 7800 MiB.
2025-09-07T17:24:29Z Cache configuration:
2025-09-07T17:24:29Z * Using 2.0 MiB for block index database
2025-09-07T17:24:29Z * Using 8.0 MiB for chain state database
2025-09-07T17:24:29Z * Using 6990.0 MiB for in-memory UTXO set (plus up to 286.1 MiB of unused mempool space)
```

Besides the [godbolt](https://godbolt.org/z/EPsaE3xTj) reproducers for the new total memory method, we also tested the warnings manually on:
- [x] Apple M4 Max, macOS 15.6.1
- [x] Intel Core i9-9900K, Ubuntu 24.04.2 LTS
- [x] Raspberry Pi 4 Model B, Armbian Linux 6.12.22-current-bcm2711
- [x] Intel Xeon x64, Windows 11 Home Version 24H2, OS Build 26100.4351

Co-authored-by: stickies-v <stickies-v@protonmail.com>
Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
Co-authored-by: w0xlt <woltx@protonmail.com>
2025-09-17 11:36:21 -07:00
Lőrinc 6c720459be system: add helper for fetching total system memory
Added a minimal system helper to query total physical RAM on [Linux/macOS/Windows](https://stackoverflow.com/a/2513561) (on other platforms we just return an empty optional).

The added test checks if the value is roughly correct by checking if the CI platforms are returning any value and if the value is at least 1 GiB and not more than 10 TiB.

The max value is only validated on 64 bits, since it's not unreasonable for 32 bits to have max memory, but on 64 bits it's likely an error.

https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-memorystatusex
> ullTotalPhys The amount of actual physical memory, in bytes.

https://man7.org/linux/man-pages/man3/sysconf.3.html:
> _SC_PHYS_PAGES The number of pages of physical memory. Note that it is possible for the product of this value and the value of _SC_PAGESIZE to overflow.
> _SC_PAGESIZE Size of a page in bytes. Must not be less than 1.

See https://godbolt.org/z/ec81Tjvrj for further details
2025-09-17 11:36:21 -07:00
Ryan Ofsky e9c52272eb test: Avoid interface_ipc.py Duplicate ID errors
This change should fix issue https://github.com/bitcoin/bitcoin/issues/33417
reported by zaidmstrr. It's possible to reproduce the `mp/proxy.capnp:0:
failed: Duplicate ID @0xcc316e3f71a040fb` error by installing libmultiprocess
system-wide, or to one of the locations listed in the python test's `imports`
list before the local libmultiprocess subtree, and then running the test.
2025-09-17 12:34:07 -04:00
Ryan Ofsky c49a43591f Merge commit '535fa0ad0d2637f845beae92ea9dbbbbbe377c74' into pr/subtree-5 2025-09-17 05:30:43 -04:00
Ryan Ofsky 535fa0ad0d Squashed 'src/ipc/libmultiprocess/' changes from 13424cf2ecc1..47d79db8a552
47d79db8a552 Merge bitcoin-core/libmultiprocess#201: bug: fix mptest hang, ProxyClient<Thread> deadlock in disconnect handler
f15ae9c9b9fb Merge bitcoin-core/libmultiprocess#211: Add .gitignore
4a269b21b8c8 bug: fix ProxyClient<Thread> deadlock if disconnected as IPC call is returning
85df96482c49 Use try_emplace in SetThread instead of threads.find
ca9b380ea91a Use std::optional in ConnThreads to allow shortening locks
9b0799113557 doc: describe ThreadContext struct and synchronization requirements
d60db601ed9b proxy-io.h: add Waiter::m_mutex thread safety annotations
4e365b019a9f ci: Use -Wthread-safety not -Wthread-safety-analysis
15d7bafbb001 Add .gitignore
fe1cd8c76131 Merge bitcoin-core/libmultiprocess#208: ci: Test minimum cmake version in olddeps job
b713a0b7bfbc Merge bitcoin-core/libmultiprocess#207: ci: output CMake version in CI script
0f580397c913 ci: Test minimum cmake version in olddeps job
d603dcc0eef0 ci: output CMake version in CI script

git-subtree-dir: src/ipc/libmultiprocess
git-subtree-split: 47d79db8a5528097b408e18f7b0bae11a6702d26
2025-09-17 05:30:43 -04:00
Ryan Ofsky 453b0fa286 bitcoin: Make wrapper not require -m
Choose the right binary by default if an IPC option is specified
2025-09-17 04:57:09 -04:00
merge-script 1444ed855f
Merge bitcoin/bitcoin#33407: cmake: Install `bitcoin` manpage
7584a4fda9 cmake: Install `bitcoin` manpage (Hennadii Stepanov)

Pull request description:

  This PR is an amendment to https://github.com/bitcoin/bitcoin/pull/31375.

ACKs for top commit:
  ryanofsky:
    Code review ACK 7584a4fda9.

Tree-SHA512: 66810c1d65fa8ae469b8161a5f807aa7b43a7b18e88d40b05617c7110b2e03e07bcb8f310c1736fb2c3738e274fc524032ff5d34d5c644824a4edd64372f1e9f
2025-09-17 09:57:09 +01:00
Ryan Ofsky 29e836fae6 test: add tool_bitcoin to test bitcoin wrapper behavior 2025-09-17 04:57:09 -04:00
Ryan Ofsky 0972f55040 init: add exe name to bitcoind, bitcoin-node -version output to be able to distinguish these in tests 2025-09-17 04:57:09 -04:00
merge-script 2b0cd1f3fb
Merge bitcoin/bitcoin#33395: net: do not apply whitelist permissions to onion inbounds
f563ce9081 net: Do not apply whitelist permission to onion inbounds (Martin Zumsande)

Pull request description:

  Tor inbound connections do not reveal the peer's actual network address. Do not apply whitelist permissions to them since address-based matching is ineffective.

ACKs for top commit:
  darosior:
    ACK f563ce9081
  furszy:
    ACK f563ce9081
  vasild:
    ACK f563ce9081

Tree-SHA512: 49ae70e382fc2f78b7073553fe649a6843a41214b2986ea7f77e285d02b7bd00fe0320a1b71d1aaca08713808fb14af058f0b1f19f19adb3a77b97cb9d3449ce
2025-09-17 09:53:55 +01:00
Hennadii Stepanov ef20c2d11d
build, msvc: Update vcpkg manifest baseline
This change updates the vcpkg manifest baseline from the "2025.03.19
Release" to the "2025.08.27 Release", with the following package
changes:
 - boost: 1.87.0 --> 1.88.0
 - qtbase: 6.8.2#1 -> 6.9.1
 - qttools: 6.8.2 -> 6.9.1
 - sqlite3: 3.49.1 --> 3.50.4
2025-09-16 22:03:27 +01:00
Sebastian Falbesoner 1ff9e92948 key: use static context for libsecp256k1 calls where applicable
The dynamically created signing context for libsecp256k1 calls is only
needed for functions that involve generator point multiplication with a
secret key, i.e. different variants of public key creation and signing.
The API docs hint to this by stating "not secp256k1_context_static" for
the context parameter. In our case that applies to the following calls:
- `secp256k1_ec_pubkey_create`
- `secp256k1_keypair_create`
- `secp256k1_ellswift_create`
- `secp256k1_ecdsa_sign`
- `secp256k1_ecdsa_sign_recoverable`
- `secp256k1_schnorrsig_sign32`
- `ec_seckey_export_der` (not a direct secp256k1 function, but calls
  `secp256k1_ec_pubkey_create` inside)

For all the other secp256k1 calls we can simply use the static context.
2025-09-16 21:46:18 +02:00
Martin Zumsande f563ce9081 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>
2025-09-16 13:35:34 -04:00
merge-script 947bed28fe
Merge bitcoin/bitcoin#33380: test: Add submitblock test in interface_ipc
0a26731c4c test: Add submitblock test in interface_ipc (TheCharlatan)

Pull request description:

  Expands the ipc mining test a bit with submitting a solved block and checking its validity.

ACKs for top commit:
  Sjors:
    ACK 0a26731c4c
  marcofleon:
    code review ACK 0a26731c4c
  zaidmstrr:
    Tested ACK [0a26731](0a26731c4c)

Tree-SHA512: 35c87d88496eec469bddedf2ae82c494626abb47ae15d5a45d6ab0400199c86501199c3e569e83836549830042be76b197b470e1100a317bdfef2578a9d5a92f
2025-09-16 12:44:35 -04:00
Hennadii Stepanov 7584a4fda9
cmake: Install `bitcoin` manpage 2025-09-16 14:18:59 +01:00
Matthew Zipkin 67f632b6de
net: remove unnecessary casts in socket operations
These methods in the Sock class wrap corresponding syscalls,
accepting void* arguments and casting to char* internally, which is
needed for Windows support and ignored on other platforms because
the syscall itself accepts void*:

Send()
Recv()
GetSockOpt()
SetSockOpt()
2025-09-16 06:26:01 -04:00
merge-script c4adfbf706
Merge bitcoin/bitcoin#33373: depends: systemtap 5.3
28efd724b4 depends: systemtap 5.3 (fanquake)

Pull request description:

  The diff in the copied header is:
  ```diff
  < #if __STDC_VERSION__ >= 199901L
  ---
  > #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
  ```

  From
  https://sourceware.org/git/?p=systemtap.git;a=commit;h=b8345d8e07b725a943a97b19aa4866e74baadd98.

ACKs for top commit:
  0xB10C:
    ACK 28efd724b4

Tree-SHA512: 30eb4656d354e463937b68f8977d3c3bfe1e5a63be19a9e446a41cabcd1222290f4c7ecc64e516c4f5cc38b744229906fd92a9a56f4e1380dfb8db9ed518ebb4
2025-09-16 11:20:54 +01:00
Ava Chow 5aa3d3135d
Merge bitcoin/bitcoin#33391: test: Prevent disk space warning during node_init_tests
bdf01c6f61 test: Prevent disk space warning during node_init_tests (Ryan Ofsky)

Pull request description:

  mzumsande pointed out https://github.com/bitcoin/bitcoin/pull/32345#issuecomment-3286964369 that this test was print a warning:

  ```
  Warning: Disk space for "/tmp/test_common bitcoin/node_init_tests/init_test/bf78678cb7723a3e84b5/blocks" may not accommodate the block files. Approximately 810 GB of data will be stored in this directory.
  ```

  Fix by setting regtest instead of mainnet network before running the test.

ACKs for top commit:
  achow101:
    ACK bdf01c6f61
  Eunovo:
    Tested ACK bdf01c6f61:
  janb84:
    ACK bdf01c6f61
  l0rinc:
    tested ACK bdf01c6f61
  mzumsande:
    utACK bdf01c6f61
  enirox001:
    utACK bdf01c6

Tree-SHA512: ac4e1e48246c84a4c4b80ccb25e962b0090359ab0e541ee4f1a9e18ac9da8ec35a78c9a55501d231423053e945ff785862f0db141d4b620d622327670c764f8c
2025-09-15 18:21:08 -07:00
Ryan Ofsky bdf01c6f61 test: Prevent disk space warning during node_init_tests
mzumsande pointed out https://github.com/bitcoin/bitcoin/pull/32345#issuecomment-3286964369 that this test was causing a warning:

   Warning: Disk space for "/tmp/test_common bitcoin/node_init_tests/init_test/bf78678cb7723a3e84b5/blocks" may not accommodate the block files. Approximately 810 GB of data will be stored in this directory.

Fix by setting regtest instead of mainnet network before running the test.
2025-09-15 09:48:36 -04:00
TheCharlatan 0a26731c4c
test: Add submitblock test in interface_ipc
Co-Authored-By: Sjors Provoost <sjors@sprovoost.nl>
2025-09-15 12:25:43 +02:00
merge-script 2d6a0c4649
Merge bitcoin/bitcoin#33379: cmake: Fix regression in `secp256k1.cmake`
9193c3e434 cmake: Fix regression in `secp256k1.cmake` (Hennadii Stepanov)

Pull request description:

  This PR fixes a regression introduced in https://github.com/bitcoin/bitcoin/pull/33101 (mea culpa).

  From the CMake [docs](https://cmake.org/cmake/help/latest/command/enable_language.html):
  > The following restrictions apply to where `enable_language()` may be called:
  >
  >    - It must be called in file scope, not in a function call.

  Fixes https://github.com/bitcoin/bitcoin/issues/33153.

ACKs for top commit:
  TheCharlatan:
    ACK 9193c3e434
  furszy:
    ACK 9193c3e434

Tree-SHA512: 5f9ca2209af195a5eefefffdceae1acf650db29b371616f803b482a6b8acc4e87acc66714488520ef91d06ad4436438d9030be9979bd4c482cb5d1ce65b7f67e
2025-09-15 09:49:29 +01:00
Hennadii Stepanov 9193c3e434
cmake: Fix regression in `secp256k1.cmake`
The `enable_language` command must be called in file scope, not in a
function call.

See: https://cmake.org/cmake/help/latest/command/enable_language.html
2025-09-12 17:56:12 +01:00
fanquake 28efd724b4
depends: systemtap 5.3
The diff in the copied header is:
```diff
< #if __STDC_VERSION__ >= 199901L
---
> #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
```

From
https://sourceware.org/git/?p=systemtap.git;a=commit;h=b8345d8e07b725a943a97b19aa4866e74baadd98.
2025-09-12 11:59:45 +01:00
Lőrinc 75e6984ec8 test/refactor: use test deque to avoid quadratic iteration
Extracted from https://github.com/bitcoin/bitcoin/pull/33141#discussion_r2323012972.
In Python, list `pop(0)` is linear, so consuming all items is quadratic.
Switched to `collections.deque` with `popleft()` to express FIFO intent and avoid the O(n^2) path.
Behavior is unchanged; for a few hundred items the perf impact is likely negligible.

Ref: https://docs.python.org/3/tutorial/datastructures.html#using-lists-as-queues
> While appends and pops from the end of list are fast, doing inserts or pops
> from the beginning of a list is slow (because all of the other elements have
> to be shifted by one).

Co-authored-by: maflcko <6399679+maflcko@users.noreply.github.com>
2025-09-11 13:09:23 -07:00
Anthony Towns 652424ad16 test: additional test coverage for script_verify_flags 2025-09-11 11:24:09 +10:00
will 00c253d494
ci: disable cirrus cache in 32bit arm job
Co-authored-by: Max Edwards <youwontforgetthis@gmail.com>
Add an optional matrix field allowing opt-out of configuring cirrus
GHA cache when not using cirrus runners.

This is not needed for the cirruslabs/[save|restore]-cache actions, as
they automatically fallback based on runner type.
2025-09-10 21:34:09 +01:00
will ff18b6bbaf
ci: refactor docker action to return provider str
Avoid relying on future truthy evaluations of string 'false'.
2025-09-10 21:34:07 +01:00
fanquake 8e434a8499
macdeploy: rename macOS output to bitcoin-macos-app.zip
We were naming this "Bitcoin-Core.zip", just to immediately rename it.
Similar to what we do with Windows, i.e `bitcoin-win64-setup.exe`.
2025-09-03 13:00:38 +01:00
fanquake 05353d9cf0
macdeploy: combine appname & -zip arguments
appname is only used by -zip.
2025-09-03 13:00:35 +01:00
MarcoFalke fabc2615af
test: Use extra_port() helper in feature_bind_extra.py 2025-08-27 09:46:26 +02:00
Anthony Towns 417437eb01 script/verify_flags: extend script_verify_flags to 64 bits 2025-08-14 10:17:32 +10:00
Anthony Towns 3cbbcb66ef script/interpreter: make script_verify_flag_name an ordinary enum
Instead of having `SCRIPT_VERIFY_FOO = (1U << n)` just have it
be `n` directly, and do the bit shifting when converting it to
`script_verify_flags`.
2025-08-14 10:17:32 +10:00
Anthony Towns bddcadee82 script/verify_flags: make script_verify_flags type safe
`using script_verify_flags = uint32_t` allows implicit conversion to
and from int, so replace it with a class to have the compiler ensure we
use the correct type. Provide from_int and as_int to allow for explicit
conversions when desired.

Introduces the type `script_verify_flag_name` for the individual flag
name enumeration.
2025-08-14 10:17:32 +10:00
Anthony Towns a5ead122fe script/interpreter: introduce script_verify_flags typename
Previously the SCRIPT_VERIFY_* flags were specified as either uint32_t,
unsigned int, or unsigned. This converts them to a common type alias in
preparation for changing the underlying type.
2025-08-14 10:17:32 +10:00
Anthony Towns 4577fb2b1e rpc: have getdeploymentinfo report script verify flags 2025-08-14 10:17:32 +10:00
Anthony Towns a3986935f0 validation: export GetBlockScriptFlags() 2025-08-14 10:17:32 +10:00
Anthony Towns 5db8cd2d37 Move mapFlagNames and FormatScriptFlags logic to script/interpreter.h
Moves FormatScriptFlags logic into GetScriptFlagNames which returns a
vector of strings. For completeness, also has GetScriptFlagNames report
on any bits that do not match a known script flag.
2025-08-14 10:17:30 +10:00
Anthony Towns adefb51c54 rpc/net: add per-peer inv_to_send sizes 2025-08-13 13:21:26 +10:00
Ava Chow 88b0647f02 wallet: Always write last hardened cache flag in migrated wallets 2025-07-31 10:29:32 -07:00
Ava Chow 8a08eef645 tests: Check that the last hardened cache upgrade occurs
When loading an older wallet without the last hardened cache, an
automatic upgrade should be performed. Check this in
wallet_backwards_compatibility.py

When migrating a wallet, the migrated wallet should always have the last
hardened cache, so verify in wallet_migration.py
2025-07-31 10:29:32 -07:00
Vasil Dimov 0802398e74
fuzz: make it possible to mock (fuzz) CThreadInterrupt
* Make the methods of `CThreadInterrupt` virtual and store a pointer to
  it in `CConnman`, thus making it possible to override with a mocked
  instance.
* Initialize `CConnman::m_interrupt_net` from the constructor, making it
  possible for callers to supply mocked version.
* Introduce `FuzzedThreadInterrupt` and `ConsumeThreadInterrupt()` and
  use them in `src/test/fuzz/connman.cpp` and `src/test/fuzz/i2p.cpp`.

This improves the CPU utilization of the `connman` fuzz test.

As a nice side effect, the `std::shared_ptr` used for
`CConnman::m_interrupt_net` resolves the possible lifetime issues with
it (see the removed comment for that variable).
2025-06-09 14:17:33 +02:00
Vasil Dimov 6d9e5d130d
fuzz: add CConnman::SocketHandler() to the tests 2025-06-09 14:17:33 +02:00
Vasil Dimov 3265df63a4
fuzz: add CConnman::InitBinds() to the tests 2025-06-09 14:17:29 +02:00
Vasil Dimov 91cbf4dbd8
fuzz: add CConnman::CreateNodeFromAcceptedSocket() to the tests 2025-06-09 14:13:53 +02:00
Vasil Dimov 50da7432ec
fuzz: add CConnman::OpenNetworkConnection() to the tests
Now that all network calls done by `CConnman::OpenNetworkConnection()`
are done via `Sock` they can be redirected (mocked) to `FuzzedSocket`
for testing.
2025-06-09 14:13:52 +02:00
Vasil Dimov e6a917c8f8
fuzz: add Fuzzed NetEventsInterface and use it in connman tests 2025-06-09 14:13:49 +02:00
Vasil Dimov e883b37768
fuzz: set the output argument of FuzzedSock::Accept()
`FuzzedSock::Accept()` properly returns a new socket, but it forgot to
set the output argument `addr`, like `accept(2)` is expected to.

This could lead to reading uninitialized data during testing when we
read it, e.g. from `CService::SetSockAddr()` which reads the `sa_family`
member.

Set `addr` to a fuzzed IPv4 or IPv6 address.
2025-06-09 10:45:52 +02:00
Anthony Towns b81f37031c p2p: Increase tx relay rate
In the presence of smaller transactions on the network, blocks can sustain a
higher relay rate than 7tx/second. In this event, the per-peer inventory queues
can grow too large.

This commit bumps the rate up to 14 tx/s (for inbound peers), increasing the
safety margin by a factor of 2.

Outbound peers continue to receive relayed transactions at 2.5x the rate of
inbound peers, for a rate of 35tx/second.

Co-Authored-By: Suhas Daftuar <sdaftuar@gmail.com>
2024-12-03 17:24:45 +10:00
169 changed files with 7617 additions and 1048 deletions

View File

@ -1,9 +1,12 @@
name: 'Configure Docker'
description: 'Set up Docker build driver and configure build cache args'
inputs:
use-cirrus:
description: 'Use cirrus cache'
cache-provider:
description: 'gha or cirrus cache provider'
required: true
options:
- gh
- cirrus
runs:
using: 'composite'
steps:
@ -32,7 +35,7 @@ runs:
# 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
if [[ ${{ inputs.cache-provider }} == 'cirrus' ]]; then
url_args="url=${CIRRUS_CACHE_HOST},url_v2=${CIRRUS_CACHE_HOST}"
else
url_args=""

View File

@ -42,6 +42,8 @@ def main():
"-DBUILD_BENCH=ON",
"-DBUILD_FUZZ_BINARY=ON",
"-DWITH_USDT=ON",
"-DBUILD_KERNEL_LIB=ON",
"-DBUILD_KERNEL_TEST=ON",
"-DCMAKE_CXX_FLAGS=-Wno-error=unused-member-function",
])
run(["cmake", "--build", "build", "-j", str(num_procs)])

View File

@ -33,15 +33,15 @@ jobs:
name: 'determine runners'
runs-on: ubuntu-latest
outputs:
use-cirrus-runners: ${{ steps.runners.outputs.use-cirrus-runners }}
provider: ${{ steps.runners.outputs.provider }}
steps:
- id: runners
run: |
if [[ "${REPO_USE_CIRRUS_RUNNERS}" == "${{ github.repository }}" ]]; then
echo "use-cirrus-runners=true" >> "$GITHUB_OUTPUT"
echo "provider=cirrus" >> "$GITHUB_OUTPUT"
echo "::notice title=Runner Selection::Using Cirrus Runners"
else
echo "use-cirrus-runners=false" >> "$GITHUB_OUTPUT"
echo "provider=gha" >> "$GITHUB_OUTPUT"
echo "::notice title=Runner Selection::Using GitHub-hosted runners"
fi
@ -105,7 +105,7 @@ jobs:
name: ${{ matrix.job-name }}
# Use any image to support the xcode-select below, but hardcode version to avoid silent upgrades (and breaks).
# See: https://github.com/actions/runner-images#available-images.
runs-on: macos-14
runs-on: macos-15
# 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:
@ -123,10 +123,10 @@ jobs:
include:
- job-type: standard
file-env: './ci/test/00_setup_env_mac_native.sh'
job-name: 'macOS 14 native, arm64, no depends, sqlite only, gui'
job-name: 'macOS native, no depends, sqlite only, gui'
- job-type: fuzz
file-env: './ci/test/00_setup_env_mac_native_fuzz.sh'
job-name: 'macOS 14 native, arm64, fuzz'
job-name: 'macOS native, fuzz'
env:
DANGER_RUN_CI_ON_HOST: 1
@ -145,8 +145,8 @@ jobs:
# Use the earliest Xcode supported by the version of macOS denoted in
# doc/release-notes-empty-template.md and providing at least the
# minimum clang version denoted in doc/dependencies.md.
# See: https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes
sudo xcode-select --switch /Applications/Xcode_15.0.app
# See: https://developer.apple.com/documentation/xcode-release-notes/xcode-16-release-notes
sudo xcode-select --switch /Applications/Xcode_16.0.app
clang --version
- name: Install Homebrew packages
@ -202,7 +202,7 @@ jobs:
job-type: [standard, fuzz]
include:
- job-type: standard
generate-options: '-DBUILD_GUI=ON -DWITH_ZMQ=ON -DBUILD_BENCH=ON -DWERROR=ON'
generate-options: '-DBUILD_GUI=ON -DWITH_ZMQ=ON -DBUILD_BENCH=ON -DBUILD_KERNEL_LIB=ON -DBUILD_UTIL_CHAINSTATE=ON -DBUILD_KERNEL_TEST=OFF -DWERROR=ON'
job-name: 'Windows native, VS 2022'
- job-type: fuzz
generate-options: '-DVCPKG_MANIFEST_NO_DEFAULT_FEATURES=ON -DVCPKG_MANIFEST_FEATURES="wallet" -DBUILD_GUI=OFF -DBUILD_FOR_FUZZING=ON -DWERROR=ON'
@ -211,11 +211,16 @@ jobs:
steps:
- *CHECKOUT
- name: Configure Developer Command Prompt for Microsoft Visual C++
# Using microsoft/setup-msbuild is not enough.
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- &SET_UP_VS
name: Set up VS Developer Prompt
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
run: |
$vswherePath = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
$installationPath = & $vswherePath -latest -property installationPath
& "${env:COMSPEC}" /s /c "`"$installationPath\Common7\Tools\vsdevcmd.bat`" -arch=x64 -no_logo && set" | foreach-object {
$name, $value = $_ -split '=', 2
echo "$name=$value" >> $env:GITHUB_ENV
}
- name: Get tool information
shell: pwsh
@ -263,14 +268,26 @@ jobs:
run: |
cmake --build . -j $NUMBER_OF_PROCESSORS --config Release
- name: Get bitcoind manifest
- name: Check executable manifests
if: matrix.job-type == 'standard'
working-directory: build
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
run: |
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -out:bitcoind.manifest
cat bitcoind.manifest
echo
mt.exe -nologo -inputresource:bin/Release/bitcoind.exe -validate_manifest
mt.exe -nologo -inputresource:bin\Release\bitcoind.exe -out:bitcoind.manifest
Get-Content bitcoind.manifest
Get-ChildItem -Filter "bin\Release\*.exe" | ForEach-Object {
$exeName = $_.Name
# Skip as they currently do not have manifests
if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe" -or $exeName -eq "test_bitcoin-qt.exe") {
Write-Host "Skipping $exeName (no manifest present)"
return
}
Write-Host "Checking $exeName"
& mt.exe -nologo -inputresource:$_.FullName -validate_manifest
}
- name: Run test suite
if: matrix.job-type == 'standard'
@ -290,6 +307,7 @@ jobs:
BITCOINTX: '${{ github.workspace }}\build\bin\Release\bitcoin-tx.exe'
BITCOINUTIL: '${{ github.workspace }}\build\bin\Release\bitcoin-util.exe'
BITCOINWALLET: '${{ github.workspace }}\build\bin\Release\bitcoin-wallet.exe'
BITCOINCHAINSTATE: '${{ github.workspace }}\build\bin\Release\bitcoin-chainstate.exe'
TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }}
run: py -3 test/functional/test_runner.py --jobs $NUMBER_OF_PROCESSORS --ci --quiet --tmpdirprefix="${RUNNER_TEMP}" --combinedlogslen=99999999 --timeout-factor=${TEST_RUNNER_TIMEOUT_FACTOR} ${TEST_RUNNER_EXTRA}
@ -312,7 +330,7 @@ jobs:
windows-cross:
name: 'Linux->Windows cross, no tests'
needs: runners
runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm' || 'ubuntu-24.04' }}
runs-on: ${{ needs.runners.outputs.provider == 'cirrus' && 'ghcr.io/cirruslabs/ubuntu-runner-amd64:24.04-sm' || 'ubuntu-24.04' }}
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
env:
@ -332,7 +350,7 @@ jobs:
- name: Configure Docker
uses: ./.github/actions/configure-docker
with:
use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }}
cache-provider: ${{ needs.runners.outputs.provider }}
- name: CI script
run: ./ci/test_run_all.sh
@ -370,19 +388,26 @@ jobs:
- name: Run bitcoind.exe
run: ./bin/bitcoind.exe -version
- name: Find mt.exe tool
shell: pwsh
run: |
$sdk_dir = (Get-ItemProperty 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows Kits\Installed Roots' -Name KitsRoot10).KitsRoot10
$sdk_latest = (Get-ChildItem "$sdk_dir\bin" -Directory | Where-Object { $_.Name -match '^\d+\.\d+\.\d+\.\d+$' } | Sort-Object Name -Descending | Select-Object -First 1).Name
"MT_EXE=${sdk_dir}bin\${sdk_latest}\x64\mt.exe" >> $env:GITHUB_ENV
- *SET_UP_VS
- name: Get bitcoind manifest
shell: pwsh
- name: Check executable manifests
shell: pwsh -Command "$PSVersionTable; $PSNativeCommandUseErrorActionPreference = $true; $ErrorActionPreference = 'Stop'; & '{0}'"
run: |
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
mt.exe -nologo -inputresource:bin\bitcoind.exe -out:bitcoind.manifest
Get-Content bitcoind.manifest
& $env:MT_EXE -nologo -inputresource:bin\bitcoind.exe -validate_manifest
Get-ChildItem -Filter "bin\*.exe" | ForEach-Object {
$exeName = $_.Name
# Skip as they currently do not have manifests
if ($exeName -eq "fuzz.exe" -or $exeName -eq "bench_bitcoin.exe") {
Write-Host "Skipping $exeName (no manifest present)"
return
}
Write-Host "Checking $exeName"
& mt.exe -nologo -inputresource:$_.FullName -validate_manifest
}
- name: Run unit tests
# Can't use ctest here like other jobs as we don't have a CMake build tree.
@ -422,7 +447,7 @@ jobs:
ci-matrix:
name: ${{ matrix.name }}
needs: runners
runs-on: ${{ needs.runners.outputs.use-cirrus-runners == 'true' && matrix.cirrus-runner || matrix.fallback-runner }}
runs-on: ${{ needs.runners.outputs.provider == 'cirrus' && matrix.cirrus-runner || matrix.fallback-runner }}
if: ${{ vars.SKIP_BRANCH_PUSH != 'true' || github.event_name == 'pull_request' }}
timeout-minutes: ${{ matrix.timeout-minutes }}
@ -439,6 +464,7 @@ jobs:
fallback-runner: 'ubuntu-24.04-arm'
timeout-minutes: 120
file-env: './ci/test/00_setup_env_arm.sh'
provider: 'gha'
- 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
@ -513,7 +539,7 @@ jobs:
- name: Configure Docker
uses: ./.github/actions/configure-docker
with:
use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }}
cache-provider: ${{ matrix.provider || needs.runners.outputs.provider }}
- name: Enable bpfcc script
if: ${{ env.CONTAINER_NAME == 'ci_native_asan' }}
@ -550,7 +576,7 @@ jobs:
- name: Configure Docker
uses: ./.github/actions/configure-docker
with:
use-cirrus: ${{ needs.runners.outputs.use-cirrus-runners }}
cache-provider: ${{ needs.runners.outputs.provider }}
- name: CI script
run: |

View File

@ -105,6 +105,7 @@ option(BUILD_UTIL "Build bitcoin-util executable." ${BUILD_TESTS})
option(BUILD_UTIL_CHAINSTATE "Build experimental bitcoin-chainstate executable." OFF)
option(BUILD_KERNEL_LIB "Build experimental bitcoinkernel library." ${BUILD_UTIL_CHAINSTATE})
option(BUILD_KERNEL_TEST "Build tests for the experimental bitcoinkernel library." ${BUILD_KERNEL_LIB})
option(ENABLE_WALLET "Enable wallet." ON)
if(ENABLE_WALLET)
@ -210,6 +211,7 @@ if(BUILD_FOR_FUZZING)
set(BUILD_UTIL OFF)
set(BUILD_UTIL_CHAINSTATE OFF)
set(BUILD_KERNEL_LIB OFF)
set(BUILD_KERNEL_TEST OFF)
set(BUILD_WALLET_TOOL OFF)
set(BUILD_GUI OFF)
set(ENABLE_EXTERNAL_SIGNER OFF)
@ -668,6 +670,7 @@ message(" bitcoin-util ........................ ${BUILD_UTIL}")
message(" bitcoin-wallet ...................... ${BUILD_WALLET_TOOL}")
message(" bitcoin-chainstate (experimental) ... ${BUILD_UTIL_CHAINSTATE}")
message(" libbitcoinkernel (experimental) ..... ${BUILD_KERNEL_LIB}")
message(" kernel-test (experimental) .......... ${BUILD_KERNEL_TEST}")
message("Optional features:")
message(" wallet support ...................... ${ENABLE_WALLET}")
message(" external signer ..................... ${ENABLE_EXTERNAL_SIGNER}")

View File

@ -41,10 +41,10 @@ python3 --version
${CI_RETRY_EXE} pip3 install \
codespell==2.4.1 \
lief==0.16.6 \
mypy==1.4.1 \
pyzmq==25.1.0 \
ruff==0.5.5 \
vulture==2.6
mypy==1.18.2 \
pyzmq==27.1.0 \
ruff==0.13.2 \
vulture==2.14
SHELLCHECK_VERSION=v0.11.0
curl -sL "https://github.com/koalaman/shellcheck/releases/download/${SHELLCHECK_VERSION}/shellcheck-${SHELLCHECK_VERSION}.linux.x86_64.tar.xz" | \

View File

@ -12,7 +12,7 @@ export CONTAINER_NAME="ci_mac_native" # macos does not use a container, but the
export PIP_PACKAGES="--break-system-packages zmq"
export GOAL="install deploy"
export CMAKE_GENERATOR="Ninja"
export BITCOIN_CONFIG="-DBUILD_GUI=ON -DWITH_ZMQ=ON -DREDUCE_EXPORTS=ON -DCMAKE_EXE_LINKER_FLAGS='-Wl,-stack_size -Wl,0x80000'"
export BITCOIN_CONFIG="-DBUILD_GUI=ON -DWITH_ZMQ=ON -DBUILD_KERNEL_LIB=ON -DBUILD_KERNEL_TEST=ON -DREDUCE_EXPORTS=ON -DCMAKE_EXE_LINKER_FLAGS='-Wl,-stack_size -Wl,0x80000'"
export CI_OS_NAME="macos"
export NO_DEPENDS=1
export OSX_SDK=""

View File

@ -7,12 +7,15 @@
export LC_ALL=C.UTF-8
export CI_IMAGE_NAME_TAG="mirror.gcr.io/ubuntu:24.04"
export APT_LLVM_V="21"
LIBCXX_DIR="/cxx_build/"
export MSAN_FLAGS="-fsanitize=memory -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O1 -fno-optimize-sibling-calls"
LIBCXX_FLAGS="-nostdinc++ -nostdlib++ -isystem ${LIBCXX_DIR}include/c++/v1 -L${LIBCXX_DIR}lib -Wl,-rpath,${LIBCXX_DIR}lib -lc++ -lc++abi -lpthread -Wno-unused-command-line-argument"
# -lstdc++ to resolve link issues due to upstream packaging
LIBCXX_FLAGS="-nostdinc++ -nostdlib++ -isystem ${LIBCXX_DIR}include/c++/v1 -L${LIBCXX_DIR}lib -Wl,-rpath,${LIBCXX_DIR}lib -lc++ -lc++abi -lpthread -Wno-unused-command-line-argument -lstdc++"
export MSAN_AND_LIBCXX_FLAGS="${MSAN_FLAGS} ${LIBCXX_FLAGS}"
export CONTAINER_NAME="ci_native_fuzz_msan"
export PACKAGES="clang-${APT_LLVM_V} llvm-${APT_LLVM_V} llvm-${APT_LLVM_V}-dev libclang-${APT_LLVM_V}-dev libclang-rt-${APT_LLVM_V}-dev"
export DEP_OPTS="DEBUG=1 NO_QT=1 CC=clang CXX=clang++ CFLAGS='${MSAN_FLAGS}' CXXFLAGS='${MSAN_AND_LIBCXX_FLAGS}'"
export GOAL="all"
# Setting CMAKE_{C,CXX}_FLAGS_DEBUG flags to an empty string ensures that the flags set in MSAN_FLAGS remain unaltered.

View File

@ -13,4 +13,4 @@ export PACKAGES="python3-zmq python3-pip clang-16 llvm-16 libc++abi-16-dev libc+
export PIP_PACKAGES="--break-system-packages pycapnp"
export DEP_OPTS="NO_WALLET=1 CC=clang-16 CXX='clang++-16 -stdlib=libc++'"
export GOAL="install"
export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_UTIL_CHAINSTATE=ON -DBUILD_KERNEL_LIB=ON -DBUILD_SHARED_LIBS=ON"
export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_UTIL_CHAINSTATE=ON -DBUILD_KERNEL_LIB=ON -DBUILD_KERNEL_TEST=ON -DBUILD_SHARED_LIBS=ON"

View File

@ -14,5 +14,5 @@ export PACKAGES="g++-mingw-w64-x86-64-posix nsis"
export RUN_UNIT_TESTS=false
export RUN_FUNCTIONAL_TESTS=false
export GOAL="deploy"
export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_GUI_TESTS=OFF \
export BITCOIN_CONFIG="-DREDUCE_EXPORTS=ON -DBUILD_GUI_TESTS=OFF -DBUILD_KERNEL_LIB=ON -DBUILD_KERNEL_TEST=ON \
-DCMAKE_CXX_FLAGS='-Wno-error=maybe-uninitialized'"

View File

@ -58,23 +58,6 @@ fi
if [[ -n "${USE_INSTRUMENTED_LIBCPP}" ]]; then
${CI_RETRY_EXE} git clone --depth=1 https://github.com/llvm/llvm-project -b "llvmorg-21.1.1" /llvm-project
if [ -n "${APT_LLVM_V}" ]; then
cmake -G Ninja -B /clang_build/ \
-DLLVM_ENABLE_PROJECTS="clang" \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_TARGETS_TO_BUILD=Native \
-DLLVM_ENABLE_RUNTIMES="compiler-rt;libcxx;libcxxabi;libunwind" \
-S /llvm-project/llvm
ninja -C /clang_build/ "$MAKEJOBS"
ninja -C /clang_build/ install-runtimes
update-alternatives --install /usr/bin/clang++ clang++ /clang_build/bin/clang++ 100
update-alternatives --install /usr/bin/clang clang /clang_build/bin/clang 100
update-alternatives --install /usr/bin/llvm-symbolizer llvm-symbolizer /clang_build/bin/llvm-symbolizer 100
fi
cmake -G Ninja -B /cxx_build/ \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
-DCMAKE_BUILD_TYPE=Release \

View File

@ -130,7 +130,8 @@ if [[ "${RUN_TIDY}" == "true" ]]; then
BITCOIN_CONFIG_ALL="$BITCOIN_CONFIG_ALL -DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
fi
bash -c "cmake -S $BASE_ROOT_DIR -B ${BASE_BUILD_DIR} $BITCOIN_CONFIG_ALL $BITCOIN_CONFIG" || (
eval "CMAKE_ARGS=($BITCOIN_CONFIG_ALL $BITCOIN_CONFIG)"
cmake -S "$BASE_ROOT_DIR" -B "$BASE_BUILD_DIR" "${CMAKE_ARGS[@]}" || (
cd "${BASE_BUILD_DIR}"
# shellcheck disable=SC2046
cat $(cmake -P "${BASE_ROOT_DIR}/ci/test/GetCMakeLogFiles.cmake")

View File

@ -96,24 +96,24 @@ function(add_macos_deploy_target)
VERBATIM
)
string(REPLACE " " "-" osx_volname ${CLIENT_NAME})
set(macos_zip "bitcoin-macos-app")
if(CMAKE_HOST_APPLE)
add_custom_command(
OUTPUT ${PROJECT_BINARY_DIR}/${osx_volname}.zip
COMMAND Python3::Interpreter ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} ${osx_volname} -translations-dir=${QT_TRANSLATIONS_DIR} -zip
OUTPUT ${PROJECT_BINARY_DIR}/${macos_zip}.zip
COMMAND Python3::Interpreter ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} -translations-dir=${QT_TRANSLATIONS_DIR} -zip=${macos_zip}
DEPENDS ${PROJECT_BINARY_DIR}/${macos_app}/Contents/MacOS/Bitcoin-Qt
VERBATIM
)
add_custom_target(deploydir
DEPENDS ${PROJECT_BINARY_DIR}/${osx_volname}.zip
DEPENDS ${PROJECT_BINARY_DIR}/${macos_zip}.zip
)
add_custom_target(deploy
DEPENDS ${PROJECT_BINARY_DIR}/${osx_volname}.zip
DEPENDS ${PROJECT_BINARY_DIR}/${macos_zip}.zip
)
else()
add_custom_command(
OUTPUT ${PROJECT_BINARY_DIR}/dist/${macos_app}/Contents/MacOS/Bitcoin-Qt
COMMAND ${CMAKE_COMMAND} -E env OBJDUMP=${CMAKE_OBJDUMP} $<TARGET_FILE:Python3::Interpreter> ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} ${osx_volname} -translations-dir=${QT_TRANSLATIONS_DIR}
COMMAND ${CMAKE_COMMAND} -E env OBJDUMP=${CMAKE_OBJDUMP} $<TARGET_FILE:Python3::Interpreter> ${PROJECT_SOURCE_DIR}/contrib/macdeploy/macdeployqtplus ${macos_app} -translations-dir=${QT_TRANSLATIONS_DIR}
DEPENDS ${PROJECT_BINARY_DIR}/${macos_app}/Contents/MacOS/Bitcoin-Qt
VERBATIM
)
@ -128,13 +128,13 @@ function(add_macos_deploy_target)
)
else()
add_custom_command(
OUTPUT ${PROJECT_BINARY_DIR}/dist/${osx_volname}.zip
OUTPUT ${PROJECT_BINARY_DIR}/dist/${macos_zip}.zip
WORKING_DIRECTORY dist
COMMAND ${PROJECT_SOURCE_DIR}/cmake/script/macos_zip.sh ${ZIP_EXECUTABLE} ${osx_volname}.zip
COMMAND ${PROJECT_SOURCE_DIR}/cmake/script/macos_zip.sh ${ZIP_EXECUTABLE} ${macos_zip}.zip
VERBATIM
)
add_custom_target(deploy
DEPENDS ${PROJECT_BINARY_DIR}/dist/${osx_volname}.zip
DEPENDS ${PROJECT_BINARY_DIR}/dist/${macos_zip}.zip
)
endif()
endif()

View File

@ -2,6 +2,8 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or https://opensource.org/license/mit/.
enable_language(C)
function(add_secp256k1 subdir)
message("")
message("Configuring secp256k1 subtree...")
@ -30,7 +32,6 @@ function(add_secp256k1 subdir)
string(STRIP "${SECP256K1_APPEND_LDFLAGS} ${APPEND_LDFLAGS}" SECP256K1_APPEND_LDFLAGS)
set(SECP256K1_APPEND_LDFLAGS ${SECP256K1_APPEND_LDFLAGS} CACHE STRING "" FORCE)
# We want to build libsecp256k1 with the most tested RelWithDebInfo configuration.
enable_language(C)
foreach(config IN LISTS CMAKE_BUILD_TYPE CMAKE_CONFIGURATION_TYPES)
if(config STREQUAL "")
continue()

View File

@ -369,7 +369,7 @@ mkdir -p "$DISTSRC"
;;
*darwin*)
cmake --build build --target deploy ${V:+--verbose}
mv build/dist/Bitcoin-Core.zip "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip"
mv build/dist/bitcoin-macos-app.zip "${OUTDIR}/${DISTNAME}-${HOST}-unsigned.zip"
mkdir -p "unsigned-app-${HOST}"
cp --target-directory="unsigned-app-${HOST}" \
contrib/macdeploy/detached-sig-create.sh

View File

@ -112,7 +112,6 @@ ELF_ALLOWED_LIBRARIES = {
'libfontconfig.so.1', # font support
'libfreetype.so.6', # font parsing
'libdl.so.2', # programming interface to dynamic linker
'libxcb-cursor.so.0',
'libxcb-icccm.so.4',
'libxcb-image.so.0',
'libxcb-shm.so.0',
@ -249,7 +248,7 @@ def check_MACHO_libraries(binary) -> bool:
return ok
def check_MACHO_min_os(binary) -> bool:
if binary.build_version.minos == [13,0,0]:
if binary.build_version.minos == [14,0,0]:
return True
return False

View File

@ -390,12 +390,11 @@ Note, that the "dist" folder will be deleted before deploying on each run.
Optionally, Qt translation files (.qm) can be added to the bundle.""")
ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed")
ap.add_argument("appname", nargs=1, metavar="appname", help="name of the app being deployed")
ap.add_argument("-verbose", nargs="?", const=True, help="Output additional debugging information")
ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment")
ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries")
ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translations. Base translations will automatically be added to the bundle's resources.")
ap.add_argument("-zip", nargs="?", const="", metavar="zip", help="create a .zip containing the app bundle")
ap.add_argument("-zip", nargs=1, metavar="zip", help="create a .zip containing the app bundle")
config = ap.parse_args()
@ -404,7 +403,6 @@ verbose = config.verbose
# ------------------------------------------------
app_bundle = config.app_bundle[0]
appname = config.appname[0]
if not os.path.exists(app_bundle):
sys.stderr.write(f"Error: Could not find app bundle \"{app_bundle}\"\n")
@ -416,10 +414,6 @@ if os.path.exists("dist"):
print("+ Removing existing dist folder +")
shutil.rmtree("dist")
if os.path.exists(appname + ".zip"):
print("+ Removing existing .zip +")
os.unlink(appname + ".zip")
# ------------------------------------------------
target = os.path.join("dist", "Bitcoin-Qt.app")
@ -466,15 +460,15 @@ 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:
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))
@ -499,7 +493,13 @@ if platform.system() == "Darwin":
# ------------------------------------------------
if config.zip is not None:
shutil.make_archive('{}'.format(appname), format='zip', root_dir='dist', base_dir='Bitcoin-Qt.app')
name = config.zip[0]
if os.path.exists(name + ".zip"):
print("+ Removing existing .zip +")
os.unlink(name + ".zip")
shutil.make_archive('{}'.format(name), format='zip', root_dir='dist', base_dir='Bitcoin-Qt.app')
# ------------------------------------------------

View File

@ -36,9 +36,8 @@ define fetch_file_inner
endef
define fetch_file
( test -f $$($(1)_source_dir)/$(4) || \
( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5))))
$(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))
endef
# Shell script to create a source tarball in $(1)_source from local directory
@ -109,7 +108,7 @@ $(1)_prefixbin:=$($($(1)_type)_prefix)/bin/
$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources)
#stamps
$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_file_name).hash
$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_version)-$($(1)_sha256_hash).hash
$(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted
$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed
$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned
@ -247,7 +246,6 @@ endif
$($(1)_fetched):
mkdir -p $$(@D) $(SOURCES_PATH)
rm -f $$@
touch $$@
cd $$(@D); $($(1)_fetch_cmds)
cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);)
touch $$@

View File

@ -1,4 +1,4 @@
OSX_MIN_VERSION=13.0
OSX_MIN_VERSION=14.0
OSX_SDK_VERSION=14.0
XCODE_VERSION=15.0
XCODE_BUILD_ID=15A240d

View File

@ -6,7 +6,7 @@ $(package)_sha256_hash=0e9c5446dc6f3beb8af6ebfcc9e27bcc6da6fe2860f7fc07b99144dfa
$(package)_dependencies=libxcb libxcb_util_render libxcb_util_image
define $(package)_set_vars
$(package)_config_opts = --disable-static
$(package)_config_opts = --disable-shared
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking
endef

View File

@ -1,8 +1,9 @@
package=qrencode
$(package)_version=4.1.1
$(package)_download_path=https://fukuchi.org/works/qrencode/
$(package)_download_path=https://github.com/fukuchi/libqrencode/archive/refs/tags/
$(package)_download_file=v$($(package)_version).tar.gz
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=da448ed4f52aba6bcb0cd48cac0dd51b8692bccc4cd127431402fca6f8171e8e
$(package)_sha256_hash=5385bc1b8c2f20f3b91d258bf8ccc8cf62023935df2d2676b5b67049f31a049c
$(package)_patches=cmake_fixups.patch
define $(package)_set_vars

View File

@ -1,8 +1,8 @@
package=systemtap
$(package)_version=4.8
$(package)_version=5.3
$(package)_download_path=https://sourceware.org/ftp/systemtap/releases/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=cbd50a4eba5b261394dc454c12448ddec73e55e6742fda7f508f9fbc1331c223
$(package)_sha256_hash=966a360fb73a4b65a8d0b51b389577b3c4f92a327e84aae58682103e8c65a69a
$(package)_patches=remove_SDT_ASM_SECTION_AUTOGROUP_SUPPORT_check.patch
define $(package)_preprocess_cmds

View File

@ -81,8 +81,6 @@ the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if yo
sudo apt-get install qt6-base-dev qt6-tools-dev qt6-l10n-tools qt6-tools-dev-tools libgl-dev
For Qt 6.5 and later, the `libxcb-cursor0` package must be installed at runtime.
Additionally, to support Wayland protocol for modern desktop environments:
sudo apt install qt6-wayland
@ -133,8 +131,6 @@ the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if yo
sudo dnf install qt6-qtbase-devel qt6-qttools-devel
For Qt 6.5 and later, the `xcb-util-cursor` package must be installed at runtime.
Additionally, to support Wayland protocol for modern desktop environments:
sudo dnf install qt6-qtwayland
@ -182,8 +178,6 @@ the necessary parts of Qt, the libqrencode and pass `-DBUILD_GUI=ON`. Skip if yo
apk add qt6-qtbase-dev qt6-qttools-dev
For Qt 6.5 and later, the `xcb-util-cursor` package must be installed at runtime.
The GUI will be able to encode addresses in QR codes unless this feature is explicitly disabled. To install libqrencode, run:
apk add libqrencode-dev

View File

@ -8,7 +8,7 @@
| *libbitcoin_crypto* | Hardware-optimized functions for data encryption, hashing, message authentication, and key derivation. |
| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node*. |
| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables. |
| *libbitcoin_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`-DENABLE_IPC=ON`](multiprocess.md) is used. |
| *libbitcoin_ipc* | IPC functionality used by *bitcoin-node* and *bitcoin-gui* executables to communicate when [`-DENABLE_IPC=ON`](multiprocess.md) is used. |
| *libbitcoin_node* | P2P and RPC server functionality used by *bitcoind* and *bitcoin-qt* executables. |
| *libbitcoin_util* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_common*, but lower-level (see [Dependencies](#dependencies)). |
| *libbitcoin_wallet* | Wallet functionality used by *bitcoind* and *bitcoin-wallet* executables. |

View File

@ -36,7 +36,7 @@ Compatibility
==============
Bitcoin Core is supported and tested on operating systems using the
Linux Kernel 3.17+, macOS 13+, and Windows 10+. Bitcoin
Linux Kernel 3.17+, macOS 14+, and Windows 10+. Bitcoin
Core should also work on most other Unix-like systems but is not as
frequently tested on them. It is not recommended to use Bitcoin Core on
unsupported systems.

View File

@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>LSMinimumSystemVersion</key>
<string>13</string>
<string>14</string>
<key>LSArchitecturePriority</key>
<array>

View File

@ -113,6 +113,19 @@ Section -post SEC0001
WriteRegStr HKCR "@CLIENT_TARNAME@" "" "URL:Bitcoin"
WriteRegStr HKCR "@CLIENT_TARNAME@\DefaultIcon" "" $INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@
WriteRegStr HKCR "@CLIENT_TARNAME@\shell\open\command" "" '"$INSTDIR\@BITCOIN_GUI_NAME@@EXEEXT@" "%1"'
# Lingering since fb2b05b1259d3e69e6e675adfa30b429424c7625 which removed the suffix
DeleteRegValue HKCU "${REGKEY} (64-bit)\Components" Main
DeleteRegKey HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$(^Name) (64-bit)"
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Uninstall $(^Name) (64-bit).lnk"
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\$(^Name) (64-bit).lnk"
DeleteRegValue HKCU "${REGKEY} (64-bit)" StartMenuGroup
DeleteRegValue HKCU "${REGKEY} (64-bit)" Path
DeleteRegKey /IfEmpty HKCU "${REGKEY} (64-bit)\Components"
DeleteRegKey /IfEmpty HKCU "${REGKEY} (64-bit)"
# Lingering since 77b2923f87131a407f7d4193c54db22375130403
Delete /REBOOTOK "$SMPROGRAMS\$StartMenuGroup\Bitcoin Core (testnet, 64-bit).lnk"
SectionEnd
# Macro for selecting uninstaller sections

View File

@ -292,8 +292,8 @@ if(BUILD_BITCOIN_BIN)
add_executable(bitcoin bitcoin.cpp)
add_windows_resources(bitcoin bitcoin-res.rc)
add_windows_application_manifest(bitcoin)
target_link_libraries(bitcoin core_interface bitcoin_util)
install_binary_component(bitcoin)
target_link_libraries(bitcoin core_interface bitcoin_common bitcoin_util)
install_binary_component(bitcoin HAS_MANPAGE)
endif()
# Bitcoin Core bitcoind.
@ -404,6 +404,9 @@ endif()
if(BUILD_KERNEL_LIB)
add_subdirectory(kernel)
if (BUILD_KERNEL_TEST)
add_subdirectory(test/kernel)
endif()
endif()
if(BUILD_UTIL_CHAINSTATE)

View File

@ -24,7 +24,7 @@ static void VerifyScriptBench(benchmark::Bench& bench)
{
ECC_Context ecc_context{};
const uint32_t flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
const script_verify_flags flags{SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH};
const int witnessversion = 0;
// Key pair.

View File

@ -1,53 +1,144 @@
// Copyright (c) 2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// The bitcoin-chainstate executable serves to surface the dependencies required
// by a program wishing to use Bitcoin Core's consensus engine as it is right
// now.
//
// DEVELOPER NOTE: Since this is a "demo-only", experimental, etc. executable,
// it may diverge from Bitcoin Core's coding style.
//
// It is part of the libbitcoinkernel project.
#include <kernel/chainparams.h>
#include <kernel/chainstatemanager_opts.h>
#include <kernel/checks.h>
#include <kernel/context.h>
#include <kernel/warning.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <kernel/caches.h>
#include <logging.h>
#include <node/blockstorage.h>
#include <node/chainstate.h>
#include <random.h>
#include <script/sigcache.h>
#include <util/chaintype.h>
#include <util/fs.h>
#include <util/signalinterrupt.h>
#include <util/task_runner.h>
#include <util/translation.h>
#include <validation.h>
#include <validationinterface.h>
#include <kernel/bitcoinkernel_wrapper.h>
#include <cassert>
#include <cstdint>
#include <functional>
#include <iosfwd>
#include <memory>
#include <charconv>
#include <filesystem>
#include <iostream>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#ifdef WIN32
// clang-format off
#include <windows.h>
// clang-format on
#include <codecvt>
#include <locale>
#include <shellapi.h>
#endif
using namespace btck;
std::vector<std::byte> hex_string_to_byte_vec(std::string_view hex)
{
std::vector<std::byte> bytes;
bytes.reserve(hex.length() / 2);
for (size_t i{0}; i < hex.length(); i += 2) {
uint8_t byte_value;
auto [ptr, ec] = std::from_chars(hex.data() + i, hex.data() + i + 2, byte_value, 16);
if (ec != std::errc{} || ptr != hex.data() + i + 2) {
throw std::invalid_argument("Invalid hex character");
}
bytes.push_back(static_cast<std::byte>(byte_value));
}
return bytes;
}
class KernelLog
{
public:
void LogMessage(std::string_view message)
{
std::cout << "kernel: " << message;
}
};
class TestValidationInterface : public ValidationInterface<TestValidationInterface>
{
public:
TestValidationInterface() = default;
std::optional<std::string> m_expected_valid_block = std::nullopt;
void BlockChecked(const Block block, const BlockValidationState state) override
{
auto mode{state.GetValidationMode()};
switch (mode) {
case ValidationMode::VALID: {
std::cout << "Valid block" << std::endl;
return;
}
case ValidationMode::INVALID: {
std::cout << "Invalid block: ";
auto result{state.GetBlockValidationResult()};
switch (result) {
case BlockValidationResult::UNSET:
std::cout << "initial value. Block has not yet been rejected" << std::endl;
break;
case BlockValidationResult::HEADER_LOW_WORK:
std::cout << "the block header may be on a too-little-work chain" << std::endl;
break;
case BlockValidationResult::CONSENSUS:
std::cout << "invalid by consensus rules (excluding any below reasons)" << std::endl;
break;
case BlockValidationResult::CACHED_INVALID:
std::cout << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
break;
case BlockValidationResult::INVALID_HEADER:
std::cout << "invalid proof of work or time too old" << std::endl;
break;
case BlockValidationResult::MUTATED:
std::cout << "the block's data didn't match the data committed to by the PoW" << std::endl;
break;
case BlockValidationResult::MISSING_PREV:
std::cout << "We don't have the previous block the checked one is built on" << std::endl;
break;
case BlockValidationResult::INVALID_PREV:
std::cout << "A block this one builds on is invalid" << std::endl;
break;
case BlockValidationResult::TIME_FUTURE:
std::cout << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
break;
}
return;
}
case ValidationMode::INTERNAL_ERROR: {
std::cout << "Internal error" << std::endl;
return;
}
}
}
};
class TestKernelNotifications : public KernelNotifications<TestKernelNotifications>
{
public:
void BlockTipHandler(SynchronizationState, const BlockTreeEntry, double) override
{
std::cout << "Block tip changed" << std::endl;
}
void ProgressHandler(std::string_view title, int progress_percent, bool resume_possible) override
{
std::cout << "Made progress: " << title << " " << progress_percent << "%" << std::endl;
}
void WarningSetHandler(Warning warning, std::string_view message) override
{
std::cout << message << std::endl;
}
void WarningUnsetHandler(Warning warning) override
{
std::cout << "Warning unset: " << static_cast<std::underlying_type_t<Warning>>(warning) << std::endl;
}
void FlushErrorHandler(std::string_view error) override
{
std::cout << error << std::endl;
}
void FatalErrorHandler(std::string_view error) override
{
std::cout << error << std::endl;
}
};
int main(int argc, char* argv[])
{
// We do not enable logging for this app, so explicitly disable it.
// To enable logging instead, replace with:
// LogInstance().m_print_to_console = true;
// LogInstance().StartLogging();
LogInstance().DisableLogging();
// SETUP: Argument parsing and handling
if (argc != 2) {
std::cerr
@ -58,213 +149,81 @@ int main(int argc, char* argv[])
<< " BREAK IN FUTURE VERSIONS. DO NOT USE ON YOUR ACTUAL DATADIR." << std::endl;
return 1;
}
fs::path abs_datadir{fs::absolute(argv[1])};
fs::create_directories(abs_datadir);
#ifdef WIN32
int win_argc;
wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &win_argc);
std::vector<std::string> utf8_args(win_argc);
std::vector<char*> win_argv(win_argc);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf8_cvt;
for (int i = 0; i < win_argc; i++) {
utf8_args[i] = utf8_cvt.to_bytes(wargv[i]);
win_argv[i] = &utf8_args[i][0];
}
LocalFree(wargv);
argc = win_argc;
argv = win_argv.data();
#endif
// SETUP: Context
kernel::Context kernel_context{};
// We can't use a goto here, but we can use an assert since none of the
// things instantiated so far requires running the epilogue to be torn down
// properly
assert(kernel::SanityChecks(kernel_context));
std::filesystem::path abs_datadir{std::filesystem::absolute(argv[1])};
std::filesystem::create_directories(abs_datadir);
ValidationSignals validation_signals{std::make_unique<util::ImmediateTaskRunner>()};
class KernelNotifications : public kernel::Notifications
{
public:
kernel::InterruptResult blockTip(SynchronizationState, const CBlockIndex&, double) override
{
std::cout << "Block tip changed" << std::endl;
return {};
}
void headerTip(SynchronizationState, int64_t height, int64_t timestamp, bool presync) override
{
std::cout << "Header tip changed: " << height << ", " << timestamp << ", " << presync << std::endl;
}
void progress(const bilingual_str& title, int progress_percent, bool resume_possible) override
{
std::cout << "Progress: " << title.original << ", " << progress_percent << ", " << resume_possible << std::endl;
}
void warningSet(kernel::Warning id, const bilingual_str& message) override
{
std::cout << "Warning " << static_cast<int>(id) << " set: " << message.original << std::endl;
}
void warningUnset(kernel::Warning id) override
{
std::cout << "Warning " << static_cast<int>(id) << " unset" << std::endl;
}
void flushError(const bilingual_str& message) override
{
std::cerr << "Error flushing block data to disk: " << message.original << std::endl;
}
void fatalError(const bilingual_str& message) override
{
std::cerr << "Error: " << message.original << std::endl;
}
btck_LoggingOptions logging_options = {
.log_timestamps = true,
.log_time_micros = false,
.log_threadnames = false,
.log_sourcelocations = false,
.always_print_category_levels = true,
};
auto notifications = std::make_unique<KernelNotifications>();
kernel::CacheSizes cache_sizes{DEFAULT_KERNEL_CACHE};
Logger logger{std::make_unique<KernelLog>(KernelLog{}), logging_options};
// SETUP: Chainstate
auto chainparams = CChainParams::Main();
const ChainstateManager::Options chainman_opts{
.chainparams = *chainparams,
.datadir = abs_datadir,
.notifications = *notifications,
.signals = &validation_signals,
};
const node::BlockManager::Options blockman_opts{
.chainparams = chainman_opts.chainparams,
.blocks_dir = abs_datadir / "blocks",
.notifications = chainman_opts.notifications,
.block_tree_db_params = DBParams{
.path = abs_datadir / "blocks" / "index",
.cache_bytes = cache_sizes.block_tree_db,
},
};
util::SignalInterrupt interrupt;
ChainstateManager chainman{interrupt, chainman_opts, blockman_opts};
ContextOptions options{};
ChainParams params{ChainType::MAINNET};
options.SetChainParams(params);
node::ChainstateLoadOptions options;
auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
if (status != node::ChainstateLoadStatus::SUCCESS) {
std::cerr << "Failed to load Chain state from your datadir." << std::endl;
goto epilogue;
} else {
std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options);
if (status != node::ChainstateLoadStatus::SUCCESS) {
std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl;
goto epilogue;
}
options.SetNotifications(std::make_shared<TestKernelNotifications>());
options.SetValidationInterface(std::make_shared<TestValidationInterface>());
Context context{options};
ChainstateManagerOptions chainman_opts{context, abs_datadir.string(), (abs_datadir / "blocks").string()};
chainman_opts.SetWorkerThreads(4);
std::unique_ptr<ChainMan> chainman;
try {
chainman = std::make_unique<ChainMan>(context, chainman_opts);
} catch (std::exception&) {
std::cerr << "Failed to instantiate ChainMan, exiting" << std::endl;
return 1;
}
for (Chainstate* chainstate : WITH_LOCK(::cs_main, return chainman.GetAll())) {
BlockValidationState state;
if (!chainstate->ActivateBestChain(state, nullptr)) {
std::cerr << "Failed to connect best block (" << state.ToString() << ")" << std::endl;
goto epilogue;
}
}
// Main program logic starts here
std::cout
<< "Hello! I'm going to print out some information about your datadir." << std::endl
<< "\t"
<< "Path: " << abs_datadir << std::endl;
{
LOCK(chainman.GetMutex());
std::cout
<< "\t" << "Blockfiles Indexed: " << std::boolalpha << chainman.m_blockman.m_blockfiles_indexed.load() << std::noboolalpha << std::endl
<< "\t" << "Snapshot Active: " << std::boolalpha << chainman.IsSnapshotActive() << std::noboolalpha << std::endl
<< "\t" << "Active Height: " << chainman.ActiveHeight() << std::endl
<< "\t" << "Active IBD: " << std::boolalpha << chainman.IsInitialBlockDownload() << std::noboolalpha << std::endl;
CBlockIndex* tip = chainman.ActiveTip();
if (tip) {
std::cout << "\t" << tip->ToString() << std::endl;
}
}
std::cout << "Enter the block you want to validate on the next line:" << std::endl;
for (std::string line; std::getline(std::cin, line);) {
if (line.empty()) {
std::cerr << "Empty line found" << std::endl;
break;
std::cerr << "Empty line found, try again:" << std::endl;
continue;
}
std::shared_ptr<CBlock> blockptr = std::make_shared<CBlock>();
CBlock& block = *blockptr;
if (!DecodeHexBlk(block, line)) {
std::cerr << "Block decode failed" << std::endl;
break;
auto raw_block{hex_string_to_byte_vec(line)};
std::unique_ptr<Block> block;
try {
block = std::make_unique<Block>(raw_block);
} catch (std::exception&) {
std::cerr << "Block decode failed, try again:" << std::endl;
continue;
}
{
LOCK(cs_main);
const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
if (pindex) {
chainman.UpdateUncommittedBlockStructures(block, pindex);
}
}
// Adapted from rpc/mining.cpp
class submitblock_StateCatcher final : public CValidationInterface
{
public:
uint256 hash;
bool found;
BlockValidationState state;
explicit submitblock_StateCatcher(const uint256& hashIn) : hash(hashIn), found(false), state() {}
protected:
void BlockChecked(const std::shared_ptr<const CBlock>& block, const BlockValidationState& stateIn) override
{
if (block->GetHash() != hash)
return;
found = true;
state = stateIn;
}
};
bool new_block;
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
validation_signals.RegisterSharedValidationInterface(sc);
bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
validation_signals.UnregisterSharedValidationInterface(sc);
if (!new_block && accepted) {
std::cerr << "duplicate" << std::endl;
break;
}
if (!sc->found) {
std::cerr << "inconclusive" << std::endl;
break;
}
std::cout << sc->state.ToString() << std::endl;
switch (sc->state.GetResult()) {
case BlockValidationResult::BLOCK_RESULT_UNSET:
std::cerr << "initial value. Block has not yet been rejected" << std::endl;
break;
case BlockValidationResult::BLOCK_HEADER_LOW_WORK:
std::cerr << "the block header may be on a too-little-work chain" << std::endl;
break;
case BlockValidationResult::BLOCK_CONSENSUS:
std::cerr << "invalid by consensus rules (excluding any below reasons)" << std::endl;
break;
case BlockValidationResult::BLOCK_CACHED_INVALID:
std::cerr << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
break;
case BlockValidationResult::BLOCK_INVALID_HEADER:
std::cerr << "invalid proof of work or time too old" << std::endl;
break;
case BlockValidationResult::BLOCK_MUTATED:
std::cerr << "the block's data didn't match the data committed to by the PoW" << std::endl;
break;
case BlockValidationResult::BLOCK_MISSING_PREV:
std::cerr << "We don't have the previous block the checked one is built on" << std::endl;
break;
case BlockValidationResult::BLOCK_INVALID_PREV:
std::cerr << "A block this one builds on is invalid" << std::endl;
break;
case BlockValidationResult::BLOCK_TIME_FUTURE:
std::cerr << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
break;
}
}
epilogue:
// Without this precise shutdown sequence, there will be a lot of nullptr
// dereferencing and UB.
validation_signals.FlushBackgroundCallbacks();
{
LOCK(cs_main);
for (Chainstate* chainstate : chainman.GetAll()) {
if (chainstate->CanFlushToDisk()) {
chainstate->ForceFlushStateToDisk();
chainstate->ResetCoinsViews();
bool new_block = false;
bool accepted = chainman->ProcessBlock(*block, &new_block);
if (accepted) {
std::cerr << "Block has not yet been rejected" << std::endl;
} else {
std::cerr << "Block was not accepted" << std::endl;
}
if (!new_block) {
std::cerr << "Block is a duplicate" << std::endl;
}
}
}

View File

@ -5,6 +5,7 @@
#include <bitcoin-build-config.h> // IWYU pragma: keep
#include <clientversion.h>
#include <common/args.h>
#include <util/fs.h>
#include <util/exec.h>
#include <util/strencodings.h>
@ -47,7 +48,7 @@ Run '%s help' to see additional commands (e.g. for testing and debugging).
)";
struct CommandLine {
bool use_multiprocess{false};
std::optional<bool> use_multiprocess;
bool show_version{false};
bool show_help{false};
std::string_view command;
@ -55,6 +56,7 @@ struct CommandLine {
};
CommandLine ParseCommandLine(int argc, char* argv[]);
bool UseMultiprocess(const CommandLine& cmd);
static void ExecCommand(const std::vector<const char*>& args, std::string_view argv0);
int main(int argc, char* argv[])
@ -78,9 +80,9 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}
} else if (cmd.command == "gui") {
args.emplace_back(cmd.use_multiprocess ? "bitcoin-gui" : "bitcoin-qt");
args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-gui" : "bitcoin-qt");
} else if (cmd.command == "node") {
args.emplace_back(cmd.use_multiprocess ? "bitcoin-node" : "bitcoind");
args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-node" : "bitcoind");
} else if (cmd.command == "rpc") {
args.emplace_back("bitcoin-cli");
// Since "bitcoin rpc" is a new interface that doesn't need to be
@ -143,6 +145,30 @@ CommandLine ParseCommandLine(int argc, char* argv[])
return cmd;
}
bool UseMultiprocess(const CommandLine& cmd)
{
// If -m or -M options were explicitly specified, there is no need to
// further parse arguments to determine which to use.
if (cmd.use_multiprocess) return *cmd.use_multiprocess;
ArgsManager args;
args.SetDefaultFlags(ArgsManager::ALLOW_ANY);
std::string error_message;
auto argv{cmd.args};
argv.insert(argv.begin(), nullptr);
if (!args.ParseParameters(argv.size(), argv.data(), error_message)) {
tfm::format(std::cerr, "Warning: failed to parse subcommand command line options: %s\n", error_message);
}
if (!args.ReadConfigFiles(error_message, true)) {
tfm::format(std::cerr, "Warning: failed to parse subcommand config: %s\n", error_message);
}
args.SelectConfigNetwork(args.GetChainTypeString());
// If any -ipc* options are set these need to be processed by a
// multiprocess-capable binary.
return args.IsArgSet("-ipcbind") || args.IsArgSet("-ipcconnect") || args.IsArgSet("-ipcfd");
}
//! Execute the specified bitcoind, bitcoin-qt or other command line in `args`
//! using src, bin and libexec directory paths relative to this executable, where
//! the path to this executable is specified in `wrapper_argv0`.

View File

@ -132,11 +132,16 @@ static bool ParseArgs(NodeContext& node, int argc, char* argv[])
return true;
}
static bool ProcessInitCommands(ArgsManager& args)
static bool ProcessInitCommands(interfaces::Init& init, ArgsManager& args)
{
// Process help and version before taking care about datadir
if (HelpRequested(args) || args.GetBoolArg("-version", false)) {
std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion() + "\n";
std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion();
if (const char* exe_name{init.exeName()}) {
strUsage += " ";
strUsage += exe_name;
}
strUsage += "\n";
if (args.GetBoolArg("-version", false)) {
strUsage += FormatParagraph(LicenseInfo());
@ -277,7 +282,7 @@ MAIN_FUNCTION
ArgsManager& args = *Assert(node.args);
if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE;
// Process early info return commands such as -help or -version
if (ProcessInitCommands(args)) return EXIT_SUCCESS;
if (ProcessInitCommands(*init, args)) return EXIT_SUCCESS;
// Start application
if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {

View File

@ -5,6 +5,7 @@
#include <chain.h>
#include <tinyformat.h>
#include <util/check.h>
#include <util/time.h>
std::string CBlockFileInfo::ToString() const
@ -158,18 +159,26 @@ int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& fr
/** Find the last common ancestor two blocks have.
* Both pa and pb must be non-nullptr. */
const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex* pb) {
// First rewind to the last common height (the forking point cannot be past one of the two).
if (pa->nHeight > pb->nHeight) {
pa = pa->GetAncestor(pb->nHeight);
} else if (pb->nHeight > pa->nHeight) {
pb = pb->GetAncestor(pa->nHeight);
}
while (pa != pb && pa && pb) {
while (pa != pb) {
// Jump back until pa and pb have a common "skip" ancestor.
while (pa->pskip != pb->pskip) {
// This logic relies on the property that equal-height blocks have equal-height skip
// pointers.
Assume(pa->nHeight == pb->nHeight);
Assume(pa->pskip->nHeight == pb->pskip->nHeight);
pa = pa->pskip;
pb = pb->pskip;
}
// At this point, pa and pb are different, but have equal pskip. The forking point lies in
// between pa/pb on the one end, and pa->pskip/pb->pskip on the other end.
pa = pa->pprev;
pb = pb->pprev;
}
// Eventually all chain branches meet at the genesis block.
assert(pa == pb);
return pa;
}

View File

@ -266,7 +266,13 @@ std::optional<unsigned int> ArgsManager::GetArgFlags(const std::string& name) co
return search->second.m_flags;
}
}
return std::nullopt;
return m_default_flags;
}
void ArgsManager::SetDefaultFlags(std::optional<unsigned int> flags)
{
LOCK(cs_args);
m_default_flags = flags;
}
fs::path ArgsManager::GetPathArg(std::string arg, const fs::path& default_value) const

View File

@ -137,6 +137,7 @@ protected:
std::string m_network GUARDED_BY(cs_args);
std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
std::optional<unsigned int> m_default_flags GUARDED_BY(cs_args){};
bool m_accept_any_command GUARDED_BY(cs_args){true};
std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
std::optional<fs::path> m_config_path GUARDED_BY(cs_args);
@ -375,10 +376,15 @@ protected:
/**
* Return Flags for known arg.
* Return nullopt for unknown arg.
* Return default flags for unknown arg.
*/
std::optional<unsigned int> GetArgFlags(const std::string& name) const;
/**
* Set default flags to return for an unknown arg.
*/
void SetDefaultFlags(std::optional<unsigned int>);
/**
* Get settings file path, or return false if read-write settings were
* disabled with -nosettings.

View File

@ -11,19 +11,25 @@
#include <util/string.h>
#include <util/time.h>
#ifndef WIN32
#include <sys/stat.h>
#else
#include <compat/compat.h>
#ifdef WIN32
#include <codecvt>
#include <compat/compat.h>
#include <windows.h>
#else
#include <sys/stat.h>
#include <unistd.h>
#endif
#ifdef HAVE_MALLOPT_ARENA_MAX
#include <malloc.h>
#endif
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <locale>
#include <optional>
#include <stdexcept>
#include <string>
#include <thread>
@ -105,6 +111,22 @@ int GetNumCores()
return std::thread::hardware_concurrency();
}
std::optional<size_t> GetTotalRAM()
{
[[maybe_unused]] auto clamp{[](uint64_t v) { return size_t(std::min(v, uint64_t{std::numeric_limits<size_t>::max()})); }};
#ifdef WIN32
if (MEMORYSTATUSEX m{}; (m.dwLength = sizeof(m), GlobalMemoryStatusEx(&m))) return clamp(m.ullTotalPhys);
#elif defined(__APPLE__) || \
defined(__FreeBSD__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__) || \
defined(__illumos__) || \
defined(__linux__)
if (long p{sysconf(_SC_PHYS_PAGES)}, s{sysconf(_SC_PAGESIZE)}; p > 0 && s > 0) return clamp(1ULL * p * s);
#endif
return std::nullopt;
}
// Obtain the application startup time (used for uptime calculation)
int64_t GetStartupTime()
{

View File

@ -9,6 +9,7 @@
#include <bitcoin-build-config.h> // IWYU pragma: keep
#include <cstdint>
#include <optional>
#include <string>
// Application startup time (used for uptime calculation)
@ -29,4 +30,9 @@ void runCommand(const std::string& strCommand);
*/
int GetNumCores();
/**
* Return the total RAM available on the current system, if detectable.
*/
std::optional<size_t> GetTotalRAM();
#endif // BITCOIN_COMMON_SYSTEM_H

View File

@ -75,14 +75,6 @@ typedef unsigned int SOCKET;
typedef SSIZE_T ssize_t;
#endif
// The type of the option value passed to getsockopt & setsockopt
// differs between Windows and non-Windows.
#ifndef WIN32
typedef void* sockopt_arg_type;
#else
typedef char* sockopt_arg_type;
#endif
#ifdef WIN32
// Export main() and ensure working ASLR when using mingw-w64.
// Exporting a symbol will prevent the linker from stripping

View File

@ -6,6 +6,7 @@
#ifndef BITCOIN_CONSENSUS_PARAMS_H
#define BITCOIN_CONSENSUS_PARAMS_H
#include <script/verify_flags.h>
#include <uint256.h>
#include <array>
@ -89,7 +90,7 @@ struct Params {
* - buried in the chain, and
* - fail if the default script verify flags are applied.
*/
std::map<uint256, uint32_t> script_flag_exceptions;
std::map<uint256, script_verify_flags> script_flag_exceptions;
/** Block height and hash at which BIP34 becomes active */
int BIP34Height;
uint256 BIP34Hash;

View File

@ -140,7 +140,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
return nSigOps;
}
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, uint32_t flags)
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags)
{
int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;

View File

@ -6,6 +6,7 @@
#define BITCOIN_CONSENSUS_TX_VERIFY_H
#include <consensus/amount.h>
#include <script/verify_flags.h>
#include <cstdint>
#include <vector>
@ -52,7 +53,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma
* @param[in] flags Script verification flags
* @return Total signature operation cost of tx
*/
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, uint32_t flags);
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags);
/**
* Check if transaction is final and can be included in a block with the

View File

@ -8,8 +8,10 @@
#include <consensus/params.h>
#include <array>
#include <cassert>
#include <optional>
#include <string>
#include <string_view>
struct VBDeploymentInfo {
/** Deployment name */

View File

@ -401,7 +401,7 @@ static bool HTTPBindAddresses(struct evhttp* http)
// Set the no-delay option (disable Nagle's algorithm) on the TCP socket.
evutil_socket_t fd = evhttp_bound_socket_get_fd(bind_handle);
int one = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (sockopt_arg_type)&one, sizeof(one)) == SOCKET_ERROR) {
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&one), sizeof(one)) == SOCKET_ERROR) {
LogInfo("WARNING: Unable to set TCP_NODELAY on RPC server socket, continuing anyway\n");
}
boundSockets.push_back(bind_handle);

View File

@ -119,7 +119,7 @@ namespace sam {
Session::Session(const fs::path& private_key_file,
const Proxy& control_host,
CThreadInterrupt* interrupt)
std::shared_ptr<CThreadInterrupt> interrupt)
: m_private_key_file{private_key_file},
m_control_host{control_host},
m_interrupt{interrupt},
@ -127,7 +127,7 @@ Session::Session(const fs::path& private_key_file,
{
}
Session::Session(const Proxy& control_host, CThreadInterrupt* interrupt)
Session::Session(const Proxy& control_host, std::shared_ptr<CThreadInterrupt> interrupt)
: m_control_host{control_host},
m_interrupt{interrupt},
m_transient{true}
@ -162,7 +162,7 @@ bool Session::Accept(Connection& conn)
std::string errmsg;
bool disconnect{false};
while (!*m_interrupt) {
while (!m_interrupt->interrupted()) {
Sock::Event occurred;
if (!conn.sock->Wait(MAX_WAIT_FOR_IO, Sock::RECV, &occurred)) {
errmsg = "wait on socket failed";
@ -205,7 +205,7 @@ bool Session::Accept(Connection& conn)
return true;
}
if (*m_interrupt) {
if (m_interrupt->interrupted()) {
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Accept was interrupted\n");
} else {
LogPrintLevel(BCLog::I2P, BCLog::Level::Debug, "Error accepting%s: %s\n", disconnect ? " (will close the session)" : "", errmsg);

View File

@ -63,13 +63,11 @@ public:
* private key will be generated and saved into the file.
* @param[in] control_host Location of the SAM proxy.
* @param[in,out] interrupt If this is signaled then all operations are canceled as soon as
* possible and executing methods throw an exception. Notice: only a pointer to the
* `CThreadInterrupt` object is saved, so it must not be destroyed earlier than this
* `Session` object.
* possible and executing methods throw an exception.
*/
Session(const fs::path& private_key_file,
const Proxy& control_host,
CThreadInterrupt* interrupt);
std::shared_ptr<CThreadInterrupt> interrupt);
/**
* Construct a transient session which will generate its own I2P private key
@ -78,11 +76,9 @@ public:
* the session will be lazily created later when first used.
* @param[in] control_host Location of the SAM proxy.
* @param[in,out] interrupt If this is signaled then all operations are canceled as soon as
* possible and executing methods throw an exception. Notice: only a pointer to the
* `CThreadInterrupt` object is saved, so it must not be destroyed earlier than this
* `Session` object.
* possible and executing methods throw an exception.
*/
Session(const Proxy& control_host, CThreadInterrupt* interrupt);
Session(const Proxy& control_host, std::shared_ptr<CThreadInterrupt> interrupt);
/**
* Destroy the session, closing the internally used sockets. The sockets that have been
@ -235,7 +231,7 @@ private:
/**
* Cease network activity when this is signaled.
*/
CThreadInterrupt* const m_interrupt;
const std::shared_ptr<CThreadInterrupt> m_interrupt;
/**
* Mutex protecting the members that can be concurrently accessed.

View File

@ -658,9 +658,9 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)
argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-acceptstalefeeestimates", strprintf("Read fee estimates even if they are stale (%sdefault: %u) fee estimates are considered stale if they are %s hours old", "regtest only; ", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES, Ticks<std::chrono::hours>(MAX_FILE_AGE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST);
argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-datacarrier", strprintf("(DEPRECATED) Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
argsman.AddArg("-datacarriersize",
strprintf("(DEPRECATED) Relay and mine transactions whose data-carrying raw scriptPubKeys in aggregate "
strprintf("Relay and mine transactions whose data-carrying raw scriptPubKeys in aggregate "
"are of this size or less, allowing multiple outputs (default: %u)",
MAX_OP_RETURN_RELAY),
ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
@ -903,10 +903,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
InitWarning(_("Option '-checkpoints' is set but checkpoints were removed. This option has no effect."));
}
if (args.IsArgSet("-datacarriersize") || args.IsArgSet("-datacarrier")) {
InitWarning(_("Options '-datacarrier' or '-datacarriersize' are set but are marked as deprecated and are expected to be removed in a future version."));
}
// We no longer limit the orphanage based on number of transactions but keep the option to warn users who still have it in their config.
if (args.IsArgSet("-maxorphantx")) {
InitWarning(_("Option '-maxorphantx' is set but no longer has any effect (see release notes). Please remove it from your configuration."));
@ -1767,6 +1763,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// ********************************************************* Step 7: load block chain
// cache size calculations
node::LogOversizedDbCache(args);
const auto [index_cache_sizes, kernel_cache_sizes] = CalculateCacheSizes(args, g_enabled_filter_types.size());
LogInfo("Cache configuration:");

View File

@ -39,6 +39,7 @@ public:
// bitcoin-node accepts the option, and bitcoin-gui accepts all bitcoin-node
// options and will start the node with those options.
bool canListenIpc() override { return true; }
const char* exeName() override { return EXE_NAME; }
node::NodeContext m_node;
std::unique_ptr<interfaces::Ipc> m_ipc;
};

View File

@ -38,6 +38,7 @@ public:
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
interfaces::Ipc* ipc() override { return m_ipc.get(); }
bool canListenIpc() override { return true; }
const char* exeName() override { return EXE_NAME; }
node::NodeContext& m_node;
std::unique_ptr<interfaces::Ipc> m_ipc;
};

View File

@ -16,6 +16,8 @@
namespace init {
namespace {
const char* EXE_NAME = "bitcoin-qt";
class BitcoinQtInit : public interfaces::Init
{
public:
@ -32,6 +34,7 @@ public:
return MakeWalletLoader(chain, *Assert(m_node.args));
}
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
const char* exeName() override { return EXE_NAME; }
node::NodeContext m_node;
};
} // namespace

View File

@ -18,6 +18,8 @@ using node::NodeContext;
namespace init {
namespace {
const char* EXE_NAME = "bitcoind";
class BitcoindInit : public interfaces::Init
{
public:
@ -34,6 +36,7 @@ public:
return MakeWalletLoader(chain, *Assert(m_node.args));
}
std::unique_ptr<interfaces::Echo> makeEcho() override { return interfaces::MakeEcho(); }
const char* exeName() override { return EXE_NAME; }
NodeContext& m_node;
};
} // namespace

View File

@ -38,6 +38,7 @@ public:
virtual std::unique_ptr<Echo> makeEcho() { return nullptr; }
virtual Ipc* ipc() { return nullptr; }
virtual bool canListenIpc() { return false; }
virtual const char* exeName() { return nullptr; }
};
//! Return implementation of Init interface for the node process. If the argv

5
src/ipc/libmultiprocess/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# CMake artifacts
/*build*
# Git artifacts
*.patch

View File

@ -2,7 +2,7 @@ CI_DESC="CI job using LLVM-based libraries and tools (clang, libc++, clang-tidy,
CI_DIR=build-llvm
NIX_ARGS=(--arg enableLibcxx true)
export CXX=clang++
export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wthread-safety-analysis -Wno-unused-parameter"
export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wthread-safety -Wno-unused-parameter"
CMAKE_ARGS=(
-G Ninja
-DMP_ENABLE_CLANG_TIDY=ON

View File

@ -1,5 +1,5 @@
CI_DESC="CI job using old Cap'n Proto version"
CI_DESC="CI job using old Cap'n Proto and cmake versions"
CI_DIR=build-olddeps
export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter -Wno-error=array-bounds"
NIX_ARGS=(--argstr capnprotoVersion "0.7.1")
NIX_ARGS=(--argstr capnprotoVersion "0.7.1" --argstr cmakeVersion "3.12.4")
BUILD_ARGS=(-k)

View File

@ -1,7 +1,7 @@
CI_DESC="CI job running ThreadSanitizer"
CI_DIR=build-sanitize
export CXX=clang++
export CXXFLAGS="-ggdb -Werror -Wall -Wextra -Wpedantic -Wthread-safety-analysis -Wno-unused-parameter -fsanitize=thread"
export CXXFLAGS="-ggdb -Werror -Wall -Wextra -Wpedantic -Wthread-safety -Wno-unused-parameter -fsanitize=thread"
CMAKE_ARGS=()
BUILD_ARGS=(-k -j4)
BUILD_TARGETS=(mptest)

View File

@ -17,6 +17,21 @@ fi
[ -n "${CI_CLEAN-}" ] && rm -rf "${CI_DIR}"
cmake -B "$CI_DIR" "${CMAKE_ARGS[@]+"${CMAKE_ARGS[@]}"}"
cmake --build "$CI_DIR" -t "${BUILD_TARGETS[@]}" -- "${BUILD_ARGS[@]+"${BUILD_ARGS[@]}"}"
ctest --test-dir "$CI_DIR" --output-on-failure
cmake --version
cmake_ver=$(cmake --version | awk '/version/{print $3; exit}')
ver_ge() { [ "$(printf '%s\n' "$2" "$1" | sort -V | head -n1)" = "$2" ]; }
src_dir=$PWD
mkdir -p "$CI_DIR"
cd "$CI_DIR"
cmake "$src_dir" "${CMAKE_ARGS[@]+"${CMAKE_ARGS[@]}"}"
if ver_ge "$cmake_ver" "3.15"; then
cmake --build . -t "${BUILD_TARGETS[@]}" -- "${BUILD_ARGS[@]+"${BUILD_ARGS[@]}"}"
else
# Older versions of cmake can only build one target at a time with --target,
# and do not support -t shortcut
for t in "${BUILD_TARGETS[@]}"; do
cmake --build . --target "$t" -- "${BUILD_ARGS[@]+"${BUILD_ARGS[@]}"}"
done
fi
ctest --output-on-failure

View File

@ -66,8 +66,6 @@ struct ProxyClient<Thread> : public ProxyClientBase<Thread, ::capnp::Void>
ProxyClient(const ProxyClient&) = delete;
~ProxyClient();
void setDisconnectCallback(const std::function<void()>& fn);
//! Reference to callback function that is run if there is a sudden
//! disconnect and the Connection object is destroyed before this
//! ProxyClient<Thread> object. The callback will destroy this object and
@ -285,16 +283,16 @@ struct Waiter
template <typename Fn>
void post(Fn&& fn)
{
const std::unique_lock<std::mutex> lock(m_mutex);
const Lock lock(m_mutex);
assert(!m_fn);
m_fn = std::forward<Fn>(fn);
m_cv.notify_all();
}
template <class Predicate>
void wait(std::unique_lock<std::mutex>& lock, Predicate pred)
void wait(Lock& lock, Predicate pred)
{
m_cv.wait(lock, [&] {
m_cv.wait(lock.m_lock, [&]() MP_REQUIRES(m_mutex) {
// Important for this to be "while (m_fn)", not "if (m_fn)" to avoid
// a lost-wakeup bug. A new m_fn and m_cv notification might be sent
// after the fn() call and before the lock.lock() call in this loop
@ -317,9 +315,9 @@ struct Waiter
//! mutexes than necessary. This mutex can be held at the same time as
//! EventLoop::m_mutex as long as Waiter::mutex is locked first and
//! EventLoop::m_mutex is locked second.
std::mutex m_mutex;
Mutex m_mutex;
std::condition_variable m_cv;
std::optional<kj::Function<void()>> m_fn;
std::optional<kj::Function<void()>> m_fn MP_GUARDED_BY(m_mutex);
};
//! Object holding network & rpc state associated with either an incoming server
@ -544,29 +542,73 @@ void ProxyServerBase<Interface, Impl>::invokeDestroy()
CleanupRun(m_context.cleanup_fns);
}
using ConnThreads = std::map<Connection*, ProxyClient<Thread>>;
//! Map from Connection to local or remote thread handle which will be used over
//! that connection. This map will typically only contain one entry, but can
//! contain multiple if a single thread makes IPC calls over multiple
//! connections. A std::optional value type is used to avoid the map needing to
//! be locked while ProxyClient<Thread> objects are constructed, see
//! ThreadContext "Synchronization note" below.
using ConnThreads = std::map<Connection*, std::optional<ProxyClient<Thread>>>;
using ConnThread = ConnThreads::iterator;
// Retrieve ProxyClient<Thread> object associated with this connection from a
// map, or create a new one and insert it into the map. Return map iterator and
// inserted bool.
std::tuple<ConnThread, bool> SetThread(ConnThreads& threads, std::mutex& mutex, Connection* connection, const std::function<Thread::Client()>& make_thread);
std::tuple<ConnThread, bool> SetThread(GuardedRef<ConnThreads> threads, Connection* connection, const std::function<Thread::Client()>& make_thread);
//! The thread_local ThreadContext g_thread_context struct provides information
//! about individual threads and a way of communicating between them. Because
//! it's a thread local struct, each ThreadContext instance is initialized by
//! the thread that owns it.
//!
//! ThreadContext is used for any client threads created externally which make
//! IPC calls, and for server threads created by
//! ProxyServer<ThreadMap>::makeThread() which execute IPC calls for clients.
//!
//! In both cases, the struct holds information like the thread name, and a
//! Waiter object where the EventLoop can post incoming IPC requests to execute
//! on the thread. The struct also holds ConnThread maps associating the thread
//! with local and remote ProxyClient<Thread> objects.
struct ThreadContext
{
//! Identifying string for debug.
std::string thread_name;
//! Waiter object used to allow client threads blocked waiting for a server
//! response to execute callbacks made from the client's corresponding
//! server thread.
//! Waiter object used to allow remote clients to execute code on this
//! thread. For server threads created by
//! ProxyServer<ThreadMap>::makeThread(), this is initialized in that
//! function. Otherwise, for client threads created externally, this is
//! initialized the first time the thread tries to make an IPC call. Having
//! a waiter is necessary for threads making IPC calls in case a server they
//! are calling expects them to execute a callback during the call, before
//! it sends a response.
//!
//! For IPC client threads, the Waiter pointer is never cleared and the Waiter
//! just gets destroyed when the thread does. For server threads created by
//! makeThread(), this pointer is set to null in the ~ProxyServer<Thread> as
//! a signal for the thread to exit and destroy itself. In both cases, the
//! same Waiter object is used across different calls and only created and
//! destroyed once for the lifetime of the thread.
std::unique_ptr<Waiter> waiter = nullptr;
//! When client is making a request to a server, this is the
//! `callbackThread` argument it passes in the request, used by the server
//! in case it needs to make callbacks into the client that need to execute
//! while the client is waiting. This will be set to a local thread object.
ConnThreads callback_threads;
//!
//! Synchronization note: The callback_thread and request_thread maps are
//! only ever accessed internally by this thread's destructor and externally
//! by Cap'n Proto event loop threads. Since it's possible for IPC client
//! threads to make calls over different connections that could have
//! different event loops, these maps are guarded by Waiter::m_mutex in case
//! different event loop threads add or remove map entries simultaneously.
//! However, individual ProxyClient<Thread> objects in the maps will only be
//! associated with one event loop and guarded by EventLoop::m_mutex. So
//! Waiter::m_mutex does not need to be held while accessing individual
//! ProxyClient<Thread> instances, and may even need to be released to
//! respect lock order and avoid locking Waiter::m_mutex before
//! EventLoop::m_mutex.
ConnThreads callback_threads MP_GUARDED_BY(waiter->m_mutex);
//! When client is making a request to a server, this is the `thread`
//! argument it passes in the request, used to control which thread on
@ -575,7 +617,9 @@ struct ThreadContext
//! by makeThread. If a client call is being made from a thread currently
//! handling a server request, this will be set to the `callbackThread`
//! request thread argument passed in that request.
ConnThreads request_threads;
//!
//! Synchronization note: \ref callback_threads note applies here as well.
ConnThreads request_threads MP_GUARDED_BY(waiter->m_mutex);
//! Whether this thread is a capnp event loop thread. Not really used except
//! to assert false if there's an attempt to execute a blocking operation

View File

@ -617,7 +617,7 @@ void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, Fiel
const char* disconnected = nullptr;
proxy_client.m_context.loop->sync([&]() {
if (!proxy_client.m_context.connection) {
const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
const Lock lock(thread_context.waiter->m_mutex);
done = true;
disconnected = "IPC client method called after disconnect.";
thread_context.waiter->m_cv.notify_all();
@ -644,7 +644,7 @@ void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, Fiel
} catch (...) {
exception = std::current_exception();
}
const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
const Lock lock(thread_context.waiter->m_mutex);
done = true;
thread_context.waiter->m_cv.notify_all();
},
@ -656,13 +656,13 @@ void clientInvoke(ProxyClient& proxy_client, const GetRequest& get_request, Fiel
proxy_client.m_context.loop->logPlain()
<< "{" << thread_context.thread_name << "} IPC client exception " << kj_exception;
}
const std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
const Lock lock(thread_context.waiter->m_mutex);
done = true;
thread_context.waiter->m_cv.notify_all();
}));
});
std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
Lock lock(thread_context.waiter->m_mutex);
thread_context.waiter->wait(lock, [&done]() { return done; });
if (exception) std::rethrow_exception(exception);
if (!kj_exception.empty()) proxy_client.m_context.loop->raise() << kj_exception;

View File

@ -25,7 +25,7 @@ void CustomBuildField(TypeList<>,
// Also store the Thread::Client reference in the callback_threads map so
// future calls over this connection can reuse it.
auto [callback_thread, _]{SetThread(
thread_context.callback_threads, thread_context.waiter->m_mutex, &connection,
GuardedRef{thread_context.waiter->m_mutex, thread_context.callback_threads}, &connection,
[&] { return connection.m_threads.add(kj::heap<ProxyServer<Thread>>(thread_context, std::thread{})); })};
// Call remote ThreadMap.makeThread function so server will create a
@ -43,12 +43,12 @@ void CustomBuildField(TypeList<>,
return request.send().getResult(); // Nonblocking due to capnp request pipelining.
}};
auto [request_thread, _1]{SetThread(
thread_context.request_threads, thread_context.waiter->m_mutex,
GuardedRef{thread_context.waiter->m_mutex, thread_context.request_threads},
&connection, make_request_thread)};
auto context = output.init();
context.setThread(request_thread->second.m_client);
context.setCallbackThread(callback_thread->second.m_client);
context.setThread(request_thread->second->m_client);
context.setCallbackThread(callback_thread->second->m_client);
}
//! PassField override for mp.Context arguments. Return asynchronously and call
@ -89,29 +89,39 @@ auto PassField(Priority<1>, TypeList<>, ServerContext& server_context, const Fn&
// need to update the map.
auto& thread_context = g_thread_context;
auto& request_threads = thread_context.request_threads;
auto [request_thread, inserted]{SetThread(
request_threads, thread_context.waiter->m_mutex,
server.m_context.connection,
[&] { return context_arg.getCallbackThread(); })};
ConnThread request_thread;
bool inserted;
server.m_context.loop->sync([&] {
std::tie(request_thread, inserted) = SetThread(
GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection,
[&] { return context_arg.getCallbackThread(); });
});
// If an entry was inserted into the requests_threads map,
// If an entry was inserted into the request_threads map,
// remove it after calling fn.invoke. If an entry was not
// inserted, one already existed, meaning this must be a
// recursive call (IPC call calling back to the caller which
// makes another IPC call), so avoid modifying the map.
const bool erase_thread{inserted};
KJ_DEFER(if (erase_thread) {
std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
// Call erase here with a Connection* argument instead
// of an iterator argument, because the `request_thread`
// iterator may be invalid if the connection is closed
// during this function call. More specifically, the
// iterator may be invalid because SetThread adds a
// cleanup callback to the Connection destructor that
// erases the thread from the map, and also because the
// ProxyServer<Thread> destructor calls
// request_threads.clear().
request_threads.erase(server.m_context.connection);
// Erase the request_threads entry on the event loop
// thread with loop->sync(), so if the connection is
// broken there is not a race between this thread and
// the disconnect handler trying to destroy the thread
// client object.
server.m_context.loop->sync([&] {
// Look up the thread again without using existing
// iterator since entry may no longer be there after
// a disconnect. Destroy node after releasing
// Waiter::m_mutex, so the ProxyClient<Thread>
// destructor is able to use EventLoop::mutex
// without violating lock order.
ConnThreads::node_type removed;
{
Lock lock(thread_context.waiter->m_mutex);
removed = request_threads.extract(server.m_context.connection);
}
});
});
fn.invoke(server_context, args...);
}

View File

@ -182,6 +182,17 @@ public:
std::unique_lock<std::mutex> m_lock;
};
template<typename T>
struct GuardedRef
{
Mutex& mutex;
T& ref MP_GUARDED_BY(mutex);
};
// CTAD for Clang 16: GuardedRef{mutex, x} -> GuardedRef<decltype(x)>
template <class U>
GuardedRef(Mutex&, U&) -> GuardedRef<U>;
//! Analog to std::lock_guard that unlocks instead of locks.
template <typename Lock>
struct UnlockGuard

View File

@ -3,6 +3,7 @@
, enableLibcxx ? false # Whether to use libc++ toolchain and libraries instead of libstdc++
, minimal ? false # Whether to create minimal shell without extra tools (faster when cross compiling)
, capnprotoVersion ? null
, cmakeVersion ? null
}:
let
@ -37,12 +38,23 @@ let
capnproto = capnprotoBase.override (lib.optionalAttrs enableLibcxx { clangStdenv = llvm.libcxxStdenv; });
clang = if enableLibcxx then llvm.libcxxClang else llvm.clang;
clang-tools = llvm.clang-tools.override { inherit enableLibcxx; };
cmakeHashes = {
"3.12.4" = "sha256-UlVYS/0EPrcXViz/iULUcvHA5GecSUHYS6raqbKOMZQ=";
};
cmakeBuild = if cmakeVersion == null then pkgs.cmake else (pkgs.cmake.overrideAttrs (old: {
version = cmakeVersion;
src = pkgs.fetchurl {
url = "https://cmake.org/files/v${lib.versions.majorMinor cmakeVersion}/cmake-${cmakeVersion}.tar.gz";
hash = lib.attrByPath [cmakeVersion] "" cmakeHashes;
};
patches = [];
})).override { isMinimalBuild = true; };
in crossPkgs.mkShell {
buildInputs = [
capnproto
];
nativeBuildInputs = with pkgs; [
cmake
cmakeBuild
include-what-you-use
ninja
] ++ lib.optionals (!minimal) [

View File

@ -12,6 +12,7 @@
#include <atomic>
#include <capnp/capability.h>
#include <capnp/common.h> // IWYU pragma: keep
#include <capnp/rpc.h>
#include <condition_variable>
#include <functional>
@ -25,7 +26,6 @@
#include <kj/memory.h>
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <stdexcept>
#include <string>
@ -81,6 +81,11 @@ ProxyContext::ProxyContext(Connection* connection) : connection(connection), loo
Connection::~Connection()
{
// Connection destructor is always called on the event loop thread. If this
// is a local disconnect, it will trigger I/O, so this needs to run on the
// event loop thread, and if there was a remote disconnect, this is called
// by an onDisconnect callback directly from the event loop thread.
assert(std::this_thread::get_id() == m_loop->m_thread_id);
// Shut down RPC system first, since this will garbage collect any
// ProxyServer objects that were not freed before the connection was closed.
// Typically all ProxyServer objects associated with this connection will be
@ -156,6 +161,9 @@ CleanupIt Connection::addSyncCleanup(std::function<void()> fn)
void Connection::removeSyncCleanup(CleanupIt it)
{
// Require cleanup functions to be removed on the event loop thread to avoid
// needing to deal with them being removed in the middle of a disconnect.
assert(std::this_thread::get_id() == m_loop->m_thread_id);
const Lock lock(m_loop->m_mutex);
m_sync_cleanup_fns.erase(it);
}
@ -305,15 +313,18 @@ bool EventLoop::done() const
return m_num_clients == 0 && m_async_fns->empty();
}
std::tuple<ConnThread, bool> SetThread(ConnThreads& threads, std::mutex& mutex, Connection* connection, const std::function<Thread::Client()>& make_thread)
std::tuple<ConnThread, bool> SetThread(GuardedRef<ConnThreads> threads, Connection* connection, const std::function<Thread::Client()>& make_thread)
{
const std::unique_lock<std::mutex> lock(mutex);
auto thread = threads.find(connection);
if (thread != threads.end()) return {thread, false};
thread = threads.emplace(
std::piecewise_construct, std::forward_as_tuple(connection),
std::forward_as_tuple(make_thread(), connection, /* destroy_connection= */ false)).first;
thread->second.setDisconnectCallback([&threads, &mutex, thread] {
assert(std::this_thread::get_id() == connection->m_loop->m_thread_id);
ConnThread thread;
bool inserted;
{
const Lock lock(threads.mutex);
std::tie(thread, inserted) = threads.ref.try_emplace(connection);
}
if (inserted) {
thread->second.emplace(make_thread(), connection, /* destroy_connection= */ false);
thread->second->m_disconnect_cb = connection->addSyncCleanup([threads, thread] {
// Note: it is safe to use the `thread` iterator in this cleanup
// function, because the iterator would only be invalid if the map entry
// was removed, and if the map entry is removed the ProxyClient<Thread>
@ -322,12 +333,14 @@ std::tuple<ConnThread, bool> SetThread(ConnThreads& threads, std::mutex& mutex,
// Connection is being destroyed before thread client is, so reset
// thread client m_disconnect_cb member so thread client destructor does not
// try to unregister this callback after connection is destroyed.
thread->second->m_disconnect_cb.reset();
// Remove connection pointer about to be destroyed from the map
const std::unique_lock<std::mutex> lock(mutex);
thread->second.m_disconnect_cb.reset();
threads.erase(thread);
const Lock lock(threads.mutex);
threads.ref.erase(thread);
});
return {thread, true};
}
return {thread, inserted};
}
ProxyClient<Thread>::~ProxyClient()
@ -335,16 +348,17 @@ ProxyClient<Thread>::~ProxyClient()
// If thread is being destroyed before connection is destroyed, remove the
// cleanup callback that was registered to handle the connection being
// destroyed before the thread being destroyed.
if (m_disconnect_cb) {
// Remove disconnect callback on the event loop thread with
// loop->sync(), so if the connection is broken there is not a race
// between this thread trying to remove the callback and the disconnect
// handler attempting to call it.
m_context.loop->sync([&]() {
if (m_disconnect_cb) {
m_context.connection->removeSyncCleanup(*m_disconnect_cb);
}
}
void ProxyClient<Thread>::setDisconnectCallback(const std::function<void()>& fn)
{
assert(fn);
assert(!m_disconnect_cb);
m_disconnect_cb = m_context.connection->addSyncCleanup(fn);
});
}
}
ProxyServer<Thread>::ProxyServer(ThreadContext& thread_context, std::thread&& thread)
@ -364,7 +378,7 @@ ProxyServer<Thread>::~ProxyServer()
assert(m_thread_context.waiter.get());
std::unique_ptr<Waiter> waiter;
{
const std::unique_lock<std::mutex> lock(m_thread_context.waiter->m_mutex);
const Lock lock(m_thread_context.waiter->m_mutex);
//! Reset thread context waiter pointer, as shutdown signal for done
//! lambda passed as waiter->wait() argument in makeThread code below.
waiter = std::move(m_thread_context.waiter);
@ -398,7 +412,7 @@ kj::Promise<void> ProxyServer<ThreadMap>::makeThread(MakeThreadContext context)
g_thread_context.thread_name = ThreadName(m_connection.m_loop->m_exe_name) + " (from " + from + ")";
g_thread_context.waiter = std::make_unique<Waiter>();
thread_context.set_value(&g_thread_context);
std::unique_lock<std::mutex> lock(g_thread_context.waiter->m_mutex);
Lock lock(g_thread_context.waiter->m_mutex);
// Wait for shutdown signal from ProxyServer<Thread> destructor (signal
// is just waiter getting set to null.)
g_thread_context.waiter->wait(lock, [] { return !g_thread_context.waiter; });

View File

@ -96,20 +96,15 @@ target_link_libraries(bitcoinkernel
target_include_directories(bitcoinkernel PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src/leveldb/include>)
# libbitcoinkernel requires default symbol visibility, explicitly
# specify that here so that things still work even when user
# configures with -DREDUCE_EXPORTS=ON
#
# Note this is a quick hack that will be removed as we
# incrementally define what to export from the library.
set_target_properties(bitcoinkernel PROPERTIES
CXX_VISIBILITY_PRESET default
)
# Add a convenience libbitcoinkernel target as a synonym for bitcoinkernel.
add_custom_target(libbitcoinkernel)
add_dependencies(libbitcoinkernel bitcoinkernel)
get_target_property(bitcoinkernel_type bitcoinkernel TYPE)
if(bitcoinkernel_type STREQUAL "STATIC_LIBRARY")
target_compile_definitions(bitcoinkernel PUBLIC BITCOINKERNEL_STATIC)
endif()
configure_file(${PROJECT_SOURCE_DIR}/libbitcoinkernel.pc.in ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc @ONLY)
install(FILES ${PROJECT_BINARY_DIR}/libbitcoinkernel.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" COMPONENT libbitcoinkernel)
@ -124,3 +119,5 @@ install(TARGETS bitcoinkernel
DESTINATION ${CMAKE_INSTALL_LIBDIR}
COMPONENT libbitcoinkernel
)
install(FILES bitcoinkernel.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} COMPONENT libbitcoinkernel)

File diff suppressed because it is too large Load Diff

1551
src/kernel/bitcoinkernel.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -155,7 +155,7 @@ int ec_seckey_export_der(const secp256k1_context *ctx, unsigned char *seckey, si
}
bool CKey::Check(const unsigned char *vch) {
return secp256k1_ec_seckey_verify(secp256k1_context_sign, vch);
return secp256k1_ec_seckey_verify(secp256k1_context_static, vch);
}
void CKey::MakeNewKey(bool fCompressedIn) {
@ -186,7 +186,7 @@ CPubKey CKey::GetPubKey() const {
CPubKey result;
int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, UCharCast(begin()));
assert(ret);
secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
secp256k1_ec_pubkey_serialize(secp256k1_context_static, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
assert(result.size() == clen);
assert(result.IsValid());
return result;
@ -196,7 +196,7 @@ CPubKey CKey::GetPubKey() const {
bool SigHasLowR(const secp256k1_ecdsa_signature* sig)
{
unsigned char compact_sig[64];
secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_sign, compact_sig, sig);
secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_static, compact_sig, sig);
// In DER serialization, all values are interpreted as big-endian, signed integers. The highest bit in the integer indicates
// its signed-ness; 0 is positive, 1 is negative. When the value is interpreted as a negative integer, it must be converted
@ -222,7 +222,7 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool gr
ret = secp256k1_ecdsa_sign(secp256k1_context_sign, &sig, hash.begin(), UCharCast(begin()), secp256k1_nonce_function_rfc6979, extra_entropy);
}
assert(ret);
secp256k1_ecdsa_signature_serialize_der(secp256k1_context_sign, vchSig.data(), &nSigLen, &sig);
secp256k1_ecdsa_signature_serialize_der(secp256k1_context_static, vchSig.data(), &nSigLen, &sig);
vchSig.resize(nSigLen);
// Additional verification step to prevent using a potentially corrupted signature
secp256k1_pubkey pk;
@ -254,7 +254,7 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
secp256k1_ecdsa_recoverable_signature rsig;
int ret = secp256k1_ecdsa_sign_recoverable(secp256k1_context_sign, &rsig, hash.begin(), UCharCast(begin()), secp256k1_nonce_function_rfc6979, nullptr);
assert(ret);
ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_sign, &vchSig[1], &rec, &rsig);
ret = secp256k1_ecdsa_recoverable_signature_serialize_compact(secp256k1_context_static, &vchSig[1], &rec, &rsig);
assert(ret);
assert(rec != -1);
vchSig[0] = 27 + rec + (fCompressed ? 4 : 0);
@ -277,7 +277,7 @@ bool CKey::SignSchnorr(const uint256& hash, std::span<unsigned char> sig, const
bool CKey::Load(const CPrivKey &seckey, const CPubKey &vchPubKey, bool fSkipCheck=false) {
MakeKeyData();
if (!ec_seckey_import_der(secp256k1_context_sign, (unsigned char*)begin(), seckey.data(), seckey.size())) {
if (!ec_seckey_import_der(secp256k1_context_static, (unsigned char*)begin(), seckey.data(), seckey.size())) {
ClearKeyData();
return false;
}
@ -303,7 +303,7 @@ bool CKey::Derive(CKey& keyChild, ChainCode &ccChild, unsigned int nChild, const
}
memcpy(ccChild.begin(), vout.data()+32, 32);
keyChild.Set(begin(), begin() + 32, true);
bool ret = secp256k1_ec_seckey_tweak_add(secp256k1_context_sign, (unsigned char*)keyChild.begin(), vout.data());
bool ret = secp256k1_ec_seckey_tweak_add(secp256k1_context_static, (unsigned char*)keyChild.begin(), vout.data());
if (!ret) keyChild.ClearKeyData();
return ret;
}
@ -331,7 +331,7 @@ ECDHSecret CKey::ComputeBIP324ECDHSecret(const EllSwiftPubKey& their_ellswift, c
ECDHSecret output;
// BIP324 uses the initiator as party A, and the responder as party B. Remap the inputs
// accordingly:
bool success = secp256k1_ellswift_xdh(secp256k1_context_sign,
bool success = secp256k1_ellswift_xdh(secp256k1_context_static,
UCharCast(output.data()),
UCharCast(initiating ? our_ellswift.data() : their_ellswift.data()),
UCharCast(initiating ? their_ellswift.data() : our_ellswift.data()),
@ -415,8 +415,8 @@ KeyPair::KeyPair(const CKey& key, const uint256* merkle_root)
if (success && merkle_root) {
secp256k1_xonly_pubkey pubkey;
unsigned char pubkey_bytes[32];
assert(secp256k1_keypair_xonly_pub(secp256k1_context_sign, &pubkey, nullptr, keypair));
assert(secp256k1_xonly_pubkey_serialize(secp256k1_context_sign, pubkey_bytes, &pubkey));
assert(secp256k1_keypair_xonly_pub(secp256k1_context_static, &pubkey, nullptr, keypair));
assert(secp256k1_xonly_pubkey_serialize(secp256k1_context_static, pubkey_bytes, &pubkey));
uint256 tweak = XOnlyPubKey(pubkey_bytes).ComputeTapTweakHash(merkle_root->IsNull() ? nullptr : merkle_root);
success = secp256k1_keypair_xonly_tweak_add(secp256k1_context_static, keypair, tweak.data());
}

View File

@ -201,6 +201,7 @@ static const std::map<std::string, BCLog::LogFlags, std::less<>> LOG_CATEGORIES_
{"txreconciliation", BCLog::TXRECONCILIATION},
{"scan", BCLog::SCAN},
{"txpackages", BCLog::TXPACKAGES},
{"kernel", BCLog::KERNEL},
};
static const std::unordered_map<BCLog::LogFlags, std::string> LOG_CATEGORIES_BY_FLAG{

View File

@ -94,6 +94,7 @@ namespace BCLog {
TXRECONCILIATION = (CategoryMask{1} << 26),
SCAN = (CategoryMask{1} << 27),
TXPACKAGES = (CategoryMask{1} << 28),
KERNEL = (CategoryMask{1} << 29),
ALL = ~NONE,
};
enum class Level {
@ -256,6 +257,12 @@ namespace BCLog {
m_print_callbacks.erase(it);
}
size_t NumConnections()
{
StdLockGuard scoped_lock(m_cs);
return m_print_callbacks.size();
}
/** Start logging (and flush all buffered messages) */
bool StartLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
/** Only for testing */
@ -287,6 +294,11 @@ namespace BCLog {
StdLockGuard scoped_lock(m_cs);
m_category_log_levels = levels;
}
void AddCategoryLogLevel(LogFlags category, Level level)
{
StdLockGuard scoped_lock(m_cs);
m_category_log_levels[category] = level;
}
bool SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
Level LogLevel() const { return m_log_level.load(); }

View File

@ -108,7 +108,7 @@ const std::string NET_MESSAGE_TYPE_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
static const uint64_t RANDOMIZER_ID_ADDRCACHE = 0x1cf2e4ddd306dda9ULL; // SHA256("addrcache")[0:8]
static const uint64_t RANDOMIZER_ID_NETWORKKEY = 0x0e8a2b136c592a7dULL; // SHA256("networkkey")[0:8]
//
// Global state variables
//
@ -331,42 +331,22 @@ bool IsLocal(const CService& addr)
return mapLocalHost.count(addr) > 0;
}
CNode* CConnman::FindNode(const CNetAddr& ip)
bool CConnman::AlreadyConnectedToHost(const std::string& host) const
{
LOCK(m_nodes_mutex);
for (CNode* pnode : m_nodes) {
if (static_cast<CNetAddr>(pnode->addr) == ip) {
return pnode;
}
}
return nullptr;
return std::ranges::any_of(m_nodes, [&host](CNode* node) { return node->m_addr_name == host; });
}
CNode* CConnman::FindNode(const std::string& addrName)
bool CConnman::AlreadyConnectedToAddressPort(const CService& addr_port) const
{
LOCK(m_nodes_mutex);
for (CNode* pnode : m_nodes) {
if (pnode->m_addr_name == addrName) {
return pnode;
}
}
return nullptr;
return std::ranges::any_of(m_nodes, [&addr_port](CNode* node) { return node->addr == addr_port; });
}
CNode* CConnman::FindNode(const CService& addr)
bool CConnman::AlreadyConnectedToAddress(const CNetAddr& addr) const
{
LOCK(m_nodes_mutex);
for (CNode* pnode : m_nodes) {
if (static_cast<CService>(pnode->addr) == addr) {
return pnode;
}
}
return nullptr;
}
bool CConnman::AlreadyConnectedToAddress(const CAddress& addr)
{
return FindNode(static_cast<CNetAddr>(addr));
return std::ranges::any_of(m_nodes, [&addr](CNode* node) { return node->addr == addr; });
}
bool CConnman::CheckIncomingNonce(uint64_t nonce)
@ -393,7 +373,12 @@ static CService GetBindAddress(const Sock& sock)
return addr_bind;
}
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type, bool use_v2transport)
CNode* CConnman::ConnectNode(CAddress addrConnect,
const char* pszDest,
bool fCountFailure,
ConnectionType conn_type,
bool use_v2transport,
const std::optional<Proxy>& proxy_override)
{
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
assert(conn_type != ConnectionType::INBOUND);
@ -403,10 +388,8 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
return nullptr;
// Look for an existing connection
CNode* pnode = FindNode(static_cast<CService>(addrConnect));
if (pnode)
{
LogPrintf("Failed to open new connection, already connected\n");
if (AlreadyConnectedToAddressPort(addrConnect)) {
LogInfo("Failed to open new connection to %s, already connected", addrConnect.ToStringAddrPort());
return nullptr;
}
}
@ -436,9 +419,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
}
// It is possible that we already have a connection to the IP/port pszDest resolved to.
// In that case, drop the connection that was just created.
LOCK(m_nodes_mutex);
CNode* pnode = FindNode(static_cast<CService>(addrConnect));
if (pnode) {
if (AlreadyConnectedToAddressPort(addrConnect)) {
LogPrintf("Not opening a connection to %s, already connected to %s\n", pszDest, addrConnect.ToStringAddrPort());
return nullptr;
}
@ -463,7 +444,13 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
for (auto& target_addr: connect_to) {
if (target_addr.IsValid()) {
const bool use_proxy{GetProxy(target_addr.GetNetwork(), proxy)};
bool use_proxy;
if (proxy_override.has_value()) {
use_proxy = true;
proxy = proxy_override.value();
} else {
use_proxy = GetProxy(target_addr.GetNetwork(), proxy);
}
bool proxyConnectionFailed = false;
if (target_addr.IsI2P() && use_proxy) {
@ -477,7 +464,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
LOCK(m_unused_i2p_sessions_mutex);
if (m_unused_i2p_sessions.empty()) {
i2p_transient_session =
std::make_unique<i2p::sam::Session>(proxy, &interruptNet);
std::make_unique<i2p::sam::Session>(proxy, m_interrupt_net);
} else {
i2p_transient_session.swap(m_unused_i2p_sessions.front());
m_unused_i2p_sessions.pop();
@ -530,6 +517,13 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (!addr_bind.IsValid()) {
addr_bind = GetBindAddress(*sock);
}
uint64_t network_id = GetDeterministicRandomizer(RANDOMIZER_ID_NETWORKKEY)
.Write(target_addr.GetNetClass())
.Write(addr_bind.GetAddrBytes())
// For outbound connections, the port of the bound address is randomly
// assigned by the OS and would therefore not be useful for seeding.
.Write(0)
.Finalize();
CNode* pnode = new CNode(id,
std::move(sock),
target_addr,
@ -539,6 +533,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
pszDest ? pszDest : "",
conn_type,
/*inbound_onion=*/false,
network_id,
CNodeOptions{
.permission_flags = permission_flags,
.i2p_sam_session = std::move(i2p_transient_session),
@ -574,9 +569,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);
}
}
@ -1638,7 +1633,7 @@ std::pair<size_t, bool> CConnman::SocketSendData(CNode& node) const
flags |= MSG_MORE;
}
#endif
nBytes = node.m_sock->Send(reinterpret_cast<const char*>(data.data()), data.size(), flags);
nBytes = node.m_sock->Send(data.data(), data.size(), flags);
}
if (nBytes > 0) {
node.m_last_send = GetTime<std::chrono::seconds>();
@ -1768,7 +1763,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);
@ -1823,12 +1822,16 @@ 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();
const bool use_v2transport(local_services & NODE_P2P_V2);
uint64_t network_id = GetDeterministicRandomizer(RANDOMIZER_ID_NETWORKKEY)
.Write(inbound_onion ? NET_ONION : addr.GetNetClass())
.Write(addr_bind.GetAddrBytes())
.Write(addr_bind.GetPort()) // inbound connections use bind port
.Finalize();
CNode* pnode = new CNode(id,
std::move(sock),
CAddress{addr, NODE_NONE},
@ -1838,6 +1841,7 @@ void CConnman::CreateNodeFromAcceptedSocket(std::unique_ptr<Sock>&& sock,
/*addrNameIn=*/"",
ConnectionType::INBOUND,
inbound_onion,
network_id,
CNodeOptions{
.permission_flags = permission_flags,
.prefer_evict = discouraged,
@ -2100,7 +2104,7 @@ void CConnman::SocketHandler()
// empty sets.
events_per_sock = GenerateWaitSockets(snap.Nodes());
if (events_per_sock.empty() || !events_per_sock.begin()->first->WaitMany(timeout, events_per_sock)) {
interruptNet.sleep_for(timeout);
m_interrupt_net->sleep_for(timeout);
}
// Service (send/receive) each of the already connected nodes.
@ -2117,8 +2121,9 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
AssertLockNotHeld(m_total_bytes_sent_mutex);
for (CNode* pnode : nodes) {
if (interruptNet)
if (m_interrupt_net->interrupted()) {
return;
}
//
// Receive
@ -2213,7 +2218,7 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
void CConnman::SocketHandlerListening(const Sock::EventsPerSock& events_per_sock)
{
for (const ListenSocket& listen_socket : vhListenSocket) {
if (interruptNet) {
if (m_interrupt_net->interrupted()) {
return;
}
const auto it = events_per_sock.find(listen_socket.sock);
@ -2227,8 +2232,7 @@ void CConnman::ThreadSocketHandler()
{
AssertLockNotHeld(m_total_bytes_sent_mutex);
while (!interruptNet)
{
while (!m_interrupt_net->interrupted()) {
DisconnectNodes();
NotifyNumConnectionsChanged();
SocketHandler();
@ -2252,9 +2256,10 @@ void CConnman::ThreadDNSAddressSeed()
auto start = NodeClock::now();
constexpr std::chrono::seconds SEEDNODE_TIMEOUT = 30s;
LogPrintf("-seednode enabled. Trying the provided seeds for %d seconds before defaulting to the dnsseeds.\n", SEEDNODE_TIMEOUT.count());
while (!interruptNet) {
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
while (!m_interrupt_net->interrupted()) {
if (!m_interrupt_net->sleep_for(500ms)) {
return;
}
// Abort if we have spent enough time without reaching our target.
// Giving seed nodes 30 seconds so this does not become a race against fixedseeds (which triggers after 1 min)
@ -2315,7 +2320,7 @@ void CConnman::ThreadDNSAddressSeed()
// early to see if we have enough peers and can stop
// this thread entirely freeing up its resources
std::chrono::seconds w = std::min(DNSSEEDS_DELAY_FEW_PEERS, to_wait);
if (!interruptNet.sleep_for(w)) return;
if (!m_interrupt_net->sleep_for(w)) return;
to_wait -= w;
if (GetFullOutboundConnCount() >= SEED_OUTBOUND_CONNECTION_THRESHOLD) {
@ -2331,13 +2336,13 @@ void CConnman::ThreadDNSAddressSeed()
}
}
if (interruptNet) return;
if (m_interrupt_net->interrupted()) return;
// hold off on querying seeds if P2P network deactivated
if (!fNetworkActive) {
LogPrintf("Waiting for network to be reactivated before querying DNS seeds.\n");
do {
if (!interruptNet.sleep_for(std::chrono::seconds{1})) return;
if (!m_interrupt_net->sleep_for(1s)) return;
} while (!fNetworkActive);
}
@ -2532,12 +2537,14 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
OpenNetworkConnection(addr, false, {}, strAddr.c_str(), ConnectionType::MANUAL, /*use_v2transport=*/use_v2transport);
for (int i = 0; i < 10 && i < nLoop; i++)
{
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
if (!m_interrupt_net->sleep_for(500ms)) {
return;
}
}
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
}
if (!m_interrupt_net->sleep_for(500ms)) {
return;
}
PerformReconnections();
}
}
@ -2561,8 +2568,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
LogPrintf("Fixed seeds are disabled\n");
}
while (!interruptNet)
{
while (!m_interrupt_net->interrupted()) {
if (add_addr_fetch) {
add_addr_fetch = false;
const auto& seed{SpanPopBack(seed_nodes)};
@ -2577,14 +2583,16 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
ProcessAddrFetch();
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
if (!m_interrupt_net->sleep_for(500ms)) {
return;
}
PerformReconnections();
CountingSemaphoreGrant<> grant(*semOutbound);
if (interruptNet)
if (m_interrupt_net->interrupted()) {
return;
}
const std::unordered_set<Network> fixed_seed_networks{GetReachableEmptyNetworks()};
if (add_fixed_seeds && !fixed_seed_networks.empty()) {
@ -2758,8 +2766,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
int nTries = 0;
const auto reachable_nets{g_reachable_nets.All()};
while (!interruptNet)
{
while (!m_interrupt_net->interrupted()) {
if (anchor && !m_anchors.empty()) {
const CAddress addr = m_anchors.back();
m_anchors.pop_back();
@ -2861,7 +2868,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
if (addrConnect.IsValid()) {
if (fFeeler) {
// Add small amount of random noise before connection to avoid synchronization.
if (!interruptNet.sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {
if (!m_interrupt_net->sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {
return;
}
LogDebug(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToStringAddrPort());
@ -2876,7 +2883,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std
const bool count_failures{((int)outbound_ipv46_peer_netgroups.size() + outbound_privacy_network_peers) >= std::min(m_max_automatic_connections - 1, 2)};
// Use BIP324 transport when both us and them have NODE_V2_P2P set.
const bool use_v2transport(addrConnect.nServices & GetLocalServices() & NODE_P2P_V2);
OpenNetworkConnection(addrConnect, count_failures, std::move(grant), /*strDest=*/nullptr, conn_type, use_v2transport);
OpenNetworkConnection(addrConnect, count_failures, std::move(grant), /*pszDest=*/nullptr, conn_type, use_v2transport);
}
}
}
@ -2972,19 +2979,26 @@ void CConnman::ThreadOpenAddedConnections()
tried = true;
CAddress addr(CService(), NODE_NONE);
OpenNetworkConnection(addr, false, std::move(grant), info.m_params.m_added_node.c_str(), ConnectionType::MANUAL, info.m_params.m_use_v2transport);
if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) return;
if (!m_interrupt_net->sleep_for(500ms)) return;
grant = CountingSemaphoreGrant<>(*semAddnode, /*fTry=*/true);
}
// See if any reconnections are desired.
PerformReconnections();
// Retry every 60 seconds if a connection was attempted, otherwise two seconds
if (!interruptNet.sleep_for(std::chrono::seconds(tried ? 60 : 2)))
if (!m_interrupt_net->sleep_for(tried ? 60s : 2s)) {
return;
}
}
}
// if successful, this moves the passed grant to the constructed node
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CountingSemaphoreGrant<>&& grant_outbound, const char *pszDest, ConnectionType conn_type, bool use_v2transport)
bool CConnman::OpenNetworkConnection(const CAddress& addrConnect,
bool fCountFailure,
CountingSemaphoreGrant<>&& grant_outbound,
const char* pszDest,
ConnectionType conn_type,
bool use_v2transport,
const std::optional<Proxy>& proxy_override)
{
AssertLockNotHeld(m_unused_i2p_sessions_mutex);
assert(conn_type != ConnectionType::INBOUND);
@ -2992,24 +3006,25 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
//
// Initiate outbound network connection
//
if (interruptNet) {
return;
if (m_interrupt_net->interrupted()) {
return false;
}
if (!fNetworkActive) {
return;
return false;
}
if (!pszDest) {
bool banned_or_discouraged = m_banman && (m_banman->IsDiscouraged(addrConnect) || m_banman->IsBanned(addrConnect));
if (IsLocal(addrConnect) || banned_or_discouraged || AlreadyConnectedToAddress(addrConnect)) {
return;
return false;
}
} else if (AlreadyConnectedToHost(pszDest)) {
return false;
}
} else if (FindNode(std::string(pszDest)))
return;
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport);
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type, use_v2transport, proxy_override);
if (!pnode)
return;
return false;
pnode->grantOutbound = std::move(grant_outbound);
m_msgproc->InitializeNode(*pnode, m_local_services);
@ -3027,6 +3042,8 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
pnode->ConnectionTypeAsString().c_str(),
pnode->ConnectedThroughNetwork(),
GetNodeCount(ConnectionDirection::Out));
return true;
}
Mutex NetEventsInterface::g_msgproc_mutex;
@ -3080,13 +3097,13 @@ void CConnman::ThreadI2PAcceptIncoming()
i2p::Connection conn;
auto SleepOnFailure = [&]() {
interruptNet.sleep_for(err_wait);
m_interrupt_net->sleep_for(err_wait);
if (err_wait < err_wait_cap) {
err_wait += 1s;
}
};
while (!interruptNet) {
while (!m_interrupt_net->interrupted()) {
if (!m_i2p_sam_session->Listen(conn)) {
if (advertising_listen_addr && conn.me.IsValid()) {
@ -3136,7 +3153,7 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
// Allow binding if the port is still in TIME_WAIT state after
// the program was closed and restarted.
if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) {
if (sock->SetSockOpt(SOL_SOCKET, SO_REUSEADDR, &nOne, sizeof(int)) == SOCKET_ERROR) {
strError = Untranslated(strprintf("Error setting SO_REUSEADDR on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));
LogPrintf("%s\n", strError.original);
}
@ -3145,14 +3162,14 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
// and enable it by default or not. Try to enable it, if possible.
if (addrBind.IsIPv6()) {
#ifdef IPV6_V6ONLY
if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_arg_type)&nOne, sizeof(int)) == SOCKET_ERROR) {
if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_V6ONLY, &nOne, sizeof(int)) == SOCKET_ERROR) {
strError = Untranslated(strprintf("Error setting IPV6_V6ONLY on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));
LogPrintf("%s\n", strError.original);
}
#endif
#ifdef WIN32
int nProtLevel = PROTECTION_LEVEL_UNRESTRICTED;
if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, (const char*)&nProtLevel, sizeof(int)) == SOCKET_ERROR) {
if (sock->SetSockOpt(IPPROTO_IPV6, IPV6_PROTECTION_LEVEL, &nProtLevel, sizeof(int)) == SOCKET_ERROR) {
strError = Untranslated(strprintf("Error setting IPV6_PROTECTION_LEVEL on socket: %s, continuing anyway", NetworkErrorString(WSAGetLastError())));
LogPrintf("%s\n", strError.original);
}
@ -3208,12 +3225,18 @@ void CConnman::SetNetworkActive(bool active)
}
}
CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, AddrMan& addrman_in,
const NetGroupManager& netgroupman, const CChainParams& params, bool network_active)
CConnman::CConnman(uint64_t nSeed0In,
uint64_t nSeed1In,
AddrMan& addrman_in,
const NetGroupManager& netgroupman,
const CChainParams& params,
bool network_active,
std::shared_ptr<CThreadInterrupt> interrupt_net)
: addrman(addrman_in)
, m_netgroupman{netgroupman}
, nSeed0(nSeed0In)
, nSeed1(nSeed1In)
, m_interrupt_net{interrupt_net}
, m_params(params)
{
SetTryNewOutboundPeer(false);
@ -3309,7 +3332,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
Proxy i2p_sam;
if (GetProxy(NET_I2P, i2p_sam) && connOptions.m_i2p_accept_incoming) {
m_i2p_sam_session = std::make_unique<i2p::sam::Session>(gArgs.GetDataDirNet() / "i2p_private_key",
i2p_sam, &interruptNet);
i2p_sam, m_interrupt_net);
}
// Randomize the order in which we may query seednode to potentially prevent connecting to the same one every restart (and signal that we have restarted)
@ -3346,7 +3369,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
// Start threads
//
assert(m_msgproc);
interruptNet.reset();
m_interrupt_net->reset();
flagInterruptMsgProc = false;
{
@ -3422,7 +3445,7 @@ void CConnman::Interrupt()
}
condMsgProc.notify_all();
interruptNet();
(*m_interrupt_net)();
g_socks5_interrupt();
if (semOutbound) {
@ -3516,15 +3539,9 @@ std::vector<CAddress> CConnman::GetAddressesUnsafe(size_t max_addresses, size_t
std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addresses, size_t max_pct)
{
auto local_socket_bytes = requestor.addrBind.GetAddrBytes();
uint64_t cache_id = GetDeterministicRandomizer(RANDOMIZER_ID_ADDRCACHE)
.Write(requestor.ConnectedThroughNetwork())
.Write(local_socket_bytes)
// For outbound connections, the port of the bound address is randomly
// assigned by the OS and would therefore not be useful for seeding.
.Write(requestor.IsInboundConn() ? requestor.addrBind.GetPort() : 0)
.Finalize();
uint64_t network_id = requestor.m_network_key;
const auto current_time = GetTime<std::chrono::microseconds>();
auto r = m_addr_response_caches.emplace(cache_id, CachedAddrResponse{});
auto r = m_addr_response_caches.emplace(network_id, CachedAddrResponse{});
CachedAddrResponse& cache_entry = r.first->second;
if (cache_entry.m_cache_entry_expiration < current_time) { // If emplace() added new one it has expiration 0.
cache_entry.m_addrs_response_cache = GetAddressesUnsafe(max_addresses, max_pct, /*network=*/std::nullopt);
@ -3638,9 +3655,11 @@ void CConnman::GetNodeStats(std::vector<CNodeStats>& vstats) const
bool CConnman::DisconnectNode(const std::string& strNode)
{
LOCK(m_nodes_mutex);
if (CNode* pnode = FindNode(strNode)) {
LogDebug(BCLog::NET, "disconnect by address%s match, %s", (fLogIPs ? strprintf("=%s", strNode) : ""), pnode->DisconnectMsg(fLogIPs));
pnode->fDisconnect = true;
auto it = std::ranges::find_if(m_nodes, [&strNode](CNode* node) { return node->m_addr_name == strNode; });
if (it != m_nodes.end()) {
CNode* node{*it};
LogDebug(BCLog::NET, "disconnect by address%s match, %s", (fLogIPs ? strprintf("=%s", strNode) : ""), node->DisconnectMsg(fLogIPs));
node->fDisconnect = true;
return true;
}
return false;
@ -3801,6 +3820,7 @@ CNode::CNode(NodeId idIn,
const std::string& addrNameIn,
ConnectionType conn_type_in,
bool inbound_onion,
uint64_t network_key,
CNodeOptions&& node_opts)
: m_transport{MakeTransport(idIn, node_opts.use_v2transport, conn_type_in == ConnectionType::INBOUND)},
m_permission_flags{node_opts.permission_flags},
@ -3813,6 +3833,7 @@ CNode::CNode(NodeId idIn,
m_inbound_onion{inbound_onion},
m_prefer_evict{node_opts.prefer_evict},
nKeyedNetGroup{nKeyedNetGroupIn},
m_network_key{network_key},
m_conn_type{conn_type_in},
id{idIn},
nLocalHostNonce{nLocalHostNonceIn},

View File

@ -738,6 +738,10 @@ public:
std::atomic_bool fPauseRecv{false};
std::atomic_bool fPauseSend{false};
/** Network key used to prevent fingerprinting our node across networks.
* Influenced by the network and the bind address (+ bind port for inbounds) */
const uint64_t m_network_key;
const ConnectionType m_conn_type;
/** Move all messages from the received queue to the processing queue. */
@ -889,6 +893,7 @@ public:
const std::string& addrNameIn,
ConnectionType conn_type_in,
bool inbound_onion,
uint64_t network_key,
CNodeOptions&& node_opts = {});
CNode(const CNode&) = delete;
CNode& operator=(const CNode&) = delete;
@ -1119,8 +1124,13 @@ public:
whitelist_relay = connOptions.whitelist_relay;
}
CConnman(uint64_t seed0, uint64_t seed1, AddrMan& addrman, const NetGroupManager& netgroupman,
const CChainParams& params, bool network_active = true);
CConnman(uint64_t seed0,
uint64_t seed1,
AddrMan& addrman,
const NetGroupManager& netgroupman,
const CChainParams& params,
bool network_active = true,
std::shared_ptr<CThreadInterrupt> interrupt_net = std::make_shared<CThreadInterrupt>());
~CConnman();
@ -1138,7 +1148,28 @@ public:
bool GetNetworkActive() const { return fNetworkActive; };
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
void SetNetworkActive(bool active);
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CountingSemaphoreGrant<>&& grant_outbound, const char* strDest, ConnectionType conn_type, bool use_v2transport) EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
/**
* Open a new P2P connection and initialize it with the PeerManager at `m_msgproc`.
* @param[in] addrConnect Address to connect to, if `pszDest` is `nullptr`.
* @param[in] fCountFailure Increment the number of connection attempts to this address in Addrman.
* @param[in] grant_outbound Take ownership of this grant, to be released later when the connection is closed.
* @param[in] pszDest Address to resolve and connect to.
* @param[in] conn_type Type of the connection to open, must not be `ConnectionType::INBOUND`.
* @param[in] use_v2transport Use P2P encryption, (aka V2 transport, BIP324).
* @param[in] proxy_override Optional proxy to use and override normal proxy selection.
* @retval true The connection was opened successfully.
* @retval false The connection attempt failed.
*/
bool OpenNetworkConnection(const CAddress& addrConnect,
bool fCountFailure,
CountingSemaphoreGrant<>&& grant_outbound,
const char* pszDest,
ConnectionType conn_type,
bool use_v2transport,
const std::optional<Proxy>& proxy_override = std::nullopt)
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
bool CheckIncomingNonce(uint64_t nonce);
void ASMapHealthCheck();
@ -1365,19 +1396,50 @@ private:
uint64_t CalculateKeyedNetGroup(const CNetAddr& ad) const;
CNode* FindNode(const CNetAddr& ip);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& addr);
/**
* Determine whether we're already connected to a given "host:port".
* Note that for inbound connections, the peer is likely using a random outbound
* port on their side, so this will likely not match any inbound connections.
* @param[in] host String of the form "host[:port]", e.g. "localhost" or "localhost:8333" or "1.2.3.4:8333".
* @return true if connected to `host`.
*/
bool AlreadyConnectedToHost(const std::string& host) const;
/**
* Determine whether we're already connected to a given address, in order to
* avoid initiating duplicate connections.
* Determine whether we're already connected to a given address:port.
* Note that for inbound connections, the peer is likely using a random outbound
* port on their side, so this will likely not match any inbound connections.
* @param[in] addr_port Address and port to check.
* @return true if connected to addr_port.
*/
bool AlreadyConnectedToAddress(const CAddress& addr);
bool AlreadyConnectedToAddressPort(const CService& addr_port) const;
/**
* Determine whether we're already connected to a given address.
*/
bool AlreadyConnectedToAddress(const CNetAddr& addr) const;
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;
/**
* Open a new P2P connection.
* @param[in] addrConnect Address to connect to, if `pszDest` is `nullptr`.
* @param[in] pszDest Address to resolve and connect to.
* @param[in] fCountFailure Increment the number of connection attempts to this address in Addrman.
* @param[in] conn_type Type of the connection to open, must not be `ConnectionType::INBOUND`.
* @param[in] use_v2transport Use P2P encryption, (aka V2 transport, BIP324).
* @param[in] proxy_override Optional proxy to use and override normal proxy selection.
* @return Newly created CNode object or nullptr if the connection failed.
*/
CNode* ConnectNode(CAddress addrConnect,
const char* pszDest,
bool fCountFailure,
ConnectionType conn_type,
bool use_v2transport,
const std::optional<Proxy>& proxy_override)
EXCLUSIVE_LOCKS_REQUIRED(!m_unused_i2p_sessions_mutex);
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr, const std::vector<NetWhitelistPermissions>& ranges) const;
void DeleteNode(CNode* pnode);
@ -1555,11 +1617,9 @@ private:
/**
* This is signaled when network activity should cease.
* A pointer to it is saved in `m_i2p_sam_session`, so make sure that
* the lifetime of `interruptNet` is not shorter than
* the lifetime of `m_i2p_sam_session`.
* A copy of this is saved in `m_i2p_sam_session`.
*/
CThreadInterrupt interruptNet;
const std::shared_ptr<CThreadInterrupt> m_interrupt_net;
/**
* I2P SAM session.

View File

@ -167,7 +167,7 @@ static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL{5s};
static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL{2s};
/** Maximum rate of inventory items to send per second.
* Limits the impact of low-fee transaction floods. */
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND = 7;
static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND{14};
/** Target number of tx inventory items to send per transmission. */
static constexpr unsigned int INVENTORY_BROADCAST_TARGET = INVENTORY_BROADCAST_PER_SECOND * count_seconds(INBOUND_INVENTORY_BROADCAST_INTERVAL);
/** Maximum number of inventory items to send per transmission. */
@ -312,7 +312,7 @@ struct Peer {
std::chrono::microseconds m_next_inv_send_time GUARDED_BY(m_tx_inventory_mutex){0};
/** The mempool sequence num at which we sent the last `inv` message to this peer.
* Can relay txs with lower sequence numbers than this (see CTxMempool::info_for_relay). */
uint64_t m_last_inv_sequence GUARDED_BY(NetEventsInterface::g_msgproc_mutex){1};
uint64_t m_last_inv_sequence GUARDED_BY(m_tx_inventory_mutex){1};
/** Minimum fee rate with which to filter transaction announcements to this node. See BIP133. */
std::atomic<CAmount> m_fee_filter_received{0};
@ -807,7 +807,7 @@ private:
uint32_t GetFetchFlags(const Peer& peer) const;
std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
std::map<uint64_t, std::chrono::microseconds> m_next_inv_to_inbounds_per_network_key GUARDED_BY(g_msgproc_mutex);
/** Number of nodes with fSyncStarted. */
int nSyncStarted GUARDED_BY(cs_main) = 0;
@ -837,12 +837,14 @@ private:
/**
* For sending `inv`s to inbound peers, we use a single (exponentially
* distributed) timer for all peers. If we used a separate timer for each
* distributed) timer for all peers with the same network key. If we used a separate timer for each
* peer, a spy node could make multiple inbound connections to us to
* accurately determine when we received the transaction (and potentially
* determine the transaction's origin). */
* accurately determine when we received a transaction (and potentially
* determine the transaction's origin). Each network key has its own timer
* to make fingerprinting harder. */
std::chrono::microseconds NextInvToInbounds(std::chrono::microseconds now,
std::chrono::seconds average_interval) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
std::chrono::seconds average_interval,
uint64_t network_key) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
// All of the following cache a recent block, and are protected by m_most_recent_block_mutex
@ -942,7 +944,7 @@ private:
/** Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed). */
CTransactionRef FindTxForGetData(const Peer::TxRelay& tx_relay, const GenTxid& gtxid)
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, NetEventsInterface::g_msgproc_mutex);
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, !tx_relay.m_tx_inventory_mutex);
void ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic<bool>& interruptMsgProc)
EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex, peer.m_getdata_requests_mutex, NetEventsInterface::g_msgproc_mutex)
@ -1143,15 +1145,15 @@ static bool CanServeWitnesses(const Peer& peer)
}
std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
std::chrono::seconds average_interval)
std::chrono::seconds average_interval,
uint64_t network_key)
{
if (m_next_inv_to_inbounds.load() < now) {
// If this function were called from multiple threads simultaneously
// it would possible that both update the next send variable, and return a different result to their caller.
// This is not possible in practice as only the net processing thread invokes this function.
m_next_inv_to_inbounds = now + m_rng.rand_exp_duration(average_interval);
auto [it, inserted] = m_next_inv_to_inbounds_per_network_key.try_emplace(network_key, 0us);
auto& timer{it->second};
if (timer < now) {
timer = now + m_rng.rand_exp_duration(average_interval);
}
return m_next_inv_to_inbounds;
return timer;
}
bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
@ -1728,9 +1730,13 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
if (auto tx_relay = peer->GetTxRelay(); tx_relay != nullptr) {
stats.m_relay_txs = WITH_LOCK(tx_relay->m_bloom_filter_mutex, return tx_relay->m_relay_txs);
stats.m_fee_filter_received = tx_relay->m_fee_filter_received.load();
LOCK(tx_relay->m_tx_inventory_mutex);
stats.m_last_inv_seq = tx_relay->m_last_inv_sequence;
stats.m_inv_to_send = tx_relay->m_tx_inventory_to_send.size();
} else {
stats.m_relay_txs = false;
stats.m_fee_filter_received = 0;
stats.m_inv_to_send = 0;
}
stats.m_ping_wait = ping_wait;
@ -2362,8 +2368,8 @@ CTransactionRef PeerManagerImpl::FindTxForGetData(const Peer::TxRelay& tx_relay,
{
// If a tx was in the mempool prior to the last INV for this peer, permit the request.
auto txinfo{std::visit(
[&](const auto& id) EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex) {
return m_mempool.info_for_relay(id, tx_relay.m_last_inv_sequence);
[&](const auto& id) {
return m_mempool.info_for_relay(id, WITH_LOCK(tx_relay.m_tx_inventory_mutex, return tx_relay.m_last_inv_sequence));
},
gtxid)};
if (txinfo.tx) {
@ -5711,7 +5717,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
if (tx_relay->m_next_inv_send_time < current_time) {
fSendTrickle = true;
if (pto->IsInboundConn()) {
tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL);
tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL, pto->m_network_key);
} else {
tx_relay->m_next_inv_send_time = current_time + m_rng.rand_exp_duration(OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
}

View File

@ -54,6 +54,8 @@ struct CNodeStateStats {
std::chrono::microseconds m_ping_wait;
std::vector<int> vHeightInFlight;
bool m_relay_txs;
int m_inv_to_send = 0;
uint64_t m_last_inv_seq{0};
CAmount m_fee_filter_received;
uint64_t m_addr_processed = 0;
uint64_t m_addr_rate_limited = 0;

View File

@ -551,7 +551,7 @@ std::unique_ptr<Sock> CreateSockOS(int domain, int type, int protocol)
int set = 1;
// Set the no-sigpipe option on the socket for BSD systems, other UNIXes
// should use the MSG_NOSIGNAL flag for every send.
if (sock->SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(int)) == SOCKET_ERROR) {
if (sock->SetSockOpt(SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(int)) == SOCKET_ERROR) {
LogPrintf("Error setting SO_NOSIGPIPE on socket: %s, continuing anyway\n",
NetworkErrorString(WSAGetLastError()));
}
@ -620,7 +620,7 @@ static bool ConnectToSocket(const Sock& sock, struct sockaddr* sockaddr, socklen
// sockerr here.
int sockerr;
socklen_t sockerr_len = sizeof(sockerr);
if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR, (sockopt_arg_type)&sockerr, &sockerr_len) ==
if (sock.GetSockOpt(SOL_SOCKET, SO_ERROR, &sockerr, &sockerr_len) ==
SOCKET_ERROR) {
LogPrintf("getsockopt() for %s failed: %s\n", dest_str, NetworkErrorString(WSAGetLastError()));
return false;

View File

@ -5,9 +5,12 @@
#include <node/caches.h>
#include <common/args.h>
#include <common/system.h>
#include <index/txindex.h>
#include <kernel/caches.h>
#include <logging.h>
#include <node/interface_ui.h>
#include <tinyformat.h>
#include <util/byte_units.h>
#include <algorithm>
@ -23,16 +26,20 @@ static constexpr size_t MAX_FILTER_INDEX_CACHE{1024_MiB};
static constexpr size_t MAX_32BIT_DBCACHE{1024_MiB};
namespace node {
size_t CalculateDbCacheBytes(const ArgsManager& args)
{
if (auto db_cache{args.GetIntArg("-dbcache")}) {
if (*db_cache < 0) db_cache = 0;
const uint64_t db_cache_bytes{SaturatingLeftShift<uint64_t>(*db_cache, 20)};
constexpr auto max_db_cache{sizeof(void*) == 4 ? MAX_32BIT_DBCACHE : std::numeric_limits<size_t>::max()};
return std::max<size_t>(MIN_DB_CACHE, std::min<uint64_t>(db_cache_bytes, max_db_cache));
}
return DEFAULT_DB_CACHE;
}
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes)
{
// Convert -dbcache from MiB units to bytes. The total cache is floored by MIN_DB_CACHE and capped by max size_t value.
size_t total_cache{DEFAULT_DB_CACHE};
if (std::optional<int64_t> db_cache = args.GetIntArg("-dbcache")) {
if (*db_cache < 0) db_cache = 0;
uint64_t db_cache_bytes = SaturatingLeftShift<uint64_t>(*db_cache, 20);
constexpr auto max_db_cache{sizeof(void*) == 4 ? MAX_32BIT_DBCACHE : std::numeric_limits<size_t>::max()};
total_cache = std::max<size_t>(MIN_DB_CACHE, std::min<uint64_t>(db_cache_bytes, max_db_cache));
}
size_t total_cache{CalculateDbCacheBytes(args)};
IndexCacheSizes index_sizes;
index_sizes.tx_index = std::min(total_cache / 8, args.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? MAX_TX_INDEX_CACHE : 0);
@ -44,4 +51,15 @@ CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes)
}
return {index_sizes, kernel::CacheSizes{total_cache}};
}
void LogOversizedDbCache(const ArgsManager& args) noexcept
{
if (const auto total_ram{GetTotalRAM()}) {
const size_t db_cache{CalculateDbCacheBytes(args)};
if (ShouldWarnOversizedDbCache(db_cache, *total_ram)) {
InitWarning(bilingual_str{tfm::format(_("A %zu MiB dbcache may be too large for a system memory of only %zu MiB."),
db_cache >> 20, *total_ram >> 20)});
}
}
}
} // namespace node

View File

@ -27,6 +27,13 @@ struct CacheSizes {
kernel::CacheSizes kernel;
};
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes = 0);
constexpr bool ShouldWarnOversizedDbCache(size_t dbcache, size_t total_ram) noexcept
{
const size_t cap{(total_ram < 2048_MiB) ? DEFAULT_DB_CACHE : (total_ram / 100) * 75};
return dbcache > cap;
}
void LogOversizedDbCache(const ArgsManager& args) noexcept;
} // namespace node
#endif // BITCOIN_NODE_CACHES_H

View File

@ -397,8 +397,8 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
++nConsecutiveFailed;
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight >
m_options.nBlockMaxWeight - BLOCK_FULL_ENOUGH_WEIGHT_DELTA) {
if (nConsecutiveFailed > MAX_CONSECUTIVE_FAILURES && nBlockWeight +
BLOCK_FULL_ENOUGH_WEIGHT_DELTA > m_options.nBlockMaxWeight) {
// Give up if we're close to full and haven't succeeded in a while
break;
}

View File

@ -98,7 +98,7 @@ static constexpr unsigned int MAX_DUST_OUTPUTS_PER_TX{1};
* Note that this does not affect consensus validity; see GetBlockScriptFlags()
* for that.
*/
static constexpr unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
static constexpr script_verify_flags MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
SCRIPT_VERIFY_DERSIG |
SCRIPT_VERIFY_NULLDUMMY |
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY |
@ -112,7 +112,7 @@ static constexpr unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH |
* the additional (non-mandatory) rules here, to improve forwards and
* backwards compatibility.
*/
static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERIFY_FLAGS |
static constexpr script_verify_flags STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERIFY_FLAGS |
SCRIPT_VERIFY_STRICTENC |
SCRIPT_VERIFY_MINIMALDATA |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
@ -128,7 +128,7 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE};
/** For convenience, standard but not mandatory verify flags. */
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
static constexpr script_verify_flags STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
/** Used as the flags parameter to sequence and nLocktime checks in non-consensus code. */
static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS{LOCKTIME_VERIFY_SEQUENCE};

View File

@ -166,7 +166,7 @@ UniValue blockheaderToJSON(const CBlockIndex& tip, const CBlockIndex& blockindex
result.pushKV("mediantime", blockindex.GetMedianTimePast());
result.pushKV("nonce", blockindex.nNonce);
result.pushKV("bits", strprintf("%08x", blockindex.nBits));
result.pushKV("target", GetTarget(tip, pow_limit).GetHex());
result.pushKV("target", GetTarget(blockindex, pow_limit).GetHex());
result.pushKV("difficulty", GetDifficulty(blockindex));
result.pushKV("chainwork", blockindex.nChainWork.GetHex());
result.pushKV("nTx", blockindex.nTx);
@ -1469,6 +1469,9 @@ RPCHelpMan getdeploymentinfo()
RPCResult::Type::OBJ, "", "", {
{RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
{RPCResult::Type::NUM, "height", "requested block height (or tip)"},
{RPCResult::Type::ARR, "script_flags", "script verify flags for the block", {
{RPCResult::Type::STR, "flag", "a script verify flag"},
}},
{RPCResult::Type::OBJ_DYN, "deployments", "", {
{RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
}},
@ -1495,6 +1498,12 @@ RPCHelpMan getdeploymentinfo()
UniValue deploymentinfo(UniValue::VOBJ);
deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
deploymentinfo.pushKV("height", blockindex->nHeight);
{
const auto flagnames = GetScriptFlagNames(GetBlockScriptFlags(*blockindex, chainman));
UniValue uv_flagnames(UniValue::VARR);
uv_flagnames.push_backV(flagnames.begin(), flagnames.end());
deploymentinfo.pushKV("script_flags", uv_flagnames);
}
deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, chainman));
return deploymentinfo;
},

View File

@ -18,6 +18,7 @@ public:
std::string methodName; //!< method whose params want conversion
int paramIdx; //!< 0-based idx of param to convert
std::string paramName; //!< parameter name
bool also_string{false}; //!< The parameter is also a string
};
// clang-format off
@ -188,10 +189,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "gettxout", 1, "n" },
{ "gettxout", 2, "include_mempool" },
{ "gettxoutproof", 0, "txids" },
{ "gettxoutsetinfo", 1, "hash_or_height" },
{ "gettxoutsetinfo", 1, "hash_or_height", /*also_string=*/true },
{ "gettxoutsetinfo", 2, "use_index"},
{ "dumptxoutset", 2, "options" },
{ "dumptxoutset", 2, "rollback" },
{ "dumptxoutset", 2, "rollback", /*also_string=*/true },
{ "lockunspent", 0, "unlock" },
{ "lockunspent", 1, "transactions" },
{ "lockunspent", 2, "persistent" },
@ -246,7 +247,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listdescriptors", 0, "private" },
{ "verifychain", 0, "checklevel" },
{ "verifychain", 1, "nblocks" },
{ "getblockstats", 0, "hash_or_height" },
{ "getblockstats", 0, "hash_or_height", /*also_string=*/true },
{ "getblockstats", 1, "stats" },
{ "pruneblockchain", 0, "height" },
{ "keypoolrefill", 0, "newsize" },
@ -318,18 +319,21 @@ static const CRPCConvertParam vRPCConvertParams[] =
// clang-format on
/** Parse string to UniValue or throw runtime_error if string contains invalid JSON */
static UniValue Parse(std::string_view raw)
static UniValue Parse(std::string_view raw, bool also_string)
{
UniValue parsed;
if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
if (!parsed.read(raw)) {
if (!also_string) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
return raw;
}
return parsed;
}
class CRPCConvertTable
{
private:
std::set<std::pair<std::string, int>> members;
std::set<std::pair<std::string, std::string>> membersByName;
std::map<std::pair<std::string, int>, bool> members;
std::map<std::pair<std::string, std::string>, bool> membersByName;
public:
CRPCConvertTable();
@ -337,21 +341,29 @@ public:
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx)
{
return members.count({method, param_idx}) > 0 ? Parse(arg_value) : arg_value;
const auto& it = members.find({method, param_idx});
if (it != members.end()) {
return Parse(arg_value, it->second);
}
return arg_value;
}
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name)
{
return membersByName.count({method, param_name}) > 0 ? Parse(arg_value) : arg_value;
const auto& it = membersByName.find({method, param_name});
if (it != membersByName.end()) {
return Parse(arg_value, it->second);
}
return arg_value;
}
};
CRPCConvertTable::CRPCConvertTable()
{
for (const auto& cp : vRPCConvertParams) {
members.emplace(cp.methodName, cp.paramIdx);
membersByName.emplace(cp.methodName, cp.paramName);
members.emplace(std::make_pair(cp.methodName, cp.paramIdx), cp.also_string);
membersByName.emplace(std::make_pair(cp.methodName, cp.paramName), cp.also_string);
}
}

View File

@ -955,7 +955,7 @@ static RPCHelpMan submitpackage()
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
{RPCResult::Type::OBJ_DYN, "tx-results", "transaction results keyed by wtxid",
{RPCResult::Type::OBJ_DYN, "tx-results", "The transaction results keyed by wtxid. An entry is returned for every submitted wtxid.",
{
{RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
@ -968,7 +968,7 @@ static RPCHelpMan submitpackage()
{{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
}},
}},
{RPCResult::Type::STR, "error", /*optional=*/true, "The transaction error string, if it was rejected by the mempool"},
{RPCResult::Type::STR, "error", /*optional=*/true, "Error string if rejected from mempool, or \"package-not-validated\" when the package aborts before any per-tx processing."},
}}
}},
{RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
@ -1082,10 +1082,15 @@ static RPCHelpMan submitpackage()
for (const auto& tx : txns) {
UniValue result_inner{UniValue::VOBJ};
result_inner.pushKV("txid", tx->GetHash().GetHex());
const auto wtxid_hex = tx->GetWitnessHash().GetHex();
auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
if (it == package_result.m_tx_results.end()) {
// No results, report error and continue
result_inner.pushKV("error", "unevaluated");
// No per-tx result for this wtxid
// Current invariant: per-tx results are all-or-none (every member or empty on package abort).
// If any exist yet this one is missing, it's an unexpected partial map.
CHECK_NONFATAL(package_result.m_tx_results.empty());
result_inner.pushKV("error", "package-not-validated");
tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
continue;
}
const auto& tx_result = it->second;
@ -1118,7 +1123,7 @@ static RPCHelpMan submitpackage()
}
break;
}
tx_result_map.pushKV(tx->GetWitnessHash().GetHex(), std::move(result_inner));
tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
}
rpc_result.pushKV("tx-results", std::move(tx_result_map));
UniValue replaced_list(UniValue::VARR);

View File

@ -130,7 +130,7 @@ static RPCHelpMan getpeerinfo()
{
{
{RPCResult::Type::NUM, "id", "Peer index"},
{RPCResult::Type::STR, "addr", "(host:port) The IP address and port of the peer"},
{RPCResult::Type::STR, "addr", "(host:port) The IP address/hostname optionally followed by :port of the peer"},
{RPCResult::Type::STR, "addrbind", /*optional=*/true, "(ip:port) Bind address of the connection to the peer"},
{RPCResult::Type::STR, "addrlocal", /*optional=*/true, "(ip:port) Local address as reported by the peer"},
{RPCResult::Type::STR, "network", "Network (" + Join(GetNetworkNames(/*append_unroutable=*/true), ", ") + ")"},
@ -142,6 +142,8 @@ static RPCHelpMan getpeerinfo()
{RPCResult::Type::STR, "SERVICE_NAME", "the service name if it is recognised"}
}},
{RPCResult::Type::BOOL, "relaytxes", "Whether we relay transactions to this peer"},
{RPCResult::Type::NUM, "last_inv_sequence", "Mempool sequence number of this peer's last INV"},
{RPCResult::Type::NUM, "inv_to_send", "How many txs we have queued to announce to this peer"},
{RPCResult::Type::NUM_TIME, "lastsend", "The " + UNIX_EPOCH_TIME + " of the last send"},
{RPCResult::Type::NUM_TIME, "lastrecv", "The " + UNIX_EPOCH_TIME + " of the last receive"},
{RPCResult::Type::NUM_TIME, "last_transaction", "The " + UNIX_EPOCH_TIME + " of the last valid transaction received from this peer"},
@ -238,6 +240,8 @@ static RPCHelpMan getpeerinfo()
obj.pushKV("services", strprintf("%016x", services));
obj.pushKV("servicesnames", GetServicesNames(services));
obj.pushKV("relaytxes", statestats.m_relay_txs);
obj.pushKV("last_inv_sequence", statestats.m_last_inv_seq);
obj.pushKV("inv_to_send", statestats.m_inv_to_send);
obj.pushKV("lastsend", count_seconds(stats.m_last_send));
obj.pushKV("lastrecv", count_seconds(stats.m_last_recv));
obj.pushKV("last_transaction", count_seconds(stats.m_last_tx_time));
@ -318,7 +322,7 @@ static RPCHelpMan addnode()
strprintf("Addnode connections are limited to %u at a time", MAX_ADDNODE_CONNECTIONS) +
" and are counted separately from the -maxconnections limit.\n",
{
{"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The address of the peer to connect to"},
{"node", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address/hostname optionally followed by :port of the peer to connect to"},
{"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once"},
{"v2transport", RPCArg::Type::BOOL, RPCArg::DefaultHint{"set by -v2transport"}, "Attempt to connect using BIP324 v2 transport protocol (ignored for 'remove' command)"},
},
@ -1000,9 +1004,12 @@ static RPCHelpMan addpeeraddress()
UniValue obj(UniValue::VOBJ);
std::optional<CNetAddr> net_addr{LookupHost(addr_string, false)};
if (!net_addr.has_value()) {
throw JSONRPCError(RPC_CLIENT_INVALID_IP_OR_SUBNET, "Invalid IP address");
}
bool success{false};
if (net_addr.has_value()) {
CService service{net_addr.value(), port};
CAddress address{MaybeFlipIPv6toCJDNS(service), ServiceFlags{NODE_NETWORK | NODE_WITNESS}};
address.nTime = Now<NodeSeconds>();
@ -1020,7 +1027,6 @@ static RPCHelpMan addpeeraddress()
} else {
obj.pushKV("error", "failed-adding-to-new");
}
}
obj.pushKV("success", success);
return obj;

View File

@ -1608,7 +1608,7 @@ static RPCHelpMan finalizepsbt()
return RPCHelpMan{"finalizepsbt",
"Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n"
"network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n"
"created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n"
"created which has the final_scriptSig and final_scriptwitness fields filled for inputs that are complete.\n"
"Implements the Finalizer and Extractor roles.\n",
{
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"},

View File

@ -10,6 +10,7 @@
#include <crypto/sha256.h>
#include <pubkey.h>
#include <script/script.h>
#include <tinyformat.h>
#include <uint256.h>
typedef std::vector<unsigned char> valtype;
@ -197,7 +198,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
return true;
}
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror) {
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, script_verify_flags flags, ScriptError* serror) {
// Empty signature. Not strictly DER encoded, but allowed to provide a
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
if (vchSig.size() == 0) {
@ -214,7 +215,7 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
return true;
}
bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {
bool static CheckPubKeyEncoding(const valtype &vchPubKey, script_verify_flags flags, const SigVersion &sigversion, ScriptError* serror) {
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
}
@ -317,7 +318,7 @@ public:
};
}
static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPubKey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& fSuccess)
{
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0);
@ -343,7 +344,7 @@ static bool EvalChecksigPreTapscript(const valtype& vchSig, const valtype& vchPu
return true;
}
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, ScriptExecutionData& execdata, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
{
assert(sigversion == SigVersion::TAPSCRIPT);
@ -388,7 +389,7 @@ static bool EvalChecksigTapscript(const valtype& sig, const valtype& pubkey, Scr
* A return value of false means the script fails entirely. When true is returned, the
* success variable indicates whether the signature check itself succeeded.
*/
static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::const_iterator pbegincodehash, CScript::const_iterator pend, ScriptExecutionData& execdata, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror, bool& success)
{
switch (sigversion) {
case SigVersion::BASE:
@ -403,7 +404,7 @@ static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::con
assert(false);
}
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
{
static const CScriptNum bnZero(0);
static const CScriptNum bnOne(1);
@ -1233,7 +1234,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
return set_success(serror);
}
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)
{
ScriptExecutionData execdata;
return EvalScript(stack, script, flags, checker, sigversion, execdata, serror);
@ -1824,7 +1825,7 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
template class GenericTransactionSignatureChecker<CTransaction>;
template class GenericTransactionSignatureChecker<CMutableTransaction>;
static bool ExecuteWitnessScript(const std::span<const valtype>& stack_span, const CScript& exec_script, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
static bool ExecuteWitnessScript(const std::span<const valtype>& stack_span, const CScript& exec_script, script_verify_flags flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
{
std::vector<valtype> stack{stack_span.begin(), stack_span.end()};
@ -1909,7 +1910,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
return q.CheckTapTweak(p, merkle_root, control[0] & 1);
}
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const std::vector<unsigned char>& program, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror, bool is_p2sh)
{
CScript exec_script; //!< Actually executed script (last stack item in P2WSH; implied P2PKH script in P2WPKH; leaf script in P2TR)
std::span stack{witness.stack};
@ -1994,7 +1995,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
// There is intentionally no return statement here, to be able to use "control reaches end of non-void function" warnings to detect gaps in the logic above.
}
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
static const CScriptWitness emptyWitness;
if (witness == nullptr) {
@ -2131,7 +2132,7 @@ size_t static WitnessSigOps(int witversion, const std::vector<unsigned char>& wi
return 0;
}
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags)
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags)
{
static const CScriptWitness witnessEmpty;
@ -2161,3 +2162,48 @@ size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey,
return 0;
}
#define FLAG_NAME(flag) {std::string(#flag), SCRIPT_VERIFY_##flag}
const std::map<std::string, script_verify_flag_name> g_verify_flag_names{
FLAG_NAME(P2SH),
FLAG_NAME(STRICTENC),
FLAG_NAME(DERSIG),
FLAG_NAME(LOW_S),
FLAG_NAME(SIGPUSHONLY),
FLAG_NAME(MINIMALDATA),
FLAG_NAME(NULLDUMMY),
FLAG_NAME(DISCOURAGE_UPGRADABLE_NOPS),
FLAG_NAME(CLEANSTACK),
FLAG_NAME(MINIMALIF),
FLAG_NAME(NULLFAIL),
FLAG_NAME(CHECKLOCKTIMEVERIFY),
FLAG_NAME(CHECKSEQUENCEVERIFY),
FLAG_NAME(WITNESS),
FLAG_NAME(DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM),
FLAG_NAME(WITNESS_PUBKEYTYPE),
FLAG_NAME(CONST_SCRIPTCODE),
FLAG_NAME(TAPROOT),
FLAG_NAME(DISCOURAGE_UPGRADABLE_PUBKEYTYPE),
FLAG_NAME(DISCOURAGE_OP_SUCCESS),
FLAG_NAME(DISCOURAGE_UPGRADABLE_TAPROOT_VERSION),
};
#undef FLAG_NAME
std::vector<std::string> GetScriptFlagNames(script_verify_flags flags)
{
std::vector<std::string> res;
if (flags == SCRIPT_VERIFY_NONE) {
return res;
}
script_verify_flags leftover = flags;
for (const auto& [name, flag] : g_verify_flag_names) {
if ((flags & flag) != 0) {
res.push_back(name);
leftover &= ~flag;
}
}
if (leftover != 0) {
res.push_back(strprintf("0x%08x", leftover.as_int()));
}
return res;
}

View File

@ -10,6 +10,7 @@
#include <hash.h>
#include <primitives/transaction.h>
#include <script/script_error.h> // IWYU pragma: export
#include <script/verify_flags.h> // IWYU pragma: export
#include <span.h>
#include <uint256.h>
@ -42,35 +43,36 @@ enum
* All flags are intended to be soft forks: the set of acceptable scripts under
* flags (A | B) is a subset of the acceptable scripts under flag (A).
*/
enum : uint32_t {
SCRIPT_VERIFY_NONE = 0,
static constexpr script_verify_flags SCRIPT_VERIFY_NONE{0};
enum class script_verify_flag_name : uint8_t {
// Evaluate P2SH subscripts (BIP16).
SCRIPT_VERIFY_P2SH = (1U << 0),
SCRIPT_VERIFY_P2SH,
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
// Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure.
// (not used or intended as a consensus rule).
SCRIPT_VERIFY_STRICTENC = (1U << 1),
SCRIPT_VERIFY_STRICTENC,
// Passing a non-strict-DER signature to a checksig operation causes script failure (BIP62 rule 1)
SCRIPT_VERIFY_DERSIG = (1U << 2),
SCRIPT_VERIFY_DERSIG,
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
// (BIP62 rule 5).
SCRIPT_VERIFY_LOW_S = (1U << 3),
SCRIPT_VERIFY_LOW_S,
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (BIP62 rule 7).
SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
SCRIPT_VERIFY_NULLDUMMY,
// Using a non-push operator in the scriptSig causes script failure (BIP62 rule 2).
SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
SCRIPT_VERIFY_SIGPUSHONLY,
// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
// any other push causes the script to fail (BIP62 rule 3).
// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
SCRIPT_VERIFY_MINIMALDATA = (1U << 6),
SCRIPT_VERIFY_MINIMALDATA,
// Discourage use of NOPs reserved for upgrades (NOP1-10)
//
@ -82,7 +84,7 @@ enum : uint32_t {
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
// NOPs that have associated forks to give them new meaning (CLTV, CSV)
// are not subject to this rule.
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
// Require that only a single stack element remains after evaluation. This changes the success criterion from
// "At least one stack element must remain, and when interpreted as a boolean, it must be true" to
@ -91,64 +93,72 @@ enum : uint32_t {
// Note: CLEANSTACK should never be used without P2SH or WITNESS.
// Note: WITNESS_V0 and TAPSCRIPT script execution have behavior similar to CLEANSTACK as part of their
// consensus rules. It is automatic there and does not need this flag.
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
SCRIPT_VERIFY_CLEANSTACK,
// Verify CHECKLOCKTIMEVERIFY
//
// See BIP65 for details.
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
// support CHECKSEQUENCEVERIFY opcode
//
// See BIP112 for details
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10),
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
// Support segregated witness
//
SCRIPT_VERIFY_WITNESS = (1U << 11),
SCRIPT_VERIFY_WITNESS,
// Making v1-v16 witness program non-standard
//
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1U << 12),
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,
// Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
//
// Note: TAPSCRIPT script execution has behavior similar to MINIMALIF as part of its consensus
// rules. It is automatic there and does not depend on this flag.
SCRIPT_VERIFY_MINIMALIF = (1U << 13),
SCRIPT_VERIFY_MINIMALIF,
// Signature(s) must be empty vector if a CHECK(MULTI)SIG operation failed
//
SCRIPT_VERIFY_NULLFAIL = (1U << 14),
SCRIPT_VERIFY_NULLFAIL,
// Public keys in segregated witness scripts must be compressed
//
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE,
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
//
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
SCRIPT_VERIFY_CONST_SCRIPTCODE,
// Taproot/Tapscript validation (BIPs 341 & 342)
//
SCRIPT_VERIFY_TAPROOT = (1U << 17),
SCRIPT_VERIFY_TAPROOT,
// Making unknown Taproot leaf versions non-standard
//
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION = (1U << 18),
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION,
// Making unknown OP_SUCCESS non-standard
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS = (1U << 19),
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS,
// Making unknown public key versions (in BIP 342 scripts) non-standard
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE,
// Constants to point to the highest flag in use. Add new flags above this line.
//
SCRIPT_VERIFY_END_MARKER
};
using enum script_verify_flag_name;
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
static constexpr int MAX_SCRIPT_VERIFY_FLAGS_BITS = static_cast<int>(SCRIPT_VERIFY_END_MARKER);
// assert there is still a spare bit
static_assert(0 < MAX_SCRIPT_VERIFY_FLAGS_BITS && MAX_SCRIPT_VERIFY_FLAGS_BITS <= 63);
static constexpr script_verify_flags::value_type MAX_SCRIPT_VERIFY_FLAGS = ((script_verify_flags::value_type{1} << MAX_SCRIPT_VERIFY_FLAGS_BITS) - 1);
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, script_verify_flags flags, ScriptError* serror);
struct PrecomputedTransactionData
{
@ -363,12 +373,16 @@ uint256 ComputeTapbranchHash(std::span<const unsigned char> a, std::span<const u
* Requires control block to have valid length (33 + k*32, with k in {0,1,..,128}). */
uint256 ComputeTaprootMerkleRoot(std::span<const unsigned char> control, const uint256& tapleaf_hash);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* error = nullptr);
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* error = nullptr);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags, const BaseSignatureChecker& checker, ScriptError* serror = nullptr);
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, unsigned int flags);
size_t CountWitnessSigOps(const CScript& scriptSig, const CScript& scriptPubKey, const CScriptWitness* witness, script_verify_flags flags);
int FindAndDelete(CScript& script, const CScript& b);
extern const std::map<std::string, script_verify_flag_name> g_verify_flag_names;
std::vector<std::string> GetScriptFlagNames(script_verify_flags flags);
#endif // BITCOIN_SCRIPT_INTERPRETER_H

71
src/script/verify_flags.h Normal file
View File

@ -0,0 +1,71 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-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.
#ifndef BITCOIN_SCRIPT_VERIFY_FLAGS_H
#define BITCOIN_SCRIPT_VERIFY_FLAGS_H
#include <compare>
#include <cstdint>
enum class script_verify_flag_name : uint8_t;
class script_verify_flags
{
public:
using value_type = uint64_t;
consteval script_verify_flags() = default;
// also allow construction with hard-coded 0 (but not other integers)
consteval explicit(false) script_verify_flags(value_type f) : m_value{f} { if (f != 0) throw 0; }
// implicit construction from a hard-coded SCRIPT_VERIFY_* constant is also okay
constexpr explicit(false) script_verify_flags(script_verify_flag_name f) : m_value{value_type{1} << static_cast<uint8_t>(f)} { }
// rule of 5
constexpr script_verify_flags(const script_verify_flags&) = default;
constexpr script_verify_flags(script_verify_flags&&) = default;
constexpr script_verify_flags& operator=(const script_verify_flags&) = default;
constexpr script_verify_flags& operator=(script_verify_flags&&) = default;
constexpr ~script_verify_flags() = default;
// integer conversion needs to be very explicit
static constexpr script_verify_flags from_int(value_type f) { script_verify_flags r; r.m_value = f; return r; }
constexpr value_type as_int() const { return m_value; }
// bitwise operations
constexpr script_verify_flags operator~() const { return from_int(~m_value); }
friend constexpr script_verify_flags operator|(script_verify_flags a, script_verify_flags b) { return from_int(a.m_value | b.m_value); }
friend constexpr script_verify_flags operator&(script_verify_flags a, script_verify_flags b) { return from_int(a.m_value & b.m_value); }
// in-place bitwise operations
constexpr script_verify_flags& operator|=(script_verify_flags vf) { m_value |= vf.m_value; return *this; }
constexpr script_verify_flags& operator&=(script_verify_flags vf) { m_value &= vf.m_value; return *this; }
// tests
constexpr explicit operator bool() const { return m_value != 0; }
constexpr bool operator==(script_verify_flags other) const { return m_value == other.m_value; }
/** Compare two script_verify_flags. <, >, <=, and >= are auto-generated from this. */
friend constexpr std::strong_ordering operator<=>(const script_verify_flags& a, const script_verify_flags& b) noexcept
{
return a.m_value <=> b.m_value;
}
private:
value_type m_value{0}; // default value is SCRIPT_VERIFY_NONE
};
inline constexpr script_verify_flags operator~(script_verify_flag_name f)
{
return ~script_verify_flags{f};
}
inline constexpr script_verify_flags operator|(script_verify_flag_name f1, script_verify_flag_name f2)
{
return script_verify_flags{f1} | f2;
}
#endif // BITCOIN_SCRIPT_VERIFY_FLAGS_H

View File

@ -26,7 +26,7 @@
static constexpr uint8_t SIGNET_HEADER[4] = {0xec, 0xc7, 0xda, 0xa2};
static constexpr unsigned int BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
static constexpr script_verify_flags BLOCK_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_NULLDUMMY;
static bool FetchAndClearCommitmentSection(const std::span<const uint8_t> header, CScript& witness_commitment, std::vector<uint8_t>& result)
{

View File

@ -25,6 +25,8 @@ add_executable(test_bitcoin
blockmanager_tests.cpp
bloom_tests.cpp
bswap_tests.cpp
caches_tests.cpp
chain_tests.cpp
chainstate_write_tests.cpp
checkqueue_tests.cpp
cluster_linearize_tests.cpp
@ -101,6 +103,7 @@ add_executable(test_bitcoin
span_tests.cpp
streams_tests.cpp
sync_tests.cpp
system_ram_tests.cpp
system_tests.cpp
testnet4_miner_tests.cpp
timeoffsets_tests.cpp
@ -196,7 +199,10 @@ function(add_boost_test source_file)
COMMAND test_bitcoin --run_test=${test_suite_name} --catch_system_error=no --log_level=test_suite -- DEBUG_LOG_OUT
)
set_property(TEST ${test_suite_name} PROPERTY
SKIP_REGULAR_EXPRESSION "no test cases matching filter" "skipping script_assets_test"
SKIP_REGULAR_EXPRESSION
"no test cases matching filter"
"skipping script_assets_test"
"skipping total_ram"
)
endforeach()
endfunction()

View File

@ -459,10 +459,16 @@ BOOST_AUTO_TEST_CASE(getaddr_unfiltered)
addrman->Attempt(addr3, /*fCountFailure=*/true, /*time=*/Now<NodeSeconds>() - 61s);
}
// Set time more than 10 minutes in the future (flying DeLorean), so this
// addr should be isTerrible = true
CAddress addr4 = CAddress(ResolveService("250.252.2.4", 9997), NODE_NONE);
addr4.nTime = Now<NodeSeconds>() + 11min;
BOOST_CHECK(addrman->Add({addr4}, source));
// GetAddr filtered by quality (i.e. not IsTerrible) should only return addr1
BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt).size(), 1U);
// Unfiltered GetAddr should return all addrs
BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false).size(), 3U);
BOOST_CHECK_EQUAL(addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt, /*filtered=*/false).size(), 4U);
}
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)

40
src/test/caches_tests.cpp Normal file
View File

@ -0,0 +1,40 @@
#include <node/caches.h>
#include <util/byte_units.h>
#include <boost/test/unit_test.hpp>
using namespace node;
BOOST_AUTO_TEST_SUITE(caches_tests)
BOOST_AUTO_TEST_CASE(oversized_dbcache_warning)
{
// memory restricted setup - cap is DEFAULT_DB_CACHE (450 MiB)
BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/4_MiB, /*total_ram=*/1024_MiB)); // Under cap
BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/512_MiB, /*total_ram=*/1024_MiB)); // At cap
BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/1500_MiB, /*total_ram=*/1024_MiB)); // Over cap
// 2 GiB RAM - cap is 75%
BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/1500_MiB, /*total_ram=*/2048_MiB)); // Under cap
BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/1600_MiB, /*total_ram=*/2048_MiB)); // Over cap
if constexpr (SIZE_MAX == UINT64_MAX) {
// 4 GiB RAM - cap is 75%
BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/2500_MiB, /*total_ram=*/4096_MiB)); // Under cap
BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/3500_MiB, /*total_ram=*/4096_MiB)); // Over cap
// 8 GiB RAM - cap is 75%
BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/6000_MiB, /*total_ram=*/8192_MiB)); // Under cap
BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/7000_MiB, /*total_ram=*/8192_MiB)); // Over cap
// 16 GiB RAM - cap is 75%
BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/10'000_MiB, /*total_ram=*/16384_MiB)); // Under cap
BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/15'000_MiB, /*total_ram=*/16384_MiB)); // Over cap
// 32 GiB RAM - cap is 75%
BOOST_CHECK(!ShouldWarnOversizedDbCache(/*dbcache=*/20'000_MiB, /*total_ram=*/32768_MiB)); // Under cap
BOOST_CHECK( ShouldWarnOversizedDbCache(/*dbcache=*/30'000_MiB, /*total_ram=*/32768_MiB)); // Over cap
}
}
BOOST_AUTO_TEST_SUITE_END()

85
src/test/chain_tests.cpp Normal file
View File

@ -0,0 +1,85 @@
// Copyright (c) The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <boost/test/unit_test.hpp>
#include <chain.h>
#include <test/util/setup_common.h>
#include <memory>
BOOST_FIXTURE_TEST_SUITE(chain_tests, BasicTestingSetup)
namespace {
const CBlockIndex* NaiveGetAncestor(const CBlockIndex* a, int height)
{
while (a->nHeight > height) {
a = a->pprev;
}
BOOST_REQUIRE_EQUAL(a->nHeight, height);
return a;
}
const CBlockIndex* NaiveLastCommonAncestor(const CBlockIndex* a, const CBlockIndex* b)
{
while (a->nHeight > b->nHeight) {
a = a->pprev;
}
while (b->nHeight > a->nHeight) {
b = b->pprev;
}
while (a != b) {
BOOST_REQUIRE_EQUAL(a->nHeight, b->nHeight);
a = a->pprev;
b = b->pprev;
}
BOOST_REQUIRE_EQUAL(a, b);
return a;
}
} // namespace
BOOST_AUTO_TEST_CASE(chain_test)
{
FastRandomContext ctx;
std::vector<std::unique_ptr<CBlockIndex>> block_index;
// Run 10 iterations of the whole test.
for (int i = 0; i < 10; ++i) {
block_index.clear();
// Create genesis block.
auto genesis = std::make_unique<CBlockIndex>();
genesis->nHeight = 0;
block_index.push_back(std::move(genesis));
// Create 10000 more blocks.
for (int b = 0; b < 10000; ++b) {
auto new_index = std::make_unique<CBlockIndex>();
// 95% of blocks build on top of the last block; the others fork off randomly.
if (ctx.randrange(20) != 0) {
new_index->pprev = block_index.back().get();
} else {
new_index->pprev = block_index[ctx.randrange(block_index.size())].get();
}
new_index->nHeight = new_index->pprev->nHeight + 1;
new_index->BuildSkip();
block_index.push_back(std::move(new_index));
}
// Run 10000 random GetAncestor queries.
for (int q = 0; q < 10000; ++q) {
const CBlockIndex* block = block_index[ctx.randrange(block_index.size())].get();
unsigned height = ctx.randrange<unsigned>(block->nHeight + 1);
const CBlockIndex* result = block->GetAncestor(height);
BOOST_CHECK(result == NaiveGetAncestor(block, height));
}
// Run 10000 random LastCommonAncestor queries.
for (int q = 0; q < 10000; ++q) {
const CBlockIndex* block1 = block_index[ctx.randrange(block_index.size())].get();
const CBlockIndex* block2 = block_index[ctx.randrange(block_index.size())].get();
const CBlockIndex* result = LastCommonAncestor(block1, block2);
BOOST_CHECK(result == NaiveLastCommonAncestor(block1, block2));
}
}
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -62,7 +62,8 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
CAddress(),
/*addrNameIn=*/"",
ConnectionType::OUTBOUND_FULL_RELAY,
/*inbound_onion=*/false};
/*inbound_onion=*/false,
/*network_key=*/0};
connman.Handshake(
/*node=*/dummyNode1,
@ -128,7 +129,8 @@ void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager&
CAddress(),
/*addrNameIn=*/"",
connType,
/*inbound_onion=*/false});
/*inbound_onion=*/false,
/*network_key=*/0});
CNode &node = *vNodes.back();
node.SetCommonVersion(PROTOCOL_VERSION);
@ -327,7 +329,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
CAddress(),
/*addrNameIn=*/"",
ConnectionType::INBOUND,
/*inbound_onion=*/false};
/*inbound_onion=*/false,
/*network_key=*/1};
nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
nodes[0]->fSuccessfullyConnected = true;
@ -347,7 +350,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
CAddress(),
/*addrNameIn=*/"",
ConnectionType::INBOUND,
/*inbound_onion=*/false};
/*inbound_onion=*/false,
/*network_key=*/1};
nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
nodes[1]->fSuccessfullyConnected = true;
@ -377,7 +381,8 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
CAddress(),
/*addrNameIn=*/"",
ConnectionType::OUTBOUND_FULL_RELAY,
/*inbound_onion=*/false};
/*inbound_onion=*/false,
/*network_key=*/2};
nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
nodes[2]->fSuccessfullyConnected = true;
@ -419,7 +424,8 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
CAddress(),
/*addrNameIn=*/"",
ConnectionType::INBOUND,
/*inbound_onion=*/false};
/*inbound_onion=*/false,
/*network_key=*/1};
dummyNode.SetCommonVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
dummyNode.fSuccessfullyConnected = true;

View File

@ -288,7 +288,7 @@ void TestCoinsView(FuzzedDataProvider& fuzzed_data_provider, CCoinsView& backend
// consensus/tx_verify.cpp:130: unsigned int GetP2SHSigOpCount(const CTransaction &, const CCoinsViewCache &): Assertion `!coin.IsSpent()' failed.
return;
}
const auto flags{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
if (!transaction.vin.empty() && (flags & SCRIPT_VERIFY_WITNESS) != 0 && (flags & SCRIPT_VERIFY_P2SH) == 0) {
// Avoid:
// script/interpreter.cpp:1705: size_t CountWitnessSigOps(const CScript &, const CScript &, const CScriptWitness *, unsigned int): Assertion `(flags & SCRIPT_VERIFY_P2SH) != 0' failed.

View File

@ -6,12 +6,14 @@
#include <chainparams.h>
#include <common/args.h>
#include <net.h>
#include <net_processing.h>
#include <netaddress.h>
#include <protocol.h>
#include <test/fuzz/FuzzedDataProvider.h>
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/fuzz/util/net.h>
#include <test/fuzz/util/threadinterrupt.h>
#include <test/util/setup_common.h>
#include <util/translation.h>
@ -51,19 +53,36 @@ FUZZ_TARGET(connman, .init = initialize_connman)
}
}
AddrManDeterministic& addr_man{*addr_man_ptr};
auto net_events{ConsumeNetEvents(fuzzed_data_provider)};
// Mock CreateSock() to create FuzzedSock.
auto CreateSockOrig = CreateSock;
CreateSock = [&fuzzed_data_provider](int, int, int) {
return std::make_unique<FuzzedSock>(fuzzed_data_provider);
};
// Mock g_dns_lookup() to return a fuzzed address.
auto g_dns_lookup_orig = g_dns_lookup;
g_dns_lookup = [&fuzzed_data_provider](const std::string&, bool) {
return std::vector<CNetAddr>{ConsumeNetAddr(fuzzed_data_provider)};
};
ConnmanTestMsg connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
fuzzed_data_provider.ConsumeIntegral<uint64_t>(),
addr_man,
netgroupman,
Params(),
fuzzed_data_provider.ConsumeBool()};
fuzzed_data_provider.ConsumeBool(),
ConsumeThreadInterrupt(fuzzed_data_provider)};
const uint64_t max_outbound_limit{fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
CConnman::Options options;
options.m_msgproc = &net_events;
options.nMaxOutboundLimit = max_outbound_limit;
connman.Init(options);
CNetAddr random_netaddr;
CAddress random_address;
CNode random_node = ConsumeNode(fuzzed_data_provider);
CSubNet random_subnet;
std::string random_string;
@ -79,6 +98,9 @@ FUZZ_TARGET(connman, .init = initialize_connman)
[&] {
random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
},
[&] {
random_address = ConsumeAddress(fuzzed_data_provider);
},
[&] {
random_subnet = ConsumeSubNet(fuzzed_data_provider);
},
@ -143,6 +165,52 @@ FUZZ_TARGET(connman, .init = initialize_connman)
},
[&] {
connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool());
},
[&] {
ConnectionType conn_type{
fuzzed_data_provider.PickValueInArray(ALL_CONNECTION_TYPES)};
if (conn_type == ConnectionType::INBOUND) { // INBOUND is not allowed
conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
}
connman.OpenNetworkConnection(
/*addrConnect=*/random_address,
/*fCountFailure=*/fuzzed_data_provider.ConsumeBool(),
/*grant_outbound=*/{},
/*pszDest=*/fuzzed_data_provider.ConsumeBool() ? nullptr : random_string.c_str(),
/*conn_type=*/conn_type,
/*use_v2transport=*/fuzzed_data_provider.ConsumeBool());
},
[&] {
connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool());
const auto peer = ConsumeAddress(fuzzed_data_provider);
connman.CreateNodeFromAcceptedSocketPublic(
/*sock=*/CreateSock(AF_INET, SOCK_STREAM, IPPROTO_TCP),
/*permissions=*/ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS),
/*addr_bind=*/ConsumeAddress(fuzzed_data_provider),
/*addr_peer=*/peer);
},
[&] {
CConnman::Options options;
options.vBinds = ConsumeServiceVector(fuzzed_data_provider);
options.vWhiteBinds = std::vector<NetWhitebindPermissions>{
fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 5)};
for (auto& wb : options.vWhiteBinds) {
wb.m_flags = ConsumeWeakEnum(fuzzed_data_provider, ALL_NET_PERMISSION_FLAGS);
wb.m_service = ConsumeService(fuzzed_data_provider);
}
options.onion_binds = ConsumeServiceVector(fuzzed_data_provider);
options.bind_on_any = options.vBinds.empty() && options.vWhiteBinds.empty() &&
options.onion_binds.empty();
connman.InitBindsPublic(options);
},
[&] {
connman.SocketHandlerPublic();
});
}
(void)connman.GetAddedNodeInfo(fuzzed_data_provider.ConsumeBool());
@ -162,4 +230,6 @@ FUZZ_TARGET(connman, .init = initialize_connman)
(void)connman.ASMapHealthCheck();
connman.ClearTestNodes();
g_dns_lookup = g_dns_lookup_orig;
CreateSock = CreateSockOrig;
}

View File

@ -12,7 +12,7 @@
FUZZ_TARGET(eval_script)
{
FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
const unsigned int flags = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
const auto flags = script_verify_flags::from_int(fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>());
const std::vector<uint8_t> script_bytes = [&] {
if (fuzzed_data_provider.remaining_bytes() != 0) {
return fuzzed_data_provider.ConsumeRemainingBytes<uint8_t>();

View File

@ -75,7 +75,7 @@ auto& FuzzTargets()
void FuzzFrameworkRegisterTarget(std::string_view name, TypeTestOneInput target, FuzzTargetOptions opts)
{
const auto [it, ins]{FuzzTargets().try_emplace(name, FuzzTarget /* temporary can be dropped after Apple-Clang-16 ? */ {std::move(target), std::move(opts)})};
const auto [it, ins]{FuzzTargets().try_emplace(name, std::move(target), std::move(opts))};
Assert(ins);
}

View File

@ -10,6 +10,7 @@
#include <test/fuzz/fuzz.h>
#include <test/fuzz/util.h>
#include <test/fuzz/util/net.h>
#include <test/fuzz/util/threadinterrupt.h>
#include <test/util/setup_common.h>
#include <util/fs_helpers.h>
#include <util/threadinterrupt.h>
@ -35,15 +36,15 @@ FUZZ_TARGET(i2p, .init = initialize_i2p)
const fs::path private_key_path = gArgs.GetDataDirNet() / "fuzzed_i2p_private_key";
const CService addr{in6_addr(IN6ADDR_LOOPBACK_INIT), 7656};
const Proxy sam_proxy{addr, /*tor_stream_isolation=*/false};
CThreadInterrupt interrupt;
auto interrupt{ConsumeThreadInterrupt(fuzzed_data_provider)};
i2p::sam::Session session{private_key_path, sam_proxy, &interrupt};
i2p::sam::Session session{private_key_path, sam_proxy, interrupt};
i2p::Connection conn;
if (session.Listen(conn)) {
if (session.Accept(conn)) {
try {
(void)conn.sock->RecvUntilTerminator('\n', 10ms, interrupt, i2p::sam::MAX_MSG_SIZE);
(void)conn.sock->RecvUntilTerminator('\n', 10ms, *interrupt, i2p::sam::MAX_MSG_SIZE);
} catch (const std::runtime_error&) {
}
}
@ -53,7 +54,7 @@ FUZZ_TARGET(i2p, .init = initialize_i2p)
if (session.Connect(CService{}, conn, proxy_error)) {
try {
conn.sock->SendComplete("verack\n", 10ms, interrupt);
conn.sock->SendComplete("verack\n", 10ms, *interrupt);
} catch (const std::runtime_error&) {
}
}

View File

@ -50,7 +50,7 @@ FUZZ_TARGET(mini_miner, .init = initialize_miner)
std::deque<COutPoint> available_coins = g_available_coins;
LOCK2(::cs_main, pool.cs);
// Cluster size cannot exceed 500
LIMITED_WHILE(!available_coins.empty(), 500)
LIMITED_WHILE(!available_coins.empty(), 100)
{
CMutableTransaction mtx = CMutableTransaction();
const size_t num_inputs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, available_coins.size());

View File

@ -70,7 +70,7 @@ void HeadersSyncSetup::ResetAndInitialize()
for (auto conn_type : conn_types) {
CAddress addr{};
m_connections.push_back(new CNode(id++, nullptr, addr, 0, 0, addr, "", conn_type, false));
m_connections.push_back(new CNode(id++, nullptr, addr, 0, 0, addr, "", conn_type, false, 0));
CNode& p2p_node = *m_connections.back();
connman.Handshake(

View File

@ -325,7 +325,7 @@ FUZZ_TARGET(ephemeral_package_eval, .init = initialize_tx_pool)
return ProcessNewPackage(chainstate, tx_pool, txs, /*test_accept=*/single_submit, /*client_maxfeerate=*/{}));
const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, txs.back(), GetTime(),
/*bypass_limits=*/fuzzed_data_provider.ConsumeBool(), /*test_accept=*/!single_submit));
/*bypass_limits=*/false, /*test_accept=*/!single_submit));
if (!single_submit && result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) {
// We don't know anything about the validity since transactions were randomly generated, so

View File

@ -118,8 +118,8 @@ FUZZ_TARGET(script, .init = initialize_script)
(void)FindAndDelete(script_mut, *other_script);
}
const std::vector<std::string> random_string_vector = ConsumeRandomLengthStringVector(fuzzed_data_provider);
const uint32_t u32{fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
const uint32_t flags{u32 | SCRIPT_VERIFY_P2SH};
const auto flags_rand{fuzzed_data_provider.ConsumeIntegral<script_verify_flags::value_type>()};
const auto flags = script_verify_flags::from_int(flags_rand) | SCRIPT_VERIFY_P2SH;
{
CScriptWitness wit;
for (const auto& s : random_string_vector) {

Some files were not shown because too many files have changed in this diff Show More