Skip to content

Commit

Permalink
Merge branch 'develop' into capella
Browse files Browse the repository at this point in the history
  • Loading branch information
potuz committed Dec 12, 2022
2 parents 5650311 + fa01ee5 commit 55a9e0d
Show file tree
Hide file tree
Showing 41 changed files with 3,414 additions and 109 deletions.
3 changes: 1 addition & 2 deletions api/client/builder/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ func stringToUint256(s string) (Uint256, error) {

// sszBytesToUint256 creates a Uint256 from a ssz-style (little-endian byte slice) representation.
func sszBytesToUint256(b []byte) (Uint256, error) {
bi := new(big.Int)
bi.SetBytes(bytesutil.ReverseByteOrder(b))
bi := bytesutil.LittleEndianBytesToBigInt(b)
if !isValidUint256(bi) {
return Uint256{}, errors.Wrapf(errDecodeUint256, "value=%s", b)
}
Expand Down
2 changes: 0 additions & 2 deletions beacon-chain/blockchain/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ var (
errInvalidNilSummary = errors.New("nil summary returned from the DB")
// errWrongBlockCount is returned when the wrong number of blocks or block roots is used
errWrongBlockCount = errors.New("wrong number of blocks or block roots")
// block is not a valid optimistic candidate block
errNotOptimisticCandidate = errors.New("block is not suitable for optimistic sync")
// errBlockNotFoundInCacheOrDB is returned when a block is not found in the cache or DB.
errBlockNotFoundInCacheOrDB = errors.New("block not found in cache or db")
// errNilStateFromStategen is returned when a nil state is returned from the state generator.
Expand Down
36 changes: 21 additions & 15 deletions beacon-chain/blockchain/execution_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,8 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
}

nextSlot := s.CurrentSlot() + 1 // Cache payload ID for next slot proposer.
hasAttr, attr, proposerId, err := s.getPayloadAttribute(ctx, arg.headState, nextSlot)
if err != nil {
log.WithError(err).Error("Could not get head payload attribute")
}
hasAttr, attr, proposerId := s.getPayloadAttribute(ctx, arg.headState, nextSlot)

payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, attr)
if err != nil {
switch err {
Expand Down Expand Up @@ -252,23 +250,25 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,

// getPayloadAttributes returns the payload attributes for the given state and slot.
// The attribute is required to initiate a payload build process in the context of an `engine_forkchoiceUpdated` call.
func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot types.Slot) (bool, payloadattribute.Attributer, types.ValidatorIndex, error) {
func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot types.Slot) (bool, payloadattribute.Attributer, types.ValidatorIndex) {
emptyAttri := payloadattribute.EmptyWithVersion(st.Version())
// Root is `[32]byte{}` since we are retrieving proposer ID of a given slot. During insertion at assignment the root was not known.
proposerID, _, ok := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, [32]byte{} /* root */)
if !ok { // There's no need to build attribute if there is no proposer for slot.
return false, emptyAttri, 0, nil
return false, emptyAttri, 0
}

// Get previous randao.
st = st.Copy()
st, err := transition.ProcessSlotsIfPossible(ctx, st, slot)
if err != nil {
return false, emptyAttri, 0, err
log.WithError(err).Error("Could not process slots to get payload attribute")
return false, emptyAttri, 0
}
prevRando, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
if err != nil {
return false, emptyAttri, 0, err
log.WithError(err).Error("Could not get randao mix to get payload attribute")
return false, emptyAttri, 0
}

// Get fee recipient.
Expand All @@ -286,23 +286,26 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
"Please refer to our documentation for instructions")
}
case err != nil:
return false, emptyAttri, 0, errors.Wrap(err, "could not get fee recipient in db")
log.WithError(err).Error("Could not get fee recipient to get payload attribute")
return false, emptyAttri, 0
default:
feeRecipient = recipient
}

