@ -27,7 +27,9 @@ import (
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/downloader"
@ -37,6 +39,7 @@ import (
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params/forks"
"github.com/ethereum/go-ethereum/params/forks"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/rpc"
)
)
@ -82,6 +85,9 @@ var caps = []string{
"engine_forkchoiceUpdatedV1" ,
"engine_forkchoiceUpdatedV1" ,
"engine_forkchoiceUpdatedV2" ,
"engine_forkchoiceUpdatedV2" ,
"engine_forkchoiceUpdatedV3" ,
"engine_forkchoiceUpdatedV3" ,
"engine_forkchoiceUpdatedWithWitnessV1" ,
"engine_forkchoiceUpdatedWithWitnessV2" ,
"engine_forkchoiceUpdatedWithWitnessV3" ,
"engine_exchangeTransitionConfigurationV1" ,
"engine_exchangeTransitionConfigurationV1" ,
"engine_getPayloadV1" ,
"engine_getPayloadV1" ,
"engine_getPayloadV2" ,
"engine_getPayloadV2" ,
@ -91,6 +97,14 @@ var caps = []string{
"engine_newPayloadV2" ,
"engine_newPayloadV2" ,
"engine_newPayloadV3" ,
"engine_newPayloadV3" ,
"engine_newPayloadV4" ,
"engine_newPayloadV4" ,
"engine_newPayloadWithWitnessV1" ,
"engine_newPayloadWithWitnessV2" ,
"engine_newPayloadWithWitnessV3" ,
"engine_newPayloadWithWitnessV4" ,
"engine_executeStatelessPayloadV1" ,
"engine_executeStatelessPayloadV2" ,
"engine_executeStatelessPayloadV3" ,
"engine_executeStatelessPayloadV4" ,
"engine_getPayloadBodiesByHashV1" ,
"engine_getPayloadBodiesByHashV1" ,
"engine_getPayloadBodiesByHashV2" ,
"engine_getPayloadBodiesByHashV2" ,
"engine_getPayloadBodiesByRangeV1" ,
"engine_getPayloadBodiesByRangeV1" ,
@ -188,7 +202,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update engine.ForkchoiceStateV1, pa
return engine . STATUS_INVALID , engine . InvalidParams . With ( errors . New ( "forkChoiceUpdateV1 called post-shanghai" ) )
return engine . STATUS_INVALID , engine . InvalidParams . With ( errors . New ( "forkChoiceUpdateV1 called post-shanghai" ) )
}
}
}
}
return api . forkchoiceUpdated ( update , payloadAttributes , engine . PayloadV1 )
return api . forkchoiceUpdated ( update , payloadAttributes , engine . PayloadV1 , false )
}
}
// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload
// ForkchoiceUpdatedV2 is equivalent to V1 with the addition of withdrawals in the payload
@ -211,7 +225,7 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV2(update engine.ForkchoiceStateV1, pa
return engine . STATUS_INVALID , engine . UnsupportedFork . With ( errors . New ( "forkchoiceUpdatedV2 must only be called with paris and shanghai payloads" ) )
return engine . STATUS_INVALID , engine . UnsupportedFork . With ( errors . New ( "forkchoiceUpdatedV2 must only be called with paris and shanghai payloads" ) )
}
}
}
}
return api . forkchoiceUpdated ( update , params , engine . PayloadV2 )
return api . forkchoiceUpdated ( update , params , engine . PayloadV2 , false )
}
}
// ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root
// ForkchoiceUpdatedV3 is equivalent to V2 with the addition of parent beacon block root
@ -232,10 +246,68 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa
// hash, even if params are wrong. To do this we need to split up
// 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
// forkchoiceUpdate into a function that only updates the head and then a
// function that kicks off block construction.
// function that kicks off block construction.
return api . forkchoiceUpdated ( update , params , engine . PayloadV3 )
return api . forkchoiceUpdated ( update , params , engine . PayloadV3 , false )
}
}
func ( api * ConsensusAPI ) forkchoiceUpdated ( update engine . ForkchoiceStateV1 , payloadAttributes * engine . PayloadAttributes , payloadVersion engine . PayloadVersion ) ( engine . ForkChoiceResponse , error ) {
// ForkchoiceUpdatedWithWitnessV1 is analogous to ForkchoiceUpdatedV1, only it
// generates an execution witness too if block building was requested.
func ( api * ConsensusAPI ) ForkchoiceUpdatedWithWitnessV1 ( update engine . ForkchoiceStateV1 , payloadAttributes * engine . PayloadAttributes ) ( engine . ForkChoiceResponse , error ) {
if payloadAttributes != nil {
if payloadAttributes . Withdrawals != nil || payloadAttributes . BeaconRoot != nil {
return engine . STATUS_INVALID , engine . InvalidParams . With ( errors . New ( "withdrawals and beacon root not supported in V1" ) )
}
if api . eth . BlockChain ( ) . Config ( ) . IsShanghai ( api . eth . BlockChain ( ) . Config ( ) . LondonBlock , payloadAttributes . Timestamp ) {
return engine . STATUS_INVALID , engine . InvalidParams . With ( errors . New ( "forkChoiceUpdateV1 called post-shanghai" ) )
}
}
return api . forkchoiceUpdated ( update , payloadAttributes , engine . PayloadV1 , true )
}
// ForkchoiceUpdatedWithWitnessV2 is analogous to ForkchoiceUpdatedV2, only it
// generates an execution witness too if block building was requested.
func ( api * ConsensusAPI ) ForkchoiceUpdatedWithWitnessV2 ( update engine . ForkchoiceStateV1 , params * engine . PayloadAttributes ) ( engine . ForkChoiceResponse , error ) {
if params != nil {
if params . BeaconRoot != nil {
return engine . STATUS_INVALID , engine . InvalidPayloadAttributes . With ( errors . New ( "unexpected beacon root" ) )
}
switch api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) {
case forks . Paris :
if params . Withdrawals != nil {
return engine . STATUS_INVALID , engine . InvalidPayloadAttributes . With ( errors . New ( "withdrawals before shanghai" ) )
}
case forks . Shanghai :
if params . Withdrawals == nil {
return engine . STATUS_INVALID , engine . InvalidPayloadAttributes . With ( errors . New ( "missing withdrawals" ) )
}
default :
return engine . STATUS_INVALID , engine . UnsupportedFork . With ( errors . New ( "forkchoiceUpdatedV2 must only be called with paris and shanghai payloads" ) )
}
}
return api . forkchoiceUpdated ( update , params , engine . PayloadV2 , true )
}
// ForkchoiceUpdatedWithWitnessV3 is analogous to ForkchoiceUpdatedV3, only it
// generates an execution witness too if block building was requested.
func ( api * ConsensusAPI ) ForkchoiceUpdatedWithWitnessV3 ( update engine . ForkchoiceStateV1 , params * engine . PayloadAttributes ) ( engine . ForkChoiceResponse , error ) {
if params != nil {
if params . Withdrawals == nil {
return engine . STATUS_INVALID , engine . InvalidPayloadAttributes . With ( errors . New ( "missing withdrawals" ) )
}
if params . BeaconRoot == nil {
return engine . STATUS_INVALID , engine . InvalidPayloadAttributes . With ( errors . New ( "missing beacon root" ) )
}
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Cancun && api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Prague {
return engine . STATUS_INVALID , engine . UnsupportedFork . With ( errors . New ( "forkchoiceUpdatedV3 must only be called for cancun payloads" ) )
}
}
// TODO(matt): the spec requires that fcu is applied when called on a valid
// 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
// function that kicks off block construction.
return api . forkchoiceUpdated ( update , params , engine . PayloadV3 , true )
}
func ( api * ConsensusAPI ) forkchoiceUpdated ( update engine . ForkchoiceStateV1 , payloadAttributes * engine . PayloadAttributes , payloadVersion engine . PayloadVersion , payloadWitness bool ) ( engine . ForkChoiceResponse , error ) {
api . forkchoiceLock . Lock ( )
api . forkchoiceLock . Lock ( )
defer api . forkchoiceLock . Unlock ( )
defer api . forkchoiceLock . Unlock ( )
@ -378,7 +450,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
if api . localBlocks . has ( id ) {
if api . localBlocks . has ( id ) {
return valid ( & id ) , nil
return valid ( & id ) , nil
}
}
payload , err := api . eth . Miner ( ) . BuildPayload ( args )
payload , err := api . eth . Miner ( ) . BuildPayload ( args , payloadWitness )
if err != nil {
if err != nil {
log . Error ( "Failed to build payload" , "err" , err )
log . Error ( "Failed to build payload" , "err" , err )
return valid ( nil ) , engine . InvalidPayloadAttributes . With ( err )
return valid ( nil ) , engine . InvalidPayloadAttributes . With ( err )
@ -469,7 +541,7 @@ func (api *ConsensusAPI) NewPayloadV1(params engine.ExecutableData) (engine.Payl
if params . Withdrawals != nil {
if params . Withdrawals != nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "withdrawals not supported in V1" ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "withdrawals not supported in V1" ) )
}
}
return api . newPayload ( params , nil , nil )
return api . newPayload ( params , nil , nil , false )
}
}
// 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.
@ -492,7 +564,7 @@ func (api *ConsensusAPI) NewPayloadV2(params engine.ExecutableData) (engine.Payl
if params . BlobGasUsed != nil {
if params . BlobGasUsed != nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil blobGasUsed pre-cancun" ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil blobGasUsed pre-cancun" ) )
}
}
return api . newPayload ( params , nil , nil )
return api . newPayload ( params , nil , nil , false )
}
}
// 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.
@ -517,9 +589,10 @@ func (api *ConsensusAPI) NewPayloadV3(params engine.ExecutableData, versionedHas
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Cancun {
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Cancun {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . UnsupportedFork . With ( errors . New ( "newPayloadV3 must only be called for cancun payloads" ) )
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 , false )
}
}
// NewPayloadV4 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
// NewPayloadV4 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
// NewPayloadV4 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
func ( api * ConsensusAPI ) NewPayloadV4 ( params engine . ExecutableData , versionedHashes [ ] common . Hash , beaconRoot * common . Hash ) ( engine . PayloadStatusV1 , error ) {
func ( api * ConsensusAPI ) NewPayloadV4 ( params engine . ExecutableData , versionedHashes [ ] common . Hash , beaconRoot * common . Hash ) ( engine . PayloadStatusV1 , error ) {
if params . Withdrawals == nil {
if params . Withdrawals == nil {
@ -545,10 +618,186 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Prague {
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Prague {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . UnsupportedFork . With ( errors . New ( "newPayloadV4 must only be called for prague payloads" ) )
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . UnsupportedFork . With ( errors . New ( "newPayloadV4 must only be called for prague payloads" ) )
}
}
return api . newPayload ( params , versionedHashes , beaconRoot )
return api . newPayload ( params , versionedHashes , beaconRoot , false )
}
}
func ( api * ConsensusAPI ) newPayload ( params engine . ExecutableData , versionedHashes [ ] common . Hash , beaconRoot * common . Hash ) ( engine . PayloadStatusV1 , error ) {
// NewPayloadWithWitnessV1 is analogous to NewPayloadV1, only it also generates
// and returns a stateless witness after running the payload.
func ( api * ConsensusAPI ) NewPayloadWithWitnessV1 ( params engine . ExecutableData ) ( engine . PayloadStatusV1 , error ) {
if params . Withdrawals != nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "withdrawals not supported in V1" ) )
}
return api . newPayload ( params , nil , nil , true )
}
// NewPayloadWithWitnessV2 is analogous to NewPayloadV2, only it also generates
// and returns a stateless witness after running the payload.
func ( api * ConsensusAPI ) NewPayloadWithWitnessV2 ( params engine . ExecutableData ) ( engine . PayloadStatusV1 , error ) {
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 newPayloadV2 post-cancun" ) )
}
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) == forks . Shanghai {
if params . Withdrawals == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil withdrawals post-shanghai" ) )
}
} else {
if params . Withdrawals != nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil withdrawals pre-shanghai" ) )
}
}
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 blobGasUsed pre-cancun" ) )
}
return api . newPayload ( params , nil , nil , true )
}
// NewPayloadWithWitnessV3 is analogous to NewPayloadV3, only it also generates
// and returns a stateless witness after running the payload.
func ( api * ConsensusAPI ) NewPayloadWithWitnessV3 ( 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 {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil excessBlobGas post-cancun" ) )
}
if params . BlobGasUsed == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil blobGasUsed post-cancun" ) )
}
if versionedHashes == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil versionedHashes post-cancun" ) )
}
if beaconRoot == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil beaconRoot post-cancun" ) )
}
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Cancun {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . UnsupportedFork . With ( errors . New ( "newPayloadWithWitnessV3 must only be called for cancun payloads" ) )
}
return api . newPayload ( params , versionedHashes , beaconRoot , true )
}
// NewPayloadWithWitnessV4 is analogous to NewPayloadV4, only it also generates
// and returns a stateless witness after running the payload.
func ( api * ConsensusAPI ) NewPayloadWithWitnessV4 ( 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 {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil excessBlobGas post-cancun" ) )
}
if params . BlobGasUsed == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil blobGasUsed post-cancun" ) )
}
if params . Deposits == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil deposits post-prague" ) )
}
if versionedHashes == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil versionedHashes post-cancun" ) )
}
if beaconRoot == nil {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil beaconRoot post-cancun" ) )
}
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Prague {
return engine . PayloadStatusV1 { Status : engine . INVALID } , engine . UnsupportedFork . With ( errors . New ( "newPayloadWithWitnessV4 must only be called for prague payloads" ) )
}
return api . newPayload ( params , versionedHashes , beaconRoot , true )
}
// ExecuteStatelessPayloadV1 is analogous to NewPayloadV1, only it operates in
// a stateless mode on top of a provided witness instead of the local database.
func ( api * ConsensusAPI ) ExecuteStatelessPayloadV1 ( params engine . ExecutableData , opaqueWitness hexutil . Bytes ) ( engine . StatelessPayloadStatusV1 , error ) {
if params . Withdrawals != nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "withdrawals not supported in V1" ) )
}
return api . executeStatelessPayload ( params , nil , nil , opaqueWitness )
}
// ExecuteStatelessPayloadV2 is analogous to NewPayloadV2, only it operates in
// a stateless mode on top of a provided witness instead of the local database.
func ( api * ConsensusAPI ) ExecuteStatelessPayloadV2 ( params engine . ExecutableData , opaqueWitness hexutil . Bytes ) ( engine . StatelessPayloadStatusV1 , error ) {
if api . eth . BlockChain ( ) . Config ( ) . IsCancun ( api . eth . BlockChain ( ) . Config ( ) . LondonBlock , params . Timestamp ) {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "can't use newPayloadV2 post-cancun" ) )
}
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) == forks . Shanghai {
if params . Withdrawals == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil withdrawals post-shanghai" ) )
}
} else {
if params . Withdrawals != nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil withdrawals pre-shanghai" ) )
}
}
if params . ExcessBlobGas != nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil excessBlobGas pre-cancun" ) )
}
if params . BlobGasUsed != nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "non-nil blobGasUsed pre-cancun" ) )
}
return api . executeStatelessPayload ( params , nil , nil , opaqueWitness )
}
// ExecuteStatelessPayloadV3 is analogous to NewPayloadV3, only it operates in
// a stateless mode on top of a provided witness instead of the local database.
func ( api * ConsensusAPI ) ExecuteStatelessPayloadV3 ( params engine . ExecutableData , versionedHashes [ ] common . Hash , beaconRoot * common . Hash , opaqueWitness hexutil . Bytes ) ( engine . StatelessPayloadStatusV1 , error ) {
if params . Withdrawals == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil withdrawals post-shanghai" ) )
}
if params . ExcessBlobGas == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil excessBlobGas post-cancun" ) )
}
if params . BlobGasUsed == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil blobGasUsed post-cancun" ) )
}
if versionedHashes == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil versionedHashes post-cancun" ) )
}
if beaconRoot == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil beaconRoot post-cancun" ) )
}
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Cancun {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . UnsupportedFork . With ( errors . New ( "executeStatelessPayloadV3 must only be called for cancun payloads" ) )
}
return api . executeStatelessPayload ( params , versionedHashes , beaconRoot , opaqueWitness )
}
// ExecuteStatelessPayloadV4 is analogous to NewPayloadV4, only it operates in
// a stateless mode on top of a provided witness instead of the local database.
func ( api * ConsensusAPI ) ExecuteStatelessPayloadV4 ( params engine . ExecutableData , versionedHashes [ ] common . Hash , beaconRoot * common . Hash , opaqueWitness hexutil . Bytes ) ( engine . StatelessPayloadStatusV1 , error ) {
if params . Withdrawals == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil withdrawals post-shanghai" ) )
}
if params . ExcessBlobGas == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil excessBlobGas post-cancun" ) )
}
if params . BlobGasUsed == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil blobGasUsed post-cancun" ) )
}
if params . Deposits == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil deposits post-prague" ) )
}
if versionedHashes == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil versionedHashes post-cancun" ) )
}
if beaconRoot == nil {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . InvalidParams . With ( errors . New ( "nil beaconRoot post-cancun" ) )
}
if api . eth . BlockChain ( ) . Config ( ) . LatestFork ( params . Timestamp ) != forks . Prague {
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID } , engine . UnsupportedFork . With ( errors . New ( "executeStatelessPayloadV4 must only be called for prague payloads" ) )
}
return api . executeStatelessPayload ( params , versionedHashes , beaconRoot , opaqueWitness )
}
func ( api * ConsensusAPI ) newPayload ( params engine . ExecutableData , versionedHashes [ ] common . Hash , beaconRoot * common . Hash , witness bool ) ( engine . PayloadStatusV1 , error ) {
// The locking here is, strictly, not required. Without these locks, this can happen:
// The locking here is, strictly, not required. Without these locks, this can happen:
//
//
// 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to
// 1. NewPayload( execdata-N ) is invoked from the CL. It goes all the way down to
@ -656,8 +905,9 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
return engine . PayloadStatusV1 { Status : engine . ACCEPTED } , nil
return engine . PayloadStatusV1 { Status : engine . ACCEPTED } , nil
}
}
log . Trace ( "Inserting block without sethead" , "hash" , block . Hash ( ) , "number" , block . Number ( ) )
log . Trace ( "Inserting block without sethead" , "hash" , block . Hash ( ) , "number" , block . Number ( ) )
if err := api . eth . BlockChain ( ) . InsertBlockWithoutSetHead ( block ) ; err != nil {
proofs , err := api . eth . BlockChain ( ) . InsertBlockWithoutSetHead ( block , witness )
log . Warn ( "NewPayloadV1: inserting block failed" , "error" , err )
if err != nil {
log . Warn ( "NewPayload: inserting block failed" , "error" , err )
api . invalidLock . Lock ( )
api . invalidLock . Lock ( )
api . invalidBlocksHits [ block . Hash ( ) ] = 1
api . invalidBlocksHits [ block . Hash ( ) ] = 1
@ -667,7 +917,71 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
return api . invalid ( err , parent . Header ( ) ) , nil
return api . invalid ( err , parent . Header ( ) ) , nil
}
}
hash := block . Hash ( )
hash := block . Hash ( )
return engine . PayloadStatusV1 { Status : engine . VALID , LatestValidHash : & hash } , nil
// If witness collection was requested, inject that into the result too
var ow * hexutil . Bytes
if proofs != nil {
ow = new ( hexutil . Bytes )
* ow , _ = rlp . EncodeToBytes ( proofs )
}
return engine . PayloadStatusV1 { Status : engine . VALID , Witness : ow , LatestValidHash : & hash } , nil
}
func ( api * ConsensusAPI ) executeStatelessPayload ( params engine . ExecutableData , versionedHashes [ ] common . Hash , beaconRoot * common . Hash , opaqueWitness hexutil . Bytes ) ( engine . StatelessPayloadStatusV1 , error ) {
log . Trace ( "Engine API request received" , "method" , "ExecuteStatelessPayload" , "number" , params . Number , "hash" , params . BlockHash )
block , err := engine . ExecutableDataToBlockNoHash ( params , versionedHashes , beaconRoot )
if err != nil {
bgu := "nil"
if params . BlobGasUsed != nil {
bgu = strconv . Itoa ( int ( * params . BlobGasUsed ) )
}
ebg := "nil"
if params . ExcessBlobGas != nil {
ebg = strconv . Itoa ( int ( * params . ExcessBlobGas ) )
}
log . Warn ( "Invalid ExecuteStatelessPayload params" ,
"params.Number" , params . Number ,
"params.ParentHash" , params . ParentHash ,
"params.BlockHash" , params . BlockHash ,
"params.StateRoot" , params . StateRoot ,
"params.FeeRecipient" , params . FeeRecipient ,
"params.LogsBloom" , common . PrettyBytes ( params . LogsBloom ) ,
"params.Random" , params . Random ,
"params.GasLimit" , params . GasLimit ,
"params.GasUsed" , params . GasUsed ,
"params.Timestamp" , params . Timestamp ,
"params.ExtraData" , common . PrettyBytes ( params . ExtraData ) ,
"params.BaseFeePerGas" , params . BaseFeePerGas ,
"params.BlobGasUsed" , bgu ,
"params.ExcessBlobGas" , ebg ,
"len(params.Transactions)" , len ( params . Transactions ) ,
"len(params.Withdrawals)" , len ( params . Withdrawals ) ,
"len(params.Deposits)" , len ( params . Deposits ) ,
"beaconRoot" , beaconRoot ,
"error" , err )
errorMsg := err . Error ( )
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID , ValidationError : & errorMsg } , nil
}
witness := new ( stateless . Witness )
if err := rlp . DecodeBytes ( opaqueWitness , witness ) ; err != nil {
log . Warn ( "Invalid ExecuteStatelessPayload witness" , "err" , err )
errorMsg := err . Error ( )
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID , ValidationError : & errorMsg } , nil
}
// Stash away the last update to warn the user if the beacon client goes offline
api . lastNewPayloadLock . Lock ( )
api . lastNewPayloadUpdate = time . Now ( )
api . lastNewPayloadLock . Unlock ( )
log . Trace ( "Executing block statelessly" , "number" , block . Number ( ) , "hash" , params . BlockHash )
stateRoot , receiptRoot , err := core . ExecuteStateless ( api . eth . BlockChain ( ) . Config ( ) , block , witness )
if err != nil {
log . Warn ( "ExecuteStatelessPayload: execution failed" , "err" , err )
errorMsg := err . Error ( )
return engine . StatelessPayloadStatusV1 { Status : engine . INVALID , ValidationError : & errorMsg } , nil
}
return engine . StatelessPayloadStatusV1 { Status : engine . VALID , StateRoot : stateRoot , ReceiptsRoot : receiptRoot } , nil
}
}
// delayPayloadImport stashes the given block away for import at a later time,
// delayPayloadImport stashes the given block away for import at a later time,