diff --git a/test/functional/interface_usdt_coinselection.py b/test/functional/interface_usdt_coinselection.py
index 8148e651a2e7..737740a43bfd 100755
--- a/test/functional/interface_usdt_coinselection.py
+++ b/test/functional/interface_usdt_coinselection.py
@@ -163,7 +163,7 @@ def run_test(self):
         ctx.enable_probe(probe="coin_selection:normal_create_tx_internal", fn_name="trace_normal_create_tx")
         ctx.enable_probe(probe="coin_selection:attempting_aps_create_tx", fn_name="trace_attempt_aps")
         ctx.enable_probe(probe="coin_selection:aps_create_tx_internal", fn_name="trace_aps_create_tx")
-        self.bpf = BPF(text=coinselection_tracepoints_program, usdt_contexts=[ctx], debug=0)
+        self.bpf = BPF(text=coinselection_tracepoints_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
 
         self.log.info("Prepare wallets")
         self.generate(self.nodes[0], 101)
diff --git a/test/functional/interface_usdt_mempool.py b/test/functional/interface_usdt_mempool.py
new file mode 100644
index 000000000000..0168d9f916a4
--- /dev/null
+++ b/test/functional/interface_usdt_mempool.py
@@ -0,0 +1,325 @@
+#!/usr/bin/env python3
+# 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.
+
+"""  Tests the mempool:* tracepoint API interface.
+     See https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#context-mempool
+"""
+
+from decimal import Decimal
+
+# Test will be skipped if we don't have bcc installed
+try:
+    from bcc import BPF, USDT  # type: ignore[import]
+except ImportError:
+    pass
+
+from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.messages import COIN, DEFAULT_MEMPOOL_EXPIRY_HOURS
+from test_framework.p2p import P2PDataStore
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+from test_framework.wallet import MiniWallet
+
+MEMPOOL_TRACEPOINTS_PROGRAM = """
+# include <uapi/linux/ptrace.h>
+
+// The longest rejection reason is 118 chars and is generated in case of SCRIPT_ERR_EVAL_FALSE by
+// strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))
+#define MAX_REJECT_REASON_LENGTH        118
+// The longest string returned by RemovalReasonToString() is 'sizelimit'
+#define MAX_REMOVAL_REASON_LENGTH       9
+#define HASH_LENGTH                     32
+
+struct added_event
+{
+  u8    hash[HASH_LENGTH];
+  s32   vsize;
+  s64   fee;
+};
+
+struct removed_event
+{
+  u8    hash[HASH_LENGTH];
+  char  reason[MAX_REMOVAL_REASON_LENGTH];
+  s32   vsize;
+  s64   fee;
+  u64   entry_time;
+};
+
+struct rejected_event
+{
+  u8    hash[HASH_LENGTH];
+  char  reason[MAX_REJECT_REASON_LENGTH];
+};
+
+struct replaced_event
+{
+  u8    replaced_hash[HASH_LENGTH];
+  s32   replaced_vsize;
+  s64   replaced_fee;
+  u64   replaced_entry_time;
+  u8    replacement_hash[HASH_LENGTH];
+  s32   replacement_vsize;
+  s64   replacement_fee;
+};
+
+// BPF perf buffer to push the data to user space.
+BPF_PERF_OUTPUT(added_events);
+BPF_PERF_OUTPUT(removed_events);
+BPF_PERF_OUTPUT(rejected_events);
+BPF_PERF_OUTPUT(replaced_events);
+
+int trace_added(struct pt_regs *ctx) {
+  struct added_event added = {};
+
+  bpf_usdt_readarg_p(1, ctx, &added.hash, HASH_LENGTH);
+  bpf_usdt_readarg(2, ctx, &added.vsize);
+  bpf_usdt_readarg(3, ctx, &added.fee);
+
+  added_events.perf_submit(ctx, &added, sizeof(added));
+  return 0;
+}
+
+int trace_removed(struct pt_regs *ctx) {
+  struct removed_event removed = {};
+
+  bpf_usdt_readarg_p(1, ctx, &removed.hash, HASH_LENGTH);
+  bpf_usdt_readarg_p(2, ctx, &removed.reason, MAX_REMOVAL_REASON_LENGTH);
+  bpf_usdt_readarg(3, ctx, &removed.vsize);
+  bpf_usdt_readarg(4, ctx, &removed.fee);
+  bpf_usdt_readarg(5, ctx, &removed.entry_time);
+
+  removed_events.perf_submit(ctx, &removed, sizeof(removed));
+  return 0;
+}
+
+int trace_rejected(struct pt_regs *ctx) {
+  struct rejected_event rejected = {};
+
+  bpf_usdt_readarg_p(1, ctx, &rejected.hash, HASH_LENGTH);
+  bpf_usdt_readarg_p(2, ctx, &rejected.reason, MAX_REJECT_REASON_LENGTH);
+
+  rejected_events.perf_submit(ctx, &rejected, sizeof(rejected));
+  return 0;
+}
+
+int trace_replaced(struct pt_regs *ctx) {
+  struct replaced_event replaced = {};
+
+  bpf_usdt_readarg_p(1, ctx, &replaced.replaced_hash, HASH_LENGTH);
+  bpf_usdt_readarg(2, ctx, &replaced.replaced_vsize);
+  bpf_usdt_readarg(3, ctx, &replaced.replaced_fee);
+  bpf_usdt_readarg(4, ctx, &replaced.replaced_entry_time);
+  bpf_usdt_readarg_p(5, ctx, &replaced.replacement_hash, HASH_LENGTH);
+  bpf_usdt_readarg(6, ctx, &replaced.replacement_vsize);
+  bpf_usdt_readarg(7, ctx, &replaced.replacement_fee);
+
+  replaced_events.perf_submit(ctx, &replaced, sizeof(replaced));
+  return 0;
+}
+
+"""
+
+
+class MempoolTracepointTest(BitcoinTestFramework):
+    def set_test_params(self):
+        self.num_nodes = 1
+        self.setup_clean_chain = True
+
+    def skip_test_if_missing_module(self):
+        self.skip_if_platform_not_linux()
+        self.skip_if_no_bitcoind_tracepoints()
+        self.skip_if_no_python_bcc()
+        self.skip_if_no_bpf_permissions()
+
+    def added_test(self):
+        """Add a transaction to the mempool and make sure the tracepoint returns
+        the expected txid, vsize, and fee."""
+
+        events = []
+
+        self.log.info("Hooking into mempool:added tracepoint...")
+        node = self.nodes[0]
+        ctx = USDT(pid=node.process.pid)
+        ctx.enable_probe(probe="mempool:added", fn_name="trace_added")
+        bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
+
+        def handle_added_event(_, data, __):
+            events.append(bpf["added_events"].event(data))
+
+        bpf["added_events"].open_perf_buffer(handle_added_event)
+
+        self.log.info("Sending transaction...")
+        fee = Decimal(31200)
+        tx = self.wallet.send_self_transfer(from_node=node, fee=fee / COIN)
+
+        self.log.info("Polling buffer...")
+        bpf.perf_buffer_poll(timeout=200)
+
+        self.log.info("Cleaning up mempool...")
+        self.generate(node, 1)
+
+        self.log.info("Ensuring mempool:added event was handled successfully...")
+        assert_equal(1, len(events))
+        event = events[0]
+        assert_equal(bytes(event.hash)[::-1].hex(), tx["txid"])
+        assert_equal(event.vsize, tx["tx"].get_vsize())
+        assert_equal(event.fee, fee)
+
+        bpf.cleanup()
+        self.generate(self.wallet, 1)
+
+    def removed_test(self):
+        """Expire a transaction from the mempool and make sure the tracepoint returns
+        the expected txid, expiry reason, vsize, and fee."""
+
+        events = []
+
+        self.log.info("Hooking into mempool:removed tracepoint...")
+        node = self.nodes[0]
+        ctx = USDT(pid=node.process.pid)
+        ctx.enable_probe(probe="mempool:removed", fn_name="trace_removed")
+        bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
+
+        def handle_removed_event(_, data, __):
+            events.append(bpf["removed_events"].event(data))
+
+        bpf["removed_events"].open_perf_buffer(handle_removed_event)
+
+        self.log.info("Sending transaction...")
+        fee = Decimal(31200)
+        tx = self.wallet.send_self_transfer(from_node=node, fee=fee / COIN)
+        txid = tx["txid"]
+
+        self.log.info("Fast-forwarding time to mempool expiry...")
+        entry_time = node.getmempoolentry(txid)["time"]
+        expiry_time = entry_time + 60 * 60 * DEFAULT_MEMPOOL_EXPIRY_HOURS + 5
+        node.setmocktime(expiry_time)
+
+        self.log.info("Triggering expiry...")
+        self.wallet.get_utxo(txid=txid)
+        self.wallet.send_self_transfer(from_node=node)
+
+        self.log.info("Polling buffer...")
+        bpf.perf_buffer_poll(timeout=200)
+
+        self.log.info("Ensuring mempool:removed event was handled successfully...")
+        assert_equal(1, len(events))
+        event = events[0]
+        assert_equal(bytes(event.hash)[::-1].hex(), txid)
+        assert_equal(event.reason.decode("UTF-8"), "expiry")
+        assert_equal(event.vsize, tx["tx"].get_vsize())
+        assert_equal(event.fee, fee)
+        assert_equal(event.entry_time, entry_time)
+
+        bpf.cleanup()
+        self.generate(self.wallet, 1)
+
+    def replaced_test(self):
+        """Replace one and two transactions in the mempool and make sure the tracepoint
+        returns the expected txids, vsizes, and fees."""
+
+        events = []
+
+        self.log.info("Hooking into mempool:replaced tracepoint...")
+        node = self.nodes[0]
+        ctx = USDT(pid=node.process.pid)
+        ctx.enable_probe(probe="mempool:replaced", fn_name="trace_replaced")
+        bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
+
+        def handle_replaced_event(_, data, __):
+            events.append(bpf["replaced_events"].event(data))
+
+        bpf["replaced_events"].open_perf_buffer(handle_replaced_event)
+
+        self.log.info("Sending RBF transaction...")
+        utxo = self.wallet.get_utxo(mark_as_spent=True)
+        original_fee = Decimal(40000)
+        original_tx = self.wallet.send_self_transfer(
+            from_node=node, utxo_to_spend=utxo, fee=original_fee / COIN
+        )
+        entry_time = node.getmempoolentry(original_tx["txid"])["time"]
+
+        self.log.info("Sending replacement transaction...")
+        replacement_fee = Decimal(45000)
+        replacement_tx = self.wallet.send_self_transfer(
+            from_node=node, utxo_to_spend=utxo, fee=replacement_fee / COIN
+        )
+
+        self.log.info("Polling buffer...")
+        bpf.perf_buffer_poll(timeout=200)
+
+        self.log.info("Ensuring mempool:replaced event was handled successfully...")
+        assert_equal(1, len(events))
+        event = events[0]
+        assert_equal(bytes(event.replaced_hash)[::-1].hex(), original_tx["txid"])
+        assert_equal(event.replaced_vsize, original_tx["tx"].get_vsize())
+        assert_equal(event.replaced_fee, original_fee)
+        assert_equal(event.replaced_entry_time, entry_time)
+        assert_equal(bytes(event.replacement_hash)[::-1].hex(), replacement_tx["txid"])
+        assert_equal(event.replacement_vsize, replacement_tx["tx"].get_vsize())
+        assert_equal(event.replacement_fee, replacement_fee)
+
+        bpf.cleanup()
+        self.generate(self.wallet, 1)
+
+    def rejected_test(self):
+        """Create an invalid transaction and make sure the tracepoint returns
+        the expected txid, rejection reason, peer id, and peer address."""
+
+        events = []
+
+        self.log.info("Adding P2P connection...")
+        node = self.nodes[0]
+        node.add_p2p_connection(P2PDataStore())
+
+        self.log.info("Hooking into mempool:rejected tracepoint...")
+        ctx = USDT(pid=node.process.pid)
+        ctx.enable_probe(probe="mempool:rejected", fn_name="trace_rejected")
+        bpf = BPF(text=MEMPOOL_TRACEPOINTS_PROGRAM, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
+
+        def handle_rejected_event(_, data, __):
+            events.append(bpf["rejected_events"].event(data))
+
+        bpf["rejected_events"].open_perf_buffer(handle_rejected_event)
+
+        self.log.info("Sending invalid transaction...")
+        tx = self.wallet.create_self_transfer(fee_rate=Decimal(0))
+        node.p2ps[0].send_txs_and_test([tx["tx"]], node, success=False)
+
+        self.log.info("Polling buffer...")
+        bpf.perf_buffer_poll(timeout=200)
+
+        self.log.info("Ensuring mempool:rejected event was handled successfully...")
+        assert_equal(1, len(events))
+        event = events[0]
+        assert_equal(bytes(event.hash)[::-1].hex(), tx["tx"].hash)
+        # The next test is already known to fail, so disable it to avoid
+        # wasting CPU time and developer time. See
+        # https://github.com/bitcoin/bitcoin/issues/27380
+        #assert_equal(event.reason.decode("UTF-8"), "min relay fee not met")
+
+        bpf.cleanup()
+        self.generate(self.wallet, 1)
+
+    def run_test(self):
+        """Tests the mempool:added, mempool:removed, mempool:replaced,
+        and mempool:rejected tracepoints."""
+
+        # Create some coinbase transactions and mature them so they can be spent
+        node = self.nodes[0]
+        self.wallet = MiniWallet(node)
+        self.generate(self.wallet, 4)
+        self.generate(node, COINBASE_MATURITY)
+
+        # Test individual tracepoints
+        self.added_test()
+        self.removed_test()
+        self.replaced_test()
+        self.rejected_test()
+
+
+if __name__ == "__main__":
+    MempoolTracepointTest().main()
diff --git a/test/functional/interface_usdt_net.py b/test/functional/interface_usdt_net.py
index d446c0e5b7a1..5d7c8c23041f 100755
--- a/test/functional/interface_usdt_net.py
+++ b/test/functional/interface_usdt_net.py
@@ -4,7 +4,7 @@
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 """  Tests the net:* tracepoint API interface.
-     See https://github.com/dashpay/dash/blob/develop/doc/tracing.md#context-net
+     See https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#context-net
 """
 
 import ctypes
@@ -92,7 +92,7 @@ def skip_test_if_missing_module(self):
 
     def run_test(self):
         # Tests the net:inbound_message and net:outbound_message tracepoints
-        # See https://github.com/dashpay/dash/blob/develop/doc/tracing.md#context-net
+        # See https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#context-net
 
         class P2PMessage(ctypes.Structure):
             _fields_ = [
@@ -109,7 +109,7 @@ def __repr__(self):
 
         self.log.info(
             "hook into the net:inbound_message and net:outbound_message tracepoints")
-        ctx = USDT(path=str(self.options.bitcoind))
+        ctx = USDT(pid=self.nodes[0].process.pid)
         ctx.enable_probe(probe="net:inbound_message",
                          fn_name="trace_inbound_message")
         ctx.enable_probe(probe="net:outbound_message",
@@ -121,11 +121,11 @@ def __repr__(self):
         checked_outbound_version_msg = 0
         events = []
 
-        def check_p2p_message(event, inbound):
+        def check_p2p_message(event, is_inbound):
             nonlocal checked_inbound_version_msg, checked_outbound_version_msg
             if event.msg_type.decode("utf-8") == "version":
                 self.log.info(
-                    f"check_p2p_message(): {'inbound' if inbound else 'outbound'} {event}")
+                    f"check_p2p_message(): {'inbound' if is_inbound else 'outbound'} {event}")
                 peer = self.nodes[0].getpeerinfo()[0]
                 msg = msg_version()
                 msg.deserialize(BytesIO(bytes(event.msg[:event.msg_size])))
@@ -133,13 +133,12 @@ def check_p2p_message(event, inbound):
                 assert_equal(peer["addr"], event.peer_addr.decode("utf-8"))
                 assert_equal(peer["connection_type"],
                              event.peer_conn_type.decode("utf-8"))
-                if inbound:
+                if is_inbound:
                     checked_inbound_version_msg += 1
                 else:
                     checked_outbound_version_msg += 1
 
         def handle_inbound(_, data, __):
-            nonlocal events
             event = ctypes.cast(data, ctypes.POINTER(P2PMessage)).contents
             events.append((event, True))
 
@@ -150,15 +149,15 @@ def handle_outbound(_, data, __):
         bpf["inbound_messages"].open_perf_buffer(handle_inbound)
         bpf["outbound_messages"].open_perf_buffer(handle_outbound)
 
-        self.log.info("connect a P2P test node to our dashd node")
+        self.log.info("connect a P2P test node to our bitcoind node")
         test_node = P2PInterface()
         self.nodes[0].add_p2p_connection(test_node)
         bpf.perf_buffer_poll(timeout=200)
 
         self.log.info(
             "check receipt and content of in- and outbound version messages")
-        for event, inbound in events:
-            check_p2p_message(event, inbound)
+        for event, is_inbound in events:
+            check_p2p_message(event, is_inbound)
         assert_equal(EXPECTED_INOUTBOUND_VERSION_MSG,
                      checked_inbound_version_msg)
         assert_equal(EXPECTED_INOUTBOUND_VERSION_MSG,
diff --git a/test/functional/interface_usdt_utxocache.py b/test/functional/interface_usdt_utxocache.py
index 76bddc392ac9..06cdcd10a04b 100755
--- a/test/functional/interface_usdt_utxocache.py
+++ b/test/functional/interface_usdt_utxocache.py
@@ -4,7 +4,7 @@
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 """ Tests the utxocache:* tracepoint API interface.
-    See https://github.com/dashpay/dash/blob/develop/doc/tracing.md#context-utxocache
+    See https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#context-utxocache
 """
 
 import ctypes
@@ -14,7 +14,6 @@
 except ImportError:
     pass
 from test_framework.messages import COIN
-from test_framework.governance import EXPECTED_STDERR_NO_GOV_PRUNE
 from test_framework.test_framework import BitcoinTestFramework
 from test_framework.util import assert_equal
 from test_framework.wallet import MiniWallet
@@ -145,7 +144,6 @@ def skip_test_if_missing_module(self):
 
     def run_test(self):
         self.wallet = MiniWallet(self.nodes[0])
-        self.generate(self.wallet, 101)
 
         self.test_uncache()
         self.test_add_spent()
@@ -153,7 +151,7 @@ def run_test(self):
 
     def test_uncache(self):
         """ Tests the utxocache:uncache tracepoint API.
-        https://github.com/dashpay/dash/blob/develop/doc/tracing.md#tracepoint-utxocacheuncache
+        https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#tracepoint-utxocacheuncache
         """
         # To trigger an UTXO uncache from the cache, we create an invalid transaction
         # spending a not-cached, but existing UTXO. During transaction validation, this
@@ -174,7 +172,7 @@ def test_uncache(self):
         invalid_tx.vin[0].prevout.hash = int(block_1_coinbase_txid, 16)
 
         self.log.info("hooking into the utxocache:uncache tracepoint")
-        ctx = USDT(path=str(self.options.bitcoind))
+        ctx = USDT(pid=self.nodes[0].process.pid)
         ctx.enable_probe(probe="utxocache:uncache",
                          fn_name="trace_utxocache_uncache")
         bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
@@ -218,8 +216,8 @@ def handle_utxocache_uncache(_, data, __):
 
     def test_add_spent(self):
         """ Tests the utxocache:add utxocache:spent tracepoint API
-            See https://github.com/dashpay/dash/blob/develop/doc/tracing.md#tracepoint-utxocacheadd
-            and https://github.com/dashpay/dash/blob/develop/doc/tracing.md#tracepoint-utxocachespent
+            See https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#tracepoint-utxocacheadd
+            and https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#tracepoint-utxocachespent
         """
 
         self.log.info(
@@ -242,7 +240,7 @@ def test_add_spent(self):
 
         self.log.info(
             "hook into the utxocache:add and utxocache:spent tracepoints")
-        ctx = USDT(path=str(self.options.bitcoind))
+        ctx = USDT(pid=self.nodes[0].process.pid)
         ctx.enable_probe(probe="utxocache:add", fn_name="trace_utxocache_add")
         ctx.enable_probe(probe="utxocache:spent",
                          fn_name="trace_utxocache_spent")
@@ -254,43 +252,30 @@ def test_add_spent(self):
         # that the handle_* functions succeeded.
         EXPECTED_HANDLE_ADD_SUCCESS = 2
         EXPECTED_HANDLE_SPENT_SUCCESS = 1
-        handle_add_succeeds = 0
-        handle_spent_succeeds = 0
 
-        expected_utxocache_spents = []
         expected_utxocache_adds = []
+        expected_utxocache_spents = []
+
+        actual_utxocache_adds = []
+        actual_utxocache_spents = []
+
+        def compare_utxo_with_event(utxo, event):
+            """Compare a utxo dict to the event produced by BPF"""
+            assert_equal(utxo["txid"], bytes(event.txid[::-1]).hex())
+            assert_equal(utxo["index"], event.index)
+            assert_equal(utxo["height"], event.height)
+            assert_equal(utxo["value"], event.value)
+            assert_equal(utxo["is_coinbase"], event.is_coinbase)
 
         def handle_utxocache_add(_, data, __):
-            nonlocal handle_add_succeeds
             event = ctypes.cast(data, ctypes.POINTER(UTXOCacheChange)).contents
             self.log.info(f"handle_utxocache_add(): {event}")
-            add = expected_utxocache_adds.pop(0)
-            try:
-                assert_equal(add["txid"], bytes(event.txid[::-1]).hex())
-                assert_equal(add["index"], event.index)
-                assert_equal(add["height"], event.height)
-                assert_equal(add["value"], event.value)
-                assert_equal(add["is_coinbase"], event.is_coinbase)
-            except AssertionError:
-                self.log.exception("Assertion failed")
-            else:
-                handle_add_succeeds += 1
+            actual_utxocache_adds.append(event)
 
         def handle_utxocache_spent(_, data, __):
-            nonlocal handle_spent_succeeds
             event = ctypes.cast(data, ctypes.POINTER(UTXOCacheChange)).contents
             self.log.info(f"handle_utxocache_spent(): {event}")
-            spent = expected_utxocache_spents.pop(0)
-            try:
-                assert_equal(spent["txid"], bytes(event.txid[::-1]).hex())
-                assert_equal(spent["index"], event.index)
-                assert_equal(spent["height"], event.height)
-                assert_equal(spent["value"], event.value)
-                assert_equal(spent["is_coinbase"], event.is_coinbase)
-            except AssertionError:
-                self.log.exception("Assertion failed")
-            else:
-                handle_spent_succeeds += 1
+            actual_utxocache_spents.append(event)
 
         bpf["utxocache_add"].open_perf_buffer(handle_utxocache_add)
         bpf["utxocache_spent"].open_perf_buffer(handle_utxocache_spent)
@@ -326,27 +311,26 @@ def handle_utxocache_spent(_, data, __):
                         "is_coinbase": block_index == 0,
                     })
 
-        assert_equal(EXPECTED_HANDLE_ADD_SUCCESS, len(expected_utxocache_adds))
-        assert_equal(EXPECTED_HANDLE_SPENT_SUCCESS,
-                     len(expected_utxocache_spents))
-
         bpf.perf_buffer_poll(timeout=200)
-        bpf.cleanup()
+
+        assert_equal(EXPECTED_HANDLE_ADD_SUCCESS, len(expected_utxocache_adds), len(actual_utxocache_adds))
+        assert_equal(EXPECTED_HANDLE_SPENT_SUCCESS, len(expected_utxocache_spents), len(actual_utxocache_spents))
 
         self.log.info(
             f"check that we successfully traced {EXPECTED_HANDLE_ADD_SUCCESS} adds and {EXPECTED_HANDLE_SPENT_SUCCESS} spent")
-        assert_equal(0, len(expected_utxocache_adds))
-        assert_equal(0, len(expected_utxocache_spents))
-        assert_equal(EXPECTED_HANDLE_ADD_SUCCESS, handle_add_succeeds)
-        assert_equal(EXPECTED_HANDLE_SPENT_SUCCESS, handle_spent_succeeds)
+        for expected_utxo, actual_event in zip(expected_utxocache_adds + expected_utxocache_spents,
+                                               actual_utxocache_adds + actual_utxocache_spents):
+            compare_utxo_with_event(expected_utxo, actual_event)
+
+        bpf.cleanup()
 
     def test_flush(self):
         """ Tests the utxocache:flush tracepoint API.
-            See https://github.com/dashpay/dash/blob/develop/doc/tracing.md#tracepoint-utxocacheflush"""
+            See https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#tracepoint-utxocacheflush"""
 
         self.log.info("test the utxocache:flush tracepoint API")
         self.log.info("hook into the utxocache:flush tracepoint")
-        ctx = USDT(path=str(self.options.bitcoind))
+        ctx = USDT(pid=self.nodes[0].process.pid)
         ctx.enable_probe(probe="utxocache:flush",
                          fn_name="trace_utxocache_flush")
         bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
@@ -357,52 +341,61 @@ def test_flush(self):
         # that the handle_* functions succeeded.
         EXPECTED_HANDLE_FLUSH_SUCCESS = 3
         handle_flush_succeeds = 0
-        possible_cache_sizes = set()
-        expected_flushes = []
+        expected_flushes = list()
 
         def handle_utxocache_flush(_, data, __):
             nonlocal handle_flush_succeeds
             event = ctypes.cast(data, ctypes.POINTER(UTXOCacheFlush)).contents
             self.log.info(f"handle_utxocache_flush(): {event}")
-            expected = expected_flushes.pop(0)
-            assert_equal(expected["mode"], FLUSHMODE_NAME[event.mode])
-            possible_cache_sizes.remove(event.size)  # fails if size not in set
+            expected_flushes.remove({
+                "mode": FLUSHMODE_NAME[event.mode],
+                "for_prune": event.for_prune,
+                "size": event.size
+            })
             # sanity checks only
-            assert(event.memory > 0)
-            assert(event.duration > 0)
-            handle_flush_succeeds += 1
+            try:
+                assert event.memory > 0
+                assert event.duration > 0
+            except AssertionError:
+                self.log.exception("Assertion error")
+            else:
+                handle_flush_succeeds += 1
 
         bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
 
         self.log.info("stop the node to flush the UTXO cache")
-        UTXOS_IN_CACHE = 104  # might need to be changed if the earlier tests are modified
+        UTXOS_IN_CACHE = 2 # might need to be changed if the earlier tests are modified
         # A node shutdown causes two flushes. One that flushes UTXOS_IN_CACHE
         # UTXOs and one that flushes 0 UTXOs. Normally the 0-UTXO-flush is the
         # second flush, however it can happen that the order changes.
-        possible_cache_sizes = {UTXOS_IN_CACHE, 0}
-        flush_for_shutdown = {"mode": "ALWAYS", "for_prune": False}
-        expected_flushes.extend([flush_for_shutdown, flush_for_shutdown])
+        expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": UTXOS_IN_CACHE})
+        expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": 0})
         self.stop_node(0)
 
         bpf.perf_buffer_poll(timeout=200)
+        bpf.cleanup()
 
         self.log.info("check that we don't expect additional flushes")
         assert_equal(0, len(expected_flushes))
-        assert_equal(0, len(possible_cache_sizes))
 
         self.log.info("restart the node with -prune")
         self.start_node(0, ["-fastprune=1", "-prune=1"])
 
-        BLOCKS_TO_MINE = 450
+        BLOCKS_TO_MINE = 350
         self.log.info(f"mine {BLOCKS_TO_MINE} blocks to be able to prune")
         self.generate(self.wallet, BLOCKS_TO_MINE)
-        # we added BLOCKS_TO_MINE coinbase UTXOs to the cache
-        possible_cache_sizes = {BLOCKS_TO_MINE}
-        expected_flushes.append(
-            {"mode": "NONE", "for_prune": True, "size_fn": lambda x: x == BLOCKS_TO_MINE})
+
+        self.log.info("test the utxocache:flush tracepoint API with pruning")
+        self.log.info("hook into the utxocache:flush tracepoint")
+        ctx = USDT(pid=self.nodes[0].process.pid)
+        ctx.enable_probe(probe="utxocache:flush",
+                         fn_name="trace_utxocache_flush")
+        bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
+        bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
 
         self.log.info(f"prune blockchain to trigger a flush for pruning")
-        self.nodes[0].pruneblockchain(415)
+        expected_flushes.append({"mode": "NONE", "for_prune": True, "size": 0})
+        self.nodes[0].pruneblockchain(315)
 
         bpf.perf_buffer_poll(timeout=500)
         bpf.cleanup()
@@ -410,10 +403,8 @@ def handle_utxocache_flush(_, data, __):
         self.log.info(
             f"check that we don't expect additional flushes and that the handle_* function succeeded")
         assert_equal(0, len(expected_flushes))
-        assert_equal(0, len(possible_cache_sizes))
         assert_equal(EXPECTED_HANDLE_FLUSH_SUCCESS, handle_flush_succeeds)
 
-        self.stop_node(0, expected_stderr=EXPECTED_STDERR_NO_GOV_PRUNE)
 
 if __name__ == '__main__':
     UTXOCacheTracepointTest().main()
diff --git a/test/functional/interface_usdt_validation.py b/test/functional/interface_usdt_validation.py
index 0fe56abe0d51..30982393d85b 100755
--- a/test/functional/interface_usdt_validation.py
+++ b/test/functional/interface_usdt_validation.py
@@ -4,7 +4,7 @@
 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 """ Tests the validation:* tracepoint API interface.
-    See https://github.com/dashpay/dash/blob/develop/doc/tracing.md#context-validation
+    See https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#context-validation
 """
 
 import ctypes
@@ -64,7 +64,7 @@ def run_test(self):
         # Tests the validation:block_connected tracepoint by generating blocks
         # and comparing the values passed in the tracepoint arguments with the
         # blocks.
-        # See https://github.com/dashpay/dash/blob/develop/doc/tracing.md#tracepoint-validationblock_connected
+        # See https://github.com/bitcoin/bitcoin/blob/master/doc/tracing.md#tracepoint-validationblock_connected
 
         class Block(ctypes.Structure):
             _fields_ = [
@@ -86,39 +86,27 @@ def __repr__(self):
                     self.duration)
 
         BLOCKS_EXPECTED = 2
-        blocks_checked = 0
         expected_blocks = dict()
         events = []
 
         self.log.info("hook into the validation:block_connected tracepoint")
-        ctx = USDT(path=str(self.options.bitcoind))
+        ctx = USDT(pid=self.nodes[0].process.pid)
         ctx.enable_probe(probe="validation:block_connected",
                          fn_name="trace_block_connected")
         bpf = BPF(text=validation_blockconnected_program,
                   usdt_contexts=[ctx], debug=0, cflags=["-Wno-error=implicit-function-declaration"])
 
         def handle_blockconnected(_, data, __):
-            nonlocal events, blocks_checked
             event = ctypes.cast(data, ctypes.POINTER(Block)).contents
             self.log.info(f"handle_blockconnected(): {event}")
-            block_hash = bytes(event.hash[::-1]).hex()
-            block = expected_blocks[block_hash]
-            assert_equal(block["hash"], block_hash)
-            assert_equal(block["height"], event.height)
-            assert_equal(len(block["tx"]), event.transactions)
-            assert_equal(len([tx["vin"] for tx in block["tx"]]), event.inputs)
-            assert_equal(0, event.sigops)  # no sigops in coinbase tx
-            # only plausibility checks
-            assert(event.duration > 0)
-            del expected_blocks[block_hash]
-            blocks_checked += 1
+            events.append(event)
 
         bpf["block_connected"].open_perf_buffer(
             handle_blockconnected)
 
         self.log.info(f"mine {BLOCKS_EXPECTED} blocks")
-        block_hashes = self.generatetoaddress(self.nodes[0],
-            BLOCKS_EXPECTED, ADDRESS_BCRT1_UNSPENDABLE)
+        block_hashes = self.generatetoaddress(
+            self.nodes[0], BLOCKS_EXPECTED, ADDRESS_BCRT1_UNSPENDABLE)
         for block_hash in block_hashes:
             expected_blocks[block_hash] = self.nodes[0].getblock(block_hash, 2)
 
@@ -136,7 +124,7 @@ def handle_blockconnected(_, data, __):
             # only plausibility checks
             assert event.duration > 0
             del expected_blocks[block_hash]
-        assert_equal(BLOCKS_EXPECTED, blocks_checked)
+        assert_equal(BLOCKS_EXPECTED, len(events))
         assert_equal(0, len(expected_blocks))
 
         bpf.cleanup()
