Skip to content

TIP-1017 Validator Config V2#2181

Merged
SuperFluffy merged 28 commits intomainfrom
janis/val-cfg-v2
Feb 9, 2026
Merged

TIP-1017 Validator Config V2#2181
SuperFluffy merged 28 commits intomainfrom
janis/val-cfg-v2

Conversation

@SuperFluffy
Copy link
Copy Markdown
Contributor

@SuperFluffy SuperFluffy commented Jan 20, 2026

Rendered TIP-1017

@SuperFluffy SuperFluffy force-pushed the janis/val-cfg-v2 branch 2 times, most recently from e61f62b to 9824220 Compare January 20, 2026 17:26
@SuperFluffy SuperFluffy changed the title WIP: TIP-1008 WIP: TIP-XXXX Validator Config V2 Jan 20, 2026
Comment thread tips/tip-1017.mdx
@SuperFluffy SuperFluffy force-pushed the janis/val-cfg-v2 branch 3 times, most recently from 920281b to 983e145 Compare January 21, 2026 13:12
Comment thread tips/tip-1017.mdx
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread tips/tip-1017.mdx
SuperFluffy and others added 2 commits January 22, 2026 12:53
Comment thread tips/tip-1017.mdx
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread tips/tip-1017.mdx
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread tips/tip-1017.mdx
Comment thread tips/tip-1017.mdx
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread tips/tip-1017.mdx
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
at the boundary height:

```
if chainspec.is_allegro_active_at_timestamp(block.timestamp) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
if chainspec.is_allegro_active_at_timestamp(block.timestamp) {
if chainspec.is_hardfork_active_at_timestamp(contract_upgrade_hardfork, block.timestamp) {

Copy link
Copy Markdown
Contributor Author

@SuperFluffy SuperFluffy Feb 5, 2026

Choose a reason for hiding this comment

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

Why the extra contract_upgrade_hardfork argument?

Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread tips/tip-1017.mdx
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread docs/pages/protocol/tips/tip-xxxx.mdx Outdated
Comment thread tips/tip-1017.mdx
SuperFluffy and others added 4 commits January 28, 2026 12:47
## Summary

**Manual migration**: Admin migrates validators one at a time via
`migrateValidator(valIdx)`, then calls `initialize()` to flip the flag.
CL reads from V1 until the flag is set.

| Change | Description |
|--------|-------------|
| **Read before init** | CL reads directly from V1 (no proxying in V2) |
| **migrateValidator(valIdx)** | Migrates single validator; copies owner
on first call; reverts if `valIdx != validatorsArray.length` |
| **initialize()** | Copies `nextDkgCeremony` from V1, sets `initialized
= true` |
| **Active validators** | `addedAtHeight = 0`, `deletedAtHeight = 0` |
| **Inactive validators** | `addedAtHeight = deletedAtHeight =
block.timestamp` |
| **Filter logic** | `v.addedAtHeight <= H && (deletedAtHeight == 0 \|\|
deletedAtHeight > H)` |

## Migration Steps (Existing Networks)

1. Release new node software with Allegro hardfork support
2. Schedule the fork by updating chainspec with target `allegroTime`
3. At fork activation: CL reads from V1 (since `isInitialized() ==
false`)
4. Admin migrates validators: `migrateValidator(0)`,
`migrateValidator(1)`, ...
5. Admin calls `initialize()` → sets `initialized = true`, CL reads from
V2
6. Post-migration: All reads/writes use V2 state directly

## New Networks

1. Initialize V2 at genesis with the initial validator set (set
`initialized = true`)
2. Set `allegroTime = 0` to activate V2 immediately
3. V1 Validator Config contract/precompile is not necessary

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Richard Janis Goldschmidt <github@aberrat.io>
Co-authored-by: Tanishk Goyal <goyaltanishk02@gmail.com>
Comment thread tips/tip-1017.mdx
function deactivateValidator(address validatorAddress) external;

/// @notice Rotate a validator to a new identity (owner or validator only)
/// @dev Atomically deletes the specified validator entry and adds a new one. This is equivalent
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.

If you do it this way, and I rotate a validator mid-epoch, i would be ineligible to participate in the next DKG right? is that intentional? the fact that you're saying it is equivalent to delete and then add suggests that it is intentional, but given our current thin margins is this safe (we might have too few players available for the next dkg)

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.

nevermind now i understand. it might be worth explaining to validators that rotation involves a one epoch worth of deactivation (if it wasn't explained somewhere that i missed) but i think no change needed here.

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.

maybe worth a test case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is briefly explained in the doc, but I agree - we should make this part of the docs so people understand.

But you pointing this out raises a point about how this spec wants to make deactivation immediate while leaving 1 epoch to warmup the new validator:

  1. in epoch E: call rotateValidator($old, $new)
  2. in epoch E+1: $old leaves the set of players (it is still a validator + dealer in this epoch); $new is not a player, merely registered as a peer and receives votes and certificates allowing it to sync up
  3. in epoch E+2: $old dropped out of the committee; $new is a player and will receives shares from the other dealers to acknowledge
  4. in epoch E+3: $new is in the committee.

This means there is a forced downtime of 1 epoch.

Comment thread tips/tip-1017.mdx Outdated
14. **Address update**: `transferValidatorOwnership` updates the address of an existing
validator without changing any other fields. This is useful for updating
addresses post-migration or correcting address assignments.

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.

this clashes with invariant 2?

Copy link
Copy Markdown
Contributor Author

@SuperFluffy SuperFluffy Feb 9, 2026

Choose a reason for hiding this comment

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

Good catch! I updated invariant 2 and moved 14 into position 3 to clarify this point: validatorAddress is only mutable by the contract owner to address post-migration fixes. It cannot be changed by the owner of the entry.

c01f841

Comment thread tips/tip-1017.mdx Outdated
Comment thread tips/tip-1017.mdx
function deactivateValidator(address validatorAddress) external;

/// @notice Rotate a validator to a new identity (owner or validator only)
/// @dev Atomically deletes the specified validator entry and adds a new one. This is equivalent
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.

maybe worth a test case?

Comment thread tips/tip-1017.mdx
8. **Historical consistency**: For any height H, the active validator set
consists of validators where `addedAtHeight <= H && (deactivatedAtHeight == 0 ||
deactivatedAtHeight > H)`. Validators with `addedAtHeight == deactivatedAtHeight` are
never considered active.
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.

should add !=0 here right? otherwise you rule out migrated vals...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank you once more. This, too, was incorrect. addedAtHeight = block.height always: f80ecc4

Comment thread tips/tip-1017.mdx Outdated
))
```

