aboutsummaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'contrib')
-rw-r--r--contrib/guix/INSTALL.md26
-rw-r--r--contrib/guix/README.md9
-rwxr-xr-xcontrib/guix/guix-attest13
-rwxr-xr-xcontrib/guix/guix-build4
-rwxr-xr-xcontrib/guix/guix-codesign2
-rwxr-xr-xcontrib/guix/guix-verify28
-rwxr-xr-xcontrib/guix/libexec/build.sh1
-rwxr-xr-xcontrib/install_db4.sh8
-rw-r--r--contrib/tracing/README.md241
-rwxr-xr-xcontrib/tracing/connectblock_benchmark.bt150
-rwxr-xr-xcontrib/tracing/log_p2p_traffic.bt28
-rwxr-xr-xcontrib/tracing/log_raw_p2p_msgs.py180
-rwxr-xr-xcontrib/tracing/p2p_monitor.py250
-rwxr-xr-xcontrib/verifybinaries/verify.py2
14 files changed, 901 insertions, 41 deletions
diff --git a/contrib/guix/INSTALL.md b/contrib/guix/INSTALL.md
index 86f91cc87b..63aa3e02b2 100644
--- a/contrib/guix/INSTALL.md
+++ b/contrib/guix/INSTALL.md
@@ -79,8 +79,8 @@ Guix v1.2.0 is available as a distribution package starting in [Debian
21.04](https://packages.ubuntu.com/hirsute/guix).
Note that if you intend on using Guix without using any substitutes (more
-details [here][security-model]), v1.2.0 has a known problems when building
-GnuTLS from source. Solutions and workarounds are documented
+details [here][security-model]), v1.2.0 has a known problem when building GnuTLS
+from source. Solutions and workarounds are documented
[here](#gnutls-test-suite-fail-status-request-revoked).
@@ -124,7 +124,7 @@ particular commit of Guix). Previous experience with using autotools-style build
systems to build packages from source will be helpful. *hic sunt dracones.*
I strongly urge you to at least skim through the entire section once before you
-start issuing commands, as it will save you a lot of unncessary pain and
+start issuing commands, as it will save you a lot of unnecessary pain and
anguish.
### Installing common build tools
@@ -165,7 +165,7 @@ packaged and installable without manually building and installing.
For reference, the graphic below outlines Guix v1.3.0's dependency graph:
-![boostrap map](https://user-images.githubusercontent.com/6399679/125064185-a9a59880-e0b0-11eb-82c1-9b8e5dc9950d.png)
+![bootstrap map](https://user-images.githubusercontent.com/6399679/125064185-a9a59880-e0b0-11eb-82c1-9b8e5dc9950d.png)
#### Guile
@@ -270,23 +270,11 @@ Note that these environment variables are used to check for packages during
`./configure`, so they should be set as soon as possible should you want to use
a prefix other than `/usr`.
-<!-- ##### Example: Consistently using Guile 3.0 on Ubuntu -->
-
-<!-- For example, on Ubuntu, if you choose to use Guile 3.0 and install the -->
-<!-- `guile-3.0` package, you want to make sure that if you also want to install the -->
-<!-- `guile-git` package with `apt` that said `guile-git` package was built for Guile -->
-<!-- v3.0. This can be checked by invoking the following: -->
-
-<!-- ``` -->
-<!-- apt update -->
-<!-- apt show guile-git -->
-<!-- ``` -->
-
#### Building and installing source-built packages
-***IMPORTANT**: A few dependencies have non-obvious quirks/erratas which are documented in the
-sub-sections immediately below. Please read these sections before proceeding to
-build and install these packages.*
+***IMPORTANT**: A few dependencies have non-obvious quirks/errata which are
+documented in the sub-sections immediately below. Please read these sections
+before proceeding to build and install these packages.*
Although you should always refer to the README or INSTALL files for the most
accurate information, most of these dependencies use autoconf-style build
diff --git a/contrib/guix/README.md b/contrib/guix/README.md
index 4680368a6f..2bb464a40d 100644
--- a/contrib/guix/README.md
+++ b/contrib/guix/README.md
@@ -11,7 +11,7 @@ We achieve bootstrappability by using Guix as a functional package manager.
# Requirements
-Conservatively, a x86_64 machine with:
+Conservatively, you will need an x86_64 machine with:
- 16GB of free disk space on the partition that /gnu/store will reside in
- 8GB of free disk space **per platform triple** you're planning on building
@@ -87,7 +87,7 @@ crucial differences:
An invocation with all default options would look like:
```
-env DETACHED_SIGS_REPO=<path/to/bitcoin-detached-sigs> ./contrib/guix-codesign
+env DETACHED_SIGS_REPO=<path/to/bitcoin-detached-sigs> ./contrib/guix/guix-codesign
```
## Cleaning intermediate work directories
@@ -437,9 +437,8 @@ In the extraordinarily rare case where you messed up your Guix installation in
an irreversible way, you may want to completely purge Guix from your system and
start over.
-1. Uninstall Guix itself according to the way you installed it. (e.g. `sudo apt
- purge guix` for Ubuntu packaging, `sudo make uninstall` for
- built-from-source).
+1. Uninstall Guix itself according to the way you installed it (e.g. `sudo apt
+ purge guix` for Ubuntu packaging, `sudo make uninstall` for a build from source).
2. Remove all build users and groups
You may check for relevant users and groups using:
diff --git a/contrib/guix/guix-attest b/contrib/guix/guix-attest
index 51d589c1de..dcf709b542 100755
--- a/contrib/guix/guix-attest
+++ b/contrib/guix/guix-attest
@@ -207,8 +207,8 @@ mkdir -p "$outsigdir"
exit 1
fi
- temp_codesigned="$(mktemp)"
- trap 'rm -rf -- "$temp_codesigned"' EXIT
+ temp_all="$(mktemp)"
+ trap 'rm -rf -- "$temp_all"' EXIT
if (( ${#codesigned_fragments[@]} )); then
# Note: all.SHA256SUMS attests to all of $sha256sum_fragments, but is
@@ -216,20 +216,19 @@ mkdir -p "$outsigdir"
cat "${sha256sum_fragments[@]}" \
| sort -u \
| sort -k2 \
- | sed 's/$/\r/' \
| rfc4880_normalize_document \
- > "$temp_codesigned"
- if [ -e codesigned.SHA256SUMS ]; then
+ > "$temp_all"
+ if [ -e all.SHA256SUMS ]; then
# The SHA256SUMS already exists, make sure it's exactly what we
# expect, error out if not
- if diff -u all.SHA256SUMS "$temp_codesigned"; then
+ if diff -u all.SHA256SUMS "$temp_all"; then
echo "An all.SHA256SUMS file already exists for '${VERSION}' and is up-to-date."
else
shasum_already_exists all.SHA256SUMS
exit 1
fi
else
- mv "$temp_codesigned" codesigned.SHA256SUMS
+ mv "$temp_all" all.SHA256SUMS
fi
else
# It is fine to have the codesigned outputs be missing (perhaps the
diff --git a/contrib/guix/guix-build b/contrib/guix/guix-build
index f6da8435e9..dd7229b6fa 100755
--- a/contrib/guix/guix-build
+++ b/contrib/guix/guix-build
@@ -190,7 +190,7 @@ fi
# Services database must have basic entries
################
-if ! getent services http https ftp; then
+if ! getent services http https ftp > /dev/null 2>&1; then
cat << EOF
ERR: Your system's C library can not find service database entries for at least
one of the following services: http, https, ftp.
@@ -232,7 +232,7 @@ host_to_commonname() {
}
# Determine the reference time used for determinism (overridable by environment)
-SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git log --format=%at -1)}"
+SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git -c log.showSignature=false log --format=%at -1)}"
# Execute "$@" in a pinned, possibly older version of Guix, for reproducibility
# across time.
diff --git a/contrib/guix/guix-codesign b/contrib/guix/guix-codesign
index 11610a92e1..3f464f89e6 100755
--- a/contrib/guix/guix-codesign
+++ b/contrib/guix/guix-codesign
@@ -220,7 +220,7 @@ fi
JOBS="${JOBS:-$(nproc)}"
# Determine the reference time used for determinism (overridable by environment)
-SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git log --format=%at -1)}"
+SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git -c log.showSignature=false log --format=%at -1)}"
# Execute "$@" in a pinned, possibly older version of Guix, for reproducibility
# across time.
diff --git a/contrib/guix/guix-verify b/contrib/guix/guix-verify
index a6e2c4065e..e4863f115b 100755
--- a/contrib/guix/guix-verify
+++ b/contrib/guix/guix-verify
@@ -28,7 +28,11 @@ cmd_usage() {
cat <<EOF
Synopsis:
- env GUIX_SIGS_REPO=<path/to/guix.sigs> ./contrib/guix/guix-verify
+ env GUIX_SIGS_REPO=<path/to/guix.sigs> [ SIGNER=<signer> ] ./contrib/guix/guix-verify
+
+Example overriding signer's manifest to use as base
+
+ env GUIX_SIGS_REPO=/home/dongcarl/guix.sigs SIGNER=achow101 ./contrib/guix/guix-verify
EOF
}
@@ -92,6 +96,17 @@ echo "--------------------"
echo ""
if (( ${#all_noncodesigned[@]} )); then
compare_noncodesigned="${all_noncodesigned[0]}"
+ if [[ -n "$SIGNER" ]]; then
+ signer_noncodesigned="$OUTSIGDIR_BASE/$SIGNER/noncodesigned.SHA256SUMS"
+ if [[ -f "$signer_noncodesigned" ]]; then
+ echo "Using $SIGNER's manifest as the base to compare against"
+ compare_noncodesigned="$signer_noncodesigned"
+ else
+ echo "Unable to find $SIGNER's manifest, using the first one found"
+ fi
+ else
+ echo "No SIGNER provided, using the first manifest found"
+ fi
for current_manifest in "${all_noncodesigned[@]}"; do
verify "$compare_noncodesigned" "$current_manifest"
@@ -112,6 +127,17 @@ echo "--------------------"
echo ""
if (( ${#all_all[@]} )); then
compare_all="${all_all[0]}"
+ if [[ -n "$SIGNER" ]]; then
+ signer_all="$OUTSIGDIR_BASE/$SIGNER/all.SHA256SUMS"
+ if [[ -f "$signer_all" ]]; then
+ echo "Using $SIGNER's manifest as the base to compare against"
+ compare_all="$signer_all"
+ else
+ echo "Unable to find $SIGNER's manifest, using the first one found"
+ fi
+ else
+ echo "No SIGNER provided, using the first manifest found"
+ fi
for current_manifest in "${all_all[@]}"; do
verify "$compare_all" "$current_manifest"
diff --git a/contrib/guix/libexec/build.sh b/contrib/guix/libexec/build.sh
index bc3391e089..356bd70070 100755
--- a/contrib/guix/libexec/build.sh
+++ b/contrib/guix/libexec/build.sh
@@ -227,7 +227,6 @@ GIT_ARCHIVE="${DIST_ARCHIVE_BASE}/${DISTNAME}.tar.gz"
# Create the source tarball if not already there
if [ ! -e "$GIT_ARCHIVE" ]; then
mkdir -p "$(dirname "$GIT_ARCHIVE")"
- touch "${DIST_ARCHIVE_BASE}"/SKIPATTEST.TAG
git archive --prefix="${DISTNAME}/" --output="$GIT_ARCHIVE" HEAD
fi
diff --git a/contrib/install_db4.sh b/contrib/install_db4.sh
index 4037936404..dd4d862dee 100755
--- a/contrib/install_db4.sh
+++ b/contrib/install_db4.sh
@@ -221,10 +221,10 @@ EOF
# The packaged config.guess and config.sub are ancient (2009) and can cause build issues.
# Replace them with modern versions.
# See https://github.com/bitcoin/bitcoin/issues/16064
-CONFIG_GUESS_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=55eaf3e779455c4e5cc9f82efb5278be8f8f900b'
-CONFIG_GUESS_HASH='2d1ff7bca773d2ec3c6217118129220fa72d8adda67c7d2bf79994b3129232c1'
-CONFIG_SUB_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=55eaf3e779455c4e5cc9f82efb5278be8f8f900b'
-CONFIG_SUB_HASH='3a4befde9bcdf0fdb2763fc1bfa74e8696df94e1ad7aac8042d133c8ff1d2e32'
+CONFIG_GUESS_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f'
+CONFIG_GUESS_HASH='c8f530e01840719871748a8071113435bdfdf75b74c57e78e47898edea8754ae'
+CONFIG_SUB_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=4550d2f15b3a7ce2451c1f29500b9339430c877f'
+CONFIG_SUB_HASH='3969f7d5f6967ccc6f792401b8ef3916a1d1b1d0f0de5a4e354c95addb8b800e'
rm -f "dist/config.guess"
rm -f "dist/config.sub"
diff --git a/contrib/tracing/README.md b/contrib/tracing/README.md
new file mode 100644
index 0000000000..047354cda1
--- /dev/null
+++ b/contrib/tracing/README.md
@@ -0,0 +1,241 @@
+Example scripts for User-space, Statically Defined Tracing (USDT)
+=================================================================
+
+This directory contains scripts showcasing User-space, Statically Defined
+Tracing (USDT) support for Bitcoin Core on Linux using. For more information on
+USDT support in Bitcoin Core see the [USDT documentation].
+
+[USDT documentation]: ../../doc/tracing.md
+
+
+Examples for the two main eBPF front-ends, [bpftrace] and
+[BPF Compiler Collection (BCC)], with support for USDT, are listed. BCC is used
+for complex tools and daemons and `bpftrace` is preferred for one-liners and
+shorter scripts.
+
+[bpftrace]: https://github.com/iovisor/bpftrace
+[BPF Compiler Collection (BCC)]: https://github.com/iovisor/bcc
+
+
+To develop and run bpftrace and BCC scripts you need to install the
+corresponding packages. See [installing bpftrace] and [installing BCC] for more
+information. For development there exist a [bpftrace Reference Guide], a
+[BCC Reference Guide], and a [bcc Python Developer Tutorial].
+
+[installing bpftrace]: https://github.com/iovisor/bpftrace/blob/master/INSTALL.md
+[installing BCC]: https://github.com/iovisor/bcc/blob/master/INSTALL.md
+[bpftrace Reference Guide]: https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md
+[BCC Reference Guide]: https://github.com/iovisor/bcc/blob/master/docs/reference_guide.md
+[bcc Python Developer Tutorial]: https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md
+
+## Examples
+
+The bpftrace examples contain a relative path to the `bitcoind` binary. By
+default, the scripts should be run from the repository-root and assume a
+self-compiled `bitcoind` binary. The paths in the examples can be changed, for
+example, to point to release builds if needed. See the
+[Bitcoin Core USDT documentation] on how to list available tracepoints in your
+`bitcoind` binary.
+
+[Bitcoin Core USDT documentation]: ../../doc/tracing.md#listing-available-tracepoints
+
+**WARNING: eBPF programs require root privileges to be loaded into a Linux
+kernel VM. This means the bpftrace and BCC examples must be executed with root
+privileges. Make sure to carefully review any scripts that you run with root
+privileges first!**
+
+### log_p2p_traffic.bt
+
+A bpftrace script logging information about inbound and outbound P2P network
+messages. Based on the `net:inbound_message` and `net:outbound_message`
+tracepoints.
+
+By default, `bpftrace` limits strings to 64 bytes due to the limited stack size
+in the eBPF VM. For example, Tor v3 addresses exceed the string size limit which
+results in the port being cut off during logging. The string size limit can be
+increased with the `BPFTRACE_STRLEN` environment variable (`BPFTRACE_STRLEN=70`
+works fine).
+
+```
+$ bpftrace contrib/tracing/log_p2p_traffic.bt
+```
+
+Output
+```
+outbound 'ping' msg to peer 11 (outbound-full-relay, [2a02:b10c:f747:1:ef:fake:ipv6:addr]:8333) with 8 bytes
+inbound 'pong' msg from peer 11 (outbound-full-relay, [2a02:b10c:f747:1:ef:fake:ipv6:addr]:8333) with 8 bytes
+inbound 'inv' msg from peer 16 (outbound-full-relay, XX.XX.XXX.121:8333) with 37 bytes
+outbound 'getdata' msg to peer 16 (outbound-full-relay, XX.XX.XXX.121:8333) with 37 bytes
+inbound 'tx' msg from peer 16 (outbound-full-relay, XX.XX.XXX.121:8333) with 222 bytes
+outbound 'inv' msg to peer 9 (outbound-full-relay, faketorv3addressa2ufa6odvoi3s77j4uegey0xb10csyfyve2t33curbyd.onion:8333) with 37 bytes
+outbound 'inv' msg to peer 7 (outbound-full-relay, XX.XX.XXX.242:8333) with 37 bytes
+…
+```
+
+### p2p_monitor.py
+
+A BCC Python script using curses for an interactive P2P message monitor. Based
+on the `net:inbound_message` and `net:outbound_message` tracepoints.
+
+Inbound and outbound traffic is listed for each peer together with information
+about the connection. Peers can be selected individually to view recent P2P
+messages.
+
+```
+$ python3 contrib/tracing/p2p_monitor.py ./src/bitcoind
+```
+
+Lists selectable peers and traffic and connection information.
+```
+ P2P Message Monitor
+ Navigate with UP/DOWN or J/K and select a peer with ENTER or SPACE to see individual P2P messages
+
+ PEER OUTBOUND INBOUND TYPE ADDR
+ 0 46 398 byte 61 1407590 byte block-relay-only XX.XX.XXX.196:8333
+ 11 1156 253570 byte 3431 2394924 byte outbound-full-relay XXX.X.XX.179:8333
+ 13 3425 1809620 byte 1236 305458 byte inbound XXX.X.X.X:60380
+ 16 1046 241633 byte 1589 1199220 byte outbound-full-relay 4faketorv2pbfu7x.onion:8333
+ 19 577 181679 byte 390 148951 byte outbound-full-relay kfake4vctorjv2o2.onion:8333
+ 20 11 1248 byte 13 1283 byte block-relay-only [2600:fake:64d9:b10c:4436:aaaa:fe:bb]:8333
+ 21 11 1248 byte 13 1299 byte block-relay-only XX.XXX.X.155:8333
+ 22 5 103 byte 1 102 byte feeler XX.XX.XXX.173:8333
+ 23 11 1248 byte 12 1255 byte block-relay-only XX.XXX.XXX.220:8333
+ 24 3 103 byte 1 102 byte feeler XXX.XXX.XXX.64:8333
+…
+```
+
+Showing recent P2P messages between our node and a selected peer.
+
+```
+ ----------------------------------------------------------------------
+ | PEER 16 (4faketorv2pbfu7x.onion:8333) |
+ | OUR NODE outbound-full-relay PEER |
+ | <--- sendcmpct (9 bytes) |
+ | inv (37 byte) ---> |
+ | <--- ping (8 bytes) |
+ | pong (8 byte) ---> |
+ | inv (37 byte) ---> |
+ | <--- addr (31 bytes) |
+ | inv (37 byte) ---> |
+ | <--- getheaders (1029 bytes) |
+ | headers (1 byte) ---> |
+ | <--- feefilter (8 bytes) |
+ | <--- pong (8 bytes) |
+ | <--- headers (82 bytes) |
+ | <--- addr (30003 bytes) |
+ | inv (1261 byte) ---> |
+ | … |
+
+```
+
+### log_raw_p2p_msgs.py
+
+A BCC Python script showcasing eBPF and USDT limitations when passing data
+larger than about 32kb. Based on the `net:inbound_message` and
+`net:outbound_message` tracepoints.
+
+Bitcoin P2P messages can be larger than 32kb (e.g. `tx`, `block`, ...). The
+eBPF VM's stack is limited to 512 bytes, and we can't allocate more than about
+32kb for a P2P message in the eBPF VM. The **message data is cut off** when the
+message is larger than MAX_MSG_DATA_LENGTH (see script). This can be detected
+in user-space by comparing the data length to the message length variable. The
+message is cut off when the data length is smaller than the message length.
+A warning is included with the printed message data.
+
+Data is submitted to user-space (i.e. to this script) via a ring buffer. The
+throughput of the ring buffer is limited. Each p2p_message is about 32kb in
+size. In- or outbound messages submitted to the ring buffer in rapid
+succession fill the ring buffer faster than it can be read. Some messages are
+lost. BCC prints: `Possibly lost 2 samples` on lost messages.
+
+
+```
+$ python3 contrib/tracing/log_raw_p2p_msgs.py ./src/bitcoind
+```
+
+```
+Logging raw P2P messages.
+Messages larger that about 32kb will be cut off!
+Some messages might be lost!
+ outbound msg 'inv' from peer 4 (outbound-full-relay, XX.XXX.XX.4:8333) with 253 bytes: 0705000000be2245c8f844c9f763748e1a7…
+…
+Warning: incomplete message (only 32568 out of 53552 bytes)! inbound msg 'tx' from peer 32 (outbound-full-relay, XX.XXX.XXX.43:8333) with 53552 bytes: 020000000001fd3c01939c85ad6756ed9fc…
+…
+Possibly lost 2 samples
+```
+
+### connectblock_benchmark.bt
+
+A `bpftrace` script to benchmark the `ConnectBlock()` function during, for
+example, a blockchain re-index. Based on the `validation:block_connected` USDT
+tracepoint.
+
+The script takes three positional arguments. The first two arguments, the start,
+and end height indicate between which blocks the benchmark should be run. The
+third acts as a duration threshold in milliseconds. When the `ConnectBlock()`
+function takes longer than the threshold, information about the block, is
+printed. For more details, see the header comment in the script.
+
+By default, `bpftrace` limits strings to 64 bytes due to the limited stack size
+in the kernel VM. Block hashes as zero-terminated hex strings are 65 bytes which
+exceed the string limit. The string size limit can be set to 65 bytes with the
+environment variable `BPFTRACE_STRLEN`.
+
+The following command can be used to benchmark, for example, `ConnectBlock()`
+between height 20000 and 38000 on SigNet while logging all blocks that take
+longer than 25ms to connect.
+
+```
+$ BPFTRACE_STRLEN=65 bpftrace contrib/tracing/connectblock_benchmark.bt 20000 38000 25
+```
+
+In a different terminal, starting Bitcoin Core in SigNet mode and with
+re-indexing enabled.
+
+```
+$ ./src/bitcoind -signet -reindex
+```
+
+This produces the following output.
+```
+Attaching 5 probes...
+ConnectBlock Benchmark between height 20000 and 38000 inclusive
+Logging blocks taking longer than 25 ms to connect.
+Starting Connect Block Benchmark between height 20000 and 38000.
+BENCH 39 blk/s 59 tx/s 59 inputs/s 20 sigops/s (height 20038)
+Block 20492 (000000f555653bb05e2f3c6e79925e01a20dd57033f4dc7c354b46e34735d32b) 20 tx 2319 ins 2318 sigops took 38 ms
+BENCH 1840 blk/s 2117 tx/s 4478 inputs/s 2471 sigops/s (height 21879)
+BENCH 1816 blk/s 4972 tx/s 4982 inputs/s 125 sigops/s (height 23695)
+BENCH 2095 blk/s 2890 tx/s 2910 inputs/s 152 sigops/s (height 25790)
+BENCH 1684 blk/s 3979 tx/s 4053 inputs/s 288 sigops/s (height 27474)
+BENCH 1155 blk/s 3216 tx/s 3252 inputs/s 115 sigops/s (height 28629)
+BENCH 1797 blk/s 2488 tx/s 2503 inputs/s 111 sigops/s (height 30426)
+BENCH 1849 blk/s 6318 tx/s 6569 inputs/s 12189 sigops/s (height 32275)
+BENCH 946 blk/s 20209 tx/s 20775 inputs/s 83809 sigops/s (height 33221)
+Block 33406 (0000002adfe4a15cfcd53bd890a89bbae836e5bb7f38bac566f61ad4548c87f6) 25 tx 2045 ins 2090 sigops took 29 ms
+Block 33687 (00000073231307a9828e5607ceb8156b402efe56747271a4442e75eb5b77cd36) 52 tx 1797 ins 1826 sigops took 26 ms
+BENCH 582 blk/s 21581 tx/s 27673 inputs/s 60345 sigops/s (height 33803)
+BENCH 1035 blk/s 19735 tx/s 19776 inputs/s 51355 sigops/s (height 34838)
+Block 35625 (0000006b00b347390c4768ea9df2655e9ff4b120f29d78594a2a702f8a02c997) 20 tx 3374 ins 3371 sigops took 49 ms
+BENCH 887 blk/s 17857 tx/s 22191 inputs/s 24404 sigops/s (height 35725)
+Block 35937 (000000d816d13d6e39b471cd4368db60463a764ba1f29168606b04a22b81ea57) 75 tx 3943 ins 3940 sigops took 61 ms
+BENCH 823 blk/s 16298 tx/s 21031 inputs/s 18440 sigops/s (height 36548)
+Block 36583 (000000c3e260556dbf42968aae3f904dba8b8c1ff96a6f6e3aa5365d2e3ad317) 24 tx 2198 ins 2194 sigops took 34 ms
+Block 36700 (000000b3b173de9e65a3cfa738d976af6347aaf83fa17ab3f2a4d2ede3ddfac4) 73 tx 1615 ins 1611 sigops took 31 ms
+Block 36832 (0000007859578c02c1ac37dabd1b9ec19b98f350b56935f5dd3a41e9f79f836e) 34 tx 1440 ins 1436 sigops took 26 ms
+BENCH 613 blk/s 16718 tx/s 25074 inputs/s 23022 sigops/s (height 37161)
+Block 37870 (000000f5c1086291ba2d943fb0c3bc82e71c5ee341ee117681d1456fbf6c6c38) 25 tx 1517 ins 1514 sigops took 29 ms
+BENCH 811 blk/s 16031 tx/s 20921 inputs/s 18696 sigops/s (height 37972)
+
+Took 14055 ms to connect the blocks between height 20000 and 38000.
+
+Histogram of block connection times in milliseconds (ms).
+@durations:
+[0] 16838 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
+[1] 882 |@@ |
+[2, 4) 236 | |
+[4, 8) 23 | |
+[8, 16) 9 | |
+[16, 32) 9 | |
+[32, 64) 4 | |
+```
diff --git a/contrib/tracing/connectblock_benchmark.bt b/contrib/tracing/connectblock_benchmark.bt
new file mode 100755
index 0000000000..d268eff7f8
--- /dev/null
+++ b/contrib/tracing/connectblock_benchmark.bt
@@ -0,0 +1,150 @@
+#!/usr/bin/env bpftrace
+
+/*
+
+ USAGE:
+
+ BPFTRACE_STRLEN=65 bpftrace contrib/tracing/connectblock_benchmark.bt <start height> <end height> <logging threshold in ms>
+
+ - The environment variable BPFTRACE_STRLEN needs to be set to 65 chars as
+ strings are limited to 64 chars by default. Hex strings with Bitcoin block
+ hashes are 64 hex chars + 1 null-termination char.
+ - <start height> sets the height at which the benchmark should start. Setting
+ the start height to 0 starts the benchmark immediately, even before the
+ first block is connected.
+ - <end height> sets the height after which the benchmark should end. Setting
+ the end height to 0 disables the benchmark. The script only logs blocks
+ over <logging threshold in ms>.
+ - Threshold <logging threshold in ms>
+
+ This script requires a 'bitcoind' binary compiled with eBPF support and the
+ 'validation:block_connected' USDT. By default, it's assumed that 'bitcoind' is
+ located in './src/bitcoind'. This can be modified in the script below.
+
+ EXAMPLES:
+
+ BPFTRACE_STRLEN=65 bpftrace contrib/tracing/connectblock_benchmark.bt 300000 680000 1000
+
+ When run together 'bitcoind -reindex', this benchmarks the time it takes to
+ connect the blocks between height 300.000 and 680.000 (inclusive) and prints
+ details about all blocks that take longer than 1000ms to connect. Prints a
+ histogram with block connection times when the benchmark is finished.
+
+
+ BPFTRACE_STRLEN=65 bpftrace contrib/tracing/connectblock_benchmark.bt 0 0 500
+
+ When running together 'bitcoind', all newly connected blocks that
+ take longer than 500ms to connect are logged. A histogram with block
+ connection times is shown when the script is terminated.
+
+*/
+
+BEGIN
+{
+ $start_height = $1;
+ $end_height = $2;
+ $logging_threshold_ms = $3;
+
+ if ($end_height < $start_height) {
+ printf("Error: start height (%d) larger than end height (%d)!\n", $start_height, $end_height);
+ exit();
+ }
+
+ if ($end_height > 0) {
+ printf("ConnectBlock benchmark between height %d and %d inclusive\n", $start_height, $end_height);
+ } else {
+ printf("ConnectBlock logging starting at height %d\n", $start_height);
+ }
+
+ if ($logging_threshold_ms > 0) {
+ printf("Logging blocks taking longer than %d ms to connect.\n", $3);
+ }
+
+ if ($start_height == 0) {
+ @start = nsecs;
+ }
+}
+
+/*
+ Attaches to the 'validation:block_connected' USDT and collects stats when the
+ connected block is between the start and end height (or the end height is
+ unset).
+*/
+usdt:./src/bitcoind:validation:block_connected /arg1 >= $1 && (arg1 <= $2 || $2 == 0 )/
+{
+ $height = arg1;
+ $transactions = arg2;
+ $inputs = arg3;
+ $sigops = arg4;
+ $duration = (uint64) arg5;
+
+ @height = $height;
+
+ @blocks = @blocks + 1;
+ @transactions = @transactions + $transactions;
+ @inputs = @inputs + $inputs;
+ @sigops = @sigops + $sigops;
+
+ @durations = hist($duration / 1000);
+
+ if ($height == $1 && $height != 0) {
+ @start = nsecs;
+ printf("Starting Connect Block Benchmark between height %d and %d.\n", $1, $2);
+ }
+
+ if ($2 > 0 && $height >= $2) {
+ @end = nsecs;
+ $duration = @end - @start;
+ printf("\nTook %d ms to connect the blocks between height %d and %d.\n", $duration / 1000000, $1, $2);
+ exit();
+ }
+}
+
+/*
+ Attaches to the 'validation:block_connected' USDT and logs information about
+ blocks where the time it took to connect the block is above the
+ <logging threshold in ms>.
+*/
+usdt:./src/bitcoind:validation:block_connected / (uint64) arg5 / 1000> $3 /
+{
+ $hash_str = str(arg0);
+ $height = (int32) arg1;
+ $transactions = (uint64) arg2;
+ $inputs = (int32) arg3;
+ $sigops = (int64) arg4;
+ $duration = (int64) arg5;
+
+ printf("Block %d (%s) %4d tx %5d ins %5d sigops took %4d ms\n", $height, $hash_str, $transactions, $inputs, $sigops, (uint64) $duration / 1000);
+}
+
+
+/*
+ Prints stats about the blocks, transactions, inputs, and sigops processed in
+ the last second (if any).
+*/
+interval:s:1 {
+ if (@blocks > 0) {
+ printf("BENCH %4d blk/s %6d tx/s %7d inputs/s %8d sigops/s (height %d)\n", @blocks, @transactions, @inputs, @sigops, @height);
+
+ zero(@blocks);
+ zero(@transactions);
+ zero(@inputs);
+ zero(@sigops);
+ }
+}
+
+END
+{
+ printf("\nHistogram of block connection times in milliseconds (ms).\n");
+ print(@durations);
+
+ clear(@durations);
+ clear(@blocks);
+ clear(@transactions);
+ clear(@inputs);
+ clear(@sigops);
+ clear(@height);
+ clear(@start);
+ clear(@end);
+}
+
diff --git a/contrib/tracing/log_p2p_traffic.bt b/contrib/tracing/log_p2p_traffic.bt
new file mode 100755
index 0000000000..f62956aa5e
--- /dev/null
+++ b/contrib/tracing/log_p2p_traffic.bt
@@ -0,0 +1,28 @@
+#!/usr/bin/env bpftrace
+
+BEGIN
+{
+ printf("Logging P2P traffic\n")
+}
+
+usdt:./src/bitcoind:net:inbound_message
+{
+ $peer_id = (int64) arg0;
+ $peer_addr = str(arg1);
+ $peer_type = str(arg2);
+ $msg_type = str(arg3);
+ $msg_len = arg4;
+ printf("inbound '%s' msg from peer %d (%s, %s) with %d bytes\n", $msg_type, $peer_id, $peer_type, $peer_addr, $msg_len);
+}
+
+usdt:./src/bitcoind:net:outbound_message
+{
+ $peer_id = (int64) arg0;
+ $peer_addr = str(arg1);
+ $peer_type = str(arg2);
+ $msg_type = str(arg3);
+ $msg_len = arg4;
+
+ printf("outbound '%s' msg to peer %d (%s, %s) with %d bytes\n", $msg_type, $peer_id, $peer_type, $peer_addr, $msg_len);
+}
+
diff --git a/contrib/tracing/log_raw_p2p_msgs.py b/contrib/tracing/log_raw_p2p_msgs.py
new file mode 100755
index 0000000000..b5b5755632
--- /dev/null
+++ b/contrib/tracing/log_raw_p2p_msgs.py
@@ -0,0 +1,180 @@
+#!/usr/bin/env python3
+
+""" Demonstration of eBPF limitations and the effect on USDT with the
+ net:inbound_message and net:outbound_message tracepoints. """
+
+# This script shows a limitation of eBPF when data larger than 32kb is passed to
+# user-space. It uses BCC (https://github.com/iovisor/bcc) to load a sandboxed
+# eBPF program into the Linux kernel (root privileges are required). The eBPF
+# program attaches to two statically defined tracepoints. The tracepoint
+# 'net:inbound_message' is called when a new P2P message is received, and
+# 'net:outbound_message' is called on outbound P2P messages. The eBPF program
+# submits the P2P messages to this script via a BPF ring buffer. The submitted
+# messages are printed.
+
+# eBPF Limitations:
+#
+# Bitcoin P2P messages can be larger than 32kb (e.g. tx, block, ...). The eBPF
+# VM's stack is limited to 512 bytes, and we can't allocate more than about 32kb
+# for a P2P message in the eBPF VM. The message data is cut off when the message
+# is larger than MAX_MSG_DATA_LENGTH (see definition below). This can be detected
+# in user-space by comparing the data length to the message length variable. The
+# message is cut off when the data length is smaller than the message length.
+# A warning is included with the printed message data.
+#
+# Data is submitted to user-space (i.e. to this script) via a ring buffer. The
+# throughput of the ring buffer is limited. Each p2p_message is about 32kb in
+# size. In- or outbound messages submitted to the ring buffer in rapid
+# succession fill the ring buffer faster than it can be read. Some messages are
+# lost.
+#
+# BCC prints: "Possibly lost 2 samples" on lost messages.
+
+import sys
+from bcc import BPF, USDT
+
+# BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into
+# a sandboxed Linux kernel VM.
+program = """
+#include <uapi/linux/ptrace.h>
+
+#define MIN(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
+
+// Maximum possible allocation size
+// from include/linux/percpu.h in the Linux kernel
+#define PCPU_MIN_UNIT_SIZE (32 << 10)
+
+// Tor v3 addresses are 62 chars + 6 chars for the port (':12345').
+#define MAX_PEER_ADDR_LENGTH 62 + 6
+#define MAX_PEER_CONN_TYPE_LENGTH 20
+#define MAX_MSG_TYPE_LENGTH 20
+#define MAX_MSG_DATA_LENGTH PCPU_MIN_UNIT_SIZE - 200
+
+struct p2p_message
+{
+ u64 peer_id;
+ char peer_addr[MAX_PEER_ADDR_LENGTH];
+ char peer_conn_type[MAX_PEER_CONN_TYPE_LENGTH];
+ char msg_type[MAX_MSG_TYPE_LENGTH];
+ u64 msg_size;
+ u8 msg[MAX_MSG_DATA_LENGTH];
+};
+
+// We can't store the p2p_message struct on the eBPF stack as it is limited to
+// 512 bytes and P2P message can be bigger than 512 bytes. However, we can use
+// an BPF-array with a length of 1 to allocate up to 32768 bytes (this is
+// defined by PCPU_MIN_UNIT_SIZE in include/linux/percpu.h in the Linux kernel).
+// Also see https://github.com/iovisor/bcc/issues/2306
+BPF_ARRAY(msg_arr, struct p2p_message, 1);
+
+// Two BPF perf buffers for pushing data (here P2P messages) to user-space.
+BPF_PERF_OUTPUT(inbound_messages);
+BPF_PERF_OUTPUT(outbound_messages);
+
+int trace_inbound_message(struct pt_regs *ctx) {
+ int idx = 0;
+ struct p2p_message *msg = msg_arr.lookup(&idx);
+
+ // lookup() does not return a NULL pointer. However, the BPF verifier
+ // requires an explicit check that that the `msg` pointer isn't a NULL
+ // pointer. See https://github.com/iovisor/bcc/issues/2595
+ if (msg == NULL) return 1;
+
+ bpf_usdt_readarg(1, ctx, &msg->peer_id);
+ bpf_usdt_readarg_p(2, ctx, &msg->peer_addr, MAX_PEER_ADDR_LENGTH);
+ bpf_usdt_readarg_p(3, ctx, &msg->peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH);
+ bpf_usdt_readarg_p(4, ctx, &msg->msg_type, MAX_MSG_TYPE_LENGTH);
+ bpf_usdt_readarg(5, ctx, &msg->msg_size);
+ bpf_usdt_readarg_p(6, ctx, &msg->msg, MIN(msg->msg_size, MAX_MSG_DATA_LENGTH));
+
+ inbound_messages.perf_submit(ctx, msg, sizeof(*msg));
+ return 0;
+};
+
+int trace_outbound_message(struct pt_regs *ctx) {
+ int idx = 0;
+ struct p2p_message *msg = msg_arr.lookup(&idx);
+
+ // lookup() does not return a NULL pointer. However, the BPF verifier
+ // requires an explicit check that that the `msg` pointer isn't a NULL
+ // pointer. See https://github.com/iovisor/bcc/issues/2595
+ if (msg == NULL) return 1;
+
+ bpf_usdt_readarg(1, ctx, &msg->peer_id);
+ bpf_usdt_readarg_p(2, ctx, &msg->peer_addr, MAX_PEER_ADDR_LENGTH);
+ bpf_usdt_readarg_p(3, ctx, &msg->peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH);
+ bpf_usdt_readarg_p(4, ctx, &msg->msg_type, MAX_MSG_TYPE_LENGTH);
+ bpf_usdt_readarg(5, ctx, &msg->msg_size);
+ bpf_usdt_readarg_p(6, ctx, &msg->msg, MIN(msg->msg_size, MAX_MSG_DATA_LENGTH));
+
+ outbound_messages.perf_submit(ctx, msg, sizeof(*msg));
+ return 0;
+};
+"""
+
+
+def print_message(event, inbound):
+ print(f"%s %s msg '%s' from peer %d (%s, %s) with %d bytes: %s" %
+ (
+ f"Warning: incomplete message (only %d out of %d bytes)!" % (
+ len(event.msg), event.msg_size) if len(event.msg) < event.msg_size else "",
+ "inbound" if inbound else "outbound",
+ event.msg_type.decode("utf-8"),
+ event.peer_id,
+ event.peer_conn_type.decode("utf-8"),
+ event.peer_addr.decode("utf-8"),
+ event.msg_size,
+ bytes(event.msg[:event.msg_size]).hex(),
+ )
+ )
+
+
+def main(bitcoind_path):
+ bitcoind_with_usdts = USDT(path=str(bitcoind_path))
+
+ # attaching the trace functions defined in the BPF program to the tracepoints
+ bitcoind_with_usdts.enable_probe(
+ probe="inbound_message", fn_name="trace_inbound_message")
+ bitcoind_with_usdts.enable_probe(
+ probe="outbound_message", fn_name="trace_outbound_message")
+ bpf = BPF(text=program, usdt_contexts=[bitcoind_with_usdts])
+
+ # BCC: perf buffer handle function for inbound_messages
+ def handle_inbound(_, data, size):
+ """ Inbound message handler.
+
+ Called each time a message is submitted to the inbound_messages BPF table."""
+
+ event = bpf["inbound_messages"].event(data)
+ print_message(event, True)
+
+ # BCC: perf buffer handle function for outbound_messages
+
+ def handle_outbound(_, data, size):
+ """ Outbound message handler.
+
+ Called each time a message is submitted to the outbound_messages BPF table."""
+
+ event = bpf["outbound_messages"].event(data)
+ print_message(event, False)
+
+ # BCC: add handlers to the inbound and outbound perf buffers
+ bpf["inbound_messages"].open_perf_buffer(handle_inbound)
+ bpf["outbound_messages"].open_perf_buffer(handle_outbound)
+
+ print("Logging raw P2P messages.")
+ print("Messages larger that about 32kb will be cut off!")
+ print("Some messages might be lost!")
+ while True:
+ try:
+ bpf.perf_buffer_poll()
+ except KeyboardInterrupt:
+ exit()
+
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("USAGE:", sys.argv[0], "path/to/bitcoind")
+ exit()
+ path = sys.argv[1]
+ main(path)
diff --git a/contrib/tracing/p2p_monitor.py b/contrib/tracing/p2p_monitor.py
new file mode 100755
index 0000000000..14e3e3a801
--- /dev/null
+++ b/contrib/tracing/p2p_monitor.py
@@ -0,0 +1,250 @@
+#!/usr/bin/env python3
+
+""" Interactive bitcoind P2P network traffic monitor utilizing USDT and the
+ net:inbound_message and net:outbound_message tracepoints. """
+
+# This script demonstrates what USDT for Bitcoin Core can enable. It uses BCC
+# (https://github.com/iovisor/bcc) to load a sandboxed eBPF program into the
+# Linux kernel (root privileges are required). The eBPF program attaches to two
+# statically defined tracepoints. The tracepoint 'net:inbound_message' is called
+# when a new P2P message is received, and 'net:outbound_message' is called on
+# outbound P2P messages. The eBPF program submits the P2P messages to
+# this script via a BPF ring buffer.
+
+import sys
+import curses
+from curses import wrapper, panel
+from bcc import BPF, USDT
+
+# BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into
+# a sandboxed Linux kernel VM.
+program = """
+#include <uapi/linux/ptrace.h>
+
+// Tor v3 addresses are 62 chars + 6 chars for the port (':12345').
+// I2P addresses are 60 chars + 6 chars for the port (':12345').
+#define MAX_PEER_ADDR_LENGTH 62 + 6
+#define MAX_PEER_CONN_TYPE_LENGTH 20
+#define MAX_MSG_TYPE_LENGTH 20
+
+struct p2p_message
+{
+ u64 peer_id;
+ char peer_addr[MAX_PEER_ADDR_LENGTH];
+ char peer_conn_type[MAX_PEER_CONN_TYPE_LENGTH];
+ char msg_type[MAX_MSG_TYPE_LENGTH];
+ u64 msg_size;
+};
+
+
+// Two BPF perf buffers for pushing data (here P2P messages) to user space.
+BPF_PERF_OUTPUT(inbound_messages);
+BPF_PERF_OUTPUT(outbound_messages);
+
+int trace_inbound_message(struct pt_regs *ctx) {
+ struct p2p_message msg = {};
+
+ bpf_usdt_readarg(1, ctx, &msg.peer_id);
+ bpf_usdt_readarg_p(2, ctx, &msg.peer_addr, MAX_PEER_ADDR_LENGTH);
+ bpf_usdt_readarg_p(3, ctx, &msg.peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH);
+ bpf_usdt_readarg_p(4, ctx, &msg.msg_type, MAX_MSG_TYPE_LENGTH);
+ bpf_usdt_readarg(5, ctx, &msg.msg_size);
+
+ inbound_messages.perf_submit(ctx, &msg, sizeof(msg));
+ return 0;
+};
+
+int trace_outbound_message(struct pt_regs *ctx) {
+ struct p2p_message msg = {};
+
+ bpf_usdt_readarg(1, ctx, &msg.peer_id);
+ bpf_usdt_readarg_p(2, ctx, &msg.peer_addr, MAX_PEER_ADDR_LENGTH);
+ bpf_usdt_readarg_p(3, ctx, &msg.peer_conn_type, MAX_PEER_CONN_TYPE_LENGTH);
+ bpf_usdt_readarg_p(4, ctx, &msg.msg_type, MAX_MSG_TYPE_LENGTH);
+ bpf_usdt_readarg(5, ctx, &msg.msg_size);
+
+ outbound_messages.perf_submit(ctx, &msg, sizeof(msg));
+ return 0;
+};
+"""
+
+
+class Message:
+ """ A P2P network message. """
+ msg_type = ""
+ size = 0
+ data = bytes()
+ inbound = False
+
+ def __init__(self, msg_type, size, inbound):
+ self.msg_type = msg_type
+ self.size = size
+ self.inbound = inbound
+
+
+class Peer:
+ """ A P2P network peer. """
+ id = 0
+ address = ""
+ connection_type = ""
+ last_messages = list()
+
+ total_inbound_msgs = 0
+ total_inbound_bytes = 0
+ total_outbound_msgs = 0
+ total_outbound_bytes = 0
+
+ def __init__(self, id, address, connection_type):
+ self.id = id
+ self.address = address
+ self.connection_type = connection_type
+ self.last_messages = list()
+
+ def add_message(self, message):
+ self.last_messages.append(message)
+ if len(self.last_messages) > 25:
+ self.last_messages.pop(0)
+ if message.inbound:
+ self.total_inbound_bytes += message.size
+ self.total_inbound_msgs += 1
+ else:
+ self.total_outbound_bytes += message.size
+ self.total_outbound_msgs += 1
+
+
+def main(bitcoind_path):
+ peers = dict()
+
+ bitcoind_with_usdts = USDT(path=str(bitcoind_path))
+
+ # attaching the trace functions defined in the BPF program to the tracepoints
+ bitcoind_with_usdts.enable_probe(
+ probe="inbound_message", fn_name="trace_inbound_message")
+ bitcoind_with_usdts.enable_probe(
+ probe="outbound_message", fn_name="trace_outbound_message")
+ bpf = BPF(text=program, usdt_contexts=[bitcoind_with_usdts])
+
+ # BCC: perf buffer handle function for inbound_messages
+ def handle_inbound(_, data, size):
+ """ Inbound message handler.
+
+ Called each time a message is submitted to the inbound_messages BPF table."""
+ event = bpf["inbound_messages"].event(data)
+ if event.peer_id not in peers:
+ peer = Peer(event.peer_id, event.peer_addr.decode(
+ "utf-8"), event.peer_conn_type.decode("utf-8"))
+ peers[peer.id] = peer
+ peers[event.peer_id].add_message(
+ Message(event.msg_type.decode("utf-8"), event.msg_size, True))
+
+ # BCC: perf buffer handle function for outbound_messages
+ def handle_outbound(_, data, size):
+ """ Outbound message handler.
+
+ Called each time a message is submitted to the outbound_messages BPF table."""
+ event = bpf["outbound_messages"].event(data)
+ if event.peer_id not in peers:
+ peer = Peer(event.peer_id, event.peer_addr.decode(
+ "utf-8"), event.peer_conn_type.decode("utf-8"))
+ peers[peer.id] = peer
+ peers[event.peer_id].add_message(
+ Message(event.msg_type.decode("utf-8"), event.msg_size, False))
+
+ # BCC: add handlers to the inbound and outbound perf buffers
+ bpf["inbound_messages"].open_perf_buffer(handle_inbound)
+ bpf["outbound_messages"].open_perf_buffer(handle_outbound)
+
+ wrapper(loop, bpf, peers)
+
+
+def loop(screen, bpf, peers):
+ screen.nodelay(1)
+ cur_list_pos = 0
+ win = curses.newwin(30, 70, 2, 7)
+ win.erase()
+ win.border(ord("|"), ord("|"), ord("-"), ord("-"),
+ ord("-"), ord("-"), ord("-"), ord("-"))
+ info_panel = panel.new_panel(win)
+ info_panel.hide()
+
+ ROWS_AVALIABLE_FOR_LIST = curses.LINES - 5
+ scroll = 0
+
+ while True:
+ try:
+ # BCC: poll the perf buffers for new events or timeout after 50ms
+ bpf.perf_buffer_poll(timeout=50)
+
+ ch = screen.getch()
+ if (ch == curses.KEY_DOWN or ch == ord("j")) and cur_list_pos < len(
+ peers.keys()) -1 and info_panel.hidden():
+ cur_list_pos += 1
+ if cur_list_pos >= ROWS_AVALIABLE_FOR_LIST:
+ scroll += 1
+ if (ch == curses.KEY_UP or ch == ord("k")) and cur_list_pos > 0 and info_panel.hidden():
+ cur_list_pos -= 1
+ if scroll > 0:
+ scroll -= 1
+ if ch == ord('\n') or ch == ord(' '):
+ if info_panel.hidden():
+ info_panel.show()
+ else:
+ info_panel.hide()
+ screen.erase()
+ render(screen, peers, cur_list_pos, scroll, ROWS_AVALIABLE_FOR_LIST, info_panel)
+ curses.panel.update_panels()
+ screen.refresh()
+ except KeyboardInterrupt:
+ exit()
+
+
+def render(screen, peers, cur_list_pos, scroll, ROWS_AVALIABLE_FOR_LIST, info_panel):
+ """ renders the list of peers and details panel
+
+ This code is unrelated to USDT, BCC and BPF.
+ """
+ header_format = "%6s %-20s %-20s %-22s %-67s"
+ row_format = "%6s %-5d %9d byte %-5d %9d byte %-22s %-67s"
+
+ screen.addstr(0, 1, (" P2P Message Monitor "), curses.A_REVERSE)
+ screen.addstr(
+ 1, 0, (" Navigate with UP/DOWN or J/K and select a peer with ENTER or SPACE to see individual P2P messages"), curses.A_NORMAL)
+ screen.addstr(3, 0,
+ header_format % ("PEER", "OUTBOUND", "INBOUND", "TYPE", "ADDR"), curses.A_BOLD | curses.A_UNDERLINE)
+ peer_list = sorted(peers.keys())[scroll:ROWS_AVALIABLE_FOR_LIST+scroll]
+ for i, peer_id in enumerate(peer_list):
+ peer = peers[peer_id]
+ screen.addstr(i + 4, 0,
+ row_format % (peer.id, peer.total_outbound_msgs, peer.total_outbound_bytes,
+ peer.total_inbound_msgs, peer.total_inbound_bytes,
+ peer.connection_type, peer.address),
+ curses.A_REVERSE if i + scroll == cur_list_pos else curses.A_NORMAL)
+ if i + scroll == cur_list_pos:
+ info_window = info_panel.window()
+ info_window.erase()
+ info_window.border(
+ ord("|"), ord("|"), ord("-"), ord("-"),
+ ord("-"), ord("-"), ord("-"), ord("-"))
+
+ info_window.addstr(
+ 1, 1, f"PEER {peer.id} ({peer.address})".center(68), curses.A_REVERSE | curses.A_BOLD)
+ info_window.addstr(
+ 2, 1, f" OUR NODE{peer.connection_type:^54}PEER ",
+ curses.A_BOLD)
+ for i, msg in enumerate(peer.last_messages):
+ if msg.inbound:
+ info_window.addstr(
+ i + 3, 1, "%68s" %
+ (f"<--- {msg.msg_type} ({msg.size} bytes) "), curses.A_NORMAL)
+ else:
+ info_window.addstr(
+ i + 3, 1, " %s (%d byte) --->" %
+ (msg.msg_type, msg.size), curses.A_NORMAL)
+
+
+if __name__ == "__main__":
+ if len(sys.argv) < 2:
+ print("USAGE:", sys.argv[0], "path/to/bitcoind")
+ exit()
+ path = sys.argv[1]
+ main(path)
diff --git a/contrib/verifybinaries/verify.py b/contrib/verifybinaries/verify.py
index 6cbaf2dc0c..51c151add8 100755
--- a/contrib/verifybinaries/verify.py
+++ b/contrib/verifybinaries/verify.py
@@ -2,7 +2,7 @@
# Copyright (c) 2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Script for verifying Bitoin Core release binaries
+"""Script for verifying Bitcoin Core release binaries
This script attempts to download the signature file SHA256SUMS.asc from
bitcoincore.org and bitcoin.org and compares them.