@@ -53,6 +53,8 @@ type ConsensusAPI struct {
5353 preparedBlocks * payloadQueue // preparedBlocks caches payloads (*ExecutableDataV1) by payload ID (PayloadID)
5454}
5555
56+ // NewConsensusAPI creates a new consensus api for the given backend.
57+ // The underlying blockchain needs to have a valid terminal total difficulty set.
5658func NewConsensusAPI (eth * eth.Ethereum ) * ConsensusAPI {
5759 if eth .BlockChain ().Config ().TerminalTotalDifficulty == nil {
5860 panic ("Catalyst started without valid total difficulty" )
@@ -63,15 +65,16 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI {
6365 }
6466}
6567
66- func (api * ConsensusAPI ) GetPayloadV1 (payloadID beacon.PayloadID ) (* beacon.ExecutableDataV1 , error ) {
67- log .Trace ("Engine API request received" , "method" , "GetPayload" , "id" , payloadID )
68- data := api .preparedBlocks .get (payloadID )
69- if data == nil {
70- return nil , & beacon .UnknownPayload
71- }
72- return data , nil
73- }
74-
68+ // ForkchoiceUpdatedV1 has several responsibilities:
69+ // If the method is called with an empty head block:
70+ // we return success, which can be used to check if the catalyst mode is enabled
71+ // If the total difficulty was not reached:
72+ // we return INVALID
73+ // If the finalizedBlockHash is set:
74+ // we check if we have the finalizedBlockHash in our db, if not we start a sync
75+ // We try to set our blockchain to the headBlock
76+ // If there are payloadAttributes:
77+ // we try to assemble a block with the payloadAttributes and return its payloadID
7578func (api * ConsensusAPI ) ForkchoiceUpdatedV1 (heads beacon.ForkchoiceStateV1 , payloadAttributes * beacon.PayloadAttributesV1 ) (beacon.ForkChoiceResponse , error ) {
7679 log .Trace ("Engine API request received" , "method" , "ForkChoiceUpdated" , "head" , heads .HeadBlockHash , "finalized" , heads .FinalizedBlockHash , "safe" , heads .SafeBlockHash )
7780 if heads .HeadBlockHash == (common.Hash {}) {
@@ -109,20 +112,14 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(heads beacon.ForkchoiceStateV1, pay
109112 return beacon.ForkChoiceResponse {Status : beacon .SUCCESS .Status , PayloadID : nil }, nil
110113}
111114
112- func computePayloadId (headBlockHash common.Hash , params * beacon.PayloadAttributesV1 ) beacon.PayloadID {
113- // Hash
114- hasher := sha256 .New ()
115- hasher .Write (headBlockHash [:])
116- binary .Write (hasher , binary .BigEndian , params .Timestamp )
117- hasher .Write (params .Random [:])
118- hasher .Write (params .SuggestedFeeRecipient [:])
119- var out beacon.PayloadID
120- copy (out [:], hasher .Sum (nil )[:8 ])
121- return out
122- }
123-
124- func (api * ConsensusAPI ) invalid () beacon.ExecutePayloadResponse {
125- return beacon.ExecutePayloadResponse {Status : beacon .INVALID .Status , LatestValidHash : api .eth .BlockChain ().CurrentHeader ().Hash ()}
115+ // GetPayloadV1 returns a cached payload by id.
116+ func (api * ConsensusAPI ) GetPayloadV1 (payloadID beacon.PayloadID ) (* beacon.ExecutableDataV1 , error ) {
117+ log .Trace ("Engine API request received" , "method" , "GetPayload" , "id" , payloadID )
118+ data := api .preparedBlocks .get (payloadID )
119+ if data == nil {
120+ return nil , & beacon .UnknownPayload
121+ }
122+ return data , nil
126123}
127124
128125// ExecutePayloadV1 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
@@ -159,8 +156,26 @@ func (api *ConsensusAPI) ExecutePayloadV1(params beacon.ExecutableDataV1) (beaco
159156 return beacon.ExecutePayloadResponse {Status : beacon .VALID .Status , LatestValidHash : block .Hash ()}, nil
160157}
161158
162- // AssembleBlock creates a new block, inserts it into the chain, and returns the "execution
163- // data" required for eth2 clients to process the new block.
159+ // computePayloadId computes a pseudo-random payloadid, based on the parameters.
160+ func computePayloadId (headBlockHash common.Hash , params * beacon.PayloadAttributesV1 ) beacon.PayloadID {
161+ // Hash
162+ hasher := sha256 .New ()
163+ hasher .Write (headBlockHash [:])
164+ binary .Write (hasher , binary .BigEndian , params .Timestamp )
165+ hasher .Write (params .Random [:])
166+ hasher .Write (params .SuggestedFeeRecipient [:])
167+ var out beacon.PayloadID
168+ copy (out [:], hasher .Sum (nil )[:8 ])
169+ return out
170+ }
171+
172+ // invalid returns a response "INVALID" with the latest valid hash set to the current head.
173+ func (api * ConsensusAPI ) invalid () beacon.ExecutePayloadResponse {
174+ return beacon.ExecutePayloadResponse {Status : beacon .INVALID .Status , LatestValidHash : api .eth .BlockChain ().CurrentHeader ().Hash ()}
175+ }
176+
177+ // assembleBlock creates a new block and returns the "execution
178+ // data" required for beacon clients to process the new block.
164179func (api * ConsensusAPI ) assembleBlock (parentHash common.Hash , params * beacon.PayloadAttributesV1 ) (* beacon.ExecutableDataV1 , error ) {
165180 log .Info ("Producing block" , "parentHash" , parentHash )
166181 block , err := api .eth .Miner ().GetSealingBlock (parentHash , params .Timestamp , params .SuggestedFeeRecipient , params .Random )
@@ -190,6 +205,12 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
190205 return txs , nil
191206}
192207
208+ // ExecutableDataToBlock constructs a block from executable data.
209+ // It verifies that the following fields:
210+ // len(extraData) <= 32
211+ // uncleHash = emptyUncleHash
212+ // difficulty = 0
213+ // and that the blockhash of the constructed block matches the parameters.
193214func ExecutableDataToBlock (params beacon.ExecutableDataV1 ) (* types.Block , error ) {
194215 txs , err := decodeTransactions (params .Transactions )
195216 if err != nil {
0 commit comments