xplugeth

07/05/2025

Xplugeth is an evolution of Plugeth that is used to build go-ethereum binaries with extended functionality and utility. In this note i just want to introduce it and highlight some interestings parts of xplugeth, it’s not so much of a technical deep dive or documentation, for that you can check the docs.

  1. OG plugeth
  2. more on what xplugeth is
  3. my contributions in this project
Xplugeth is developed and maintained by OpenRelay (DBA Rivet). While it's stable and used in mainnet deployments, it's still a work in progress — we are actively adding features, writing plugins, and improving test coverage. It's been a year of development, and I hope it's useful to other teams.

Plugeth

Originally Plugeth was a fork of Geth that leveraged on Go’s plugin architecture to let developers extend and adapt Geth’s capabilities without needing to fork it. Since the Geth team avoids making core changes to support other networks or niche features, many projects have had to fork Geth to implement their own consensus protocols, modify the EVM, or extract information from Ethereum in ways the standard Geth client doesn’t support.

As time went on and updates from upstream geth emerged, maintaining and keeping plugeth updated was a bit of work. It also created room for code drift because by design plugeth had to stay in sync with plugeth-utils for it to work. I already wrote about this before in my note on Mimesis.


Xplugeth

xplugeth was born out of a devops-driven solution to the practical challenges of maintaining plugeth, rather than a fundamental protocol-level implementation or refactor.

xplugeth is a build system or framework for producing geth binaries, but not just standard geth binaries. The source it builds from is a modified version patched with hooks that allow developers to extend Geth without directly modifying its core. It applies patches during the build process, integrates several hooks into the codebase, and then compiles everything into a binary ready for deployment. The core of xplugeth is simply just patches, hooks, and plugins.

1. Patches

Patches in Xplugeth are changes applied at build time to modify the Geth source before compiling the final binary. They lay the foundation for plugins by injecting the necessary imports, setup files, and structural modifications required for them to work. Patches in xplugeth are defined in several patches.go files, for example in /hooks/blockchain/patches.go you’ll see this.

var initializePatchsets = []xplugeth.Patchset {
	xplugeth.Patchset{
		Remote: "github.com/openrelayxyz/xplugeth-patches",
		Ref: "hooks_foundation_init_v1.15.0_0",
		// https://github.com/openrelayxyz/xplugeth-patches/commit/be5ea0b65724131135ffe17971a1fdea2e41359d
		Tests: []xplugeth.Test{
			{
				Package: "./cmd/geth",
				TestNames: []string{
					"TestGethPkgInjections",
				},
			},
		},
	},
    ...
}

Each patchset contains:

  • a remote – the repository where the patches are stored (xplugeth-patches).
  • a ref – a tag pointing to a specific commit.
  • a test – which ensures the hooks and their injections work.

During the build process, xplugeth cherry-picks the relevant commits from the defined patchsets in the appropriate branch of xplugeth-patches and applies them to a fresh Geth source.

2. Hooks

Hooks in xplugeth are interfaces that allow plugins to interact with Geth’s execution flow. They serve as connection points between the core system and external modules. They allow plugins to modify execution by exposing pre-defined entry points.

In xplugeth’s design, hooks are defined and registered within the framework itself. The hooks package in xplugeth is where these interfaces are created, along with their corresponding patchsets, ensuring that they are properly injected into the modified Geth source during the build process. Hooks are also present in the patched Geth source. When a patchset is applied, it brings in xplugeth_hooks files, which contain the logic to retrieve registered modules, iterate over them, and execute their respective functions at the appropriate points in Geth’s lifecycle.

For example, a hook like NewSideBlockPlugin allows plugins to respond when a side block is processed. The patched Geth source will include a function like this:

// core/xplugeth_hooks.go

func pluginNewSideBlock(block *types.Block, hash common.Hash, logs []*types.Log) {
	for _, m := range xplugeth.GetModules[blockchain.NewSideBlockPlugin]() {
		m.NewSideBlock(block, hash, logs)
	}
}

This function retrieves all modules that implement NewSideBlockPlugin, loops through them, and invokes their NewSideBlock method. This hook is then injected into the relevant part of the Geth code, ensuring that whenever a side block is processed, any registered plugins receive that event and can act on it.

// core/blockchain.go

newBlock := bc.GetBlock(newChain[len(newChain) -1].Hash(), newChain[len(newChain) -1].Number.Uint64())
pluginNewSideBlock(newBlock, newBlock.Hash(), rebirthLogs)

3. Plugins

Plugins in xplugeth are standalone Go packages that integrate into the Geth binary at build time. They implement one or more predefined hook interfaces, allowing them to interact with different parts of the Ethereum client. During the build process, xplugeth imports the plugins that have been added to the build, making them available at runtime. Once the binary runs, these plugins remain inactive until the hooks they’ve implemented are triggered.

Since plugins register through hooks, they don’t modify the core system. They simply attach themselves to predefined extension points and execute when the conditions for their hooks are met. For example, you can checkout the example plugin we have in the repo example.go.


My Contributions

My main contributions to the project were in patching, plugins, testing, and the build system (basically everywhere)

  • writing patches: I created the patches that introduced injections and hooks, making it possible for several plugins to integrate with xplugeth,
  • writing plugins: I migrated plugins from the old plugin structure to xplugeth’s new system and implemented new plugins that are essential to Rivet’s node service,
  • testing: I worked on the binary test; which verifies the correctness of the data produced by the binaries. Also the integration tests that run when a patchset is applied to ensure the patches integrate correctly,
  • I helped create and document the build tool.

Build xplugeth

To build a binary using xplugeth, run:

python3 build/build.py --workdir /tmp/build_xplugeth

This will clone Geth, apply patches, integrate plugins (if specified) and compile the final binary leaving the code in the specified --wordkir. The output binary is stored in /tmp/output/ by default. But you can use the --artifacts.directory flag to specify it’s location. The build tool provides several options for customization. If you run with the --help flag, it shows you all the available arguments that can be passed in with flags

python3 build/build.py --help

For more details on available build options and plugins, check out the docs.


Home Work Notes 🗑️