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(delegation): load genesis state #26

Merged

Conversation

MaxMustermann2
Copy link
Contributor

@MaxMustermann2 MaxMustermann2 commented Apr 3, 2024

This PR subsumes #27 within itself, and therefore should be merged after that one. For ease of review, this PR may be reviewed after the merge of #27 happens and this PR is rebased.

The x/delegation module needs to load the genesis state of delegations (for each possible combination of staker, asset and operator) for the network to successfully bootstrap with the rPOS process.

The genesis state is structured as follows.

{
    "delegations": [
        {
            "staker_id": "0xaaaaaa_0x65",
            "delegations": [
                {
                    "asset_id": "0xbbbb_0x65",
                    "per_operator_amounts": [
                        {"key": "exo1.....", "value": {"amount": "700"}},
                        {"key": "exo1.....", "value": {"amount": "500"}}, {...}
                    ]
                }, {...}
            ]
        }, {...}
    ]
}

At genesis, the module should perform these delegations as it would if the chain were live. To do this, we call the exact same DelegateTo function that is called by the precompile and use a flag to skip (1) the operator frozen check, (2) the operator module update and (3) the delegation hooks.

The stateless validation uses this algorithm:

  • There are no repeat stakers.
  • The stakerID is valid: lowercase, exactly one underscore, with the left side of the underscore non-empty and a hex address, and the right side a hex uint64.
  • For each stakerID, there is no repeating assetID.
  • Each assetID is valid (defined above).
  • The LayerZeroID derived from the stakerID equals that derived from the assetID for each provided stakerID + assetID combination.
  • The per-operator amount, for each operator, is non-nil and non-negative.
  • The provided operator address is bech32 encoded appropriately.

@MaxMustermann2 MaxMustermann2 changed the title feat(assets): load delegation state feat(delegation): load genesis state Apr 3, 2024
@MaxMustermann2 MaxMustermann2 reopened this Apr 3, 2024
Since Cosmos uses an IAVL+ based tree, the order of (unrelated) edits to
the leaf nodes can impact the state root. Even though protobuf
guarantees the order of a map when serializing it, it cannot guarantee
that the order will be maintained once the map is deserialized into
Golang. Hence, we cannot use a map during genesis (or anywhere
meaningful at all).
The total delegated amount is not required at genesis and only adds an
additional level of complexity that we don't need.
...for total delegated amount removal.
Copy link
Contributor

@TimmyExogenous TimmyExogenous left a comment

Choose a reason for hiding this comment

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

LGTM

// #nosec G703 // already validated
stakerAddress, lzID, _ := assetstype.ParseID(stakerID)
// we have checked IsHexAddress already
stakerAddressBytes := common.HexToAddress(stakerAddress)
Copy link
Contributor

Choose a reason for hiding this comment

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

If the genesis state contains a lot of delegate information, the current nested loop may affect the performance of the initialization. Consider whether it is possible to improve efficiency by optimizing data structures or parallel processing.

  1. Consider distributing processing operations on each delegate to different goroutines to execute in parallel. Ensure data consistency and thread safety when processing in parallel.Pay attention to the number of goroutines to avoid resource contention caused by creating too many goroutines
  2. If the delegateTo function supports batch processing, that is, processing multiple delegates at a time, we can collect a batch of delegates in each goroutine and call delegateTo to process them. This reduces the number of function calls and increases efficiency.

Copy link
Contributor Author

@MaxMustermann2 MaxMustermann2 Apr 9, 2024

Choose a reason for hiding this comment

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

1. It is not trivial to build something like this because the order of goroutine execution is not guaranteed. This can result in inconsistency across nodes in calculating the state root, since it depends on the order of insertion.
2. Within delegateTo, there are 6 different function calls, only 4 of which can be batched either on the staker + asset level or on the operator + asset level. Others cannot be batched, hence, batching is not necessarily possible.

I have added a TODO for this.

// Validate performs basic genesis state validation returning an error upon any
// failure.
func (gs GenesisState) Validate() error {
stakers := make(map[string]struct{}, len(gs.Delegations))
Copy link
Contributor

Choose a reason for hiding this comment

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

During the verification process, for each level of data (stakeholder, asset, operator), a separate hash table is used to check for uniqueness. Be aware that memory usage may increase when processing large amounts of data.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, added a TODO for this.

- parallelization of loading genesis
- size of hash map for validation. I don't believe this is a super big
  concern given Cosmos genesis has a similar validation and the size of
  their genesis files is also very big.
@MaxMustermann2 MaxMustermann2 merged commit d28c021 into imua-xyz:develop Apr 9, 2024
19 checks passed
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.

3 participants