api.go 4.81 KB
Newer Older
1 2 3 4 5 6
package node

import (
	"context"
	"fmt"

7 8 9 10
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
	"github.com/ethereum/go-ethereum/log"

11
	"github.com/ethereum-optimism/optimism/op-node/rollup"
12
	"github.com/ethereum-optimism/optimism/op-node/version"
13
	"github.com/ethereum-optimism/optimism/op-service/eth"
14
	oplog "github.com/ethereum-optimism/optimism/op-service/log"
15 16 17
)

type l2EthClient interface {
18
	InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error)
19
	// GetProof returns a proof of the account, it may return a nil result without error if the address was not found.
20 21
	// Optionally keys of the account storage trie can be specified to include with corresponding values in the proof.
	GetProof(ctx context.Context, address common.Address, storage []common.Hash, blockTag string) (*eth.AccountResult, error)
22
	OutputV0AtBlock(ctx context.Context, blockHash common.Hash) (*eth.OutputV0, error)
23 24
}

25
type driverClient interface {
26
	SyncStatus(ctx context.Context) (*eth.SyncStatus, error)
27
	BlockRefWithStatus(ctx context.Context, num uint64) (eth.L2BlockRef, *eth.SyncStatus, error)
28
	ResetDerivationPipeline(context.Context) error
29 30
	StartSequencer(ctx context.Context, blockHash common.Hash) error
	StopSequencer(context.Context) (common.Hash, error)
31
	SequencerActive(context.Context) (bool, error)
32 33
}

34 35 36 37 38
type rpcMetrics interface {
	// RecordRPCServerRequest returns a function that records the duration of serving the given RPC method
	RecordRPCServerRequest(method string) func()
}

39
type adminAPI struct {
40 41 42
	dr  driverClient
	m   rpcMetrics
	log log.Logger
43 44
}

45
func NewAdminAPI(dr driverClient, m rpcMetrics, log log.Logger) *adminAPI {
46
	return &adminAPI{
47 48 49
		dr:  dr,
		m:   m,
		log: log,
50 51 52 53 54 55 56
	}
}

func (n *adminAPI) ResetDerivationPipeline(ctx context.Context) error {
	recordDur := n.m.RecordRPCServerRequest("admin_resetDerivationPipeline")
	defer recordDur()
	return n.dr.ResetDerivationPipeline(ctx)
57 58
}

59
func (n *adminAPI) StartSequencer(ctx context.Context, blockHash common.Hash) error {
60 61
	recordDur := n.m.RecordRPCServerRequest("admin_startSequencer")
	defer recordDur()
62
	return n.dr.StartSequencer(ctx, blockHash)
63 64
}

65
func (n *adminAPI) StopSequencer(ctx context.Context) (common.Hash, error) {
66 67 68 69 70
	recordDur := n.m.RecordRPCServerRequest("admin_stopSequencer")
	defer recordDur()
	return n.dr.StopSequencer(ctx)
}

71 72 73 74 75 76
func (n *adminAPI) SequencerActive(ctx context.Context) (bool, error) {
	recordDur := n.m.RecordRPCServerRequest("admin_sequencerActive")
	defer recordDur()
	return n.dr.SequencerActive(ctx)
}

77
func (n *adminAPI) SetLogLevel(ctx context.Context, lvlStr string) error {
78 79
	recordDur := n.m.RecordRPCServerRequest("admin_setLogLevel")
	defer recordDur()
80 81 82 83 84 85 86 87

	h := n.log.GetHandler()

	lvl, err := log.LvlFromString(lvlStr)
	if err != nil {
		return err
	}

88 89 90 91 92 93 94
	// We set the log level, and do not wrap the handler with an additional filter handler,
	// as the underlying handler would otherwise also still filter with the previous log level.
	lvlSetter, ok := h.(oplog.LvlSetter)
	if !ok {
		return fmt.Errorf("log handler type %T cannot change log level", h)
	}
	lvlSetter.SetLogLevel(lvl)
95
	return nil
96 97
}

98 99 100
type nodeAPI struct {
	config *rollup.Config
	client l2EthClient
101
	dr     driverClient
102
	log    log.Logger
103
	m      rpcMetrics
104 105
}

106
func NewNodeAPI(config *rollup.Config, l2Client l2EthClient, dr driverClient, log log.Logger, m rpcMetrics) *nodeAPI {
107 108 109
	return &nodeAPI{
		config: config,
		client: l2Client,
110
		dr:     dr,
111
		log:    log,
112
		m:      m,
113 114 115
	}
}

116
func (n *nodeAPI) OutputAtBlock(ctx context.Context, number hexutil.Uint64) (*eth.OutputResponse, error) {
117 118
	recordDur := n.m.RecordRPCServerRequest("optimism_outputAtBlock")
	defer recordDur()
119

120
	ref, status, err := n.dr.BlockRefWithStatus(ctx, uint64(number))
121
	if err != nil {
122 123 124
		return nil, fmt.Errorf("failed to get L2 block ref with sync status: %w", err)
	}

125
	output, err := n.client.OutputV0AtBlock(ctx, ref.Hash)
126
	if err != nil {
127
		return nil, fmt.Errorf("failed to get L2 output at block %s: %w", ref, err)
128
	}
129
	return &eth.OutputResponse{
130 131
		Version:               output.Version(),
		OutputRoot:            eth.OutputRoot(output),
132
		BlockRef:              ref,
133 134
		WithdrawalStorageRoot: common.Hash(output.MessagePasserStorageRoot),
		StateRoot:             common.Hash(output.StateRoot),
135 136
		Status:                status,
	}, nil
137 138
}

139
func (n *nodeAPI) SyncStatus(ctx context.Context) (*eth.SyncStatus, error) {
140 141
	recordDur := n.m.RecordRPCServerRequest("optimism_syncStatus")
	defer recordDur()
142 143 144
	return n.dr.SyncStatus(ctx)
}

145 146 147 148 149 150
func (n *nodeAPI) RollupConfig(_ context.Context) (*rollup.Config, error) {
	recordDur := n.m.RecordRPCServerRequest("optimism_rollupConfig")
	defer recordDur()
	return n.config, nil
}

151
func (n *nodeAPI) Version(ctx context.Context) (string, error) {
152 153
	recordDur := n.m.RecordRPCServerRequest("optimism_version")
	defer recordDur()
154 155
	return version.Version + "-" + version.Meta, nil
}