github.com/ethereum-optimism/optimism@v1.7.2/op-node/node/api.go (about) 1 package node 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 8 "github.com/ethereum-optimism/optimism/op-node/node/safedb" 9 "github.com/ethereum/go-ethereum/common" 10 "github.com/ethereum/go-ethereum/common/hexutil" 11 "github.com/ethereum/go-ethereum/log" 12 13 "github.com/ethereum-optimism/optimism/op-node/rollup" 14 "github.com/ethereum-optimism/optimism/op-node/version" 15 "github.com/ethereum-optimism/optimism/op-service/eth" 16 "github.com/ethereum-optimism/optimism/op-service/metrics" 17 "github.com/ethereum-optimism/optimism/op-service/rpc" 18 ) 19 20 type l2EthClient interface { 21 InfoByHash(ctx context.Context, hash common.Hash) (eth.BlockInfo, error) 22 // GetProof returns a proof of the account, it may return a nil result without error if the address was not found. 23 // Optionally keys of the account storage trie can be specified to include with corresponding values in the proof. 24 GetProof(ctx context.Context, address common.Address, storage []common.Hash, blockTag string) (*eth.AccountResult, error) 25 OutputV0AtBlock(ctx context.Context, blockHash common.Hash) (*eth.OutputV0, error) 26 } 27 28 type driverClient interface { 29 SyncStatus(ctx context.Context) (*eth.SyncStatus, error) 30 BlockRefWithStatus(ctx context.Context, num uint64) (eth.L2BlockRef, *eth.SyncStatus, error) 31 ResetDerivationPipeline(context.Context) error 32 StartSequencer(ctx context.Context, blockHash common.Hash) error 33 StopSequencer(context.Context) (common.Hash, error) 34 SequencerActive(context.Context) (bool, error) 35 OnUnsafeL2Payload(ctx context.Context, payload *eth.ExecutionPayloadEnvelope) error 36 } 37 38 type SafeDBReader interface { 39 SafeHeadAtL1(ctx context.Context, l1BlockNum uint64) (l1 eth.BlockID, l2 eth.BlockID, err error) 40 } 41 42 type adminAPI struct { 43 *rpc.CommonAdminAPI 44 dr driverClient 45 } 46 47 func NewAdminAPI(dr driverClient, m metrics.RPCMetricer, log log.Logger) *adminAPI { 48 return &adminAPI{ 49 CommonAdminAPI: rpc.NewCommonAdminAPI(m, log), 50 dr: dr, 51 } 52 } 53 54 func (n *adminAPI) ResetDerivationPipeline(ctx context.Context) error { 55 recordDur := n.M.RecordRPCServerRequest("admin_resetDerivationPipeline") 56 defer recordDur() 57 return n.dr.ResetDerivationPipeline(ctx) 58 } 59 60 func (n *adminAPI) StartSequencer(ctx context.Context, blockHash common.Hash) error { 61 recordDur := n.M.RecordRPCServerRequest("admin_startSequencer") 62 defer recordDur() 63 return n.dr.StartSequencer(ctx, blockHash) 64 } 65 66 func (n *adminAPI) StopSequencer(ctx context.Context) (common.Hash, error) { 67 recordDur := n.M.RecordRPCServerRequest("admin_stopSequencer") 68 defer recordDur() 69 return n.dr.StopSequencer(ctx) 70 } 71 72 func (n *adminAPI) SequencerActive(ctx context.Context) (bool, error) { 73 recordDur := n.M.RecordRPCServerRequest("admin_sequencerActive") 74 defer recordDur() 75 return n.dr.SequencerActive(ctx) 76 } 77 78 // PostUnsafePayload is a special API that allow posting an unsafe payload to the L2 derivation pipeline. 79 // It should only be used by op-conductor for sequencer failover scenarios. 80 // TODO(ethereum-optimism/optimism#9064): op-conductor Dencun changes. 81 func (n *adminAPI) PostUnsafePayload(ctx context.Context, envelope *eth.ExecutionPayloadEnvelope) error { 82 recordDur := n.M.RecordRPCServerRequest("admin_postUnsafePayload") 83 defer recordDur() 84 85 payload := envelope.ExecutionPayload 86 if actual, ok := envelope.CheckBlockHash(); !ok { 87 log.Error("payload has bad block hash", "bad_hash", payload.BlockHash.String(), "actual", actual.String()) 88 return fmt.Errorf("payload has bad block hash: %s, actual block hash is: %s", payload.BlockHash.String(), actual.String()) 89 } 90 91 return n.dr.OnUnsafeL2Payload(ctx, envelope) 92 } 93 94 type nodeAPI struct { 95 config *rollup.Config 96 client l2EthClient 97 dr driverClient 98 safeDB SafeDBReader 99 log log.Logger 100 m metrics.RPCMetricer 101 } 102 103 func NewNodeAPI(config *rollup.Config, l2Client l2EthClient, dr driverClient, safeDB SafeDBReader, log log.Logger, m metrics.RPCMetricer) *nodeAPI { 104 return &nodeAPI{ 105 config: config, 106 client: l2Client, 107 dr: dr, 108 safeDB: safeDB, 109 log: log, 110 m: m, 111 } 112 } 113 114 func (n *nodeAPI) OutputAtBlock(ctx context.Context, number hexutil.Uint64) (*eth.OutputResponse, error) { 115 recordDur := n.m.RecordRPCServerRequest("optimism_outputAtBlock") 116 defer recordDur() 117 118 ref, status, err := n.dr.BlockRefWithStatus(ctx, uint64(number)) 119 if err != nil { 120 return nil, fmt.Errorf("failed to get L2 block ref with sync status: %w", err) 121 } 122 123 output, err := n.client.OutputV0AtBlock(ctx, ref.Hash) 124 if err != nil { 125 return nil, fmt.Errorf("failed to get L2 output at block %s: %w", ref, err) 126 } 127 return ð.OutputResponse{ 128 Version: output.Version(), 129 OutputRoot: eth.OutputRoot(output), 130 BlockRef: ref, 131 WithdrawalStorageRoot: common.Hash(output.MessagePasserStorageRoot), 132 StateRoot: common.Hash(output.StateRoot), 133 Status: status, 134 }, nil 135 } 136 137 func (n *nodeAPI) SafeHeadAtL1Block(ctx context.Context, number hexutil.Uint64) (*eth.SafeHeadResponse, error) { 138 recordDur := n.m.RecordRPCServerRequest("optimism_safeHeadAtL1Block") 139 defer recordDur() 140 l1Block, safeHead, err := n.safeDB.SafeHeadAtL1(ctx, uint64(number)) 141 if errors.Is(err, safedb.ErrNotFound) { 142 return nil, err 143 } else if err != nil { 144 return nil, fmt.Errorf("failed to get safe head at l1 block %s: %w", number, err) 145 } 146 return ð.SafeHeadResponse{ 147 L1Block: l1Block, 148 SafeHead: safeHead, 149 }, nil 150 } 151 152 func (n *nodeAPI) SyncStatus(ctx context.Context) (*eth.SyncStatus, error) { 153 recordDur := n.m.RecordRPCServerRequest("optimism_syncStatus") 154 defer recordDur() 155 return n.dr.SyncStatus(ctx) 156 } 157 158 func (n *nodeAPI) RollupConfig(_ context.Context) (*rollup.Config, error) { 159 recordDur := n.m.RecordRPCServerRequest("optimism_rollupConfig") 160 defer recordDur() 161 return n.config, nil 162 } 163 164 func (n *nodeAPI) Version(ctx context.Context) (string, error) { 165 recordDur := n.m.RecordRPCServerRequest("optimism_version") 166 defer recordDur() 167 return version.Version + "-" + version.Meta, nil 168 }