Skip to content

feat(eth): web3signer external signer for remote Ethereum key custody#3950

Draft
rickstaa wants to merge 3 commits into
masterfrom
rs/external-signer
Draft

feat(eth): web3signer external signer for remote Ethereum key custody#3950
rickstaa wants to merge 3 commits into
masterfrom
rs/external-signer

Conversation

@rickstaa

Copy link
Copy Markdown
Member

Note

Draft for discussion — opened to showcase the minimal, provider-agnostic in-tree approach for external key custody, as an alternative framing to eliteprox#5. Cc @eliteprox.

Closes #3941 (ENG-105).

What this does

Adds a single alternative eth.AccountManager that delegates signing to a remote Web3Signer-compatible endpoint (eth_* JSON-RPC) instead of a local keystore, so the Ethereum private key never lives on the node host. Selected with one flag:

livepeer -remoteSigner -ethAcctAddr 0x… -ethExternalSigner https://signer:9000

That's the whole in-tree surface: +263 LOC of code (one adapter + ~11 lines of wiring), no change to remote_signer.go, the payment structs, or the protocol.

The idea (what I meant)

go-livepeer should own one generic signing protocol and nothing vendor-specific. Everything else lives outside the node:

go-livepeer ──eth_* only (-ethExternalSigner)──┬─▶ Web3Signer ─▶ KMS / Vault / Azure / HSM   (config only, no code)
  one protocol, ~263 LOC                        └─▶ external-signer service ─▶ Turnkey / MPC   (separate repo)
  • KMS / Vault / HSM are reached off-the-shelf via Web3Signer — config only, zero go-livepeer code.
  • Turnkey / Fireblocks / MPC (proprietary APIs) sit behind a small standalone external-signer service that presents the same eth_* API and forwards to the provider. The vendor code + credentials live there, out of go-livepeer. (Companion repo, WIP — the Turnkey backend is ported from @eliteprox's work in Peer Optimization #5.)

The contrast with #5: that PR integrates the Turnkey SDK, wallet management, and multi-address routing directly into the node (~1,593 additions across 19 files). This keeps go-livepeer vendor-neutral and isolates the provider concern. Per-app-address generation and accounting (the multi-tenant bits) then belong to the clearinghouse layer above the signer, not the node.

Compatibility

Output is byte-identical to the keystore path — EIP-191 (accounts.TextHash) message signing, latest-signer transactions, recovery id normalized to {27,28}. PM tickets, deposit/reserve funding, and redemption are unchanged. Verified with a unit test that drives the adapter through a stub signer and recovers the signing address.

Open items (why this is a draft)

  • Live integration not yet tested against a real Web3Signer or a real Turnkey org (only stubs + go-ethereum's client conventions so far).
  • Multi-address signingeth_* already supports an address param; the adapter currently pins one address. Needed if the clearinghouse wants per-app Turnkey addresses.
  • mTLS between node and signer for the networked (non-loopback) deployment — optional, opt-in, not yet implemented.

Docs

doc/external-signer.md covers usage, the Web3Signer-fronted KMS/Vault/HSM path, the Turnkey-sidecar path, and a custody security ladder (local keystore < KMS/Vault/HSM < enclave/MPC).

🤖 Generated with Claude Code

…tody

Add an alternative AccountManager that delegates signing to a remote
Web3Signer-compatible endpoint (eth_* JSON-RPC) instead of a local
keystore, so the Ethereum private key never lives on the node host.
This is aimed at pooled-wallet payment remote signers, where a host
compromise could otherwise drain the deposit/reserve.

Select it with -ethExternalSigner <endpoint> plus -ethAcctAddr for the
address the signer holds. Output is byte-compatible with the keystore
path: EIP-191 (accounts.TextHash) message signing, latest-signer tx
signing, and recovery id normalized to {27,28}. remote_signer.go, the
payment structs, and the protocol are unchanged.

One protocol covers every backend: Web3Signer fronts AWS KMS, Azure Key
Vault, HashiCorp Vault, and HSM with no go-livepeer change (config only),
and MPC/enclave custody (Turnkey, Fireblocks) sits behind an eth_* sidecar
(livepeer/external-signer). Documented in doc/external-signer.md.

Co-authored-by: John | Elite Encoder <john@eliteencoder.net>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4398f4c6-75d1-47ad-a30d-4338383b42b1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rs/external-signer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added go Pull requests that update Go code docs labels Jun 15, 2026
Add a "Where it sits in the stack" section showing the end-to-end loop:
clearinghouse control plane (auth/metering/billing) above the signer,
go-livepeer owning the signing protocol, and the external signer service
+ backend owning key custody below it. Add a terminology section
(adapter / external signer service / backend) and stop calling the
standalone service a "sidecar" except as a deployment mode.

Co-authored-by: John | Elite Encoder <john@eliteencoder.net>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The web3signer adapter called the remote signer with rpc.Call, which
uses context.Background() and no deadline — a hung or slow signer would
block the PM ticket hot path indefinitely. Switch the signing calls and
the startup reachability check to CallContext with a per-call timeout,
configurable via -ethExternalSignerTimeout (default 5s). Add a test that
asserts Sign returns promptly on timeout instead of waiting for a slow
signer.

Co-authored-by: John | Elite Encoder <john@eliteencoder.net>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 54.13534% with 61 lines in your changes missing coverage. Please review.
✅ Project coverage is 33.30573%. Comparing base (e628b9c) to head (46d2ecc).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
eth/web3signer.go 36.36364% 52 Missing and 4 partials ⚠️
cmd/livepeer/starter/starter.go 88.37209% 5 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@                 Coverage Diff                 @@
##              master       #3950         +/-   ##
===================================================
+ Coverage   33.30014%   33.30573%   +0.00559%     
===================================================
  Files            171         172          +1     
  Lines          42174       42272         +98     
===================================================
+ Hits           14044       14079         +35     
- Misses         27077       27135         +58     
- Partials        1053        1058          +5     
Files with missing lines Coverage Δ
cmd/livepeer/starter/flags.go 87.50000% <100.00000%> (+0.18657%) ⬆️
cmd/livepeer/starter/starter.go 22.57426% <88.37209%> (+0.14559%) ⬆️
eth/web3signer.go 36.36364% <36.36364%> (ø)

... and 5 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e628b9c...46d2ecc. Read the comment docs.

Files with missing lines Coverage Δ
cmd/livepeer/starter/flags.go 87.50000% <100.00000%> (+0.18657%) ⬆️
cmd/livepeer/starter/starter.go 22.57426% <88.37209%> (+0.14559%) ⬆️
eth/web3signer.go 36.36364% <36.36364%> (ø)

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support external key custody / remote signing (Turnkey, KMS) for payment signers

1 participant