Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ mkosi.tools.manifest
.claudesync/
.claudeignore
tmp/
logs/

!/**/.gitkeep
.vscode/

.venv/
78 changes: 78 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Makefile for flashbots-images
# Build VM images using mkosi
#
# NOTE: Current implementation uses venv with pip for dependency management.
# TODO: Revisit tooling choice (pip vs uv vs nix) in future PR.

.DEFAULT_GOAL := help

VERSION := $(shell git describe --tags --always --dirty="-dev" 2>/dev/null || echo "dev")
SHELL := /bin/bash
.SHELLFLAGS := -eu -o pipefail -c

# mkosi version
MKOSI_COMMIT := a425313c5811d2ed840630dbfc45c6bc296bfd48
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets avoid putting project dependency versions in the Makefile. main branch is using Nix which I think is too heavy for bnet images use-case (we don't need to install system tools).

Below you're also opting to use pip for dependency management. Originally, I intentionally avoided relying on any single tool for Python dependency management as there is no one blessed tool in the Python ecosystem and people use whatever (pip, pipx, poetry, uv).

Let's first discuss which dependency management tool we want to use for the project. I personally like uv.

To not block the PR on the tool selection decision let's proceed with the current implementation of the Makefile and come back to it later.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added TODO to the Makefile to revisit tooling choice.


# Virtual environment paths
VENV := .venv
VENV_BIN := $(VENV)/bin
VENV_MARKER := $(VENV)/.installed-$(MKOSI_COMMIT)
MKOSI := $(VENV_BIN)/mkosi

# Build logs
LOGS_DIR := logs
TIMESTAMP := $(shell date +%Y%m%d-%H%M%S)

##@ Help

# Awk script from https://github.com/paradigmxyz/reth/blob/main/Makefile
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "Usage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

.PHONY: v
v: ## Show the version
@echo "Version: $(VERSION)"

##@ Build

.PHONY: build
build: $(VENV_MARKER) ## Build VM image
@mkdir -p $(LOGS_DIR)
$(MKOSI) --force -I buildernet.conf 2>&1 | tee $(LOGS_DIR)/build-$(TIMESTAMP).log

.PHONY: build-playground
build-playground: $(VENV_MARKER) ## Build VM image for playground
@mkdir -p $(LOGS_DIR)
$(MKOSI) --force -I buildernet.conf --profile="devtools,playground" 2>&1 | tee $(LOGS_DIR)/build-playground-$(TIMESTAMP).log

##@ Setup

# Create venv only if it doesn't exist
$(VENV_BIN)/activate:
@echo "Creating Python virtual environment at $(VENV)..."
python3 -m venv $(VENV)

# Install/update dependencies when mkosi version changed
$(VENV_MARKER): $(VENV_BIN)/activate
@echo "Installing mkosi (commit: $(MKOSI_COMMIT))..."
@rm -f $(VENV)/.installed-*
$(VENV_BIN)/pip install -q --upgrade pip
$(VENV_BIN)/pip install -q git+https://github.com/systemd/mkosi.git@$(MKOSI_COMMIT)
@touch $@
@echo "Installed: $$($(MKOSI) --version)"

.PHONY: setup
setup: $(VENV_MARKER) ## Setup build environment (venv + mkosi)
@echo "Environment ready. mkosi: $$($(MKOSI) --version)"

##@ Utilities

.PHONY: clean
clean: ## Remove build artifacts (keeps venv)
git clean -fdX mkosi.output mkosi.builddir
rm -rf $(LOGS_DIR)

.PHONY: clean-all
clean-all: clean ## Remove all artifacts including venv
rm -rf $(VENV)
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ set -euo pipefail

echo "Installing attested-tls-proxy..."

VERSION="v0.0.2"
EXPECTED_SHA256=0e75fd4cc84065e95e5201be24a20186ef20167268ac0b1348509fa50dcfc4ad
VERSION="v1.0.0"
EXPECTED_SHA256=a4807589563a765e7f2153df5d4adb43b1f69f4aa8ffcf46596dcce4c03544c3
curl -sSfL https://github.com/flashbots/attested-tls-proxy/releases/download/${VERSION}/attested-tls-proxy_1.${VERSION}_amd64.deb \
-o $PACKAGEDIR/attested-tls-proxy.deb
echo "${EXPECTED_SHA256}" $PACKAGEDIR/attested-tls-proxy.deb | sha256sum --check
5 changes: 5 additions & 0 deletions mkosi.images/buildernet/mkosi.conf.d/playground.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Match]
Profiles=playground

