14 Commits

Author SHA1 Message Date
Ryan Ofsky
d8fe5f0326 test: improve interface_ipc.py waitNext tests
As pointed out by Sjors in
https://github.com/bitcoin/bitcoin/pull/34003#discussion_r2598844209 and
https://github.com/bitcoin/bitcoin/pull/34003#discussion_r2598858386 the
original intention of having waitNext and waitTipChanged calls in the test was
to ensure that if new blocks were connected or fees were increased *during* the
waits, that the calls would wake up and return.

But the tests were written incorrectly, to generate blocks and transactions
before the wait calls instead of during the calls. So the tests were less
meaningful then they should be.

There was also a similar problem in the interruptWait test. The test was
intended to test the interruptWait method, but it was never actually calling
the method due to a missing await keyword. Instead it was testing that
miniwallet.send_self_transfer would interrupt the wait.

This commit fixes these issues by introducing a wait_and_do() helper function
to start parallel tasks and trigger an action after a wait call is started.

Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
2025-12-08 22:22:43 -05:00
Ryan Ofsky
a5e61b1917 test: interface_ipc.py minor fixes and cleanup
There are a few things that are incorrect or messy in the interface_ipc.py test.
This commit tries to clean them up:

- isTestChain and isInitialBlockDownload asserts were not checking the results
  of those calls, only that calls were, made because they were not checking the
  responses' .result member.

- A lot of result accesses like `template.result` `mining.result` were repeated
  unnecessarily because variables like `template` and `mining` were assigned
  response objects instead of result objects. These variables are now changed
  to point directly to results.

- Some coroutine calls were assigned to temporary `wait` before being awaited.
  This was unnecessarily confusing and would make code not run in top-down
  order.

- `to_dict` calls were being made to check if result variables were unset. This
  was inefficient and indirect because it iterates over all fields in response
  structs instead of just checking whether the result field is present. The
  to_dict calls are now replaced with more direct `_has('result')` calls.

- The `res` variables used to hold various responses did not have descriptive
  names. These are replaced with clearer names.

Co-authored-by: rkrux <rkrux.connect@gmail.com>
2025-12-08 21:23:40 -05:00
Ryan Ofsky
ded11fb04d test: fix interface_ipc.py template destruction
Use context managers to destroy block templates. Previously, block templates
were not being destroyed before disconnecting because the destroy coroutines
were called but never awaited. It's not necessary to explicitly destroy the
templates since they will get garbage collected asynchronously, but it's good
to destroy them to make the test more predictable, and to make the destroy
calls that are present actually do something.

This change also removes `await waitnext` expressions without changing
behavior, because the previous code was misleading about what order waitNext
calls were executed.

This change is easiest to review ignoring whitespace.

Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
2025-12-03 16:04:10 -05:00
Fabian Jahr
2578e6fc0f test: Fix race condition in IPC interface block propagation test 2025-11-19 23:20:24 +01:00
merge-script
3c3c6adb72 Merge bitcoin/bitcoin#33745: mining: check witness commitment in submitBlock
6eaa00fe20 test: clarify submitBlock() mutates the template (Sjors Provoost)
862bd43283 mining: ensure witness commitment check in submitBlock (Sjors Provoost)
00d1b6ef4b doc: clarify UpdateUncommittedBlockStructures (Sjors Provoost)

