github.com/ethereum-optimism/optimism@v1.7.2/op-node/node/runtime_config.go (about)

     1  package node
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/ethereum/go-ethereum/common"
     9  	"github.com/ethereum/go-ethereum/log"
    10  	"github.com/ethereum/go-ethereum/params"
    11  
    12  	"github.com/ethereum-optimism/optimism/op-node/p2p"
    13  	"github.com/ethereum-optimism/optimism/op-node/rollup"
    14  	"github.com/ethereum-optimism/optimism/op-service/eth"
    15  )
    16  
    17  var (
    18  	// UnsafeBlockSignerAddressSystemConfigStorageSlot is the storage slot identifier of the unsafeBlockSigner
    19  	// `address` storage value in the SystemConfig L1 contract. Computed as `keccak256("systemconfig.unsafeblocksigner")`
    20  	UnsafeBlockSignerAddressSystemConfigStorageSlot = common.HexToHash("0x65a7ed542fb37fe237fdfbdd70b31598523fe5b32879e307bae27a0bd9581c08")
    21  
    22  	// RequiredProtocolVersionStorageSlot is the storage slot that the required protocol version is stored at.
    23  	// Computed as: `bytes32(uint256(keccak256("protocolversion.required")) - 1)`
    24  	RequiredProtocolVersionStorageSlot = common.HexToHash("0x4aaefe95bd84fd3f32700cf3b7566bc944b73138e41958b5785826df2aecace0")
    25  
    26  	// RecommendedProtocolVersionStorageSlot is the storage slot that the recommended protocol version is stored at.
    27  	// Computed as: `bytes32(uint256(keccak256("protocolversion.recommended")) - 1)`
    28  	RecommendedProtocolVersionStorageSlot = common.HexToHash("0xe314dfc40f0025322aacc0ba8ef420b62fb3b702cf01e0cdf3d829117ac2ff1a")
    29  )
    30  
    31  type RuntimeCfgL1Source interface {
    32  	ReadStorageAt(ctx context.Context, address common.Address, storageSlot common.Hash, blockHash common.Hash) (common.Hash, error)
    33  }
    34  
    35  type ReadonlyRuntimeConfig interface {
    36  	P2PSequencerAddress() common.Address
    37  	RequiredProtocolVersion() params.ProtocolVersion
    38  	RecommendedProtocolVersion() params.ProtocolVersion
    39  }
    40  
    41  // RuntimeConfig maintains runtime-configurable options.
    42  // These options are loaded based on initial loading + updates for every subsequent L1 block.
    43  // Only the *latest* values are maintained however, the runtime config has no concept of chain history,
    44  // does not require any archive data, and may be out of sync with the rollup derivation process.
    45  type RuntimeConfig struct {
    46  	mu sync.RWMutex
    47  
    48  	log log.Logger
    49  
    50  	l1Client  RuntimeCfgL1Source
    51  	rollupCfg *rollup.Config
    52  
    53  	// l1Ref is the current source of the data,
    54  	// if this is invalidated with a reorg the data will have to be reloaded.
    55  	l1Ref eth.L1BlockRef
    56  
    57  	runtimeConfigData
    58  }
    59  
    60  // runtimeConfigData is a flat bundle of configurable data, easy and light to copy around.
    61  type runtimeConfigData struct {
    62  	p2pBlockSignerAddr common.Address
    63  
    64  	// superchain protocol version signals
    65  	recommended params.ProtocolVersion
    66  	required    params.ProtocolVersion
    67  }
    68  
    69  var _ p2p.GossipRuntimeConfig = (*RuntimeConfig)(nil)
    70  
    71  func NewRuntimeConfig(log log.Logger, l1Client RuntimeCfgL1Source, rollupCfg *rollup.Config) *RuntimeConfig {
    72  	return &RuntimeConfig{
    73  		log:       log,
    74  		l1Client:  l1Client,
    75  		rollupCfg: rollupCfg,
    76  	}
    77  }
    78  
    79  func (r *RuntimeConfig) P2PSequencerAddress() common.Address {
    80  	r.mu.RLock()
    81  	defer r.mu.RUnlock()
    82  	return r.p2pBlockSignerAddr
    83  }
    84  
    85  func (r *RuntimeConfig) RequiredProtocolVersion() params.ProtocolVersion {
    86  	r.mu.RLock()
    87  	defer r.mu.RUnlock()
    88  	return r.required
    89  }
    90  
    91  func (r *RuntimeConfig) RecommendedProtocolVersion() params.ProtocolVersion {
    92  	r.mu.RLock()
    93  	defer r.mu.RUnlock()
    94  	return r.recommended
    95  }
    96  
    97  // Load resets the runtime configuration by fetching the latest config data from L1 at the given L1 block.
    98  // Load is safe to call concurrently, but will lock the runtime configuration modifications only,
    99  // and will thus not block other Load calls with possibly alternative L1 block views.
   100  func (r *RuntimeConfig) Load(ctx context.Context, l1Ref eth.L1BlockRef) error {
   101  	p2pSignerVal, err := r.l1Client.ReadStorageAt(ctx, r.rollupCfg.L1SystemConfigAddress, UnsafeBlockSignerAddressSystemConfigStorageSlot, l1Ref.Hash)
   102  	if err != nil {
   103  		return fmt.Errorf("failed to fetch unsafe block signing address from system config: %w", err)
   104  	}
   105  	// The superchain protocol version data is optional; only applicable to rollup configs that specify a ProtocolVersions address.
   106  	var requiredProtVersion, recommendedProtoVersion params.ProtocolVersion
   107  	if r.rollupCfg.ProtocolVersionsAddress != (common.Address{}) {
   108  		requiredVal, err := r.l1Client.ReadStorageAt(ctx, r.rollupCfg.ProtocolVersionsAddress, RequiredProtocolVersionStorageSlot, l1Ref.Hash)
   109  		if err != nil {
   110  			return fmt.Errorf("required-protocol-version value failed to load from L1 contract: %w", err)
   111  		}
   112  		requiredProtVersion = params.ProtocolVersion(requiredVal)
   113  		recommendedVal, err := r.l1Client.ReadStorageAt(ctx, r.rollupCfg.ProtocolVersionsAddress, RecommendedProtocolVersionStorageSlot, l1Ref.Hash)
   114  		if err != nil {
   115  			return fmt.Errorf("recommended-protocol-version value failed to load from L1 contract: %w", err)
   116  		}
   117  		recommendedProtoVersion = params.ProtocolVersion(recommendedVal)
   118  	}
   119  	r.mu.Lock()
   120  	defer r.mu.Unlock()
   121  	r.l1Ref = l1Ref
   122  	r.p2pBlockSignerAddr = common.BytesToAddress(p2pSignerVal[:])
   123  	r.required = requiredProtVersion
   124  	r.recommended = recommendedProtoVersion
   125  	r.log.Info("loaded new runtime config values!", "p2p_seq_address", r.p2pBlockSignerAddr)
   126  	return nil
   127  }