diff --git a/consensus/system_contract/consensus.go b/consensus/system_contract/consensus.go index 797297870d86..2f3c389504b1 100644 --- a/consensus/system_contract/consensus.go +++ b/consensus/system_contract/consensus.go @@ -226,15 +226,34 @@ func (s *SystemContract) VerifyUncles(chain consensus.ChainReader, block *types. } func (s *SystemContract) CalcTimestamp(parent *types.Header) uint64 { - timestamp := parent.Time + s.config.Period + // Get the base timestamp (in seconds) + baseTimestamp := parent.Time + + // Convert period to milliseconds and calculate blocks per second + // For example: if Period = 250ms = 0.25s, then periodMs = 250 + periodMs := s.config.Period + blocksPerSecond := 1000 / periodMs // integer division, e.g. 1000/250 = 4 + if blocksPerSecond == 0 { + blocksPerSecond = 1 + } + + // Calculate the block index within the current second + blockIndex := parent.Number.Uint64() % blocksPerSecond + + // If this block is the last one in the current second, increment the timestamp + // We compare with blocksPerSecond-1 because blockIndex is 0-based + if blockIndex == blocksPerSecond-1 { + baseTimestamp++ + } // If RelaxedPeriod is enabled, always set the header timestamp to now (ie the time we start building it) as // we don't know when it will be sealed - if s.config.RelaxedPeriod || timestamp < uint64(time.Now().Unix()) { - timestamp = uint64(time.Now().Unix()) + nowTimestamp := uint64(time.Now().Unix()) + if s.config.RelaxedPeriod || baseTimestamp < nowTimestamp { + baseTimestamp = nowTimestamp } - return timestamp + return baseTimestamp } // Prepare initializes the consensus fields of a block header according to the diff --git a/miner/scroll_worker.go b/miner/scroll_worker.go index b95fb6027aee..9504639e315b 100644 --- a/miner/scroll_worker.go +++ b/miner/scroll_worker.go @@ -557,9 +557,24 @@ func (w *worker) newWork(now time.Time, parentHash common.Hash, reorging bool, r // clique with relaxed period uses time.Now() as the header.Time, calculate the deadline deadline = time.Unix(int64(header.Time+w.chainConfig.Clique.Period), 0) } - if w.chainConfig.SystemContract != nil && w.chainConfig.SystemContract.RelaxedPeriod { - // system contract with relaxed period uses time.Now() as the header.Time, calculate the deadline - deadline = time.Unix(int64(header.Time+w.chainConfig.SystemContract.Period), 0) + if w.chainConfig.SystemContract != nil { + periodMs := w.chainConfig.SystemContract.Period + blocksPerSecond := uint64(1000) / periodMs + if blocksPerSecond == 0 { + blocksPerSecond = 1 + } + + // Calculate the actual timing based on block number within the current second + blockIndex := header.Number.Uint64() % blocksPerSecond + + // Calculate base time and add the fraction of a second based on block index + baseTimeNano := int64(header.Time) * int64(time.Second) + fractionNano := int64(blockIndex) * int64(periodMs) * int64(time.Millisecond) + + // Add one period to determine the deadline + nextBlockNano := baseTimeNano + fractionNano + int64(periodMs)*int64(time.Millisecond) + + deadline = time.Unix(0, nextBlockNano) } w.current = &work{ diff --git a/params/config.go b/params/config.go index d5f1a2166c21..329856accd79 100644 --- a/params/config.go +++ b/params/config.go @@ -797,7 +797,7 @@ func (c *CliqueConfig) String() string { // SystemContractConfig is the consensus engine configs for rollup sequencer sealing. type SystemContractConfig struct { - Period uint64 `json:"period"` // Number of seconds between blocks to enforce + Period uint64 `json:"period"` // Number of milliseconds between blocks to enforce SystemContractAddress common.Address `json:"system_contract_address"` // address of system contract on L1 SystemContractSlot common.Hash `json:"system_contract_slot"` // slot of signer address in system contract on L1 diff --git a/params/version.go b/params/version.go index d3a716650585..c3e76c74e660 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 5 // Major version component of the current release VersionMinor = 8 // Minor version component of the current release - VersionPatch = 40 // Patch version component of the current release + VersionPatch = 41 // Patch version component of the current release VersionMeta = "mainnet" // Version metadata to append to the version string )