Skip to content
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ Flags:

- `--external-builder`: URL of an external builder to use (enables rollup-boost)
- `--enable-latest-fork` (int): Enables the latest fork (jovian) at startup (0) or n blocks after genesis.
- `--proxyd`: Enable proxyd for routing `eth_sendRawTransaction` (and bundle methods) to ingress RPC while routing other methods to standard execution layer
- `--ingress-rpc <service-name>`: Specify the service name for the ingress RPC endpoint (default: "ingress-rpc")
- `--proxyd-ingress-methods <methods>`: Additional RPC methods to route to ingress (comma-separated)
- `--proxyd-standard-methods <methods>`: Additional RPC methods to route to standard EL (comma-separated)

Note: When `--flashblocks` is enabled, proxyd automatically routes `base_meter*` methods (base_meterBundle, base_meterBlockByHash, base_meterBlockByNumber, base_meteredPriorityFeePerGas) to flashblocks-rpc.

### Example Commands

Expand Down
138 changes: 137 additions & 1 deletion playground/artifacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ type ArtifactsBuilder struct {
// Extra files to copy to artifacts (artifactName -> sourcePath)
extraFiles map[string]string
predeploysFile string

// Proxyd options
proxydEnabled bool
proxydIngressURL string
proxydStandardURL string
proxydIngressMethods []string
proxydStandardMethods []string
}