The old validator is identified by `msg.sender`, which must be an existing active validator.
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.

i think this contradicts invariant 11?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed that comment - unnecessary and confusing: d57544c

Comment thread tips/tip-1017.mdx

---

# Invariants
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.

Amp suggested this: "For validators added via addValidator, addedAtHeight > 0. addedAtHeight == 0 is reserved for validators migrated from V1

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I changed this in f80ecc4: addedAtHeight is now always set to block.height. While this might be confusing for historical backlook, this is fine from CL's point of view because we only care about looking forward.

Comment thread tips/tip-1017.mdx
**Validator Addition and Deactivation**: When validators are added or deleted (this also applies to rotation),
there is no warmup period: deactivated validators are immediately removed from the set of players on the next epoch,
while activated validators are immediately added on the next epoch. This means that compared to validator config V1,
there is no cooldown and no warmup period.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@Zygimantass for confirmation: there is no cooldown and warmup period anymore.

@SuperFluffy SuperFluffy enabled auto-merge February 9, 2026 16:26
@SuperFluffy SuperFluffy added this pull request to the merge queue Feb 9, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Feb 9, 2026
@SuperFluffy SuperFluffy added this pull request to the merge queue Feb 9, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Feb 9, 2026
@SuperFluffy SuperFluffy added this pull request to the merge queue Feb 9, 2026
Merged via the queue into main with commit 1f1aed7 Feb 9, 2026
21 of 23 checks passed
@SuperFluffy SuperFluffy deleted the janis/val-cfg-v2 branch February 9, 2026 17:39
github-merge-queue Bot pushed a commit that referenced this pull request Feb 12, 2026
Prepares peer management for the changes in #2181 (TIP 1017) by moving
it to a self standing actor: after the hardfork, it will check every
finalized block for changes to IP addresses in the peer set and update
its tracked peers accordingly.

For now there are no other changes other than delegating messages to the
peer manager to its wrapped p2p oracle.
github-merge-queue Bot pushed a commit that referenced this pull request Feb 12, 2026
Prepares peer management for the changes in #2181 (TIP 1017) by moving
it to a self standing actor: after the hardfork, it will check every
finalized block for changes to IP addresses in the peer set and update
its tracked peers accordingly.

For now there are no other changes other than delegating messages to the
peer manager to its wrapped p2p oracle.
github-merge-queue Bot pushed a commit that referenced this pull request Feb 13, 2026
… state (#2638)

Migrates the DKG actor's state from a continuous journal to a `Metadata`
object. The journal had unnecessary extra complexity that was not
needed. The `Metadata` object is simpler to reason about.

This migration is non-breaking: the journal is migrated to metadata and
deleted. If a metadata object is already present it is not overwritten.

As part of the migration, the DKG actor no longer tracks the socket
addresses of dealers and players. This information is available in the
execution layer state and can be read from there.

These changes are in preparation for the Validator Config V2 where
address tracking will be moved out of the DKG actor.

Related #2181, #2617
github-merge-queue Bot pushed a commit that referenced this pull request Feb 23, 2026
Moves peer handling from the DKG actor and into the peer manager.

In preparation for the val config V2 changes introduced in TIP 1017.

Related: #2181 #2617
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants