Skip to content

op-node: add FETCH_WITHDRAWAL_ROOT_FROM_STATE config var #15150

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 4, 2025
8 changes: 8 additions & 0 deletions op-node/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ var (
EnvVars: prefixEnvVars("RPC_ADMIN_STATE"),
Category: OperationsCategory,
}
FetchWithdrawalRootFromState = &cli.BoolFlag{
Name: "fetch-withdrawal-root-from-state",
Usage: "Read withdrawal_storage_root (aka message passer storage root) from state trie (via execution layer) instead of the block header. Restores pre-Isthmus behavior, requires an archive EL client.",
Required: false,
EnvVars: prefixEnvVars("FETCH_WITHDRAWAL_ROOT_FROM_STATE"),
Category: OperationsCategory,
}
L1TrustRPC = &cli.BoolFlag{
Name: "l1.trustrpc",
Usage: "Trust the L1 RPC, sync faster at risk of malicious/buggy RPC providing bad or inconsistent L1 data",
Expand Down Expand Up @@ -451,6 +458,7 @@ var optionalFlags = []cli.Flag{
BeaconCheckIgnore,
BeaconFetchAllSidecars,
SyncModeFlag,
FetchWithdrawalRootFromState,
RPCListenAddr,
RPCListenPort,
L1TrustRPC,
Expand Down
1 change: 1 addition & 0 deletions op-node/node/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type Config struct {
AltDA altda.CLIConfig

IgnoreMissingPectraBlobSchedule bool
FetchWithdrawalRootFromState bool
}

// ConductorRPCFunc retrieves the endpoint. The RPC may not immediately be available.
Expand Down
2 changes: 2 additions & 0 deletions op-node/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ func (n *OpNode) initL2(ctx context.Context, cfg *Config) error {
return fmt.Errorf("failed to setup L2 execution-engine RPC client: %w", err)
}

rpcCfg.FetchWithdrawalRootFromState = cfg.FetchWithdrawalRootFromState

n.l2Source, err = sources.NewEngineClient(rpcClient, n.log, n.metrics.L2SourceCache, rpcCfg)
if err != nil {
return fmt.Errorf("failed to create Engine client: %w", err)
Expand Down
1 change: 1 addition & 0 deletions op-node/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) {
AltDA: altda.ReadCLIConfig(ctx),

IgnoreMissingPectraBlobSchedule: ctx.Bool(flags.IgnoreMissingPectraBlobSchedule.Name),
FetchWithdrawalRootFromState: ctx.Bool(flags.FetchWithdrawalRootFromState.Name),
}

if err := cfg.LoadPersisted(log); err != nil {
Expand Down
23 changes: 15 additions & 8 deletions op-service/sources/l2_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import (
type L2ClientConfig struct {
EthClientConfig

L2BlockRefsCacheSize int
L1ConfigsCacheSize int
L2BlockRefsCacheSize int
L1ConfigsCacheSize int
FetchWithdrawalRootFromState bool

RollupCfg *rollup.Config
}
Expand Down Expand Up @@ -75,6 +76,8 @@ type L2Client struct {
// cache SystemConfig by L2 hash
// common.Hash -> eth.SystemConfig
systemConfigsCache *caching.LRUCache[common.Hash, eth.SystemConfig]

fetchWithdrawalRootFromState bool
}

var _ apis.L2EthExtendedClient = (*L2Client)(nil)
Expand All @@ -89,10 +92,11 @@ func NewL2Client(client client.RPC, log log.Logger, metrics caching.Metrics, con
}

return &L2Client{
EthClient: ethClient,
rollupCfg: config.RollupCfg,
l2BlockRefsCache: caching.NewLRUCache[common.Hash, eth.L2BlockRef](metrics, "blockrefs", config.L2BlockRefsCacheSize),
systemConfigsCache: caching.NewLRUCache[common.Hash, eth.SystemConfig](metrics, "systemconfigs", config.L1ConfigsCacheSize),
EthClient: ethClient,
rollupCfg: config.RollupCfg,
l2BlockRefsCache: caching.NewLRUCache[common.Hash, eth.L2BlockRef](metrics, "blockrefs", config.L2BlockRefsCacheSize),
systemConfigsCache: caching.NewLRUCache[common.Hash, eth.SystemConfig](metrics, "systemconfigs", config.L1ConfigsCacheSize),
fetchWithdrawalRootFromState: config.FetchWithdrawalRootFromState,
}, nil
}

Expand Down Expand Up @@ -197,11 +201,14 @@ func (s *L2Client) outputV0(ctx context.Context, block eth.BlockInfo) (*eth.Outp

blockHash := block.Hash()
var messagePasserStorageRoot eth.Bytes32
if s.rollupCfg.IsIsthmus(block.Time()) {
// If Isthmus hard fork has activated, we can get the messagePasserStorageRoot directly from the header
if s.rollupCfg.IsIsthmus(block.Time()) && !s.fetchWithdrawalRootFromState {
s.log.Debug("Retrieving withdrawal root from block header")
// If Isthmus hard fork has activated, we can get the withdrawal root directly from the header
// instead of having to compute it from the contract storage trie.
messagePasserStorageRoot = eth.Bytes32(*block.WithdrawalsRoot())

} else {
s.log.Debug("Bypassing block header, retrieving withdrawal root from state")
proof, err := s.GetProof(ctx, predeploys.L2ToL1MessagePasserAddr, []common.Hash{}, blockHash.String())
if err != nil {
return nil, fmt.Errorf("failed to get contract proof at block %s: %w", blockHash, err)
Expand Down