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

refactor!: x/slashing missed block window #15580

Merged
merged 38 commits into from
Apr 10, 2023

Conversation

alexanderbez
Copy link
Contributor

@alexanderbez alexanderbez commented Mar 28, 2023

Description

Closes: #2562

This PR introduces a refactor into the way we store, represent, and use a validator's missed block bitmap, i.e the rolling window.

Prior, we were storing a single boolean entry for each possible index, where index ranges [0, SignedBlocksWindow). E.g. if a chain has a window of 32,000, then this means we'd store 32,000 boolean entries per validator! So we treated this like a bitmap, although it wasn't a real bitmap.

With this refactor, we use a real bitmap. So each validator has a bitmap where each bit corresponds to a missed or signed block in the rolling window. However, we don't store the entire bitmap as a single entry in state. We instead break up the bitmap into chunks favoring IAVL's storage semantics, offering better write and read performance. These chunks compose the validator's bitmap. So taking our 32,000 block window and a chunk size of 1024 bits, we'd have roughly ~31 chunks/state entries per validator.


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • included the correct type prefix in the PR title
  • added ! to the type prefix if API or client breaking change
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • followed the guidelines for building modules
  • included the necessary unit and integration tests
  • added a changelog entry to CHANGELOG.md
  • included comments for documenting Go code
  • updated the relevant documentation or specification
  • reviewed "Files changed" and left comments if necessary
  • confirmed all CI checks have passed

Reviewers Checklist

All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.

I have...

  • confirmed the correct type prefix in the PR title
  • confirmed ! in the type prefix if API or client breaking change
  • confirmed all author checklist items have been addressed
  • reviewed state machine logic
  • reviewed API design and naming
  • reviewed documentation is accurate
  • reviewed tests and test coverage
  • manually tested (if applicable)

x/slashing/keeper/infractions.go Fixed Show fixed Hide fixed
x/slashing/keeper/infractions.go Fixed Show resolved Hide resolved
x/slashing/keeper/genesis.go Fixed Show resolved Hide resolved
// determine if the validator signed the previous block
previous, err := k.GetMissedBlockBitmapValue(ctx, consAddr, index)
if err != nil {
panic(errors.Wrap(err, "failed to get the validator's bitmap value"))

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
@github-actions github-actions bot added the C:CLI label Apr 2, 2023
@alexanderbez alexanderbez changed the title refactor!: refactor x/slashing missed block window refactor!: x/slashing missed block window Apr 2, 2023
Copy link
Member

@facundomedica facundomedica left a comment

Choose a reason for hiding this comment

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

Lgtm, I'll give it another read to fully understand it before approving

x/slashing/keeper/infractions.go Show resolved Hide resolved
x/slashing/keeper/signing_info.go Show resolved Hide resolved
x/slashing/keeper/signing_info.go Show resolved Hide resolved
Copy link
Member

@mark-rushakoff mark-rushakoff left a comment

Choose a reason for hiding this comment

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

I left a few comments so far. I'm still learning how everything comes together with keepers in general and with the slashing module, so I'd like to take another read through this, most likely later today.

x/slashing/keeper/genesis.go Fixed Show resolved Hide resolved
x/slashing/keeper/genesis.go Outdated Show resolved Hide resolved
x/slashing/migrations/v4/migrate.go Outdated Show resolved Hide resolved
x/slashing/migrations/v4/migrate.go Show resolved Hide resolved
x/slashing/migrations/v4/migrate.go Outdated Show resolved Hide resolved
x/slashing/migrations/v4/migrate.go Outdated Show resolved Hide resolved
x/slashing/types/keys.go Show resolved Hide resolved
Comment on lines 98 to 108
// GetMissedBlockBitmapChunk gets the bitmap chunk at the given chunk index for
// a validator's missed block signing window.
func (k Keeper) GetMissedBlockBitmapChunk(ctx sdk.Context, addr sdk.ConsAddress, chunkIndex int64) []byte {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&gogotypes.BoolValue{Value: missed})
store.Set(types.ValidatorMissedBlockBitArrayKey(address, index), bz)
chunk := store.Get(types.ValidatorMissedBlockBitmapKey(addr, chunkIndex))
return chunk
}

