mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 13:28:01 -05:00
Compare commits
6 Commits
d929e1dcaa
...
opt-store-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a849515f3 | ||
|
|
e9371631de | ||
|
|
08ba1120a5 | ||
|
|
5dbc944111 | ||
|
|
5d34431965 | ||
|
|
c16d19e3c1 |
@@ -15,3 +15,6 @@ var ErrNotFoundOriginBlockRoot = errors.Wrap(ErrNotFound, "OriginBlockRoot")
|
||||
|
||||
// ErrNotFoundFeeRecipient is a not found error specifically for the fee recipient getter
|
||||
var ErrNotFoundFeeRecipient = errors.Wrap(ErrNotFound, "fee recipient")
|
||||
|
||||
// errInvalidCheckpointSize is returned when the supplied checkoint size is not as expected
|
||||
var errInvalidCheckpointSize = errors.New("invalid checkpoint size")
|
||||
|
||||
@@ -175,6 +175,7 @@ func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, er
|
||||
powchainBucket,
|
||||
stateSummaryBucket,
|
||||
stateValidatorsBucket,
|
||||
lastValidatedCheckpoint,
|
||||
// Indices buckets.
|
||||
attestationHeadBlockRootBucket,
|
||||
attestationSourceRootIndicesBucket,
|
||||
|
||||
@@ -19,6 +19,7 @@ var (
|
||||
powchainBucket = []byte("powchain")
|
||||
stateValidatorsBucket = []byte("state-validators")
|
||||
feeRecipientBucket = []byte("fee-recipient")
|
||||
lastValidatedCheckpoint = []byte("last-validated-checkpoint")
|
||||
|
||||
// Deprecated: This bucket was migrated in PR 6461. Do not use, except for migrations.
|
||||
slotsHasObjectBucket = []byte("slots-has-objects")
|
||||
|
||||
@@ -2,48 +2,49 @@ package kv
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// LastValidatedCheckpoint returns the latest fully validated checkpoint in beacon chain.
|
||||
func (s *Store) LastValidatedCheckpoint(ctx context.Context) (*ethpb.Checkpoint, error) {
|
||||
const (
|
||||
validatedCheckpointSize = 40 // 32 for checkpoint root + 8 bytes for slot
|
||||
)
|
||||
|
||||
func (s *Store) LastValidatedCheckpoint(ctx context.Context) ([32]byte, types.Slot, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.LastValidatedCheckpoint")
|
||||
defer span.End()
|
||||
var checkpoint *ethpb.Checkpoint
|
||||
|
||||
var root [32]byte
|
||||
var slot types.Slot
|
||||
err := s.db.View(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(checkpointBucket)
|
||||
enc := bkt.Get(lastValidatedCheckpointKey)
|
||||
if enc == nil {
|
||||
var finErr error
|
||||
checkpoint, finErr = s.FinalizedCheckpoint(ctx)
|
||||
return finErr
|
||||
bkt := tx.Bucket(lastValidatedCheckpoint)
|
||||
val := bkt.Get([]byte("lastChkPoint"))
|
||||
if len(val) != validatedCheckpointSize {
|
||||
return errInvalidCheckpointSize
|
||||
}
|
||||
checkpoint = ðpb.Checkpoint{}
|
||||
return decode(ctx, enc, checkpoint)
|
||||
root = bytesutil.ToBytes32(val[:32])
|
||||
slot = types.Slot(binary.LittleEndian.Uint64(val[32:]))
|
||||
return nil
|
||||
})
|
||||
return checkpoint, err
|
||||
return root, slot, err
|
||||
}
|
||||
|
||||
// SaveLastValidatedCheckpoint saves the last validated checkpoint in beacon chain.
|
||||
func (s *Store) SaveLastValidatedCheckpoint(ctx context.Context, checkpoint *ethpb.Checkpoint) error {
|
||||
func (s *Store) SaveLastValidatedCheckpoint(ctx context.Context, root [32]byte, slot types.Slot) error {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveLastValidatedCheckpoint")
|
||||
defer span.End()
|
||||
|
||||
enc, err := encode(ctx, checkpoint)
|
||||
if err != nil {
|
||||
updateErr := s.db.Update(func(tx *bolt.Tx) error {
|
||||
value := make([]byte, validatedCheckpointSize)
|
||||
copy(value[:32], root[:])
|
||||
binary.LittleEndian.PutUint64(value[32:], uint64(slot))
|
||||
bkt := tx.Bucket(lastValidatedCheckpoint)
|
||||
err := bkt.Put([]byte("lastChkPoint"), value)
|
||||
return err
|
||||
}
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
bucket := tx.Bucket(checkpointBucket)
|
||||
hasStateSummary := s.hasStateSummaryBytes(tx, bytesutil.ToBytes32(checkpoint.Root))
|
||||
hasStateInDB := tx.Bucket(stateBucket).Get(checkpoint.Root) != nil
|
||||
if !(hasStateInDB || hasStateSummary) {
|
||||
return errMissingStateForCheckpoint
|
||||
}
|
||||
return bucket.Put(lastValidatedCheckpointKey, enc)
|
||||
})
|
||||
|
||||
return updateErr
|
||||
}
|
||||
|
||||
@@ -1,67 +1,39 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestStore_LastValidatedCheckpoint_CanSaveRetrieve(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
func TestValidatedCheckpoint(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
root := bytesutil.ToBytes32([]byte{'A'})
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 10,
|
||||
Root: root[:],
|
||||
}
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(1))
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, cp))
|
||||
|
||||
retrieved, err := db.LastValidatedCheckpoint(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, proto.Equal(cp, retrieved), "Wanted %v, received %v", cp, retrieved)
|
||||
}
|
||||
|
||||
func TestStore_LastValidatedCheckpoint_DefaultIsFinalized(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
genesis := bytesutil.ToBytes32([]byte{'G', 'E', 'N', 'E', 'S', 'I', 'S'})
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesis))
|
||||
checkpointA := [32]byte{'A'}
|
||||
slotA := types.Slot(1)
|
||||
|
||||
blk := util.NewBeaconBlock()
|
||||
blk.Block.ParentRoot = genesis[:]
|
||||
blk.Block.Slot = 40
|
||||
checkpointB := [32]byte{'B'}
|
||||
slotB := types.Slot(2)
|
||||
|
||||
root, err := blk.Block.HashTreeRoot()
|
||||
// add first checkpoint
|
||||
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, checkpointA, slotA))
|
||||
|
||||
rcvdRoot, rcvdSlot, err := db.LastValidatedCheckpoint(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 5,
|
||||
Root: root[:],
|
||||
}
|
||||
require.Equal(t, 0, bytes.Compare(checkpointA[:], rcvdRoot[:]))
|
||||
require.Equal(t, uint64(slotA), uint64(rcvdSlot))
|
||||
|
||||
// a valid chain is required to save finalized checkpoint.
|
||||
require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blk)))
|
||||
st, err := util.NewBeaconState()
|
||||
// update the checkpoint and slot
|
||||
require.NoError(t, db.SaveLastValidatedCheckpoint(ctx, checkpointB, slotB))
|
||||
|
||||
rcvdRoot, rcvdSlot, err = db.LastValidatedCheckpoint(ctx)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, st.SetSlot(1))
|
||||
// a state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
retrieved, err := db.LastValidatedCheckpoint(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, proto.Equal(cp, retrieved), "Wanted %v, received %v", cp, retrieved)
|
||||
require.Equal(t, 0, bytes.Compare(checkpointB[:], rcvdRoot[:]))
|
||||
require.Equal(t, uint64(slotB), uint64(rcvdSlot))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user