[Include]
Include=../../mkosi.profiles/playground
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ After=network-online.target
[Service]
Type=oneshot
Environment=RBUILDER_BIDDING_SHA256SUM=60a52b4b33a76b3f3eb66ddb02c20435340a577da04d0bcc2ebc82122410b29b \
RBUILDER_BIDDING_TAG=v1.3.1
RBUILDER_BIDDING_TAG=v1.3.1 \
RBUILDER_BIDDING_REPO=rbuilder-bidding-service \
RBUILDER_BIDDING_ARTIFACT=bidding-service
EnvironmentFile=%E/rbuilder-bidding/gh_token.env
ExecStart=/bin/bash -c '[[ -f /usr/bin/rbuilder-bidding ]] || /usr/bin/fetch-gh-release-artifact fetch \
--repo rbuilder-bidding-service --tag "$RBUILDER_BIDDING_TAG" \
--artifact-name bidding-service --output-file /usr/bin/rbuilder-bidding'
--repo "$RBUILDER_BIDDING_REPO" --tag "$RBUILDER_BIDDING_TAG" \
--artifact-name "$RBUILDER_BIDDING_ARTIFACT" --output-file /usr/bin/rbuilder-bidding'
ExecStart=/bin/bash -c '[[ -f /usr/bin/rbuilder-bidding ]] || \
echo "$RBUILDER_BIDDING_SHA256SUM" /usr/bin/rbuilder-bidding | sha256sum --check'
ExecStart=/bin/chmod +x /usr/bin/rbuilder-bidding
Expand Down
11 changes: 11 additions & 0 deletions mkosi.profiles/playground/mkosi.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[Content]
# Use with devtools profile for full debugging capabilities:
# mkosi --profile=playground,devtools

Autologin=true
Packages=login

# BuilderHub URL override for playground
# 10.0.2.2 is the QEMU user networking default gateway that maps to host
# 7000 is the port of the attested-tls-proxy server service
Environment=BUILDERNET_BUILDERHUB_URL=10.0.2.2:7000
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Playground profile - disables services requiring external dependencies
#
# Services can be enabled at runtime with:
# systemctl enable --now <service>.service

# Downloads Reth state snapshot from S3
disable reth-sync.service

# Ships logs to CloudWatch, metrics to Prometheus
disable vector.service

# ACME services
# - Issues TLS certs via Let's Encrypt
disable acme-le.service
# - Renews Let's Encrypt TLS certs
disable acme-le-renewal.service
# - Metrics exporter
disable acme-le-textfile-collector.service

# Rebalances ETH across builder wallets
disable rbuilder-rebalancer.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Service]
ExecStart=
ExecStart=/usr/bin/attested-tls-proxy client \
--listen-addr 127.0.0.1:7937 \
--client-attestation-type none \
--allowed-remote-attestation-type none \
--allow-self-signed \
--log-json ${BUILDERNET_BUILDERHUB_URL}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Service]
Environment=
ExecStart=
ExecStart=/usr/bin/persistent-setup --device-lun 10 --key-file /etc/disk-encryption-key
TimeoutStartSec=120
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=Fetch configuration files from playground
Wants=network-online.target render-config.service
After=network.target network-online.target render-config.service persistent-setup.service
Before=reth.service lighthouse.service rbuilder-operator.service
ConditionPathIsDirectory=!/var/lib/persistent/playground

