Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1#!/usr/bin/env python32# Copyright (c) 2021-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.6""" Interactive bitcoind P2P network traffic monitor utilizing USDT and the7net:inbound_message and net:outbound_message tracepoints. """9# This script demonstrates what USDT for Bitcoin Core can enable. It uses BCC10# (https://github.com/iovisor/bcc) to load a sandboxed eBPF program into the11# Linux kernel (root privileges are required). The eBPF program attaches to two12# statically defined tracepoints. The tracepoint 'net:inbound_message' is called13# when a new P2P message is received, and 'net:outbound_message' is called on14# outbound P2P messages. The eBPF program submits the P2P messages to15# this script via a BPF ring buffer.17import curses18import os19import sys20from curses import wrapper, panel21from bcc import BPF, USDT23# BCC: The C program to be compiled to an eBPF program (by BCC) and loaded into24# a sandboxed Linux kernel VM.25program = """26#include <uapi/linux/ptrace.h>28// Tor v3 addresses are 62 chars + 6 chars for the port (':12345').29// I2P addresses are 60 chars + 6 chars for the port (':12345').30#define MAX_PEER_ADDR_LENGTH 62 + 631#define MAX_PEER_CONN_TYPE_LENGTH 2032#define MAX_MSG_TYPE_LENGTH 2034struct p2p_message35{36u64 peer_id;37char peer_addr[MAX_PEER_ADDR_LENGTH];38char peer_conn_type[MAX_PEER_CONN_TYPE_LENGTH];39char msg_type[MAX_MSG_TYPE_LENGTH];40u64 msg_size;41};44// Two BPF perf buffers for pushing data (here P2P messages) to user space.45BPF_PERF_OUTPUT(inbound_messages);46BPF_PERF_OUTPUT(outbound_messages);48int trace_inbound_message(struct pt_regs *ctx) {49struct p2p_message msg = {};50void *paddr = NULL, *pconn_type = NULL, *pmsg_type = NULL;52bpf_usdt_readarg(1, ctx, &msg.peer_id);53bpf_usdt_readarg(2, ctx, &paddr);54bpf_probe_read_user_str(&msg.peer_addr, sizeof(msg.peer_addr), paddr);55bpf_usdt_readarg(3, ctx, &pconn_type);56bpf_probe_read_user_str(&msg.peer_conn_type, sizeof(msg.peer_conn_type), pconn_type);57bpf_usdt_readarg(4, ctx, &pmsg_type);58bpf_probe_read_user_str(&msg.msg_type, sizeof(msg.msg_type), pmsg_type);59bpf_usdt_readarg(5, ctx, &msg.msg_size);61inbound_messages.perf_submit(ctx, &msg, sizeof(msg));62return 0;63};65int trace_outbound_message(struct pt_regs *ctx) {66struct p2p_message msg = {};67void *paddr = NULL, *pconn_type = NULL, *pmsg_type = NULL;69bpf_usdt_readarg(1, ctx, &msg.peer_id);70bpf_usdt_readarg(2, ctx, &paddr);71bpf_probe_read_user_str(&msg.peer_addr, sizeof(msg.peer_addr), paddr);72bpf_usdt_readarg(3, ctx, &pconn_type);73bpf_probe_read_user_str(&msg.peer_conn_type, sizeof(msg.peer_conn_type), pconn_type);74bpf_usdt_readarg(4, ctx, &pmsg_type);75bpf_probe_read_user_str(&msg.msg_type, sizeof(msg.msg_type), pmsg_type);76bpf_usdt_readarg(5, ctx, &msg.msg_size);78outbound_messages.perf_submit(ctx, &msg, sizeof(msg));79return 0;80};81"""84class Message:85""" A P2P network message. """86msg_type = ""87size = 088data = bytes()89inbound = False91def __init__(self, msg_type, size, inbound):92self.msg_type = msg_type93self.size = size94self.inbound = inbound97class Peer:98""" A P2P network peer. """99id = 0100address = ""101connection_type = ""102last_messages = list()104total_inbound_msgs = 0105total_inbound_bytes = 0106total_outbound_msgs = 0107total_outbound_bytes = 0109def __init__(self, id, address, connection_type):110self.id = id111self.address = address112self.connection_type = connection_type113self.last_messages = list()115def add_message(self, message):116self.last_messages.append(message)117if len(self.last_messages) > 25:118self.last_messages.pop(0)119if message.inbound:120self.total_inbound_bytes += message.size121self.total_inbound_msgs += 1122else:123self.total_outbound_bytes += message.size124self.total_outbound_msgs += 1127def main(pid):128peers = dict()129print(f"Hooking into bitcoind with pid {pid}")130bitcoind_with_usdts = USDT(pid=int(pid))132# attaching the trace functions defined in the BPF program to the tracepoints133bitcoind_with_usdts.enable_probe(134probe="inbound_message", fn_name="trace_inbound_message")135bitcoind_with_usdts.enable_probe(136probe="outbound_message", fn_name="trace_outbound_message")137bpf = BPF(text=program, usdt_contexts=[bitcoind_with_usdts])139# BCC: perf buffer handle function for inbound_messages140def handle_inbound(_, data, size):141""" Inbound message handler.143Called each time a message is submitted to the inbound_messages BPF table."""144event = bpf["inbound_messages"].event(data)145if event.peer_id not in peers:146peer = Peer(event.peer_id, event.peer_addr.decode(147"utf-8"), event.peer_conn_type.decode("utf-8"))148peers[peer.id] = peer149peers[event.peer_id].add_message(150Message(event.msg_type.decode("utf-8"), event.msg_size, True))152# BCC: perf buffer handle function for outbound_messages153def handle_outbound(_, data, size):154""" Outbound message handler.156Called each time a message is submitted to the outbound_messages BPF table."""157event = bpf["outbound_messages"].event(data)158if event.peer_id not in peers:159peer = Peer(event.peer_id, event.peer_addr.decode(160"utf-8"), event.peer_conn_type.decode("utf-8"))161peers[peer.id] = peer162peers[event.peer_id].add_message(163Message(event.msg_type.decode("utf-8"), event.msg_size, False))165# BCC: add handlers to the inbound and outbound perf buffers166bpf["inbound_messages"].open_perf_buffer(handle_inbound)167bpf["outbound_messages"].open_perf_buffer(handle_outbound)169wrapper(loop, bpf, peers)172def loop(screen, bpf, peers):173screen.nodelay(1)174cur_list_pos = 0175win = curses.newwin(30, 70, 2, 7)176win.erase()177win.border(ord("|"), ord("|"), ord("-"), ord("-"),178ord("-"), ord("-"), ord("-"), ord("-"))179info_panel = panel.new_panel(win)180info_panel.hide()182ROWS_AVAILABLE_FOR_LIST = curses.LINES - 5183scroll = 0185while True:186try:187# BCC: poll the perf buffers for new events or timeout after 50ms188bpf.perf_buffer_poll(timeout=50)190ch = screen.getch()191if (ch == curses.KEY_DOWN or ch == ord("j")) and cur_list_pos < len(192peers.keys()) -1 and info_panel.hidden():193cur_list_pos += 1194if cur_list_pos >= ROWS_AVAILABLE_FOR_LIST:195scroll += 1196if (ch == curses.KEY_UP or ch == ord("k")) and cur_list_pos > 0 and info_panel.hidden():197cur_list_pos -= 1198if scroll > 0:199scroll -= 1200if ch == ord('\n') or ch == ord(' '):201if info_panel.hidden():202info_panel.show()203else:204info_panel.hide()205screen.erase()206render(screen, peers, cur_list_pos, scroll, ROWS_AVAILABLE_FOR_LIST, info_panel)207curses.panel.update_panels()208screen.refresh()209except KeyboardInterrupt:210exit()213def render(screen, peers, cur_list_pos, scroll, ROWS_AVAILABLE_FOR_LIST, info_panel):214""" renders the list of peers and details panel216This code is unrelated to USDT, BCC and BPF.217"""218header_format = "%6s %-20s %-20s %-22s %-67s"219row_format = "%6s %-5d %9d byte %-5d %9d byte %-22s %-67s"221screen.addstr(0, 1, (" P2P Message Monitor "), curses.A_REVERSE)222screen.addstr(2231, 0, (" Navigate with UP/DOWN or J/K and select a peer with ENTER or SPACE to see individual P2P messages"), curses.A_NORMAL)224screen.addstr(3, 0,225header_format % ("PEER", "OUTBOUND", "INBOUND", "TYPE", "ADDR"), curses.A_BOLD | curses.A_UNDERLINE)226peer_list = sorted(peers.keys())[scroll:ROWS_AVAILABLE_FOR_LIST+scroll]227for i, peer_id in enumerate(peer_list):228peer = peers[peer_id]229screen.addstr(i + 4, 0,230row_format % (peer.id, peer.total_outbound_msgs, peer.total_outbound_bytes,231peer.total_inbound_msgs, peer.total_inbound_bytes,232peer.connection_type, peer.address),233curses.A_REVERSE if i + scroll == cur_list_pos else curses.A_NORMAL)234if i + scroll == cur_list_pos:235info_window = info_panel.window()236info_window.erase()237info_window.border(238ord("|"), ord("|"), ord("-"), ord("-"),239ord("-"), ord("-"), ord("-"), ord("-"))241info_window.addstr(2421, 1, f"PEER {peer.id} ({peer.address})".center(68), curses.A_REVERSE | curses.A_BOLD)243info_window.addstr(2442, 1, f" OUR NODE{peer.connection_type:^54}PEER ",245curses.A_BOLD)246for i, msg in enumerate(peer.last_messages):247if msg.inbound:248info_window.addstr(249i + 3, 1, "%68s" %250(f"<--- {msg.msg_type} ({msg.size} bytes) "), curses.A_NORMAL)
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.