Skip to content

opcm.update prestate template#1336

Open
Wazabie wants to merge 32 commits intomainfrom
af/OPCM.updatePrestate-template
Open

opcm.update prestate template#1336
Wazabie wants to merge 32 commits intomainfrom
af/OPCM.updatePrestate-template

Conversation

@Wazabie
Copy link
Copy Markdown
Contributor

@Wazabie Wazabie commented Jan 10, 2026

Update prestate template for OPCMv600/U18

@Wazabie Wazabie requested review from a team as code owners January 10, 2026 22:33
@Wazabie Wazabie requested a review from stevennevins January 10, 2026 22:33
Comment thread src/template/OPCMUpdatePrestateV600.sol
Comment thread src/template/OPCMUpdatePrestateV600.sol
Comment thread src/template/OPCMUpdatePrestateV600.sol
@Wazabie Wazabie self-assigned this Jan 10, 2026
Comment thread src/template/OPCMUpdatePrestateV600.sol
Comment thread src/template/OPCMUpdatePrestateV600.sol
Comment thread src/template/OPCMUpdatePrestateV600.sol
Comment thread src/template/OPCMUpdatePrestateV600.sol
Comment thread src/template/OPCMUpdatePrestateV600.sol
Comment thread src/template/OPCMUpdatePrestateV600.sol
Wazabie and others added 2 commits January 11, 2026 10:31
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
Comment thread src/template/OPCMUpdatePrestateV600.sol
Comment thread src/template/OPCMUpdatePrestateV600.sol
Comment on lines +106 to +148
function _validate(VmSafe.AccountAccess[] memory, Action[] memory, address) internal view override {
SuperchainAddressRegistry.ChainInfo[] memory chains = superchainAddrRegistry.getChains();

// Cache standard validator's expected values (same for all chains)
address standardL1PAO = STANDARD_VALIDATOR.l1PAOMultisig();
address standardChallenger = STANDARD_VALIDATOR.challenger();

for (uint256 i = 0; i < chains.length; i++) {
uint256 chainId = chains[i].chainId;

IOPContractsManagerStandardValidator.ValidationInput memory input = IOPContractsManagerStandardValidator
.ValidationInput({
sysCfg: ISystemConfig(superchainAddrRegistry.getAddress("SystemConfigProxy", chainId)),
cannonPrestate: Claim.unwrap(upgrades[chainId].cannonPrestate),
cannonKonaPrestate: Claim.unwrap(upgrades[chainId].cannonKonaPrestate),
l2ChainID: chainId,
proposer: superchainAddrRegistry.getAddress("Proposer", chainId)
});

// Compute overrides: non-zero only if chain differs from standard
address l1PAOOverride = superchainAddrRegistry.getAddress("ProxyAdminOwner", chainId);
address challengerOverride = superchainAddrRegistry.getAddress("Challenger", chainId);

l1PAOOverride = l1PAOOverride != standardL1PAO ? l1PAOOverride : address(0);
challengerOverride = challengerOverride != standardChallenger ? challengerOverride : address(0);

string memory errors;
if (l1PAOOverride != address(0) || challengerOverride != address(0)) {
errors = STANDARD_VALIDATOR.validateWithOverrides({
_input: input,
_allowFailure: true,
_overrides: IOPContractsManagerStandardValidator.ValidationOverrides({
l1PAOMultisig: l1PAOOverride,
challenger: challengerOverride
})
});
} else {
errors = STANDARD_VALIDATOR.validate({_input: input, _allowFailure: true});
}

string memory expErrors = upgrades[chainId].expectedValidationErrors;
require(errors.eq(expErrors), string.concat("Unexpected errors: ", errors, "; expected: ", expErrors));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical bug: The validation function has the same issue as _build - it validates ALL chains from the registry without checking if they have configurations. If a chain exists in the registry but not in the upgrades mapping, it will validate using default zero values.

What breaks: For chains without configurations, upgrades[chainId] returns default struct values (zero prestates, empty string for expectedValidationErrors). This will pass incorrect zero prestates to the validator and compare against an empty expected error string, causing validation failures or false positives.

Fix: Only validate chains that have configurations:

function _validate(VmSafe.AccountAccess[] memory, Action[] memory, address) internal view override {
    SuperchainAddressRegistry.ChainInfo[] memory chains = superchainAddrRegistry.getChains();
    
    address standardL1PAO = STANDARD_VALIDATOR.l1PAOMultisig();
    address standardChallenger = STANDARD_VALIDATOR.challenger();

    for (uint256 i = 0; i < chains.length; i++) {
        uint256 chainId = chains[i].chainId;
        
        // Skip chains without configurations
        if (upgrades[chainId].chainId == 0) continue;
        
        // ... rest of validation logic
    }
}
Suggested change
function _validate(VmSafe.AccountAccess[] memory, Action[] memory, address) internal view override {
SuperchainAddressRegistry.ChainInfo[] memory chains = superchainAddrRegistry.getChains();
// Cache standard validator's expected values (same for all chains)
address standardL1PAO = STANDARD_VALIDATOR.l1PAOMultisig();
address standardChallenger = STANDARD_VALIDATOR.challenger();
for (uint256 i = 0; i < chains.length; i++) {
uint256 chainId = chains[i].chainId;
IOPContractsManagerStandardValidator.ValidationInput memory input = IOPContractsManagerStandardValidator
.ValidationInput({
sysCfg: ISystemConfig(superchainAddrRegistry.getAddress("SystemConfigProxy", chainId)),
cannonPrestate: Claim.unwrap(upgrades[chainId].cannonPrestate),
cannonKonaPrestate: Claim.unwrap(upgrades[chainId].cannonKonaPrestate),
l2ChainID: chainId,
proposer: superchainAddrRegistry.getAddress("Proposer", chainId)
});
// Compute overrides: non-zero only if chain differs from standard
address l1PAOOverride = superchainAddrRegistry.getAddress("ProxyAdminOwner", chainId);
address challengerOverride = superchainAddrRegistry.getAddress("Challenger", chainId);
l1PAOOverride = l1PAOOverride != standardL1PAO ? l1PAOOverride : address(0);
challengerOverride = challengerOverride != standardChallenger ? challengerOverride : address(0);
string memory errors;
if (l1PAOOverride != address(0) || challengerOverride != address(0)) {
errors = STANDARD_VALIDATOR.validateWithOverrides({
_input: input,
_allowFailure: true,
_overrides: IOPContractsManagerStandardValidator.ValidationOverrides({
l1PAOMultisig: l1PAOOverride,
challenger: challengerOverride
})
});
} else {
errors = STANDARD_VALIDATOR.validate({_input: input, _allowFailure: true});
}
string memory expErrors = upgrades[chainId].expectedValidationErrors;
require(errors.eq(expErrors), string.concat("Unexpected errors: ", errors, "; expected: ", expErrors));
}
function _validate(VmSafe.AccountAccess[] memory, Action[] memory, address) internal view override {
SuperchainAddressRegistry.ChainInfo[] memory chains = superchainAddrRegistry.getChains();
// Cache standard validator's expected values (same for all chains)
address standardL1PAO = STANDARD_VALIDATOR.l1PAOMultisig();
address standardChallenger = STANDARD_VALIDATOR.challenger();
for (uint256 i = 0; i < chains.length; i++) {
uint256 chainId = chains[i].chainId;
// Skip chains without configurations
if (upgrades[chainId].chainId == 0) continue;
IOPContractsManagerStandardValidator.ValidationInput memory input = IOPContractsManagerStandardValidator
.ValidationInput({
sysCfg: ISystemConfig(superchainAddrRegistry.getAddress("SystemConfigProxy", chainId)),
cannonPrestate: Claim.unwrap(upgrades[chainId].cannonPrestate),
cannonKonaPrestate: Claim.unwrap(upgrades[chainId].cannonKonaPrestate),
l2ChainID: chainId,
proposer: superchainAddrRegistry.getAddress("Proposer", chainId)
});
// Compute overrides: non-zero only if chain differs from standard
address l1PAOOverride = superchainAddrRegistry.getAddress("ProxyAdminOwner", chainId);
address challengerOverride = superchainAddrRegistry.getAddress("Challenger", chainId);
l1PAOOverride = l1PAOOverride != standardL1PAO ? l1PAOOverride : address(0);
challengerOverride = challengerOverride != standardChallenger ? challengerOverride : address(0);
string memory errors;
if (l1PAOOverride != address(0) || challengerOverride != address(0)) {
errors = STANDARD_VALIDATOR.validateWithOverrides({
_input: input,
_allowFailure: true,
_overrides: IOPContractsManagerStandardValidator.ValidationOverrides({
l1PAOMultisig: l1PAOOverride,
challenger: challengerOverride
})
});
} else {
errors = STANDARD_VALIDATOR.validate({_input: input, _allowFailure: true});
}
string memory expErrors = upgrades[chainId].expectedValidationErrors;
require(errors.eq(expErrors), string.concat("Unexpected errors: ", errors, "; expected: ", expErrors));
}

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant