feat(eth): web3signer external signer for remote Ethereum key custody#3950
feat(eth): web3signer external signer for remote Ethereum key custody#3950rickstaa wants to merge 3 commits into
Conversation
…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>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
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 Report❌ Patch coverage is
Additional details and impacted files@@ 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
... and 5 files with indirect coverage changes Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
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.AccountManagerthat 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: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:
external-signerservice that presents the sameeth_*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)
eth_*already supports an address param; the adapter currently pins one address. Needed if the clearinghouse wants per-app Turnkey addresses.Docs
doc/external-signer.mdcovers 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