// Get timestamp.
t, err := slots.ToTime(uint64(s.genesisTime.Unix()), slot)
if err != nil {
return false, emptyAttri, 0, err
log.WithError(err).Error("Could not get timestamp to get payload attribute")
return false, emptyAttri, 0
}

var attr payloadattribute.Attributer
switch st.Version() {
case version.Capella:
withdrawals, err := st.ExpectedWithdrawals()
if err != nil {
return false, emptyAttri, 0, errors.Wrap(err, "could not get expected withdrawals")
log.WithError(err).Error("Could not get expected withdrawals to get payload attribute")
return false, emptyAttri, 0
}
attr, err = payloadattribute.New(&enginev1.PayloadAttributesV2{
Timestamp: uint64(t.Unix()),
Expand All @@ -311,7 +314,8 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
Withdrawals: withdrawals,
})
if err != nil {
return false, emptyAttri, 0, err
log.WithError(err).Error("Could not get payload attribute")
return false, emptyAttri, 0
}
case version.Bellatrix:
attr, err = payloadattribute.New(&enginev1.PayloadAttributes{
Expand All @@ -320,13 +324,15 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
SuggestedFeeRecipient: feeRecipient.Bytes(),
})
if err != nil {
return false, emptyAttri, 0, err
log.WithError(err).Error("Could not get payload attribute")
return false, emptyAttri, 0
}
default:
return false, emptyAttri, 0, errors.New("unknown state version")
log.WithField("version", st.Version()).Error("Could not get payload attribute due to unknown state version")
return false, emptyAttri, 0
}

return true, attr, proposerID, nil
return true, attr, proposerID
}

// removeInvalidBlockAndState removes the invalid block and its corresponding state from the cache and DB.
Expand Down
53 changes: 47 additions & 6 deletions beacon-chain/blockchain/execution_engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -792,19 +792,17 @@ func Test_GetPayloadAttribute(t *testing.T) {
// Cache miss
service, err := NewService(ctx, opts...)
require.NoError(t, err)
hasPayload, _, vId, err := service.getPayloadAttribute(ctx, nil, 0)
require.NoError(t, err)
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0)
require.Equal(t, false, hasPayload)
require.Equal(t, types.ValidatorIndex(0), vId)

// Cache hit, advance state, no fee recipient
suggestedVid := types.ValidatorIndex(1)
slot := types.Slot(1)
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
st, _ := util.DeterministicGenesisState(t, 1)
hook := logTest.NewGlobal()
hasPayload, attr, vId, err := service.getPayloadAttribute(ctx, st, slot)
require.NoError(t, err)
hasPayload, attr, vId := service.getPayloadAttribute(ctx, st, slot)
require.Equal(t, true, hasPayload)
require.Equal(t, suggestedVid, vId)
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
Expand All @@ -814,11 +812,54 @@ func Test_GetPayloadAttribute(t *testing.T) {
suggestedAddr := common.HexToAddress("123")
require.NoError(t, service.cfg.BeaconDB.SaveFeeRecipientsByValidatorIDs(ctx, []types.ValidatorIndex{suggestedVid}, []common.Address{suggestedAddr}))
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
hasPayload, attr, vId, err = service.getPayloadAttribute(ctx, st, slot)
hasPayload, attr, vId = service.getPayloadAttribute(ctx, st, slot)
require.Equal(t, true, hasPayload)
require.Equal(t, suggestedVid, vId)
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
}

func Test_GetPayloadAttributeV2(t *testing.T) {
ctx := context.Background()
beaconDB := testDB.SetupDB(t)
opts := []Option{
WithDatabase(beaconDB),
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
}

// Cache miss
service, err := NewService(ctx, opts...)
require.NoError(t, err)
st, _ := util.DeterministicGenesisStateCapella(t, 1)
hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0)
require.Equal(t, false, hasPayload)
require.Equal(t, types.ValidatorIndex(0), vId)

