Skip to content

Commit eeb5a94

Browse files
author
MacroFake
committed
Merge bitcoin/bitcoin#25528: ci: run USDT interface tests in the CI
cc7335e ci: run USDT interface test in a VM (0xb10c) dba6f82 test: adopt USDT utxocache interface tests (0xb10c) 220a5a2 test: hook into PID in tracing tests (0xb10c) Pull request description: Changes a CI task that runs test the previously not run `test/functional/interface_usdt_*.py` functional tests (added in bitcoin/bitcoin#24358). This task is run as CirussCI `compute_engine_instance` VM as hooking into the tracepoints is not possible in CirrusCI docker containers (bitcoin/bitcoin#23296 (comment)). We use an unoffical PPA and untrusted `bpfcc-tools` package in the CI as the Ubuntu jammy and Debian bullseye packages are outdated. We hope use an official package when new Ubuntu/Debian releases are available for the use with Google Compute Engine. We make sure to hook into `bitcoind` binaries in USDT interface tests via their PID, instead of their path. This makes sure multiple functional tests running in parallel don't interfere with each other. The utxocache USDT interface tests is adopted to a change of the functional test framework that wasn't detected as the tests weren't run in the CI. As the tracepoints expose internals, it can happen that we need to adopt the interface test when internals change. This is a bit awkward, and if it happens to frequently, we should consider generalizing the tests a bit more. For now it's fine, I think. See the individual commit messages for more details on the changes. Fixes bitcoin/bitcoin#24782 Fixes bitcoin/bitcoin#23296 I'd like to hear from reviewers: - Are we OK with using the [`hadret/bpfcc`](https://launchpad.net/~hadret/+archive/ubuntu/bpfcc) PPA for now? There is a clear plan when to drop it and as is currently, it could only impact the newly added VM task. - ~~Adding a new task increases CI runtime and costs. Should an existing `container` CI task be ported to a VM and reused instead?~~ Yes, see bitcoin/bitcoin#25528 (comment) ACKs for top commit: MarcoFalke: cr ACK cc7335e Tree-SHA512: b7fddccc0a77d82371229d048abe0bf2c4ccaa45906497ef3040cf99e7f05561890aef4c253c40e4afc96bb838c9787fae81c8454c6fd9db583276e005a4ccb3
2 parents da23320 + cc7335e commit eeb5a94

File tree

7 files changed

+52
-27
lines changed

7 files changed

+52
-27
lines changed

.cirrus.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,12 +259,20 @@ task:
259259
MAKEJOBS: "-j4" # Avoid excessive memory use due to MSan
260260

261261
task:
262-
name: '[ASan + LSan + UBSan + integer, no depends] [jammy]'
262+
name: '[ASan + LSan + UBSan + integer, no depends, USDT] [jammy]'
263263
<< : *GLOBAL_TASK_TEMPLATE
264-
container:
265-
image: ubuntu:jammy
264+
# We can't use a 'container' for the USDT interface tests as the CirrusCI
265+
# containers don't have privileges to hook into bitcoind. CirrusCI uses
266+
# Google Compute Engine instances: https://cirrus-ci.org/guide/custom-vms/
267+
# Images can be found here: https://cloud.google.com/compute/docs/images/os-details
268+
compute_engine_instance:
269+
image_project: ubuntu-os-cloud
270+
image: family/ubuntu-2204-lts # when upgrading, check if we can drop "ADD_UNTRUSTED_BPFCC_PPA"
271+
cpu: 4
272+
memory: 12G
266273
env:
267274
<< : *CIRRUS_EPHEMERAL_WORKER_TEMPLATE_ENV
275+
HOME: /root/ # Only needed for compute_engine_instance
268276
FILE_ENV: "./ci/test/00_setup_env_native_asan.sh"
269277
MAKEJOBS: "-j4" # Avoid excessive memory use
270278

ci/test/00_setup_env_native_asan.sh

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66

77
export LC_ALL=C.UTF-8
88

9+
# We install an up-to-date 'bpfcc-tools' package from an untrusted PPA.
10+
# This can be dropped with the next Ubuntu or Debian release that includes up-to-date packages.
11+
# See the if-then in ci/test/04_install.sh too.
12+
export ADD_UNTRUSTED_BPFCC_PPA=true
13+
914
export CONTAINER_NAME=ci_native_asan
10-
export PACKAGES="clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
11-
export DOCKER_NAME_TAG=ubuntu:22.04
15+
export PACKAGES="systemtap-sdt-dev bpfcc-tools clang llvm python3-zmq qtbase5-dev qttools5-dev-tools libevent-dev bsdmainutils libboost-dev libdb5.3++-dev libminiupnpc-dev libnatpmp-dev libzmq3-dev libqrencode-dev libsqlite3-dev"
16+
export DOCKER_NAME_TAG=ubuntu:22.04 # May not run in docker unless --enable-usdt is dropped
1217
export NO_DEPENDS=1
1318
export GOAL="install"
14-
export BITCOIN_CONFIG="--enable-c++20 --enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"
19+
export BITCOIN_CONFIG="--enable-usdt --enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS='-DARENA_DEBUG -DDEBUG_LOCKORDER' --with-sanitizers=address,integer,undefined CC=clang CXX=clang++"

ci/test/00_setup_env_native_tidy.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ export RUN_FUNCTIONAL_TESTS=false
1515
export RUN_FUZZ_TESTS=false
1616
export RUN_TIDY=true
1717
export GOAL="install"
18-
export BITCOIN_CONFIG="CC=clang CXX=clang++ --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'"
18+
export BITCOIN_CONFIG="CC=clang CXX=clang++ --enable-c++20 --with-incompatible-bdb --disable-hardening CFLAGS='-O0 -g0' CXXFLAGS='-O0 -g0'"
1919
export CCACHE_SIZE=200M

ci/test/04_install.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ if [[ $DOCKER_NAME_TAG == *centos* ]]; then
6868
${CI_RETRY_EXE} CI_EXEC dnf -y install epel-release
6969
${CI_RETRY_EXE} CI_EXEC dnf -y --allowerasing install "$DOCKER_PACKAGES" "$PACKAGES"
7070
elif [ "$CI_USE_APT_INSTALL" != "no" ]; then
71+
if [[ "${ADD_UNTRUSTED_BPFCC_PPA}" == "true" ]]; then
72+
# Ubuntu 22.04 LTS and Debian 11 both have an outdated bpfcc-tools packages.
73+
# The iovisor PPA is outdated as well. The next Ubuntu and Debian releases will contain updated
74+
# packages. Meanwhile, use an untrusted PPA to install an up-to-date version of the bpfcc-tools
75+
# package.
76+
# TODO: drop this once we can use newer images in GCE
77+
CI_EXEC add-apt-repository ppa:hadret/bpfcc
78+
fi
7179
${CI_RETRY_EXE} CI_EXEC apt-get update
7280
${CI_RETRY_EXE} CI_EXEC apt-get install --no-install-recommends --no-upgrade -y "$PACKAGES" "$DOCKER_PACKAGES"
7381
if [ -n "$PIP_PACKAGES" ]; then

test/functional/interface_usdt_net.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def __repr__(self):
109109

110110
self.log.info(
111111
"hook into the net:inbound_message and net:outbound_message tracepoints")
112-
ctx = USDT(path=str(self.options.bitcoind))
112+
ctx = USDT(pid=self.nodes[0].process.pid)
113113
ctx.enable_probe(probe="net:inbound_message",
114114
fn_name="trace_inbound_message")
115115
ctx.enable_probe(probe="net:outbound_message",

test/functional/interface_usdt_utxocache.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def test_uncache(self):
173173
invalid_tx.vin[0].prevout.hash = int(block_1_coinbase_txid, 16)
174174

175175
self.log.info("hooking into the utxocache:uncache tracepoint")
176-
ctx = USDT(path=str(self.options.bitcoind))
176+
ctx = USDT(pid=self.nodes[0].process.pid)
177177
ctx.enable_probe(probe="utxocache:uncache",
178178
fn_name="trace_utxocache_uncache")
179179
bpf = BPF(text=utxocache_changes_program, usdt_contexts=[ctx], debug=0)
@@ -238,7 +238,7 @@ def test_add_spent(self):
238238

239239
self.log.info(
240240
"hook into the utxocache:add and utxocache:spent tracepoints")
241-
ctx = USDT(path=str(self.options.bitcoind))
241+
ctx = USDT(pid=self.nodes[0].process.pid)
242242
ctx.enable_probe(probe="utxocache:add", fn_name="trace_utxocache_add")
243243
ctx.enable_probe(probe="utxocache:spent",
244244
fn_name="trace_utxocache_spent")
@@ -334,7 +334,7 @@ def test_flush(self):
334334

335335
self.log.info("test the utxocache:flush tracepoint API")
336336
self.log.info("hook into the utxocache:flush tracepoint")
337-
ctx = USDT(path=str(self.options.bitcoind))
337+
ctx = USDT(pid=self.nodes[0].process.pid)
338338
ctx.enable_probe(probe="utxocache:flush",
339339
fn_name="trace_utxocache_flush")
340340
bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0)
@@ -345,16 +345,17 @@ def test_flush(self):
345345
# that the handle_* functions succeeded.
346346
EXPECTED_HANDLE_FLUSH_SUCCESS = 3
347347
handle_flush_succeeds = 0
348-
possible_cache_sizes = set()
349-
expected_flushes = []
348+
expected_flushes = list()
350349

351350
def handle_utxocache_flush(_, data, __):
352351
nonlocal handle_flush_succeeds
353352
event = ctypes.cast(data, ctypes.POINTER(UTXOCacheFlush)).contents
354353
self.log.info(f"handle_utxocache_flush(): {event}")
355-
expected = expected_flushes.pop(0)
356-
assert_equal(expected["mode"], FLUSHMODE_NAME[event.mode])
357-
possible_cache_sizes.remove(event.size) # fails if size not in set
354+
expected_flushes.remove({
355+
"mode": FLUSHMODE_NAME[event.mode],
356+
"for_prune": event.for_prune,
357+
"size": event.size
358+
})
358359
# sanity checks only
359360
assert(event.memory > 0)
360361
assert(event.duration > 0)
@@ -363,33 +364,37 @@ def handle_utxocache_flush(_, data, __):
363364
bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
364365

365366
self.log.info("stop the node to flush the UTXO cache")
366-
UTXOS_IN_CACHE = 104 # might need to be changed if the eariler tests are modified
367+
UTXOS_IN_CACHE = 2 # might need to be changed if the eariler tests are modified
367368
# A node shutdown causes two flushes. One that flushes UTXOS_IN_CACHE
368369
# UTXOs and one that flushes 0 UTXOs. Normally the 0-UTXO-flush is the
369370
# second flush, however it can happen that the order changes.
370-
possible_cache_sizes = {UTXOS_IN_CACHE, 0}
371-
flush_for_shutdown = {"mode": "ALWAYS", "for_prune": False}
372-
expected_flushes.extend([flush_for_shutdown, flush_for_shutdown])
371+
expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": UTXOS_IN_CACHE})
372+
expected_flushes.append({"mode": "ALWAYS", "for_prune": False, "size": 0})
373373
self.stop_node(0)
374374

375375
bpf.perf_buffer_poll(timeout=200)
376+
bpf.cleanup()
376377

377378
self.log.info("check that we don't expect additional flushes")
378379
assert_equal(0, len(expected_flushes))
379-
assert_equal(0, len(possible_cache_sizes))
380380

381381
self.log.info("restart the node with -prune")
382382
self.start_node(0, ["-fastprune=1", "-prune=1"])
383383

384384
BLOCKS_TO_MINE = 350
385385
self.log.info(f"mine {BLOCKS_TO_MINE} blocks to be able to prune")
386386
self.generate(self.wallet, BLOCKS_TO_MINE)
387-
# we added BLOCKS_TO_MINE coinbase UTXOs to the cache
388-
possible_cache_sizes = {BLOCKS_TO_MINE}
389-
expected_flushes.append(
390-
{"mode": "NONE", "for_prune": True, "size_fn": lambda x: x == BLOCKS_TO_MINE})
387+
388+
self.log.info("test the utxocache:flush tracepoint API with pruning")
389+
self.log.info("hook into the utxocache:flush tracepoint")
390+
ctx = USDT(pid=self.nodes[0].process.pid)
391+
ctx.enable_probe(probe="utxocache:flush",
392+
fn_name="trace_utxocache_flush")
393+
bpf = BPF(text=utxocache_flushes_program, usdt_contexts=[ctx], debug=0)
394+
bpf["utxocache_flush"].open_perf_buffer(handle_utxocache_flush)
391395

392396
self.log.info(f"prune blockchain to trigger a flush for pruning")
397+
expected_flushes.append({"mode": "NONE", "for_prune": True, "size": 0})
393398
self.nodes[0].pruneblockchain(315)
394399

395400
bpf.perf_buffer_poll(timeout=500)
@@ -398,7 +403,6 @@ def handle_utxocache_flush(_, data, __):
398403
self.log.info(
399404
f"check that we don't expect additional flushes and that the handle_* function succeeded")
400405
assert_equal(0, len(expected_flushes))
401-
assert_equal(0, len(possible_cache_sizes))
402406
assert_equal(EXPECTED_HANDLE_FLUSH_SUCCESS, handle_flush_succeeds)
403407

404408

test/functional/interface_usdt_validation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def __repr__(self):
9494
expected_blocks = list()
9595

9696
self.log.info("hook into the validation:block_connected tracepoint")
97-
ctx = USDT(path=str(self.options.bitcoind))
97+
ctx = USDT(pid=self.nodes[0].process.pid)
9898
ctx.enable_probe(probe="validation:block_connected",
9999
fn_name="trace_block_connected")
100100
bpf = BPF(text=validation_blockconnected_program,

0 commit comments

Comments
 (0)