-
Notifications
You must be signed in to change notification settings - Fork 170
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
epoching API: validator lifecycle #109
Conversation
Just fixed a bug on recording heights of bonded -> unbonding. Only when the validator's operator undelegates from the validator, the validator becomes unbonding from bonded. Previous implementation does not impose such limit, but refreshes the height upon any undelegation of its delegations. Question: do we need to record the height for delegations undelegating from validators? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, I believe that this validator lifecycle structure needs some extra checks to verify correctness (e.g. see my unbonding height vs unbonded height comment below). A more useful and less complex data structure would be one that contains the validator address, an event (Create|Bonded|Unbonding|Unbonded
), and a height.
Then, someone that wants to see the lifecycle of the validator can query and get a list of events corresponding to that validator in the form:
{
val_addr: [(create, 10), (bonded, 13), (unbonding, 27), (unbonded, 42), (bonded, 103), ...]
}
This would also simplify storage and the query endpoint since the validator address could be used as a key.
This would require some computation from the front-end to calculate the current status of the validator, but it would be just traversing the list and implementing a very simple state machine.
@@ -29,3 +29,26 @@ message QueuedMessage { | |||
// TODO: after we bump to Cosmos SDK v0.46, add MsgCancelUnbondingDelegation | |||
} | |||
} | |||
|
|||
message ValidatorLifecycle { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if a validator address has multiple bonding/unbonding requests over time?
x/epoching/keeper/val_lifecycle.go
Outdated
case types.ValStateUnbonding: | ||
lc.UnbondingHeight = uint64(ctx.BlockHeight()) | ||
case types.ValStateUnbonded: | ||
lc.UnbondedHeight = uint64(ctx.BlockHeight()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we panic
if the UnbondingHeight
has not been set here? Accordingly with the above cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Such sanity checks on the validator's state transition have been done elsewhere (e.g., in the staking module), right?
Thanks for the comment and totally agree on this! Yeah it's possible that a validator can get bonded/unbonded back and forth. I think your way of recording lists of events is more simple and generic. Will adapt to this approach. 👍 |
} | ||
if _, err := sdk.ValAddressFromBech32(msg.Msg.ValidatorDstAddress); err != nil { | ||
return nil, err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need these extra validations now, but not before this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without these validations users can submit malformed msgs, eg msgs with empty fields. This was a bug in the code and was not tested. I found this in this PR because when handling these APIs we need the validator address inside the msg, which was allowed to be empty.
x/epoching/keeper/val_lifecycle.go
Outdated
k.SetValLifecycle(ctx, valAddr, &lc) | ||
} | ||
|
||
// InitValState adds a state for an existing validator lifecycle, including bonded, unbonding and unbonded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// InitValState adds a state for an existing validator lifecycle, including bonded, unbonding and unbonded | |
// UpdateValState adds a state for an existing validator lifecycle, including bonded, unbonding and unbonded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally the explorer's backend would build up this database from the events in the blocks, similarly to how Vitalis suggested. I was wondering if for such cases there should be a separate module that subscribes to these event; but events are probably not visible to modules.
Agree. In the long term perhaps we need a new module (say metrics) to subscribe a lot of hooks and do statistics. Im also not sure what's the standard way of doing statistics in Cosmos SDK. For the sake of demo perhaps we can have this API for now. |
Sure, for the demo you can have temporary queries, I just thought that if it was easy to add a module (which I don't think it is, unless you use hooks but even that's more than the normal event emission) then it would be very clear which parts of the app exist only to stand in for a missing explorer backend, and it would be easy to remove it later. |
Thanks for the comments Akosh and Vitalis! Now this PR is significantly simplified by using hooks and adapts the data structure that is more generic. Specifically, this PR:
Please feel free to have a look again :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!
k.stk.RemoveValidator(ctx, val.GetOperator()) | ||
} | ||
|
||
// Babylon modification: record the height when this validator becomes unbonded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks for adding these comments!
- Update delegation and undelegation to new btc transactions format
Fixes BM-118
This PR aims at implementing the validator lifecycle API. In this API, upon a validator address, it outputs the entire lifecycle of this validator, including
MsgWrappedCreateValidator
is handledMsgWrappedUndelegate
is handledMsgWrappedUndelegate
msg is checkpointedTechnical approaches
MsgWrappedCreateValidator
, this validator enters stateValStateCreateRequestSubmitted
at current heightMsgWrappedCreateValidator
successfully, this validator enters stateValStateBonded
at current heightMsgWrappedUndelegate
, this validator enters stateValStateUnbondingRequestSubmitted
at current heightMsgWrappedUndelegate
successfully, this validator enters stateValStateUnbonding
at current heightValStateUnbonded
at current height"/babylon/epoching/v1/validator_lifecycle/{val_addr}"
is implemented for reading this KVStoreMisc
I also marked @gitferry as reviewer since this PR touches the checkpointing module in the following. Feel free to have a look and provide comments:
InitGenValLifecycle
to initialise the lifecycle of the genesis validatorsgenesis_bls.go
togenesis_val.go
due to the above modificationWrappedCreateValidator
. These are needed for filtering out malformed requests.I also marked @vitsalis as reviewer since this API will be used by the explorer