OSSolidity.004 investigates a recently demonstrated smart-contract risk: Base’s Denim upgrade moved from one canonical block every 2 seconds to one every 200 milliseconds. A timer based on a fixed number of blocks could consequently finish 10 times sooner than its author intended. The danger is not that Solidity became faster; it is that block counts were mistaken for elapsed time.
The official Base engineering announcement, November 5, 2026, confirms the live mainnet change. BitcoinVersus.Tech previously covered the Denim rollout as technology news. The present lesson is a practical programming exercise, not a repeat of the news report.
Learning objectives and prerequisites
- Explain the differences among a canonical block, a block number, an on-chain timestamp, and transaction finality.
- Calculate block cadence, time-to-deadline, relative changes and their units without mistaking estimates for observations.
- Read and write
uint256,bool, constructor parameters, conditional expressions andrequirestatements. - Recognize a block-count timing anti-pattern and build a safer timestamp-based contract.
- Compile and exercise the code in a local Remix VM and record expected results and failure cases.
- Identify the limitations of timestamp precision, sequencer behavior and final settlement.
Prerequisites: OSSolidity.001: EVM and Smart Contracts and OSSolidity.002: Contract Structure. A browser with the Remix IDE is sufficient. Select Solidity compiler 0.8.38, officially released October 22, 2026. No mainnet wallet, ETH or external dependency is necessary.
The claim: 200 ms blocks are ten times as frequent
A canonical block is part of the chain’s current accepted history and carries a number, hash, state and transaction receipts. A block interval describes how frequently scheduled blocks appear. A block timestamp is an integer representation of time within that block. Finality is a stronger settlement guarantee: Base blocks become safe after their batches reach Ethereum and finalized when Ethereum finalizes those batches. Faster inclusion is not immediate Ethereum finality.
Calculate the rate: blocks per minute = 60 seconds ÷ seconds per block. Before Denim, 60 / 2 = 30 blocks/minute. After Denim, 60 / 0.2 = 300 blocks/minute. Therefore 300 / 30 = 10×. The increase in block count is (300 − 30) / 30 × 100 = 900%. Neither number is a measured transaction-per-second rate; empty blocks, gas limits and workload affect transaction throughput.

A smart-contract deadline can shrink from 60 to 6 minutes
Suppose a developer assumes a two-second interval and writes a rule allowing an action after 1,800 blocks. The old expected elapsed time was 1,800 × 2 = 3,600 seconds = 60 minutes. At 200 ms per block, the equivalent period is 1,800 × 0.2 = 360 seconds = 6 minutes. The deadline becomes 90% shorter, a critical difference for governance delays, auctions, vesting and withdrawal cooldowns.
// Anti-pattern: not a duration-safe deadline on Base.
// Assume the author intended 1,800 x 2 seconds = 1 hour.
uint256 public unlockBlock = block.number + 1800;
function unlocked() external view returns (bool) {
return block.number >= unlockBlock;
}
The anti-pattern compiles as Solidity code, but block.number counts chain progress; it is not a portable clock. Existing contracts cannot be assumed safe after an upgrade merely because their code remains unchanged. A contract whose threshold was established before Denim requires specific migration analysis rather than blindly multiplying remaining blocks.