func NewArtifactsBuilder() *ArtifactsBuilder {
Expand Down Expand Up @@ -184,6 +191,23 @@ func (b *ArtifactsBuilder) PredeployFile(filePath string) *ArtifactsBuilder {
return b
}

func (b *ArtifactsBuilder) WithProxyd(ingressURL, standardURL string) *ArtifactsBuilder {
b.proxydEnabled = true
b.proxydIngressURL = ingressURL
b.proxydStandardURL = standardURL
return b
}

func (b *ArtifactsBuilder) ProxydIngressMethods(methods []string) *ArtifactsBuilder {
b.proxydIngressMethods = methods
return b
}

func (b *ArtifactsBuilder) ProxydStandardMethods(methods []string) *ArtifactsBuilder {
b.proxydStandardMethods = methods
return b
}

func (b *ArtifactsBuilder) loadPredeploys() (types.GenesisAlloc, error) {
if b.predeploysFile == "" {
return types.GenesisAlloc{}, nil
Expand Down Expand Up @@ -420,7 +444,7 @@ func (b *ArtifactsBuilder) Build(out *output) error {
}
}

// Copy extra files from recipe directory
// Copy extra files from recipe directory
for artifactName, sourcePath := range b.extraFiles {
data, err := os.ReadFile(sourcePath)
if err != nil {
Expand All @@ -431,6 +455,13 @@ func (b *ArtifactsBuilder) Build(out *output) error {
}
}

// Generate proxyd config if enabled
if b.proxydEnabled {
if err := b.GenerateProxydConfig(out, b.proxydIngressURL, b.proxydStandardURL); err != nil {
return err
}
}

return nil
}

Expand Down Expand Up @@ -846,3 +877,108 @@ func appendPredeploysToAlloc(allocs *types.GenesisAlloc, predeploys types.Genesi
}
return nil
}

// GenerateProxydConfig generates proxyd TOML configuration for routing RPC methods
func (b *ArtifactsBuilder) GenerateProxydConfig(out *output, ingressURL, standardELURL string) error {
// Build additional method mappings
var additionalMappings string
for _, method := range b.proxydIngressMethods {
additionalMappings += fmt.Sprintf("%s = \"ingress\"\n", method)
}
for _, method := range b.proxydStandardMethods {
additionalMappings += fmt.Sprintf("%s = \"standard\"\n", method)
}

config := fmt.Sprintf(`[server]
rpc_host = "0.0.0.0"
rpc_port = 8545

[backend]
response_timeout_seconds = 30
max_response_size_bytes = 5242880

[backends]
[backends.ingress]
rpc_url = "%s"

[backends.standard]
rpc_url = "%s"

[backend_groups]
[backend_groups.ingress]
backends = ["ingress"]

[backend_groups.standard]
backends = ["standard"]

[rpc_method_mappings]
# Transaction submission methods routed to ingress
eth_sendRawTransaction = "ingress"
eth_sendBundle = "ingress"
eth_sendBackrunBundle = "ingress"
eth_cancelBundle = "ingress"
eth_sendUserOperation = "ingress"

# All other methods routed to standard EL
eth_getBlockByHash = "standard"
eth_getBlockByNumber = "standard"
eth_getBlockTransactionCountByHash = "standard"
eth_getBlockTransactionCountByNumber = "standard"
eth_getUncleCountByBlockHash = "standard"
eth_getUncleCountByBlockNumber = "standard"
eth_chainId = "standard"
eth_syncing = "standard"
eth_coinbase = "standard"
eth_accounts = "standard"
eth_blockNumber = "standard"
eth_call = "standard"
eth_estimateGas = "standard"
eth_createAccessList = "standard"
eth_gasPrice = "standard"
eth_maxPriorityFeePerGas = "standard"
eth_blobBaseFee = "standard"
eth_feeHistory = "standard"
eth_newFilter = "standard"
eth_newBlockFilter = "standard"
eth_newPendingTransactionFilter = "standard"
eth_uninstallFilter = "standard"
eth_getFilterChanges = "standard"
eth_getFilterLogs = "standard"
eth_getLogs = "standard"
eth_mining = "standard"
eth_hashrate = "standard"
eth_getWork = "standard"
eth_submitWork = "standard"
eth_submitHashrate = "standard"
eth_sign = "standard"
eth_signTransaction = "standard"
eth_getBalance = "standard"
eth_getStorageAt = "standard"
eth_getTransactionCount = "standard"
eth_getCode = "standard"
eth_getProof = "standard"
eth_getTransactionByHash = "standard"
eth_getTransactionByBlockHashAndIndex = "standard"
eth_getTransactionByBlockNumberAndIndex = "standard"
eth_getTransactionReceipt = "standard"
net_version = "standard"
web3_clientVersion = "standard"
web3_sha3 = "standard"
debug_getRawHeader = "standard"
debug_getRawBlock = "standard"
debug_getRawTransaction = "standard"
debug_getRawReceipts = "standard"
debug_getBadBlocks = "standard"

# Base-specific RPC methods
base_transactionStatus = "standard"
base_meterBundle = "standard"
base_meterBlockByHash = "standard"
base_meterBlockByNumber = "standard"
base_meteredPriorityFeePerGas = "standard"

# Additional custom method mappings
%s`, ingressURL, standardELURL, additionalMappings)

return out.WriteFile("proxyd-config.toml", config)
}
29 changes: 29 additions & 0 deletions playground/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ type WebsocketProxy struct {
func (w *WebsocketProxy) Apply(ctx *ExContext) *Component {
component := NewComponent("webproxy")

// NOTE: The mikawamp/websocket-rpc image is amd64-only.
// For other architectures, build from https://github.com/flashbots/rollup-boost with:
// docker build --build-arg SERVICE_NAME=flashblocks-websocket-proxy -t websocket-proxy:<tag> .
// and use: --override websocket-proxy=websocket-proxy:<tag>
component.NewService("websocket-proxy").
WithImage("docker.io/mikawamp/websocket-rpc").
WithTag("latest").
Expand Down Expand Up @@ -622,6 +626,31 @@ func (c *ClProxy) Apply(ctx *ExContext) *Component {
return component
}

type Proxyd struct {
IngressRPC string // URL for ingress RPC (e.g., "http://ingress-rpc:8080")
StandardEL string // URL for standard EL (e.g., "http://op-geth:8545")
}

func (p *Proxyd) Apply(ctx *ExContext) *Component {
component := NewComponent("proxyd")

// NOTE: The upstream OP Labs proxyd image is amd64-only.
// For other architectures, build from https://github.com/ethereum-optimism/infra with:
// docker build -t proxyd:<tag> -f proxyd/Dockerfile .
// and use: --override proxyd=proxyd:<tag>
component.NewService("proxyd").
WithImage("us-docker.pkg.dev/oplabs-tools-artifacts/images/proxyd").
WithTag("latest").
WithArgs(
"/bin/proxyd",
"/config/proxyd.toml",
).
WithArtifact("/config/proxyd.toml", "proxyd-config.toml").
WithPort("http", 8545)

return component
}

type MevBoostRelay struct {
BeaconClient string
ValidationServer string
Expand Down
Loading
Loading