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

New Engine API semantics (Kiln v1) #3340

Merged
merged 56 commits into from
Feb 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
c0d71f4
Disable PoS sync temporarily
yperbasis Jan 18, 2022
bb644a6
Merge branch 'devel' into new_merge_approach
yperbasis Jan 18, 2022
77d4e92
Resore PoS sync
yperbasis Jan 18, 2022
a7c4600
Handle Ctrl^C in HeadersPOS
yperbasis Jan 18, 2022
180fe54
Consistent naming
yperbasis Jan 19, 2022
3b26881
Merge branch 'devel' into new_merge_approach
yperbasis Jan 19, 2022
c970deb
Extract verifyAndSavePoSHeader & downloadMissingPoSHeaders
yperbasis Jan 19, 2022
de1ddf5
Preparation for EngineForkChoiceUpdated re-orgs
yperbasis Jan 20, 2022
104daa1
Merge branch 'devel' into new_merge_approach
yperbasis Jan 20, 2022
78de6ce
Extract ForkingPoint
yperbasis Jan 20, 2022
fb4a35e
Comments
yperbasis Jan 21, 2022
bf90a40
Merge branch 'devel' into new_merge_approach
yperbasis Jan 23, 2022
963b6b1
New proto for Engine API
yperbasis Jan 24, 2022
a36d93a
EngineExecutePayload -> EngineNewPayload
yperbasis Jan 24, 2022
dcd0170
Return INVALID_BLOCK_HASH if block hash is invalid
yperbasis Jan 24, 2022
0048ad3
Return EngineStatus_ACCEPTED for side chain blocks
yperbasis Jan 24, 2022
aeddbb6
Merge branch 'devel' into new_merge_approach
yperbasis Jan 24, 2022
4570b96
Update erigon-lib (PR 268)
yperbasis Jan 24, 2022
929f8f4
Fix payload2Hash
yperbasis Jan 25, 2022
0422e71
reverseDownloadCh -> beaconPayloadCh
yperbasis Jan 25, 2022
f0841a8
Merge branch 'devel' into new_merge_approach
yperbasis Jan 25, 2022
859f0f9
Update erigon-lib
yperbasis Jan 25, 2022
c8b69a7
Engine API updated
yperbasis Jan 25, 2022
9752f3b
ExecutionStatus -> PayloadStatus
yperbasis Jan 25, 2022
b544b86
Introduce forkChoiceCh
yperbasis Jan 25, 2022
fcaf168
Mock ForkChoiceMessage/PayloadStatus
yperbasis Jan 27, 2022
6952c0b
Add ValidationError to PayloadStatus
yperbasis Jan 27, 2022
191bb9e
Small clean-ups
yperbasis Jan 27, 2022
a53ee48
Merge branch 'devel' into new_merge_approach
yperbasis Jan 27, 2022
f81ef1d
Add INVALID_TERMINAL_BLOCK to EngineStatus
yperbasis Jan 27, 2022
a3f2b00
Add a comment
yperbasis Jan 28, 2022
b73f30c
Extract handleNewPayload & handleForkChoice
yperbasis Jan 28, 2022
b38e5dc
Partially implement handleForkChoice
yperbasis Jan 31, 2022
59520b6
Update erigon-lib
yperbasis Jan 31, 2022
4349d84
Merge branch 'devel' into new_merge_approach
yperbasis Jan 31, 2022
d4c1374
short vs long re-org
yperbasis Feb 2, 2022
3bf9aee
Move header insertion out of downloadMissingPoSHeaders
yperbasis Feb 2, 2022
355c4b6
Update erigon-lib
yperbasis Feb 6, 2022
2d4a8c6
Refactor ProcessSegmentPOS
yperbasis Feb 6, 2022
3e4aca6
Merge branch 'devel' into new_merge_approach
yperbasis Feb 6, 2022
a61e952
Fix imports
yperbasis Feb 6, 2022
252a62f
Wire downloadMissingPoSHeaders into handleForkChoice
yperbasis Feb 7, 2022
a02083f
Merge branch 'devel' into new_merge_approach
yperbasis Feb 7, 2022
4c65569
evictOldPendingPayloads
yperbasis Feb 8, 2022
12429cb
Merge branch 'devel' into new_merge_approach
yperbasis Feb 8, 2022
3a198c4
nolint:unused for assertSegment
yperbasis Feb 8, 2022
ce46b02
Try nolint instead of nolint:unused
yperbasis Feb 8, 2022
d597f20
Small comment improvements
yperbasis Feb 8, 2022
72d6f9a
HeadHeaderHash/StageProgress in handleForkChoice
yperbasis Feb 8, 2022
5740028
TODO: bodyDownloader.AddToPrefetch(block)
yperbasis Feb 8, 2022
b98dde0
Review call suggestions
yperbasis Feb 8, 2022
3bdc08a
Don't use ReadHeaderNumber in ProcessSegmentPOS
yperbasis Feb 8, 2022
c8818df
Don't leave ethbackend waiting when server is stopping
yperbasis Feb 9, 2022
5416512
Update erigon-lib
yperbasis Feb 9, 2022
e9869bc
Merge branch 'devel' into new_merge_approach
yperbasis Feb 9, 2022
f1e3575
More explicit signature of downloadMissingPoSHeaders
yperbasis Feb 9, 2022
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
2 changes: 1 addition & 1 deletion cmd/integration/commands/stages.go
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ func newSync(ctx context.Context, db kv.RwDB, miningConfig *params.MiningConfig)

sync, err := stages2.NewStagedSync(context.Background(), logger, db, p2p.Config{}, cfg,
chainConfig.TerminalTotalDifficulty, sentryControlServer, tmpdir,
nil, nil, nil, nil,
nil, nil, nil, nil, nil,
)
if err != nil {
panic(err)
Expand Down
84 changes: 40 additions & 44 deletions cmd/rpcdaemon/commands/engine_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ type PayloadAttributes struct {
// EngineAPI Beacon chain communication endpoint
type EngineAPI interface {
ForkchoiceUpdatedV1(ctx context.Context, forkChoiceState *ForkChoiceState, payloadAttributes *PayloadAttributes) (map[string]interface{}, error)
ExecutePayloadV1(context.Context, *ExecutionPayload) (map[string]interface{}, error)
NewPayloadV1(context.Context, *ExecutionPayload) (map[string]interface{}, error)
GetPayloadV1(ctx context.Context, payloadID hexutil.Bytes) (*ExecutionPayload, error)
GetPayloadBodiesV1(ctx context.Context, blockHashes []rpc.BlockNumberOrHash) (map[common.Hash]ExecutionPayload, error)
}
Expand All @@ -68,51 +68,56 @@ type EngineImpl struct {
api services.ApiBackend
}

// ForkchoiceUpdatedV1 is executed only if we are running a beacon validator,
// in erigon we do not use this for reorgs like go-ethereum does since we can do that in engine_executePayloadV1
// if the payloadAttributes is different than null, we return
func convertPayloadStatus(x *remote.EnginePayloadStatus) map[string]interface{} {
json := map[string]interface{}{
"status": x.Status.String(),
}
if x.LatestValidHash != nil {
json["latestValidHash"] = gointerfaces.ConvertH256ToHash(x.LatestValidHash)
}
if x.ValidationError != "" {
json["validationError"] = x.ValidationError
}

return json
}

func (e *EngineImpl) ForkchoiceUpdatedV1(ctx context.Context, forkChoiceState *ForkChoiceState, payloadAttributes *PayloadAttributes) (map[string]interface{}, error) {
// Unwinds can be made within engine_excutePayloadV1 so we can return success regardless
if payloadAttributes == nil {
return map[string]interface{}{
"status": "SUCCESS",
}, nil
var prepareParameters *remote.EnginePayloadAttributes
if payloadAttributes != nil {
prepareParameters = &remote.EnginePayloadAttributes{
Timestamp: uint64(payloadAttributes.Timestamp),
Random: gointerfaces.ConvertHashToH256(payloadAttributes.Random),
SuggestedFeeRecipient: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient),
}
}
// Request for assembling payload
reply, err := e.api.EngineForkchoiceUpdateV1(ctx, &remote.EngineForkChoiceUpdatedRequest{
Prepare: &remote.EnginePreparePayload{
Timestamp: uint64(payloadAttributes.Timestamp),
Random: gointerfaces.ConvertHashToH256(payloadAttributes.Random),
FeeRecipient: gointerfaces.ConvertAddressToH160(payloadAttributes.SuggestedFeeRecipient),
},
Forkchoice: &remote.EngineForkChoiceUpdated{
reply, err := e.api.EngineForkchoiceUpdatedV1(ctx, &remote.EngineForkChoiceUpdatedRequest{
ForkchoiceState: &remote.EngineForkChoiceState{
HeadBlockHash: gointerfaces.ConvertHashToH256(forkChoiceState.HeadHash),
FinalizedBlockHash: gointerfaces.ConvertHashToH256(forkChoiceState.FinalizedBlockHash),
SafeBlockHash: gointerfaces.ConvertHashToH256(forkChoiceState.SafeBlockHash),
},
PayloadAttributes: prepareParameters,
})
if err != nil {
return nil, err
}
// Process reply
if reply.Status == "SYNCING" {
return map[string]interface{}{
"status": reply.Status,
}, nil

json := map[string]interface{}{
"payloadStatus": convertPayloadStatus(reply.PayloadStatus),
}
if reply.PayloadId != 0 {
encodedPayloadId := make([]byte, 8)
binary.BigEndian.PutUint64(encodedPayloadId, reply.PayloadId)
json["payloadId"] = hexutil.Bytes(encodedPayloadId)
}
encodedPayloadId := make([]byte, 8)
binary.BigEndian.PutUint64(encodedPayloadId, reply.PayloadId)
// Answer
return map[string]interface{}{
"status": reply.Status,
"payloadId": hexutil.Bytes(encodedPayloadId),
}, nil

return json, nil
}

// ExecutePayloadV1 takes a block from the beacon chain and do either two of the following things
// - Stageloop the block just received if we have the payload's parent hash already
// - Start the reverse sync process otherwise, and return "Syncing"
func (e *EngineImpl) ExecutePayloadV1(ctx context.Context, payload *ExecutionPayload) (map[string]interface{}, error) {
// NewPayloadV1 processes new payloads (blocks) from the beacon chain.
// See https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_newpayloadv1
func (e *EngineImpl) NewPayloadV1(ctx context.Context, payload *ExecutionPayload) (map[string]interface{}, error) {
var baseFee *uint256.Int
if payload.BaseFeePerGas != nil {
var overflow bool
Expand All @@ -128,7 +133,7 @@ func (e *EngineImpl) ExecutePayloadV1(ctx context.Context, payload *ExecutionPay
for i, transaction := range payload.Transactions {
transactions[i] = ([]byte)(transaction)
}
res, err := e.api.EngineExecutePayloadV1(ctx, &types2.ExecutionPayload{
res, err := e.api.EngineNewPayloadV1(ctx, &types2.ExecutionPayload{
ParentHash: gointerfaces.ConvertHashToH256(payload.ParentHash),
Coinbase: gointerfaces.ConvertAddressToH160(payload.FeeRecipient),
StateRoot: gointerfaces.ConvertHashToH256(payload.StateRoot),
Expand All @@ -148,16 +153,7 @@ func (e *EngineImpl) ExecutePayloadV1(ctx context.Context, payload *ExecutionPay
return nil, err
}

if res.LatestValidHash != nil {
var latestValidHash common.Hash = gointerfaces.ConvertH256ToHash(res.LatestValidHash)
return map[string]interface{}{
"status": res.Status,
"latestValidHash": latestValidHash,
}, nil
}
return map[string]interface{}{
"status": res.Status,
}, nil
return convertPayloadStatus(res), nil
}

func (e *EngineImpl) GetPayloadV1(ctx context.Context, payloadID hexutil.Bytes) (*ExecutionPayload, error) {
Expand Down
5 changes: 2 additions & 3 deletions cmd/rpcdaemon/rpcdaemontest/test_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import (
"net"
"testing"

"github.com/ledgerwatch/erigon-lib/gointerfaces/starknet"

"github.com/holiman/uint256"
"github.com/ledgerwatch/erigon-lib/gointerfaces/remote"
"github.com/ledgerwatch/erigon-lib/gointerfaces/starknet"
"github.com/ledgerwatch/erigon-lib/gointerfaces/txpool"
"github.com/ledgerwatch/erigon-lib/kv"
"github.com/ledgerwatch/erigon/accounts/abi/bind"
Expand Down Expand Up @@ -223,7 +222,7 @@ func CreateTestGrpcConn(t *testing.T, m *stages.MockSentry) (context.Context, *g
ethashApi := apis[1].Service.(*ethash.API)
server := grpc.NewServer()

remote.RegisterETHBACKENDServer(server, privateapi.NewEthBackendServer(ctx, nil, m.DB, m.Notifications.Events, snapshotsync.NewBlockReader(), nil, nil, nil, nil, nil, nil, false))
remote.RegisterETHBACKENDServer(server, privateapi.NewEthBackendServer(ctx, nil, m.DB, m.Notifications.Events, snapshotsync.NewBlockReader(), nil, nil, nil, nil, nil, nil, nil, false))
txpool.RegisterTxpoolServer(server, m.TxPoolGrpcServer)
txpool.RegisterMiningServer(server, privateapi.NewMiningServer(ctx, &IsMiningMock{}, ethashApi))
starknet.RegisterCAIROVMServer(server, &starknet.UnimplementedCAIROVMServer{})
Expand Down
10 changes: 5 additions & 5 deletions cmd/rpcdaemon/services/eth_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ type ApiBackend interface {
ClientVersion(ctx context.Context) (string, error)
Subscribe(ctx context.Context, cb func(*remote.SubscribeReply)) error
BlockWithSenders(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (block *types.Block, senders []common.Address, err error)
EngineExecutePayloadV1(ctx context.Context, payload *types2.ExecutionPayload) (*remote.EngineExecutePayloadReply, error)
EngineForkchoiceUpdateV1(ctx context.Context, request *remote.EngineForkChoiceUpdatedRequest) (*remote.EngineForkChoiceUpdatedReply, error)
EngineNewPayloadV1(ctx context.Context, payload *types2.ExecutionPayload) (*remote.EnginePayloadStatus, error)
EngineForkchoiceUpdatedV1(ctx context.Context, request *remote.EngineForkChoiceUpdatedRequest) (*remote.EngineForkChoiceUpdatedReply, error)
EngineGetPayloadV1(ctx context.Context, payloadId uint64) (*types2.ExecutionPayload, error)
NodeInfo(ctx context.Context, limit uint32) ([]p2p.NodeInfo, error)
}
Expand Down Expand Up @@ -164,11 +164,11 @@ func (back *RemoteBackend) BlockWithSenders(ctx context.Context, tx kv.Getter, h
return back.blockReader.BlockWithSenders(ctx, tx, hash, blockHeight)
}

func (back *RemoteBackend) EngineExecutePayloadV1(ctx context.Context, payload *types2.ExecutionPayload) (res *remote.EngineExecutePayloadReply, err error) {
return back.remoteEthBackend.EngineExecutePayloadV1(ctx, payload)
func (back *RemoteBackend) EngineNewPayloadV1(ctx context.Context, payload *types2.ExecutionPayload) (res *remote.EnginePayloadStatus, err error) {
return back.remoteEthBackend.EngineNewPayloadV1(ctx, payload)
}

func (back *RemoteBackend) EngineForkchoiceUpdateV1(ctx context.Context, request *remote.EngineForkChoiceUpdatedRequest) (*remote.EngineForkChoiceUpdatedReply, error) {
func (back *RemoteBackend) EngineForkchoiceUpdatedV1(ctx context.Context, request *remote.EngineForkChoiceUpdatedRequest) (*remote.EngineForkChoiceUpdatedReply, error) {
return back.remoteEthBackend.EngineForkChoiceUpdatedV1(ctx, request)
}

Expand Down
14 changes: 8 additions & 6 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ type Ethereum struct {
txPool2GrpcServer *txpool2.GrpcServer
notifyMiningAboutNewTxs chan struct{}
// When we receive something here, it means that the beacon chain transitioned
// to proof-of-stake so we start reverse syncing from the header
reverseDownloadCh chan privateapi.PayloadMessage
// to proof-of-stake so we start reverse syncing from the block
newPayloadCh chan privateapi.PayloadMessage
forkChoiceCh chan privateapi.ForkChoiceMessage
waitingForBeaconChain uint32 // atomic boolean flag

downloadProtocols *downloader.Protocols
Expand Down Expand Up @@ -372,7 +373,8 @@ func New(stack *node.Node, config *ethconfig.Config, txpoolCfg txpool2.Config, l
miner := stagedsync.NewMiningState(&config.Miner)
backend.pendingBlocks = miner.PendingResultCh
backend.minedBlocks = miner.MiningResultCh
backend.reverseDownloadCh = make(chan privateapi.PayloadMessage)
backend.newPayloadCh = make(chan privateapi.PayloadMessage)
backend.forkChoiceCh = make(chan privateapi.ForkChoiceMessage)

// proof-of-work mining
mining := stagedsync.New(
Expand Down Expand Up @@ -413,8 +415,8 @@ func New(stack *node.Node, config *ethconfig.Config, txpoolCfg txpool2.Config, l
atomic.StoreUint32(&backend.waitingForBeaconChain, 0)
// Initialize ethbackend
ethBackendRPC := privateapi.NewEthBackendServer(ctx, backend, backend.chainDB, backend.notifications.Events,
blockReader, chainConfig, backend.reverseDownloadCh, backend.sentryControlServer.Hd.ExecutionStatusCh, &backend.waitingForBeaconChain,
backend.sentryControlServer.Hd.SkipCycleHack, assembleBlockPOS, config.Miner.EnabledPOS)
blockReader, chainConfig, backend.newPayloadCh, backend.forkChoiceCh, backend.sentryControlServer.Hd.PayloadStatusCh,
&backend.waitingForBeaconChain, backend.sentryControlServer.Hd.SkipCycleHack, assembleBlockPOS, config.Miner.EnabledPOS)
miningRPC = privateapi.NewMiningServer(ctx, backend, ethashApi)
// If we enabled the proposer flag we initiates the block proposing thread
if config.Miner.EnabledPOS && chainConfig.TerminalTotalDifficulty != nil {
Expand Down Expand Up @@ -490,7 +492,7 @@ func New(stack *node.Node, config *ethconfig.Config, txpoolCfg txpool2.Config, l
backend.stagedSync, err = stages2.NewStagedSync(backend.sentryCtx, backend.logger, backend.chainDB,
stack.Config().P2P, *config, chainConfig.TerminalTotalDifficulty,
backend.sentryControlServer, tmpdir, backend.notifications.Accumulator,
backend.reverseDownloadCh, &backend.waitingForBeaconChain,
backend.newPayloadCh, backend.forkChoiceCh, &backend.waitingForBeaconChain,
backend.downloaderClient)
if err != nil {
return nil, err
Expand Down
Loading