diff --git a/simulators/ethereum/engine/clmock.go b/simulators/ethereum/engine/clmock.go index 0f3843b203..41b7df45ae 100644 --- a/simulators/ethereum/engine/clmock.go +++ b/simulators/ethereum/engine/clmock.go @@ -29,11 +29,12 @@ type CLMocker struct { ExecutedPayloadHistory map[uint64]ExecutableDataV1 // Latest broadcasted data using the PoS Engine API - LatestFinalizedNumber *big.Int - LatestFinalizedHeader *types.Header - LatestPayloadBuilt ExecutableDataV1 - LatestExecutedPayload ExecutableDataV1 - LatestForkchoice ForkchoiceStateV1 + LatestFinalizedNumber *big.Int + LatestFinalizedHeader *types.Header + LatestPayloadBuilt ExecutableDataV1 + LatestPayloadAttributes PayloadAttributesV1 + LatestExecutedPayload ExecutableDataV1 + LatestForkchoice ForkchoiceStateV1 // Merge related FirstPoSBlockNumber *big.Int @@ -207,7 +208,7 @@ func (cl *CLMocker) getNextPayloadID() { nextPrevRandao := common.Hash{} rand.Read(nextPrevRandao[:]) - payloadAttributes := PayloadAttributesV1{ + cl.LatestPayloadAttributes = PayloadAttributesV1{ Timestamp: cl.LatestFinalizedHeader.Time + 1, PrevRandao: nextPrevRandao, SuggestedFeeRecipient: cl.NextFeeRecipient, @@ -216,13 +217,16 @@ func (cl *CLMocker) getNextPayloadID() { // Save random value cl.PrevRandaoHistory[cl.LatestFinalizedHeader.Number.Uint64()+1] = nextPrevRandao - resp, err := cl.NextBlockProducer.EngineForkchoiceUpdatedV1(cl.NextBlockProducer.Ctx(), &cl.LatestForkchoice, &payloadAttributes) + resp, err := cl.NextBlockProducer.EngineForkchoiceUpdatedV1(cl.NextBlockProducer.Ctx(), &cl.LatestForkchoice, &cl.LatestPayloadAttributes) if err != nil { cl.Fatalf("CLMocker: Could not send forkchoiceUpdatedV1 (%v): %v", cl.NextBlockProducer.Client.Container, err) } if resp.PayloadStatus.Status != Valid { cl.Fatalf("CLMocker: Unexpected forkchoiceUpdated Response from Payload builder: %v", resp) } + if resp.PayloadStatus.LatestValidHash == nil || *resp.PayloadStatus.LatestValidHash != cl.LatestForkchoice.HeadBlockHash { + cl.Fatalf("CLMocker: Unexpected forkchoiceUpdated LatestValidHash Response from Payload builder: %v != %v", resp.PayloadStatus.LatestValidHash, cl.LatestForkchoice.HeadBlockHash) + } cl.NextPayloadID = resp.PayloadID } @@ -232,6 +236,21 @@ func (cl *CLMocker) getNextPayload() { if err != nil { cl.Fatalf("CLMocker: Could not getPayload (%v, %v): %v", cl.NextBlockProducer.Client.Container, cl.NextPayloadID, err) } + if cl.LatestPayloadBuilt.Timestamp != cl.LatestPayloadAttributes.Timestamp { + cl.Fatalf("CLMocker: Incorrect Timestamp on payload built: %d != %d", cl.LatestPayloadBuilt.Timestamp, cl.LatestPayloadAttributes.Timestamp) + } + if cl.LatestPayloadBuilt.FeeRecipient != cl.LatestPayloadAttributes.SuggestedFeeRecipient { + cl.Fatalf("CLMocker: Incorrect SuggestedFeeRecipient on payload built: %v != %v", cl.LatestPayloadBuilt.FeeRecipient, cl.LatestPayloadAttributes.SuggestedFeeRecipient) + } + if cl.LatestPayloadBuilt.PrevRandao != cl.LatestPayloadAttributes.PrevRandao { + cl.Fatalf("CLMocker: Incorrect PrevRandao on payload built: %v != %v", cl.LatestPayloadBuilt.PrevRandao, cl.LatestPayloadAttributes.PrevRandao) + } + if cl.LatestPayloadBuilt.ParentHash != cl.LatestFinalizedHeader.Hash() { + cl.Fatalf("CLMocker: Incorrect ParentHash on payload built: %v != %v", cl.LatestPayloadBuilt.ParentHash, cl.LatestFinalizedHeader.Hash()) + } + if cl.LatestPayloadBuilt.Number != cl.LatestFinalizedHeader.Number.Uint64()+1 { + cl.Fatalf("CLMocker: Incorrect Number on payload built: %v != %v", cl.LatestPayloadBuilt.Number, cl.LatestFinalizedHeader.Number.Uint64()+1) + } } func (cl *CLMocker) broadcastNextNewPayload() { @@ -258,8 +277,7 @@ func (cl *CLMocker) broadcastNextNewPayload() { // the blockHash of the payload is valid // the payload doesn't extend the canonical chain // the payload hasn't been fully validated. - nullHash := common.Hash{} - if resp.ExecutePayloadResponse.LatestValidHash != nil && *resp.ExecutePayloadResponse.LatestValidHash != nullHash { + if resp.ExecutePayloadResponse.LatestValidHash != nil && *resp.ExecutePayloadResponse.LatestValidHash != (common.Hash{}) { cl.Fatalf("CLMocker: NewPayload returned ACCEPTED status with incorrect LatestValidHash==%v", resp.ExecutePayloadResponse.LatestValidHash) } } else { @@ -275,6 +293,18 @@ func (cl *CLMocker) broadcastLatestForkchoice() { for _, resp := range cl.broadcastForkchoiceUpdated(&cl.LatestForkchoice, nil) { if resp.Error != nil { cl.Logf("CLMocker: broadcastForkchoiceUpdated Error (%v): %v\n", resp.Container, resp.Error) + } else if resp.ForkchoiceResponse.PayloadStatus.Status == Valid { + // {payloadStatus: {status: VALID, latestValidHash: forkchoiceState.headBlockHash, validationError: null}, + // payloadId: null} + if *resp.ForkchoiceResponse.PayloadStatus.LatestValidHash != cl.LatestForkchoice.HeadBlockHash { + cl.Fatalf("CLMocker: Incorrect LatestValidHash from ForkchoiceUpdated (%v): %v != %v\n", resp.Container, resp.ForkchoiceResponse.PayloadStatus.LatestValidHash, cl.LatestForkchoice.HeadBlockHash) + } + if resp.ForkchoiceResponse.PayloadStatus.ValidationError != nil { + cl.Fatalf("CLMocker: Expected empty validationError: %s\n", resp.Container, *resp.ForkchoiceResponse.PayloadStatus.ValidationError) + } + if resp.ForkchoiceResponse.PayloadID != nil { + cl.Fatalf("CLMocker: Expected empty PayloadID: %v\n", resp.Container, resp.ForkchoiceResponse.PayloadID) + } } else if resp.ForkchoiceResponse.PayloadStatus.Status != Valid { cl.Logf("CLMocker: broadcastForkchoiceUpdated Response (%v): %v\n", resp.Container, resp.ForkchoiceResponse) } @@ -367,6 +397,26 @@ func (cl *CLMocker) produceSingleBlock(callbacks BlockProcessCallbacks) { if newHeader.Hash() != cl.LatestPayloadBuilt.BlockHash { continue } + // Check that the new finalized header has the correct properties + // ommersHash == 0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347 + if newHeader.UncleHash != types.EmptyUncleHash { + cl.Fatalf("CLMocker: Client %v produced a new header with incorrect ommersHash: %v", ec.Container, newHeader.UncleHash) + } + // difficulty == 0 + if newHeader.Difficulty.Cmp(big0) != 0 { + cl.Fatalf("CLMocker: Client %v produced a new header with incorrect difficulty: %v", ec.Container, newHeader.Difficulty) + } + // mixHash == prevRandao + if newHeader.MixDigest != cl.PrevRandaoHistory[cl.LatestFinalizedNumber.Uint64()] { + cl.Fatalf("CLMocker: Client %v produced a new header with incorrect mixHash: %v != %v", ec.Container, newHeader.MixDigest, cl.PrevRandaoHistory[cl.LatestFinalizedNumber.Uint64()]) + } + // nonce == 0x0000000000000000 + if newHeader.Nonce != (types.BlockNonce{}) { + cl.Fatalf("CLMocker: Client %v produced a new header with incorrect nonce: %v", ec.Container, newHeader.Nonce) + } + if len(newHeader.Extra) > 32 { + cl.Fatalf("CLMocker: Client %v produced a new header with incorrect extraData (len > 32): %v", ec.Container, newHeader.Extra) + } cl.LatestFinalizedHeader = newHeader } if cl.LatestFinalizedHeader == nil {