Update to v0.12 (#5614)

This commit is contained in:
Nishant Das
2020-06-10 06:40:48 +08:00
committed by GitHub
parent 47dacb88f7
commit d1a1043ef1
143 changed files with 3104 additions and 1095 deletions

View File

@@ -2,7 +2,7 @@
[![Build status](https://badge.buildkite.com/b555891daf3614bae4284dcf365b2340cefc0089839526f096.svg?branch=master)](https://buildkite.com/prysmatic-labs/prysm)
[![fuzzit](https://app.fuzzit.dev/badge?org_id=prysmaticlabs-gh)](https://app.fuzzit.dev/orgs/prysmaticlabs-gh/dashboard)
[![ETH2.0_Spec_Version 0.11.3](https://img.shields.io/badge/ETH2.0%20Spec%20Version-v0.11.3-blue.svg)](https://github.com/ethereum/eth2.0-specs/tree/v0.11.3)
[![ETH2.0_Spec_Version 0.12.1](https://img.shields.io/badge/ETH2.0%20Spec%20Version-v0.12.1-blue.svg)](https://github.com/ethereum/eth2.0-specs/tree/v0.12.1)
[![Discord](https://user-images.githubusercontent.com/7288322/34471967-1df7808a-efbb-11e7-9088-ed0b04151291.png)](https://discord.gg/KSA7rPr)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/prysmaticlabs/geth-sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)

View File

@@ -215,8 +215,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "489f85d7c17a901b9069c95f656154fdf1385db00f3aeb3e0319aed8745f9453",
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.11.3/general.tar.gz",
sha256 = "678c50336ce39bef19b2a0dc69e20a7bda37a673ae07dc0577386e9876e0a525",
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.1/general.tar.gz",
)
http_archive(
@@ -231,8 +231,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "b83000fbcb60b7a5b8c0e805f3fee6953b17bfe0fe6658416e7d99e6d261f284",
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.11.3/minimal.tar.gz",
sha256 = "d0ce95a3ca0d30df24f96a1b5cfad1f7e6fcc07ad84ca221d92480add051af3e",
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.1/minimal.tar.gz",
)
http_archive(
@@ -247,8 +247,8 @@ filegroup(
visibility = ["//visibility:public"],
)
""",
sha256 = "ae0c09ab49afa69085c91f9e2f2f4de6526d43b927609839b1597c674b4dccde",
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.11.3/mainnet.tar.gz",
sha256 = "1dfa1ae6822912508dbf6d1fe7608169372daa3ad1e53a3ed0867cb2d6e0ccb0",
url = "https://github.com/ethereum/eth2.0-spec-tests/releases/download/v0.12.1/mainnet.tar.gz",
)
http_archive(

View File

@@ -45,6 +45,7 @@ type HeadFetcher interface {
HeadValidatorsIndices(epoch uint64) ([]uint64, error)
HeadSeed(epoch uint64) ([32]byte, error)
HeadGenesisValidatorRoot() [32]byte
HeadETH1Data() *ethpb.Eth1Data
ProtoArrayStore() *protoarray.Store
}
@@ -179,6 +180,14 @@ func (s *Service) HeadGenesisValidatorRoot() [32]byte {
return s.headGenesisValidatorRoot()
}
// HeadETH1Data returns the eth1data of the current head state.
func (s *Service) HeadETH1Data() *ethpb.Eth1Data {
if !s.hasHeadState() {
return &ethpb.Eth1Data{}
}
return s.head.state.Eth1Data()
}
// ProtoArrayStore returns the proto array store object.
func (s *Service) ProtoArrayStore() *protoarray.Store {
return s.forkChoiceStore.Store()

View File

@@ -210,3 +210,24 @@ func TestGenesisValidatorRoot_CanRetrieve(t *testing.T) {
t.Error("Did not get correct genesis validator root")
}
}
func TestHeadETH1Data_Nil(t *testing.T) {
db := testDB.SetupDB(t)
c := setupBeaconChain(t, db)
if !reflect.DeepEqual(c.HeadETH1Data(), &ethpb.Eth1Data{}) {
t.Error("Incorrect pre chain start value")
}
}
func TestHeadETH1Data_CanRetrieve(t *testing.T) {
d := &ethpb.Eth1Data{DepositCount: 999}
s, err := state.InitializeFromProto(&pb.BeaconState{Eth1Data: d})
if err != nil {
t.Fatal(err)
}
c := &Service{}
c.head = &head{state: s}
if !proto.Equal(c.HeadETH1Data(), d) {
t.Error("Received incorrect eth1 data")
}
}

View File

@@ -7,7 +7,6 @@ import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
@@ -242,7 +241,7 @@ func TestGenerateState_CorrectlyGenerated(t *testing.T) {
}
beaconState, privs := testutil.DeterministicGenesisState(t, 32)
genesisBlock := blocks.NewGenesisBlock([]byte{})
genesisBlock := testutil.NewBeaconBlock()
bodyRoot, err := stateutil.BlockRoot(genesisBlock.Block)
if err != nil {
t.Fatal(err)

View File

@@ -36,14 +36,12 @@ var ErrTargetRootNotInDB = errors.New("target root does not exist in db")
// current_epoch = compute_epoch_at_slot(get_current_slot(store))
// # Use GENESIS_EPOCH for previous when genesis to avoid underflow
// previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else GENESIS_EPOCH
// # If attestation target is from a future epoch, delay consideration until the epoch arrives
// assert target.epoch in [current_epoch, previous_epoch]
// assert target.epoch == compute_epoch_at_slot(attestation.data.slot)
//
// # Attestations target be for a known block. If target block is unknown, delay consideration until the block is found
// assert target.root in store.blocks
// # Attestations cannot be from future epochs. If they are, delay consideration until the epoch arrives
// base_state = store.block_states[target.root].copy()
// assert store.time >= base_state.genesis_time + compute_start_slot_at_epoch(target.epoch) * SECONDS_PER_SLOT
//
// # Attestations must be for a known block. If block is unknown, delay consideration until the block is found
// assert attestation.data.beacon_block_root in store.blocks
@@ -68,6 +66,7 @@ var ErrTargetRootNotInDB = errors.New("target root does not exist in db")
// for i in indexed_attestation.attesting_indices:
// if i not in store.latest_messages or target.epoch > store.latest_messages[i].epoch:
// store.latest_messages[i] = LatestMessage(epoch=target.epoch, root=attestation.data.beacon_block_root)
// TODO(#6072): This code path is highly untested. Requires comprehensive tests and simpler refactoring.
func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]uint64, error) {
ctx, span := trace.StartSpan(ctx, "blockchain.onAttestation")
defer span.End()
@@ -83,7 +82,6 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
}
tgt := stateTrie.CopyCheckpoint(a.Data.Target)
tgtSlot := helpers.StartSlot(tgt.Epoch)
if helpers.SlotToEpoch(a.Data.Slot) != a.Data.Target.Epoch {
return nil, fmt.Errorf("data slot is not in the same epoch as target %d != %d", helpers.SlotToEpoch(a.Data.Slot), a.Data.Target.Epoch)
@@ -108,16 +106,16 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
return nil, err
}
// Verify Attestations cannot be from future epochs.
if err := helpers.VerifySlotTime(genesisTime, tgtSlot, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
return nil, errors.Wrap(err, "could not verify attestation target slot")
}
// Verify attestation beacon block is known and not from the future.
if err := s.verifyBeaconBlock(ctx, a.Data); err != nil {
return nil, errors.Wrap(err, "could not verify attestation beacon block")
}
// Verify LMG GHOST and FFG votes are consistent with each other.
if err := s.verifyLMDFFGConsistent(ctx, a.Data.Target.Epoch, a.Data.Target.Root, a.Data.BeaconBlockRoot); err != nil {
return nil, errors.Wrap(err, "could not verify attestation beacon block")
}
// Verify attestations can only affect the fork choice of subsequent slots.
if err := helpers.VerifySlotTime(genesisTime, a.Data.Slot+1, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
return nil, err

View File

@@ -143,6 +143,20 @@ func (s *Service) verifyBeaconBlock(ctx context.Context, data *ethpb.Attestation
return nil
}
// verifyLMDFFGConsistent verifies LMD GHOST and FFG votes are consistent with each other.
func (s *Service) verifyLMDFFGConsistent(ctx context.Context, ffgEpoch uint64, ffgRoot []byte, lmdRoot []byte) error {
ffgSlot := helpers.StartSlot(ffgEpoch)
r, err := s.ancestor(ctx, lmdRoot, ffgSlot)
if err != nil {
return err
}
if !bytes.Equal(ffgRoot, r) {
return errors.New("FFG and LMD votes are not consistent")
}
return nil
}
// verifyAttestation validates input attestation is valid.
func (s *Service) verifyAttestation(ctx context.Context, baseState *stateTrie.BeaconState, a *ethpb.Attestation) (*ethpb.IndexedAttestation, error) {
committee, err := helpers.BeaconCommitteeFromState(baseState, a.Data.Slot, a.Data.CommitteeIndex)

View File

@@ -468,3 +468,68 @@ func TestVerifyBeaconBlock_OK(t *testing.T) {
t.Error("Did not receive the wanted error")
}
}
func TestVerifyLMDFFGConsistent_NotOK(t *testing.T) {
ctx := context.Background()
db := testDB.SetupDB(t)
cfg := &Config{BeaconDB: db}
service, err := NewService(ctx, cfg)
if err != nil {
t.Fatal(err)
}
b32 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 32}}
if err := service.beaconDB.SaveBlock(ctx, b32); err != nil {
t.Fatal(err)
}
r32, err := stateutil.BlockRoot(b32.Block)
if err != nil {
t.Fatal(err)
}
b33 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 33, ParentRoot: r32[:]}}
if err := service.beaconDB.SaveBlock(ctx, b33); err != nil {
t.Fatal(err)
}
r33, err := stateutil.BlockRoot(b33.Block)
if err != nil {
t.Fatal(err)
}
wanted := "FFG and LMD votes are not consistent"
if err := service.verifyLMDFFGConsistent(context.Background(), 1, []byte{'a'}, r33[:]); err.Error() != wanted {
t.Error("Did not get wanted error")
}
}
func TestVerifyLMDFFGConsistent_OK(t *testing.T) {
ctx := context.Background()
db := testDB.SetupDB(t)
cfg := &Config{BeaconDB: db}
service, err := NewService(ctx, cfg)
if err != nil {
t.Fatal(err)
}
b32 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 32}}
if err := service.beaconDB.SaveBlock(ctx, b32); err != nil {
t.Fatal(err)
}
r32, err := stateutil.BlockRoot(b32.Block)
if err != nil {
t.Fatal(err)
}
b33 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 33, ParentRoot: r32[:]}}
if err := service.beaconDB.SaveBlock(ctx, b33); err != nil {
t.Fatal(err)
}
r33, err := stateutil.BlockRoot(b33.Block)
if err != nil {
t.Fatal(err)
}
if err := service.verifyLMDFFGConsistent(context.Background(), 1, r32[:], r33[:]); err != nil {
t.Errorf("Could not verify LMD and FFG votes to be consistent: %v", err)
}
}

View File

@@ -387,7 +387,8 @@ func (s *Service) filterBlockRoots(ctx context.Context, roots [][32]byte) ([][32
// elif block.slot == slot:
// return root
// else:
// return Bytes32() # root is older than queried slot: no results.
// # root is older than queried slot, thus a skip slot. Return most recent root prior to slot.
// return root
func (s *Service) ancestor(ctx context.Context, root []byte, slot uint64) ([]byte, error) {
ctx, span := trace.StartSpan(ctx, "forkchoice.ancestor")
defer span.End()

View File

@@ -230,13 +230,15 @@ func TestRemoveStateSinceLastFinalized_EmptyStartSlot(t *testing.T) {
if !update {
t.Error("Should be able to update justified, received false")
}
lastJustifiedBlk := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{ParentRoot: []byte{'G'}}}
lastJustifiedBlk := testutil.NewBeaconBlock()
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
lastJustifiedRoot, err := stateutil.BlockRoot(lastJustifiedBlk.Block)
if err != nil {
t.Fatal(err)
}
newJustifiedBlk := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 1, ParentRoot: lastJustifiedRoot[:]}}
newJustifiedBlk := testutil.NewBeaconBlock()
newJustifiedBlk.Block.Slot = 1
newJustifiedBlk.Block.ParentRoot = bytesutil.PadTo(lastJustifiedRoot[:], 32)
newJustifiedRoot, err := stateutil.BlockRoot(newJustifiedBlk.Block)
if err != nil {
t.Fatal(err)
@@ -271,12 +273,14 @@ func TestShouldUpdateJustified_ReturnFalse(t *testing.T) {
if err != nil {
t.Fatal(err)
}
lastJustifiedBlk := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{ParentRoot: []byte{'G'}}}
lastJustifiedBlk := testutil.NewBeaconBlock()
lastJustifiedBlk.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
lastJustifiedRoot, err := stateutil.BlockRoot(lastJustifiedBlk.Block)
if err != nil {
t.Fatal(err)
}
newJustifiedBlk := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{ParentRoot: lastJustifiedRoot[:]}}
newJustifiedBlk := testutil.NewBeaconBlock()
newJustifiedBlk.Block.ParentRoot = bytesutil.PadTo(lastJustifiedRoot[:], 32)
newJustifiedRoot, err := stateutil.BlockRoot(newJustifiedBlk.Block)
if err != nil {
t.Fatal(err)
@@ -743,11 +747,14 @@ func blockTree1(db db.Database, genesisRoot []byte) ([][]byte, error) {
st := testutil.NewBeaconState()
for _, b := range []*ethpb.BeaconBlock{b0, b1, b3, b4, b5, b6, b7, b8} {
b.Body = &ethpb.BeaconBlockBody{}
if err := db.SaveBlock(context.Background(), &ethpb.SignedBeaconBlock{Block: b}); err != nil {
beaconBlock := testutil.NewBeaconBlock()
beaconBlock.Block.Slot = b.Slot
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
beaconBlock.Block.Body = &ethpb.BeaconBlockBody{}
if err := db.SaveBlock(context.Background(), beaconBlock); err != nil {
return nil, err
}
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(b.ParentRoot)); err != nil {
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(beaconBlock.Block.ParentRoot)); err != nil {
return nil, err
}
}

View File

@@ -31,6 +31,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
protodb "github.com/prysmaticlabs/prysm/proto/beacon/db"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/event"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
@@ -64,6 +65,11 @@ func (mb *mockBroadcaster) Broadcast(_ context.Context, _ proto.Message) error {
return nil
}
func (mb *mockBroadcaster) BroadcastAttestation(_ context.Context, _ uint64, _ *ethpb.Attestation) error {
mb.broadcastCalled = true
return nil
}
var _ = p2p.Broadcaster(&mockBroadcaster{})
func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
@@ -186,7 +192,7 @@ func TestChainStartStop_Initialized(t *testing.T) {
chainService := setupBeaconChain(t, db)
genesisBlk := b.NewGenesisBlock([]byte{})
genesisBlk := testutil.NewBeaconBlock()
blkRoot, err := stateutil.BlockRoot(genesisBlk.Block)
if err != nil {
t.Fatal(err)
@@ -283,7 +289,7 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
db := testDB.SetupDB(t)
ctx := context.Background()
genesis := b.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(genesis.Block)
if err != nil {
t.Fatal(err)
@@ -296,7 +302,9 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
}
finalizedSlot := params.BeaconConfig().SlotsPerEpoch*2 + 1
headBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: finalizedSlot, ParentRoot: genesisRoot[:]}}
headBlock := testutil.NewBeaconBlock()
headBlock.Block.Slot = finalizedSlot
headBlock.Block.ParentRoot = bytesutil.PadTo(genesisRoot[:], 32)
headState := testutil.NewBeaconState()
if err := headState.SetSlot(finalizedSlot); err != nil {
t.Fatal(err)
@@ -323,9 +331,6 @@ func TestChainService_InitializeChainInfo(t *testing.T) {
}); err != nil {
t.Fatal(err)
}
if err := db.SaveBlock(ctx, headBlock); err != nil {
t.Fatal(err)
}
c := &Service{beaconDB: db, stateGen: stategen.New(db, cache.NewStateSummaryCache())}
if err := c.initializeChainInfo(ctx); err != nil {
t.Fatal(err)

View File

@@ -37,6 +37,7 @@ type ChainService struct {
Genesis time.Time
ValidatorsRoot [32]byte
Fork *pb.Fork
ETH1Data *ethpb.Eth1Data
DB db.Database
stateNotifier statefeed.Notifier
blockNotifier blockfeed.Notifier
@@ -222,6 +223,11 @@ func (ms *ChainService) HeadSeed(epoch uint64) ([32]byte, error) {
return helpers.Seed(ms.State, epoch, params.BeaconConfig().DomainBeaconAttester)
}
// HeadETH1Data provides the current ETH1Data of the head state.
func (ms *ChainService) HeadETH1Data() *ethpb.Eth1Data {
return ms.ETH1Data
}
// ProtoArrayStore mocks the same method in the chain service.
func (ms *ChainService) ProtoArrayStore() *protoarray.Store {
return ms.ForkChoiceStore
@@ -252,6 +258,12 @@ func (ms *ChainService) IsValidAttestation(ctx context.Context, att *ethpb.Attes
return ms.ValidAttestation
}
// IsCanonical returns and determines whether a block with the provided root is part of
// the canonical chain.
func (ms *ChainService) IsCanonical(ctx context.Context, blockRoot [32]byte) (bool, error) {
return true, nil
}
// ClearCachedStates does nothing.
func (ms *ChainService) ClearCachedStates() {}

View File

@@ -7,12 +7,12 @@ go_library(
"attestation_data.go",
"checkpoint_state.go",
"committee.go",
"committee_ids.go",
"common.go",
"doc.go",
"hot_state_cache.go",
"skip_slot_cache.go",
"state_summary.go",
"subnet_ids.go",
],
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/cache",
visibility = [
@@ -44,11 +44,11 @@ go_test(
"attestation_data_test.go",
"checkpoint_state_test.go",
"committee_fuzz_test.go",
"committee_ids_test.go",
"committee_test.go",
"feature_flag_test.go",
"hot_state_cache_test.go",
"skip_slot_cache_test.go",
"subnet_ids_test.go",
],
embed = [":go_default_library"],
deps = [

View File

@@ -10,7 +10,7 @@ import (
"github.com/prysmaticlabs/prysm/shared/sliceutil"
)
type committeeIDs struct {
type subnetIDs struct {
attester *lru.Cache
attesterLock sync.RWMutex
aggregator *lru.Cache
@@ -19,10 +19,10 @@ type committeeIDs struct {
subnetsLock sync.RWMutex
}
// CommitteeIDs for attester and aggregator.
var CommitteeIDs = newCommitteeIDs()
// SubnetIDs for attester and aggregator.
var SubnetIDs = newSubnetIDs()
func newCommitteeIDs() *committeeIDs {
func newSubnetIDs() *subnetIDs {
// Given a node can calculate committee assignments of current epoch and next epoch.
// Max size is set to 2 epoch length.
cacheSize := int(params.BeaconConfig().MaxCommitteesPerSlot * params.BeaconConfig().SlotsPerEpoch * 2)
@@ -37,15 +37,15 @@ func newCommitteeIDs() *committeeIDs {
epochDuration := time.Duration(params.BeaconConfig().SlotsPerEpoch * params.BeaconConfig().SecondsPerSlot)
subLength := epochDuration * time.Duration(params.BeaconNetworkConfig().EpochsPerRandomSubnetSubscription)
persistentCache := cache.New(subLength*time.Second, epochDuration*time.Second)
return &committeeIDs{attester: attesterCache, aggregator: aggregatorCache, persistentSubnets: persistentCache}
return &subnetIDs{attester: attesterCache, aggregator: aggregatorCache, persistentSubnets: persistentCache}
}
// AddAttesterCommiteeID adds committee ID for subscribing subnet for the attester of a given slot.
func (c *committeeIDs) AddAttesterCommiteeID(slot uint64, committeeID uint64) {
// AddAttesterSubnetID adds the subnet index for subscribing subnet for the attester of a given slot.
func (c *subnetIDs) AddAttesterSubnetID(slot uint64, subnetID uint64) {
c.attesterLock.Lock()
defer c.attesterLock.Unlock()
ids := []uint64{committeeID}
ids := []uint64{subnetID}
val, exists := c.attester.Get(slot)
if exists {
ids = sliceutil.UnionUint64(append(val.([]uint64), ids...))
@@ -53,8 +53,8 @@ func (c *committeeIDs) AddAttesterCommiteeID(slot uint64, committeeID uint64) {
c.attester.Add(slot, ids)
}
// GetAttesterCommitteeIDs gets the committee ID for subscribing subnet for attester of the slot.
func (c *committeeIDs) GetAttesterCommitteeIDs(slot uint64) []uint64 {
// GetAttesterSubnetIDs gets the subnet IDs for subscribed subnets for attesters of the slot.
func (c *subnetIDs) GetAttesterSubnetIDs(slot uint64) []uint64 {
c.attesterLock.RLock()
defer c.attesterLock.RUnlock()
@@ -68,12 +68,12 @@ func (c *committeeIDs) GetAttesterCommitteeIDs(slot uint64) []uint64 {
return nil
}
// AddAggregatorCommiteeID adds committee ID for subscribing subnet for the aggregator of a given slot.
func (c *committeeIDs) AddAggregatorCommiteeID(slot uint64, committeeID uint64) {
// AddAggregatorSubnetID adds the subnet ID for subscribing subnet for the aggregator of a given slot.
func (c *subnetIDs) AddAggregatorSubnetID(slot uint64, subnetID uint64) {
c.aggregatorLock.Lock()
defer c.aggregatorLock.Unlock()
ids := []uint64{committeeID}
ids := []uint64{subnetID}
val, exists := c.aggregator.Get(slot)
if exists {
ids = sliceutil.UnionUint64(append(val.([]uint64), ids...))
@@ -81,8 +81,8 @@ func (c *committeeIDs) AddAggregatorCommiteeID(slot uint64, committeeID uint64)
c.aggregator.Add(slot, ids)
}
// GetAggregatorCommitteeIDs gets the committee ID for subscribing subnet for aggregator of the slot.
func (c *committeeIDs) GetAggregatorCommitteeIDs(slot uint64) []uint64 {
// GetAggregatorSubnetIDs gets the subnet IDs for subscribing subnet for aggregator of the slot.
func (c *subnetIDs) GetAggregatorSubnetIDs(slot uint64) []uint64 {
c.aggregatorLock.RLock()
defer c.aggregatorLock.RUnlock()
@@ -93,9 +93,9 @@ func (c *committeeIDs) GetAggregatorCommitteeIDs(slot uint64) []uint64 {
return val.([]uint64)
}
// GetPersistentCommittees retrieves the persistent committee and expiration time of that validator's
// GetPersistentSubnets retrieves the persistent subnet and expiration time of that validator's
// subscription.
func (c *committeeIDs) GetPersistentCommittees(pubkey []byte) ([]uint64, bool, time.Time) {
func (c *subnetIDs) GetPersistentSubnets(pubkey []byte) ([]uint64, bool, time.Time) {
c.subnetsLock.RLock()
defer c.subnetsLock.RUnlock()
@@ -106,9 +106,9 @@ func (c *committeeIDs) GetPersistentCommittees(pubkey []byte) ([]uint64, bool, t
return id.([]uint64), ok, duration
}
// GetAllCommittees retrieves all the non-expired subscribed committees of all the validators
// GetAllSubnets retrieves all the non-expired subscribed subnets of all the validators
// in the cache.
func (c *committeeIDs) GetAllCommittees() []uint64 {
func (c *subnetIDs) GetAllSubnets() []uint64 {
c.subnetsLock.RLock()
defer c.subnetsLock.RUnlock()
@@ -126,7 +126,7 @@ func (c *committeeIDs) GetAllCommittees() []uint64 {
// AddPersistentCommittee adds the relevant committee for that particular validator along with its
// expiration period.
func (c *committeeIDs) AddPersistentCommittee(pubkey []byte, comIndex []uint64, duration time.Duration) {
func (c *subnetIDs) AddPersistentCommittee(pubkey []byte, comIndex []uint64, duration time.Duration) {
c.subnetsLock.Lock()
defer c.subnetsLock.Unlock()

View File

@@ -5,59 +5,59 @@ import (
"testing"
)
func TestCommitteeIDCache_RoundTrip(t *testing.T) {
c := newCommitteeIDs()
func TestSubnetIDsCache_RoundTrip(t *testing.T) {
c := newSubnetIDs()
slot := uint64(100)
committeeIDs := c.GetAggregatorCommitteeIDs(slot)
committeeIDs := c.GetAggregatorSubnetIDs(slot)
if len(committeeIDs) != 0 {
t.Errorf("Empty cache returned an object: %v", committeeIDs)
}
c.AddAggregatorCommiteeID(slot, 1)
res := c.GetAggregatorCommitteeIDs(slot)
c.AddAggregatorSubnetID(slot, 1)
res := c.GetAggregatorSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{1}) {
t.Error("Expected equal value to return from cache")
}
c.AddAggregatorCommiteeID(slot, 2)
res = c.GetAggregatorCommitteeIDs(slot)
c.AddAggregatorSubnetID(slot, 2)
res = c.GetAggregatorSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{1, 2}) {
t.Error("Expected equal value to return from cache")
}
c.AddAggregatorCommiteeID(slot, 3)
res = c.GetAggregatorCommitteeIDs(slot)
c.AddAggregatorSubnetID(slot, 3)
res = c.GetAggregatorSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{1, 2, 3}) {
t.Error("Expected equal value to return from cache")
}
committeeIDs = c.GetAttesterCommitteeIDs(slot)
committeeIDs = c.GetAttesterSubnetIDs(slot)
if len(committeeIDs) != 0 {
t.Errorf("Empty cache returned an object: %v", committeeIDs)
}
c.AddAttesterCommiteeID(slot, 11)
res = c.GetAttesterCommitteeIDs(slot)
c.AddAttesterSubnetID(slot, 11)
res = c.GetAttesterSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{11}) {
t.Error("Expected equal value to return from cache")
}
c.AddAttesterCommiteeID(slot, 22)
res = c.GetAttesterCommitteeIDs(slot)
c.AddAttesterSubnetID(slot, 22)
res = c.GetAttesterSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{11, 22}) {
t.Error("Expected equal value to return from cache")
}
c.AddAttesterCommiteeID(slot, 33)
res = c.GetAttesterCommitteeIDs(slot)
c.AddAttesterSubnetID(slot, 33)
res = c.GetAttesterSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{11, 22, 33}) {
t.Error("Expected equal value to return from cache")
}
}
func TestCommitteeIDs_PersistentCommitteeRoundtrip(t *testing.T) {
func TestSubnetIDsCache_PersistentCommitteeRoundtrip(t *testing.T) {
pubkeySet := [][48]byte{}
c := newCommitteeIDs()
c := newSubnetIDs()
for i := 0; i < 20; i++ {
pubkey := [48]byte{byte(i)}
@@ -68,7 +68,7 @@ func TestCommitteeIDs_PersistentCommitteeRoundtrip(t *testing.T) {
for i := 0; i < 20; i++ {
pubkey := [48]byte{byte(i)}
idxs, ok, _ := c.GetPersistentCommittees(pubkey[:])
idxs, ok, _ := c.GetPersistentSubnets(pubkey[:])
if !ok {
t.Errorf("Couldn't find entry in cache for pubkey %#x", pubkey)
continue
@@ -77,7 +77,7 @@ func TestCommitteeIDs_PersistentCommitteeRoundtrip(t *testing.T) {
t.Fatalf("Wanted index of %d but got %d", i, idxs[0])
}
}
coms := c.GetAllCommittees()
coms := c.GetAllSubnets()
if len(coms) != 20 {
t.Errorf("Number of committees is not %d but is %d", 20, len(coms))
}

View File

@@ -44,11 +44,11 @@ func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, pub []byte, signature
if err != nil {
return errors.Wrap(err, "could not get signing root")
}
sigRoot := &pb.SigningRoot{
signingData := &pb.SigningData{
ObjectRoot: root[:],
Domain: domain,
}
ctrRoot, err := ssz.HashTreeRoot(sigRoot)
ctrRoot, err := ssz.HashTreeRoot(signingData)
if err != nil {
return errors.Wrap(err, "could not get container root")
}
@@ -67,11 +67,11 @@ func verifySignature(signedData []byte, pub []byte, signature []byte, domain []b
if err != nil {
return errors.Wrap(err, "could not convert bytes to signature")
}
ctr := &pb.SigningRoot{
signingData := &pb.SigningData{
ObjectRoot: signedData,
Domain: domain,
}
root, err := ssz.HashTreeRoot(ctr)
root, err := ssz.HashTreeRoot(signingData)
if err != nil {
return errors.Wrap(err, "could not hash container")
}
@@ -1104,11 +1104,11 @@ func VerifyExit(validator *stateTrie.ReadOnlyValidator, currentSlot uint64, fork
return fmt.Errorf("expected current epoch >= exit epoch, received %d < %d", currentEpoch, exit.Epoch)
}
// Verify the validator has been active long enough.
if currentEpoch < validator.ActivationEpoch()+params.BeaconConfig().PersistentCommitteePeriod {
if currentEpoch < validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod {
return fmt.Errorf(
"validator has not been active long enough to exit, wanted epoch %d >= %d",
currentEpoch,
validator.ActivationEpoch()+params.BeaconConfig().PersistentCommitteePeriod,
validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod,
)
}
domain, err := helpers.Domain(fork, exit.Epoch, params.BeaconConfig().DomainVoluntaryExit, genesisRoot)

View File

@@ -433,7 +433,7 @@ func TestProcessRandao_IncorrectProposerFailsVerification(t *testing.T) {
if err != nil {
t.Fatal(err)
}
root, err := ssz.HashTreeRoot(&pb.SigningRoot{ObjectRoot: buf, Domain: domain})
root, err := ssz.HashTreeRoot(&pb.SigningData{ObjectRoot: buf, Domain: domain})
if err != nil {
t.Fatal(err)
}
@@ -2018,7 +2018,7 @@ func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = state.SetSlot(state.Slot() + (params.BeaconConfig().PersistentCommitteePeriod * params.BeaconConfig().SlotsPerEpoch))
err = state.SetSlot(state.Slot() + (params.BeaconConfig().ShardCommitteePeriod * params.BeaconConfig().SlotsPerEpoch))
if err != nil {
t.Fatal(err)
}

View File

@@ -43,6 +43,7 @@ go_test(
"//beacon-chain/state:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/attestationutil:go_default_library",
"//shared/mathutil:go_default_library",
"//shared/params:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",

View File

@@ -9,6 +9,7 @@ import (
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/attestationutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/traceutil"
"go.opencensus.io/trace"
)
@@ -90,12 +91,14 @@ func AttestedPrevEpoch(s *stateTrie.BeaconState, a *pb.PendingAttestation) (bool
votedTarget = true
}
same, err = SameHead(s, a)
if err != nil {
return false, false, false, errors.Wrap(err, "could not check same head")
}
if same {
votedHead = true
if votedTarget {
same, err = SameHead(s, a)
if err != nil {
return false, false, false, errors.Wrap(err, "could not check same head")
}
if same {
votedHead = true
}
}
}
return votedPrevEpoch, votedTarget, votedHead, nil
@@ -176,5 +179,34 @@ func UpdateBalance(vp []*Validator, bBal *Balance) *Balance {
}
}
}
return EnsureBalancesLowerBound(bBal)
}
// EnsureBalancesLowerBound ensures all the balances such as active current epoch, active previous epoch and more
// have EffectiveBalanceIncrement(1 eth) as a lower bound.
func EnsureBalancesLowerBound(bBal *Balance) *Balance {
ebi := params.BeaconConfig().EffectiveBalanceIncrement
if ebi > bBal.ActiveCurrentEpoch {
bBal.ActiveCurrentEpoch = ebi
}
if ebi > bBal.ActivePrevEpoch {
bBal.ActivePrevEpoch = ebi
}
if ebi > bBal.CurrentEpochAttested {
bBal.CurrentEpochAttested = ebi
}
if ebi > bBal.CurrentEpochTargetAttested {
bBal.CurrentEpochTargetAttested = ebi
}
if ebi > bBal.PrevEpochAttested {
bBal.PrevEpochAttested = ebi
}
if ebi > bBal.PrevEpochTargetAttested {
bBal.PrevEpochTargetAttested = ebi
}
if ebi > bBal.PrevEpochHeadAttested {
bBal.PrevEpochHeadAttested = ebi
}
return bBal
}

View File

@@ -50,21 +50,23 @@ func TestUpdateValidator_InclusionOnlyCountsPrevEpoch(t *testing.T) {
func TestUpdateBalance(t *testing.T) {
vp := []*precompute.Validator{
{IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100},
{IsCurrentEpochTargetAttester: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100},
{IsCurrentEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100},
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 100},
{IsPrevEpochAttester: true, IsPrevEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100},
{IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100},
{IsPrevEpochAttester: true, IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100},
{IsSlashed: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100},
{IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsCurrentEpochTargetAttester: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsCurrentEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsPrevEpochAttester: true, IsPrevEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsPrevEpochAttester: true, IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsSlashed: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
}
wantedPBal := &precompute.Balance{
CurrentEpochAttested: 200,
CurrentEpochTargetAttested: 200,
PrevEpochAttested: 300,
PrevEpochTargetAttested: 100,
PrevEpochHeadAttested: 200,
ActiveCurrentEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
ActivePrevEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
CurrentEpochAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
CurrentEpochTargetAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochAttested: 300 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochTargetAttested: 100 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochHeadAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
}
pBal := precompute.UpdateBalance(vp, &precompute.Balance{})
if !reflect.DeepEqual(pBal, wantedPBal) {
@@ -220,7 +222,7 @@ func TestProcessAttestations(t *testing.T) {
if err := beaconState.SetBlockRoots(br); err != nil {
t.Fatal(err)
}
att2.Data.Target.Root = rt[:]
att2.Data.Target.Root = newRt[:]
att2.Data.BeaconBlockRoot = newRt[:]
err := beaconState.SetPreviousEpochAttestations([]*pb.PendingAttestation{{Data: att1.Data, AggregationBits: bf}})
if err != nil {
@@ -260,8 +262,37 @@ func TestProcessAttestations(t *testing.T) {
if !pVals[i].IsPrevEpochAttester {
t.Error("Not a prev epoch attester")
}
if !pVals[i].IsPrevEpochTargetAttester {
t.Error("Not a prev epoch target attester")
}
if !pVals[i].IsPrevEpochHeadAttester {
t.Error("Not a prev epoch head attester")
}
}
}
func TestEnsureBalancesLowerBound(t *testing.T) {
b := &precompute.Balance{}
b = precompute.EnsureBalancesLowerBound(b)
if b.ActiveCurrentEpoch != params.BeaconConfig().EffectiveBalanceIncrement {
t.Error("Did not get wanted active current balance")
}
if b.ActivePrevEpoch != params.BeaconConfig().EffectiveBalanceIncrement {
t.Error("Did not get wanted active previous balance")
}
if b.CurrentEpochAttested != params.BeaconConfig().EffectiveBalanceIncrement {
t.Error("Did not get wanted current attested balance")
}
if b.CurrentEpochTargetAttested != params.BeaconConfig().EffectiveBalanceIncrement {
t.Error("Did not get wanted target attested balance")
}
if b.PrevEpochAttested != params.BeaconConfig().EffectiveBalanceIncrement {
t.Error("Did not get wanted prev attested balance")
}
if b.PrevEpochTargetAttested != params.BeaconConfig().EffectiveBalanceIncrement {
t.Error("Did not get wanted prev target attested balance")
}
if b.PrevEpochHeadAttested != params.BeaconConfig().EffectiveBalanceIncrement {
t.Error("Did not get wanted prev head attested balance")
}
}

View File

@@ -27,7 +27,7 @@ func New(ctx context.Context, state *stateTrie.BeaconState) ([]*Validator, *Bala
if err := state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
// Was validator withdrawable or slashed
withdrawable := currentEpoch >= val.WithdrawableEpoch()
withdrawable := prevEpoch+1 >= val.WithdrawableEpoch()
pVal := &Validator{
IsSlashed: val.Slashed(),
IsWithdrawableCurrentEpoch: withdrawable,

View File

@@ -2,7 +2,6 @@ package precompute
import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/shared/mathutil"
@@ -27,116 +26,144 @@ func ProcessRewardsAndPenaltiesPrecompute(
return state, errors.New("precomputed registries not the same length as state registries")
}
attsRewards, attsPenalties, err := attestationDeltas(state, pBal, vp)
attsRewards, attsPenalties, err := AttestationsDelta(state, pBal, vp)
if err != nil {
return nil, errors.Wrap(err, "could not get attestation delta")
}
proposerRewards, err := proposerDeltaPrecompute(state, pBal, vp)
proposerRewards, err := ProposersDelta(state, pBal, vp)
if err != nil {
return nil, errors.Wrap(err, "could not get attestation delta")
}
validatorBals := state.Balances()
for i := 0; i < numOfVals; i++ {
vp[i].BeforeEpochTransitionBalance, err = state.BalanceAtIndex(uint64(i))
if err != nil {
return nil, errors.Wrap(err, "could not get validator balance before epoch")
}
vp[i].BeforeEpochTransitionBalance = validatorBals[i]
if err := helpers.IncreaseBalance(state, uint64(i), attsRewards[i]+proposerRewards[i]); err != nil {
return nil, err
}
if err := helpers.DecreaseBalance(state, uint64(i), attsPenalties[i]); err != nil {
return nil, err
}
// Compute the post balance of the validator after accounting for the
// attester and proposer rewards and penalties.
validatorBals[i] = helpers.IncreaseBalanceWithVal(validatorBals[i], attsRewards[i]+proposerRewards[i])
validatorBals[i] = helpers.DecreaseBalanceWithVal(validatorBals[i], attsPenalties[i])
vp[i].AfterEpochTransitionBalance, err = state.BalanceAtIndex(uint64(i))
if err != nil {
return nil, errors.Wrap(err, "could not get validator balance after epoch")
}
vp[i].AfterEpochTransitionBalance = validatorBals[i]
}
if err := state.SetBalances(validatorBals); err != nil {
return nil, errors.Wrap(err, "could not set validator balances")
}
return state, nil
}
// This computes the rewards and penalties differences for individual validators based on the
// AttestationsDelta computes and returns the rewards and penalties differences for individual validators based on the
// voting records.
func attestationDeltas(state *stateTrie.BeaconState, pBal *Balance, vp []*Validator) ([]uint64, []uint64, error) {
func AttestationsDelta(state *stateTrie.BeaconState, pBal *Balance, vp []*Validator) ([]uint64, []uint64, error) {
numOfVals := state.NumValidators()
rewards := make([]uint64, numOfVals)
penalties := make([]uint64, numOfVals)
prevEpoch := helpers.PrevEpoch(state)
finalizedEpoch := state.FinalizedCheckpointEpoch()
for i, v := range vp {
rewards[i], penalties[i] = attestationDelta(state, pBal, v)
rewards[i], penalties[i] = attestationDelta(pBal, v, prevEpoch, finalizedEpoch)
}
return rewards, penalties, nil
}
func attestationDelta(state *stateTrie.BeaconState, pBal *Balance, v *Validator) (uint64, uint64) {
func attestationDelta(pBal *Balance, v *Validator, prevEpoch uint64, finalizedEpoch uint64) (uint64, uint64) {
eligible := v.IsActivePrevEpoch || (v.IsSlashed && !v.IsWithdrawableCurrentEpoch)
if !eligible || pBal.ActiveCurrentEpoch == 0 {
return 0, 0
}
e := helpers.PrevEpoch(state)
baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch
effectiveBalanceIncrement := params.BeaconConfig().EffectiveBalanceIncrement
vb := v.CurrentEpochEffectiveBalance
br := vb * params.BeaconConfig().BaseRewardFactor / mathutil.IntegerSquareRoot(pBal.ActiveCurrentEpoch) / params.BeaconConfig().BaseRewardsPerEpoch
br := vb * params.BeaconConfig().BaseRewardFactor / mathutil.IntegerSquareRoot(pBal.ActiveCurrentEpoch) / baseRewardsPerEpoch
r, p := uint64(0), uint64(0)
currentEpochBalance := pBal.ActiveCurrentEpoch / effectiveBalanceIncrement
// Process source reward / penalty
if v.IsPrevEpochAttester && !v.IsSlashed {
inc := params.BeaconConfig().EffectiveBalanceIncrement
rewardNumerator := br * pBal.PrevEpochAttested / inc
r += rewardNumerator / (pBal.ActiveCurrentEpoch / inc)
proposerReward := br / params.BeaconConfig().ProposerRewardQuotient
maxAtteserReward := br - proposerReward
r += maxAtteserReward / v.InclusionDistance
maxAttesterReward := br - proposerReward
r += maxAttesterReward / v.InclusionDistance
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
// Since full base reward will be canceled out by inactivity penalty deltas,
// optimal participation receives full base reward compensation here.
r += br
} else {
rewardNumerator := br * (pBal.PrevEpochAttested / effectiveBalanceIncrement)
r += rewardNumerator / currentEpochBalance
}
} else {
p += br
}
// Process target reward / penalty
if v.IsPrevEpochTargetAttester && !v.IsSlashed {
inc := params.BeaconConfig().EffectiveBalanceIncrement
rewardNumerator := br * pBal.PrevEpochAttested / inc
r += rewardNumerator / (pBal.ActiveCurrentEpoch / inc)
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
// Since full base reward will be canceled out by inactivity penalty deltas,
// optimal participation receives full base reward compensation here.
r += br
} else {
rewardNumerator := br * (pBal.PrevEpochTargetAttested / effectiveBalanceIncrement)
r += rewardNumerator / currentEpochBalance
}
} else {
p += br
}
// Process head reward / penalty
if v.IsPrevEpochHeadAttester && !v.IsSlashed {
inc := params.BeaconConfig().EffectiveBalanceIncrement
rewardNumerator := br * pBal.PrevEpochAttested / inc
r += rewardNumerator / (pBal.ActiveCurrentEpoch / inc)
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
// Since full base reward will be canceled out by inactivity penalty deltas,
// optimal participation receives full base reward compensation here.
r += br
} else {
rewardNumerator := br * (pBal.PrevEpochHeadAttested / effectiveBalanceIncrement)
r += rewardNumerator / currentEpochBalance
}
} else {
p += br
}
// Process finality delay penalty
finalizedEpoch := state.FinalizedCheckpointEpoch()
finalityDelay := e - finalizedEpoch
if finalityDelay > params.BeaconConfig().MinEpochsToInactivityPenalty {
p += params.BeaconConfig().BaseRewardsPerEpoch * br
if !v.IsPrevEpochTargetAttester {
finalityDelay := finalityDelay(prevEpoch, finalizedEpoch)
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
// If validator is performing optimally, this cancels all rewards for a neutral balance.
proposerReward := br / params.BeaconConfig().ProposerRewardQuotient
p += baseRewardsPerEpoch*br - proposerReward
// Apply an additional penalty to validators that did not vote on the correct target or has been slashed.
// Equivalent to the following condition from the spec:
// `index not in get_unslashed_attesting_indices(state, matching_target_attestations)`
if !v.IsPrevEpochTargetAttester || v.IsSlashed {
p += vb * finalityDelay / params.BeaconConfig().InactivityPenaltyQuotient
}
}
return r, p
}
// This computes the rewards and penalties differences for individual validators based on the
// ProposersDelta computes and returns the rewards and penalties differences for individual validators based on the
// proposer inclusion records.
func proposerDeltaPrecompute(state *stateTrie.BeaconState, pBal *Balance, vp []*Validator) ([]uint64, error) {
func ProposersDelta(state *stateTrie.BeaconState, pBal *Balance, vp []*Validator) ([]uint64, error) {
numofVals := state.NumValidators()
rewards := make([]uint64, numofVals)
totalBalance := pBal.ActiveCurrentEpoch
balanceSqrt := mathutil.IntegerSquareRoot(totalBalance)
// Balance square root cannot be 0, this prevents division by 0.
if balanceSqrt == 0 {
balanceSqrt = 1
}
baseRewardFactor := params.BeaconConfig().BaseRewardFactor
balanceSqrt := mathutil.IntegerSquareRoot(totalBalance)
baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch
proposerRewardQuotient := params.BeaconConfig().ProposerRewardQuotient
for _, v := range vp {
if v.IsPrevEpochAttester {
// Only apply inclusion rewards to proposer only if the attested hasn't been slashed.
if v.IsPrevEpochAttester && !v.IsSlashed {
vBalance := v.CurrentEpochEffectiveBalance
baseReward := vBalance * baseRewardFactor / balanceSqrt / baseRewardsPerEpoch
proposerReward := baseReward / proposerRewardQuotient
@@ -145,3 +172,21 @@ func proposerDeltaPrecompute(state *stateTrie.BeaconState, pBal *Balance, vp []*
}
return rewards, nil
}
// isInInactivityLeak returns true if the state is experiencing inactivity leak.
//
// Spec code:
// def is_in_inactivity_leak(state: BeaconState) -> bool:
// return get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY
func isInInactivityLeak(prevEpoch uint64, finalizedEpoch uint64) bool {
return finalityDelay(prevEpoch, finalizedEpoch) > params.BeaconConfig().MinEpochsToInactivityPenalty
}
// finalityDelay returns the finality delay using the beacon state.
//
// Spec code:
// def get_finality_delay(state: BeaconState) -> uint64:
// return get_previous_epoch(state) - state.finalized_checkpoint.epoch
func finalityDelay(prevEpoch uint64, finalizedEpoch uint64) uint64 {
return prevEpoch - finalizedEpoch
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/mathutil"
"github.com/prysmaticlabs/prysm/shared/params"
)
@@ -90,6 +91,14 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
if err != nil {
t.Fatal(err)
}
slashedAttestedIndices := []uint64{1413}
for _, i := range slashedAttestedIndices {
vs := state.Validators()
vs[i].Slashed = true
if state.SetValidators(vs) != nil {
t.Fatal(err)
}
}
vp, bp, err := New(context.Background(), state)
if err != nil {
@@ -100,7 +109,11 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
t.Fatal(err)
}
rewards, penalties, err := attestationDeltas(state, bp, vp)
// Add some variances to target and head balances.
// See: https://github.com/prysmaticlabs/prysm/issues/5593
bp.PrevEpochTargetAttested = bp.PrevEpochTargetAttested / 2
bp.PrevEpochHeadAttested = bp.PrevEpochHeadAttested * 2 / 3
rewards, penalties, err := AttestationsDelta(state, bp, vp)
if err != nil {
t.Fatal(err)
}
@@ -113,18 +126,21 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
t.Fatal(err)
}
attestedIndices := []uint64{55, 1339, 1746, 1811, 1569, 1413}
attestedIndices := []uint64{55, 1339, 1746, 1811, 1569}
for _, i := range attestedIndices {
base, err := epoch.BaseReward(state, i)
if err != nil {
t.Errorf("Could not get base reward: %v", err)
}
// Base rewards for getting source right
wanted := 3 * (base * attestedBalance / totalBalance)
wanted := attestedBalance*base/totalBalance +
bp.PrevEpochTargetAttested*base/totalBalance +
bp.PrevEpochHeadAttested*base/totalBalance
// Base rewards for proposer and attesters working together getting attestation
// on chain in the fatest manner
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
wanted += (base - proposerReward) * params.BeaconConfig().MinAttestationInclusionDelay
wanted += (base-proposerReward)*params.BeaconConfig().MinAttestationInclusionDelay - 1
if rewards[i] != wanted {
t.Errorf("Wanted reward balance %d, got %d for validator with index %d", wanted, rewards[i], i)
}
@@ -134,6 +150,19 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
}
}
for _, i := range slashedAttestedIndices {
base, err := epoch.BaseReward(state, i)
if err != nil {
t.Errorf("Could not get base reward: %v", err)
}
if rewards[i] != 0 {
t.Errorf("Wanted slashed indices reward balance 0, got %d", penalties[i])
}
if penalties[i] != 3*base {
t.Errorf("Wanted slashed indices penalty balance %d, got %d", 3*base, penalties[i])
}
}
nonAttestedIndices := []uint64{434, 677, 872, 791}
for _, i := range nonAttestedIndices {
base, err := epoch.BaseReward(state, i)
@@ -190,12 +219,79 @@ func TestAttestationDeltas_ZeroEpoch(t *testing.T) {
pBal.ActiveCurrentEpoch = 0 // Could cause a divide by zero panic.
_, _, err = attestationDeltas(state, pBal, pVals)
_, _, err = AttestationsDelta(state, pBal, pVals)
if err != nil {
t.Fatal(err)
}
}
func TestProcessRewardsAndPenaltiesPrecompute_SlashedInactivePenalty(t *testing.T) {
e := params.BeaconConfig().SlotsPerEpoch
validatorCount := uint64(2048)
base := buildState(e+3, validatorCount)
atts := make([]*pb.PendingAttestation, 3)
for i := 0; i < len(atts); i++ {
atts[i] = &pb.PendingAttestation{
Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{},
Source: &ethpb.Checkpoint{},
},
AggregationBits: bitfield.Bitlist{0xC0, 0xC0, 0xC0, 0xC0, 0x01},
InclusionDelay: 1,
}
}
base.PreviousEpochAttestations = atts
state, err := state.InitializeFromProto(base)
if err != nil {
t.Fatal(err)
}
if err := state.SetSlot(params.BeaconConfig().SlotsPerEpoch * 10); err != nil {
t.Fatal(err)
}
slashedAttestedIndices := []uint64{14, 37, 68, 77, 139}
for _, i := range slashedAttestedIndices {
vs := state.Validators()
vs[i].Slashed = true
if state.SetValidators(vs) != nil {
t.Fatal(err)
}
}
vp, bp, err := New(context.Background(), state)
if err != nil {
t.Error(err)
}
vp, bp, err = ProcessAttestations(context.Background(), state, vp, bp)
if err != nil {
t.Fatal(err)
}
rewards, penalties, err := AttestationsDelta(state, bp, vp)
if err != nil {
t.Fatal(err)
}
finalityDelay := helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
for _, i := range slashedAttestedIndices {
base, err := epoch.BaseReward(state, i)
if err != nil {
t.Errorf("Could not get base reward: %v", err)
}
penalty := 3 * base
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
penalty += params.BeaconConfig().BaseRewardsPerEpoch*base - proposerReward
penalty += vp[i].CurrentEpochEffectiveBalance * finalityDelay / params.BeaconConfig().InactivityPenaltyQuotient
if penalties[i] != penalty {
t.Errorf("Wanted slashed indices penalty balance %d, got %d", penalty, penalties[i])
}
if rewards[i] != 0 {
t.Errorf("Wanted slashed indices reward balance 0, got %d", penalties[i])
}
}
}
func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
validators := make([]*ethpb.Validator, validatorCount)
for i := 0; i < len(validators); i++ {
@@ -234,3 +330,133 @@ func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
CurrentJustifiedCheckpoint: &ethpb.Checkpoint{},
}
}
func TestProposerDeltaPrecompute_HappyCase(t *testing.T) {
e := params.BeaconConfig().SlotsPerEpoch
validatorCount := uint64(10)
base := buildState(e, validatorCount)
state, err := state.InitializeFromProto(base)
if err != nil {
t.Fatal(err)
}
proposerIndex := uint64(1)
b := &Balance{ActiveCurrentEpoch: 1000}
v := []*Validator{
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex},
}
r, err := ProposersDelta(state, b, v)
if err != nil {
t.Fatal(err)
}
baseReward := v[0].CurrentEpochEffectiveBalance * params.BeaconConfig().BaseRewardFactor /
mathutil.IntegerSquareRoot(b.ActiveCurrentEpoch) / params.BeaconConfig().BaseRewardsPerEpoch
proposerReward := baseReward / params.BeaconConfig().ProposerRewardQuotient
if r[proposerIndex] != proposerReward {
t.Errorf("Wanted proposer reward %d, got %d", proposerReward, r[proposerIndex])
}
}
func TestProposerDeltaPrecompute_SlashedCase(t *testing.T) {
e := params.BeaconConfig().SlotsPerEpoch
validatorCount := uint64(10)
base := buildState(e, validatorCount)
state, err := state.InitializeFromProto(base)
if err != nil {
t.Fatal(err)
}
proposerIndex := uint64(1)
b := &Balance{ActiveCurrentEpoch: 1000}
v := []*Validator{
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex, IsSlashed: true},
}
r, err := ProposersDelta(state, b, v)
if err != nil {
t.Fatal(err)
}
if r[proposerIndex] != 0 {
t.Errorf("Wanted proposer reward for slashed %d, got %d", 0, r[proposerIndex])
}
}
func TestFinalityDelay(t *testing.T) {
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
base.FinalizedCheckpoint = &ethpb.Checkpoint{Epoch: 3}
state, err := state.InitializeFromProto(base)
if err != nil {
t.Fatal(err)
}
prevEpoch := uint64(0)
finalizedEpoch := uint64(0)
// Set values for each test case
setVal := func() {
prevEpoch = helpers.PrevEpoch(state)
finalizedEpoch = state.FinalizedCheckpointEpoch()
}
setVal()
d := finalityDelay(prevEpoch, finalizedEpoch)
w := helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
if d != w {
t.Error("Did not get wanted finality delay")
}
if err := state.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 4}); err != nil {
t.Fatal(err)
}
setVal()
d = finalityDelay(prevEpoch, finalizedEpoch)
w = helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
if d != w {
t.Error("Did not get wanted finality delay")
}
if err := state.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 5}); err != nil {
t.Fatal(err)
}
setVal()
d = finalityDelay(prevEpoch, finalizedEpoch)
w = helpers.PrevEpoch(state) - state.FinalizedCheckpointEpoch()
if d != w {
t.Error("Did not get wanted finality delay")
}
}
func TestIsInInactivityLeak(t *testing.T) {
base := buildState(params.BeaconConfig().SlotsPerEpoch*10, 1)
base.FinalizedCheckpoint = &ethpb.Checkpoint{Epoch: 3}
state, err := state.InitializeFromProto(base)
if err != nil {
t.Fatal(err)
}
prevEpoch := uint64(0)
finalizedEpoch := uint64(0)
// Set values for each test case
setVal := func() {
prevEpoch = helpers.PrevEpoch(state)
finalizedEpoch = state.FinalizedCheckpointEpoch()
}
setVal()
if !isInInactivityLeak(prevEpoch, finalizedEpoch) {
t.Error("Wanted inactivity leak true")
}
if err := state.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 4}); err != nil {
t.Fatal(err)
}
setVal()
if !isInInactivityLeak(prevEpoch, finalizedEpoch) {
t.Error("Wanted inactivity leak true")
}
if err := state.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 5}); err != nil {
t.Fatal(err)
}
setVal()
if isInInactivityLeak(prevEpoch, finalizedEpoch) {
t.Error("Wanted inactivity leak false")
}
}

View File

@@ -0,0 +1,76 @@
load("@io_bazel_rules_go//go:def.bzl", "go_test")
load("@prysm//tools/go:def.bzl", "go_library")
test_suite(
name = "go_default_test",
tags = ["spectest"],
tests = [
":go_mainnet_test",
# Minimal tests must be run with --define ssz=minimal
#":go_minimal_test",
],
)
go_test(
name = "go_mainnet_test",
size = "small",
srcs = glob(
["*_test.go"],
exclude = ["*_minimal_test.go"],
),
data = [
"@eth2_spec_tests_mainnet//:test_data",
],
shard_count = 4,
tags = [
"spectest",
],
deps = [
"//beacon-chain/core/epoch:go_default_library",
"//beacon-chain/core/epoch/precompute:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/state:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/params/spectest:go_default_library",
"//shared/params:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
"@com_github_ghodss_yaml//:go_default_library",
],
)
# Requires --define ssz=minimal
go_test(
name = "go_minimal_test",
size = "small",
srcs = glob(
["*_test.go"],
exclude = ["*_mainnet_test.go"],
),
data = [
"@eth2_spec_tests_minimal//:test_data",
],
tags = [
"manual",
"minimal",
"spectest",
],
deps = [
"//beacon-chain/core/epoch:go_default_library",
"//beacon-chain/core/epoch/precompute:go_default_library",
"//beacon-chain/core/helpers:go_default_library",
"//beacon-chain/state:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared/params/spectest:go_default_library",
"//shared/params:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
"@com_github_ghodss_yaml//:go_default_library",
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
],
)

View File

@@ -0,0 +1,9 @@
package spectest
import (
"testing"
)
func TestRewardsPenaltiesMainnet(t *testing.T) {
runPrecomputeRewardsAndPenaltiesTests(t, "mainnet")
}

View File

@@ -0,0 +1,9 @@
package spectest
import (
"testing"
)
func TestRewardsPenaltiesMinimal(t *testing.T) {
runPrecomputeRewardsAndPenaltiesTests(t, "minimal")
}

View File

@@ -0,0 +1,111 @@
package spectest
import (
"context"
"path"
"reflect"
"testing"
"github.com/ghodss/yaml"
"github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
type Delta struct {
Rewards []uint64 `json:"rewards"`
Penalties []uint64 `json:"penalties"`
}
var deltaFiles = []string{"source_deltas.yaml", "target_deltas.yaml", "head_deltas.yaml", "inactivity_penalty_deltas.yaml", "inclusion_delay_deltas.yaml"}
func runPrecomputeRewardsAndPenaltiesTests(t *testing.T, config string) {
if err := spectest.SetConfig(t, config); err != nil {
t.Fatal(err)
}
testPath := "rewards/core/pyspec_tests"
testFolders, testsFolderPath := testutil.TestFolders(t, config, testPath)
for _, folder := range testFolders {
helpers.ClearCache()
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
runPrecomputeRewardsAndPenaltiesTest(t, folderPath)
})
}
}
func runPrecomputeRewardsAndPenaltiesTest(t *testing.T, testFolderPath string) {
ctx := context.Background()
preBeaconStateFile, err := testutil.BazelFileBytes(path.Join(testFolderPath, "pre.ssz"))
if err != nil {
t.Fatal(err)
}
preBeaconStateBase := &pb.BeaconState{}
if err := ssz.Unmarshal(preBeaconStateFile, preBeaconStateBase); err != nil {
t.Fatalf("Failed to unmarshal: %v", err)
}
preBeaconState, err := beaconstate.InitializeFromProto(preBeaconStateBase)
if err != nil {
t.Fatal(err)
}
vp, bp, err := precompute.New(ctx, preBeaconState)
if err != nil {
t.Fatal(err)
}
vp, bp, err = precompute.ProcessAttestations(ctx, preBeaconState, vp, bp)
if err != nil {
t.Fatal(err)
}
rewards, penalties, err := precompute.AttestationsDelta(preBeaconState, bp, vp)
if err != nil {
t.Fatal(err)
}
pRewards, err := precompute.ProposersDelta(preBeaconState, bp, vp)
if err != nil {
t.Fatal(err)
}
if len(rewards) != len(penalties) && len(pRewards) != len(pRewards) {
t.Fatal("Incorrect lengths")
}
for i, reward := range rewards {
rewards[i] = reward + pRewards[i]
}
totalSpecTestRewards := make([]uint64, len(rewards))
totalSpecTestPenalties := make([]uint64, len(penalties))
for _, dFile := range deltaFiles {
sourceFile, err := testutil.BazelFileBytes(path.Join(testFolderPath, dFile))
if err != nil {
t.Fatal(err)
}
d := &Delta{}
err = yaml.Unmarshal(sourceFile, &d)
if err != nil {
panic(err)
}
for i, reward := range d.Rewards {
totalSpecTestRewards[i] += reward
}
for i, penalty := range d.Penalties {
totalSpecTestPenalties[i] += penalty
}
}
if !reflect.DeepEqual(rewards, totalSpecTestRewards) {
t.Error("Rewards don't match")
t.Log(rewards)
t.Log(totalSpecTestRewards)
}
if !reflect.DeepEqual(penalties, totalSpecTestPenalties) {
t.Error("Penalties don't match")
t.Log(penalties)
t.Log(totalSpecTestPenalties)
}
}

View File

@@ -0,0 +1,9 @@
package spectest
import (
"testing"
)
func TestRewardsAndPenaltiesMinimal(t *testing.T) {
runRewardsAndPenaltiesTests(t, "minimal")
}

View File

@@ -0,0 +1,48 @@
package spectest
import (
"context"
"path"
"testing"
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/precompute"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/shared/params/spectest"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
func runRewardsAndPenaltiesTests(t *testing.T, config string) {
if err := spectest.SetConfig(t, config); err != nil {
t.Fatal(err)
}
testPath := "epoch_processing/rewards_and_penalties/pyspec_tests"
testFolders, testsFolderPath := testutil.TestFolders(t, config, testPath)
for _, folder := range testFolders {
helpers.ClearCache()
t.Run(folder.Name(), func(t *testing.T) {
folderPath := path.Join(testsFolderPath, folder.Name())
testutil.RunEpochOperationTest(t, folderPath, processRewardsAndPenaltiesPrecomputeWrapper)
})
}
}
func processRewardsAndPenaltiesPrecomputeWrapper(t *testing.T, state *state.BeaconState) (*state.BeaconState, error) {
ctx := context.Background()
vp, bp, err := precompute.New(ctx, state)
if err != nil {
t.Fatal(err)
}
vp, bp, err = precompute.ProcessAttestations(ctx, state, vp, bp)
if err != nil {
t.Fatal(err)
}
state, err = precompute.ProcessRewardsAndPenaltiesPrecompute(state, bp, vp)
if err != nil {
t.Fatalf("could not process reward: %v", err)
}
return state, nil
}

View File

@@ -176,3 +176,40 @@ func AggregateSignature(attestations []*ethpb.Attestation) (*bls.Signature, erro
func IsAggregated(attestation *ethpb.Attestation) bool {
return attestation.AggregationBits.Count() > 1
}
// ComputeSubnetForAttestation returns the subnet for which the provided attestation will be broadcasted to.
// This differs from the spec definition by instead passing in the active validators indices in the attestation's
// given epoch.
//
// Spec pseudocode definition:
// def compute_subnet_for_attestation(state: BeaconState, attestation: Attestation) -> uint64:
// """
// Compute the correct subnet for an attestation for Phase 0.
// Note, this mimics expected Phase 1 behavior where attestations will be mapped to their shard subnet.
// """
// slots_since_epoch_start = attestation.data.slot % SLOTS_PER_EPOCH
// committees_since_epoch_start = get_committee_count_at_slot(state, attestation.data.slot) * slots_since_epoch_start
// return (committees_since_epoch_start + attestation.data.index) % ATTESTATION_SUBNET_COUNT
func ComputeSubnetForAttestation(activeValCount uint64, att *ethpb.Attestation) uint64 {
return ComputeSubnetFromCommitteeAndSlot(activeValCount, att.Data.CommitteeIndex, att.Data.Slot)
}
// ComputeSubnetFromCommitteeAndSlot is a flattened version of ComputeSubnetForAttestation where we only pass in
// the relevant fields from the attestation as function arguments.
//
// Spec pseudocode definition:
// def compute_subnet_for_attestation(state: BeaconState, attestation: Attestation) -> uint64:
// """
// Compute the correct subnet for an attestation for Phase 0.
// Note, this mimics expected Phase 1 behavior where attestations will be mapped to their shard subnet.
// """
// slots_since_epoch_start = attestation.data.slot % SLOTS_PER_EPOCH
// committees_since_epoch_start = get_committee_count_at_slot(state, attestation.data.slot) * slots_since_epoch_start
// return (committees_since_epoch_start + attestation.data.index) % ATTESTATION_SUBNET_COUNT
func ComputeSubnetFromCommitteeAndSlot(activeValCount, comIdx, attSlot uint64) uint64 {
slotSinceStart := SlotsSinceEpochStarts(attSlot)
comCount := SlotCommitteeCount(activeValCount)
commsSinceStart := comCount * slotSinceStart
computedSubnet := (commsSinceStart + comIdx) % params.BeaconNetworkConfig().AttestationSubnetCount
return computedSubnet
}

View File

@@ -3,6 +3,7 @@ package helpers_test
import (
"bytes"
"sort"
"strconv"
"testing"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
@@ -348,3 +349,53 @@ func TestAggregateSignature_False(t *testing.T) {
t.Error("Signature not suppose to verify")
}
}
func TestComputeSubnetForAttestation_ComputeForAttestation(t *testing.T) {
// Create 10 committees
committeeCount := uint64(10)
validatorCount := committeeCount * params.BeaconConfig().TargetCommitteeSize
validators := make([]*ethpb.Validator, validatorCount)
for i := 0; i < len(validators); i++ {
k := make([]byte, 48)
copy(k, strconv.Itoa(i))
validators[i] = &ethpb.Validator{
PublicKey: k,
WithdrawalCredentials: make([]byte, 32),
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
}
}
state, err := beaconstate.InitializeFromProto(&pb.BeaconState{
Validators: validators,
Slot: 200,
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
StateRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
})
if err != nil {
t.Fatal(err)
}
att := &ethpb.Attestation{
AggregationBits: []byte{'A'},
Data: &ethpb.AttestationData{
Slot: 34,
CommitteeIndex: 4,
BeaconBlockRoot: []byte{'C'},
Source: nil,
Target: nil,
},
Signature: []byte{'B'},
XXX_NoUnkeyedLiteral: struct{}{},
XXX_unrecognized: nil,
XXX_sizecache: 0,
}
valCount, err := helpers.ActiveValidatorCount(state, helpers.SlotToEpoch(att.Data.Slot))
if err != nil {
t.Fatal(err)
}
sub := helpers.ComputeSubnetForAttestation(valCount, att)
if sub != 6 {
t.Errorf("Did not get correct subnet for attestation, wanted %d but got %d", 6, sub)
}
}

View File

@@ -69,7 +69,21 @@ func IncreaseBalance(state *stateTrie.BeaconState, idx uint64, delta uint64) err
if err != nil {
return err
}
return state.UpdateBalancesAtIndex(idx, balAtIdx+delta)
return state.UpdateBalancesAtIndex(idx, IncreaseBalanceWithVal(balAtIdx, delta))
}
// IncreaseBalanceWithVal increases validator with the given 'index' balance by 'delta' in Gwei.
// This method is flattened version of the spec method, taking in the raw balance and returning
// the post balance.
//
// Spec pseudocode definition:
// def increase_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
// """
// Increase the validator balance at index ``index`` by ``delta``.
// """
// state.balances[index] += delta
func IncreaseBalanceWithVal(currBalance uint64, delta uint64) uint64 {
return currBalance + delta
}
// DecreaseBalance decreases validator with the given 'index' balance by 'delta' in Gwei.
@@ -85,8 +99,22 @@ func DecreaseBalance(state *stateTrie.BeaconState, idx uint64, delta uint64) err
if err != nil {
return err
}
if delta > balAtIdx {
return state.UpdateBalancesAtIndex(idx, 0)
}
return state.UpdateBalancesAtIndex(idx, balAtIdx-delta)
return state.UpdateBalancesAtIndex(idx, DecreaseBalanceWithVal(balAtIdx, delta))
}
// DecreaseBalanceWithVal decreases validator with the given 'index' balance by 'delta' in Gwei.
// This method is flattened version of the spec method, taking in the raw balance and returning
// the post balance.
//
// Spec pseudocode definition:
// def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> None:
// """
// Decrease the validator balance at index ``index`` by ``delta``, with underflow protection.
// """
// state.balances[index] = 0 if delta > state.balances[index] else state.balances[index] - delta
func DecreaseBalanceWithVal(currBalance uint64, delta uint64) uint64 {
if delta > currBalance {
return 0
}
return currBalance - delta
}

View File

@@ -22,20 +22,19 @@ const DomainByteLength = 4
// failed to verify.
var ErrSigFailedToVerify = errors.New("signature did not verify")
// ComputeSigningRoot computes the root of the object by calculating the root of the object domain tree.
// ComputeSigningRoot computes the root of the object by calculating the hash tree root of the signing data with the given domain.
//
// Spec pseudocode definition:
// def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root:
// """
// Return the signing root of an object by calculating the root of the object-domain tree.
// Return the signing root for the corresponding signing data.
// """
// domain_wrapped_object = SigningRoot(
// return hash_tree_root(SigningData(
// object_root=hash_tree_root(ssz_object),
// domain=domain,
// )
// return hash_tree_root(domain_wrapped_object)
// ))
func ComputeSigningRoot(object interface{}, domain []byte) ([32]byte, error) {
return signingRoot(func() ([32]byte, error) {
return signingData(func() ([32]byte, error) {
switch object.(type) {
case *ethpb.BeaconBlock:
return stateutil.BlockRoot(object.(*ethpb.BeaconBlock))
@@ -48,14 +47,14 @@ func ComputeSigningRoot(object interface{}, domain []byte) ([32]byte, error) {
}, domain)
}
// Computes the signing root by utilising the provided root function and then
// returning the signing root of the container object.
func signingRoot(rootFunc func() ([32]byte, error), domain []byte) ([32]byte, error) {
// Computes the signing data by utilising the provided root function and then
// returning the signing data of the container object.
func signingData(rootFunc func() ([32]byte, error), domain []byte) ([32]byte, error) {
objRoot, err := rootFunc()
if err != nil {
return [32]byte{}, err
}
container := &p2ppb.SigningRoot{
container := &p2ppb.SigningData{
ObjectRoot: objRoot[:],
Domain: domain,
}
@@ -92,7 +91,7 @@ func VerifyBlockSigningRoot(blk *ethpb.BeaconBlock, pub []byte, signature []byte
if err != nil {
return errors.Wrap(err, "could not convert bytes to signature")
}
root, err := signingRoot(func() ([32]byte, error) {
root, err := signingData(func() ([32]byte, error) {
// utilize custom block hashing function
return stateutil.BlockRoot(blk)
}, domain)
@@ -115,7 +114,7 @@ func VerifyBlockHeaderSigningRoot(blkHdr *ethpb.BeaconBlockHeader, pub []byte, s
if err != nil {
return errors.Wrap(err, "could not convert bytes to signature")
}
root, err := signingRoot(func() ([32]byte, error) {
root, err := signingData(func() ([32]byte, error) {
return stateutil.BlockHeaderRoot(blkHdr)
}, domain)
if err != nil {

View File

@@ -52,7 +52,7 @@ func TestSigningRoot_Compatibility(t *testing.T) {
if err != nil {
t.Fatal(err)
}
newRoot, err := signingRoot(func() ([32]byte, error) {
newRoot, err := signingData(func() ([32]byte, error) {
return stateutil.BlockRoot(blk)
}, params.BeaconConfig().DomainBeaconProposer[:])
if err != nil {

View File

@@ -54,7 +54,10 @@ go_test(
"transition_fuzz_test.go",
"transition_test.go",
],
data = ["//shared/benchutil/benchmark_files:benchmark_data"],
data = [
"//beacon-chain/core/state/regression_files:regression_data",
"//shared/benchutil/benchmark_files:benchmark_data",
],
embed = [":go_default_library"],
shard_count = 3,
deps = [

View File

@@ -16,7 +16,7 @@ import (
var runAmount = 25
func TestBenchmarkExecuteStateTransition(t *testing.T) {
func TestExecuteStateTransition_FullBlock(t *testing.T) {
benchutil.SetBenchmarkConfig()
beaconState, err := benchutil.PreGenState1Epoch()
if err != nil {

View File

@@ -0,0 +1,9 @@
filegroup(
name = "regression_data",
srcs = glob([
"*.ssz",
]),
visibility = [
"//beacon-chain/core/state:__pkg__",
],
)

View File

@@ -190,9 +190,9 @@ func OptimizedGenesisBeaconState(genesisTime uint64, preState *stateTrie.BeaconS
Eth1DepositIndex: preState.Eth1DepositIndex(),
}
bodyRoot, err := ssz.HashTreeRoot(&ethpb.BeaconBlockBody{})
bodyRoot, err := stateutil.BlockBodyRoot(&ethpb.BeaconBlockBody{})
if err != nil {
return nil, errors.Wrapf(err, "could not hash tree root %v", bodyRoot)
return nil, errors.Wrap(err, "could not hash tree root empty block body")
}
state.LatestBlockHeader = &ethpb.BeaconBlockHeader{

View File

@@ -92,9 +92,18 @@ func TestExecuteStateTransition_FullProcess(t *testing.T) {
if err := beaconState.SetSlot(beaconState.Slot() - 1); err != nil {
t.Fatal(err)
}
nextSlotState := beaconState.Copy()
if err := nextSlotState.SetSlot(beaconState.Slot() + 1); err != nil {
t.Fatal(err)
}
proposerIdx, err := helpers.BeaconProposerIndex(nextSlotState)
if err != nil {
t.Error(err)
}
block := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ProposerIndex: 74,
ProposerIndex: proposerIdx,
Slot: beaconState.Slot() + 1,
ParentRoot: parentRoot[:],
Body: &ethpb.BeaconBlockBody{
@@ -371,7 +380,7 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
proposerSlashIdx := uint64(3)
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
err = beaconState.SetSlot((params.BeaconConfig().PersistentCommitteePeriod * slotsPerEpoch) + params.BeaconConfig().MinAttestationInclusionDelay)
err = beaconState.SetSlot((params.BeaconConfig().ShardCommitteePeriod * slotsPerEpoch) + params.BeaconConfig().MinAttestationInclusionDelay)
if err != nil {
t.Fatal(err)
}
@@ -754,7 +763,7 @@ func BenchmarkProcessBlk_65536Validators_FullBlock(b *testing.B) {
if err != nil {
b.Fatal(err)
}
ctr := &pb.SigningRoot{
ctr := &pb.SigningData{
ObjectRoot: buf,
Domain: domain,
}
@@ -902,9 +911,17 @@ func TestProcessBlk_AttsBasedOnValidatorCount(t *testing.T) {
t.Fatal(err)
}
nextSlotState := s.Copy()
if err := nextSlotState.SetSlot(s.Slot() + 1); err != nil {
t.Fatal(err)
}
proposerIdx, err := helpers.BeaconProposerIndex(nextSlotState)
if err != nil {
t.Error(err)
}
blk := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ProposerIndex: 156,
ProposerIndex: proposerIdx,
Slot: s.Slot() + 1,
ParentRoot: parentRoot[:],
Body: &ethpb.BeaconBlockBody{

View File

@@ -2,7 +2,6 @@ package kv
import (
"context"
"reflect"
"sort"
"testing"
@@ -10,7 +9,9 @@ import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
func TestStore_SaveBlock_NoDuplicates(t *testing.T) {
@@ -22,7 +23,7 @@ func TestStore_SaveBlock_NoDuplicates(t *testing.T) {
prevBlock := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: slot - 1,
ParentRoot: []byte{1, 2, 3},
ParentRoot: bytesutil.PadTo([]byte{1, 2, 3}, 32),
},
}
if err := db.SaveBlock(ctx, prevBlock); err != nil {
@@ -31,7 +32,7 @@ func TestStore_SaveBlock_NoDuplicates(t *testing.T) {
block := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: slot,
ParentRoot: []byte{1, 2, 3},
ParentRoot: bytesutil.PadTo([]byte{1, 2, 3}, 32),
},
}
// Even with a full cache, saving new blocks should not cause
@@ -59,7 +60,7 @@ func TestStore_BlocksCRUD(t *testing.T) {
block := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: 20,
ParentRoot: []byte{1, 2, 3},
ParentRoot: bytesutil.PadTo([]byte{1, 2, 3}, 32),
},
}
blockRoot, err := stateutil.BlockRoot(block.Block)
@@ -97,18 +98,15 @@ func TestStore_BlocksCRUD(t *testing.T) {
func TestStore_BlocksBatchDelete(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
numBlocks := 1000
numBlocks := 10
totalBlocks := make([]*ethpb.SignedBeaconBlock, numBlocks)
blockRoots := make([][32]byte, 0)
oddBlocks := make([]*ethpb.SignedBeaconBlock, 0)
for i := 0; i < len(totalBlocks); i++ {
totalBlocks[i] = &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: uint64(i),
ParentRoot: []byte("parent"),
},
}
b := testutil.NewBeaconBlock()
b.Block.Slot = uint64(i)
b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
totalBlocks[i] = b
if i%2 == 0 {
r, err := stateutil.BlockRoot(totalBlocks[i].Block)
if err != nil {
@@ -122,7 +120,7 @@ func TestStore_BlocksBatchDelete(t *testing.T) {
if err := db.SaveBlocks(ctx, totalBlocks); err != nil {
t.Fatal(err)
}
retrieved, err := db.Blocks(ctx, filters.NewFilter().SetParentRoot([]byte("parent")))
retrieved, err := db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32)))
if err != nil {
t.Fatal(err)
}
@@ -134,27 +132,25 @@ func TestStore_BlocksBatchDelete(t *testing.T) {
t.Fatal(err)
}
// When we retrieve the data, only the odd indexed blocks should remain.
retrieved, err = db.Blocks(ctx, filters.NewFilter().SetParentRoot([]byte("parent")))
retrieved, err = db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32)))
if err != nil {
t.Fatal(err)
}
sort.Slice(retrieved, func(i, j int) bool {
return retrieved[i].Block.Slot < retrieved[j].Block.Slot
})
if !reflect.DeepEqual(retrieved, oddBlocks) {
t.Errorf("Wanted %v, received %v", oddBlocks, retrieved)
for i, block := range retrieved {
if !proto.Equal(block, oddBlocks[i]) {
t.Errorf("Wanted %v, received %v", oddBlocks[i], block)
}
}
}
func TestStore_GenesisBlock(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
genesisBlock := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: 0,
ParentRoot: []byte{1, 2, 3},
},
}
genesisBlock := testutil.NewBeaconBlock()
genesisBlock.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32)
blockRoot, err := stateutil.BlockRoot(genesisBlock.Block)
if err != nil {
t.Fatal(err)
@@ -177,12 +173,9 @@ func TestStore_GenesisBlock(t *testing.T) {
func TestStore_BlocksCRUD_NoCache(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
block := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: 20,
ParentRoot: []byte{1, 2, 3},
},
}
block := testutil.NewBeaconBlock()
block.Block.Slot = 20
block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32)
blockRoot, err := stateutil.BlockRoot(block.Block)
if err != nil {
t.Fatal(err)
@@ -218,38 +211,22 @@ func TestStore_BlocksCRUD_NoCache(t *testing.T) {
func TestStore_Blocks_FiltersCorrectly(t *testing.T) {
db := setupDB(t)
blocks := []*ethpb.SignedBeaconBlock{
{
Block: &ethpb.BeaconBlock{
Slot: 4,
ParentRoot: []byte("parent"),
},
},
{
Block: &ethpb.BeaconBlock{
Slot: 5,
ParentRoot: []byte("parent2"),
},
},
{
Block: &ethpb.BeaconBlock{
Slot: 6,
ParentRoot: []byte("parent2"),
},
},
{
Block: &ethpb.BeaconBlock{
Slot: 7,
ParentRoot: []byte("parent3"),
},
},
{
Block: &ethpb.BeaconBlock{
Slot: 8,
ParentRoot: []byte("parent4"),
},
},
}
b4 := testutil.NewBeaconBlock()
b4.Block.Slot = 4
b4.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
b5 := testutil.NewBeaconBlock()
b5.Block.Slot = 5
b5.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32)
b6 := testutil.NewBeaconBlock()
b6.Block.Slot = 6
b6.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32)
b7 := testutil.NewBeaconBlock()
b7.Block.Slot = 7
b7.Block.ParentRoot = bytesutil.PadTo([]byte("parent3"), 32)
b8 := testutil.NewBeaconBlock()
b8.Block.Slot = 8
b8.Block.ParentRoot = bytesutil.PadTo([]byte("parent4"), 32)
blocks := []*ethpb.SignedBeaconBlock{b4, b5, b6, b7, b8}
ctx := context.Background()
if err := db.SaveBlocks(ctx, blocks); err != nil {
t.Fatal(err)
@@ -260,12 +237,12 @@ func TestStore_Blocks_FiltersCorrectly(t *testing.T) {
expectedNumBlocks int
}{
{
filter: filters.NewFilter().SetParentRoot([]byte("parent2")),
filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)),
expectedNumBlocks: 2,
},
{
// No block meets the criteria below.
filter: filters.NewFilter().SetParentRoot([]byte{3, 4, 5}),
filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte{3, 4, 5}, 32)),
expectedNumBlocks: 0,
},
{
@@ -304,7 +281,7 @@ func TestStore_Blocks_FiltersCorrectly(t *testing.T) {
{
// Composite filter criteria.
filter: filters.NewFilter().
SetParentRoot([]byte("parent2")).
SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)).
SetStartSlot(6).
SetEndSlot(8),
expectedNumBlocks: 1,
@@ -323,17 +300,15 @@ func TestStore_Blocks_FiltersCorrectly(t *testing.T) {
func TestStore_Blocks_Retrieve_SlotRange(t *testing.T) {
db := setupDB(t)
b := make([]*ethpb.SignedBeaconBlock, 500)
totalBlocks := make([]*ethpb.SignedBeaconBlock, 500)
for i := 0; i < 500; i++ {
b[i] = &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ParentRoot: []byte("parent"),
Slot: uint64(i),
},
}
b := testutil.NewBeaconBlock()
b.Block.Slot = uint64(i)
b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
totalBlocks[i] = b
}
ctx := context.Background()
if err := db.SaveBlocks(ctx, b); err != nil {
if err := db.SaveBlocks(ctx, totalBlocks); err != nil {
t.Fatal(err)
}
retrieved, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399))
@@ -349,17 +324,15 @@ func TestStore_Blocks_Retrieve_SlotRange(t *testing.T) {
func TestStore_Blocks_Retrieve_Epoch(t *testing.T) {
db := setupDB(t)
slots := params.BeaconConfig().SlotsPerEpoch * 7
b := make([]*ethpb.SignedBeaconBlock, slots)
totalBlocks := make([]*ethpb.SignedBeaconBlock, slots)
for i := uint64(0); i < slots; i++ {
b[i] = &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ParentRoot: []byte("parent"),
Slot: i,
},
}
b := testutil.NewBeaconBlock()
b.Block.Slot = uint64(i)
b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
totalBlocks[i] = b
}
ctx := context.Background()
if err := db.SaveBlocks(ctx, b); err != nil {
if err := db.SaveBlocks(ctx, totalBlocks); err != nil {
t.Fatal(err)
}
retrieved, err := db.Blocks(ctx, filters.NewFilter().SetStartEpoch(5).SetEndEpoch(6))
@@ -382,18 +355,16 @@ func TestStore_Blocks_Retrieve_Epoch(t *testing.T) {
func TestStore_Blocks_Retrieve_SlotRangeWithStep(t *testing.T) {
db := setupDB(t)
b := make([]*ethpb.SignedBeaconBlock, 500)
totalBlocks := make([]*ethpb.SignedBeaconBlock, 500)
for i := 0; i < 500; i++ {
b[i] = &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ParentRoot: []byte("parent"),
Slot: uint64(i),
},
}
b := testutil.NewBeaconBlock()
b.Block.Slot = uint64(i)
b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
totalBlocks[i] = b
}
const step = 2
ctx := context.Background()
if err := db.SaveBlocks(ctx, b); err != nil {
if err := db.SaveBlocks(ctx, totalBlocks); err != nil {
t.Fatal(err)
}
retrieved, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399).SetSlotStep(step))
@@ -415,7 +386,8 @@ func TestStore_SaveBlock_CanGetHighest(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
block := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 1}}
block := testutil.NewBeaconBlock()
block.Block.Slot = 1
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatal(err)
}
@@ -427,7 +399,7 @@ func TestStore_SaveBlock_CanGetHighest(t *testing.T) {
t.Errorf("Wanted %v, received %v", block, highestSavedBlock)
}
block = &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 999}}
block.Block.Slot = 999
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatal(err)
}
@@ -439,7 +411,7 @@ func TestStore_SaveBlock_CanGetHighest(t *testing.T) {
t.Errorf("Wanted %v, received %v", block, highestSavedBlock)
}
block = &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 300000000}} // 100 years.
block.Block.Slot = 300000000
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatal(err)
}
@@ -456,15 +428,18 @@ func TestStore_SaveBlock_CanGetHighestAt(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
block1 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 1}}
block1 := testutil.NewBeaconBlock()
block1.Block.Slot = 1
if err := db.SaveBlock(ctx, block1); err != nil {
t.Fatal(err)
}
block2 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 10}}
block2 := testutil.NewBeaconBlock()
block2.Block.Slot = 10
if err := db.SaveBlock(ctx, block2); err != nil {
t.Fatal(err)
}
block3 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 100}}
block3 := testutil.NewBeaconBlock()
block3.Block.Slot = 100
if err := db.SaveBlock(ctx, block3); err != nil {
t.Fatal(err)
}
@@ -512,7 +487,7 @@ func TestStore_GenesisBlock_CanGetHighestAt(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
genesisBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{}}
genesisBlock := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(genesisBlock.Block)
if err != nil {
t.Fatal(err)
@@ -523,7 +498,8 @@ func TestStore_GenesisBlock_CanGetHighestAt(t *testing.T) {
if err := db.SaveBlock(ctx, genesisBlock); err != nil {
t.Fatal(err)
}
block1 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 1}}
block1 := testutil.NewBeaconBlock()
block1.Block.Slot = 1
if err := db.SaveBlock(ctx, block1); err != nil {
t.Fatal(err)
}
@@ -555,25 +531,23 @@ func TestStore_SaveBlocks_CanGetHighest(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
b := make([]*ethpb.SignedBeaconBlock, 500)
totalBlocks := make([]*ethpb.SignedBeaconBlock, 500)
for i := 0; i < 500; i++ {
b[i] = &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ParentRoot: []byte("parent"),
Slot: uint64(i),
},
}
b := testutil.NewBeaconBlock()
b.Block.Slot = uint64(i)
b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
totalBlocks[i] = b
}
if err := db.SaveBlocks(ctx, b); err != nil {
if err := db.SaveBlocks(ctx, totalBlocks); err != nil {
t.Fatal(err)
}
highestSavedBlock, err := db.HighestSlotBlocks(ctx)
if err != nil {
t.Fatal(err)
}
if !proto.Equal(b[len(b)-1], highestSavedBlock[0]) {
t.Errorf("Wanted %v, received %v", b[len(b)-1], highestSavedBlock)
if !proto.Equal(totalBlocks[len(totalBlocks)-1], highestSavedBlock[0]) {
t.Errorf("Wanted %v, received %v", totalBlocks[len(totalBlocks)-1], highestSavedBlock)
}
}
@@ -585,7 +559,7 @@ func TestStore_SaveBlocks_HasCachedBlocks(t *testing.T) {
for i := 0; i < 500; i++ {
b[i] = &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ParentRoot: []byte("parent"),
ParentRoot: bytesutil.PadTo([]byte("parent"), 32),
Slot: uint64(i),
},
}
@@ -613,7 +587,8 @@ func TestStore_DeleteBlock_CanGetHighest(t *testing.T) {
db := setupDB(t)
ctx := context.Background()
b50 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 50}}
b50 := testutil.NewBeaconBlock()
b50.Block.Slot = 50
if err := db.SaveBlock(ctx, b50); err != nil {
t.Fatal(err)
}
@@ -625,7 +600,8 @@ func TestStore_DeleteBlock_CanGetHighest(t *testing.T) {
t.Errorf("Wanted %v, received %v", b50, highestSavedBlock)
}
b51 := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 51}}
b51 := testutil.NewBeaconBlock()
b51.Block.Slot = 51
r51, err := stateutil.BlockRoot(b51.Block)
if err != nil {
t.Fatal(err)
@@ -659,22 +635,20 @@ func TestStore_DeleteBlocks_CanGetHighest(t *testing.T) {
ctx := context.Background()
var err error
b := make([]*ethpb.SignedBeaconBlock, 100)
totalBlocks := make([]*ethpb.SignedBeaconBlock, 100)
r := make([][32]byte, 100)
for i := 0; i < 100; i++ {
b[i] = &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ParentRoot: []byte("parent"),
Slot: uint64(i),
},
}
r[i], err = stateutil.BlockRoot(b[i].Block)
b := testutil.NewBeaconBlock()
b.Block.Slot = uint64(i)
b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
totalBlocks[i] = b
r[i], err = stateutil.BlockRoot(totalBlocks[i].Block)
if err != nil {
t.Error(err)
}
}
if err := db.SaveBlocks(ctx, b); err != nil {
if err := db.SaveBlocks(ctx, totalBlocks); err != nil {
t.Fatal(err)
}
if err := db.DeleteBlocks(ctx, [][32]byte{r[99], r[98], r[97]}); err != nil {
@@ -684,7 +658,7 @@ func TestStore_DeleteBlocks_CanGetHighest(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if !proto.Equal(b[96], highestSavedBlock[0]) {
t.Errorf("Wanted %v, received %v", b[len(b)-1], highestSavedBlock)
if !proto.Equal(totalBlocks[96], highestSavedBlock[0]) {
t.Errorf("Wanted %v, received %v", totalBlocks[len(totalBlocks)-1], highestSavedBlock)
}
}

View File

@@ -47,6 +47,10 @@ func isSSZStorageFormat(obj interface{}) bool {
switch obj.(type) {
case *pb.BeaconState:
return true
case *ethpb.SignedBeaconBlock:
return true
case *ethpb.SignedAggregateAttestationAndProof:
return true
case *ethpb.BeaconBlock:
return true
case *ethpb.Attestation:

View File

@@ -132,12 +132,9 @@ func TestStore_StatesBatchDelete(t *testing.T) {
blockRoots := make([][32]byte, 0)
evenBlockRoots := make([][32]byte, 0)
for i := 0; i < len(totalBlocks); i++ {
totalBlocks[i] = &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: uint64(i),
ParentRoot: []byte("parent"),
},
}
b := testutil.NewBeaconBlock()
b.Block.Slot = uint64(i)
totalBlocks[i] = b
r, err := stateutil.BlockRoot(totalBlocks[i].Block)
if err != nil {
t.Fatal(err)

View File

@@ -17,13 +17,13 @@ var (
DepositContractFlag = &cli.StringFlag{
Name: "deposit-contract",
Usage: "Deposit contract address. Beacon chain node will listen logs coming from the deposit contract to determine when validator is eligible to participate.",
Value: "0x5cA1e00004366Ac85f492887AAab12d0e6418876",
Value: "0x0F0F0fc0530007361933EaB5DB97d09aCDD6C1c8",
}
// RPCHost defines the host on which the RPC server should listen.
RPCHost = &cli.StringFlag{
Name: "rpc-host",
Usage: "Host on which the RPC server should listen",
Value: "0.0.0.0",
Value: "127.0.0.1",
}
// RPCPort defines a beacon node RPC port to open.
RPCPort = &cli.IntFlag{
@@ -82,7 +82,7 @@ var (
ContractDeploymentBlock = &cli.IntFlag{
Name: "contract-deployment-block",
Usage: "The eth1 block in which the deposit contract was deployed.",
Value: 2523557,
Value: 2844925,
}
// SetGCPercent is the percentage of current live allocations at which the garbage collector is to run.
SetGCPercent = &cli.IntFlag{

View File

@@ -40,7 +40,7 @@ func main() {
gw := gateway.New(
context.Background(),
*beaconRPC,
fmt.Sprintf("0.0.0.0:%d", *port),
fmt.Sprintf("127.0.0.1:%d", *port),
mux,
strings.Split(*allowedOrigins, ","),
*enableDebugRPCEndpoints,

View File

@@ -599,7 +599,7 @@ func (b *BeaconNode) registerGRPCGateway() error {
}
gatewayPort := b.cliCtx.Int(flags.GRPCGatewayPort.Name)
selfAddress := fmt.Sprintf("127.0.0.1:%d", b.cliCtx.Int(flags.RPCPort.Name))
gatewayAddress := fmt.Sprintf("0.0.0.0:%d", gatewayPort)
gatewayAddress := fmt.Sprintf("127.0.0.1:%d", gatewayPort)
allowedOrigins := strings.Split(b.cliCtx.String(flags.GPRCGatewayCorsDomain.Name), ",")
enableDebugRPCEndpoints := b.cliCtx.Bool(flags.EnableDebugRPCEndpoints.Name)
return b.services.RegisterService(

View File

@@ -528,9 +528,6 @@ func TestPool_PendingAttesterSlashings(t *testing.T) {
pending []*PendingAttesterSlashing
}
params.SetupTestConfigCleanup(t)
conf := params.BeaconConfig()
conf.MaxAttesterSlashings = 1
params.OverrideBeaconConfig(conf)
beaconState, privKeys := testutil.DeterministicGenesisState(t, 64)
pendingSlashings := make([]*PendingAttesterSlashing, 20)
slashings := make([]*ethpb.AttesterSlashing, 20)
@@ -562,14 +559,14 @@ func TestPool_PendingAttesterSlashings(t *testing.T) {
fields: fields{
pending: pendingSlashings,
},
want: slashings[0:1],
want: slashings[0:2],
},
{
name: "Multiple indices",
fields: fields{
pending: pendingSlashings[3:6],
},
want: slashings[3:4],
want: slashings[3:5],
},
}
for _, tt := range tests {

View File

@@ -18,33 +18,49 @@ import (
// GossipTypeMapping.
var ErrMessageNotMapped = errors.New("message type is not mapped to a PubSub topic")
const attestationSubnetTopicFormat = "/eth2/%x/beacon_attestation_%d"
// Broadcast a message to the p2p network.
func (s *Service) Broadcast(ctx context.Context, msg proto.Message) error {
ctx, span := trace.StartSpan(ctx, "p2p.Broadcast")
defer span.End()
forkDigest, err := s.forkDigest()
if err != nil {
err := errors.Wrap(err, "could not retrieve fork digest")
traceutil.AnnotateError(span, err)
return err
}
var topic string
switch msg.(type) {
case *eth.Attestation:
topic = attestationToTopic(msg.(*eth.Attestation), forkDigest)
default:
var ok bool
topic, ok = GossipTypeMapping[reflect.TypeOf(msg)]
if !ok {
traceutil.AnnotateError(span, ErrMessageNotMapped)
return ErrMessageNotMapped
}
topic = fmt.Sprintf(topic, forkDigest)
topic, ok := GossipTypeMapping[reflect.TypeOf(msg)]
if !ok {
traceutil.AnnotateError(span, ErrMessageNotMapped)
return ErrMessageNotMapped
}
return s.broadcastObject(ctx, msg, fmt.Sprintf(topic, forkDigest))
}
// BroadcastAttestation broadcasts an attestation to the p2p network.
func (s *Service) BroadcastAttestation(ctx context.Context, subnet uint64, att *eth.Attestation) error {
ctx, span := trace.StartSpan(ctx, "p2p.BroadcastAttestation")
defer span.End()
forkDigest, err := s.forkDigest()
if err != nil {
err := errors.Wrap(err, "could not retrieve fork digest")
traceutil.AnnotateError(span, err)
return err
}
return s.broadcastObject(ctx, att, attestationToTopic(subnet, forkDigest))
}
// method to broadcast messages to other peers in our gossip mesh.
func (s *Service) broadcastObject(ctx context.Context, obj interface{}, topic string) error {
_, span := trace.StartSpan(ctx, "p2p.broadcastObject")
defer span.End()
span.AddAttributes(trace.StringAttribute("topic", topic))
buf := new(bytes.Buffer)
if _, err := s.Encoding().EncodeGossip(buf, msg); err != nil {
if _, err := s.Encoding().EncodeGossip(buf, obj); err != nil {
err := errors.Wrap(err, "could not encode message")
traceutil.AnnotateError(span, err)
return err
@@ -64,11 +80,6 @@ func (s *Service) Broadcast(ctx context.Context, msg proto.Message) error {
return nil
}
const attestationSubnetTopicFormat = "/eth2/%x/committee_index%d_beacon_attestation"
func attestationToTopic(att *eth.Attestation, forkDigest [4]byte) string {
if att == nil || att.Data == nil {
return ""
}
return fmt.Sprintf(attestationSubnetTopicFormat, forkDigest, att.Data.CommitteeIndex)
func attestationToTopic(subnet uint64, forkDigest [4]byte) string {
return fmt.Sprintf(attestationSubnetTopicFormat, forkDigest, subnet)
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/gogo/protobuf/proto"
eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
testpb "github.com/prysmaticlabs/prysm/proto/testing"
"github.com/prysmaticlabs/prysm/shared/testutil"
@@ -109,36 +110,33 @@ func TestService_Attestation_Subnet(t *testing.T) {
att: &eth.Attestation{
Data: &eth.AttestationData{
CommitteeIndex: 0,
Slot: 2,
},
},
topic: "/eth2/00000000/committee_index0_beacon_attestation",
topic: "/eth2/00000000/beacon_attestation_2",
},
{
att: &eth.Attestation{
Data: &eth.AttestationData{
CommitteeIndex: 11,
Slot: 10,
},
},
topic: "/eth2/00000000/committee_index11_beacon_attestation",
topic: "/eth2/00000000/beacon_attestation_21",
},
{
att: &eth.Attestation{
Data: &eth.AttestationData{
CommitteeIndex: 55,
Slot: 529,
},
},
topic: "/eth2/00000000/committee_index55_beacon_attestation",
},
{
att: &eth.Attestation{},
topic: "",
},
{
topic: "",
topic: "/eth2/00000000/beacon_attestation_8",
},
}
for _, tt := range tests {
if res := attestationToTopic(tt.att, [4]byte{} /* fork digest */); res != tt.topic {
subnet := helpers.ComputeSubnetFromCommitteeAndSlot(100, tt.att.Data.CommitteeIndex, tt.att.Data.Slot)
if res := attestationToTopic(subnet, [4]byte{} /* fork digest */); res != tt.topic {
t.Errorf("Wrong topic, got %s wanted %s", res, tt.topic)
}
}

View File

@@ -10,12 +10,12 @@ import (
// GossipTopicMappings represent the protocol ID to protobuf message type map for easy
// lookup.
var GossipTopicMappings = map[string]proto.Message{
"/eth2/%x/beacon_block": &pb.SignedBeaconBlock{},
"/eth2/%x/committee_index%d_beacon_attestation": &pb.Attestation{},
"/eth2/%x/voluntary_exit": &pb.SignedVoluntaryExit{},
"/eth2/%x/proposer_slashing": &pb.ProposerSlashing{},
"/eth2/%x/attester_slashing": &pb.AttesterSlashing{},
"/eth2/%x/beacon_aggregate_and_proof": &pb.SignedAggregateAttestationAndProof{},
"/eth2/%x/beacon_block": &pb.SignedBeaconBlock{},
"/eth2/%x/beacon_attestation_%d": &pb.Attestation{},
"/eth2/%x/voluntary_exit": &pb.SignedVoluntaryExit{},
"/eth2/%x/proposer_slashing": &pb.ProposerSlashing{},
"/eth2/%x/attester_slashing": &pb.AttesterSlashing{},
"/eth2/%x/beacon_aggregate_and_proof": &pb.SignedAggregateAttestationAndProof{},
}
// GossipTypeMapping is the inverse of GossipTopicMappings so that an arbitrary protobuf message

View File

@@ -7,6 +7,7 @@ import (
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
pubsub "github.com/libp2p/go-libp2p-pubsub"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/encoder"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
@@ -28,6 +29,7 @@ type P2P interface {
// Broadcaster broadcasts messages to peers over the p2p pubsub protocol.
type Broadcaster interface {
Broadcast(context.Context, proto.Message) error
BroadcastAttestation(ctx context.Context, subnet uint64, att *ethpb.Attestation) error
}
// SetStreamHandler configures p2p to handle streams of a certain topic ID.

View File

@@ -37,6 +37,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/runutil"
"github.com/prysmaticlabs/prysm/shared/slotutil"
)
@@ -136,7 +137,7 @@ func NewService(cfg *Config) (*Service, error) {
return nil, err
}
if len(cfg.KademliaBootStrapAddr) != 0 && !cfg.NoDiscovery {
if len(cfg.KademliaBootStrapAddr) != 0 && !cfg.NoDiscovery && featureconfig.Get().EnableKadDHT {
dopts := []dhtopts.Option{
dhtopts.Datastore(dsync.MutexWrap(ds.NewMapDatastore())),
dhtopts.Protocols(
@@ -235,7 +236,7 @@ func (s *Service) Start() {
go s.listenForNewNodes()
}
if len(s.cfg.KademliaBootStrapAddr) != 0 && !s.cfg.NoDiscovery {
if len(s.cfg.KademliaBootStrapAddr) != 0 && !s.cfg.NoDiscovery && featureconfig.Get().EnableKadDHT {
for _, addr := range s.cfg.KademliaBootStrapAddr {
peersToWatch = append(peersToWatch, addr)
err := startDHTDiscovery(s.host, addr)
@@ -390,7 +391,7 @@ func (s *Service) RefreshENR() {
return
}
bitV := bitfield.NewBitvector64()
committees := cache.CommitteeIDs.GetAllCommittees()
committees := cache.SubnetIDs.GetAllSubnets()
for _, idx := range committees {
bitV.SetBitAt(idx, true)
}

View File

@@ -124,7 +124,7 @@ func TestStartDiscV5_DiscoverPeersWithSubnets(t *testing.T) {
dv5Listener: listeners[0],
metaData: &pb.MetaData{},
}
cache.CommitteeIDs.AddAttesterCommiteeID(0, 10)
cache.SubnetIDs.AddAttesterSubnetID(0, 10)
testService.RefreshENR()
time.Sleep(2 * time.Second)

View File

@@ -26,6 +26,7 @@ go_library(
"@com_github_libp2p_go_libp2p_pubsub//:go_default_library",
"@com_github_libp2p_go_libp2p_swarm//testing:go_default_library",
"@com_github_multiformats_go_multiaddr//:go_default_library",
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
)

View File

@@ -4,6 +4,7 @@ import (
"context"
"github.com/gogo/protobuf/proto"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
)
// MockBroadcaster implements p2p.Broadcaster for testing.
@@ -16,3 +17,9 @@ func (m *MockBroadcaster) Broadcast(context.Context, proto.Message) error {
m.BroadcastCalled = true
return nil
}
// BroadcastAttestation records a broadcast occurred.
func (m *MockBroadcaster) BroadcastAttestation(ctx context.Context, subnet uint64, att *ethpb.Attestation) error {
m.BroadcastCalled = true
return nil
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/libp2p/go-libp2p-core/protocol"
pubsub "github.com/libp2p/go-libp2p-pubsub"
swarmt "github.com/libp2p/go-libp2p-swarm/testing"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/encoder"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
@@ -133,6 +134,12 @@ func (p *TestP2P) Broadcast(ctx context.Context, msg proto.Message) error {
return nil
}
// BroadcastAttestation broadcasts an attestation.
func (p *TestP2P) BroadcastAttestation(ctx context.Context, subnet uint64, att *ethpb.Attestation) error {
p.BroadcastCalled = true
return nil
}
// SetStreamHandler for RPC.
func (p *TestP2P) SetStreamHandler(topic string, handler network.StreamHandler) {
p.Host.SetStreamHandler(protocol.ID(topic), handler)

View File

@@ -24,7 +24,6 @@ import (
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/sirupsen/logrus"
)
@@ -246,12 +245,9 @@ func (s *Service) ProcessChainStart(genesisTime uint64, eth1BlockHash [32]byte,
}
func (s *Service) createGenesisTime(timeStamp uint64) uint64 {
if featureconfig.Get().CustomGenesisDelay == 0 {
return timeStamp
}
timeStampRdDown := timeStamp - timeStamp%featureconfig.Get().CustomGenesisDelay
// genesisTime will be set to the first second of the day, two days after it was triggered.
return timeStampRdDown + 2*featureconfig.Get().CustomGenesisDelay
// adds in the genesis delay to the eth1 block time
// on which it was triggered.
return timeStamp + featureconfig.Get().CustomGenesisDelay
}
// processPastLogs processes all the past logs from the deposit contract and
@@ -284,15 +280,19 @@ func (s *Service) processPastLogs(ctx context.Context) error {
}
return nil
}
for currentBlockNum < s.LatestBlockHeight().Uint64() {
latestFollowHeight, err := s.followBlockHeight(ctx)
if err != nil {
return err
}
for currentBlockNum < latestFollowHeight {
// stop requesting, if we have all the logs
if logCount == uint64(s.lastReceivedMerkleIndex+1) {
break
}
start := currentBlockNum
end := currentBlockNum + eth1HeaderReqLimit
if end > s.LatestBlockHeight().Uint64() {
end = s.LatestBlockHeight().Uint64()
if end > latestFollowHeight {
end = latestFollowHeight
}
query := ethereum.FilterQuery{
Addresses: []common.Address{
@@ -303,9 +303,9 @@ func (s *Service) processPastLogs(ctx context.Context) error {
}
remainingLogs := logCount - uint64(s.lastReceivedMerkleIndex+1)
// only change the end block if the remaining logs are below the required log limit.
if remainingLogs < depositlogRequestLimit && end >= s.LatestBlockHeight().Uint64() {
query.ToBlock = s.LatestBlockHeight()
end = s.LatestBlockHeight().Uint64()
if remainingLogs < depositlogRequestLimit && end >= latestFollowHeight {
query.ToBlock = big.NewInt(int64(latestFollowHeight))
end = latestFollowHeight
}
logs, err := s.httpLogger.FilterLogs(ctx, query)
if err != nil {
@@ -355,7 +355,10 @@ func (s *Service) requestBatchedLogs(ctx context.Context) error {
// We request for the nth block behind the current head, in order to have
// stabilized logs when we retrieve it from the 1.0 chain.
requestedBlock := s.latestEth1Data.BlockHeight - uint64(params.BeaconConfig().LogBlockDelay)
requestedBlock, err := s.followBlockHeight(ctx)
if err != nil {
return err
}
for i := s.latestEth1Data.LastRequestedBlock + 1; i <= requestedBlock; i++ {
err := s.ProcessETH1Block(ctx, big.NewInt(int64(i)))
if err != nil {

View File

@@ -488,18 +488,18 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
}
web3Service.rpcClient = &mockPOW.RPCClient{Backend: testAcc.Backend}
web3Service.httpLogger = testAcc.Backend
web3Service.blockFetcher = &goodFetcher{backend: testAcc.Backend}
web3Service.latestEth1Data.LastRequestedBlock = 0
web3Service.latestEth1Data.BlockHeight = 0
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
params.SetupTestConfigCleanup(t)
bConfig := params.MinimalSpecConfig()
bConfig.MinGenesisTime = 0
bConfig.SecondsPerETH1Block = 10
params.OverrideBeaconConfig(bConfig)
flags.Get().DeploymentBlock = 0
testAcc.Backend.Commit()
if err := testAcc.Backend.AdjustTime(time.Duration(int64(time.Now().Nanosecond()))); err != nil {
t.Fatal(err)
}
totalNumOfDeposits := depositsReqForChainStart + 30
@@ -529,7 +529,12 @@ func TestProcessETH2GenesisLog_CorrectNumOfDeposits(t *testing.T) {
testAcc.Backend.Commit()
}
}
// Forward the chain to account for the follow distance
for i := uint64(0); i < params.BeaconConfig().Eth1FollowDistance; i++ {
testAcc.Backend.Commit()
}
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
// Set up our subscriber now to listen for the chain started event.
stateChannel := make(chan *feed.Event, 1)
@@ -726,7 +731,7 @@ func TestConsistentGenesisState(t *testing.T) {
testAcc.Backend.Commit()
}
for i := 0; i < int(params.BeaconConfig().LogBlockDelay); i++ {
for i := 0; i < int(params.BeaconConfig().Eth1FollowDistance); i++ {
testAcc.Backend.Commit()
}

View File

@@ -317,6 +317,32 @@ func (s *Service) AreAllDepositsProcessed() (bool, error) {
return true, nil
}
// refers to the latest eth1 block which follows the condition: eth1_timestamp +
// SECONDS_PER_ETH1_BLOCK * ETH1_FOLLOW_DISTANCE <= current_unix_time
func (s *Service) followBlockHeight(ctx context.Context) (uint64, error) {
latestValidBlock := uint64(0)
if s.latestEth1Data.BlockHeight > params.BeaconConfig().Eth1FollowDistance {
latestValidBlock = s.latestEth1Data.BlockHeight - params.BeaconConfig().Eth1FollowDistance
}
blockTime, err := s.BlockTimeByHeight(ctx, big.NewInt(int64(latestValidBlock)))
if err != nil {
return 0, err
}
followTime := func(t uint64) uint64 {
return t + params.BeaconConfig().Eth1FollowDistance*params.BeaconConfig().SecondsPerETH1Block
}
for followTime(blockTime) > s.latestEth1Data.BlockTime && latestValidBlock > 0 {
// reduce block height to get eth1 block which
// fulfills stated condition
latestValidBlock--
blockTime, err = s.BlockTimeByHeight(ctx, big.NewInt(int64(latestValidBlock)))
if err != nil {
return 0, err
}
}
return latestValidBlock, nil
}
func (s *Service) connectToPowChain() error {
httpClient, rpcClient, err := s.dialETH1Nodes()
if err != nil {
@@ -502,7 +528,7 @@ func safelyHandlePanic() {
}
}
func (s *Service) handleDelayTicker() {
func (s *Service) handleETH1FollowDistance() {
defer safelyHandlePanic()
// use a 5 minutes timeout for block time, because the max mining time is 278 sec (block 7208027)
@@ -568,6 +594,7 @@ func (s *Service) initPOWService() {
s.latestEth1Data.BlockHeight = header.Number.Uint64()
s.latestEth1Data.BlockHash = header.Hash().Bytes()
s.latestEth1Data.BlockTime = header.Time
if err := s.processPastLogs(context.Background()); err != nil {
log.Errorf("Unable to process past logs %v", err)
@@ -605,7 +632,7 @@ func (s *Service) run(done <-chan struct{}) {
}
s.processBlockHeader(head)
case <-ticker.C:
s.handleDelayTicker()
s.handleETH1FollowDistance()
}
}
}

View File

@@ -19,6 +19,7 @@ import (
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
protodb "github.com/prysmaticlabs/prysm/proto/beacon/db"
"github.com/prysmaticlabs/prysm/shared/event"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
logTest "github.com/sirupsen/logrus/hooks/test"
)
@@ -187,6 +188,67 @@ func TestStop_OK(t *testing.T) {
hook.Reset()
}
func TestFollowBlock_OK(t *testing.T) {
testAcc, err := contracts.Setup()
if err != nil {
t.Fatalf("Unable to set up simulated backend %v", err)
}
beaconDB := dbutil.SetupDB(t)
web3Service, err := NewService(context.Background(), &Web3ServiceConfig{
HTTPEndPoint: endpoint,
DepositContract: testAcc.ContractAddr,
BeaconDB: beaconDB,
})
if err != nil {
t.Fatalf("unable to setup web3 ETH1.0 chain service: %v", err)
}
// simulated backend sets eth1 block
// time as 10 seconds
conf := params.BeaconConfig()
conf.SecondsPerETH1Block = 10
params.OverrideBeaconConfig(conf)
defer func() {
params.UseMainnetConfig()
}()
web3Service = setDefaultMocks(web3Service)
web3Service.blockFetcher = &goodFetcher{backend: testAcc.Backend}
baseHeight := testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
// process follow_distance blocks
for i := 0; i < int(params.BeaconConfig().Eth1FollowDistance); i++ {
testAcc.Backend.Commit()
}
// set current height
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
h, err := web3Service.followBlockHeight(context.Background())
if err != nil {
t.Fatal(err)
}
if h != baseHeight {
t.Errorf("Unexpected block height of %d received instead of %d", h, baseHeight)
}
numToForward := uint64(2)
expectedHeight := numToForward + baseHeight
// forward 2 blocks
for i := uint64(0); i < numToForward; i++ {
testAcc.Backend.Commit()
}
// set current height
web3Service.latestEth1Data.BlockHeight = testAcc.Backend.Blockchain().CurrentBlock().NumberU64()
web3Service.latestEth1Data.BlockTime = testAcc.Backend.Blockchain().CurrentBlock().Time()
h, err = web3Service.followBlockHeight(context.Background())
if err != nil {
t.Fatal(err)
}
if h != expectedHeight {
t.Errorf("Unexpected block height of %d received instead of %d", h, expectedHeight)
}
}
func TestInitDataFromContract_OK(t *testing.T) {
testAcc, err := contracts.Setup()
if err != nil {

View File

@@ -93,7 +93,16 @@ func TestServer_ListAttestations_Genesis(t *testing.T) {
}); err != nil && !strings.Contains(err.Error(), "Could not find genesis") {
t.Fatal(err)
}
att := &ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2, CommitteeIndex: 1}}
att := &ethpb.Attestation{
Signature: make([]byte, 96),
Data: &ethpb.AttestationData{
Slot: 2,
CommitteeIndex: 1,
Target: &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
Source: &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
BeaconBlockRoot: make([]byte, 32),
},
}
parentRoot := [32]byte{1, 2, 3}
blk := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{
@@ -159,8 +168,11 @@ func TestServer_ListAttestations_NoPagination(t *testing.T) {
Body: &ethpb.BeaconBlockBody{
Attestations: []*ethpb.Attestation{
{
Signature: make([]byte, 96),
Data: &ethpb.AttestationData{
BeaconBlockRoot: []byte("root"),
Target: &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
Source: &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
BeaconBlockRoot: bytesutil.PadTo([]byte("root"), 32),
Slot: i,
},
AggregationBits: bitfield.Bitlist{0b11},
@@ -197,27 +209,31 @@ func TestServer_ListAttestations_FiltersCorrectly(t *testing.T) {
db := dbTest.SetupDB(t)
ctx := context.Background()
someRoot := []byte{1, 2, 3}
sourceRoot := []byte{4, 5, 6}
someRoot := [32]byte{1, 2, 3}
sourceRoot := [32]byte{4, 5, 6}
sourceEpoch := uint64(5)
targetRoot := []byte{7, 8, 9}
targetRoot := [32]byte{7, 8, 9}
targetEpoch := uint64(7)
blocks := []*ethpb.SignedBeaconBlock{
{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{
Slot: 4,
Slot: 4,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
BeaconBlockRoot: someRoot,
BeaconBlockRoot: someRoot[:],
Source: &ethpb.Checkpoint{
Root: sourceRoot,
Root: sourceRoot[:],
Epoch: sourceEpoch,
},
Target: &ethpb.Checkpoint{
Root: targetRoot,
Root: targetRoot[:],
Epoch: targetEpoch,
},
Slot: 3,
@@ -229,19 +245,23 @@ func TestServer_ListAttestations_FiltersCorrectly(t *testing.T) {
},
},
{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{
Slot: 5 + params.BeaconConfig().SlotsPerEpoch,
Slot: 5 + params.BeaconConfig().SlotsPerEpoch,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
BeaconBlockRoot: someRoot,
BeaconBlockRoot: someRoot[:],
Source: &ethpb.Checkpoint{
Root: sourceRoot,
Root: sourceRoot[:],
Epoch: sourceEpoch,
},
Target: &ethpb.Checkpoint{
Root: targetRoot,
Root: targetRoot[:],
Epoch: targetEpoch,
},
Slot: 4 + params.BeaconConfig().SlotsPerEpoch,
@@ -253,19 +273,23 @@ func TestServer_ListAttestations_FiltersCorrectly(t *testing.T) {
},
},
{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{
Slot: 5,
Slot: 5,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
BeaconBlockRoot: someRoot,
BeaconBlockRoot: someRoot[:],
Source: &ethpb.Checkpoint{
Root: sourceRoot,
Root: sourceRoot[:],
Epoch: sourceEpoch,
},
Target: &ethpb.Checkpoint{
Root: targetRoot,
Root: targetRoot[:],
Epoch: targetEpoch,
},
Slot: 4,
@@ -321,10 +345,14 @@ func TestServer_ListAttestations_Pagination_CustomPageParameters(t *testing.T) {
Attestations: []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
CommitteeIndex: s,
Slot: i,
CommitteeIndex: s,
Slot: i,
BeaconBlockRoot: make([]byte, 32),
Source: &ethpb.Checkpoint{Root: make([]byte, 32)},
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
},
AggregationBits: bitfield.Bitlist{0b11},
Signature: make([]byte, 96),
},
},
},
@@ -423,17 +451,22 @@ func TestServer_ListAttestations_Pagination_CustomPageParameters(t *testing.T) {
func TestServer_ListAttestations_Pagination_OutOfRange(t *testing.T) {
db := dbTest.SetupDB(t)
ctx := context.Background()
testutil.NewBeaconBlock()
count := uint64(1)
atts := make([]*ethpb.Attestation, 0, count)
for i := uint64(0); i < count; i++ {
blockExample := &ethpb.SignedBeaconBlock{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{
Graffiti: make([]byte, 32),
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
BeaconBlockRoot: []byte("root"),
BeaconBlockRoot: bytesutil.PadTo([]byte("root"), 32),
Slot: i,
},
AggregationBits: bitfield.Bitlist{0b11},
@@ -485,14 +518,21 @@ func TestServer_ListAttestations_Pagination_DefaultPageSize(t *testing.T) {
atts := make([]*ethpb.Attestation, 0, count)
for i := uint64(0); i < count; i++ {
blockExample := &ethpb.SignedBeaconBlock{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{
{
Data: &ethpb.AttestationData{
BeaconBlockRoot: []byte("root"),
BeaconBlockRoot: bytesutil.PadTo([]byte("root"), 32),
Target: &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
Source: &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
Slot: i,
},
Signature: bytesutil.PadTo([]byte("root"), 96),
AggregationBits: bitfield.Bitlist{0b11},
},
},
@@ -624,10 +664,15 @@ func TestServer_ListIndexedAttestations_GenesisEpoch(t *testing.T) {
Body: &ethpb.BeaconBlockBody{
Attestations: []*ethpb.Attestation{
{
Signature: make([]byte, 96),
Data: &ethpb.AttestationData{
BeaconBlockRoot: make([]byte, 32),
Target: &ethpb.Checkpoint{
Root: targetRoot[:],
},
Source: &ethpb.Checkpoint{
Root: make([]byte, 32),
},
Slot: i,
CommitteeIndex: 0,
},

View File

@@ -22,8 +22,10 @@ import (
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/mock"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
func TestServer_ListBlocks_NoResults(t *testing.T) {
@@ -91,13 +93,9 @@ func TestServer_ListBlocks_Genesis(t *testing.T) {
}
// Should return the proper genesis block if it exists.
parentRoot := [32]byte{1, 2, 3}
blk := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: 0,
ParentRoot: parentRoot[:],
},
}
parentRoot := [32]byte{'a'}
blk := testutil.NewBeaconBlock()
blk.Block.ParentRoot = parentRoot[:]
root, err := stateutil.BlockRoot(blk.Block)
if err != nil {
t.Fatal(err)
@@ -195,11 +193,8 @@ func TestServer_ListBlocks_Pagination(t *testing.T) {
blks := make([]*ethpb.SignedBeaconBlock, count)
blkContainers := make([]*ethpb.BeaconBlockContainer, count)
for i := uint64(0); i < count; i++ {
b := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: i,
},
}
b := testutil.NewBeaconBlock()
b.Block.Slot = i
root, err := stateutil.BlockRoot(b.Block)
if err != nil {
t.Fatal(err)
@@ -229,20 +224,62 @@ func TestServer_ListBlocks_Pagination(t *testing.T) {
QueryFilter: &ethpb.ListBlocksRequest_Slot{Slot: 5},
PageSize: 3},
res: &ethpb.ListBlocksResponse{
BlockContainers: []*ethpb.BeaconBlockContainer{{Block: &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 5}}, BlockRoot: blkContainers[5].BlockRoot}},
NextPageToken: "",
TotalSize: 1}},
BlockContainers: []*ethpb.BeaconBlockContainer{{Block: &ethpb.SignedBeaconBlock{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Graffiti: make([]byte, 32),
Eth1Data: &ethpb.Eth1Data{
BlockHash: make([]byte, 32),
DepositRoot: make([]byte, 32),
},
},
Slot: 5}},
BlockRoot: blkContainers[5].BlockRoot}},
NextPageToken: "",
TotalSize: 1}},
{req: &ethpb.ListBlocksRequest{
PageToken: strconv.Itoa(0),
QueryFilter: &ethpb.ListBlocksRequest_Root{Root: root6[:]},
PageSize: 3},
res: &ethpb.ListBlocksResponse{
BlockContainers: []*ethpb.BeaconBlockContainer{{Block: &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 6}}, BlockRoot: blkContainers[6].BlockRoot}},
TotalSize: 1}},
BlockContainers: []*ethpb.BeaconBlockContainer{{Block: &ethpb.SignedBeaconBlock{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Graffiti: make([]byte, 32),
Eth1Data: &ethpb.Eth1Data{
BlockHash: make([]byte, 32),
DepositRoot: make([]byte, 32),
},
},
Slot: 6}},
BlockRoot: blkContainers[6].BlockRoot}},
TotalSize: 1}},
{req: &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Root{Root: root6[:]}},
res: &ethpb.ListBlocksResponse{
BlockContainers: []*ethpb.BeaconBlockContainer{{Block: &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 6}}, BlockRoot: blkContainers[6].BlockRoot}},
TotalSize: 1}},
BlockContainers: []*ethpb.BeaconBlockContainer{{Block: &ethpb.SignedBeaconBlock{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Graffiti: make([]byte, 32),
Eth1Data: &ethpb.Eth1Data{
BlockHash: make([]byte, 32),
DepositRoot: make([]byte, 32),
},
},
Slot: 6}},
BlockRoot: blkContainers[6].BlockRoot}},
TotalSize: 1}},
{req: &ethpb.ListBlocksRequest{
PageToken: strconv.Itoa(0),
QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: 0},
@@ -374,7 +411,8 @@ func TestServer_GetChainHead_NoFinalizedBlock(t *testing.T) {
t.Fatal(err)
}
genBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 0, ParentRoot: []byte{'G'}}}
genBlock := testutil.NewBeaconBlock()
genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
if err := db.SaveBlock(context.Background(), genBlock); err != nil {
t.Fatal(err)
}
@@ -417,7 +455,8 @@ func TestServer_GetChainHead_NoHeadBlock(t *testing.T) {
func TestServer_GetChainHead(t *testing.T) {
db := dbTest.SetupDB(t)
genBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 0, ParentRoot: []byte{'G'}}}
genBlock := testutil.NewBeaconBlock()
genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
if err := db.SaveBlock(context.Background(), genBlock); err != nil {
t.Fatal(err)
}
@@ -429,7 +468,9 @@ func TestServer_GetChainHead(t *testing.T) {
t.Fatal(err)
}
finalizedBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 1, ParentRoot: []byte{'A'}}}
finalizedBlock := testutil.NewBeaconBlock()
finalizedBlock.Block.Slot = 1
finalizedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'A'}, 32)
if err := db.SaveBlock(context.Background(), finalizedBlock); err != nil {
t.Fatal(err)
}
@@ -437,7 +478,10 @@ func TestServer_GetChainHead(t *testing.T) {
if err != nil {
t.Fatal(err)
}
justifiedBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 2, ParentRoot: []byte{'B'}}}
justifiedBlock := testutil.NewBeaconBlock()
justifiedBlock.Block.Slot = 2
justifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'B'}, 32)
if err := db.SaveBlock(context.Background(), justifiedBlock); err != nil {
t.Fatal(err)
}
@@ -445,7 +489,10 @@ func TestServer_GetChainHead(t *testing.T) {
if err != nil {
t.Fatal(err)
}
prevJustifiedBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 3, ParentRoot: []byte{'C'}}}
prevJustifiedBlock := testutil.NewBeaconBlock()
prevJustifiedBlock.Block.Slot = 3
prevJustifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'C'}, 32)
if err := db.SaveBlock(context.Background(), prevJustifiedBlock); err != nil {
t.Fatal(err)
}
@@ -546,7 +593,8 @@ func TestServer_StreamChainHead_ContextCanceled(t *testing.T) {
func TestServer_StreamChainHead_OnHeadUpdated(t *testing.T) {
db := dbTest.SetupDB(t)
genBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 0, ParentRoot: []byte{'G'}}}
genBlock := testutil.NewBeaconBlock()
genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
if err := db.SaveBlock(context.Background(), genBlock); err != nil {
t.Fatal(err)
}
@@ -558,7 +606,9 @@ func TestServer_StreamChainHead_OnHeadUpdated(t *testing.T) {
t.Fatal(err)
}
finalizedBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 1, ParentRoot: []byte{'A'}}}
finalizedBlock := testutil.NewBeaconBlock()
finalizedBlock.Block.Slot = 1
finalizedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'A'}, 32)
if err := db.SaveBlock(context.Background(), finalizedBlock); err != nil {
t.Fatal(err)
}
@@ -566,7 +616,10 @@ func TestServer_StreamChainHead_OnHeadUpdated(t *testing.T) {
if err != nil {
t.Fatal(err)
}
justifiedBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 2, ParentRoot: []byte{'B'}}}
justifiedBlock := testutil.NewBeaconBlock()
justifiedBlock.Block.Slot = 2
justifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'B'}, 32)
if err := db.SaveBlock(context.Background(), justifiedBlock); err != nil {
t.Fatal(err)
}
@@ -574,7 +627,10 @@ func TestServer_StreamChainHead_OnHeadUpdated(t *testing.T) {
if err != nil {
t.Fatal(err)
}
prevJustifiedBlock := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Slot: 3, ParentRoot: []byte{'C'}}}
prevJustifiedBlock := testutil.NewBeaconBlock()
prevJustifiedBlock.Block.Slot = 3
prevJustifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'C'}, 32)
if err := db.SaveBlock(context.Background(), prevJustifiedBlock); err != nil {
t.Fatal(err)
}

View File

@@ -1892,7 +1892,9 @@ func TestServer_GetValidatorParticipation_PrevEpoch(t *testing.T) {
t.Fatal(err)
}
wanted := &ethpb.ValidatorParticipation{EligibleEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance}
wanted := &ethpb.ValidatorParticipation{EligibleEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
VotedEther: params.BeaconConfig().EffectiveBalanceIncrement,
GlobalParticipationRate: float32(params.BeaconConfig().EffectiveBalanceIncrement) / float32(validatorCount*params.BeaconConfig().MaxEffectiveBalance)}
if !reflect.DeepEqual(res.Participation, wanted) {
t.Error("Incorrect validator participation respond")
}

View File

@@ -194,7 +194,7 @@ func assignValidatorToSubnet(pubkey []byte, status ethpb.ValidatorStatus) {
return
}
_, ok, expTime := cache.CommitteeIDs.GetPersistentCommittees(pubkey)
_, ok, expTime := cache.SubnetIDs.GetPersistentSubnets(pubkey)
if ok && expTime.After(roughtime.Now()) {
return
}
@@ -208,5 +208,5 @@ func assignValidatorToSubnet(pubkey []byte, status ethpb.ValidatorStatus) {
assignedDuration += int(params.BeaconNetworkConfig().EpochsPerRandomSubnetSubscription)
totalDuration := epochDuration * time.Duration(assignedDuration)
cache.CommitteeIDs.AddPersistentCommittee(pubkey, assignedIdxs, totalDuration*time.Second)
cache.SubnetIDs.AddPersistentCommittee(pubkey, assignedIdxs, totalDuration*time.Second)
}

View File

@@ -14,7 +14,6 @@ import (
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
blk "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
@@ -40,7 +39,7 @@ func TestGetDuties_NextEpoch_CantFindValidatorIdx(t *testing.T) {
ctx := context.Background()
beaconState, _ := testutil.DeterministicGenesisState(t, 10)
genesis := blk.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(genesis.Block)
if err != nil {
t.Fatalf("Could not get signing root %v", err)
@@ -78,7 +77,7 @@ func TestGetDuties_NextEpoch_CantFindValidatorIdx(t *testing.T) {
func TestGetDuties_OK(t *testing.T) {
db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil {
@@ -165,7 +164,7 @@ func TestGetDuties_OK(t *testing.T) {
func TestGetDuties_CurrentEpoch_ShouldNotFail(t *testing.T) {
db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil {
@@ -222,7 +221,7 @@ func TestGetDuties_CurrentEpoch_ShouldNotFail(t *testing.T) {
func TestGetDuties_MultipleKeys_OK(t *testing.T) {
db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
depChainStart := uint64(64)
testutil.ResetCache()
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
@@ -274,11 +273,11 @@ func TestGetDuties_MultipleKeys_OK(t *testing.T) {
if len(res.CurrentEpochDuties) != 2 {
t.Errorf("expected 2 assignments but got %d", len(res.CurrentEpochDuties))
}
if res.CurrentEpochDuties[0].AttesterSlot != 2 {
t.Errorf("Expected res.CurrentEpochDuties[0].AttesterSlot == 7, got %d", res.CurrentEpochDuties[0].AttesterSlot)
if res.CurrentEpochDuties[0].AttesterSlot != 4 {
t.Errorf("Expected res.CurrentEpochDuties[0].AttesterSlot == 4, got %d", res.CurrentEpochDuties[0].AttesterSlot)
}
if res.CurrentEpochDuties[1].AttesterSlot != 1 {
t.Errorf("Expected res.CurrentEpochDuties[1].AttesterSlot == 1, got %d", res.CurrentEpochDuties[1].AttesterSlot)
if res.CurrentEpochDuties[1].AttesterSlot != 4 {
t.Errorf("Expected res.CurrentEpochDuties[1].AttesterSlot == 4, got %d", res.CurrentEpochDuties[1].AttesterSlot)
}
}
@@ -309,7 +308,7 @@ func TestStreamDuties_SyncNotReady(t *testing.T) {
func TestStreamDuties_OK(t *testing.T) {
db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil {
@@ -380,7 +379,7 @@ func TestStreamDuties_OK(t *testing.T) {
func TestStreamDuties_OK_ChainReorg(t *testing.T) {
db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil {
@@ -469,7 +468,7 @@ func TestAssignValidatorToSubnet(t *testing.T) {
k := pubKey(3)
assignValidatorToSubnet(k, ethpb.ValidatorStatus_ACTIVE)
coms, ok, exp := cache.CommitteeIDs.GetPersistentCommittees(k)
coms, ok, exp := cache.SubnetIDs.GetPersistentSubnets(k)
if !ok {
t.Fatal("No cache entry found for validator")
}
@@ -487,7 +486,7 @@ func TestAssignValidatorToSubnet(t *testing.T) {
func BenchmarkCommitteeAssignment(b *testing.B) {
db := dbutil.SetupDB(b)
genesis := blk.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
depChainStart := uint64(8192 * 2)
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil {

View File

@@ -148,6 +148,9 @@ func (vs *Server) GetAttestationData(ctx context.Context, req *ethpb.Attestation
// ProposeAttestation is a function called by an attester to vote
// on a block via an attestation object as defined in the Ethereum Serenity specification.
func (vs *Server) ProposeAttestation(ctx context.Context, att *ethpb.Attestation) (*ethpb.AttestResponse, error) {
ctx, span := trace.StartSpan(ctx, "AttesterServer.ProposeAttestation")
defer span.End()
if _, err := bls.SignatureFromBytes(att.Signature); err != nil {
return nil, status.Error(codes.InvalidArgument, "Incorrect attestation signature")
}
@@ -166,8 +169,16 @@ func (vs *Server) ProposeAttestation(ctx context.Context, att *ethpb.Attestation
},
})
// Determine subnet to broadcast attestation to
wantedEpoch := helpers.SlotToEpoch(att.Data.Slot)
vals, err := vs.HeadFetcher.HeadValidatorsIndices(wantedEpoch)
if err != nil {
return nil, err
}
subnet := helpers.ComputeSubnetFromCommitteeAndSlot(uint64(len(vals)), att.Data.CommitteeIndex, att.Data.Slot)
// Broadcast the new attestation to the network.
if err := vs.P2P.Broadcast(ctx, att); err != nil {
if err := vs.P2P.BroadcastAttestation(ctx, subnet, att); err != nil {
return nil, status.Errorf(codes.Internal, "Could not broadcast attestation: %v", err)
}
@@ -187,14 +198,46 @@ func (vs *Server) ProposeAttestation(ctx context.Context, att *ethpb.Attestation
// SubscribeCommitteeSubnets subscribes to the committee ID subnet given subscribe request.
func (vs *Server) SubscribeCommitteeSubnets(ctx context.Context, req *ethpb.CommitteeSubnetsSubscribeRequest) (*ptypes.Empty, error) {
ctx, span := trace.StartSpan(ctx, "AttesterServer.SubscribeCommitteeSubnets")
defer span.End()
if len(req.Slots) != len(req.CommitteeIds) && len(req.CommitteeIds) != len(req.IsAggregator) {
return nil, status.Error(codes.InvalidArgument, "request fields are not the same length")
}
if len(req.Slots) == 0 {
return nil, status.Error(codes.InvalidArgument, "no attester slots provided")
}
fetchValsLen := func(slot uint64) (uint64, error) {
wantedEpoch := helpers.SlotToEpoch(slot)
vals, err := vs.HeadFetcher.HeadValidatorsIndices(wantedEpoch)
if err != nil {
return 0, err
}
return uint64(len(vals)), nil
}
// Request the head validator indices of epoch represented by the first requested
// slot.
currValsLen, err := fetchValsLen(req.Slots[0])
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not retrieve head validator length: %v", err)
}
currEpoch := helpers.SlotToEpoch(req.Slots[0])
for i := 0; i < len(req.Slots); i++ {
cache.CommitteeIDs.AddAttesterCommiteeID(req.Slots[i], req.CommitteeIds[i])
// If epoch has changed, re-request active validators length
if currEpoch != helpers.SlotToEpoch(req.Slots[i]) {
currValsLen, err = fetchValsLen(req.Slots[i])
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not retrieve head validator length: %v", err)
}
currEpoch = helpers.SlotToEpoch(req.Slots[i])
}
subnet := helpers.ComputeSubnetFromCommitteeAndSlot(currValsLen, req.CommitteeIds[i], req.Slots[i])
cache.SubnetIDs.AddAttesterSubnetID(req.Slots[i], subnet)
if req.IsAggregator[i] {
cache.CommitteeIDs.AddAggregatorCommiteeID(req.Slots[i], req.CommitteeIds[i])
cache.SubnetIDs.AddAggregatorSubnetID(req.Slots[i], subnet)
}
}

View File

@@ -2,6 +2,7 @@ package validator
import (
"context"
"math/rand"
"strings"
"sync"
"testing"
@@ -22,6 +23,7 @@ import (
mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/roughtime"
"github.com/prysmaticlabs/prysm/shared/testutil"
@@ -40,12 +42,9 @@ func TestProposeAttestation_OK(t *testing.T) {
AttPool: attestations.NewPool(),
OperationNotifier: (&mock.ChainService{}).OperationNotifier(),
}
head := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: 999,
ParentRoot: []byte{'a'},
},
}
head := testutil.NewBeaconBlock()
head.Block.Slot = 999
head.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
if err := db.SaveBlock(ctx, head); err != nil {
t.Fatal(err)
}
@@ -637,3 +636,86 @@ func TestGetAttestationData_SucceedsInFirstEpoch(t *testing.T) {
t.Errorf("Expected attestation info to match, received %v, wanted %v", res, expectedInfo)
}
}
func TestServer_SubscribeCommitteeSubnets_NoSlots(t *testing.T) {
db := dbutil.SetupDB(t)
attesterServer := &Server{
HeadFetcher: &mock.ChainService{},
P2P: &mockp2p.MockBroadcaster{},
BeaconDB: db,
AttestationCache: cache.NewAttestationCache(),
AttPool: attestations.NewPool(),
OperationNotifier: (&mock.ChainService{}).OperationNotifier(),
}
_, err := attesterServer.SubscribeCommitteeSubnets(context.Background(), &ethpb.CommitteeSubnetsSubscribeRequest{
Slots: nil,
CommitteeIds: nil,
IsAggregator: nil,
})
if err == nil || !strings.Contains(err.Error(), "no attester slots provided") {
t.Fatalf("Expected no attester slots provided error, received: %v", err)
}
}
func TestServer_SubscribeCommitteeSubnets_MultipleSlots(t *testing.T) {
db := dbutil.SetupDB(t)
// fixed seed
s := rand.NewSource(10)
randGen := rand.New(s)
validators := make([]*ethpb.Validator, 64)
for i := 0; i < len(validators); i++ {
validators[i] = &ethpb.Validator{
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
}
}
state := testutil.NewBeaconState()
if err := state.SetValidators(validators); err != nil {
t.Fatal(err)
}
attesterServer := &Server{
HeadFetcher: &mock.ChainService{State: state},
P2P: &mockp2p.MockBroadcaster{},
BeaconDB: db,
AttestationCache: cache.NewAttestationCache(),
AttPool: attestations.NewPool(),
OperationNotifier: (&mock.ChainService{}).OperationNotifier(),
}
var slots []uint64
var comIdxs []uint64
var isAggregator []bool
for i := uint64(100); i < 200; i++ {
slots = append(slots, i)
comIdxs = append(comIdxs, uint64(randGen.Int63n(64)))
boolVal := randGen.Uint64()%2 == 0
isAggregator = append(isAggregator, boolVal)
}
_, err := attesterServer.SubscribeCommitteeSubnets(context.Background(), &ethpb.CommitteeSubnetsSubscribeRequest{
Slots: slots,
CommitteeIds: comIdxs,
IsAggregator: isAggregator,
})
if err != nil {
t.Fatal(err)
}
for i := uint64(100); i < 200; i++ {
subnets := cache.SubnetIDs.GetAttesterSubnetIDs(i)
if len(subnets) != 1 {
t.Errorf("Wanted subnets of length 1 but got %d", len(subnets))
}
if isAggregator[i-100] {
subnets = cache.SubnetIDs.GetAggregatorSubnetIDs(i)
if len(subnets) != 1 {
t.Errorf("Wanted subnets of length 1 but got %d", len(subnets))
}
}
}
}

View File

@@ -7,7 +7,6 @@ import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
blk "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
@@ -34,7 +33,7 @@ func TestSub(t *testing.T) {
if err != nil {
t.Fatal(err)
}
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -123,7 +122,7 @@ func TestProposeExit_NoPanic(t *testing.T) {
if err != nil {
t.Fatal(err)
}
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}

View File

@@ -382,6 +382,11 @@ func (vs *Server) defaultEth1DataResponse(ctx context.Context, currentHeight *bi
if depositsTillHeight == 0 {
return vs.ChainStartFetcher.ChainStartEth1Data(), nil
}
// Check for the validity of deposit count.
currentETH1Data := vs.HeadFetcher.HeadETH1Data()
if depositsTillHeight < currentETH1Data.DepositCount {
return currentETH1Data, nil
}
return &ethpb.Eth1Data{
DepositRoot: depositRoot[:],
BlockHash: blockHash[:],

View File

@@ -94,24 +94,36 @@ func TestGetBlock_OK(t *testing.T) {
Graffiti: graffiti[:],
}
// We include max proposer slashings which is currently 1 in the pool.
proposerSlashing, err := testutil.GenerateProposerSlashingForValidator(
beaconState,
privKeys[0],
0, /* validator index */
)
if err := proposerServer.SlashingsPool.InsertProposerSlashing(context.Background(), beaconState, proposerSlashing); err != nil {
t.Fatal(err)
proposerSlashings := make([]*ethpb.ProposerSlashing, params.BeaconConfig().MaxProposerSlashings)
for i := uint64(0); i < params.BeaconConfig().MaxProposerSlashings; i++ {
proposerSlashing, err := testutil.GenerateProposerSlashingForValidator(
beaconState,
privKeys[i],
i, /* validator index */
)
if err != nil {
t.Fatal(err)
}
proposerSlashings[i] = proposerSlashing
if err := proposerServer.SlashingsPool.InsertProposerSlashing(context.Background(), beaconState, proposerSlashing); err != nil {
t.Fatal(err)
}
}
// We include max attester slashings which is currently 1 in the pool.
attesterSlashing, err := testutil.GenerateAttesterSlashingForValidator(
beaconState,
privKeys[1],
1, /* validator index */
)
if err := proposerServer.SlashingsPool.InsertAttesterSlashing(context.Background(), beaconState, attesterSlashing); err != nil {
t.Fatal(err)
attSlashings := make([]*ethpb.AttesterSlashing, params.BeaconConfig().MaxAttesterSlashings)
for i := uint64(0); i < params.BeaconConfig().MaxAttesterSlashings; i++ {
attesterSlashing, err := testutil.GenerateAttesterSlashingForValidator(
beaconState,
privKeys[i+params.BeaconConfig().MaxProposerSlashings],
i+params.BeaconConfig().MaxProposerSlashings, /* validator index */
)
if err != nil {
t.Fatal(err)
}
attSlashings[i] = attesterSlashing
if err := proposerServer.SlashingsPool.InsertAttesterSlashing(context.Background(), beaconState, attesterSlashing); err != nil {
t.Fatal(err)
}
}
block, err := proposerServer.GetBlock(ctx, req)
@@ -131,17 +143,17 @@ func TestGetBlock_OK(t *testing.T) {
if !bytes.Equal(block.Body.Graffiti, req.Graffiti) {
t.Fatal("Expected block to have correct graffiti")
}
if len(block.Body.ProposerSlashings) != 1 {
t.Fatalf("Wanted %d proposer slashings, got %d", 1, len(block.Body.ProposerSlashings))
if len(block.Body.ProposerSlashings) != int(params.BeaconConfig().MaxProposerSlashings) {
t.Fatalf("Wanted %d proposer slashings, got %d", params.BeaconConfig().MaxProposerSlashings, len(block.Body.ProposerSlashings))
}
if !reflect.DeepEqual(block.Body.ProposerSlashings[0], proposerSlashing) {
t.Errorf("Wanted proposer slashing %v, got %v", proposerSlashing, block.Body.ProposerSlashings[0])
if !reflect.DeepEqual(block.Body.ProposerSlashings, proposerSlashings) {
t.Errorf("Wanted proposer slashing %v, got %v", proposerSlashings, block.Body.ProposerSlashings)
}
if len(block.Body.AttesterSlashings) != 1 {
t.Fatalf("Wanted %d attester slashings, got %d", 1, len(block.Body.AttesterSlashings))
if len(block.Body.AttesterSlashings) != int(params.BeaconConfig().MaxAttesterSlashings) {
t.Fatalf("Wanted %d attester slashings, got %d", params.BeaconConfig().MaxAttesterSlashings, len(block.Body.AttesterSlashings))
}
if !reflect.DeepEqual(block.Body.AttesterSlashings[0], attesterSlashing) {
t.Errorf("Wanted attester slashing %v, got %v", attesterSlashing, block.Body.AttesterSlashings)
if !reflect.DeepEqual(block.Body.AttesterSlashings, attSlashings) {
t.Errorf("Wanted attester slashing %v, got %v", attSlashings, block.Body.AttesterSlashings)
}
}
@@ -275,7 +287,7 @@ func TestProposeBlock_OK(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
genesis := b.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
if err := db.SaveBlock(context.Background(), genesis); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -301,13 +313,9 @@ func TestProposeBlock_OK(t *testing.T) {
HeadFetcher: c,
BlockNotifier: c.BlockNotifier(),
}
req := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: 5,
ParentRoot: []byte("parent-hash"),
Body: &ethpb.BeaconBlockBody{},
},
}
req := testutil.NewBeaconBlock()
req.Block.Slot = 5
req.Block.ParentRoot = bytesutil.PadTo([]byte("parent-hash"), 32)
if err := db.SaveBlock(ctx, req); err != nil {
t.Fatal(err)
}
@@ -355,7 +363,7 @@ func TestComputeStateRoot_OK(t *testing.T) {
req := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
ProposerIndex: 41,
ProposerIndex: 21,
ParentRoot: parentRoot[:],
Slot: 1,
Body: &ethpb.BeaconBlockBody{
@@ -1197,7 +1205,75 @@ func TestDefaultEth1Data_NoBlockExists(t *testing.T) {
// TODO(2312): Add more tests for edge cases and better coverage.
func TestEth1Data(t *testing.T) {
slot := uint64(10000)
slot := uint64(20000)
p := &mockPOW.POWChain{
BlockNumberByHeight: map[uint64]*big.Int{
slot * params.BeaconConfig().SecondsPerSlot: big.NewInt(8196),
},
HashesByHeight: map[int][]byte{
8180: []byte("8180"),
},
Eth1Data: &ethpb.Eth1Data{
DepositCount: 55,
},
}
headState := testutil.NewBeaconState()
if err := headState.SetEth1Data(&ethpb.Eth1Data{DepositCount: 55}); err != nil {
t.Fatal(err)
}
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositcache.NewDepositCache(),
HeadFetcher: &mock.ChainService{State: headState},
}
ctx := context.Background()
eth1Data, err := ps.eth1Data(ctx, slot)
if err != nil {
t.Fatal(err)
}
if eth1Data.DepositCount != 55 {
t.Error("Expected deposit count to be 55")
}
}
func TestEth1Data_SmallerDepositCount(t *testing.T) {
slot := uint64(20000)
deps := []*dbpb.DepositContainer{
{
Index: 0,
Eth1BlockHeight: 8,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: []byte("a"),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
},
{
Index: 1,
Eth1BlockHeight: 14,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: []byte("b"),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
if err != nil {
t.Fatalf("could not setup deposit trie: %v", err)
}
depositCache := depositcache.NewDepositCache()
for _, dp := range deps {
depositCache.InsertDeposit(context.Background(), dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())
}
p := &mockPOW.POWChain{
BlockNumberByHeight: map[uint64]*big.Int{
@@ -1214,7 +1290,8 @@ func TestEth1Data(t *testing.T) {
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositcache.NewDepositCache(),
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 10}},
DepositFetcher: depositCache,
}
ctx := context.Background()
@@ -1223,8 +1300,10 @@ func TestEth1Data(t *testing.T) {
t.Fatal(err)
}
if eth1Data.DepositCount != 55 {
t.Error("Expected deposit count to be 55")
// Will default to 10 as the current deposit count in the
// cache is only 2.
if eth1Data.DepositCount != 10 {
t.Errorf("Expected deposit count to be 10 but got %d", eth1Data.DepositCount)
}
}
@@ -1284,7 +1363,7 @@ func TestFilterAttestation_OK(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
genesis := b.NewGenesisBlock([]byte{})
genesis := testutil.NewBeaconBlock()
if err := db.SaveBlock(context.Background(), genesis); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}

View File

@@ -12,7 +12,6 @@ import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
blk "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
@@ -70,7 +69,7 @@ func TestWaitForActivation_ContextClosed(t *testing.T) {
if err != nil {
t.Fatal(err)
}
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -135,7 +134,7 @@ func TestWaitForActivation_ValidatorOriginallyExists(t *testing.T) {
},
},
}
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(block.Block)
if err != nil {
t.Fatalf("Could not get signing root %v", err)
@@ -244,7 +243,7 @@ func TestWaitForActivation_MultipleStatuses(t *testing.T) {
},
},
}
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(block.Block)
if err != nil {
t.Fatalf("Could not get signing root %v", err)

View File

@@ -11,7 +11,6 @@ import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
blk "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
@@ -136,7 +135,7 @@ func TestValidatorStatus_Pending(t *testing.T) {
ctx := context.Background()
pubKey := pubKey(1)
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -236,7 +235,7 @@ func TestValidatorStatus_Active(t *testing.T) {
// Active because activation epoch <= current epoch < exit epoch.
activeEpoch := helpers.ActivationExitEpoch(0)
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -301,7 +300,7 @@ func TestValidatorStatus_Exiting(t *testing.T) {
epoch := helpers.SlotToEpoch(slot)
exitEpoch := helpers.ActivationExitEpoch(epoch)
withdrawableEpoch := exitEpoch + params.BeaconConfig().MinValidatorWithdrawabilityDelay
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -372,7 +371,7 @@ func TestValidatorStatus_Slashing(t *testing.T) {
// Exit slashed because slashed is true, exit epoch is =< current epoch and withdrawable epoch > epoch .
slot := uint64(10000)
epoch := helpers.SlotToEpoch(slot)
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -442,7 +441,7 @@ func TestValidatorStatus_Exited(t *testing.T) {
// Exit because only exit epoch is =< current epoch.
slot := uint64(10000)
epoch := helpers.SlotToEpoch(slot)
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -566,7 +565,7 @@ func TestActivationStatus_OK(t *testing.T) {
},
},
})
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(block.Block)
if err != nil {
t.Fatalf("Could not get signing root %v", err)
@@ -655,7 +654,7 @@ func TestValidatorStatus_CorrectActivationQueue(t *testing.T) {
ctx := context.Background()
pbKey := pubKey(5)
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -795,7 +794,7 @@ func TestDepositBlockSlotAfterGenesisTime(t *testing.T) {
},
}
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -834,7 +833,7 @@ func TestDepositBlockSlotAfterGenesisTime(t *testing.T) {
t.Fatalf("Could not get the deposit block slot %v", err)
}
expected := uint64(53)
expected := uint64(69)
if resp != expected {
t.Errorf("Wanted %v, got %v", expected, resp)
@@ -870,7 +869,7 @@ func TestDepositBlockSlotBeforeGenesisTime(t *testing.T) {
},
}
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err)
}
@@ -940,7 +939,7 @@ func TestMultipleValidatorStatus_Pubkeys(t *testing.T) {
},
},
})
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(block.Block)
if err != nil {
t.Fatalf("Could not get signing root %v", err)
@@ -995,7 +994,7 @@ func TestMultipleValidatorStatus_Pubkeys(t *testing.T) {
},
{
Status: ethpb.ValidatorStatus_DEPOSITED,
DepositInclusionSlot: 53,
DepositInclusionSlot: 69,
ActivationEpoch: 18446744073709551615,
},
{
@@ -1059,7 +1058,7 @@ func TestMultipleValidatorStatus_Indices(t *testing.T) {
},
}
stateObj, err := stateTrie.InitializeFromProtoUnsafe(beaconState)
block := blk.NewGenesisBlock([]byte{})
block := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(block.Block)
if err != nil {
t.Fatalf("Could not get signing root %v", err)

View File

@@ -11,6 +11,7 @@ import (
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
//pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params"
@@ -245,23 +246,30 @@ func TestLastAncestorState_CanGet(t *testing.T) {
db := testDB.SetupDB(t)
service := New(db, cache.NewStateSummaryCache())
b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: []byte{'a'}}
r0, err := ssz.HashTreeRoot(b0)
b0 := testutil.NewBeaconBlock()
b0.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
r0, err := ssz.HashTreeRoot(b0.Block)
if err != nil {
t.Fatal(err)
}
b1 := &ethpb.BeaconBlock{Slot: 1, ParentRoot: r0[:]}
r1, err := ssz.HashTreeRoot(b1)
b1 := testutil.NewBeaconBlock()
b1.Block.Slot = 1
b1.Block.ParentRoot = bytesutil.PadTo(r0[:], 32)
r1, err := ssz.HashTreeRoot(b1.Block)
if err != nil {
t.Fatal(err)
}
b2 := &ethpb.BeaconBlock{Slot: 2, ParentRoot: r1[:]}
r2, err := ssz.HashTreeRoot(b2)
b2 := testutil.NewBeaconBlock()
b2.Block.Slot = 2
b2.Block.ParentRoot = bytesutil.PadTo(r1[:], 32)
r2, err := ssz.HashTreeRoot(b2.Block)
if err != nil {
t.Fatal(err)
}
b3 := &ethpb.BeaconBlock{Slot: 3, ParentRoot: r2[:]}
r3, err := ssz.HashTreeRoot(b3)
b3 := testutil.NewBeaconBlock()
b3.Block.Slot = 3
b3.Block.ParentRoot = bytesutil.PadTo(r2[:], 32)
r3, err := ssz.HashTreeRoot(b3.Block)
if err != nil {
t.Fatal(err)
}
@@ -271,16 +279,16 @@ func TestLastAncestorState_CanGet(t *testing.T) {
t.Fatal(err)
}
if err := service.beaconDB.SaveBlock(ctx, &ethpb.SignedBeaconBlock{Block: b0}); err != nil {
if err := service.beaconDB.SaveBlock(ctx, b0); err != nil {
t.Fatal(err)
}
if err := service.beaconDB.SaveBlock(ctx, &ethpb.SignedBeaconBlock{Block: b1}); err != nil {
if err := service.beaconDB.SaveBlock(ctx, b1); err != nil {
t.Fatal(err)
}
if err := service.beaconDB.SaveBlock(ctx, &ethpb.SignedBeaconBlock{Block: b2}); err != nil {
if err := service.beaconDB.SaveBlock(ctx, b2); err != nil {
t.Fatal(err)
}
if err := service.beaconDB.SaveBlock(ctx, &ethpb.SignedBeaconBlock{Block: b3}); err != nil {
if err := service.beaconDB.SaveBlock(ctx, b3); err != nil {
t.Fatal(err)
}
if err := service.beaconDB.SaveState(ctx, b1State, r1); err != nil {

View File

@@ -179,7 +179,7 @@ func TestLoadBlocks_FirstBranch(t *testing.T) {
beaconDB: db,
}
roots, savedBlocks, err := tree1(db, []byte{'A'})
roots, savedBlocks, err := tree1(db, bytesutil.PadTo([]byte{'A'}, 32))
if err != nil {
t.Fatal(err)
}
@@ -190,15 +190,18 @@ func TestLoadBlocks_FirstBranch(t *testing.T) {
}
wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[8]},
{Block: savedBlocks[6]},
{Block: savedBlocks[4]},
{Block: savedBlocks[2]},
{Block: savedBlocks[1]},
{Block: savedBlocks[0]},
savedBlocks[8],
savedBlocks[6],
savedBlocks[4],
savedBlocks[2],
savedBlocks[1],
savedBlocks[0],
}
if !reflect.DeepEqual(filteredBlocks, wanted) {
t.Error("Did not get wanted blocks")
for i, block := range wanted {
if !proto.Equal(block, filteredBlocks[i]) {
t.Error("Did not get wanted blocks")
}
}
}
@@ -220,13 +223,16 @@ func TestLoadBlocks_SecondBranch(t *testing.T) {
}
wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[5]},
{Block: savedBlocks[3]},
{Block: savedBlocks[1]},
{Block: savedBlocks[0]},
savedBlocks[5],
savedBlocks[3],
savedBlocks[1],
savedBlocks[0],
}
if !reflect.DeepEqual(filteredBlocks, wanted) {
t.Error("Did not get wanted blocks")
for i, block := range wanted {
if !proto.Equal(block, filteredBlocks[i]) {
t.Error("Did not get wanted blocks")
}
}
}
@@ -248,15 +254,18 @@ func TestLoadBlocks_ThirdBranch(t *testing.T) {
}
wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[7]},
{Block: savedBlocks[6]},
{Block: savedBlocks[4]},
{Block: savedBlocks[2]},
{Block: savedBlocks[1]},
{Block: savedBlocks[0]},
savedBlocks[7],
savedBlocks[6],
savedBlocks[4],
savedBlocks[2],
savedBlocks[1],
savedBlocks[0],
}
if !reflect.DeepEqual(filteredBlocks, wanted) {
t.Error("Did not get wanted blocks")
for i, block := range wanted {
if !proto.Equal(block, filteredBlocks[i]) {
t.Error("Did not get wanted blocks")
}
}
}
@@ -278,13 +287,16 @@ func TestLoadBlocks_SameSlots(t *testing.T) {
}
wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[6]},
{Block: savedBlocks[5]},
{Block: savedBlocks[1]},
{Block: savedBlocks[0]},
savedBlocks[6],
savedBlocks[5],
savedBlocks[1],
savedBlocks[0],
}
if !reflect.DeepEqual(filteredBlocks, wanted) {
t.Error("Did not get wanted blocks")
for i, block := range wanted {
if !proto.Equal(block, filteredBlocks[i]) {
t.Error("Did not get wanted blocks")
}
}
}
@@ -295,7 +307,7 @@ func TestLoadBlocks_SameEndSlots(t *testing.T) {
beaconDB: db,
}
roots, savedBlocks, err := tree3(db, []byte{'A'})
roots, savedBlocks, err := tree3(db, bytesutil.PadTo([]byte{'A'}, 32))
if err != nil {
t.Fatal(err)
}
@@ -306,12 +318,15 @@ func TestLoadBlocks_SameEndSlots(t *testing.T) {
}
wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[2]},
{Block: savedBlocks[1]},
{Block: savedBlocks[0]},
savedBlocks[2],
savedBlocks[1],
savedBlocks[0],
}
if !reflect.DeepEqual(filteredBlocks, wanted) {
t.Error("Did not get wanted blocks")
for i, block := range wanted {
if !proto.Equal(block, filteredBlocks[i]) {
t.Error("Did not get wanted blocks")
}
}
}
@@ -322,7 +337,7 @@ func TestLoadBlocks_SameEndSlotsWith2blocks(t *testing.T) {
beaconDB: db,
}
roots, savedBlocks, err := tree4(db, []byte{'A'})
roots, savedBlocks, err := tree4(db, bytesutil.PadTo([]byte{'A'}, 32))
if err != nil {
t.Fatal(err)
}
@@ -333,11 +348,14 @@ func TestLoadBlocks_SameEndSlotsWith2blocks(t *testing.T) {
}
wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[1]},
{Block: savedBlocks[0]},
savedBlocks[1],
savedBlocks[0],
}
if !reflect.DeepEqual(filteredBlocks, wanted) {
t.Error("Did not get wanted blocks")
for i, block := range wanted {
if !proto.Equal(block, filteredBlocks[i]) {
t.Error("Did not get wanted blocks")
}
}
}
@@ -348,7 +366,7 @@ func TestLoadBlocks_BadStart(t *testing.T) {
beaconDB: db,
}
roots, _, err := tree1(db, []byte{'A'})
roots, _, err := tree1(db, bytesutil.PadTo([]byte{'A'}, 32))
if err != nil {
t.Fatal(err)
}
@@ -661,7 +679,7 @@ func TestProcessStateUpToSlot_CanProcess(t *testing.T) {
// B0 - B1 - - B3 -- B5
// \- B2 -- B4 -- B6 ----- B8
// \- B7
func tree1(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock, error) {
func tree1(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
r0, err := ssz.HashTreeRoot(b0)
if err != nil {
@@ -709,15 +727,20 @@ func tree1(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
}
st := testutil.NewBeaconState()
returnedBlocks := []*ethpb.SignedBeaconBlock{}
for _, b := range []*ethpb.BeaconBlock{b0, b1, b2, b3, b4, b5, b6, b7, b8} {
if err := db.SaveBlock(context.Background(), &ethpb.SignedBeaconBlock{Block: b}); err != nil {
beaconBlock := testutil.NewBeaconBlock()
beaconBlock.Block.Slot = b.Slot
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
if err := db.SaveBlock(context.Background(), beaconBlock); err != nil {
return nil, nil, err
}
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(b.ParentRoot)); err != nil {
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(beaconBlock.Block.ParentRoot)); err != nil {
return nil, nil, err
}
returnedBlocks = append(returnedBlocks, beaconBlock)
}
return [][32]byte{r0, r1, r2, r3, r4, r5, r6, r7, r8}, []*ethpb.BeaconBlock{b0, b1, b2, b3, b4, b5, b6, b7, b8}, nil
return [][32]byte{r0, r1, r2, r3, r4, r5, r6, r7, r8}, returnedBlocks, nil
}
// tree2 constructs the following tree:
@@ -726,7 +749,7 @@ func tree1(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
// \- B2
// \- B2
// \- B2 -- B3
func tree2(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock, error) {
func tree2(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
r0, err := ssz.HashTreeRoot(b0)
if err != nil {
@@ -764,15 +787,21 @@ func tree2(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
}
st := testutil.NewBeaconState()
returnedBlocks := []*ethpb.SignedBeaconBlock{}
for _, b := range []*ethpb.BeaconBlock{b0, b1, b21, b22, b23, b24, b3} {
if err := db.SaveBlock(context.Background(), &ethpb.SignedBeaconBlock{Block: b}); err != nil {
beaconBlock := testutil.NewBeaconBlock()
beaconBlock.Block.Slot = b.Slot
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
beaconBlock.Block.StateRoot = bytesutil.PadTo(b.StateRoot, 32)
if err := db.SaveBlock(context.Background(), beaconBlock); err != nil {
return nil, nil, err
}
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(b.ParentRoot)); err != nil {
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(beaconBlock.Block.ParentRoot)); err != nil {
return nil, nil, err
}
returnedBlocks = append(returnedBlocks, beaconBlock)
}
return [][32]byte{r0, r1, r21, r22, r23, r24, r3}, []*ethpb.BeaconBlock{b0, b1, b21, b22, b23, b24, b3}, nil
return [][32]byte{r0, r1, r21, r22, r23, r24, r3}, returnedBlocks, nil
}
// tree3 constructs the following tree:
@@ -781,7 +810,7 @@ func tree2(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
// \- B2
// \- B2
// \- B2
func tree3(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock, error) {
func tree3(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
r0, err := ssz.HashTreeRoot(b0)
if err != nil {
@@ -814,16 +843,22 @@ func tree3(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
}
st := testutil.NewBeaconState()
returnedBlocks := []*ethpb.SignedBeaconBlock{}
for _, b := range []*ethpb.BeaconBlock{b0, b1, b21, b22, b23, b24} {
if err := db.SaveBlock(context.Background(), &ethpb.SignedBeaconBlock{Block: b}); err != nil {
beaconBlock := testutil.NewBeaconBlock()
beaconBlock.Block.Slot = b.Slot
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
beaconBlock.Block.StateRoot = bytesutil.PadTo(b.StateRoot, 32)
if err := db.SaveBlock(context.Background(), beaconBlock); err != nil {
return nil, nil, err
}
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(b.ParentRoot)); err != nil {
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(beaconBlock.Block.ParentRoot)); err != nil {
return nil, nil, err
}
returnedBlocks = append(returnedBlocks, beaconBlock)
}
return [][32]byte{r0, r1, r21, r22, r23, r24}, []*ethpb.BeaconBlock{b0, b1, b21, b22, b23, b24}, nil
return [][32]byte{r0, r1, r21, r22, r23, r24}, returnedBlocks, nil
}
// tree4 constructs the following tree:
@@ -832,7 +867,7 @@ func tree3(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
// \- B2
// \- B2
// \- B2
func tree4(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock, error) {
func tree4(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
r0, err := ssz.HashTreeRoot(b0)
if err != nil {
@@ -860,14 +895,20 @@ func tree4(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
}
st := testutil.NewBeaconState()
returnedBlocks := []*ethpb.SignedBeaconBlock{}
for _, b := range []*ethpb.BeaconBlock{b0, b21, b22, b23, b24} {
if err := db.SaveBlock(context.Background(), &ethpb.SignedBeaconBlock{Block: b}); err != nil {
beaconBlock := testutil.NewBeaconBlock()
beaconBlock.Block.Slot = b.Slot
beaconBlock.Block.ParentRoot = bytesutil.PadTo(b.ParentRoot, 32)
beaconBlock.Block.StateRoot = bytesutil.PadTo(b.StateRoot, 32)
if err := db.SaveBlock(context.Background(), beaconBlock); err != nil {
return nil, nil, err
}
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(b.ParentRoot)); err != nil {
if err := db.SaveState(context.Background(), st.Copy(), bytesutil.ToBytes32(beaconBlock.Block.ParentRoot)); err != nil {
return nil, nil, err
}
returnedBlocks = append(returnedBlocks, beaconBlock)
}
return [][32]byte{r0, r21, r22, r23, r24}, []*ethpb.BeaconBlock{b0, b21, b22, b23, b24}, nil
return [][32]byte{r0, r21, r22, r23, r24}, returnedBlocks, nil
}

View File

@@ -23,14 +23,14 @@ go_library(
"service.go",
"subscriber.go",
"subscriber_beacon_aggregate_proof.go",
"subscriber_beacon_attestation.go",
"subscriber_beacon_blocks.go",
"subscriber_committee_index_beacon_attestation.go",
"subscriber_handlers.go",
"utils.go",
"validate_aggregate_proof.go",
"validate_attester_slashing.go",
"validate_beacon_attestation.go",
"validate_beacon_blocks.go",
"validate_committee_index_beacon_attestation.go",
"validate_proposer_slashing.go",
"validate_voluntary_exit.go",
],
@@ -63,7 +63,6 @@ go_library(
"//beacon-chain/state/stateutil:go_default_library",
"//proto/beacon/p2p/v1:go_default_library",
"//shared:go_default_library",
"//shared/attestationutil:go_default_library",
"//shared/bls:go_default_library",
"//shared/bytesutil:go_default_library",
"//shared/featureconfig:go_default_library",
@@ -109,15 +108,15 @@ go_test(
"rpc_test.go",
"service_test.go",
"subscriber_beacon_aggregate_proof_test.go",
"subscriber_beacon_attestation_test.go",
"subscriber_beacon_blocks_test.go",
"subscriber_committee_index_beacon_attestation_test.go",
"subscriber_test.go",
"sync_test.go",
"utils_test.go",
"validate_aggregate_proof_test.go",
"validate_attester_slashing_test.go",
"validate_beacon_attestation_test.go",
"validate_beacon_blocks_test.go",
"validate_committee_index_beacon_attestation_test.go",
"validate_proposer_slashing_test.go",
"validate_voluntary_exit_test.go",
],

View File

@@ -6,6 +6,7 @@ import (
"io"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/encoder"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
)
const genericError = "internal service error"
@@ -23,7 +24,10 @@ var responseCodeServerError = byte(0x02)
func (r *Service) generateErrorResponse(code byte, reason string) ([]byte, error) {
buf := bytes.NewBuffer([]byte{code})
if _, err := r.p2p.Encoding().EncodeWithLength(buf, []byte(reason)); err != nil {
resp := &pb.ErrorResponse{
Message: []byte(reason),
}
if _, err := r.p2p.Encoding().EncodeWithLength(buf, resp); err != nil {
return nil, err
}
@@ -42,10 +46,12 @@ func ReadStatusCode(stream io.Reader, encoding encoder.NetworkEncoding) (uint8,
return 0, "", nil
}
msg := make([]byte, 0)
if err := encoding.DecodeWithLength(stream, &msg); err != nil {
msg := &pb.ErrorResponse{
Message: []byte{},
}
if err := encoding.DecodeWithLength(stream, msg); err != nil {
return 0, "", err
}
return b[0], string(msg), nil
return b[0], string(msg.Message), nil
}

View File

@@ -5,6 +5,7 @@ import (
"testing"
p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
)
func TestRegularSync_generateErrorResponse(t *testing.T) {
@@ -24,11 +25,11 @@ func TestRegularSync_generateErrorResponse(t *testing.T) {
if b[0] != responseCodeServerError {
t.Errorf("The first byte was not the status code. Got %#x wanted %#x", b, responseCodeServerError)
}
msg := make([]byte, 0)
if err := r.p2p.Encoding().DecodeWithLength(buf, &msg); err != nil {
msg := &pb.ErrorResponse{}
if err := r.p2p.Encoding().DecodeWithLength(buf, msg); err != nil {
t.Fatal(err)
}
if string(msg) != "something bad happened" {
if string(msg.Message) != "something bad happened" {
t.Errorf("Received the wrong message: %v", msg)
}
}

View File

@@ -464,11 +464,15 @@ func (f *blocksFetcher) requestBlocks(
}()
resp := make([]*eth.SignedBeaconBlock, 0, req.Count)
for {
for i := uint64(0); ; i++ {
blk, err := prysmsync.ReadChunkedBlock(stream, f.p2p)
if err == io.EOF {
break
}
// exit if more than max request blocks are returned
if i >= params.BeaconNetworkConfig().MaxRequestBlocks {
break
}
if err != nil {
return nil, err
}

View File

@@ -89,7 +89,7 @@ func (r *Service) updateMetrics() {
if err != nil {
log.WithError(err).Errorf("Could not compute fork digest")
}
indices := r.aggregatorCommitteeIndices(r.chain.CurrentSlot())
indices := r.aggregatorSubnetIndices(r.chain.CurrentSlot())
attTopic := p2p.GossipTypeMapping[reflect.TypeOf(&pb.Attestation{})]
attTopic += r.p2p.Encoding().ProtocolSuffix()
for _, committeeIdx := range indices {
@@ -99,7 +99,7 @@ func (r *Service) updateMetrics() {
// We update all other gossip topics.
for topic := range p2p.GossipTopicMappings {
// We already updated attestation subnet topics.
if strings.Contains(topic, "committee_index") {
if strings.Contains(topic, "beacon_attestation") {
continue
}
topic += r.p2p.Encoding().ProtocolSuffix()

View File

@@ -139,7 +139,7 @@ func (s *Service) processPendingAtts(ctx context.Context) error {
}
}
req := [][32]byte{bRoot}
req := [][]byte{bRoot[:]}
if err := s.sendRecentBeaconBlocksRequest(ctx, req, pid); err != nil {
traceutil.AnnotateError(span, err)
log.Errorf("Could not send recent block request: %v", err)

View File

@@ -173,11 +173,13 @@ func TestProcessPendingAtts_HasBlockSaveAggregatedAtt(t *testing.T) {
if err != nil {
t.Fatal(err)
}
sig := privKeys[33].Sign(slotRoot[:])
// Arbitrary aggregator index for testing purposes.
aggregatorIndex := committee[0]
sig := privKeys[aggregatorIndex].Sign(slotRoot[:])
aggregateAndProof := &ethpb.AggregateAttestationAndProof{
SelectionProof: sig.Marshal(),
Aggregate: att,
AggregatorIndex: 33,
AggregatorIndex: aggregatorIndex,
}
attesterDomain, err = helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainAggregateAndProof, beaconState.GenesisValidatorRoot())
if err != nil {
@@ -187,7 +189,7 @@ func TestProcessPendingAtts_HasBlockSaveAggregatedAtt(t *testing.T) {
if err != nil {
t.Error(err)
}
aggreSig := privKeys[33].Sign(signingRoot[:]).Marshal()
aggreSig := privKeys[aggregatorIndex].Sign(signingRoot[:]).Marshal()
if err := beaconState.SetGenesisTime(uint64(time.Now().Unix())); err != nil {
t.Fatal(err)

View File

@@ -75,7 +75,7 @@ func (r *Service) processPendingBlocks(ctx context.Context) error {
"currentSlot": b.Block.Slot,
"parentRoot": hex.EncodeToString(bytesutil.Trunc(b.Block.ParentRoot)),
}).Info("Requesting parent block")
req := [][32]byte{bytesutil.ToBytes32(b.Block.ParentRoot)}
req := [][]byte{b.Block.ParentRoot}
// Start with a random peer to query, but choose the first peer in our unsorted list that claims to
// have a head slot newer than the block slot we are requesting.

View File

@@ -49,7 +49,7 @@ func (r *Service) registerRPCHandlers() {
)
r.registerRPC(
p2p.RPCBlocksByRootTopic,
[][32]byte{},
&pb.BeaconBlocksByRootRequest{},
r.beaconBlocksRootRPCHandler,
)
r.registerRPC(

View File

@@ -7,11 +7,11 @@ import (
libp2pcore "github.com/libp2p/go-libp2p-core"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
"github.com/prysmaticlabs/prysm/beacon-chain/flags"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/traceutil"
"go.opencensus.io/trace"
)
@@ -61,6 +61,7 @@ func (r *Service) beaconBlocksByRangeRPCHandler(ctx context.Context, msg interfa
trace.StringAttribute("peer", stream.Conn().RemotePeer().Pretty()),
trace.Int64Attribute("remaining_capacity", remainingBucketCapacity),
)
maxRequestBlocks := params.BeaconNetworkConfig().MaxRequestBlocks
for startSlot <= endReqSlot {
remainingBucketCapacity = r.blocksRateLimiter.Remaining(stream.Conn().RemotePeer().String())
if int64(allowedBlocksPerSecond) > remainingBucketCapacity {
@@ -78,7 +79,7 @@ func (r *Service) beaconBlocksByRangeRPCHandler(ctx context.Context, msg interfa
}
// TODO(3147): Update this with reasonable constraints.
if endSlot-startSlot > rangeLimit || m.Step == 0 {
if endSlot-startSlot > rangeLimit || m.Step == 0 || m.Count > maxRequestBlocks {
r.writeErrorResponseToStream(responseCodeInvalidRequest, stepError, stream)
err := errors.New(stepError)
traceutil.AnnotateError(span, err)
@@ -145,24 +146,29 @@ func (r *Service) writeBlockRangeToStream(ctx context.Context, startSlot, endSlo
roots = append([][32]byte{genRoot}, roots...)
}
blks, roots = r.sortBlocksAndRoots(blks, roots)
checkpoint, err := r.db.FinalizedCheckpoint(ctx)
if err != nil {
log.WithError(err).Error("Failed to retrieve finalized checkpoint")
r.writeErrorResponseToStream(responseCodeServerError, genericError, stream)
traceutil.AnnotateError(span, err)
return err
}
for i, b := range blks {
if b == nil || b.Block == nil {
continue
}
blk := b.Block
// Check that the block is valid according to the request and part of the canonical chain.
isRequestedSlotStep := (blk.Slot-startSlot)%step == 0
isRecentUnfinalizedSlot := blk.Slot >= helpers.StartSlot(checkpoint.Epoch+1) || checkpoint.Epoch == 0
if isRequestedSlotStep && (isRecentUnfinalizedSlot || r.db.IsFinalizedBlock(ctx, roots[i])) {
if isRequestedSlotStep {
canonical, err := r.chain.IsCanonical(ctx, roots[i])
if err != nil {
log.WithError(err).Error("Failed to determine canonical block")
r.writeErrorResponseToStream(responseCodeServerError, genericError, stream)
traceutil.AnnotateError(span, err)
return err
}
if !canonical {
continue
}
if err := r.chunkWriter(stream, b); err != nil {
log.WithError(err).Error("Failed to send a chunked response")
r.writeErrorResponseToStream(responseCodeServerError, genericError, stream)
traceutil.AnnotateError(span, err)
return err
}
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/protocol"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
chainMock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
db "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/flags"
p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
@@ -42,7 +43,8 @@ func TestRPCBeaconBlocksByRange_RPCHandlerReturnsBlocks(t *testing.T) {
}
// Start service with 160 as allowed blocks capacity (and almost zero capacity recovery).
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, int64(req.Count*10), false)}
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, int64(req.Count*10), false),
chain: &chainMock.ChainService{}}
pcl := protocol.ID("/testing")
var wg sync.WaitGroup
@@ -107,7 +109,8 @@ func TestRPCBeaconBlocksByRange_RPCHandlerReturnsSortedBlocks(t *testing.T) {
}
// Start service with 160 as allowed blocks capacity (and almost zero capacity recovery).
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, int64(req.Count*10), false)}
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, int64(req.Count*10), false),
chain: &chainMock.ChainService{}}
pcl := protocol.ID("/testing")
var wg sync.WaitGroup
@@ -175,7 +178,7 @@ func TestRPCBeaconBlocksByRange_ReturnsGenesisBlock(t *testing.T) {
}
}
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(10000, 10000, false)}
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(10000, 10000, false), chain: &chainMock.ChainService{}}
pcl := protocol.ID("/testing")
var wg sync.WaitGroup
@@ -270,7 +273,7 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
}
capacity := int64(flags.Get().BlockBatchLimit * 3)
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, capacity, false)}
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, capacity, false), chain: &chainMock.ChainService{}}
req := &pb.BeaconBlocksByRangeRequest{
StartSlot: 100,
@@ -301,7 +304,7 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
}
capacity := int64(flags.Get().BlockBatchLimit * 3)
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, capacity, false)}
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, capacity, false), chain: &chainMock.ChainService{}}
req := &pb.BeaconBlocksByRangeRequest{
StartSlot: 100,
@@ -336,7 +339,7 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
}
capacity := int64(flags.Get().BlockBatchLimit * flags.Get().BlockBatchLimitBurstFactor)
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, capacity, false)}
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(0.000001, capacity, false), chain: &chainMock.ChainService{}}
req := &pb.BeaconBlocksByRangeRequest{
StartSlot: 100,

View File

@@ -10,15 +10,19 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params"
)
// sendRecentBeaconBlocksRequest sends a recent beacon blocks request to a peer to get
// those corresponding blocks from that peer.
func (r *Service) sendRecentBeaconBlocksRequest(ctx context.Context, blockRoots [][32]byte, id peer.ID) error {
func (r *Service) sendRecentBeaconBlocksRequest(ctx context.Context, blockRoots [][]byte, id peer.ID) error {
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
stream, err := r.p2p.Send(ctx, blockRoots, p2p.RPCBlocksByRootTopic, id)
req := &pbp2p.BeaconBlocksByRootRequest{BlockRoots: blockRoots}
stream, err := r.p2p.Send(ctx, req, p2p.RPCBlocksByRootTopic, id)
if err != nil {
return err
}
@@ -32,6 +36,10 @@ func (r *Service) sendRecentBeaconBlocksRequest(ctx context.Context, blockRoots
if err == io.EOF {
break
}
// Exit if peer sends more than max request blocks.
if uint64(i) >= params.BeaconNetworkConfig().MaxRequestBlocks {
break
}
if err != nil {
log.WithError(err).Error("Unable to retrieve block from stream")
return err
@@ -62,11 +70,11 @@ func (r *Service) beaconBlocksRootRPCHandler(ctx context.Context, msg interface{
setRPCStreamDeadlines(stream)
log := log.WithField("handler", "beacon_blocks_by_root")
blockRoots, ok := msg.([][32]byte)
req, ok := msg.(*pbp2p.BeaconBlocksByRootRequest)
if !ok {
return errors.New("message is not type [][32]byte")
return errors.New("message is not type BeaconBlocksByRootRequest")
}
if len(blockRoots) == 0 {
if len(req.BlockRoots) == 0 {
resp, err := r.generateErrorResponse(responseCodeInvalidRequest, "no block roots provided in request")
if err != nil {
log.WithError(err).Error("Failed to generate a response error")
@@ -78,7 +86,7 @@ func (r *Service) beaconBlocksRootRPCHandler(ctx context.Context, msg interface{
return errors.New("no block roots provided")
}
if int64(len(blockRoots)) > r.blocksRateLimiter.Remaining(stream.Conn().RemotePeer().String()) {
if int64(len(req.BlockRoots)) > r.blocksRateLimiter.Remaining(stream.Conn().RemotePeer().String()) {
r.p2p.Peers().IncrementBadResponses(stream.Conn().RemotePeer())
if r.p2p.Peers().IsBad(stream.Conn().RemotePeer()) {
log.Debug("Disconnecting bad peer")
@@ -99,10 +107,22 @@ func (r *Service) beaconBlocksRootRPCHandler(ctx context.Context, msg interface{
return errors.New(rateLimitedError)
}
r.blocksRateLimiter.Add(stream.Conn().RemotePeer().String(), int64(len(blockRoots)))
if uint64(len(req.BlockRoots)) > params.BeaconNetworkConfig().MaxRequestBlocks {
resp, err := r.generateErrorResponse(responseCodeInvalidRequest, "requested more than the max block limit")
if err != nil {
log.WithError(err).Error("Failed to generate a response error")
} else {
if _, err := stream.Write(resp); err != nil {
log.WithError(err).Errorf("Failed to write to stream")
}
}
return errors.New("requested more than the max block limit")
}
for _, root := range blockRoots {
blk, err := r.db.Block(ctx, root)
r.blocksRateLimiter.Add(stream.Conn().RemotePeer().String(), int64(len(req.BlockRoots)))
for _, root := range req.BlockRoots {
blk, err := r.db.Block(ctx, bytesutil.ToBytes32(root))
if err != nil {
log.WithError(err).Error("Failed to fetch block")
resp, err := r.generateErrorResponse(responseCodeServerError, genericError)

View File

@@ -17,6 +17,7 @@ import (
db "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
)
@@ -30,7 +31,7 @@ func TestRecentBeaconBlocksRPCHandler_ReturnsBlocks(t *testing.T) {
}
d := db.SetupDB(t)
var blkRoots [][32]byte
var blkRoots [][]byte
// Populate the database with blocks that would match the request.
for i := 1; i < 11; i++ {
blk := &ethpb.BeaconBlock{
@@ -43,7 +44,7 @@ func TestRecentBeaconBlocksRPCHandler_ReturnsBlocks(t *testing.T) {
if err := d.SaveBlock(context.Background(), &ethpb.SignedBeaconBlock{Block: blk}); err != nil {
t.Fatal(err)
}
blkRoots = append(blkRoots, root)
blkRoots = append(blkRoots, root[:])
}
r := &Service{p2p: p1, db: d, blocksRateLimiter: leakybucket.NewCollector(10000, 10000, false)}
@@ -69,8 +70,8 @@ func TestRecentBeaconBlocksRPCHandler_ReturnsBlocks(t *testing.T) {
if err != nil {
t.Fatal(err)
}
err = r.beaconBlocksRootRPCHandler(context.Background(), blkRoots, stream1)
req := &pb.BeaconBlocksByRootRequest{BlockRoots: blkRoots}
err = r.beaconBlocksRootRPCHandler(context.Background(), req, stream1)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
@@ -111,7 +112,7 @@ func TestRecentBeaconBlocks_RPCRequestSent(t *testing.T) {
Root: blockBRoot[:],
}
expectedRoots := [][32]byte{blockBRoot, blockARoot}
expectedRoots := [][]byte{blockBRoot[:], blockARoot[:]}
r := &Service{
p2p: p1,
@@ -132,12 +133,12 @@ func TestRecentBeaconBlocks_RPCRequestSent(t *testing.T) {
wg.Add(1)
p2.Host.SetStreamHandler(pcl, func(stream network.Stream) {
defer wg.Done()
out := [][32]byte{}
if err := p2.Encoding().DecodeWithLength(stream, &out); err != nil {
out := &pb.BeaconBlocksByRootRequest{BlockRoots: [][]byte{}}
if err := p2.Encoding().DecodeWithLength(stream, out); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(out, expectedRoots) {
t.Fatalf("Did not receive expected message. Got %+v wanted %+v", out, expectedRoots)
if !reflect.DeepEqual(out.BlockRoots, expectedRoots) {
t.Fatalf("Did not receive expected message. Got %+v wanted %+v", out.BlockRoots, expectedRoots)
}
response := []*ethpb.SignedBeaconBlock{blockB, blockA}
for _, blk := range response {

View File

@@ -66,6 +66,7 @@ type blockchainService interface {
blockchain.AttestationReceiver
blockchain.TimeFetcher
blockchain.GenesisFetcher
blockchain.CanonicalFetcher
}
// Service is responsible for handling all run time p2p related operations as the

View File

@@ -12,7 +12,6 @@ import (
"github.com/libp2p/go-libp2p-core/peer"
pubsub "github.com/libp2p/go-libp2p-pubsub"
pb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/messagehandler"
@@ -68,15 +67,16 @@ func (r *Service) registerSubscribers() {
r.attesterSlashingSubscriber,
)
if featureconfig.Get().DisableDynamicCommitteeSubnets {
r.subscribeDynamic(
"/eth2/%x/committee_index%d_beacon_attestation",
r.committeesCount, /* determineSubsLen */
r.validateCommitteeIndexBeaconAttestation, /* validator */
r.committeeIndexBeaconAttestationSubscriber, /* message handler */
)
for i := uint64(0); i < params.BeaconNetworkConfig().AttestationSubnetCount; i++ {
r.subscribe(
fmt.Sprintf("/eth2/%%x/beacon_attestation_%d", i),
r.validateCommitteeIndexBeaconAttestation, /* validator */
r.committeeIndexBeaconAttestationSubscriber, /* message handler */
)
}
} else {
r.subscribeDynamicWithSubnets(
"/eth2/%x/committee_index%d_beacon_attestation",
"/eth2/%x/beacon_attestation_%d",
r.validateCommitteeIndexBeaconAttestation, /* validator */
r.committeeIndexBeaconAttestationSubscriber, /* message handler */
)
@@ -211,9 +211,9 @@ func (r *Service) subscribeDynamicWithSubnets(
}
// Persistent subscriptions from validators
persistentSubs := r.persistentCommitteeIndices()
persistentSubs := r.persistentSubnetIndices()
// Update desired topic indices for aggregator
wantedSubs := r.aggregatorCommitteeIndices(currentSlot)
wantedSubs := r.aggregatorSubnetIndices(currentSlot)
// Combine subscriptions to get all requested subscriptions
wantedSubs = sliceutil.SetUint64(append(persistentSubs, wantedSubs...))
@@ -225,7 +225,7 @@ func (r *Service) subscribeDynamicWithSubnets(
r.subscribeAggregatorSubnet(subscriptions, idx, base, digest, validate, handle)
}
// find desired subs for attesters
attesterSubs := r.attesterCommitteeIndices(currentSlot)
attesterSubs := r.attesterSubnetIndices(currentSlot)
for _, idx := range attesterSubs {
r.lookupAttesterSubnets(digest, idx)
}
@@ -234,57 +234,6 @@ func (r *Service) subscribeDynamicWithSubnets(
}()
}
// subscribe to a dynamically increasing index of topics. This method expects a fmt compatible
// string for the topic name and a maxID to represent the number of subscribed topics that should be
// maintained. As the state feed emits a newly updated state, the maxID function will be called to
// determine the appropriate number of topics. This method supports only sequential number ranges
// for topics.
func (r *Service) subscribeDynamic(topicFormat string, determineSubsLen func() int, validate pubsub.ValidatorEx, handle subHandler) {
base := p2p.GossipTopicMappings[topicFormat]
if base == nil {
log.Fatalf("%s is not mapped to any message in GossipTopicMappings", topicFormat)
}
digest, err := r.forkDigest()
if err != nil {
log.WithError(err).Fatal("Could not compute fork digest")
}
var subscriptions []*pubsub.Subscription
stateChannel := make(chan *feed.Event, 1)
stateSub := r.stateNotifier.StateFeed().Subscribe(stateChannel)
go func() {
for {
select {
case <-r.ctx.Done():
stateSub.Unsubscribe()
return
case <-stateChannel:
if r.chainStarted && r.initialSync.Syncing() {
continue
}
// Update topic count.
wantedSubs := determineSubsLen()
// Resize as appropriate.
if len(subscriptions) > wantedSubs { // Reduce topics
var cancelSubs []*pubsub.Subscription
subscriptions, cancelSubs = subscriptions[:wantedSubs-1], subscriptions[wantedSubs:]
for i, sub := range cancelSubs {
sub.Cancel()
if err := r.p2p.PubSub().UnregisterTopicValidator(fmt.Sprintf(topicFormat, i+wantedSubs)); err != nil {
log.WithError(err).Error("Failed to unregister topic validator")
}
}
} else if len(subscriptions) < wantedSubs { // Increase topics
for i := len(subscriptions); i < wantedSubs; i++ {
sub := r.subscribeWithBase(base, fmt.Sprintf(topicFormat, digest, i), validate, handle)
subscriptions = append(subscriptions, sub)
}
}
}
}
}()
}
// revalidate that our currently connected subnets are valid.
func (r *Service) reValidateSubscriptions(subscriptions map[uint64]*pubsub.Subscription,
wantedSubs []uint64, topicFormat string, digest [4]byte) {

View File

@@ -23,7 +23,6 @@ func (r *Service) beaconAggregateProofSubscriber(ctx context.Context, msg proto.
if a.Message.Aggregate == nil || a.Message.Aggregate.Data == nil {
return errors.New("nil aggregate")
}
r.setAggregatorIndexEpochSeen(a.Message.Aggregate.Data.Target.Epoch, a.Message.AggregatorIndex)
// Broadcast the aggregated attestation on a feed to notify other services in the beacon node
// of a received aggregated attestation.

View File

@@ -46,34 +46,30 @@ func (r *Service) committeeIndexBeaconAttestationSubscriber(ctx context.Context,
return r.attPool.SaveUnaggregatedAttestation(a)
}
func (r *Service) committeesCount() int {
activeValidatorIndices, err := r.chain.HeadValidatorsIndices(helpers.SlotToEpoch(r.chain.HeadSlot()))
if err != nil {
panic(err)
}
return int(helpers.SlotCommitteeCount(uint64(len(activeValidatorIndices))))
func (r *Service) subnetCount() int {
return int(params.BeaconNetworkConfig().AttestationSubnetCount)
}
func (r *Service) persistentCommitteeIndices() []uint64 {
return cache.CommitteeIDs.GetAllCommittees()
func (r *Service) persistentSubnetIndices() []uint64 {
return cache.SubnetIDs.GetAllSubnets()
}
func (r *Service) aggregatorCommitteeIndices(currentSlot uint64) []uint64 {
func (r *Service) aggregatorSubnetIndices(currentSlot uint64) []uint64 {
endEpoch := helpers.SlotToEpoch(currentSlot) + 1
endSlot := endEpoch * params.BeaconConfig().SlotsPerEpoch
commIds := []uint64{}
for i := currentSlot; i <= endSlot; i++ {
commIds = append(commIds, cache.CommitteeIDs.GetAggregatorCommitteeIDs(i)...)
commIds = append(commIds, cache.SubnetIDs.GetAggregatorSubnetIDs(i)...)
}
return sliceutil.SetUint64(commIds)
}
func (r *Service) attesterCommitteeIndices(currentSlot uint64) []uint64 {
func (r *Service) attesterSubnetIndices(currentSlot uint64) []uint64 {
endEpoch := helpers.SlotToEpoch(currentSlot) + 1
endSlot := endEpoch * params.BeaconConfig().SlotsPerEpoch
commIds := []uint64{}
for i := currentSlot; i <= endSlot; i++ {
commIds = append(commIds, cache.CommitteeIDs.GetAttesterCommitteeIDs(i)...)
commIds = append(commIds, cache.SubnetIDs.GetAttesterSubnetIDs(i)...)
}
return sliceutil.SetUint64(commIds)
}

View File

@@ -105,7 +105,7 @@ func TestService_committeeIndexBeaconAttestationSubscriber_ValidMessage(t *testi
}
att.Signature = sKeys[16].Sign(attRoot[:]).Marshal()
p.ReceivePubSub("/eth2/%x/committee_index0_beacon_attestation", att)
p.ReceivePubSub("/eth2/%x/beacon_attestation_0", att)
time.Sleep(time.Second * 1)

View File

@@ -13,7 +13,6 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/shared/attestationutil"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
@@ -108,7 +107,7 @@ func (r *Service) validateAggregatedAtt(ctx context.Context, signed *ethpb.Signe
}
}
// Verify validator index is within the aggregate's committee.
// Verify validator index is within the beacon committee.
if err := validateIndexInCommittee(ctx, s, signed.Message.Aggregate, signed.Message.AggregatorIndex); err != nil {
traceutil.AnnotateError(span, errors.Wrapf(err, "Could not validate index in committee"))
return pubsub.ValidationReject
@@ -169,7 +168,7 @@ func (r *Service) setAggregatorIndexEpochSeen(epoch uint64, aggregatorIndex uint
r.seenAttestationCache.Add(string(b), true)
}
// This validates the aggregator's index in state is within the attesting indices of the attestation.
// This validates the aggregator's index in state is within the beacon committee.
func validateIndexInCommittee(ctx context.Context, s *stateTrie.BeaconState, a *ethpb.Attestation, validatorIndex uint64) error {
ctx, span := trace.StartSpan(ctx, "sync.validateIndexInCommittee")
defer span.End()
@@ -178,9 +177,8 @@ func validateIndexInCommittee(ctx context.Context, s *stateTrie.BeaconState, a *
if err != nil {
return err
}
attestingIndices := attestationutil.AttestingIndices(a.AggregationBits, committee)
var withinCommittee bool
for _, i := range attestingIndices {
for _, i := range committee {
if validatorIndex == i {
withinCommittee = true
break
@@ -188,7 +186,7 @@ func validateIndexInCommittee(ctx context.Context, s *stateTrie.BeaconState, a *
}
if !withinCommittee {
return fmt.Errorf("validator index %d is not within the committee: %v",
validatorIndex, attestingIndices)
validatorIndex, committee)
}
return nil
}

View File

@@ -65,6 +65,37 @@ func TestVerifyIndexInCommittee_CanVerify(t *testing.T) {
}
}
func TestVerifyIndexInCommittee_ExistsInBeaconCommittee(t *testing.T) {
ctx := context.Background()
params.UseMinimalConfig()
defer params.UseMainnetConfig()
validators := uint64(64)
s, _ := testutil.DeterministicGenesisState(t, validators)
if err := s.SetSlot(params.BeaconConfig().SlotsPerEpoch); err != nil {
t.Fatal(err)
}
bf := []byte{0xff}
att := &ethpb.Attestation{Data: &ethpb.AttestationData{
Target: &ethpb.Checkpoint{Epoch: 0}},
AggregationBits: bf}
committee, err := helpers.BeaconCommitteeFromState(s, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil {
t.Error(err)
}
if err := validateIndexInCommittee(ctx, s, att, committee[0]); err != nil {
t.Fatal(err)
}
wanted := "validator index 1000 is not within the committee"
if err := validateIndexInCommittee(ctx, s, att, 1000); err == nil || !strings.Contains(err.Error(), wanted) {
t.Error("Did not receive wanted error")
}
}
func TestVerifySelection_NotAnAggregator(t *testing.T) {
ctx := context.Background()
params.UseMinimalConfig()
@@ -400,11 +431,11 @@ func TestValidateAggregateAndProofWithNewStateMgmt_CanValidate(t *testing.T) {
t.Fatal(err)
}
sig := privKeys[33].Sign(slotRoot[:])
sig := privKeys[22].Sign(slotRoot[:])
aggregateAndProof := &ethpb.AggregateAttestationAndProof{
SelectionProof: sig.Marshal(),
Aggregate: att,
AggregatorIndex: 33,
AggregatorIndex: 22,
}
signedAggregateAndProof := &ethpb.SignedAggregateAttestationAndProof{Message: aggregateAndProof}
@@ -416,7 +447,7 @@ func TestValidateAggregateAndProofWithNewStateMgmt_CanValidate(t *testing.T) {
if err != nil {
t.Error(err)
}
aggreSig := privKeys[33].Sign(signingRoot[:]).Marshal()
aggreSig := privKeys[22].Sign(signingRoot[:]).Marshal()
signedAggregateAndProof.Signature = aggreSig[:]
if err := beaconState.SetGenesisTime(uint64(time.Now().Unix())); err != nil {
@@ -524,11 +555,11 @@ func TestVerifyIndexInCommittee_SeenAggregatorEpoch(t *testing.T) {
t.Fatal(err)
}
sig := privKeys[33].Sign(slotRoot[:])
sig := privKeys[22].Sign(slotRoot[:])
aggregateAndProof := &ethpb.AggregateAttestationAndProof{
SelectionProof: sig.Marshal(),
Aggregate: att,
AggregatorIndex: 33,
AggregatorIndex: 22,
}
signedAggregateAndProof := &ethpb.SignedAggregateAttestationAndProof{Message: aggregateAndProof}
@@ -540,7 +571,7 @@ func TestVerifyIndexInCommittee_SeenAggregatorEpoch(t *testing.T) {
if err != nil {
t.Error(err)
}
aggreSig := privKeys[33].Sign(signingRoot[:]).Marshal()
aggreSig := privKeys[22].Sign(signingRoot[:]).Marshal()
signedAggregateAndProof.Signature = aggreSig[:]
if err := beaconState.SetGenesisTime(uint64(time.Now().Unix())); err != nil {

View File

@@ -10,6 +10,7 @@ import (
pubsub "github.com/libp2p/go-libp2p-pubsub"
eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
@@ -19,7 +20,7 @@ import (
// Validation
// - The attestation's committee index (attestation.data.index) is for the correct subnet.
// - The attestation is unaggregated -- that is, it has exactly one participating validator (len([bit for bit in attestation.aggregation_bits if bit == 0b1]) == 1).
// - The attestation is unaggregated -- that is, it has exactly one participating validator (len(get_attesting_indices(state, attestation.data, attestation.aggregation_bits)) == 1).
// - The block being voted for (attestation.data.beacon_block_root) passes validation.
// - attestation.data.slot is within the last ATTESTATION_PROPAGATION_SLOT_RANGE slots (attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= attestation.data.slot).
// - The signature of attestation is valid.
@@ -57,6 +58,11 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
if att.Data == nil {
return pubsub.ValidationReject
}
// Attestation aggregation bits must exist.
if att.AggregationBits == nil {
return pubsub.ValidationReject
}
// Verify this the first attestation received for the participating validator for the slot.
if s.hasSeenCommitteeIndicesSlot(att.Data.Slot, att.Data.CommitteeIndex, att.AggregationBits) {
return pubsub.ValidationIgnore
@@ -69,12 +75,34 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
traceutil.AnnotateError(span, err)
return pubsub.ValidationIgnore
}
if !strings.HasPrefix(originalTopic, fmt.Sprintf(format, digest, att.Data.CommitteeIndex)) {
preState, err := s.chain.AttestationPreState(ctx, att)
if err != nil {
log.WithError(err).Error("Failed to retrieve pre state")
traceutil.AnnotateError(span, err)
return pubsub.ValidationIgnore
}
valCount, err := helpers.ActiveValidatorCount(preState, helpers.SlotToEpoch(att.Data.Slot))
if err != nil {
log.WithError(err).Error("Could not retrieve active validator count")
traceutil.AnnotateError(span, err)
return pubsub.ValidationIgnore
}
subnet := helpers.ComputeSubnetForAttestation(valCount, att)
if !strings.HasPrefix(originalTopic, fmt.Sprintf(format, digest, subnet)) {
return pubsub.ValidationReject
}
committee, err := helpers.BeaconCommitteeFromState(preState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil {
traceutil.AnnotateError(span, err)
return pubsub.ValidationIgnore
}
// Attestation must be unaggregated.
if att.AggregationBits == nil || att.AggregationBits.Count() != 1 {
// Attestation must be unaggregated and the bit index must exist in the range of committee indices.
// Note: eth2 spec suggests (len(get_attesting_indices(state, attestation.data, attestation.aggregation_bits)) == 1)
// however this validation can be achieved without use of get_attesting_indices which is an O(n) lookup.
if att.AggregationBits.Count() != 1 || att.AggregationBits.BitIndices()[0] >= len(committee) {
return pubsub.ValidationReject
}
@@ -95,12 +123,6 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
return pubsub.ValidationIgnore
}
preState, err := s.chain.AttestationPreState(ctx, att)
if err != nil {
log.WithError(err).Error("Failed to retrieve pre state")
traceutil.AnnotateError(span, err)
return pubsub.ValidationIgnore
}
// Attestation's signature is a valid BLS signature and belongs to correct public key..
if !featureconfig.Get().DisableStrictAttestationPubsubVerification {
if err := blocks.VerifyAttestation(ctx, preState, att); err != nil {

Some files were not shown because too many files have changed in this diff Show More