Pull request description:

  When an IPC client requests a new block template via the Mining interface, we hold on to its `CBlock`. That way when they call `submitSolution()` we can modify it in place, rather than having to reconstruct the full block like the `submitblock` RPC does.

  Before this commit however we forgot to invalidate `m_checked_witness_commitment`, which we should since the client brings a new coinbase.

  This would cause us to accept an invalid chaintip.

  Fix this and add a test to confirm that we now reject such a block. As a sanity check, we add a second node to the test and confirm that will accept our mined block.

  As first noticed in #33374 the IPC code takes the coinbase as provided, unlike the `submitblock` RPC which calls `UpdateUncommittedBlockStructures()` and adds witness commitment to the coinbase if it was missing.

  Although that could have been an alternative fix, we instead document that IPC clients are expected to provide the full coinbase including witness commitment.

  Patch to produce the original issue:

  ```diff
  diff --git a/src/node/miner.cpp b/src/node/miner.cpp
  index b988e28a3f..28e9048a4d 100644
  --- a/src/node/miner.cpp
  +++ b/src/node/miner.cpp
  @@ -450,15 +450,10 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t
       }
       block.nVersion = version;
       block.nTime = timestamp;
       block.nNonce = nonce;
       block.hashMerkleRoot = BlockMerkleRoot(block);
  -
  -    // Reset cached checks
  -    block.m_checked_witness_commitment = false;
  -    block.m_checked_merkle_root = false;
  -    block.fChecked = false;
   }

   std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,
                                                         KernelNotifications& kernel_notifications,
                                                         CTxMemPool* mempool,
  diff --git a/test/functional/interface_ipc.py b/test/functional/interface_ipc.py
  index cce56e3294..bf1b7048ab 100755
  --- a/test/functional/interface_ipc.py
  +++ b/test/functional/interface_ipc.py
  @@ -216,22 +216,22 @@ class IPCInterfaceTest(BitcoinTestFramework):
               assert_equal(res.result, True)

               # The remote template block will be mutated, capture the original:
               remote_block_before = await self.parse_and_deserialize_block(template, ctx)

  -            self.log.debug("Submitted coinbase must include witness")
  +            self.log.debug("Submitted coinbase with missing witness is accepted")
               assert_not_equal(coinbase.serialize_without_witness().hex(), coinbase.serialize().hex())
               res = await template.result.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize_without_witness())
  -            assert_equal(res.result, False)
  +            assert_equal(res.result, True)

               self.log.debug("Even a rejected submitBlock() mutates the template's block")
               # Can be used by clients to download and inspect the (rejected)
               # reconstructed block.
               remote_block_after = await self.parse_and_deserialize_block(template, ctx)
               assert_not_equal(remote_block_before.serialize().hex(), remote_block_after.serialize().hex())

  -            self.log.debug("Submit again, with the witness")
  +            self.log.debug("Submit again, with the witness - does not replace the invalid block")
               res = await template.result.submitSolution(ctx, block.nVersion, block.nTime, block.nNonce, coinbase.serialize())
               assert_equal(res.result, True)

               self.log.debug("Block should propagate")
               assert_equal(self.nodes[1].getchaintips()[0]["height"], current_block_height + 1)
  ```

ACKs for top commit:
  ryanofsky:
    Code review ACK 6eaa00fe20. Just documentation updates and test clarifications since last review, also splitting up a commit.
  TheCharlatan:
    Re-ACK 6eaa00fe20
  ismaelsadeeq:
    Code review and tested ACK   6eaa00fe20

Tree-SHA512: 3a6280345b0290fe8300ebc63c13ad4058d24ceb35b7d7a784b974d5f04f420860ac03a9bf2fc6a799ef3fc55552ce033e879fa369298f976b9a01d72bd55d9e
2025-11-12 10:03:48 -05:00
merge-script
ddd2afac10 Merge bitcoin/bitcoin#33676: interfaces: enable cancelling running waitNext calls
dcb56fd4cb interfaces: add interruptWait method (ismaelsadeeq)

Pull request description:

  This is an attempt to fix #33575 see the issue for background and the usefulness of this feature.

  This PR uses one of the suggested approaches: adding a new `interruptWaitNext()` method to the mining interface.

  It introduces a new boolean variable, `m_interrupt_wait`, which is set to `false` when the thread starts waiting. The `interruptWaitNext()` method wakes the thread and sets `m_interrupt_wait` to `true`.
  Whenever the thread wakes up, it checks whether the wait was aborted; if so, it simply set ` m_interrupt_wait ` to false and return`nullptr`.

  This PR also adds a functional test for the new method. The test uses `asyncio` to spawn two tasks and attempts to ensure that the wait is executed before the interrupt by using an event monitor. It adds a 0.1-second buffer to ensure the wait has started executing.
  If that buffer elapses without `waitNext` executing, the test will fail because a transaction is created after the buffer.