[Service]
Type=oneshot
User=root
StateDirectory=persistent/playground
ExecStart=/usr/local/bin/playground-config-fetch

[Install]
WantedBy=multi-user.target
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[Service]
# Clear Environment and EnvironmentFile from base service
Environment=
EnvironmentFile=

# Override environment with playground-specific values
Environment=RBUILDER_BIDDING_SHA256SUM=a2c3e02c40ce79e8e649fbea6cd1d4cda89139109e2d39cfb8646e1aa4a36c89 \
RBUILDER_BIDDING_TAG=v1.3.3 \
RBUILDER_BIDDING_REPO=rbuilder \
RBUILDER_BIDDING_ARTIFACT=tbv-bidding-service
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[general]
listen_addr = "0.0.0.0:3535"
pipe_file = "/run/operator-api/journal.fifo"
pprof = false
log_json = true
log_debug = false

# HTTP Basic Auth: the salt, and where to persistently store the hashed secret
basic_auth_secret_path = "/var/lib/persistent/operator-api/basic-auth-hash"
basic_auth_secret_salt = "bb36ef0b6643"

# HTTP server timeouts
# http_read_timeout_ms = 2500
# http_write_timeout_ms = 2500

# TLS configuration
tls_enabled = true
tls_create_if_missing = true
tls_cert_path = "/var/lib/persistent/operator-api/cert.pem"
tls_key_path = "/var/lib/persistent/operator-api/key.pem"

# Make sure to update buildernet/mkosi.extra/etc/sudoers.d/operator-api
# when adding a new action
[actions]
reboot = "sudo systemctl --no-pager --no-ask-password reboot"
rbuilder_restart = "sudo systemctl --no-pager --no-ask-password restart rbuilder-operator"
rbuilder_stop = "sudo systemctl --no-pager --no-ask-password stop rbuilder-operator"
fetch_config = "sudo systemctl --no-pager --no-ask-password start fetch-config"
rbuilder_bidding_restart = "sudo systemctl --no-pager --no-ask-password restart rbuilder-bidding"
ssh_stop = "sudo systemctl --no-pager --no-ask-password stop ssh.service ssh.socket"
ssh_start = "sudo systemctl --no-pager --no-ask-password start ssh.service ssh.socket"
haproxy_restart = "sudo systemctl --no-pager --no-ask-password restart haproxy"

[file_uploads]
rbuilder_blocklist = "/var/lib/persistent/rbuilder-operator/rbuilder.blocklist.json"
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# =============================================================================
# rbuilder-operator playground config
# =============================================================================

