-
Notifications
You must be signed in to change notification settings - Fork 0
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
Amend Blobs Database to Use a Rotating Buffer for Keys #3
Amend Blobs Database to Use a Rotating Buffer for Keys #3
Conversation
// where slot_to_rotating_buffer(slot) = slot % MAX_SLOTS_TO_PERSIST_BLOBS. | ||
func blobSidecarKey(blob *ethpb.BlobsSidecar) []byte { | ||
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch | ||
maxEpochsToPersistBlobs := params.BeaconNetworkConfig().MinEpochsForBlobsSidecarsRequest |
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.
Should this be configurable via a flag? I can imagine users wanting to save blobs for longer.
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.
Yep it should be done via a feature config IMO...will reserve that for a second PR
// store the blob by key and exit early. | ||
if len(firstElementKey) == 0 { | ||
return bkt.Put(key, encodedBlobSidecar) | ||
} else if len(firstElementKey) != len(key) { |
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.
Is this even possible?
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.
Yeah maybe someone changes the schema. It's just a defensive check to prevent panics and instead error gracefully because otherwise we'll be accessing slice indices out of range
beacon-chain/db/kv/blobs.go
Outdated
if shouldOverwrite { | ||
for k, _ := c.Seek(rotatingBufferPrefix); bytes.HasPrefix(k, rotatingBufferPrefix); k, _ = c.Next() { | ||
if err := bkt.Delete(k); err != nil { | ||
return 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.
Aren't we possibly leaving the db in an inconsistent state?
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.
Yeah good point, might instead collect the errors
if len(k) != blobSidecarKeyLength { | ||
continue | ||
} |
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.
Is this even possible?
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.
Same comment as above
require.NoError(t, db.SaveBlobsSidecar(ctx, sidecar)) | ||
require.Equal(t, true, db.HasBlobsSidecar(ctx, bytesutil.ToBytes32(sidecar.BeaconBlockRoot))) | ||
|
||
keyPrefix = append(bytesutil.SlotToBytesBigEndian(0), bytesutil.SlotToBytesBigEndian(64)...) |
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.
You should not append 64
because the original sidecar at round buffer's 0
value had a different slot.
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.
In this example, the key we are expecting is 0 ++ 64 ++ bytes32(foo-64). A key contains the round buffer, the slot, and the block root. The new value we are storing at round buffer 0 will be under this new key, so this is the correct value to expect
Co-authored-by: Radosław Kapka <radek@prysmaticlabs.com>
Co-authored-by: Radosław Kapka <radek@prysmaticlabs.com>
Co-authored-by: Radosław Kapka <radek@prysmaticlabs.com>
…to blob-rotating-buffer
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.
Lgtm, let's review this more in detail when it goes to the upstream develop
branch
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.
I still argue that TestBlobsSidecar_Overwriting
does not test overwriting. The last assertion will pass even if old blobs were not overwritten. We should check the number of items under key prefix bytesutil.SlotToBytesBigEndian(0)
.
@rkapka I'm going to move this to prysm branch, we'll make a note of your comment there. Thanks! |
What type of PR is this?
What does this PR do? Why is it needed?
Bolt DB does not play nicely with pruning, as evidenced by extensive pains developing slasher. Blob data can be huge, and we will be storing a lot of it in Prysm with EIP-4844. Instead of having to prune, we devise a database schema for blobs where keys are a rotating buffer that wraps around once the expiration period for blobs is reached. For example, imagine we store 2 epochs max worth of blobs. Then, once we reach epoch 2, we will be overriding the contents of epoch 0 in the database by "wrapping around" the keys using a modulo operation. This removes the need for any kind of deletion routine or frequent pruning and keeps the database size bounded.
There is some complexity involved, as we there could be multiple blob sidecars per slot, so we can't do a naive overwriting algorithm. Instead, here's how the saving of blobs works:
When we receive a blob:
The unit test included shows exactly how the algorithm works.