Compare commits

...

6 Commits

Author SHA1 Message Date
Mohamed Zahoor
5a849515f3 Merge branch 'develop' into opt-store-chkpt 2022-03-19 13:20:48 +05:30
Zahoor Mohamed
e9371631de Fixed potuz's comments 2022-03-14 11:27:41 +05:30
Zahoor Mohamed
08ba1120a5 go fmt 2022-03-11 23:06:02 +05:30
Zahoor Mohamed
5dbc944111 fix some errors 2022-03-11 23:02:10 +05:30
Zahoor Mohamed
5d34431965 fix review comments 2022-03-11 22:59:24 +05:30
Zahoor Mohamed
c16d19e3c1 add db functions for last checkpoint 2022-03-11 22:50:18 +05:30
5 changed files with 51 additions and 73 deletions

View File

@@ -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")

View File

@@ -175,6 +175,7 @@ func NewKVStore(ctx context.Context, dirPath string, config *Config) (*Store, er
powchainBucket,
stateSummaryBucket,
stateValidatorsBucket,
lastValidatedCheckpoint,
// Indices buckets.
attestationHeadBlockRootBucket,
attestationSourceRootIndicesBucket,

View File

@@ -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")

View File

@@ -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 = &ethpb.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
}

View File

@@ -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 := &ethpb.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 := &ethpb.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))
}