adjust_finalized_blocks = true
bidding_service_ipc_path = "/run/rbuilder-bidding/rpc_bidding_server.sock"
# blocklist - disabled
# blocklist = "{{rbuilder.blocklist}}"
# blocks_processor_url - disabled, no block archiving
# blocks_processor_url = "https://orderflow-archive.flashbots.net/api"
chain = "/var/lib/persistent/playground/genesis.json"
cl_node_url = ["http://127.0.0.1:3500"]
# coinbase_secret_key - omitted, rbuilder generates random key with warning
coinbase_secret_key = "{{rbuilder.coinbase_secret_key}}"
el_node_ipc_path = "/run/reth/reth.ipc"
error_storage_path = "/run/rbuilder-operator/rbuilder_errors.sqlite"
evm_caching_enable = {{rbuilder.evm_caching_enable}}
extra_data = "{{rbuilder.extra_data}}"
faster_finalize = true
full_telemetry_server_ip = "127.0.0.1"
full_telemetry_server_port = 6060
ignore_blobs = {{rbuilder.ignore_blobs}}
ignore_cancellable_orders = false
jsonrpc_server_ip = "127.0.0.1"
jsonrpc_server_port = 8645
# key_registration_url - disabled, no key registration with builderhub?
# key_registration_url = "http://127.0.0.1:7937"
live_builders = {{{rbuilder.live_builders}}}
log_color = false
log_json = true
log_level = "info,rbuilder=debug"
max_order_execution_duration_warning_us = {{rbuilder.max_order_execution_duration_warning_us}}
# optimistic_v3 - disabled for playground, no optimistic relay submissions
# optimistic_v3_server_ip = "0.0.0.0"
# optimistic_v3_server_port = 6000
# optimistic_v3_public_url = "{{rbuilder.optimistic_v3_public_url}}"
# optimistic_v3_relay_pubkeys = {{{rbuilder.optimistic_v3_relay_pubkeys}}}
# BLS secret key for signing relay submissions
relay_secret_key = "{{rbuilder.relay_secret_key}}"
require_non_empty_blocklist = {{rbuilder.require_non_empty_blocklist}}
reth_db_path = "/var/lib/persistent/reth/db"
reth_static_files_path = "/var/lib/persistent/reth/static_files"
root_hash_sparse_trie_version = "v2"
root_hash_threads = {{rbuilder.root_hash_threads}}
root_hash_use_sparse_trie = true
simulation_threads = 8
system_recipient_allowlist = {{{rbuilder.system_recipient_allowlist}}}
time_to_keep_mempool_txs_secs = {{rbuilder.time_to_keep_mempool_txs_secs}}
watchdog_timeout_sec = {{rbuilder.watchdog_timeout_sec}}

# [built_blocks_clickhouse_config] - disabled, no metrics/analytics to ClickHouse
# host = "{{rbuilder.clickhouse_host}}"
# database = "{{rbuilder.clickhouse_database}}"
# username = "{{rbuilder.clickhouse_username}}"
# password = "{{rbuilder.clickhouse_password}}"
# disk_database_path = "/persistent/rbuilder/failed_clickhouse.db"
# disk_max_size_mb = 2000
# memory_max_size_mb = 1024
# builder_name = "{{instance_name}}"

{{{rbuilder.builders}}}

{{{rbuilder.relays}}}

{{{rbuilder.relay_bid_scrapers}}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[Service]
# Clear the default ExecStart and use playground testnet config (no checkpoint sync)
ExecStart=
ExecStart=/usr/bin/lighthouse bn \
--testnet-dir /var/lib/persistent/playground/testnet \
--execution-endpoint http://localhost:8551 \
--execution-jwt /run/eth-jwt/jwt \
--suggested-fee-recipient 0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990 \
--always-prepare-payload \
--prepare-payload-lookahead 8000 \
--http \
--http-port 3500 \
--http-address 127.0.0.1 \
--port 9000 \
--metrics \
--metrics-address 127.0.0.1 \
--metrics-port 5054 \
--datadir %S/persistent/lighthouse \
--enable-private-discovery \
--disable-peer-scoring \
--disable-packet-filter \
--libp2p-addresses "{{{playground.cl_libp2p_addr}}}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[Service]
# Clear the default ExecStart and use playground genesis
ExecStart=
ExecStart=/usr/bin/reth node \
--full \
--chain /var/lib/persistent/playground/genesis.json \
--datadir %S/persistent/reth \
--authrpc.addr 127.0.0.1 \
--authrpc.jwtsecret /run/eth-jwt/jwt \
--authrpc.port 8551 \
--http \
--http.addr 127.0.0.1 \
--http.port 8545 \
--http.api "eth,net,web3,trace,rpc,debug,txpool" \
--ws \
--ws.addr 127.0.0.1 \
--ws.port 8546 \
--ws.api "eth,net,trace,web3,rpc,debug,txpool" \
--log.stdout.format json \
--log.file.max-files 0 \
--metrics "127.0.0.1:9001" \
--engine.persistence-threshold=0 \
--engine.memory-block-buffer-target=0 \
--ipcpath=%t/reth/reth.ipc \
--trusted-peers "{{{playground.el_bootnode}}}"
Loading