Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/contracts/src/precompiles/validator_config_v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ crate::sol! {
error InvalidSignature();
error InvalidSignatureFormat();
error InvalidValidatorAddress();
error MigrationStateMismatch(uint64 idx);
error MigrationNotComplete();
error NotInitialized();
error NotIp(string input, string backtrace);
Expand Down Expand Up @@ -180,6 +181,10 @@ impl ValidatorConfigV2Error {
Self::AlreadyInitialized(IValidatorConfigV2::AlreadyInitialized {})
}

pub const fn migration_state_mismatch(idx: u64) -> Self {
Self::MigrationStateMismatch(IValidatorConfigV2::MigrationStateMismatch { idx })
}

pub const fn migration_not_complete() -> Self {
Self::MigrationNotComplete(IValidatorConfigV2::MigrationNotComplete {})
}
Expand Down
15 changes: 14 additions & 1 deletion crates/precompiles/src/validator_config_v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,10 +611,23 @@ impl ValidatorConfigV2 {

// NOTE: this count comparison is sufficient because `add_validator` and
// `rotate_validator` are blocked until the contract is initialized.
if self.validator_count()? < v1.validator_count()? {
let v2_count = self.validator_count()?;
let v1_count = v1.validator_count()?;
if v2_count < v1_count {
Err(ValidatorConfigV2Error::migration_not_complete())?
}

for i in 0..v1_count {
let v1_val = v1.validators(v1.validators_array(i)?)?;
let v2_val = self.validators[i as usize].read()?;
if v1_val.active && v2_val.deactivated_at_height != 0 {
Err(ValidatorConfigV2Error::migration_state_mismatch(i))?
Copy link
Contributor

@joshieDo joshieDo Feb 26, 2026

Choose a reason for hiding this comment

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

some smol unit test would be nice

}
if !v1_val.active && v2_val.deactivated_at_height == 0 {
Err(ValidatorConfigV2Error::migration_state_mismatch(i))?
Comment on lines +623 to +627
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's simplify this:

if v1_val.active != (v2_val.deactivated == 0) {
    return Err(ValidatorConfigV2Error::migration_state_mismatch(i));
}

}
}

let v1_next_dkg = v1.get_next_full_dkg_ceremony()?;
self.next_dkg_ceremony.write(v1_next_dkg)?;

Expand Down
11 changes: 11 additions & 0 deletions tips/ref-impls/src/ValidatorConfigV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,17 @@ contract ValidatorConfigV2 is IValidatorConfigV2 {
revert MigrationNotComplete();
}

for (uint64 i = 0; i < v1Validators.length; i++) {
bool v1Active = v1Validators[i].active;
uint64 v2Deactivated = validatorsArray[i].deactivatedAtHeight;
if (v1Active && v2Deactivated != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can probably express this in simpler terms similar to the rust code.

revert MigrationStateMismatch(i);
}
if (!v1Active && v2Deactivated == 0) {
revert MigrationStateMismatch(i);
}
}

nextDkgCeremony = v1.getNextFullDkgCeremony();

_initialized = true;
Expand Down
4 changes: 4 additions & 0 deletions tips/ref-impls/src/interfaces/IValidatorConfigV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ interface IValidatorConfigV2 {
/// @notice Thrown when migration is not complete (not all V1 validators migrated)
error MigrationNotComplete();

/// @notice Thrown when a migrated validator's active/deactivated state does not match V1
/// @param idx The index of the validator with mismatched state
error MigrationStateMismatch(uint64 idx);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be added to the spec?


/// @notice Thrown when migration index is out of order
error InvalidMigrationIndex();

Expand Down
Loading