Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce PrecommitProcessors to the StateManager #257

Open
wants to merge 50 commits into
base: testnet-slashing
Choose a base branch
from

Conversation

seanmcgary
Copy link
Member

Description

In order to properly handle slashing conditions, we need to know if any stakers delegated to a slashed operator in the current block being processed. By design, EigenState models are not aware of each other, so the current logic only handles stakers that were delegated in previous blocks.

This change introduces the concept of PrecommitProcessors that can handle massaging data across multiple models. In this case, the SlashingProcessor inspects the accumulated state of the staker delegation model to find any newly delegated stakers and injects them into the StakerShares model through the PrecommitDelegatedStakers struct field.

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Automated unit and integration tests

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

seanmcgary and others added 30 commits February 19, 2025 21:31
Rewards v2.1 state models
# Motivation
We need to support Rewards v2.1 calculation. 

This PR builds on top of #197
which supported the Eigen state models for
`OperatorDirectedOperatorSetRewardSubmissions`, `OperatorSetSplits`,
`OperatorSetOperatorRegistrations`, `OperatorSetStrategyRegistrations`.

# Modifications
* Snapshot generation for:
`OperatorDirectedOperatorSetRewardSubmissions`, `OperatorSetSplits`,
`OperatorSetOperatorRegistrations`, `OperatorSetStrategyRegistrations`.
* Refactoring Staging and Final numbering from 11 and 12 to 15 and 16.
* Mississippi hard fork for Rewards v2.1.
* New Operator Directed Operator Set rewards calculation to be triggered
after Mississippi hard fork.
* Updated Rewards For All Earners (Programmatic Incentives) calculation
to include operators registered to operator sets after Mississippi hard
fork.
* Staker-operator calculation for Rewards v2.1. 

# Results
Rewards v2.1 calculation.

# Tests
Existing Rewards tests passing.

<img width="660" alt="Screenshot 2025-01-31 at 1 33 38 PM"
src="https://github.com/user-attachments/assets/876c2d7c-be22-48b6-a046-55ead8a12530"
/>
This PR introduces the concept of a state migration. When introducing
new features, it's possible that there is existing transaction data that
was not codified into a model that now needs to be. Rather than
truncating the database, re-indexing blocks resulting in modifying
existing StateRoots, this migration construct allows us to populate new
models with existing data, leaving existing StateRoots unchanged, and
codifying the changes in a sub-tree whos root is represented in the
top-level StateRoot tree.

![Screenshot 2025-02-04 at 8 25
47 AM](https://github.com/user-attachments/assets/149021bc-7457-49f0-b4f2-2091a4d0b46c)

The StateMigrator specifies which migrations run at which block height
for a given chain. Multiple migrations can be run for a single block and
will be run in the order specified. Each migration will produce a root
representing the changes made. Each of those roots are composed of the
same StateRoot structure used at the very top-level, one for each block
that was touched in the migration process. In the majority of cases
where we're populating models with only a few events, these StateRoot
trees will be rather sparse and only include the new model.

Each migration works by:

* Creating a new instance of the StateManager
* Querying the database for the TransactionLogs that need to be
processed
* Groups them by block number
* In the order of blockNumber ascending, feeds each log through the
StateManager as it would have if it came through in real time.

The same lifecycle of HandleLogStateChange --> CommitFinalState -->
GenerateStateRoot is followed.
rewards v2.1 implementation
// memoize stakers into a map to remove duplicates and get the latest action
for _, staker := range orderedStakers {
key := fmt.Sprintf("%s-%s", staker.Staker, staker.Operator)
collapsedStakers[key] = staker
Copy link
Contributor

Choose a reason for hiding this comment

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

doesn't this lose all of the ordering stuff we just did?

Copy link
Member Author

@seanmcgary seanmcgary Feb 21, 2025

Choose a reason for hiding this comment

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

Ordering on the returned result doesnt really matter. We want to make sure we're getting the last delegation status for a staker/operator pair before the slashing event occurred to know if they were delegated or not. This is basically the same as doing:

select
	staker,
	operator,
	strategy,
	row_number() over (partition by staker, operator order by transaction_index desc, log_index desc, block_number desc) as rn
where
	rn = 1

from staker_share_deltas as ssd
on ssd.staker in @stakerAddresses
and ssd.strategy = @strategy
and ssd.block_number <= @blockNumber
Copy link
Contributor

Choose a reason for hiding this comment

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

does <= here vs < everywhere else matter?

Copy link
Member Author

Choose a reason for hiding this comment

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

I need to update this one to be < rather than <= (all of them should be <)

@seanmcgary seanmcgary marked this pull request as ready for review February 21, 2025 04:19
@seanmcgary seanmcgary requested a review from a team as a code owner February 21, 2025 04:20
@seanmcgary seanmcgary requested review from 0xrajath and removed request for a team February 21, 2025 04:20
@@ -538,142 +534,6 @@ func Test_StakerSharesState(t *testing.T) {
assert.Equal(t, strings.ToLower("0x3c42cd72639e3e8d11ab8d0072cc13bd5d8aa83c"), shareDiff.Staker)
assert.Equal(t, "0xe523267698c81a372191136e477fdebfa33d9fb5", shareDiff.Strategy)
})

t.Run("Should capture delegate, deposit, slash in same block", func(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

why delete?

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved it to a different location since it has a dependency on the new PrecommitProcessor

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.

3 participants