2024-02-20 11:48:28 -06:00
|
|
|
// Copyright 2021 The go-ethereum Authors
|
|
|
|
// This file is part of the go-ethereum library.
|
|
|
|
//
|
|
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2024-02-20 17:24:29 -06:00
|
|
|
// GNU Lesser General Public License for more detailc.
|
2024-02-20 11:48:28 -06:00
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2024-02-20 17:24:29 -06:00
|
|
|
// Package engineclient provides an RPC client for engine API required functionc.
|
2024-02-20 11:48:28 -06:00
|
|
|
package engineclient
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2024-02-20 17:24:29 -06:00
|
|
|
"fmt"
|
2024-02-20 11:48:28 -06:00
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/beacon/engine"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
2024-02-20 17:24:29 -06:00
|
|
|
"github.com/ethereum/go-ethereum/ethclient"
|
2024-02-20 11:48:28 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
// Client is a wrapper around rpc.Client that implements geth-specific functionality.
|
|
|
|
//
|
|
|
|
// If you want to use the standardized Ethereum RPC functionality, use ethclient.Client instead.
|
|
|
|
type Client struct {
|
2024-02-20 17:24:29 -06:00
|
|
|
*ethclient.Client
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// New creates a client that uses the given RPC client.
|
2024-02-20 17:24:29 -06:00
|
|
|
func New(c *ethclient.Client) *Client {
|
2024-02-20 11:48:28 -06:00
|
|
|
return &Client{c}
|
|
|
|
}
|
|
|
|
|
2024-02-20 17:24:29 -06:00
|
|
|
// ExchangeTransitionConfigurationV1 calls the engine_exchangeTransitionConfigurationV1
|
|
|
|
// method via JSON-RPC. This is not really needed anymore, since we are post merge,
|
|
|
|
// but it is still here for reference / completeness sake.
|
|
|
|
func (c *Client) ExchangeTransitionConfigurationV1(
|
|
|
|
ctx context.Context,
|
|
|
|
config engine.TransitionConfigurationV1,
|
|
|
|
) (*engine.TransitionConfigurationV1, error) {
|
|
|
|
result := &engine.TransitionConfigurationV1{}
|
|
|
|
if err := c.Client.Client().CallContext(
|
|
|
|
ctx, result, "engine_exchangeTransitionConfigurationV1", config,
|
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
2024-02-20 11:48:28 -06:00
|
|
|
|
2024-02-20 17:24:29 -06:00
|
|
|
// ExchangeCapabilities calls the engine_exchangeCapabilities method via JSON-RPC.
|
|
|
|
func (c *Client) ExchangeCapabilities(
|
|
|
|
ctx context.Context,
|
|
|
|
capabilities []string,
|
|
|
|
) ([]string, error) {
|
|
|
|
result := make([]string, 0)
|
|
|
|
if err := c.Client.Client().CallContext(
|
|
|
|
ctx, &result, "engine_exchangeCapabilities", &capabilities,
|
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return result, nil
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
2024-02-20 17:24:29 -06:00
|
|
|
// GetClientVersionV1 calls the engine_getClientVersionV1 method via JSON-RPC.
|
|
|
|
func (c *Client) GetClientVersionV1(ctx context.Context) ([]engine.ClientVersionV1, error) {
|
|
|
|
result := make([]engine.ClientVersionV1, 0)
|
|
|
|
if err := c.Client.Client().CallContext(
|
|
|
|
ctx, &result, "engine_getClientVersionV1", nil,
|
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return result, nil
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewPayloadV3 calls the engine_newPayloadV3 method via JSON-RPC.
|
2024-02-20 17:24:29 -06:00
|
|
|
func (c *Client) NewPayloadV3(
|
2024-02-20 11:48:28 -06:00
|
|
|
ctx context.Context, payload *engine.ExecutionPayloadEnvelope,
|
2024-02-20 17:24:29 -06:00
|
|
|
versionedHashes common.Hash, parentBlockRoot common.Hash,
|
2024-02-20 11:48:28 -06:00
|
|
|
) (*engine.PayloadStatusV1, error) {
|
2024-02-20 17:24:29 -06:00
|
|
|
return c.newPayloadWithArgs(ctx, CancunV3, payload, versionedHashes, parentBlockRoot)
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewPayloadV2 calls the engine_newPayloadV2 method via JSON-RPC.
|
2024-02-20 17:24:29 -06:00
|
|
|
func (c *Client) NewPayloadV2(
|
2024-02-20 11:48:28 -06:00
|
|
|
ctx context.Context, payload *engine.ExecutionPayloadEnvelope,
|
|
|
|
) (*engine.PayloadStatusV1, error) {
|
2024-02-20 17:24:29 -06:00
|
|
|
return c.newPayload(ctx, ShanghaiV2, payload)
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewPayloadV1 calls the engine_newPayloadV1 method via JSON-RPC.
|
2024-02-20 17:24:29 -06:00
|
|
|
func (c *Client) NewPayloadV1(
|
2024-02-20 11:48:28 -06:00
|
|
|
ctx context.Context, payload *engine.ExecutionPayloadEnvelope,
|
|
|
|
) (*engine.PayloadStatusV1, error) {
|
2024-02-20 17:24:29 -06:00
|
|
|
return c.newPayload(ctx, ParisV1, payload)
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
2024-02-20 17:24:29 -06:00
|
|
|
// newPayload is a helper function that can call an arbitrary version of the newPayload method.
|
|
|
|
func (c *Client) newPayload(
|
|
|
|
ctx context.Context, version APIVersion, payload *engine.ExecutionPayloadEnvelope,
|
2024-02-20 11:48:28 -06:00
|
|
|
) (*engine.PayloadStatusV1, error) {
|
|
|
|
result := &engine.PayloadStatusV1{}
|
2024-02-20 17:24:29 -06:00
|
|
|
if err := c.Client.Client().CallContext(
|
|
|
|
ctx, &result, fmt.Sprintf("engine_newPayloadV%d", version), payload.ExecutionPayload,
|
2024-02-20 11:48:28 -06:00
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2024-02-20 17:24:29 -06:00
|
|
|
// newPayloadWithArgs is a helper function that can call an arbitrary version of the newPayload method.
|
|
|
|
func (c *Client) newPayloadWithArgs(
|
|
|
|
ctx context.Context, version APIVersion, payload *engine.ExecutionPayloadEnvelope, args ...any,
|
|
|
|
) (*engine.PayloadStatusV1, error) {
|
|
|
|
result := &engine.PayloadStatusV1{}
|
|
|
|
if err := c.Client.Client().CallContext(
|
|
|
|
ctx, &result, fmt.Sprintf("engine_newPayloadV%d", version), payload.ExecutionPayload, args,
|
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ForkchoiceUpdatedV1 calls the engine_forkchoiceUpdatedV1 method via JSON-RPC.
|
|
|
|
func (c *Client) ForkchoiceUpdatedV1(
|
2024-02-20 11:48:28 -06:00
|
|
|
ctx context.Context, state *engine.ForkchoiceStateV1, attrs *engine.PayloadAttributes,
|
|
|
|
) (*ForkchoiceUpdatedResponse, error) {
|
2024-02-20 17:24:29 -06:00
|
|
|
return c.forkchoiceUpdated(ctx, ParisV1, state, attrs)
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// ForkchoiceUpdatedV2 calls the engine_forkchoiceUpdatedV2 method via JSON-RPC.
|
2024-02-20 17:24:29 -06:00
|
|
|
func (c *Client) ForkchoiceUpdatedV2(
|
2024-02-20 11:48:28 -06:00
|
|
|
ctx context.Context, state *engine.ForkchoiceStateV1, attrs *engine.PayloadAttributes,
|
|
|
|
) (*ForkchoiceUpdatedResponse, error) {
|
2024-02-20 17:24:29 -06:00
|
|
|
return c.forkchoiceUpdated(ctx, ShanghaiV2, state, attrs)
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
2024-02-20 17:24:29 -06:00
|
|
|
// ForkchoiceUpdatedV3 calls the engine_forkchoiceUpdatedV3 method via JSON-RPC.
|
|
|
|
func (c *Client) ForkchoiceUpdatedV3(
|
2024-02-20 11:48:28 -06:00
|
|
|
ctx context.Context, state *engine.ForkchoiceStateV1, attrs *engine.PayloadAttributes,
|
|
|
|
) (*ForkchoiceUpdatedResponse, error) {
|
2024-02-20 17:24:29 -06:00
|
|
|
return c.forkchoiceUpdated(ctx, CancunV3, state, attrs)
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// forkchoiceUpdateCall is a helper function to call to any version of the forkchoiceUpdated
|
|
|
|
// method.
|
2024-02-20 17:24:29 -06:00
|
|
|
func (c *Client) forkchoiceUpdated(
|
|
|
|
ctx context.Context, version APIVersion, state *engine.ForkchoiceStateV1, attrs any,
|
2024-02-20 11:48:28 -06:00
|
|
|
) (*ForkchoiceUpdatedResponse, error) {
|
|
|
|
result := &ForkchoiceUpdatedResponse{}
|
|
|
|
|
2024-02-20 17:24:29 -06:00
|
|
|
if err := c.Client.Client().CallContext(
|
|
|
|
ctx, result, fmt.Sprintf("engine_forkchoiceUpdatedV%d", version), state, attrs,
|
2024-02-20 11:48:28 -06:00
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if result.Status == nil {
|
2024-02-20 17:24:29 -06:00
|
|
|
return nil, fmt.Errorf("got nil status in engine_forkchoiceUpdatedV%d", version)
|
2024-02-20 11:48:28 -06:00
|
|
|
} else if result.ValidationError != "" {
|
|
|
|
return nil, errors.New(result.ValidationError)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPayloadV3 calls the engine_getPayloadV3 method via JSON-RPC.
|
2024-02-20 17:24:29 -06:00
|
|
|
func (c *Client) GetPayloadV1(
|
|
|
|
ctx context.Context, payloadID *engine.PayloadID,
|
2024-02-20 11:48:28 -06:00
|
|
|
) (*engine.ExecutionPayloadEnvelope, error) {
|
2024-02-20 17:24:29 -06:00
|
|
|
return c.getPayload(ctx, ParisV1, payloadID)
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPayloadV2 calls the engine_getPayloadV3 method via JSON-RPC.
|
2024-02-20 17:24:29 -06:00
|
|
|
func (c *Client) GetPayloadV2(
|
|
|
|
ctx context.Context, payloadID *engine.PayloadID,
|
2024-02-20 11:48:28 -06:00
|
|
|
) (*engine.ExecutionPayloadEnvelope, error) {
|
2024-02-20 17:24:29 -06:00
|
|
|
return c.getPayload(ctx, ShanghaiV2, payloadID)
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPayloadV3 calls the engine_getPayloadV3 method via JSON-RPC.
|
2024-02-20 17:24:29 -06:00
|
|
|
func (c *Client) GetPayloadV3(
|
|
|
|
ctx context.Context, payloadID *engine.PayloadID,
|
2024-02-20 11:48:28 -06:00
|
|
|
) (*engine.ExecutionPayloadEnvelope, error) {
|
2024-02-20 17:24:29 -06:00
|
|
|
return c.getPayload(ctx, CancunV3, payloadID)
|
2024-02-20 11:48:28 -06:00
|
|
|
}
|
|
|
|
|
2024-02-20 17:24:29 -06:00
|
|
|
// getPayload is a helper function that can call an arbitrary version of the getPayload method.
|
|
|
|
func (c *Client) getPayload(ctx context.Context, version APIVersion, payloadID *engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
|
2024-02-20 11:48:28 -06:00
|
|
|
result := &engine.ExecutionPayloadEnvelope{}
|
2024-02-20 17:24:29 -06:00
|
|
|
if err := c.Client.Client().CallContext(
|
|
|
|
ctx, result, fmt.Sprintf("engine_getPayloadV%d", version), payloadID,
|
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPayloadBodiesByHashV1 calls the engine_getPayloadBodiesByHashV1 method via JSON-RPC.
|
|
|
|
func (c *Client) GetPayloadBodiesByHashV1(
|
|
|
|
ctx context.Context,
|
|
|
|
hashes []common.Hash,
|
|
|
|
) ([]*engine.ExecutionPayloadBodyV1, error) {
|
|
|
|
result := make([]*engine.ExecutionPayloadBodyV1, 0)
|
|
|
|
if err := c.Client.Client().CallContext(
|
|
|
|
ctx, &result, "engine_getPayloadBodiesByHashV1", &hashes,
|
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetPayloadBodiesByRangeV1 calls the engine_getPayloadBodiesByRangeV1 method via JSON-RPC.
|
|
|
|
func (c *Client) GetPayloadBodiesByRangeV1(
|
|
|
|
ctx context.Context, start, count hexutil.Uint64,
|
|
|
|
) ([]*engine.ExecutionPayloadBodyV1, error) {
|
|
|
|
result := make([]*engine.ExecutionPayloadBodyV1, 0)
|
|
|
|
if err := c.Client.Client().CallContext(
|
|
|
|
ctx, &result, "engine_getPayloadBodiesByRangeV1", start, count,
|
2024-02-20 11:48:28 -06:00
|
|
|
); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|