Skip to content

Commit

Permalink
simulators/ethereum/engine: Engine API Cancun (#759)
Browse files Browse the repository at this point in the history
* simulators/ethereum/engine: Cancun blob test suite

* simulators/ethereum/engine: don't populate empty fields

* simulators/ethereum/engine: modify types, remove beacon root from payload

* simulators/ethereum/engine: add beacon root tests

* simulators/ethereum/engine:use custom geth branch

* simulators/ethereum/engine: beaconRoot everywhere

* simulators/ethereum/engine: Add 1 wei to 4788 stateful precompile

* simulators/ethereum: go.work.sum

* simulators/ethereum/engine: update geth version

* simulators/ethereum/engine: add beacon root to genesis

* simulators/ethereum/engine: fix clmock method versions usage

* simulators/ethereum/engine: refactor

* simulators/ethereum/engine: Fix expectations on some tests, and print expectation on output

* simulators/ethereum/engine: Fix no beacon root on modified payloads

* simulators/ethereum/engine: Enable blob tx receipts checks

* simulators/ethereum/engine: Test case description improvements

* simulators/ethereum/engine: Fix blob gas used check

* simulators/ethereum/engine: Blob -> Cancun

* simulators/ethereum: Fixes for pyspec sim
  • Loading branch information
marioevz authored Aug 3, 2023
1 parent cc8977d commit 6399870
Show file tree
Hide file tree
Showing 40 changed files with 5,376 additions and 1,280 deletions.
36 changes: 19 additions & 17 deletions simulators/ethereum/engine/client/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"

client_types "github.com/ethereum/hive/simulators/ethereum/engine/client/types"
typ "github.com/ethereum/hive/simulators/ethereum/engine/types"
)

type Eth interface {
Expand All @@ -20,8 +19,8 @@ type Eth interface {
BlockNumber(ctx context.Context) (uint64, error)
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
SendTransaction(ctx context.Context, tx *types.Transaction) error
SendTransactions(ctx context.Context, txs []*types.Transaction) []error
SendTransaction(ctx context.Context, tx typ.Transaction) error
SendTransactions(ctx context.Context, txs ...typ.Transaction) []error
StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error)
StorageAtKeys(ctx context.Context, account common.Address, keys []common.Hash, blockNumber *big.Int) (map[common.Hash]*common.Hash, error)
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error)
Expand All @@ -30,23 +29,25 @@ type Eth interface {
}

