Skip to content
Merged
Changes from all commits
Commits
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
68 changes: 59 additions & 9 deletions simulators/ethereum/engine/clmock.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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
}

Expand All @@ -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() {
Expand All @@ -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 {
Expand All @@ -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)
}
Expand Down Expand Up @@ -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 {
Expand Down