Beginner Solidity: choose the correct types
The Solidity 0.8.38 reference defines block.number as an unsigned integer giving the block height and block.timestamp as an unsigned integer counting Unix seconds. A uint256 stores non-negative integers. A bool stores true or false. A constructor parameter such as uint256 delaySeconds supplies the wait interval when deploying the contract. The unit suffix 365 days is a compile-time conversion to seconds; it is not a calendar-aware year.
Base’s new BaseTime feature offers optional millisecond resolution, but ordinary block.timestamp still changes in whole seconds. Five consecutive 200 ms blocks can share the same timestamp. A basic one-hour or one-day deadline should use second-based time comparisons; millisecond operations require explicit Base-specific logic and additional testing.
SafeDeadline.sol — complete runnable classroom contract
Create a file named SafeDeadline.sol and paste the following source. The contract has no deposit or token-transfer functions, so a classroom exercise cannot inadvertently move cryptocurrency. The event gives a record of successful completion; the separate preview method only explores hypothetical timestamps and never bypasses access control.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.38;
contract SafeDeadline {
uint256 public immutable unlockAt;
bool public completed;
event Completed(address indexed caller, uint256 time);
constructor(uint256 delaySeconds) {
require(
delaySeconds > 0 && delaySeconds <= 365 days,
"invalid delay"
);
unlockAt = block.timestamp + delaySeconds;
}
function ready() public view returns (bool) {
return block.timestamp >= unlockAt;
}
function remainingSeconds() external view returns (uint256) {
if (ready()) return 0;
return unlockAt - block.timestamp;
}
function finish() external {
require(!completed, "already completed");
require(ready(), "deadline not reached");
completed = true;
emit Completed(msg.sender, block.timestamp);
}
// Classroom-only probe; it never authorizes finish().
function previewAt(uint256 pretendTime)
external view returns (bool)
{
return pretendTime >= unlockAt;
}
}
The immutable keyword makes unlockAt fixed after deployment. require rejects invalid durations, early execution and repeated execution. ready() compares the actual blockchain timestamp with the stored deadline. Solidity 0.8.x checks ordinary integer overflow. The finish() function modifies contract state only after both conditions pass.
Remix lab: compile, deploy and test
- Open Remix’s official Deploy & Run guide and choose the Remix VM environment, not a public blockchain or wallet extension.
- Choose compiler 0.8.38, compile
SafeDeadline.sol, selectSafeDeadlineand deploy with constructor argument3600. - Read the automatically generated
unlockAt()getter and record its integer timestamp asD. Readready()immediately; expected result isfalseunless the clock has advanced an hour. - Call
previewAt(D − 1). Expected:false. CallpreviewAt(D). Expected:true. These probes test boundary logic, not the live VM clock. - Call
finish()before the real deadline. Expected: transaction reverts withdeadline not reached. - Try deploying with
0or31536001seconds. Both constructors should revert withinvalid delay. - After advancing the VM clock through supported test tooling past the deadline, call
finish()once (expected success andcompleted() == true) and call again (expectedalready completedrevert). No claim is made that the final time-advancement test was executed here.
Numerical unit tests and expected output
The following pure function can be added inside SafeDeadline for a classroom self-check. Its returned boolean should be true in Remix; it performs arithmetic without using live blockchain state. Nine independent arithmetic assertions covering the same formulas were executed separately during preparation; Solidity compilation and EVM execution were not available in the authoring environment.
// Independent classroom arithmetic checks; no blockchain calls.
function cadenceMath() external pure returns (bool) {
uint256 beforePerMinute = 60 / 2; // 30
uint256 afterPerMinute = 60_000 / 200; // 300
uint256 oldSeconds = 1800 * 2; // 3600
uint256 newSeconds = 1800 * 200 / 1000; // 360
return beforePerMinute == 30
&& afterPerMinute == 300
&& oldSeconds == 3600
&& newSeconds == 360;
}
Expected numeric outputs: before 30 blocks/min, after 300 blocks/min, old 1,800-block duration 3,600 seconds, and new duration 360 seconds. The plot below shows additional threshold values. Larger block counts produce longer nominal waits, but every matched fixed count becomes one tenth as long under a tenfold higher block cadence.

Troubleshooting and security
- Compilation fails: verify
pragma solidity 0.8.38;matches the selected compiler exactly and all braces and semicolons are present. - The deadline looks enormous: Unix timestamps are seconds since January 1, 1970, not human-readable dates. Convert only for display; retain integer seconds for comparisons.
ready()stays false: the local VM time has not reached the deadline. A hypotheticalpreviewAt()call does not advance blockchain time.- Fast blocks appear final: canonical inclusion and Ethereum settlement are separate stages. Sensitive withdrawals should explicitly define the required confirmation and finality policy.
- A time rule works only on Base: do not treat
block.numberor proprietaryBaseTimebehavior as portable to every Ethereum-compatible network. - Contract accepts funds: do not add deposits, withdrawals, privileged actions or arbitrary token transfers to a classroom example without audited permission checks, reentrancy controls and independent tests.
The advanced lesson is about dependency management: block production cadence can change through network upgrades. Time-based policies should be modeled in seconds, tested at boundaries and audited when protocol parameters change. For a comparison of infrastructure upgrade stages, review the Ethereum Glamsterdam testnet coverage and the underlying virtual-machine fundamentals.
Assessment
- A Base contract counts 3,600 blocks to represent two hours at 2 seconds per block. How long would the same count take at a scheduled 200 ms interval?
- Why does a 200 ms block interval not prove 200 ms transaction finality?
- What is the difference between
uint256andboolinSafeDeadline? - Why might five consecutive Base blocks report the same ordinary
block.timestamp? - What happens when
finish()runs beforeunlockAtor aftercompletedbecomes true?
Answer key
A 3,600-block interval is 12 minutes at 200 ms/block. Canonical inclusion is weaker than Ethereum settlement. uint256 stores integer time values, while bool stores a true/false state. Ordinary EVM timestamps retain one-second precision despite five scheduled blocks per second. finish() reverts before the deadline and reverts again once already completed.
References and next lesson
Primary references: Base Engineering Team, November 5, 2026; Solidity 0.8.38 units and global variables; October 22 compiler release; Remix Deploy & Run; and Solidity security considerations. The next subject in the full curriculum rotation is SQL. The following Solidity-track installment can deepen integer types, arithmetic, input validation and guarded state changes.
Editor’s Note
The 200 ms block interval, the 2-second predecessor and associated clock behavior come from the Base team’s November 5, 2026 mainnet announcement. All charts are deterministic calculations from those published protocol values, not network throughput benchmarks. Nine independent numerical assertions passed in the preparation environment. The Solidity code is designed for Remix compiler 0.8.38 but was not compiled or executed in a Solidity environment during publication preparation; exercise outputs are expected results, not verified runtime logs. The featured image is an AI-generated editorial illustration, not a documentary equipment photo.
Support BitcoinVersus.Tech
To support free educational materials, scan the original BitcoinVersus.Tech donation QR using a compatible Bitcoin wallet for an optional 5,000-satoshi contribution. On mobile, show the code on another device or use supported wallet image-scanning features. Verify the receiving address and amount before sending.

We volunteer daily to ensure the information on this platform is Verifiably True. If you would like to support the research, please scan QR code.

Leave a Reply