diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 6f2d3e76b78e9..80759baddea2d 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -305,12 +305,13 @@ func (api *ConsensusAPI) assembleBlock(parentHash common.Hash, params *PayloadAt return nil, fmt.Errorf("cannot assemble block with unknown parent %s", parentHash) } - if params.Timestamp < parent.Time() { - return nil, fmt.Errorf("child timestamp lower than parent's: %d < %d", params.Timestamp, parent.Time()) + if params.Timestamp <= parent.Time() { + return nil, fmt.Errorf("child timestamp lower or equal to parent's: %d < %d", params.Timestamp, parent.Time()) } if now := uint64(time.Now().Unix()); params.Timestamp > now+1 { diff := time.Duration(params.Timestamp-now) * time.Second log.Warn("Producing block too far in the future", "diff", common.PrettyDuration(diff)) + return nil, fmt.Errorf("timestamp too far in the future: %d > %d", params.Timestamp, now) } pending := api.eth.TxPool().Pending(true) coinbase := params.SuggestedFeeRecipient diff --git a/eth/catalyst/api_test.go b/eth/catalyst/api_test.go index aa5cb80eef1d3..a9ea2eb5525e4 100644 --- a/eth/catalyst/api_test.go +++ b/eth/catalyst/api_test.go @@ -184,6 +184,41 @@ func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan co } } +func TestInvalidPayloadTimestamp(t *testing.T) { + genesis, preMergeBlocks := generatePreMergeChain(10) + n, ethservice := startEthService(t, genesis, preMergeBlocks) + ethservice.Merger().ReachTTD() + defer n.Close() + var ( + api = NewConsensusAPI(ethservice, nil) + parent = ethservice.BlockChain().CurrentBlock() + ) + tests := []uint64{ + 0, + parent.Time(), + parent.Time() - 1, + uint64(time.Now().Unix()) + uint64(time.Minute), + } + + for _, test := range tests { + params := PayloadAttributesV1{ + Timestamp: test, + Random: crypto.Keccak256Hash([]byte{byte(123)}), + SuggestedFeeRecipient: parent.Coinbase(), + } + fcState := ForkchoiceStateV1{ + HeadBlockHash: parent.Hash(), + SafeBlockHash: common.Hash{}, + FinalizedBlockHash: common.Hash{}, + } + _, err := api.ForkchoiceUpdatedV1(fcState, ¶ms) + if err == nil { + t.Fatalf("expected error preparing payload with invalid timestamp, err=%v", err) + } + } + +} + func TestEth2NewBlock(t *testing.T) { genesis, preMergeBlocks := generatePreMergeChain(10) n, ethservice := startEthService(t, genesis, preMergeBlocks) @@ -413,6 +448,5 @@ func TestFullAPI(t *testing.T) { t.Fatalf("Chain head should be updated") } parent = ethservice.BlockChain().CurrentBlock() - } }