ACKs for top commit:
  furszy:
    Code ACK dcb56fd4cb
  ryanofsky:
    Code review ACK dcb56fd4cb, just tweaking semantics slightly since last review so if an `interruptWait` call is made shortly after a `waitNext` call it will reliably cause the `waitNext` call to return right away without blocking, even if the `waitNext` call had not begun to execute or wait yet.
  Sjors:
    tACK dcb56fd4cb
  TheCharlatan:
    ACK dcb56fd4cb

Tree-SHA512: a03f049e1f303b174a9e5d125733b6583dfd8effa12e7b6c37bd9b2cff9541100f5f4514e80f89005c44a57d7e47804afe87aa5fdb6831f3b0cd9b01d83e42be
2025-11-10 09:56:27 +00:00
Sjors Provoost
6eaa00fe20 test: clarify submitBlock() mutates the template
PR #33374 proposed a new Mining IPC method applySolution() which
could be used by clients to obtain the reconstructed block for
inspection, especially in the case of a rejected block.

However it was pointed out during review that submitBlock() modified
the template CBlock in place, so the client can just call getBlock()
and no new method is needed.

This commit adds a test to document that (now intentional) behavior.
2025-10-31 12:01:04 +01:00
Sjors Provoost
862bd43283 mining: ensure witness commitment check in submitBlock
When an IPC client requests a new block template via the Mining interface,
we hold on to its CBlock. That way when they call submitSolution() we can
modify it in place, rather than having to reconstruct the full block like
the submitblock RPC does.

Before this commit however we forgot to invalidate
m_checked_witness_commitment, which we should since the client brings a
new coinbase.

This would cause us to accept an invalid chaintip.

Fix this and add a test to confirm that we now reject such a block.
As a sanity check, we add a second node to the test and confirm that will
accept our mined block.

Note that the IPC code takes the coinbase as provided, unlike the
submitblock RPC which calls UpdateUncommittedBlockStructures() and adds
witness commitment to the coinbase if it was missing.

Although that could have been an alternative fix, we instead document that
IPC clients are expected to provide the full coinbase including witness
commitment.
2025-10-31 11:53:12 +01:00
David Gumberg
51093d6ae1 test: resolve symlinks in which result for capnp 2025-10-30 14:27:17 -07:00
ismaelsadeeq
dcb56fd4cb interfaces: add interruptWait method
- This method can be used to cancel a running
  waitNext().

- This commit also adds a test case for interruptWait method
2025-10-27 19:22:12 +01:00
Sjors Provoost
8f7673257a miner: fix empty mempool case for waitNext()
Block template fees are calculated by looping over new_tmpl->vTxFees
and return (early) once the fee_threshold is exceeded.

This left an edge case when the mempool is empty, which this commit
fixes and adds a test for. It does so by using std::accumulate instead
of manual loops.

Also update interface_ipc.py to account for the new behavior.

Co-authored-by: Raimo33 <claudio.raimondi@protonmail.com>
2025-10-13 18:39:18 +02: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
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
Pieter Wuille
8d2ee88fa2 tests: add functional tests for IPC interface
Co-Authored-By: ismaelsadeeq <ask4ismailsadiq@gmail.com>
Co-Authored-By: ryanofsky <ryan@ofsky.org>
Co-Authored-By: TheCharlatan <seb.kung@gmail.com>
Co-Authored-By: Sjors Provoost <sjors@sprovoost.nl>
2025-09-05 09:24:14 -04:00