// clearValidatorMissedBlockBitArray deletes every instance of ValidatorMissedBlockBitArray in the store
func (k Keeper) clearValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.ConsAddress) {
// SetMissedBlockBitmapChunk sets the bitmap chunk at the given chunk index for
// a validator's missed block signing window.
func (k Keeper) SetMissedBlockBitmapChunk(ctx sdk.Context, addr sdk.ConsAddress, chunkIndex int64, chunk []byte) {
Copy link
Member

Choose a reason for hiding this comment

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

It looks like these two methods should be unexported. They are only called from within this package. The chunking looks like an implementation detail that should not be part of the keeper's exported API. External callers should be using {Get,Set}MissedBlockBitmapValue.

I also wonder whether these two methods should operate on [types.MissedBlockBitmapChunkSize]byte instead of a plain slice, for a little more compile-time safety. I'm not sure what would go wrong if an incorrect-sized slice was passed.

Copy link
Contributor Author

@alexanderbez alexanderbez Apr 4, 2023

Choose a reason for hiding this comment

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

Yeah there's no need for them to be public. Updated.

Re; array vs slice, the size of the bytes is not actually MissedBlockBitmapChunkSize, it could be a bit more...depending on the value of the chunk size, the bitmap might need to be padded slightly to accommodate the correct number of int64 words.

If we stick with the current value MissedBlockBitmapChunkSize, I'm pretty sure the bytes will always be the same fixed size, but if we ever change MissedBlockBitmapChunkSize then we'd have to change the array values.

Do you really see a strong motivation for this?

Copy link
Member

Choose a reason for hiding this comment

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

It seems feasible that the constant chunk size could change.

If there is a programmer mistake where they end up passing an incorrect byte slice, what happens? Would it make sense to add a runtime check that the slice has the correct length?

Copy link
Member

@mark-rushakoff mark-rushakoff left a comment

Choose a reason for hiding this comment

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

There were one or two more unhandled error warnings, but aside from that, the changes look good as far as I can see.

x/slashing/keeper/infractions.go Fixed Show resolved Hide resolved
x/slashing/keeper/infractions.go Show resolved Hide resolved
// Bitmap value has changed from not missed to missed, so we flip the bit
// and increment the counter.
if err := k.SetMissedBlockBitmapValue(ctx, consAddr, index, true); err != nil {
panic(err)

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
// Bitmap value has changed from missed to not missed, so we flip the bit
// and decrement the counter.
if err := k.SetMissedBlockBitmapValue(ctx, consAddr, index, false); err != nil {
panic(err)

Check warning

Code scanning / CodeQL

Panic in BeginBock or EndBlock consensus methods

Possible panics in BeginBock- or EndBlock-related consensus methods could cause a chain halt
@alexanderbez alexanderbez merged commit 4684c85 into main Apr 10, 2023
@alexanderbez alexanderbez deleted the bez/2562-refactor-liveness-window branch April 10, 2023 16:58
@tac0turtle tac0turtle mentioned this pull request May 3, 2023
4 tasks
larry0x pushed a commit to larry0x/cosmos-sdk that referenced this pull request May 22, 2023
pr0n00gler added a commit to neutron-org/cosmos-sdk that referenced this pull request Aug 7, 2023
pr0n00gler added a commit to neutron-org/cosmos-sdk that referenced this pull request Sep 26, 2023
pr0n00gler added a commit to neutron-org/cosmos-sdk that referenced this pull request Nov 19, 2023
pr0n00gler added a commit to neutron-org/cosmos-sdk that referenced this pull request Nov 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Change liveness window storage method
3 participants