// Cache hit, advance state, no fee recipient
suggestedVid := types.ValidatorIndex(1)
slot := types.Slot(1)
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
hook := logTest.NewGlobal()
hasPayload, attr, vId := service.getPayloadAttribute(ctx, st, slot)
require.Equal(t, true, hasPayload)
require.Equal(t, suggestedVid, vId)
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
require.LogsContain(t, hook, "Fee recipient is currently using the burn address")
a, err := attr.Withdrawals()
require.NoError(t, err)
require.Equal(t, 0, len(a))

// Cache hit, advance state, has fee recipient
suggestedAddr := common.HexToAddress("123")
require.NoError(t, service.cfg.BeaconDB.SaveFeeRecipientsByValidatorIDs(ctx, []types.ValidatorIndex{suggestedVid}, []common.Address{suggestedAddr}))
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
hasPayload, attr, vId = service.getPayloadAttribute(ctx, st, slot)
require.Equal(t, true, hasPayload)
require.Equal(t, suggestedVid, vId)
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
a, err = attr.Withdrawals()
require.NoError(t, err)
require.Equal(t, 0, len(a))
}

func Test_UpdateLastValidatedCheckpoint(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/blockchain/receive_block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestService_ReceiveBlock(t *testing.T) {
assert.NoError(t, err)
return blk
}
params.SetupTestConfigCleanupWithLock(t)
//params.SetupTestConfigCleanupWithLock(t)
bc := params.BeaconConfig().Copy()
bc.ShardCommitteePeriod = 0 // Required for voluntary exits test in reasonable time.
params.OverrideBeaconConfig(bc)
Expand Down
10 changes: 0 additions & 10 deletions beacon-chain/core/blocks/payload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -350,16 +350,6 @@ func Test_IsExecutionEnabled(t *testing.T) {
}
}

func Test_IsExecutionEnabledCapella(t *testing.T) {
st, _ := util.DeterministicGenesisStateCapella(t, 1)
blk := util.NewBeaconBlockCapella()
body, err := consensusblocks.NewBeaconBlockBody(blk.Block.Body)
require.NoError(t, err)
got, err := blocks.IsExecutionEnabled(st, body)
require.NoError(t, err)
require.Equal(t, false, got)
}

