basic tests
This commit is contained in:
parent
95be8c3b67
commit
b946852a66
|
@ -37,9 +37,12 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error {
|
|||
Override *bool `json:"shouldOverrideBuilder"`
|
||||
}
|
||||
var dec ExecutionPayloadEnvelope
|
||||
panic(input)
|
||||
panic("unreachable: generated code should never panic")
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dec.ExecutionPayload == nil {
|
||||
return errors.New("missing required field 'executionPayload' for ExecutionPayloadEnvelope")
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
|
@ -156,6 +157,25 @@ func (b *PayloadID) UnmarshalText(input []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the PayloadIDBytes to hex.
|
||||
// It is required since we can't use struct tags for [8]byte.
|
||||
func (b PayloadID) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(hexutil.Bytes(b[:]))
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals the PayloadID from hex.
|
||||
func (b *PayloadID) UnmarshalJSON(input []byte) error {
|
||||
var dec hexutil.Bytes
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(dec) != len(b) {
|
||||
return fmt.Errorf("invalid payload id %q", dec)
|
||||
}
|
||||
copy(b[:], dec)
|
||||
return nil
|
||||
}
|
||||
|
||||
type ForkChoiceResponse struct {
|
||||
PayloadStatus PayloadStatusV1 `json:"payloadStatus"`
|
||||
PayloadID *PayloadID `json:"payloadId"`
|
||||
|
|
|
@ -77,7 +77,7 @@ const (
|
|||
)
|
||||
|
||||
// All methods provided over the engine endpoint.
|
||||
var caps = []string{
|
||||
var Caps = []string{
|
||||
"engine_forkchoiceUpdatedV1",
|
||||
"engine_forkchoiceUpdatedV2",
|
||||
"engine_forkchoiceUpdatedV3",
|
||||
|
@ -813,7 +813,7 @@ func (api *ConsensusAPI) heartbeat() {
|
|||
|
||||
// ExchangeCapabilities returns the current methods provided by this node.
|
||||
func (api *ConsensusAPI) ExchangeCapabilities([]string) []string {
|
||||
return caps
|
||||
return Caps
|
||||
}
|
||||
|
||||
// GetClientVersionV1 exchanges client version data of this node.
|
||||
|
|
|
@ -9,124 +9,162 @@
|
|||
// 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
|
||||
// GNU Lesser General Public License for more details.
|
||||
// GNU Lesser General Public License for more detailc.
|
||||
//
|
||||
// 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/>.
|
||||
|
||||
// Package engineclient provides an RPC client for engine API required functions.
|
||||
// Package engineclient provides an RPC client for engine API required functionc.
|
||||
package engineclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
c *rpc.Client
|
||||
*ethclient.Client
|
||||
}
|
||||
|
||||
// New creates a client that uses the given RPC client.
|
||||
func New(c *rpc.Client) *Client {
|
||||
func New(c *ethclient.Client) *Client {
|
||||
return &Client{c}
|
||||
}
|
||||
|
||||
// PayloadIDBytes defines a custom type for Payload IDs used by the engine API
|
||||
// client with proper JSON Marshal and Unmarshal methods to hex.
|
||||
type PayloadIDBytes [8]byte
|
||||
|
||||
// MarshalJSON --
|
||||
func (b PayloadIDBytes) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(hexutil.Bytes(b[:]))
|
||||
}
|
||||
|
||||
// ForkchoiceUpdatedResponse is the response kind received by the
|
||||
// engine_forkchoiceUpdatedV1 endpoint.
|
||||
type ForkchoiceUpdatedResponse struct {
|
||||
Status *engine.PayloadStatusV1 `json:"payloadStatus"`
|
||||
PayloadId *PayloadIDBytes `json:"payloadId"`
|
||||
ValidationError string `json:"validationError"`
|
||||
}
|
||||
|
||||
// NewPayloadV3 calls the engine_newPayloadV3 method via JSON-RPC.
|
||||
func (s *Client) NewPayloadV3(
|
||||
ctx context.Context, payload *engine.ExecutionPayloadEnvelope,
|
||||
versionedHashes []common.Hash, parentBlockRoot *common.Hash,
|
||||
) (*engine.PayloadStatusV1, error) {
|
||||
return s.newPayload(ctx, "engine_newPayloadV3", payload, versionedHashes, parentBlockRoot)
|
||||
}
|
||||
|
||||
// NewPayloadV2 calls the engine_newPayloadV2 method via JSON-RPC.
|
||||
func (s *Client) NewPayloadV2(
|
||||
ctx context.Context, payload *engine.ExecutionPayloadEnvelope,
|
||||
) (*engine.PayloadStatusV1, error) {
|
||||
return s.newPayload(ctx, "engine_newPayloadV2", payload)
|
||||
}
|
||||
|
||||
// NewPayloadV1 calls the engine_newPayloadV1 method via JSON-RPC.
|
||||
func (s *Client) NewPayloadV1(
|
||||
ctx context.Context, payload *engine.ExecutionPayloadEnvelope,
|
||||
) (*engine.PayloadStatusV1, error) {
|
||||
return s.newPayload(ctx, "engine_newPayloadV1", payload)
|
||||
}
|
||||
|
||||
func (s *Client) newPayload(
|
||||
ctx context.Context, method string, payload *engine.ExecutionPayloadEnvelope, args ...any,
|
||||
) (*engine.PayloadStatusV1, error) {
|
||||
result := &engine.PayloadStatusV1{}
|
||||
if err := s.c.CallContext(
|
||||
ctx, result, method, payload, args,
|
||||
// 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
|
||||
}
|
||||
|
||||
// ForkchoiceUpdatedV3 calls the engine_forkchoiceUpdatedV3 method via JSON-RPC.
|
||||
func (s *Client) ForkchoiceUpdatedV3(
|
||||
ctx context.Context, state *engine.ForkchoiceStateV1, attrs *engine.PayloadAttributes,
|
||||
) (*ForkchoiceUpdatedResponse, error) {
|
||||
return s.forkchoiceUpdated(ctx, "engine_forkchoiceUpdatedV3", state, attrs)
|
||||
// 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
|
||||
}
|
||||
|
||||
// ForkchoiceUpdatedV2 calls the engine_forkchoiceUpdatedV2 method via JSON-RPC.
|
||||
func (s *Client) ForkchoiceUpdatedV2(
|
||||
ctx context.Context, state *engine.ForkchoiceStateV1, attrs *engine.PayloadAttributes,
|
||||
) (*ForkchoiceUpdatedResponse, error) {
|
||||
return s.forkchoiceUpdated(ctx, "engine_forkchoiceUpdatedV2", state, attrs)
|
||||
// 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
|
||||
}
|
||||
|
||||
// NewPayloadV3 calls the engine_newPayloadV3 method via JSON-RPC.
|
||||
func (c *Client) NewPayloadV3(
|
||||
ctx context.Context, payload *engine.ExecutionPayloadEnvelope,
|
||||
versionedHashes common.Hash, parentBlockRoot common.Hash,
|
||||
) (*engine.PayloadStatusV1, error) {
|
||||
return c.newPayloadWithArgs(ctx, CancunV3, payload, versionedHashes, parentBlockRoot)
|
||||
}
|
||||
|
||||
// NewPayloadV2 calls the engine_newPayloadV2 method via JSON-RPC.
|
||||
func (c *Client) NewPayloadV2(
|
||||
ctx context.Context, payload *engine.ExecutionPayloadEnvelope,
|
||||
) (*engine.PayloadStatusV1, error) {
|
||||
return c.newPayload(ctx, ShanghaiV2, payload)
|
||||
}
|
||||
|
||||
// NewPayloadV1 calls the engine_newPayloadV1 method via JSON-RPC.
|
||||
func (c *Client) NewPayloadV1(
|
||||
ctx context.Context, payload *engine.ExecutionPayloadEnvelope,
|
||||
) (*engine.PayloadStatusV1, error) {
|
||||
return c.newPayload(ctx, ParisV1, payload)
|
||||
}
|
||||
|
||||
// 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,
|
||||
) (*engine.PayloadStatusV1, error) {
|
||||
result := &engine.PayloadStatusV1{}
|
||||
if err := c.Client.Client().CallContext(
|
||||
ctx, &result, fmt.Sprintf("engine_newPayloadV%d", version), payload.ExecutionPayload,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 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 (s *Client) ForkchoiceUpdatedV1(
|
||||
func (c *Client) ForkchoiceUpdatedV1(
|
||||
ctx context.Context, state *engine.ForkchoiceStateV1, attrs *engine.PayloadAttributes,
|
||||
) (*ForkchoiceUpdatedResponse, error) {
|
||||
return s.forkchoiceUpdated(ctx, "engine_forkchoiceUpdatedV1", state, attrs)
|
||||
return c.forkchoiceUpdated(ctx, ParisV1, state, attrs)
|
||||
}
|
||||
|
||||
// ForkchoiceUpdatedV2 calls the engine_forkchoiceUpdatedV2 method via JSON-RPC.
|
||||
func (c *Client) ForkchoiceUpdatedV2(
|
||||
ctx context.Context, state *engine.ForkchoiceStateV1, attrs *engine.PayloadAttributes,
|
||||
) (*ForkchoiceUpdatedResponse, error) {
|
||||
return c.forkchoiceUpdated(ctx, ShanghaiV2, state, attrs)
|
||||
}
|
||||
|
||||
// ForkchoiceUpdatedV3 calls the engine_forkchoiceUpdatedV3 method via JSON-RPC.
|
||||
func (c *Client) ForkchoiceUpdatedV3(
|
||||
ctx context.Context, state *engine.ForkchoiceStateV1, attrs *engine.PayloadAttributes,
|
||||
) (*ForkchoiceUpdatedResponse, error) {
|
||||
return c.forkchoiceUpdated(ctx, CancunV3, state, attrs)
|
||||
}
|
||||
|
||||
// forkchoiceUpdateCall is a helper function to call to any version of the forkchoiceUpdated
|
||||
// method.
|
||||
func (s *Client) forkchoiceUpdated(
|
||||
ctx context.Context, method string, state *engine.ForkchoiceStateV1, attrs any,
|
||||
func (c *Client) forkchoiceUpdated(
|
||||
ctx context.Context, version APIVersion, state *engine.ForkchoiceStateV1, attrs any,
|
||||
) (*ForkchoiceUpdatedResponse, error) {
|
||||
result := &ForkchoiceUpdatedResponse{}
|
||||
|
||||
if err := s.c.CallContext(
|
||||
ctx, result, method, state, attrs,
|
||||
if err := c.Client.Client().CallContext(
|
||||
ctx, result, fmt.Sprintf("engine_forkchoiceUpdatedV%d", version), state, attrs,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.Status == nil {
|
||||
return nil, errors.New("got nil status in" + method)
|
||||
return nil, fmt.Errorf("got nil status in engine_forkchoiceUpdatedV%d", version)
|
||||
} else if result.ValidationError != "" {
|
||||
return nil, errors.New(result.ValidationError)
|
||||
}
|
||||
|
@ -135,30 +173,58 @@ func (s *Client) forkchoiceUpdated(
|
|||
}
|
||||
|
||||
// GetPayloadV3 calls the engine_getPayloadV3 method via JSON-RPC.
|
||||
func (s *Client) GetPayloadV3(
|
||||
ctx context.Context, payloadID PayloadIDBytes,
|
||||
func (c *Client) GetPayloadV1(
|
||||
ctx context.Context, payloadID *engine.PayloadID,
|
||||
) (*engine.ExecutionPayloadEnvelope, error) {
|
||||
return s.getPayload(ctx, "engine_getPayloadV3", payloadID)
|
||||
return c.getPayload(ctx, ParisV1, payloadID)
|
||||
}
|
||||
|
||||
// GetPayloadV2 calls the engine_getPayloadV3 method via JSON-RPC.
|
||||
func (s *Client) GetPayloadV2(
|
||||
ctx context.Context, payloadID PayloadIDBytes,
|
||||
func (c *Client) GetPayloadV2(
|
||||
ctx context.Context, payloadID *engine.PayloadID,
|
||||
) (*engine.ExecutionPayloadEnvelope, error) {
|
||||
return s.getPayload(ctx, "engine_getPayloadV2", payloadID)
|
||||
return c.getPayload(ctx, ShanghaiV2, payloadID)
|
||||
}
|
||||
|
||||
// GetPayloadV3 calls the engine_getPayloadV3 method via JSON-RPC.
|
||||
func (s *Client) GetPayloadV1(
|
||||
ctx context.Context, payloadID PayloadIDBytes,
|
||||
func (c *Client) GetPayloadV3(
|
||||
ctx context.Context, payloadID *engine.PayloadID,
|
||||
) (*engine.ExecutionPayloadEnvelope, error) {
|
||||
return s.getPayload(ctx, "engine_getPayloadV1", payloadID)
|
||||
return c.getPayload(ctx, CancunV3, payloadID)
|
||||
}
|
||||
|
||||
func (s *Client) getPayload(ctx context.Context, method string, payloadID PayloadIDBytes) (*engine.ExecutionPayloadEnvelope, error) {
|
||||
// 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) {
|
||||
result := &engine.ExecutionPayloadEnvelope{}
|
||||
if err := s.c.CallContext(
|
||||
ctx, result, method, payloadID,
|
||||
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,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
package engineclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/eth/catalyst"
|
||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var (
|
||||
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
|
||||
testBalance = big.NewInt(2e15)
|
||||
)
|
||||
|
||||
var genesis = &core.Genesis{
|
||||
Config: params.AllEthashProtocolChanges,
|
||||
Alloc: types.GenesisAlloc{testAddr: {Balance: testBalance}},
|
||||
ExtraData: []byte("test genesis"),
|
||||
Timestamp: 9000,
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
|
||||
var testTx1 = types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &types.LegacyTx{
|
||||
Nonce: 0,
|
||||
Value: big.NewInt(12),
|
||||
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||
Gas: params.TxGas,
|
||||
To: &common.Address{2},
|
||||
})
|
||||
|
||||
var testTx2 = types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &types.LegacyTx{
|
||||
Nonce: 1,
|
||||
Value: big.NewInt(8),
|
||||
GasPrice: big.NewInt(params.InitialBaseFee),
|
||||
Gas: params.TxGas,
|
||||
To: &common.Address{2},
|
||||
})
|
||||
|
||||
func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
|
||||
// Generate test chain.
|
||||
blocks := generateTestChain()
|
||||
|
||||
// Create node
|
||||
n, err := node.New(&node.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("can't create new node: %v", err)
|
||||
}
|
||||
// Create Ethereum Service
|
||||
config := ðconfig.Config{Genesis: genesis}
|
||||
ethservice, err := eth.New(n, config)
|
||||
if err != nil {
|
||||
t.Fatalf("can't create new ethereum service: %v", err)
|
||||
}
|
||||
|
||||
// Register the engine api namespace.
|
||||
catalyst.Register(n, ethservice)
|
||||
|
||||
// Import the test chain.
|
||||
if err := n.Start(); err != nil {
|
||||
t.Fatalf("can't start test node: %v", err)
|
||||
}
|
||||
if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil {
|
||||
t.Fatalf("can't import test blocks: %v", err)
|
||||
}
|
||||
// Ensure the tx indexing is fully generated
|
||||
for ; ; time.Sleep(time.Millisecond * 100) {
|
||||
progress, err := ethservice.BlockChain().TxIndexProgress()
|
||||
if err == nil && progress.Done() {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n, blocks
|
||||
}
|
||||
|
||||
func generateTestChain() []*types.Block {
|
||||
generate := func(i int, g *core.BlockGen) {
|
||||
g.OffsetTime(5)
|
||||
g.SetExtra([]byte("test"))
|
||||
if i == 1 {
|
||||
// Test transactions are included in block #2.
|
||||
g.AddTx(testTx1)
|
||||
g.AddTx(testTx2)
|
||||
}
|
||||
}
|
||||
_, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 2, generate)
|
||||
return append([]*types.Block{genesis.ToBlock()}, blocks...)
|
||||
}
|
||||
|
||||
func TestEngineClient(t *testing.T) {
|
||||
backend, chain := newTestBackend(t)
|
||||
client := New(ethclient.NewClient(backend.Attach()))
|
||||
defer backend.Close()
|
||||
defer client.Close()
|
||||
|
||||
tests := map[string]struct {
|
||||
test func(t *testing.T)
|
||||
}{
|
||||
"ExchangeCapabilities": {
|
||||
func(t *testing.T) { testExchangeCapabilities(t, chain, client) },
|
||||
},
|
||||
"GetClientVersionV1": {
|
||||
func(t *testing.T) { testGetClientV1(t, chain, client) },
|
||||
},
|
||||
"GetPayloadBodiesByHashV1": {
|
||||
func(t *testing.T) { testGetPayloadBodiesByHashV1(t, chain, client) },
|
||||
},
|
||||
"GetPayloadBodiesByRangeV1": {
|
||||
func(t *testing.T) { testGetPayloadBodiesByRangeV1(t, chain, client) },
|
||||
},
|
||||
"NewPayloadV1": {
|
||||
func(t *testing.T) { testNewPayloadV1(t, chain, client) },
|
||||
},
|
||||
"NewPayloadV2": {
|
||||
func(t *testing.T) { testNewPayloadV2(t, chain, client) },
|
||||
},
|
||||
"NewPayloadV3": {
|
||||
func(t *testing.T) { testNewPayloadV3(t, chain, client) },
|
||||
},
|
||||
"ForkchoiceUpdatedV1": {
|
||||
func(t *testing.T) { testForkchoiceUpdatedV1(t, chain, client) },
|
||||
},
|
||||
"ForkchoiceUpdatedV2": {
|
||||
func(t *testing.T) { testForkchoiceUpdatedV2(t, chain, client) },
|
||||
},
|
||||
"ForkchoiceUpdatedV3": {
|
||||
func(t *testing.T) { testForkchoiceUpdatedV3(t, chain, client) },
|
||||
},
|
||||
"GetPayloadV3": {
|
||||
func(t *testing.T) { testGetPayloadV3(t, chain, client) },
|
||||
},
|
||||
"GetPayloadV2": {
|
||||
func(t *testing.T) { testGetPayloadV2(t, chain, client) },
|
||||
},
|
||||
"GetPayloadV1": {
|
||||
func(t *testing.T) { testGetPayloadV1(t, chain, client) },
|
||||
},
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
for name, tt := range tests {
|
||||
t.Run(name, tt.test)
|
||||
}
|
||||
}
|
||||
func testExchangeCapabilities(t *testing.T, chain []*types.Block, client *Client) {
|
||||
expected := catalyst.Caps
|
||||
capabilities := []string{"random", "ignored", "strings"}
|
||||
actual, err := client.ExchangeCapabilities(context.Background(), capabilities)
|
||||
if err != nil {
|
||||
t.Fatalf("ExchangeCapabilitiesV1 failed: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Fatalf("Expected capabilities %v, got %v", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetClientV1(t *testing.T, chain []*types.Block, client *Client) {
|
||||
actual, err := client.GetClientVersionV1(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("GetClientVersionV1 failed: %v", err)
|
||||
}
|
||||
if !strings.Contains(fmt.Sprint(actual), "go-ethereum") {
|
||||
t.Fatalf("Expected go-ethereum client version, got %v", actual)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetPayloadBodiesByHashV1(t *testing.T, chain []*types.Block, client *Client) {
|
||||
actual, err := client.GetPayloadBodiesByHashV1(context.Background(), []common.Hash{chain[2].Hash()})
|
||||
if err != nil {
|
||||
t.Fatalf("GetPayloadBodiesByHashV1 failed: %v", err)
|
||||
}
|
||||
if len(actual) != 1 {
|
||||
t.Fatalf("Expected 1 payload body, got %v", actual)
|
||||
}
|
||||
|
||||
if actual[0].TransactionData == nil {
|
||||
t.Fatalf("Expected payload body, got %v", actual[0])
|
||||
}
|
||||
|
||||
tx := &types.Transaction{}
|
||||
if err := tx.UnmarshalBinary(actual[0].TransactionData[0]); err != nil {
|
||||
t.Fatalf("Failed to unmarshal transaction: %v", err)
|
||||
}
|
||||
if tx.Hash() != testTx1.Hash() {
|
||||
t.Fatalf("Expected transaction %v, got %v", testTx1, tx)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetPayloadBodiesByRangeV1(t *testing.T, chain []*types.Block, client *Client) {
|
||||
actual, err := client.GetPayloadBodiesByRangeV1(context.Background(), hexutil.Uint64(chain[2].NumberU64()), hexutil.Uint64(1))
|
||||
if err != nil {
|
||||
t.Fatalf("GetPayloadBodiesByRangeV1 failed: %v", err)
|
||||
}
|
||||
if len(actual) != 1 {
|
||||
t.Fatalf("Expected 1 payload body, got %v", len(actual))
|
||||
}
|
||||
|
||||
if actual[0].TransactionData == nil {
|
||||
t.Fatalf("Expected payload body, got %v", actual[0])
|
||||
}
|
||||
|
||||
tx := &types.Transaction{}
|
||||
fmt.Println(actual[0].TransactionData)
|
||||
tx.UnmarshalBinary(actual[0].TransactionData[0])
|
||||
if tx.Hash() != testTx1.Hash() {
|
||||
t.Fatalf("Expected transaction %v, got %v", testTx1, tx)
|
||||
}
|
||||
}
|
||||
|
||||
func testNewPayloadV1(t *testing.T, chain []*types.Block, client *Client) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a mock payload
|
||||
payload := createMockPayload(chain[len(chain)-1])
|
||||
|
||||
// Call NewPayloadV1
|
||||
status, err := client.NewPayloadV1(ctx, payload)
|
||||
if err != nil {
|
||||
t.Fatalf("NewPayloadV1 failed: %v", err)
|
||||
}
|
||||
if status.Status != engine.INVALID {
|
||||
t.Fatalf("Expected payload status to be INVALID, got %v", status.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func testNewPayloadV2(t *testing.T, chain []*types.Block, client *Client) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a mock payload
|
||||
payload := createMockPayload(chain[len(chain)-1])
|
||||
|
||||
// Call NewPayloadV1
|
||||
status, err := client.NewPayloadV1(ctx, payload)
|
||||
if err != nil {
|
||||
t.Fatalf("NewPayloadV1 failed: %v", err)
|
||||
}
|
||||
if status.Status != engine.INVALID {
|
||||
t.Fatalf("Expected payload status to be INVALID, got %v", status.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func testNewPayloadV3(t *testing.T, chain []*types.Block, client *Client) {
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a mock payload
|
||||
payload := createMockPayload(chain[len(chain)-1])
|
||||
|
||||
// Call NewPayloadV1
|
||||
status, err := client.NewPayloadV1(ctx, payload)
|
||||
if err != nil {
|
||||
t.Fatalf("NewPayloadV1 failed: %v", err)
|
||||
}
|
||||
if status.Status != engine.INVALID {
|
||||
t.Fatalf("Expected payload status to be INVALID, got %v", status.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func createMockPayload(parent *types.Block) *engine.ExecutionPayloadEnvelope {
|
||||
// Assuming createMockPayload creates and returns a mock ExecutionPayloadEnvelope
|
||||
// This is a placeholder for actual payload creation code
|
||||
return &engine.ExecutionPayloadEnvelope{
|
||||
ExecutionPayload: &engine.ExecutableData{
|
||||
ParentHash: parent.Hash(),
|
||||
BlockHash: common.BytesToHash(crypto.Keccak256([]byte("randomBlockHash"))),
|
||||
FeeRecipient: common.BytesToAddress(crypto.Keccak256([]byte("randomFeeRecipient"))),
|
||||
StateRoot: common.BytesToHash(crypto.Keccak256([]byte("randomStateRoot"))),
|
||||
ReceiptsRoot: common.BytesToHash(crypto.Keccak256([]byte("randomReceiptsRoot"))),
|
||||
LogsBloom: crypto.Keccak256([]byte("randomLogsBloom")),
|
||||
Random: common.BytesToHash(crypto.Keccak256([]byte("random"))),
|
||||
Number: parent.NumberU64() + 1,
|
||||
GasLimit: 21000,
|
||||
GasUsed: 10500,
|
||||
Timestamp: 1630425600,
|
||||
ExtraData: []byte("randomExtraData"),
|
||||
BaseFeePerGas: big.NewInt(1000000000),
|
||||
Transactions: [][]byte{
|
||||
crypto.Keccak256([]byte("randomTransaction1")),
|
||||
crypto.Keccak256([]byte("randomTransaction2"))},
|
||||
}}
|
||||
}
|
||||
|
||||
func testForkchoiceUpdatedV1(t *testing.T, chain []*types.Block, client *Client) {
|
||||
// Call ForkchoiceUpdatedV2
|
||||
resp, err := client.ForkchoiceUpdatedV1(context.Background(), &engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: common.Hash{},
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("ForkchoiceUpdatedV2 failed: %v", err)
|
||||
}
|
||||
if resp.Status == nil {
|
||||
t.Fatalf("Expected status, got %v", resp.Status)
|
||||
}
|
||||
|
||||
if resp.Status.Status != engine.INVALID {
|
||||
t.Fatalf("Expected status to be INVALID, got %v", resp.Status.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func testForkchoiceUpdatedV2(t *testing.T, chain []*types.Block, client *Client) {
|
||||
// Call ForkchoiceUpdatedV2
|
||||
resp, err := client.ForkchoiceUpdatedV2(context.Background(), &engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: common.Hash{},
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("ForkchoiceUpdatedV2 failed: %v", err)
|
||||
}
|
||||
if resp.Status == nil {
|
||||
t.Fatalf("Expected status, got %v", resp.Status)
|
||||
}
|
||||
|
||||
if resp.Status.Status != engine.INVALID {
|
||||
t.Fatalf("Expected status to be INVALID, got %v", resp.Status.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func testForkchoiceUpdatedV3(t *testing.T, chain []*types.Block, client *Client) {
|
||||
// Call ForkchoiceUpdatedV3
|
||||
resp, err := client.ForkchoiceUpdatedV3(context.Background(), &engine.ForkchoiceStateV1{
|
||||
HeadBlockHash: common.Hash{},
|
||||
}, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("ForkchoiceUpdatedV3 failed: %v", err)
|
||||
}
|
||||
if resp.Status == nil {
|
||||
t.Fatalf("Expected status, got %v", resp.Status)
|
||||
}
|
||||
|
||||
if resp.Status.Status != engine.INVALID {
|
||||
t.Fatalf("Expected status to be INVALID, got %v", resp.Status.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetPayloadV3(t *testing.T, chain []*types.Block, client *Client) {
|
||||
payloadID := engine.PayloadID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} // Example PayloadID, adjust as necessary
|
||||
_, err := client.GetPayloadV3(context.Background(), &payloadID)
|
||||
if err.Error() != "Unsupported fork" {
|
||||
t.Fatalf("GetPayloadV3 failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetPayloadV2(t *testing.T, chain []*types.Block, client *Client) {
|
||||
payloadID := engine.PayloadID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} // Example PayloadID, adjust as necessary
|
||||
_, err := client.GetPayloadV2(context.Background(), &payloadID)
|
||||
if err.Error() != "Unknown payload" {
|
||||
t.Fatalf("Expected unknown payload error, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func testGetPayloadV1(t *testing.T, chain []*types.Block, client *Client) {
|
||||
payloadID := engine.PayloadID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} // Example PayloadID, adjust as necessary
|
||||
_, err := client.GetPayloadV1(context.Background(), &payloadID)
|
||||
if err.Error() != "Unknown payload" {
|
||||
t.Fatalf("Expected unknown payload error, got: %v", err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package engineclient
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
)
|
||||
|
||||
// APIVersion is a custom type for the engine API version.
|
||||
type APIVersion int
|
||||
|
||||
const (
|
||||
Phase0 APIVersion = iota
|
||||
ParisV1
|
||||
ShanghaiV2
|
||||
CancunV3
|
||||
)
|
||||
|
||||
// ForkchoiceUpdatedResponse is the response kind received by the
|
||||
// engine_forkchoiceUpdatedV1 endpoint.
|
||||
type ForkchoiceUpdatedResponse struct {
|
||||
Status *engine.PayloadStatusV1 `json:"payloadStatus"`
|
||||
PayloadId *engine.PayloadID `json:"payloadId"`
|
||||
ValidationError string `json:"validationError"`
|
||||
}
|
|
@ -28,9 +28,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
// Temporary to get engineclient to compile for testing. Will remove
|
||||
_ "github.com/ethereum/go-ethereum/ethclient/engineclient"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
|
|
|
@ -43029,7 +43029,7 @@
|
|||
"29272a63": "BBP()",
|
||||
"29274fe1": "buyBOTx(uint256,string,string,address,uint256)",
|
||||
"2927989f": "bet(bool,address,uint256)",
|
||||
"29287ad0": "releaseTheRest()",
|
||||
"29287ad0": "releToEtherest()",
|
||||
"29287edb": "calRebase()",
|
||||
"2928859c": "runsOutOfGas()",
|
||||
"29291054": "setContract(address,address,address)",
|
||||
|
@ -82005,7 +82005,7 @@
|
|||
"4e06c968": "changeDragonDen()",
|
||||
"4e07008d": "mintWithEther(address,uint256)",
|
||||
"4e070f50": "tokenDecaySupplyForWeek(uint256)",
|
||||
"4e077f2a": "addGasEther()",
|
||||
"4e077f2a": "addGToEther()",
|
||||
"4e07a7a5": "thirdStageMinted()",
|
||||
"4e083278": "depositPrize()",
|
||||
"4e0853db": "_setVAIVaultInfo(address,uint256,uint256)",
|
||||
|
|
Loading…
Reference in New Issue