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

     1  package node
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/ethereum-optimism/optimism/op-node/metrics"
     9  	"github.com/ethereum-optimism/optimism/op-node/rollup/conductor"
    10  	"github.com/ethereum-optimism/optimism/op-service/dial"
    11  	"github.com/ethereum-optimism/optimism/op-service/eth"
    12  	"github.com/ethereum-optimism/optimism/op-service/retry"
    13  	"github.com/ethereum/go-ethereum/log"
    14  
    15  	conductorRpc "github.com/ethereum-optimism/optimism/op-conductor/rpc"
    16  )
    17  
    18  // ConductorClient is a client for the op-conductor RPC service.
    19  type ConductorClient struct {
    20  	cfg       *Config
    21  	metrics   *metrics.Metrics
    22  	log       log.Logger
    23  	apiClient *conductorRpc.APIClient
    24  }
    25  
    26  var _ conductor.SequencerConductor = &ConductorClient{}
    27  
    28  // NewConductorClient returns a new conductor client for the op-conductor RPC service.
    29  func NewConductorClient(cfg *Config, log log.Logger, metrics *metrics.Metrics) *ConductorClient {
    30  	return &ConductorClient{cfg: cfg, metrics: metrics, log: log}
    31  }
    32  
    33  // Initialize initializes the conductor client.
    34  func (c *ConductorClient) initialize() error {
    35  	if c.apiClient != nil {
    36  		return nil
    37  	}
    38  	conductorRpcClient, err := dial.DialRPCClientWithTimeout(context.Background(), time.Minute*1, c.log, c.cfg.ConductorRpc)
    39  	if err != nil {
    40  		return fmt.Errorf("failed to dial conductor RPC: %w", err)
    41  	}
    42  	c.apiClient = conductorRpc.NewAPIClient(conductorRpcClient)
    43  	return nil
    44  }
    45  
    46  // Leader returns true if this node is the leader sequencer.
    47  func (c *ConductorClient) Leader(ctx context.Context) (bool, error) {
    48  	if err := c.initialize(); err != nil {
    49  		return false, err
    50  	}
    51  	ctx, cancel := context.WithTimeout(ctx, c.cfg.ConductorRpcTimeout)
    52  	defer cancel()
    53  
    54  	isLeader, err := retry.Do(ctx, 2, retry.Fixed(50*time.Millisecond), func() (bool, error) {
    55  		record := c.metrics.RecordRPCClientRequest("conductor_leader")
    56  		result, err := c.apiClient.Leader(ctx)
    57  		record(err)
    58  		return result, err
    59  	})
    60  	return isLeader, err
    61  }
    62  
    63  // CommitUnsafePayload commits an unsafe payload to the conductor log.
    64  func (c *ConductorClient) CommitUnsafePayload(ctx context.Context, payload *eth.ExecutionPayloadEnvelope) error {
    65  	if err := c.initialize(); err != nil {
    66  		return err
    67  	}
    68  	ctx, cancel := context.WithTimeout(ctx, c.cfg.ConductorRpcTimeout)
    69  	defer cancel()
    70  
    71  	// extra bool return value is required for the generic, can be ignored.
    72  	_, err := retry.Do(ctx, 2, retry.Fixed(50*time.Millisecond), func() (bool, error) {
    73  		record := c.metrics.RecordRPCClientRequest("conductor_commitUnsafePayload")
    74  		err := c.apiClient.CommitUnsafePayload(ctx, payload)
    75  		record(err)
    76  		return true, err
    77  	})
    78  	return err
    79  }
    80  
    81  func (c *ConductorClient) Close() {
    82  	if c.apiClient == nil {
    83  		return
    84  	}
    85  	c.apiClient.Close()
    86  	c.apiClient = nil
    87  }