Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simulators/ethereum/engine: Engine API Cancun #759

Merged
merged 19 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a50e562
simulators/ethereum/engine: Cancun blob test suite
marioevz Jul 28, 2023
6d73a71
simulators/ethereum/engine: don't populate empty fields
marioevz Jul 28, 2023
067782d
simulators/ethereum/engine: modify types, remove beacon root from pay…
marioevz Jul 28, 2023
d6fbb55
simulators/ethereum/engine: add beacon root tests
marioevz Jul 28, 2023
d8462da
simulators/ethereum/engine:use custom geth branch
marioevz Jul 28, 2023
40ed5fa
simulators/ethereum/engine: beaconRoot everywhere
marioevz Jul 28, 2023
c24f868
simulators/ethereum/engine: Add 1 wei to 4788 stateful precompile
marioevz Jul 31, 2023
50c62d4
simulators/ethereum: go.work.sum
marioevz Jul 31, 2023
96d0877
simulators/ethereum/engine: update geth version
marioevz Aug 2, 2023
421bd79
simulators/ethereum/engine: add beacon root to genesis
marioevz Aug 2, 2023
8dcdeb2
simulators/ethereum/engine: fix clmock method versions usage
marioevz Aug 2, 2023
0ad850b
simulators/ethereum/engine: refactor
marioevz Aug 2, 2023
bda0d08
simulators/ethereum/engine: Fix expectations on some tests, and print…
marioevz Aug 3, 2023
2a67f32
simulators/ethereum/engine: Fix no beacon root on modified payloads
marioevz Aug 3, 2023
b9957b4
simulators/ethereum/engine: Enable blob tx receipts checks
marioevz Aug 3, 2023
c7f6073
simulators/ethereum/engine: Test case description improvements
marioevz Aug 3, 2023
4cf5b9d
simulators/ethereum/engine: Fix blob gas used check
marioevz Aug 3, 2023
5e4e424
simulators/ethereum/engine: Blob -> Cancun
marioevz Aug 3, 2023
a429a3c
simulators/ethereum: Fixes for pyspec sim
marioevz Aug 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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