type Engine interface {
ForkchoiceUpdatedV1(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *api.PayloadAttributes) (api.ForkChoiceResponse, error)
ForkchoiceUpdatedV2(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *api.PayloadAttributes) (api.ForkChoiceResponse, error)
ForkchoiceUpdated(ctx context.Context, version int, fcState *api.ForkchoiceStateV1, pAttributes *api.PayloadAttributes) (api.ForkChoiceResponse, error)
ForkchoiceUpdatedV1(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes) (api.ForkChoiceResponse, error)
ForkchoiceUpdatedV2(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes) (api.ForkChoiceResponse, error)
ForkchoiceUpdatedV3(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes) (api.ForkChoiceResponse, error)
ForkchoiceUpdated(ctx context.Context, version int, fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes) (api.ForkChoiceResponse, error)

GetPayloadV1(ctx context.Context, payloadId *api.PayloadID) (api.ExecutableData, error)
GetPayloadV2(ctx context.Context, payloadId *api.PayloadID) (api.ExecutableData, *big.Int, error)
GetPayloadV1(ctx context.Context, payloadId *api.PayloadID) (typ.ExecutableData, error)
GetPayloadV2(ctx context.Context, payloadId *api.PayloadID) (typ.ExecutableData, *big.Int, error)
GetPayloadV3(ctx context.Context, payloadId *api.PayloadID) (typ.ExecutableData, *big.Int, *typ.BlobsBundle, error)

NewPayload(ctx context.Context, version int, payload interface{}, versionedHashes []common.Hash) (api.PayloadStatusV1, error)
NewPayloadV1(ctx context.Context, payload *client_types.ExecutableDataV1) (api.PayloadStatusV1, error)
NewPayloadV2(ctx context.Context, payload *api.ExecutableData) (api.PayloadStatusV1, error)
NewPayloadV3(ctx context.Context, payload *api.ExecutableData, versionedHashes []common.Hash) (api.PayloadStatusV1, error)
NewPayload(ctx context.Context, version int, payload interface{}, versionedHashes *[]common.Hash, beaconRoot *common.Hash) (api.PayloadStatusV1, error)
NewPayloadV1(ctx context.Context, payload *typ.ExecutableDataV1) (api.PayloadStatusV1, error)
NewPayloadV2(ctx context.Context, payload *typ.ExecutableData) (api.PayloadStatusV1, error)
NewPayloadV3(ctx context.Context, payload *typ.ExecutableData, versionedHashes *[]common.Hash, beaconRoot *common.Hash) (api.PayloadStatusV1, error)

GetPayloadBodiesByRangeV1(ctx context.Context, start uint64, count uint64) ([]*client_types.ExecutionPayloadBodyV1, error)
GetPayloadBodiesByHashV1(ctx context.Context, hashes []common.Hash) ([]*client_types.ExecutionPayloadBodyV1, error)
GetPayloadBodiesByRangeV1(ctx context.Context, start uint64, count uint64) ([]*typ.ExecutionPayloadBodyV1, error)
GetPayloadBodiesByHashV1(ctx context.Context, hashes []common.Hash) ([]*typ.ExecutionPayloadBodyV1, error)

LatestForkchoiceSent() (fcState *api.ForkchoiceStateV1, pAttributes *api.PayloadAttributes)
LatestNewPayloadSent() (payload *api.ExecutableData)
LatestForkchoiceSent() (fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes)
LatestNewPayloadSent() (payload *typ.ExecutableData)

LatestForkchoiceResponse() (fcuResponse *api.ForkChoiceResponse)
LatestNewPayloadResponse() (payloadResponse *api.PayloadStatusV1)
Expand All @@ -59,6 +60,7 @@ type EngineClient interface {
EnodeURL() (string, error)

// Local Test Account Management
GetLastAccountNonce(testCtx context.Context, account common.Address) (uint64, error)
GetNextAccountNonce(testCtx context.Context, account common.Address) (uint64, error)
UpdateNonce(testCtx context.Context, account common.Address, newNonce uint64) error

Expand Down
135 changes: 102 additions & 33 deletions simulators/ethereum/engine/client/hive_rpc/hive_rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net"
"net/http"
"strings"
"sync"
"time"

"github.com/ethereum/go-ethereum"
Expand All @@ -20,9 +21,9 @@ import (
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/hive/hivesim"
"github.com/ethereum/hive/simulators/ethereum/engine/client"
client_types "github.com/ethereum/hive/simulators/ethereum/engine/client/types"
"github.com/ethereum/hive/simulators/ethereum/engine/globals"
"github.com/ethereum/hive/simulators/ethereum/engine/helper"
typ "github.com/ethereum/hive/simulators/ethereum/engine/types"
"github.com/golang-jwt/jwt/v4"
"github.com/pkg/errors"
)
Expand All @@ -37,6 +38,8 @@ type HiveRPCEngineStarter struct {
JWTSecret []byte
}

var _ client.EngineStarter = (*HiveRPCEngineStarter)(nil)

func (s HiveRPCEngineStarter) StartClient(T *hivesim.T, testContext context.Context, genesis *core.Genesis, ClientParams hivesim.Params, ClientFiles hivesim.Params, bootClients ...client.EngineClient) (client.EngineClient, error) {
var (
clientType = s.ClientType
Expand Down Expand Up @@ -156,16 +159,19 @@ type HiveRPCEngineClient struct {

// Engine updates info
latestFcUStateSent *api.ForkchoiceStateV1
latestPAttrSent *api.PayloadAttributes
latestPAttrSent *typ.PayloadAttributes
latestFcUResponse *api.ForkChoiceResponse

latestPayloadSent *api.ExecutableData
latestPayloadSent *typ.ExecutableData
latestPayloadStatusReponse *api.PayloadStatusV1

// Test account nonces
accTxInfoMap map[common.Address]*AccountTransactionInfo
accTxInfoMap map[common.Address]*AccountTransactionInfo
accTxInfoMapLock sync.Mutex
}

var _ client.EngineClient = (*HiveRPCEngineClient)(nil)

// NewClient creates a engine client that uses the given RPC client.
func NewHiveRPCEngineClient(h *hivesim.Client, enginePort int, ethPort int, jwtSecretBytes []byte, ttd *big.Int, transport http.RoundTripper) *HiveRPCEngineClient {
// Prepare HTTP Client
Expand Down Expand Up @@ -330,7 +336,9 @@ func (ec *HiveRPCEngineClient) PrepareDefaultAuthCallToken() error {
}

// Engine API Call Methods
func (ec *HiveRPCEngineClient) ForkchoiceUpdated(ctx context.Context, version int, fcState *api.ForkchoiceStateV1, pAttributes *api.PayloadAttributes) (api.ForkChoiceResponse, error) {

// Forkchoice Updated API Calls
func (ec *HiveRPCEngineClient) ForkchoiceUpdated(ctx context.Context, version int, fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes) (api.ForkChoiceResponse, error) {
var result api.ForkChoiceResponse
if err := ec.PrepareDefaultAuthCallToken(); err != nil {
return result, err
Expand All @@ -346,52 +354,66 @@ func (ec *HiveRPCEngineClient) ForkchoiceUpdated(ctx context.Context, version in
return result, err
}

func (ec *HiveRPCEngineClient) ForkchoiceUpdatedV1(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *api.PayloadAttributes) (api.ForkChoiceResponse, error) {
func (ec *HiveRPCEngineClient) ForkchoiceUpdatedV1(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes) (api.ForkChoiceResponse, error) {
return ec.ForkchoiceUpdated(ctx, 1, fcState, pAttributes)
}

func (ec *HiveRPCEngineClient) ForkchoiceUpdatedV2(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *api.PayloadAttributes) (api.ForkChoiceResponse, error) {
func (ec *HiveRPCEngineClient) ForkchoiceUpdatedV2(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes) (api.ForkChoiceResponse, error) {
return ec.ForkchoiceUpdated(ctx, 2, fcState, pAttributes)
}

func (ec *HiveRPCEngineClient) GetPayload(ctx context.Context, version int, payloadId *api.PayloadID) (api.ExecutableData, *big.Int, error) {
func (ec *HiveRPCEngineClient) ForkchoiceUpdatedV3(ctx context.Context, fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes) (api.ForkChoiceResponse, error) {
return ec.ForkchoiceUpdated(ctx, 3, fcState, pAttributes)
}

// Get Payload API Calls

func (ec *HiveRPCEngineClient) GetPayload(ctx context.Context, version int, payloadId *api.PayloadID) (typ.ExecutableData, *big.Int, *typ.BlobsBundle, error) {
var (
executableData api.ExecutableData
executableData typ.ExecutableData
blockValue *big.Int
blobsBundle *typ.BlobsBundle
err error
rpcString = fmt.Sprintf("engine_getPayloadV%d", version)
)

if err = ec.PrepareDefaultAuthCallToken(); err != nil {
return executableData, nil, err
return executableData, nil, nil, err
}

if version == 2 {
var response api.ExecutionPayloadEnvelope
if version >= 2 {
var response typ.ExecutionPayloadEnvelope
err = ec.c.CallContext(ctx, &response, rpcString, payloadId)
if response.ExecutionPayload != nil {
executableData = *response.ExecutionPayload
}
blockValue = response.BlockValue
blobsBundle = response.BlobsBundle
} else {
err = ec.c.CallContext(ctx, &executableData, rpcString, payloadId)
}

return executableData, blockValue, err
return executableData, blockValue, blobsBundle, err
}

func (ec *HiveRPCEngineClient) GetPayloadV1(ctx context.Context, payloadId *api.PayloadID) (api.ExecutableData, error) {
ed, _, err := ec.GetPayload(ctx, 1, payloadId)
func (ec *HiveRPCEngineClient) GetPayloadV1(ctx context.Context, payloadId *api.PayloadID) (typ.ExecutableData, error) {
ed, _, _, err := ec.GetPayload(ctx, 1, payloadId)
return ed, err
}

func (ec *HiveRPCEngineClient) GetPayloadV2(ctx context.Context, payloadId *api.PayloadID) (api.ExecutableData, *big.Int, error) {
return ec.GetPayload(ctx, 2, payloadId)
func (ec *HiveRPCEngineClient) GetPayloadV2(ctx context.Context, payloadId *api.PayloadID) (typ.ExecutableData, *big.Int, error) {
ed, bv, _, err := ec.GetPayload(ctx, 2, payloadId)
return ed, bv, err
}

func (ec *HiveRPCEngineClient) GetPayloadV3(ctx context.Context, payloadId *api.PayloadID) (typ.ExecutableData, *big.Int, *typ.BlobsBundle, error) {
return ec.GetPayload(ctx, 3, payloadId)
}

func (ec *HiveRPCEngineClient) GetPayloadBodiesByRangeV1(ctx context.Context, start uint64, count uint64) ([]*client_types.ExecutionPayloadBodyV1, error) {
// Get Payload Bodies API Calls
func (ec *HiveRPCEngineClient) GetPayloadBodiesByRangeV1(ctx context.Context, start uint64, count uint64) ([]*typ.ExecutionPayloadBodyV1, error) {
var (
result []*client_types.ExecutionPayloadBodyV1
result []*typ.ExecutionPayloadBodyV1
err error
)
if err = ec.PrepareDefaultAuthCallToken(); err != nil {
Expand All @@ -402,9 +424,9 @@ func (ec *HiveRPCEngineClient) GetPayloadBodiesByRangeV1(ctx context.Context, st
return result, err
}

func (ec *HiveRPCEngineClient) GetPayloadBodiesByHashV1(ctx context.Context, hashes []common.Hash) ([]*client_types.ExecutionPayloadBodyV1, error) {
func (ec *HiveRPCEngineClient) GetPayloadBodiesByHashV1(ctx context.Context, hashes []common.Hash) ([]*typ.ExecutionPayloadBodyV1, error) {
var (
result []*client_types.ExecutionPayloadBodyV1
result []*typ.ExecutionPayloadBodyV1
err error
)
if err = ec.PrepareDefaultAuthCallToken(); err != nil {
Expand All @@ -415,35 +437,52 @@ func (ec *HiveRPCEngineClient) GetPayloadBodiesByHashV1(ctx context.Context, has
return result, err
}

func (ec *HiveRPCEngineClient) NewPayload(ctx context.Context, version int, payload interface{}, versionedHashes []common.Hash) (result api.PayloadStatusV1, err error) {
// Get Blob Bundle API Calls
func (ec *HiveRPCEngineClient) GetBlobsBundleV1(ctx context.Context, payloadId *api.PayloadID) (*typ.BlobsBundle, error) {
var (
result typ.BlobsBundle
err error
)
if err = ec.PrepareDefaultAuthCallToken(); err != nil {
return nil, err
}

err = ec.c.CallContext(ctx, &result, "engine_getBlobsBundleV1", payloadId)
return &result, err
}

// New Payload API Call Methods
func (ec *HiveRPCEngineClient) NewPayload(ctx context.Context, version int, payload interface{}, versionedHashes *[]common.Hash, beaconRoot *common.Hash) (result api.PayloadStatusV1, err error) {
if err := ec.PrepareDefaultAuthCallToken(); err != nil {
return result, err
}

if versionedHashes != nil {
err = ec.c.CallContext(ctx, &result, fmt.Sprintf("engine_newPayloadV%d", version), payload, versionedHashes)
if version >= 3 {
err = ec.c.CallContext(ctx, &result, fmt.Sprintf("engine_newPayloadV%d", version), payload, versionedHashes, beaconRoot)
} else {
err = ec.c.CallContext(ctx, &result, fmt.Sprintf("engine_newPayloadV%d", version), payload)
}
ec.latestPayloadStatusReponse = &result
return result, err
}

func (ec *HiveRPCEngineClient) NewPayloadV1(ctx context.Context, payload *client_types.ExecutableDataV1) (api.PayloadStatusV1, error) {
func (ec *HiveRPCEngineClient) NewPayloadV1(ctx context.Context, payload *typ.ExecutableDataV1) (api.PayloadStatusV1, error) {
ed := payload.ToExecutableData()
ec.latestPayloadSent = &ed
return ec.NewPayload(ctx, 1, payload, nil)
return ec.NewPayload(ctx, 1, payload, nil, nil)
}

func (ec *HiveRPCEngineClient) NewPayloadV2(ctx context.Context, payload *api.ExecutableData) (api.PayloadStatusV1, error) {
func (ec *HiveRPCEngineClient) NewPayloadV2(ctx context.Context, payload *typ.ExecutableData) (api.PayloadStatusV1, error) {
ec.latestPayloadSent = payload
return ec.NewPayload(ctx, 2, payload, nil)
return ec.NewPayload(ctx, 2, payload, nil, nil)
}

func (ec *HiveRPCEngineClient) NewPayloadV3(ctx context.Context, payload *api.ExecutableData, versionedHashes []common.Hash) (api.PayloadStatusV1, error) {
func (ec *HiveRPCEngineClient) NewPayloadV3(ctx context.Context, payload *typ.ExecutableData, versionedHashes *[]common.Hash, beaconRoot *common.Hash) (api.PayloadStatusV1, error) {
ec.latestPayloadSent = payload
return ec.NewPayload(ctx, 3, payload, versionedHashes)
return ec.NewPayload(ctx, 3, payload, versionedHashes, beaconRoot)
}

// Exchange Transition Configuration API Call Methods
func (ec *HiveRPCEngineClient) ExchangeTransitionConfigurationV1(ctx context.Context, tConf *api.TransitionConfigurationV1) (api.TransitionConfigurationV1, error) {
var result api.TransitionConfigurationV1
err := ec.c.CallContext(ctx, &result, "engine_exchangeTransitionConfigurationV1", tConf)
Expand All @@ -459,6 +498,26 @@ func (ec *HiveRPCEngineClient) ExchangeCapabilities(ctx context.Context, clCapab
return result, err
}

// Account Nonce
func (ec *HiveRPCEngineClient) GetLastAccountNonce(testCtx context.Context, account common.Address) (uint64, error) {
// First get the current head of the client where we will send the tx
ctx, cancel := context.WithTimeout(testCtx, globals.RPCTimeout)
defer cancel()
head, err := ec.HeaderByNumber(ctx, nil)
if err != nil {
return 0, err
}

// Then check if we have any info about this account, and when it was last updated
if accTxInfo, ok := ec.accTxInfoMap[account]; ok && accTxInfo != nil && (accTxInfo.PreviousBlock == head.Hash() || accTxInfo.PreviousBlock == head.ParentHash) {
// We have info about this account and is up to date (or up to date until the very last block).
// Return the previous nonce
return accTxInfo.PreviousNonce, nil
}
// We don't have info about this account, so there is no previous nonce
return 0, fmt.Errorf("no previous nonce for account %s", account.String())
}

func (ec *HiveRPCEngineClient) GetNextAccountNonce(testCtx context.Context, account common.Address) (uint64, error) {
// First get the current head of the client where we will send the tx
ctx, cancel := context.WithTimeout(testCtx, globals.RPCTimeout)
Expand All @@ -482,6 +541,8 @@ func (ec *HiveRPCEngineClient) GetNextAccountNonce(testCtx context.Context, acco
if err != nil {
return 0, err
}
ec.accTxInfoMapLock.Lock()
defer ec.accTxInfoMapLock.Unlock()
ec.accTxInfoMap[account] = &AccountTransactionInfo{
PreviousBlock: head.Hash(),
PreviousNonce: nonce,
Expand All @@ -504,7 +565,15 @@ func (ec *HiveRPCEngineClient) UpdateNonce(testCtx context.Context, account comm
return nil
}

func (ec *HiveRPCEngineClient) SendTransactions(ctx context.Context, txs []*types.Transaction) []error {
func (ec *HiveRPCEngineClient) SendTransaction(ctx context.Context, tx typ.Transaction) error {
data, err := tx.MarshalBinary()
if err != nil {
return err
}
return ec.cEth.CallContext(ctx, nil, "eth_sendRawTransaction", hexutil.Encode(data))
}

func (ec *HiveRPCEngineClient) SendTransactions(ctx context.Context, txs ...typ.Transaction) []error {
reqs := make([]rpc.BatchElem, len(txs))
hashes := make([]common.Hash, len(txs))
for i := range reqs {
Expand Down Expand Up @@ -534,11 +603,11 @@ func (ec *HiveRPCEngineClient) PostRunVerifications() error {
return nil
}

func (ec *HiveRPCEngineClient) LatestForkchoiceSent() (fcState *api.ForkchoiceStateV1, pAttributes *api.PayloadAttributes) {
func (ec *HiveRPCEngineClient) LatestForkchoiceSent() (fcState *api.ForkchoiceStateV1, pAttributes *typ.PayloadAttributes) {
return ec.latestFcUStateSent, ec.latestPAttrSent
}

func (ec *HiveRPCEngineClient) LatestNewPayloadSent() *api.ExecutableData {
func (ec *HiveRPCEngineClient) LatestNewPayloadSent() *typ.ExecutableData {
return ec.latestPayloadSent
}

Expand Down
Loading

0 comments on commit 6399870

Please sign in to comment.