chore(upgrade-signal): read new ProtocolVersions schedule contract#3963
chore(upgrade-signal): read new ProtocolVersions schedule contract#3963PelleKrab wants to merge 5 commits into
Conversation
✅ Heimdall Review Status
|
8b0a575 to
b8b8020
Compare
c80117f to
93c2d9d
Compare
Replace the per-upgrade IUpgradeSignal reads (getTimestamp/getProtocolVersion by name) with the new ProtocolVersions interface from base/contracts#353: - read the full id-ordered schedule with one getSchedule() call and the global minimumProtocolVersion() in a single pinned L1 block read - map schedule entries onto the node hardfork ladder in activation (timestamp) order: id 0 (lowest timestamp) aligns with the oldest contract-backed hardfork; entries newer than the known ladder are logged and ignored, and unregistered hardforks produce no signal - attach the global minimum protocol version to every mapped signal so the existing validation and sink pipeline is unchanged - bump the supported node protocol version from 7 to packed semver 1.1.0 - drop the now-impossible TimestampOverflow error (timestamps are uint64 onchain)
Co-authored-by: Codex <codex-noreply@coinbase.com>
Cache node_protocol_version() in a LazyLock and add tests for the 0.0.0 -> U256::MAX dev-build invariant. Note the packed-semver input assumption on protocol_version_to_f64. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
The reader only issues eth_calls for getSchedule and minimumProtocolVersion; nothing decodes TimestampSet or MinimumProtocolVersionUpdated. Remove them and re-add if event-based reads are introduced later. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
93c2d9d to
6581bce
Compare
…sion - Document that map_schedule aligns entries by registration id (positional), not by activation timestamp; timestamps need not be monotonic (README + doc). - Cache the Cargo-derived node protocol version in a LazyLock instead of recomputing on every call. Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
Review SummaryThe refactor from per-upgrade What looks good:
No new findings. The inline comments from the previous review run cover the remaining minor items (metrics gauge behavior with |
❌ base-std fork tests did not runThe build or setup step failed before any tests could execute. Check the workflow logs for details.
|
jackchuma
left a comment
There was a problem hiding this comment.
looks good - just one optional nit to address
| pub fn node_protocol_version() -> U256 { | ||
| *NODE_PROTOCOL_VERSION | ||
| } | ||
|
|
||
| /// Encodes a `major.minor.patch` version into the packed-semver `uint256` layout used by the | ||
| /// L1 `ProtocolVersions` contract: `major << 96 | minor << 64 | patch << 32`, with the | ||
| /// prerelease field left zero. | ||
| pub const fn packed_protocol_version(major: u32, minor: u32, patch: u32) -> U256 { | ||
| U256::from_limbs([(patch as u64) << 32, ((major as u64) << 32) | minor as u64, 0, 0]) | ||
| } | ||
|
|
||
| /// Maps a packed Cargo version to the advertised node protocol version, promoting the | ||
| /// dev-build `0.0.0` (zero) to `U256::MAX` so no contract minimum can reject a dev build. | ||
| pub fn advertised_protocol_version(cargo_version: U256) -> U256 { | ||
| if cargo_version == U256::ZERO { U256::MAX } else { cargo_version } | ||
| } | ||
| } | ||
|
|
||
| /// Node protocol version derived from the compile-time Cargo package version, computed once. | ||
| static NODE_PROTOCOL_VERSION: LazyLock<U256> = LazyLock::new(|| { | ||
| UpgradeSignalDefaults::advertised_protocol_version( | ||
| UpgradeSignalDefaults::packed_protocol_version( | ||
| env!("CARGO_PKG_VERSION_MAJOR").parse::<u32>().expect("Cargo package major is numeric"), | ||
| env!("CARGO_PKG_VERSION_MINOR").parse::<u32>().expect("Cargo package minor is numeric"), | ||
| env!("CARGO_PKG_VERSION_PATCH").parse::<u32>().expect("Cargo package patch is numeric"), | ||
| ), | ||
| ) | ||
| }); |
There was a problem hiding this comment.
nit: LazyLock looks unnecessary here. CARGO_PKG_VERSION_* values are compile-time strings, and node_protocol_version() is only used while building upgrade-signal configuration, so caching the three parses adds global state without a meaningful payoff. Consider parsing and packing directly in node_protocol_version() instead; that removes the static and LazyLock import with no behavior change
Summary
Adds support for reading dynamic upgrade activation schedules from the L1
ProtocolVersionscontract.This updates the upgrade-signal utility to:
getSchedule()minimumProtocolVersion()BaseUpgrade::CONTRACT_VARIANTS0.0.0dev builds to bypass the minimum-version rejection withU256::MAXThe Solidity ABI in this crate intentionally includes only the read surface used by nodes, not the
full contract interface.
Notes
CONTRACT_VARIANTSremains explicit because it is not the same as allBaseUpgradevariants. Itrepresents the contract-backed upgrade set in L1 schedule order and intentionally excludes non-
contract-backed upgrades like
BedrockandZombie.Tests
cargo fmt --check -p base-upgrade-signal cargo test -p base-upgrade-signal --all-features cargo clippy -p base-upgrade-signal --all-targets --all-features -- -D warnings