Skip to content

Conversation

@alrevuelta
Copy link
Collaborator

@alrevuelta alrevuelta commented Oct 21, 2025

@alrevuelta alrevuelta changed the base branch from main to feature/v12 October 21, 2025 09:59
* The addresses and threshold are managed by the aggchainManager.
*/
contract AggchainECDSAMultisig is AggchainBase {
contract AggchainECDSAMultisig is AggchainBase, MigrationFEPToECDSASlots {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

do you both @invocamanman and @krlosMata agree on this approach?

Copy link
Member

Choose a reason for hiding this comment

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

I think it is not needed, although is does not hurt.
A comment should be enough since the storage slots fulfilled are just not used.
It is needed a deeper analysis if the chain goes again to FEP. Check if the storage slots are rewritten or can potentially imply a security issue


/// @notice Aggchain version
string public constant AGGCHAIN_ECDSA_MULTISIG_VERSION = "v1.0.0";
string public constant AGGCHAIN_ECDSA_MULTISIG_VERSION = "v1.0.1";
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

unsure if this makes sense. breaks a lot of stuff. but since the contract is changing we need versioning? using semver, +0.0.1 since its not breaking

Copy link
Member

Choose a reason for hiding this comment

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

it does not. I'd increase also to v1.0.1

address public pendingOptimisticModeManager;
mapping(bytes32 => AggchainFEP.OpSuccinctConfig) public opSuccinctConfigs;
bytes32 public selectedOpSuccinctConfigName;
bytes32 public lastRollupExitRoot;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why are you adding this storage that is not from FEP? There is an old deployed version of aggchainFEP with this storage? 🤔 (same for lastMainnetExitRoot, globalExitRootMap)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

good catch. i messed it with the copy paste. fixed 2818965

bytes32 public selectedOpSuccinctConfigName;
bytes32 public lastRollupExitRoot;
bytes32 public lastMainnetExitRoot;
mapping(bytes32 => uint256) public globalExitRootMap;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would consider adding a _gap[50] for future upgrades of FEP

@invocamanman
Copy link
Collaborator

check contract LegacyZKEVMStateVariables {
specially:
e.g

    /// @custom:oz-renamed-from multiplierBatchFee
    uint16 internal _legacyMultiplierBatchFee;

I woudl do a very similar approach here, changing names and adig the custom ox renamed from
( This can be veyr easily done with IA :P)

@invocamanman
Copy link
Collaborator

Remmeber to:
Clear possible storage slots from FEP
check if FEP uses something aggchainBase that's not used in ECDSA multisig

@alrevuelta
Copy link
Collaborator Author

There is one issue with this feature. Due to how initializers work when using upgradable contracts, there is an implicit assumption that the only allowed path is ECDSA->FEP (not the opposite way), see reinitializer(3) in AggchainFEP and reinitializer(2) in AggchainECDSAMultisig

This means that as it is, if we add a new path FEP->ECDSA, we will create an inconsistency in a migration that goes FEP->ECDSA->FEP. In the ECDSA->FEP transition initializeFromECDSAMultisig can't be called anymore, due to the modifier, leading to an inconsistency. This makes this function work only sometimes (when state n-2 was not FEP). This doesn't seem ok to me.

One option would be to remove the reinitializer(3) modifier from initializeFromECDSAMultisig but if we do so, then the function can be called multiple times, so it wont be an initializer per se anymore.

@krlosMata
Copy link
Member

I think it depends on the design that we want to take id a chain decides to move from FEP --> ECDSA --> FEP:

  • Design A
    • the chain should prove all state-transition from the last time that it was an FEP
    • no changes required in the SC
  • Design B
    • new SC call reinitializel2Output that only the aggchainManager can call (same securoty assumption since it can effectivellt set up a new aggVKEy, rangeVKey and rollupConfigHash)
      • the function just adds a new l2Output element

@alrevuelta
Copy link
Collaborator Author

@krlosMata agree with your approaches, but wanted to also address this concern.

This means that as it is, if we add a new path FEP->ECDSA, we will create an inconsistency in a migration that goes FEP->ECDSA->FEP. In the ECDSA->FEP transition initializeFromECDSAMultisig can't be called anymore, due to the modifier, leading to an inconsistency.

@krlosMata
Copy link
Member

@krlosMata agree with your approaches, but wanted to also address this concern.

This means that as it is, if we add a new path FEP->ECDSA, we will create an inconsistency in a migration that goes FEP->ECDSA->FEP. In the ECDSA->FEP transition initializeFromECDSAMultisig can't be called anymore, due to the modifier, leading to an inconsistency.

I think it is not an inconsistency. This function can be called the first time that we move from ECDSA --> FEP so certain parameters can be properly initialized. If those parameters are already initialized and the chain goes again from ECDSA --> FEP, all those parameters can be reset again, each one with its own setter....expect the initial l2Output.

@alrevuelta
Copy link
Collaborator Author

I think it is not an inconsistency. This function can be called the first time that we move from ECDSA --> FEP so certain parameters can be properly initialized. If those parameters are already initialized and the chain goes again from ECDSA --> FEP, all those parameters can be reset again, each one with its own setter....expect the initial l2Output.

yep. more than inconsistency i mean that is not idempotent. you can use the setters but you can no longer call initializeFromECDSAMultisig the second time. If that fine, i think your Design B makes sense.


function reinitializel2Outputs() external {
// Clear the array by popping all elements
while (l2Outputs.length > 0) {
Copy link
Member

Choose a reason for hiding this comment

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

just setting the length to 0 is enough

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

cant directly set it to 0.

TypeError: Member "length" is read-only and cannot be used to resize arrays.
   --> contracts/aggchains/AggchainFEP.sol:446:9:
    |
446 |         l2Outputs.length = 0;
    |         ^^^^^^^^^^^^^^^^

But i can call delete. fixed a27bfd6

Copy link
Member

Choose a reason for hiding this comment

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

older solidity versions allowed it

}
}

function reinitializel2Outputs() external {
Copy link
Member

Choose a reason for hiding this comment

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

missing onlyRollupManager

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fixed a27bfd6

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

using onlyAggchainManager as discussed privately

// If update from FEP to ECDSA, clear l2Outputs before upgrade.
// This ensures if it migrates back to FEP, the l2Outputs are empty.
if (
rollup.rollupVerifierType == VerifierType.ALGateway &&
Copy link
Member

Choose a reason for hiding this comment

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

I think adding chain specific configuration in the AgglayerManager.sol should not be done....it should be at Chains SC level.
Also, we lost history of previous verified states which may be useful.

I think it better to manage this exact same function, but on the chain implementation. I think it is easier on the long-term rather than managing all of them in the Manager

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i see. removed here. a27bfd6
the function call can be passed now as rollupData

a27bfd6#diff-5c5d2e61f08010833196980538de8ebd806d00d53326e4ba06319f3474d7d30bR440

@alrevuelta
Copy link
Collaborator Author

Summary of the FEP->ECDSA migration:

  • Without modifying the contracts we could perform the FEP->ECDSA migration by calling just updateRollup. However, adding this new migration adds a new whole dimension to migration paths:
    • Before: There was an implicit assumption that migrations where "linear". ECDSA->FEP. Without ever coming back.
    • Now: If we allow FEP->ECDSA, migration can now be "circular". Meaning one can in theory do FEP->ECDSA->FEP. This opens up new problems.
  • The main problem we can face in the FEP->ECDSA->FEP case is having stale FEP slots that may not make sense anymore after we migrate again to FEP. To solve this we have two approaches. i) When migrating to ECDSA clean up all slots or ii) keep the original slots and just clean up l2Outputs. We have chosen approach ii) in this PR, see reinitializel2Outputs.
  • Other side effects of this new path is that some initializers won't work (due to the reinitialize(x)). Eg initializeFromECDSAMultisig won't work in the FEP-ECDSA-FEP case.
  • So in short, FEP->ECDSA is possible and relatively easy. We have taken some decissions on how FEP->ECDSA->FEP can behave but most likely this path will be quite rare.

Base automatically changed from feature/v12 to develop December 19, 2025 14:56
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.

5 participants