@ -20,7 +20,6 @@ package catalyst
import (
import (
"errors"
"errors"
"fmt"
"fmt"
"math/big"
"sync"
"sync"
"time"
"time"
@ -34,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params/forks"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/rpc"
)
)
@ -184,47 +184,43 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa
}
}
// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes.
// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload attributes.
func ( api * ConsensusAPI ) ForkchoiceUpdatedV2 ( update engine . ForkchoiceStateV1 , payloadAttribute s * engine . PayloadAttributes ) ( engine . ForkChoiceResponse , error ) {
func ( api * ConsensusAPI ) ForkchoiceUpdatedV2 ( update engine . ForkchoiceStateV1 , param s * engine . PayloadAttributes ) ( engine . ForkChoiceResponse , error ) {
if payloadAttribute s != nil {
if param s != nil {
if err := api . verifyPayloadAttributes ( payloadAttributes ) ; err ! = nil {
if params . Withdrawals = = nil {
return engine . STATUS_INVALID , engine . InvalidParams . With ( err )
return engine . STATUS_INVALID , engine . InvalidParams . With ( errors . New ( "missing withdrawals" ) )
}
}
if params . BeaconRoot != nil {
return engine . STATUS_INVALID , engine . InvalidParams . With ( errors . New ( "unexpected beacon root" ) )
}
}
return api . forkchoiceUpdated ( update , payloadAttributes )
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Shanghai {
return engine . STATUS_INVALID , engine . UnsupportedFork . With ( errors . New ( "forkchoiceUpdatedV2 must only be called for shanghai payloads" ) )
}
}
// ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root in the payload attributes.
func ( api * ConsensusAPI ) ForkchoiceUpdatedV3 ( update engine . ForkchoiceStateV1 , payloadAttributes * engine . PayloadAttributes ) ( engine . ForkChoiceResponse , error ) {
if payloadAttributes != nil {
if err := api . verifyPayloadAttributes ( payloadAttributes ) ; err != nil {
return engine . STATUS_INVALID , engine . InvalidParams . With ( err )
}
}
return api . forkchoiceUpdated ( update , params )
}
}
return api . forkchoiceUpdated ( update , payloadAttributes )
}
func ( api * ConsensusAPI ) verifyPayloadAttributes ( attr * engine . PayloadAttributes ) error {
c := api . eth . BlockChain ( ) . Config ( )
// Verify withdrawals attribute for Shanghai.
// ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root in the payload attributes.
if err := checkAttribute ( c . IsShanghai , attr . Withdrawals != nil , c . LondonBlock , attr . Timestamp ) ; err != nil {
func ( api * ConsensusAPI ) ForkchoiceUpdatedV3 ( update engine . ForkchoiceStateV1 , params * engine . PayloadAttributes ) ( engine . ForkChoiceResponse , error ) {
return fmt . Errorf ( "invalid withdrawals: %w" , err )
if params != nil {
// TODO(matt): according to https://github.com/ethereum/execution-apis/pull/498,
// payload attributes that are invalid should return error
// engine.InvalidPayloadAttributes. Once hive updates this, we should update
// on our end.
if params . Withdrawals == nil {
return engine . STATUS_INVALID , engine . InvalidParams . With ( errors . New ( "missing withdrawals" ) )
}
}
// Verify beacon root attribute for Cancun.
if params . BeaconRoot == nil {
if err := checkAttribute ( c . IsCancun , attr . BeaconRoot != nil , c . LondonBlock , attr . Timestamp ) ; err != nil {
return engine . STATUS_INVALID , engine . InvalidParams . With ( errors . New ( "missing beacon root" ) )
return fmt . Errorf ( "invalid parent beacon block root: %w" , err )
}
}
return nil
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Cancun {
return engine . STATUS_INVALID , engine . UnsupportedFork . With ( errors . New ( "forkchoiceUpdatedV3 must only be called for cancun payloads" ) )
}
}
func checkAttribute ( active func ( * big . Int , uint64 ) bool , exists bool , block * big . Int , time uint64 ) error {
if active ( block , time ) && ! exists {
return errors . New ( "fork active, missing expected attribute" )
}
}
if ! active ( block , time ) && exists {
// TODO(matt): the spec requires that fcu is applied when called on a valid
return errors . New ( "fork inactive, unexpected attribute set" )
// hash, even if params are wrong. To do this we need to split up
}
// forkchoiceUpdate into a function that only updates the head and then a
return nil
// function that kicks off block construction.
return api . forkchoiceUpdated ( update , params )
}
}
func ( api * ConsensusAPI ) forkchoiceUpdated ( update engine . ForkchoiceStateV1 , payloadAttributes * engine . PayloadAttributes ) ( engine . ForkChoiceResponse , error ) {
func ( api * ConsensusAPI ) forkchoiceUpdated ( update engine . ForkchoiceStateV1 , payloadAttributes * engine . PayloadAttributes ) ( engine . ForkChoiceResponse , error ) {
@ -457,27 +453,39 @@ func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.Payl
// NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
// NewPayloadV2 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
func ( api * ConsensusAPI ) NewPayloadV2 ( params engine . ExecutableData ) ( engine . PayloadStatusV1 , error ) {
func ( api * ConsensusAPI ) NewPayloadV2 ( params engine . ExecutableData ) ( engine . PayloadStatusV1 , error ) {
if api . eth . BlockChain ( ) . Config ( ) . IsShanghai ( new ( big . Int ) . SetUint64 ( params . Number ) , params . Timestamp ) {
if api . eth . BlockChain ( ) . Config ( ) . IsCancun ( api . eth . BlockChain ( ) . Config ( ) . LondonBlock , params . Timestamp ) {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "can't use new payload v2 post-shanghai" ) )
}
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) == forks . Shanghai {
if params . Withdrawals == nil {
if params . Withdrawals == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil withdrawals post-shanghai" ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil withdrawals post-shanghai" ) )
}
}
} else if params . Withdrawals != nil {
} else {
if params . Withdrawals != nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil withdrawals pre-shanghai" ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil withdrawals pre-shanghai" ) )
}
}
if api . eth . BlockChain ( ) . Config ( ) . IsCancun ( new ( big . Int ) . SetUint64 ( params . Number ) , params . Timestamp ) {
}
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "newPayloadV2 called post-cancun" ) )
if params . ExcessBlobGas != nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil excessBlobGas pre-cancun" ) )
}
if params . BlobGasUsed != nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil params.BlobGasUsed pre-cancun" ) )
}
}
return api . newPayload ( params , nil , nil )
return api . newPayload ( params , nil , nil )
}
}
// NewPayloadV3 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
// NewPayloadV3 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
func ( api * ConsensusAPI ) NewPayloadV3 ( params engine . ExecutableData , versionedHashes [ ] common . Hash , beaconRoot * common . Hash ) ( engine . PayloadStatusV1 , error ) {
func ( api * ConsensusAPI ) NewPayloadV3 ( params engine . ExecutableData , versionedHashes [ ] common . Hash , beaconRoot * common . Hash ) ( engine . PayloadStatusV1 , error ) {
if params . Withdrawals == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil withdrawals post-shanghai" ) )
}
if params . ExcessBlobGas == nil {
if params . ExcessBlobGas == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil excessBlobGas post-cancun" ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil excessBlobGas post-cancun" ) )
}
}
if params . BlobGasUsed == nil {
if params . BlobGasUsed == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil params.BlobGasUsed post-cancun" ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil params.BlobGasUsed post-cancun" ) )
}
}
if versionedHashes == nil {
if versionedHashes == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil versionedHashes post-cancun" ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil versionedHashes post-cancun" ) )
}
}
@ -485,10 +493,9 @@ func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHas
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil parentBeaconBlockRoot post-cancun" ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil parentBeaconBlockRoot post-cancun" ) )
}
}
if ! api . eth . BlockChain ( ) . Config ( ) . IsCancun ( new ( big . Int ) . SetUint64 ( params . Number ) , params . Timestamp ) {
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Cancun {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . UnsupportedFork . With ( errors . New ( "newPayloadV3 called pre-cancun " ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . UnsupportedFork . With ( errors . New ( "newPayloadV3 must only be called for cancun payloads " ) )
}
}
return api . newPayload ( params , versionedHashes , beaconRoot )
return api . newPayload ( params , versionedHashes , beaconRoot )
}
}