func Test_IsExecutionEnabledUsingHeader(t *testing.T) {
tests := []struct {
name string
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/db/kv/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ func (s *Store) SaveBlocks(ctx context.Context, blks []interfaces.SignedBeaconBl
func (s *Store) SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error {
ctx, span := trace.StartSpan(ctx, "BeaconDB.SaveHeadBlockRoot")
defer span.End()
hasStateSummary := s.HasStateSummary(ctx, blockRoot)
return s.db.Update(func(tx *bolt.Tx) error {
hasStateSummary := s.hasStateSummaryBytes(tx, blockRoot)
hasStateInDB := tx.Bucket(stateBucket).Get(blockRoot[:]) != nil
if !(hasStateInDB || hasStateSummary) {
return errors.New("no state or state summary found with head block root")
Expand Down
4 changes: 2 additions & 2 deletions beacon-chain/db/kv/checkpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ func (s *Store) SaveJustifiedCheckpoint(ctx context.Context, checkpoint *ethpb.C
if err != nil {
return err
}
hasStateSummary := s.HasStateSummary(ctx, bytesutil.ToBytes32(checkpoint.Root))
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) {
log.Warnf("Recovering state summary for justified root: %#x", bytesutil.Trunc(checkpoint.Root))
Expand All @@ -82,9 +82,9 @@ func (s *Store) SaveFinalizedCheckpoint(ctx context.Context, checkpoint *ethpb.C
if err != nil {
return err
}
hasStateSummary := s.HasStateSummary(ctx, bytesutil.ToBytes32(checkpoint.Root))
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) {
log.Warnf("Recovering state summary for finalized root: %#x", bytesutil.Trunc(checkpoint.Root))
Expand Down
15 changes: 6 additions & 9 deletions beacon-chain/db/kv/state_summary.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,21 @@ func (s *Store) HasStateSummary(ctx context.Context, blockRoot [32]byte) bool {
ctx, span := trace.StartSpan(ctx, "BeaconDB.HasStateSummary")
defer span.End()

if s.stateSummaryCache.has(blockRoot) {
return true
}

var hasSummary bool
if err := s.db.View(func(tx *bolt.Tx) error {
hasSummary = s.hasStateSummaryBytes(tx, blockRoot)
enc := tx.Bucket(stateSummaryBucket).Get(blockRoot[:])
hasSummary = len(enc) > 0
return nil
}); err != nil {
return false
}
return hasSummary
}

func (s *Store) hasStateSummaryBytes(tx *bolt.Tx, blockRoot [32]byte) bool {
if s.stateSummaryCache.has(blockRoot) {
return true
}
enc := tx.Bucket(stateSummaryBucket).Get(blockRoot[:])
return len(enc) > 0
}

// This saves all cached state summary objects to DB, and clears up the cache.
func (s *Store) saveCachedStateSummariesDB(ctx context.Context) error {
summaries := s.stateSummaryCache.getAll()
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/db/kv/validated_checkpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ func (s *Store) SaveLastValidatedCheckpoint(ctx context.Context, checkpoint *eth
if err != nil {
return err
}
hasStateSummary := s.HasStateSummary(ctx, bytesutil.ToBytes32(checkpoint.Root))
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) {
log.Warnf("Recovering state summary for last validated root: %#x", bytesutil.Trunc(checkpoint.Root))
Expand Down
20 changes: 20 additions & 0 deletions beacon-chain/db/kv/validated_checkpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ func TestStore_LastValidatedCheckpoint_Recover(t *testing.T) {
assert.Equal(t, true, proto.Equal(cp, retrieved), "Wanted %v, received %v", cp, retrieved)
}

func BenchmarkStore_SaveLastValidatedCheckpoint(b *testing.B) {
db := setupDB(b)
ctx := context.Background()
root := bytesutil.ToBytes32([]byte{'A'})
cp := &ethpb.Checkpoint{
Epoch: 10,
Root: root[:],
}
st, err := util.NewBeaconState()
require.NoError(b, err)
require.NoError(b, st.SetSlot(1))
require.NoError(b, db.SaveState(ctx, st, root))
db.stateSummaryCache.clear()

b.ResetTimer()
for i := 0; i < b.N; i++ {
require.NoError(b, db.SaveLastValidatedCheckpoint(ctx, cp))
}
}

func TestStore_LastValidatedCheckpoint_DefaultIsFinalized(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
Expand Down
6 changes: 4 additions & 2 deletions beacon-chain/execution/engine_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const (
NewPayloadMethodV2 = "engine_newPayloadV2"
// ForkchoiceUpdatedMethod v1 request string for JSON-RPC.
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
// ForkchoiceUpdatedMethod v2 request string for JSON-RPC.
// ForkchoiceUpdatedMethodV2 v2 request string for JSON-RPC.
ForkchoiceUpdatedMethodV2 = "engine_forkchoiceUpdatedV2"
// GetPayloadMethod v1 request string for JSON-RPC.
GetPayloadMethod = "engine_getPayloadV1"
Expand Down Expand Up @@ -147,7 +147,7 @@ func (s *Service) ForkchoiceUpdated(
result := &ForkchoiceUpdatedResponse{}

if attrs == nil {
return nil, nil, errors.New("nil payload attribute")
return nil, nil, errors.New("nil payload attributer")
}
switch attrs.Version() {
case version.Bellatrix:
Expand All @@ -168,6 +168,8 @@ func (s *Service) ForkchoiceUpdated(
if err != nil {
return nil, nil, handleRPCError(err)
}
default:
return nil, nil, fmt.Errorf("unknown payload attribute version: %v", attrs.Version())
}

if result.Status == nil {
Expand Down
Loading

0 comments on commit 55a9e0d

Please sign in to comment.