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

View File

@@ -45,6 +45,7 @@ type HeadFetcher interface {
HeadValidatorsIndices(epoch uint64) ([]uint64, error) HeadValidatorsIndices(epoch uint64) ([]uint64, error)
HeadSeed(epoch uint64) ([32]byte, error) HeadSeed(epoch uint64) ([32]byte, error)
HeadGenesisValidatorRoot() [32]byte HeadGenesisValidatorRoot() [32]byte
HeadETH1Data() *ethpb.Eth1Data
ProtoArrayStore() *protoarray.Store ProtoArrayStore() *protoarray.Store
} }
@@ -179,6 +180,14 @@ func (s *Service) HeadGenesisValidatorRoot() [32]byte {
return s.headGenesisValidatorRoot() 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. // ProtoArrayStore returns the proto array store object.
func (s *Service) ProtoArrayStore() *protoarray.Store { func (s *Service) ProtoArrayStore() *protoarray.Store {
return s.forkChoiceStore.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") 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" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/go-ssz" "github.com/prysmaticlabs/go-ssz"
"github.com/prysmaticlabs/prysm/beacon-chain/cache" "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/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state" "github.com/prysmaticlabs/prysm/beacon-chain/core/state"
testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" 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) beaconState, privs := testutil.DeterministicGenesisState(t, 32)
genesisBlock := blocks.NewGenesisBlock([]byte{}) genesisBlock := testutil.NewBeaconBlock()
bodyRoot, err := stateutil.BlockRoot(genesisBlock.Block) bodyRoot, err := stateutil.BlockRoot(genesisBlock.Block)
if err != nil { if err != nil {
t.Fatal(err) 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)) // current_epoch = compute_epoch_at_slot(get_current_slot(store))
// # Use GENESIS_EPOCH for previous when genesis to avoid underflow // # Use GENESIS_EPOCH for previous when genesis to avoid underflow
// previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else GENESIS_EPOCH // 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 in [current_epoch, previous_epoch]
// assert target.epoch == compute_epoch_at_slot(attestation.data.slot) // 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 // # 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 // 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 // # 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 // 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: // for i in indexed_attestation.attesting_indices:
// if i not in store.latest_messages or target.epoch > store.latest_messages[i].epoch: // 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) // 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) { func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]uint64, error) {
ctx, span := trace.StartSpan(ctx, "blockchain.onAttestation") ctx, span := trace.StartSpan(ctx, "blockchain.onAttestation")
defer span.End() defer span.End()
@@ -83,7 +82,6 @@ func (s *Service) onAttestation(ctx context.Context, a *ethpb.Attestation) ([]ui
} }
tgt := stateTrie.CopyCheckpoint(a.Data.Target) tgt := stateTrie.CopyCheckpoint(a.Data.Target)
tgtSlot := helpers.StartSlot(tgt.Epoch)
if helpers.SlotToEpoch(a.Data.Slot) != a.Data.Target.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) 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 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. // Verify attestation beacon block is known and not from the future.
if err := s.verifyBeaconBlock(ctx, a.Data); err != nil { if err := s.verifyBeaconBlock(ctx, a.Data); err != nil {
return nil, errors.Wrap(err, "could not verify attestation beacon block") 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. // 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 { if err := helpers.VerifySlotTime(genesisTime, a.Data.Slot+1, params.BeaconNetworkConfig().MaximumGossipClockDisparity); err != nil {
return nil, err return nil, err

View File

@@ -143,6 +143,20 @@ func (s *Service) verifyBeaconBlock(ctx context.Context, data *ethpb.Attestation
return nil 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. // verifyAttestation validates input attestation is valid.
func (s *Service) verifyAttestation(ctx context.Context, baseState *stateTrie.BeaconState, a *ethpb.Attestation) (*ethpb.IndexedAttestation, error) { 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) 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") 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: // elif block.slot == slot:
// return root // return root
// else: // 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) { func (s *Service) ancestor(ctx context.Context, root []byte, slot uint64) ([]byte, error) {
ctx, span := trace.StartSpan(ctx, "forkchoice.ancestor") ctx, span := trace.StartSpan(ctx, "forkchoice.ancestor")
defer span.End() defer span.End()

View File

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

View File

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

View File

@@ -37,6 +37,7 @@ type ChainService struct {
Genesis time.Time Genesis time.Time
ValidatorsRoot [32]byte ValidatorsRoot [32]byte
Fork *pb.Fork Fork *pb.Fork
ETH1Data *ethpb.Eth1Data
DB db.Database DB db.Database
stateNotifier statefeed.Notifier stateNotifier statefeed.Notifier
blockNotifier blockfeed.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) 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. // ProtoArrayStore mocks the same method in the chain service.
func (ms *ChainService) ProtoArrayStore() *protoarray.Store { func (ms *ChainService) ProtoArrayStore() *protoarray.Store {
return ms.ForkChoiceStore return ms.ForkChoiceStore
@@ -252,6 +258,12 @@ func (ms *ChainService) IsValidAttestation(ctx context.Context, att *ethpb.Attes
return ms.ValidAttestation 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. // ClearCachedStates does nothing.
func (ms *ChainService) ClearCachedStates() {} func (ms *ChainService) ClearCachedStates() {}

View File

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

View File

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

View File

@@ -5,59 +5,59 @@ import (
"testing" "testing"
) )
func TestCommitteeIDCache_RoundTrip(t *testing.T) { func TestSubnetIDsCache_RoundTrip(t *testing.T) {
c := newCommitteeIDs() c := newSubnetIDs()
slot := uint64(100) slot := uint64(100)
committeeIDs := c.GetAggregatorCommitteeIDs(slot) committeeIDs := c.GetAggregatorSubnetIDs(slot)
if len(committeeIDs) != 0 { if len(committeeIDs) != 0 {
t.Errorf("Empty cache returned an object: %v", committeeIDs) t.Errorf("Empty cache returned an object: %v", committeeIDs)
} }
c.AddAggregatorCommiteeID(slot, 1) c.AddAggregatorSubnetID(slot, 1)
res := c.GetAggregatorCommitteeIDs(slot) res := c.GetAggregatorSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{1}) { if !reflect.DeepEqual(res, []uint64{1}) {
t.Error("Expected equal value to return from cache") t.Error("Expected equal value to return from cache")
} }
c.AddAggregatorCommiteeID(slot, 2) c.AddAggregatorSubnetID(slot, 2)
res = c.GetAggregatorCommitteeIDs(slot) res = c.GetAggregatorSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{1, 2}) { if !reflect.DeepEqual(res, []uint64{1, 2}) {
t.Error("Expected equal value to return from cache") t.Error("Expected equal value to return from cache")
} }
c.AddAggregatorCommiteeID(slot, 3) c.AddAggregatorSubnetID(slot, 3)
res = c.GetAggregatorCommitteeIDs(slot) res = c.GetAggregatorSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{1, 2, 3}) { if !reflect.DeepEqual(res, []uint64{1, 2, 3}) {
t.Error("Expected equal value to return from cache") t.Error("Expected equal value to return from cache")
} }
committeeIDs = c.GetAttesterCommitteeIDs(slot) committeeIDs = c.GetAttesterSubnetIDs(slot)
if len(committeeIDs) != 0 { if len(committeeIDs) != 0 {
t.Errorf("Empty cache returned an object: %v", committeeIDs) t.Errorf("Empty cache returned an object: %v", committeeIDs)
} }
c.AddAttesterCommiteeID(slot, 11) c.AddAttesterSubnetID(slot, 11)
res = c.GetAttesterCommitteeIDs(slot) res = c.GetAttesterSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{11}) { if !reflect.DeepEqual(res, []uint64{11}) {
t.Error("Expected equal value to return from cache") t.Error("Expected equal value to return from cache")
} }
c.AddAttesterCommiteeID(slot, 22) c.AddAttesterSubnetID(slot, 22)
res = c.GetAttesterCommitteeIDs(slot) res = c.GetAttesterSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{11, 22}) { if !reflect.DeepEqual(res, []uint64{11, 22}) {
t.Error("Expected equal value to return from cache") t.Error("Expected equal value to return from cache")
} }
c.AddAttesterCommiteeID(slot, 33) c.AddAttesterSubnetID(slot, 33)
res = c.GetAttesterCommitteeIDs(slot) res = c.GetAttesterSubnetIDs(slot)
if !reflect.DeepEqual(res, []uint64{11, 22, 33}) { if !reflect.DeepEqual(res, []uint64{11, 22, 33}) {
t.Error("Expected equal value to return from cache") t.Error("Expected equal value to return from cache")
} }
} }
func TestCommitteeIDs_PersistentCommitteeRoundtrip(t *testing.T) { func TestSubnetIDsCache_PersistentCommitteeRoundtrip(t *testing.T) {
pubkeySet := [][48]byte{} pubkeySet := [][48]byte{}
c := newCommitteeIDs() c := newSubnetIDs()
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
pubkey := [48]byte{byte(i)} pubkey := [48]byte{byte(i)}
@@ -68,7 +68,7 @@ func TestCommitteeIDs_PersistentCommitteeRoundtrip(t *testing.T) {
for i := 0; i < 20; i++ { for i := 0; i < 20; i++ {
pubkey := [48]byte{byte(i)} pubkey := [48]byte{byte(i)}
idxs, ok, _ := c.GetPersistentCommittees(pubkey[:]) idxs, ok, _ := c.GetPersistentSubnets(pubkey[:])
if !ok { if !ok {
t.Errorf("Couldn't find entry in cache for pubkey %#x", pubkey) t.Errorf("Couldn't find entry in cache for pubkey %#x", pubkey)
continue continue
@@ -77,7 +77,7 @@ func TestCommitteeIDs_PersistentCommitteeRoundtrip(t *testing.T) {
t.Fatalf("Wanted index of %d but got %d", i, idxs[0]) t.Fatalf("Wanted index of %d but got %d", i, idxs[0])
} }
} }
coms := c.GetAllCommittees() coms := c.GetAllSubnets()
if len(coms) != 20 { if len(coms) != 20 {
t.Errorf("Number of committees is not %d but is %d", 20, len(coms)) 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 { if err != nil {
return errors.Wrap(err, "could not get signing root") return errors.Wrap(err, "could not get signing root")
} }
sigRoot := &pb.SigningRoot{ signingData := &pb.SigningData{
ObjectRoot: root[:], ObjectRoot: root[:],
Domain: domain, Domain: domain,
} }
ctrRoot, err := ssz.HashTreeRoot(sigRoot) ctrRoot, err := ssz.HashTreeRoot(signingData)
if err != nil { if err != nil {
return errors.Wrap(err, "could not get container root") 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 { if err != nil {
return errors.Wrap(err, "could not convert bytes to signature") return errors.Wrap(err, "could not convert bytes to signature")
} }
ctr := &pb.SigningRoot{ signingData := &pb.SigningData{
ObjectRoot: signedData, ObjectRoot: signedData,
Domain: domain, Domain: domain,
} }
root, err := ssz.HashTreeRoot(ctr) root, err := ssz.HashTreeRoot(signingData)
if err != nil { if err != nil {
return errors.Wrap(err, "could not hash container") 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) return fmt.Errorf("expected current epoch >= exit epoch, received %d < %d", currentEpoch, exit.Epoch)
} }
// Verify the validator has been active long enough. // 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( return fmt.Errorf(
"validator has not been active long enough to exit, wanted epoch %d >= %d", "validator has not been active long enough to exit, wanted epoch %d >= %d",
currentEpoch, currentEpoch,
validator.ActivationEpoch()+params.BeaconConfig().PersistentCommitteePeriod, validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod,
) )
} }
domain, err := helpers.Domain(fork, exit.Epoch, params.BeaconConfig().DomainVoluntaryExit, genesisRoot) 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 { if err != nil {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -2018,7 +2018,7 @@ func TestProcessVoluntaryExits_AppliesCorrectStatus(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View File

@@ -43,6 +43,7 @@ go_test(
"//beacon-chain/state:go_default_library", "//beacon-chain/state:go_default_library",
"//proto/beacon/p2p/v1:go_default_library", "//proto/beacon/p2p/v1:go_default_library",
"//shared/attestationutil:go_default_library", "//shared/attestationutil:go_default_library",
"//shared/mathutil:go_default_library",
"//shared/params:go_default_library", "//shared/params:go_default_library",
"//shared/testutil:go_default_library", "//shared/testutil:go_default_library",
"@com_github_gogo_protobuf//proto: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" stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/attestationutil" "github.com/prysmaticlabs/prysm/shared/attestationutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/traceutil" "github.com/prysmaticlabs/prysm/shared/traceutil"
"go.opencensus.io/trace" "go.opencensus.io/trace"
) )
@@ -90,12 +91,14 @@ func AttestedPrevEpoch(s *stateTrie.BeaconState, a *pb.PendingAttestation) (bool
votedTarget = true votedTarget = true
} }
same, err = SameHead(s, a) if votedTarget {
if err != nil { same, err = SameHead(s, a)
return false, false, false, errors.Wrap(err, "could not check same head") if err != nil {
} return false, false, false, errors.Wrap(err, "could not check same head")
if same { }
votedHead = true if same {
votedHead = true
}
} }
} }
return votedPrevEpoch, votedTarget, votedHead, nil 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 return bBal
} }

View File

@@ -50,21 +50,23 @@ func TestUpdateValidator_InclusionOnlyCountsPrevEpoch(t *testing.T) {
func TestUpdateBalance(t *testing.T) { func TestUpdateBalance(t *testing.T) {
vp := []*precompute.Validator{ vp := []*precompute.Validator{
{IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100}, {IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsCurrentEpochTargetAttester: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100}, {IsCurrentEpochTargetAttester: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsCurrentEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100}, {IsCurrentEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 100}, {IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsPrevEpochAttester: true, IsPrevEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100}, {IsPrevEpochAttester: true, IsPrevEpochTargetAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100}, {IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsPrevEpochAttester: true, IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100}, {IsPrevEpochAttester: true, IsPrevEpochHeadAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsSlashed: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100}, {IsSlashed: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
} }
wantedPBal := &precompute.Balance{ wantedPBal := &precompute.Balance{
CurrentEpochAttested: 200, ActiveCurrentEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
CurrentEpochTargetAttested: 200, ActivePrevEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochAttested: 300, CurrentEpochAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochTargetAttested: 100, CurrentEpochTargetAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochHeadAttested: 200, PrevEpochAttested: 300 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochTargetAttested: 100 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochHeadAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
} }
pBal := precompute.UpdateBalance(vp, &precompute.Balance{}) pBal := precompute.UpdateBalance(vp, &precompute.Balance{})
if !reflect.DeepEqual(pBal, wantedPBal) { if !reflect.DeepEqual(pBal, wantedPBal) {
@@ -220,7 +222,7 @@ func TestProcessAttestations(t *testing.T) {
if err := beaconState.SetBlockRoots(br); err != nil { if err := beaconState.SetBlockRoots(br); err != nil {
t.Fatal(err) t.Fatal(err)
} }
att2.Data.Target.Root = rt[:] att2.Data.Target.Root = newRt[:]
att2.Data.BeaconBlockRoot = newRt[:] att2.Data.BeaconBlockRoot = newRt[:]
err := beaconState.SetPreviousEpochAttestations([]*pb.PendingAttestation{{Data: att1.Data, AggregationBits: bf}}) err := beaconState.SetPreviousEpochAttestations([]*pb.PendingAttestation{{Data: att1.Data, AggregationBits: bf}})
if err != nil { if err != nil {
@@ -260,8 +262,37 @@ func TestProcessAttestations(t *testing.T) {
if !pVals[i].IsPrevEpochAttester { if !pVals[i].IsPrevEpochAttester {
t.Error("Not a prev epoch attester") t.Error("Not a prev epoch attester")
} }
if !pVals[i].IsPrevEpochTargetAttester {
t.Error("Not a prev epoch target attester")
}
if !pVals[i].IsPrevEpochHeadAttester { if !pVals[i].IsPrevEpochHeadAttester {
t.Error("Not a prev epoch head attester") 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 { if err := state.ReadFromEveryValidator(func(idx int, val *stateTrie.ReadOnlyValidator) error {
// Was validator withdrawable or slashed // Was validator withdrawable or slashed
withdrawable := currentEpoch >= val.WithdrawableEpoch() withdrawable := prevEpoch+1 >= val.WithdrawableEpoch()
pVal := &Validator{ pVal := &Validator{
IsSlashed: val.Slashed(), IsSlashed: val.Slashed(),
IsWithdrawableCurrentEpoch: withdrawable, IsWithdrawableCurrentEpoch: withdrawable,

View File

@@ -2,7 +2,6 @@ package precompute
import ( import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state" stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/shared/mathutil" "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") 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 { if err != nil {
return nil, errors.Wrap(err, "could not get attestation delta") 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 { if err != nil {
return nil, errors.Wrap(err, "could not get attestation delta") return nil, errors.Wrap(err, "could not get attestation delta")
} }
validatorBals := state.Balances()
for i := 0; i < numOfVals; i++ { for i := 0; i < numOfVals; i++ {
vp[i].BeforeEpochTransitionBalance, err = state.BalanceAtIndex(uint64(i)) vp[i].BeforeEpochTransitionBalance = validatorBals[i]
if err != nil {
return nil, errors.Wrap(err, "could not get validator balance before epoch")
}
if err := helpers.IncreaseBalance(state, uint64(i), attsRewards[i]+proposerRewards[i]); err != nil { // Compute the post balance of the validator after accounting for the
return nil, err // attester and proposer rewards and penalties.
} validatorBals[i] = helpers.IncreaseBalanceWithVal(validatorBals[i], attsRewards[i]+proposerRewards[i])
if err := helpers.DecreaseBalance(state, uint64(i), attsPenalties[i]); err != nil { validatorBals[i] = helpers.DecreaseBalanceWithVal(validatorBals[i], attsPenalties[i])
return nil, err
}
vp[i].AfterEpochTransitionBalance, err = state.BalanceAtIndex(uint64(i)) vp[i].AfterEpochTransitionBalance = validatorBals[i]
if err != nil { }
return nil, errors.Wrap(err, "could not get validator balance after epoch")
} if err := state.SetBalances(validatorBals); err != nil {
return nil, errors.Wrap(err, "could not set validator balances")
} }
return state, nil 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. // 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() numOfVals := state.NumValidators()
rewards := make([]uint64, numOfVals) rewards := make([]uint64, numOfVals)
penalties := make([]uint64, numOfVals) penalties := make([]uint64, numOfVals)
prevEpoch := helpers.PrevEpoch(state)
finalizedEpoch := state.FinalizedCheckpointEpoch()
for i, v := range vp { 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 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) eligible := v.IsActivePrevEpoch || (v.IsSlashed && !v.IsWithdrawableCurrentEpoch)
if !eligible || pBal.ActiveCurrentEpoch == 0 { if !eligible || pBal.ActiveCurrentEpoch == 0 {
return 0, 0 return 0, 0
} }
e := helpers.PrevEpoch(state) baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch
effectiveBalanceIncrement := params.BeaconConfig().EffectiveBalanceIncrement
vb := v.CurrentEpochEffectiveBalance 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) r, p := uint64(0), uint64(0)
currentEpochBalance := pBal.ActiveCurrentEpoch / effectiveBalanceIncrement
// Process source reward / penalty // Process source reward / penalty
if v.IsPrevEpochAttester && !v.IsSlashed { if v.IsPrevEpochAttester && !v.IsSlashed {
inc := params.BeaconConfig().EffectiveBalanceIncrement
rewardNumerator := br * pBal.PrevEpochAttested / inc
r += rewardNumerator / (pBal.ActiveCurrentEpoch / inc)
proposerReward := br / params.BeaconConfig().ProposerRewardQuotient proposerReward := br / params.BeaconConfig().ProposerRewardQuotient
maxAtteserReward := br - proposerReward maxAttesterReward := br - proposerReward
r += maxAtteserReward / v.InclusionDistance 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 { } else {
p += br p += br
} }
// Process target reward / penalty // Process target reward / penalty
if v.IsPrevEpochTargetAttester && !v.IsSlashed { if v.IsPrevEpochTargetAttester && !v.IsSlashed {
inc := params.BeaconConfig().EffectiveBalanceIncrement if isInInactivityLeak(prevEpoch, finalizedEpoch) {
rewardNumerator := br * pBal.PrevEpochAttested / inc // Since full base reward will be canceled out by inactivity penalty deltas,
r += rewardNumerator / (pBal.ActiveCurrentEpoch / inc) // optimal participation receives full base reward compensation here.
r += br
} else {
rewardNumerator := br * (pBal.PrevEpochTargetAttested / effectiveBalanceIncrement)
r += rewardNumerator / currentEpochBalance
}
} else { } else {
p += br p += br
} }
// Process head reward / penalty // Process head reward / penalty
if v.IsPrevEpochHeadAttester && !v.IsSlashed { if v.IsPrevEpochHeadAttester && !v.IsSlashed {
inc := params.BeaconConfig().EffectiveBalanceIncrement if isInInactivityLeak(prevEpoch, finalizedEpoch) {
rewardNumerator := br * pBal.PrevEpochAttested / inc // Since full base reward will be canceled out by inactivity penalty deltas,
r += rewardNumerator / (pBal.ActiveCurrentEpoch / inc) // optimal participation receives full base reward compensation here.
r += br
} else {
rewardNumerator := br * (pBal.PrevEpochHeadAttested / effectiveBalanceIncrement)
r += rewardNumerator / currentEpochBalance
}
} else { } else {
p += br p += br
} }
// Process finality delay penalty // Process finality delay penalty
finalizedEpoch := state.FinalizedCheckpointEpoch() finalityDelay := finalityDelay(prevEpoch, finalizedEpoch)
finalityDelay := e - finalizedEpoch
if finalityDelay > params.BeaconConfig().MinEpochsToInactivityPenalty { if isInInactivityLeak(prevEpoch, finalizedEpoch) {
p += params.BeaconConfig().BaseRewardsPerEpoch * br // If validator is performing optimally, this cancels all rewards for a neutral balance.
if !v.IsPrevEpochTargetAttester { 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 p += vb * finalityDelay / params.BeaconConfig().InactivityPenaltyQuotient
} }
} }
return r, p 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. // 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() numofVals := state.NumValidators()
rewards := make([]uint64, numofVals) rewards := make([]uint64, numofVals)
totalBalance := pBal.ActiveCurrentEpoch 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 baseRewardFactor := params.BeaconConfig().BaseRewardFactor
balanceSqrt := mathutil.IntegerSquareRoot(totalBalance)
baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch
proposerRewardQuotient := params.BeaconConfig().ProposerRewardQuotient proposerRewardQuotient := params.BeaconConfig().ProposerRewardQuotient
for _, v := range vp { 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 vBalance := v.CurrentEpochEffectiveBalance
baseReward := vBalance * baseRewardFactor / balanceSqrt / baseRewardsPerEpoch baseReward := vBalance * baseRewardFactor / balanceSqrt / baseRewardsPerEpoch
proposerReward := baseReward / proposerRewardQuotient proposerReward := baseReward / proposerRewardQuotient
@@ -145,3 +172,21 @@ func proposerDeltaPrecompute(state *stateTrie.BeaconState, pBal *Balance, vp []*
} }
return rewards, nil 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/core/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/state" "github.com/prysmaticlabs/prysm/beacon-chain/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/mathutil"
"github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/params"
) )
@@ -90,6 +91,14 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) 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) vp, bp, err := New(context.Background(), state)
if err != nil { if err != nil {
@@ -100,7 +109,11 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
t.Fatal(err) 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -113,18 +126,21 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
attestedIndices := []uint64{55, 1339, 1746, 1811, 1569, 1413} attestedIndices := []uint64{55, 1339, 1746, 1811, 1569}
for _, i := range attestedIndices { for _, i := range attestedIndices {
base, err := epoch.BaseReward(state, i) base, err := epoch.BaseReward(state, i)
if err != nil { if err != nil {
t.Errorf("Could not get base reward: %v", err) t.Errorf("Could not get base reward: %v", err)
} }
// Base rewards for getting source right // 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 // Base rewards for proposer and attesters working together getting attestation
// on chain in the fatest manner // on chain in the fatest manner
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
wanted += (base - proposerReward) * params.BeaconConfig().MinAttestationInclusionDelay wanted += (base-proposerReward)*params.BeaconConfig().MinAttestationInclusionDelay - 1
if rewards[i] != wanted { if rewards[i] != wanted {
t.Errorf("Wanted reward balance %d, got %d for validator with index %d", wanted, rewards[i], i) 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} nonAttestedIndices := []uint64{434, 677, 872, 791}
for _, i := range nonAttestedIndices { for _, i := range nonAttestedIndices {
base, err := epoch.BaseReward(state, i) 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. pBal.ActiveCurrentEpoch = 0 // Could cause a divide by zero panic.
_, _, err = attestationDeltas(state, pBal, pVals) _, _, err = AttestationsDelta(state, pBal, pVals)
if err != nil { if err != nil {
t.Fatal(err) 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 { func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
validators := make([]*ethpb.Validator, validatorCount) validators := make([]*ethpb.Validator, validatorCount)
for i := 0; i < len(validators); i++ { for i := 0; i < len(validators); i++ {
@@ -234,3 +330,133 @@ func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
CurrentJustifiedCheckpoint: &ethpb.Checkpoint{}, 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 { func IsAggregated(attestation *ethpb.Attestation) bool {
return attestation.AggregationBits.Count() > 1 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 ( import (
"bytes" "bytes"
"sort" "sort"
"strconv"
"testing" "testing"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
@@ -348,3 +349,53 @@ func TestAggregateSignature_False(t *testing.T) {
t.Error("Signature not suppose to verify") 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 { if err != nil {
return err 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. // 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 { if err != nil {
return err return err
} }
if delta > balAtIdx { return state.UpdateBalancesAtIndex(idx, DecreaseBalanceWithVal(balAtIdx, delta))
return state.UpdateBalancesAtIndex(idx, 0) }
}
return state.UpdateBalancesAtIndex(idx, 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. // failed to verify.
var ErrSigFailedToVerify = errors.New("signature did not 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: // Spec pseudocode definition:
// def compute_signing_root(ssz_object: SSZObject, domain: Domain) -> Root: // 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), // object_root=hash_tree_root(ssz_object),
// domain=domain, // domain=domain,
// ) // ))
// return hash_tree_root(domain_wrapped_object)
func ComputeSigningRoot(object interface{}, domain []byte) ([32]byte, error) { func ComputeSigningRoot(object interface{}, domain []byte) ([32]byte, error) {
return signingRoot(func() ([32]byte, error) { return signingData(func() ([32]byte, error) {
switch object.(type) { switch object.(type) {
case *ethpb.BeaconBlock: case *ethpb.BeaconBlock:
return stateutil.BlockRoot(object.(*ethpb.BeaconBlock)) return stateutil.BlockRoot(object.(*ethpb.BeaconBlock))
@@ -48,14 +47,14 @@ func ComputeSigningRoot(object interface{}, domain []byte) ([32]byte, error) {
}, domain) }, domain)
} }
// Computes the signing root by utilising the provided root function and then // Computes the signing data by utilising the provided root function and then
// returning the signing root of the container object. // returning the signing data of the container object.
func signingRoot(rootFunc func() ([32]byte, error), domain []byte) ([32]byte, error) { func signingData(rootFunc func() ([32]byte, error), domain []byte) ([32]byte, error) {
objRoot, err := rootFunc() objRoot, err := rootFunc()
if err != nil { if err != nil {
return [32]byte{}, err return [32]byte{}, err
} }
container := &p2ppb.SigningRoot{ container := &p2ppb.SigningData{
ObjectRoot: objRoot[:], ObjectRoot: objRoot[:],
Domain: domain, Domain: domain,
} }
@@ -92,7 +91,7 @@ func VerifyBlockSigningRoot(blk *ethpb.BeaconBlock, pub []byte, signature []byte
if err != nil { if err != nil {
return errors.Wrap(err, "could not convert bytes to signature") 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 // utilize custom block hashing function
return stateutil.BlockRoot(blk) return stateutil.BlockRoot(blk)
}, domain) }, domain)
@@ -115,7 +114,7 @@ func VerifyBlockHeaderSigningRoot(blkHdr *ethpb.BeaconBlockHeader, pub []byte, s
if err != nil { if err != nil {
return errors.Wrap(err, "could not convert bytes to signature") 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) return stateutil.BlockHeaderRoot(blkHdr)
}, domain) }, domain)
if err != nil { if err != nil {

View File

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

View File

@@ -54,7 +54,10 @@ go_test(
"transition_fuzz_test.go", "transition_fuzz_test.go",
"transition_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"], embed = [":go_default_library"],
shard_count = 3, shard_count = 3,
deps = [ deps = [

View File

@@ -16,7 +16,7 @@ import (
var runAmount = 25 var runAmount = 25
func TestBenchmarkExecuteStateTransition(t *testing.T) { func TestExecuteStateTransition_FullBlock(t *testing.T) {
benchutil.SetBenchmarkConfig() benchutil.SetBenchmarkConfig()
beaconState, err := benchutil.PreGenState1Epoch() beaconState, err := benchutil.PreGenState1Epoch()
if err != nil { 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(), Eth1DepositIndex: preState.Eth1DepositIndex(),
} }
bodyRoot, err := ssz.HashTreeRoot(&ethpb.BeaconBlockBody{}) bodyRoot, err := stateutil.BlockBodyRoot(&ethpb.BeaconBlockBody{})
if err != nil { 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{ 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 { if err := beaconState.SetSlot(beaconState.Slot() - 1); err != nil {
t.Fatal(err) 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.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{ Block: &ethpb.BeaconBlock{
ProposerIndex: 74, ProposerIndex: proposerIdx,
Slot: beaconState.Slot() + 1, Slot: beaconState.Slot() + 1,
ParentRoot: parentRoot[:], ParentRoot: parentRoot[:],
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{
@@ -371,7 +380,7 @@ func TestProcessBlock_PassesProcessingConditions(t *testing.T) {
proposerSlashIdx := uint64(3) proposerSlashIdx := uint64(3)
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -754,7 +763,7 @@ func BenchmarkProcessBlk_65536Validators_FullBlock(b *testing.B) {
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
ctr := &pb.SigningRoot{ ctr := &pb.SigningData{
ObjectRoot: buf, ObjectRoot: buf,
Domain: domain, Domain: domain,
} }
@@ -902,9 +911,17 @@ func TestProcessBlk_AttsBasedOnValidatorCount(t *testing.T) {
t.Fatal(err) 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{ blk := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{ Block: &ethpb.BeaconBlock{
ProposerIndex: 156, ProposerIndex: proposerIdx,
Slot: s.Slot() + 1, Slot: s.Slot() + 1,
ParentRoot: parentRoot[:], ParentRoot: parentRoot[:],
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{

View File

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

View File

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

View File

@@ -17,13 +17,13 @@ var (
DepositContractFlag = &cli.StringFlag{ DepositContractFlag = &cli.StringFlag{
Name: "deposit-contract", 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.", 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 defines the host on which the RPC server should listen.
RPCHost = &cli.StringFlag{ RPCHost = &cli.StringFlag{
Name: "rpc-host", Name: "rpc-host",
Usage: "Host on which the RPC server should listen", 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 defines a beacon node RPC port to open.
RPCPort = &cli.IntFlag{ RPCPort = &cli.IntFlag{
@@ -82,7 +82,7 @@ var (
ContractDeploymentBlock = &cli.IntFlag{ ContractDeploymentBlock = &cli.IntFlag{
Name: "contract-deployment-block", Name: "contract-deployment-block",
Usage: "The eth1 block in which the deposit contract was deployed.", 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 is the percentage of current live allocations at which the garbage collector is to run.
SetGCPercent = &cli.IntFlag{ SetGCPercent = &cli.IntFlag{

View File

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

View File

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

View File

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

View File

@@ -18,33 +18,49 @@ import (
// GossipTypeMapping. // GossipTypeMapping.
var ErrMessageNotMapped = errors.New("message type is not mapped to a PubSub topic") 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. // Broadcast a message to the p2p network.
func (s *Service) Broadcast(ctx context.Context, msg proto.Message) error { func (s *Service) Broadcast(ctx context.Context, msg proto.Message) error {
ctx, span := trace.StartSpan(ctx, "p2p.Broadcast") ctx, span := trace.StartSpan(ctx, "p2p.Broadcast")
defer span.End() defer span.End()
forkDigest, err := s.forkDigest() forkDigest, err := s.forkDigest()
if err != nil { if err != nil {
err := errors.Wrap(err, "could not retrieve fork digest")
traceutil.AnnotateError(span, err)
return err return err
} }
var topic string topic, ok := GossipTypeMapping[reflect.TypeOf(msg)]
switch msg.(type) { if !ok {
case *eth.Attestation: traceutil.AnnotateError(span, ErrMessageNotMapped)
topic = attestationToTopic(msg.(*eth.Attestation), forkDigest) return ErrMessageNotMapped
default:
var ok bool
topic, ok = GossipTypeMapping[reflect.TypeOf(msg)]
if !ok {
traceutil.AnnotateError(span, ErrMessageNotMapped)
return ErrMessageNotMapped
}
topic = fmt.Sprintf(topic, forkDigest)
} }
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)) span.AddAttributes(trace.StringAttribute("topic", topic))
buf := new(bytes.Buffer) 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") err := errors.Wrap(err, "could not encode message")
traceutil.AnnotateError(span, err) traceutil.AnnotateError(span, err)
return err return err
@@ -64,11 +80,6 @@ func (s *Service) Broadcast(ctx context.Context, msg proto.Message) error {
return nil return nil
} }
const attestationSubnetTopicFormat = "/eth2/%x/committee_index%d_beacon_attestation" func attestationToTopic(subnet uint64, forkDigest [4]byte) string {
return fmt.Sprintf(attestationSubnetTopicFormat, forkDigest, subnet)
func attestationToTopic(att *eth.Attestation, forkDigest [4]byte) string {
if att == nil || att.Data == nil {
return ""
}
return fmt.Sprintf(attestationSubnetTopicFormat, forkDigest, att.Data.CommitteeIndex)
} }

View File

@@ -10,6 +10,7 @@ import (
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing" p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
testpb "github.com/prysmaticlabs/prysm/proto/testing" testpb "github.com/prysmaticlabs/prysm/proto/testing"
"github.com/prysmaticlabs/prysm/shared/testutil" "github.com/prysmaticlabs/prysm/shared/testutil"
@@ -109,36 +110,33 @@ func TestService_Attestation_Subnet(t *testing.T) {
att: &eth.Attestation{ att: &eth.Attestation{
Data: &eth.AttestationData{ Data: &eth.AttestationData{
CommitteeIndex: 0, CommitteeIndex: 0,
Slot: 2,
}, },
}, },
topic: "/eth2/00000000/committee_index0_beacon_attestation", topic: "/eth2/00000000/beacon_attestation_2",
}, },
{ {
att: &eth.Attestation{ att: &eth.Attestation{
Data: &eth.AttestationData{ Data: &eth.AttestationData{
CommitteeIndex: 11, CommitteeIndex: 11,
Slot: 10,
}, },
}, },
topic: "/eth2/00000000/committee_index11_beacon_attestation", topic: "/eth2/00000000/beacon_attestation_21",
}, },
{ {
att: &eth.Attestation{ att: &eth.Attestation{
Data: &eth.AttestationData{ Data: &eth.AttestationData{
CommitteeIndex: 55, CommitteeIndex: 55,
Slot: 529,
}, },
}, },
topic: "/eth2/00000000/committee_index55_beacon_attestation", topic: "/eth2/00000000/beacon_attestation_8",
},
{
att: &eth.Attestation{},
topic: "",
},
{
topic: "",
}, },
} }
for _, tt := range tests { 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) 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 // GossipTopicMappings represent the protocol ID to protobuf message type map for easy
// lookup. // lookup.
var GossipTopicMappings = map[string]proto.Message{ var GossipTopicMappings = map[string]proto.Message{
"/eth2/%x/beacon_block": &pb.SignedBeaconBlock{}, "/eth2/%x/beacon_block": &pb.SignedBeaconBlock{},
"/eth2/%x/committee_index%d_beacon_attestation": &pb.Attestation{}, "/eth2/%x/beacon_attestation_%d": &pb.Attestation{},
"/eth2/%x/voluntary_exit": &pb.SignedVoluntaryExit{}, "/eth2/%x/voluntary_exit": &pb.SignedVoluntaryExit{},
"/eth2/%x/proposer_slashing": &pb.ProposerSlashing{}, "/eth2/%x/proposer_slashing": &pb.ProposerSlashing{},
"/eth2/%x/attester_slashing": &pb.AttesterSlashing{}, "/eth2/%x/attester_slashing": &pb.AttesterSlashing{},
"/eth2/%x/beacon_aggregate_and_proof": &pb.SignedAggregateAttestationAndProof{}, "/eth2/%x/beacon_aggregate_and_proof": &pb.SignedAggregateAttestationAndProof{},
} }
// GossipTypeMapping is the inverse of GossipTopicMappings so that an arbitrary protobuf message // 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/network"
"github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peer"
pubsub "github.com/libp2p/go-libp2p-pubsub" 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/encoder"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers" "github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 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. // Broadcaster broadcasts messages to peers over the p2p pubsub protocol.
type Broadcaster interface { type Broadcaster interface {
Broadcast(context.Context, proto.Message) error 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. // 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" "github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared" "github.com/prysmaticlabs/prysm/shared"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/runutil" "github.com/prysmaticlabs/prysm/shared/runutil"
"github.com/prysmaticlabs/prysm/shared/slotutil" "github.com/prysmaticlabs/prysm/shared/slotutil"
) )
@@ -136,7 +137,7 @@ func NewService(cfg *Config) (*Service, error) {
return nil, err return nil, err
} }
if len(cfg.KademliaBootStrapAddr) != 0 && !cfg.NoDiscovery { if len(cfg.KademliaBootStrapAddr) != 0 && !cfg.NoDiscovery && featureconfig.Get().EnableKadDHT {
dopts := []dhtopts.Option{ dopts := []dhtopts.Option{
dhtopts.Datastore(dsync.MutexWrap(ds.NewMapDatastore())), dhtopts.Datastore(dsync.MutexWrap(ds.NewMapDatastore())),
dhtopts.Protocols( dhtopts.Protocols(
@@ -235,7 +236,7 @@ func (s *Service) Start() {
go s.listenForNewNodes() 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 { for _, addr := range s.cfg.KademliaBootStrapAddr {
peersToWatch = append(peersToWatch, addr) peersToWatch = append(peersToWatch, addr)
err := startDHTDiscovery(s.host, addr) err := startDHTDiscovery(s.host, addr)
@@ -390,7 +391,7 @@ func (s *Service) RefreshENR() {
return return
} }
bitV := bitfield.NewBitvector64() bitV := bitfield.NewBitvector64()
committees := cache.CommitteeIDs.GetAllCommittees() committees := cache.SubnetIDs.GetAllSubnets()
for _, idx := range committees { for _, idx := range committees {
bitV.SetBitAt(idx, true) bitV.SetBitAt(idx, true)
} }

View File

@@ -124,7 +124,7 @@ func TestStartDiscV5_DiscoverPeersWithSubnets(t *testing.T) {
dv5Listener: listeners[0], dv5Listener: listeners[0],
metaData: &pb.MetaData{}, metaData: &pb.MetaData{},
} }
cache.CommitteeIDs.AddAttesterCommiteeID(0, 10) cache.SubnetIDs.AddAttesterSubnetID(0, 10)
testService.RefreshENR() testService.RefreshENR()
time.Sleep(2 * time.Second) 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_pubsub//:go_default_library",
"@com_github_libp2p_go_libp2p_swarm//testing:go_default_library", "@com_github_libp2p_go_libp2p_swarm//testing:go_default_library",
"@com_github_multiformats_go_multiaddr//: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", "@com_github_sirupsen_logrus//:go_default_library",
], ],
) )

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"github.com/gogo/protobuf/proto" "github.com/gogo/protobuf/proto"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
) )
// MockBroadcaster implements p2p.Broadcaster for testing. // MockBroadcaster implements p2p.Broadcaster for testing.
@@ -16,3 +17,9 @@ func (m *MockBroadcaster) Broadcast(context.Context, proto.Message) error {
m.BroadcastCalled = true m.BroadcastCalled = true
return nil 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" "github.com/libp2p/go-libp2p-core/protocol"
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
swarmt "github.com/libp2p/go-libp2p-swarm/testing" 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/encoder"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers" "github.com/prysmaticlabs/prysm/beacon-chain/p2p/peers"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 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 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. // SetStreamHandler for RPC.
func (p *TestP2P) SetStreamHandler(topic string, handler network.StreamHandler) { func (p *TestP2P) SetStreamHandler(topic string, handler network.StreamHandler) {
p.Host.SetStreamHandler(protocol.ID(topic), handler) 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/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/hashutil" "github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -246,12 +245,9 @@ func (s *Service) ProcessChainStart(genesisTime uint64, eth1BlockHash [32]byte,
} }
func (s *Service) createGenesisTime(timeStamp uint64) uint64 { func (s *Service) createGenesisTime(timeStamp uint64) uint64 {
if featureconfig.Get().CustomGenesisDelay == 0 { // adds in the genesis delay to the eth1 block time
return timeStamp // on which it was triggered.
} return timeStamp + featureconfig.Get().CustomGenesisDelay
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
} }
// processPastLogs processes all the past logs from the deposit contract and // 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 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 // stop requesting, if we have all the logs
if logCount == uint64(s.lastReceivedMerkleIndex+1) { if logCount == uint64(s.lastReceivedMerkleIndex+1) {
break break
} }
start := currentBlockNum start := currentBlockNum
end := currentBlockNum + eth1HeaderReqLimit end := currentBlockNum + eth1HeaderReqLimit
if end > s.LatestBlockHeight().Uint64() { if end > latestFollowHeight {
end = s.LatestBlockHeight().Uint64() end = latestFollowHeight
} }
query := ethereum.FilterQuery{ query := ethereum.FilterQuery{
Addresses: []common.Address{ Addresses: []common.Address{
@@ -303,9 +303,9 @@ func (s *Service) processPastLogs(ctx context.Context) error {
} }
remainingLogs := logCount - uint64(s.lastReceivedMerkleIndex+1) remainingLogs := logCount - uint64(s.lastReceivedMerkleIndex+1)
// only change the end block if the remaining logs are below the required log limit. // only change the end block if the remaining logs are below the required log limit.
if remainingLogs < depositlogRequestLimit && end >= s.LatestBlockHeight().Uint64() { if remainingLogs < depositlogRequestLimit && end >= latestFollowHeight {
query.ToBlock = s.LatestBlockHeight() query.ToBlock = big.NewInt(int64(latestFollowHeight))
end = s.LatestBlockHeight().Uint64() end = latestFollowHeight
} }
logs, err := s.httpLogger.FilterLogs(ctx, query) logs, err := s.httpLogger.FilterLogs(ctx, query)
if err != nil { 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 // 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. // 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++ { for i := s.latestEth1Data.LastRequestedBlock + 1; i <= requestedBlock; i++ {
err := s.ProcessETH1Block(ctx, big.NewInt(int64(i))) err := s.ProcessETH1Block(ctx, big.NewInt(int64(i)))
if err != nil { if err != nil {

View File

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

View File

@@ -317,6 +317,32 @@ func (s *Service) AreAllDepositsProcessed() (bool, error) {
return true, nil 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 { func (s *Service) connectToPowChain() error {
httpClient, rpcClient, err := s.dialETH1Nodes() httpClient, rpcClient, err := s.dialETH1Nodes()
if err != nil { if err != nil {
@@ -502,7 +528,7 @@ func safelyHandlePanic() {
} }
} }
func (s *Service) handleDelayTicker() { func (s *Service) handleETH1FollowDistance() {
defer safelyHandlePanic() defer safelyHandlePanic()
// use a 5 minutes timeout for block time, because the max mining time is 278 sec (block 7208027) // 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.BlockHeight = header.Number.Uint64()
s.latestEth1Data.BlockHash = header.Hash().Bytes() s.latestEth1Data.BlockHash = header.Hash().Bytes()
s.latestEth1Data.BlockTime = header.Time
if err := s.processPastLogs(context.Background()); err != nil { if err := s.processPastLogs(context.Background()); err != nil {
log.Errorf("Unable to process past logs %v", err) log.Errorf("Unable to process past logs %v", err)
@@ -605,7 +632,7 @@ func (s *Service) run(done <-chan struct{}) {
} }
s.processBlockHeader(head) s.processBlockHeader(head)
case <-ticker.C: case <-ticker.C:
s.handleDelayTicker() s.handleETH1FollowDistance()
} }
} }
} }

View File

@@ -19,6 +19,7 @@ import (
contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract" contracts "github.com/prysmaticlabs/prysm/contracts/deposit-contract"
protodb "github.com/prysmaticlabs/prysm/proto/beacon/db" protodb "github.com/prysmaticlabs/prysm/proto/beacon/db"
"github.com/prysmaticlabs/prysm/shared/event" "github.com/prysmaticlabs/prysm/shared/event"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil" "github.com/prysmaticlabs/prysm/shared/testutil"
logTest "github.com/sirupsen/logrus/hooks/test" logTest "github.com/sirupsen/logrus/hooks/test"
) )
@@ -187,6 +188,67 @@ func TestStop_OK(t *testing.T) {
hook.Reset() 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) { func TestInitDataFromContract_OK(t *testing.T) {
testAcc, err := contracts.Setup() testAcc, err := contracts.Setup()
if err != nil { 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") { }); err != nil && !strings.Contains(err.Error(), "Could not find genesis") {
t.Fatal(err) 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} parentRoot := [32]byte{1, 2, 3}
blk := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{ blk := &ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{
@@ -159,8 +168,11 @@ func TestServer_ListAttestations_NoPagination(t *testing.T) {
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{
Attestations: []*ethpb.Attestation{ Attestations: []*ethpb.Attestation{
{ {
Signature: make([]byte, 96),
Data: &ethpb.AttestationData{ 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, Slot: i,
}, },
AggregationBits: bitfield.Bitlist{0b11}, AggregationBits: bitfield.Bitlist{0b11},
@@ -197,27 +209,31 @@ func TestServer_ListAttestations_FiltersCorrectly(t *testing.T) {
db := dbTest.SetupDB(t) db := dbTest.SetupDB(t)
ctx := context.Background() ctx := context.Background()
someRoot := []byte{1, 2, 3} someRoot := [32]byte{1, 2, 3}
sourceRoot := []byte{4, 5, 6} sourceRoot := [32]byte{4, 5, 6}
sourceEpoch := uint64(5) sourceEpoch := uint64(5)
targetRoot := []byte{7, 8, 9} targetRoot := [32]byte{7, 8, 9}
targetEpoch := uint64(7) targetEpoch := uint64(7)
blocks := []*ethpb.SignedBeaconBlock{ blocks := []*ethpb.SignedBeaconBlock{
{ {
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{ Block: &ethpb.BeaconBlock{
Slot: 4, Slot: 4,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{ Attestations: []*ethpb.Attestation{
{ {
Data: &ethpb.AttestationData{ Data: &ethpb.AttestationData{
BeaconBlockRoot: someRoot, BeaconBlockRoot: someRoot[:],
Source: &ethpb.Checkpoint{ Source: &ethpb.Checkpoint{
Root: sourceRoot, Root: sourceRoot[:],
Epoch: sourceEpoch, Epoch: sourceEpoch,
}, },
Target: &ethpb.Checkpoint{ Target: &ethpb.Checkpoint{
Root: targetRoot, Root: targetRoot[:],
Epoch: targetEpoch, Epoch: targetEpoch,
}, },
Slot: 3, Slot: 3,
@@ -229,19 +245,23 @@ func TestServer_ListAttestations_FiltersCorrectly(t *testing.T) {
}, },
}, },
{ {
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{ Block: &ethpb.BeaconBlock{
Slot: 5 + params.BeaconConfig().SlotsPerEpoch, Slot: 5 + params.BeaconConfig().SlotsPerEpoch,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{ Attestations: []*ethpb.Attestation{
{ {
Data: &ethpb.AttestationData{ Data: &ethpb.AttestationData{
BeaconBlockRoot: someRoot, BeaconBlockRoot: someRoot[:],
Source: &ethpb.Checkpoint{ Source: &ethpb.Checkpoint{
Root: sourceRoot, Root: sourceRoot[:],
Epoch: sourceEpoch, Epoch: sourceEpoch,
}, },
Target: &ethpb.Checkpoint{ Target: &ethpb.Checkpoint{
Root: targetRoot, Root: targetRoot[:],
Epoch: targetEpoch, Epoch: targetEpoch,
}, },
Slot: 4 + params.BeaconConfig().SlotsPerEpoch, Slot: 4 + params.BeaconConfig().SlotsPerEpoch,
@@ -253,19 +273,23 @@ func TestServer_ListAttestations_FiltersCorrectly(t *testing.T) {
}, },
}, },
{ {
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{ Block: &ethpb.BeaconBlock{
Slot: 5, Slot: 5,
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{ Attestations: []*ethpb.Attestation{
{ {
Data: &ethpb.AttestationData{ Data: &ethpb.AttestationData{
BeaconBlockRoot: someRoot, BeaconBlockRoot: someRoot[:],
Source: &ethpb.Checkpoint{ Source: &ethpb.Checkpoint{
Root: sourceRoot, Root: sourceRoot[:],
Epoch: sourceEpoch, Epoch: sourceEpoch,
}, },
Target: &ethpb.Checkpoint{ Target: &ethpb.Checkpoint{
Root: targetRoot, Root: targetRoot[:],
Epoch: targetEpoch, Epoch: targetEpoch,
}, },
Slot: 4, Slot: 4,
@@ -321,10 +345,14 @@ func TestServer_ListAttestations_Pagination_CustomPageParameters(t *testing.T) {
Attestations: []*ethpb.Attestation{ Attestations: []*ethpb.Attestation{
{ {
Data: &ethpb.AttestationData{ Data: &ethpb.AttestationData{
CommitteeIndex: s, CommitteeIndex: s,
Slot: i, Slot: i,
BeaconBlockRoot: make([]byte, 32),
Source: &ethpb.Checkpoint{Root: make([]byte, 32)},
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
}, },
AggregationBits: bitfield.Bitlist{0b11}, 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) { func TestServer_ListAttestations_Pagination_OutOfRange(t *testing.T) {
db := dbTest.SetupDB(t) db := dbTest.SetupDB(t)
ctx := context.Background() ctx := context.Background()
testutil.NewBeaconBlock()
count := uint64(1) count := uint64(1)
atts := make([]*ethpb.Attestation, 0, count) atts := make([]*ethpb.Attestation, 0, count)
for i := uint64(0); i < count; i++ { for i := uint64(0); i < count; i++ {
blockExample := &ethpb.SignedBeaconBlock{ blockExample := &ethpb.SignedBeaconBlock{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{ Block: &ethpb.BeaconBlock{
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{
Graffiti: make([]byte, 32),
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{ Attestations: []*ethpb.Attestation{
{ {
Data: &ethpb.AttestationData{ Data: &ethpb.AttestationData{
BeaconBlockRoot: []byte("root"), BeaconBlockRoot: bytesutil.PadTo([]byte("root"), 32),
Slot: i, Slot: i,
}, },
AggregationBits: bitfield.Bitlist{0b11}, AggregationBits: bitfield.Bitlist{0b11},
@@ -485,14 +518,21 @@ func TestServer_ListAttestations_Pagination_DefaultPageSize(t *testing.T) {
atts := make([]*ethpb.Attestation, 0, count) atts := make([]*ethpb.Attestation, 0, count)
for i := uint64(0); i < count; i++ { for i := uint64(0); i < count; i++ {
blockExample := &ethpb.SignedBeaconBlock{ blockExample := &ethpb.SignedBeaconBlock{
Signature: make([]byte, 96),
Block: &ethpb.BeaconBlock{ Block: &ethpb.BeaconBlock{
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{
RandaoReveal: make([]byte, 96),
Attestations: []*ethpb.Attestation{ Attestations: []*ethpb.Attestation{
{ {
Data: &ethpb.AttestationData{ 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, Slot: i,
}, },
Signature: bytesutil.PadTo([]byte("root"), 96),
AggregationBits: bitfield.Bitlist{0b11}, AggregationBits: bitfield.Bitlist{0b11},
}, },
}, },
@@ -624,10 +664,15 @@ func TestServer_ListIndexedAttestations_GenesisEpoch(t *testing.T) {
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{
Attestations: []*ethpb.Attestation{ Attestations: []*ethpb.Attestation{
{ {
Signature: make([]byte, 96),
Data: &ethpb.AttestationData{ Data: &ethpb.AttestationData{
BeaconBlockRoot: make([]byte, 32),
Target: &ethpb.Checkpoint{ Target: &ethpb.Checkpoint{
Root: targetRoot[:], Root: targetRoot[:],
}, },
Source: &ethpb.Checkpoint{
Root: make([]byte, 32),
},
Slot: i, Slot: i,
CommitteeIndex: 0, CommitteeIndex: 0,
}, },

View File

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

View File

@@ -1892,7 +1892,9 @@ func TestServer_GetValidatorParticipation_PrevEpoch(t *testing.T) {
t.Fatal(err) 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) { if !reflect.DeepEqual(res.Participation, wanted) {
t.Error("Incorrect validator participation respond") t.Error("Incorrect validator participation respond")
} }

View File

@@ -194,7 +194,7 @@ func assignValidatorToSubnet(pubkey []byte, status ethpb.ValidatorStatus) {
return return
} }
_, ok, expTime := cache.CommitteeIDs.GetPersistentCommittees(pubkey) _, ok, expTime := cache.SubnetIDs.GetPersistentSubnets(pubkey)
if ok && expTime.After(roughtime.Now()) { if ok && expTime.After(roughtime.Now()) {
return return
} }
@@ -208,5 +208,5 @@ func assignValidatorToSubnet(pubkey []byte, status ethpb.ValidatorStatus) {
assignedDuration += int(params.BeaconNetworkConfig().EpochsPerRandomSubnetSubscription) assignedDuration += int(params.BeaconNetworkConfig().EpochsPerRandomSubnetSubscription)
totalDuration := epochDuration * time.Duration(assignedDuration) 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" mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/cache" "github.com/prysmaticlabs/prysm/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache" "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" "github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state" statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
@@ -40,7 +39,7 @@ func TestGetDuties_NextEpoch_CantFindValidatorIdx(t *testing.T) {
ctx := context.Background() ctx := context.Background()
beaconState, _ := testutil.DeterministicGenesisState(t, 10) beaconState, _ := testutil.DeterministicGenesisState(t, 10)
genesis := blk.NewGenesisBlock([]byte{}) genesis := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(genesis.Block) genesisRoot, err := stateutil.BlockRoot(genesis.Block)
if err != nil { if err != nil {
t.Fatalf("Could not get signing root %v", err) 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) { func TestGetDuties_OK(t *testing.T) {
db := dbutil.SetupDB(t) db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{}) genesis := testutil.NewBeaconBlock()
depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart) deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil { if err != nil {
@@ -165,7 +164,7 @@ func TestGetDuties_OK(t *testing.T) {
func TestGetDuties_CurrentEpoch_ShouldNotFail(t *testing.T) { func TestGetDuties_CurrentEpoch_ShouldNotFail(t *testing.T) {
db := dbutil.SetupDB(t) db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{}) genesis := testutil.NewBeaconBlock()
depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart) deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil { if err != nil {
@@ -222,7 +221,7 @@ func TestGetDuties_CurrentEpoch_ShouldNotFail(t *testing.T) {
func TestGetDuties_MultipleKeys_OK(t *testing.T) { func TestGetDuties_MultipleKeys_OK(t *testing.T) {
db := dbutil.SetupDB(t) db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{}) genesis := testutil.NewBeaconBlock()
depChainStart := uint64(64) depChainStart := uint64(64)
testutil.ResetCache() testutil.ResetCache()
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart) deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
@@ -274,11 +273,11 @@ func TestGetDuties_MultipleKeys_OK(t *testing.T) {
if len(res.CurrentEpochDuties) != 2 { if len(res.CurrentEpochDuties) != 2 {
t.Errorf("expected 2 assignments but got %d", len(res.CurrentEpochDuties)) t.Errorf("expected 2 assignments but got %d", len(res.CurrentEpochDuties))
} }
if res.CurrentEpochDuties[0].AttesterSlot != 2 { if res.CurrentEpochDuties[0].AttesterSlot != 4 {
t.Errorf("Expected res.CurrentEpochDuties[0].AttesterSlot == 7, got %d", res.CurrentEpochDuties[0].AttesterSlot) t.Errorf("Expected res.CurrentEpochDuties[0].AttesterSlot == 4, got %d", res.CurrentEpochDuties[0].AttesterSlot)
} }
if res.CurrentEpochDuties[1].AttesterSlot != 1 { if res.CurrentEpochDuties[1].AttesterSlot != 4 {
t.Errorf("Expected res.CurrentEpochDuties[1].AttesterSlot == 1, got %d", res.CurrentEpochDuties[1].AttesterSlot) 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) { func TestStreamDuties_OK(t *testing.T) {
db := dbutil.SetupDB(t) db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{}) genesis := testutil.NewBeaconBlock()
depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart) deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil { if err != nil {
@@ -380,7 +379,7 @@ func TestStreamDuties_OK(t *testing.T) {
func TestStreamDuties_OK_ChainReorg(t *testing.T) { func TestStreamDuties_OK_ChainReorg(t *testing.T) {
db := dbutil.SetupDB(t) db := dbutil.SetupDB(t)
genesis := blk.NewGenesisBlock([]byte{}) genesis := testutil.NewBeaconBlock()
depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount depChainStart := params.BeaconConfig().MinGenesisActiveValidatorCount
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart) deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil { if err != nil {
@@ -469,7 +468,7 @@ func TestAssignValidatorToSubnet(t *testing.T) {
k := pubKey(3) k := pubKey(3)
assignValidatorToSubnet(k, ethpb.ValidatorStatus_ACTIVE) assignValidatorToSubnet(k, ethpb.ValidatorStatus_ACTIVE)
coms, ok, exp := cache.CommitteeIDs.GetPersistentCommittees(k) coms, ok, exp := cache.SubnetIDs.GetPersistentSubnets(k)
if !ok { if !ok {
t.Fatal("No cache entry found for validator") t.Fatal("No cache entry found for validator")
} }
@@ -487,7 +486,7 @@ func TestAssignValidatorToSubnet(t *testing.T) {
func BenchmarkCommitteeAssignment(b *testing.B) { func BenchmarkCommitteeAssignment(b *testing.B) {
db := dbutil.SetupDB(b) db := dbutil.SetupDB(b)
genesis := blk.NewGenesisBlock([]byte{}) genesis := testutil.NewBeaconBlock()
depChainStart := uint64(8192 * 2) depChainStart := uint64(8192 * 2)
deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart) deposits, _, err := testutil.DeterministicDepositsAndKeys(depChainStart)
if err != nil { 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 // ProposeAttestation is a function called by an attester to vote
// on a block via an attestation object as defined in the Ethereum Serenity specification. // 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) { 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 { if _, err := bls.SignatureFromBytes(att.Signature); err != nil {
return nil, status.Error(codes.InvalidArgument, "Incorrect attestation signature") 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. // 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) 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. // SubscribeCommitteeSubnets subscribes to the committee ID subnet given subscribe request.
func (vs *Server) SubscribeCommitteeSubnets(ctx context.Context, req *ethpb.CommitteeSubnetsSubscribeRequest) (*ptypes.Empty, error) { 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) { 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") 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++ { 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] { 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 ( import (
"context" "context"
"math/rand"
"strings" "strings"
"sync" "sync"
"testing" "testing"
@@ -22,6 +23,7 @@ import (
mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing" mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bls" "github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/roughtime" "github.com/prysmaticlabs/prysm/shared/roughtime"
"github.com/prysmaticlabs/prysm/shared/testutil" "github.com/prysmaticlabs/prysm/shared/testutil"
@@ -40,12 +42,9 @@ func TestProposeAttestation_OK(t *testing.T) {
AttPool: attestations.NewPool(), AttPool: attestations.NewPool(),
OperationNotifier: (&mock.ChainService{}).OperationNotifier(), OperationNotifier: (&mock.ChainService{}).OperationNotifier(),
} }
head := &ethpb.SignedBeaconBlock{ head := testutil.NewBeaconBlock()
Block: &ethpb.BeaconBlock{ head.Block.Slot = 999
Slot: 999, head.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
ParentRoot: []byte{'a'},
},
}
if err := db.SaveBlock(ctx, head); err != nil { if err := db.SaveBlock(ctx, head); err != nil {
t.Fatal(err) 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) 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" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" 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" "github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation" opfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
@@ -34,7 +33,7 @@ func TestSub(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
block := blk.NewGenesisBlock([]byte{}) block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) t.Fatalf("Could not save genesis block: %v", err)
} }
@@ -123,7 +122,7 @@ func TestProposeExit_NoPanic(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
block := blk.NewGenesisBlock([]byte{}) block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) 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 { if depositsTillHeight == 0 {
return vs.ChainStartFetcher.ChainStartEth1Data(), nil 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{ return &ethpb.Eth1Data{
DepositRoot: depositRoot[:], DepositRoot: depositRoot[:],
BlockHash: blockHash[:], BlockHash: blockHash[:],

View File

@@ -94,24 +94,36 @@ func TestGetBlock_OK(t *testing.T) {
Graffiti: graffiti[:], Graffiti: graffiti[:],
} }
// We include max proposer slashings which is currently 1 in the pool. proposerSlashings := make([]*ethpb.ProposerSlashing, params.BeaconConfig().MaxProposerSlashings)
proposerSlashing, err := testutil.GenerateProposerSlashingForValidator( for i := uint64(0); i < params.BeaconConfig().MaxProposerSlashings; i++ {
beaconState, proposerSlashing, err := testutil.GenerateProposerSlashingForValidator(
privKeys[0], beaconState,
0, /* validator index */ privKeys[i],
) i, /* validator index */
if err := proposerServer.SlashingsPool.InsertProposerSlashing(context.Background(), beaconState, proposerSlashing); err != nil { )
t.Fatal(err) 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. attSlashings := make([]*ethpb.AttesterSlashing, params.BeaconConfig().MaxAttesterSlashings)
attesterSlashing, err := testutil.GenerateAttesterSlashingForValidator( for i := uint64(0); i < params.BeaconConfig().MaxAttesterSlashings; i++ {
beaconState, attesterSlashing, err := testutil.GenerateAttesterSlashingForValidator(
privKeys[1], beaconState,
1, /* validator index */ privKeys[i+params.BeaconConfig().MaxProposerSlashings],
) i+params.BeaconConfig().MaxProposerSlashings, /* validator index */
if err := proposerServer.SlashingsPool.InsertAttesterSlashing(context.Background(), beaconState, attesterSlashing); err != nil { )
t.Fatal(err) 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) block, err := proposerServer.GetBlock(ctx, req)
@@ -131,17 +143,17 @@ func TestGetBlock_OK(t *testing.T) {
if !bytes.Equal(block.Body.Graffiti, req.Graffiti) { if !bytes.Equal(block.Body.Graffiti, req.Graffiti) {
t.Fatal("Expected block to have correct graffiti") t.Fatal("Expected block to have correct graffiti")
} }
if len(block.Body.ProposerSlashings) != 1 { if len(block.Body.ProposerSlashings) != int(params.BeaconConfig().MaxProposerSlashings) {
t.Fatalf("Wanted %d proposer slashings, got %d", 1, len(block.Body.ProposerSlashings)) t.Fatalf("Wanted %d proposer slashings, got %d", params.BeaconConfig().MaxProposerSlashings, len(block.Body.ProposerSlashings))
} }
if !reflect.DeepEqual(block.Body.ProposerSlashings[0], proposerSlashing) { if !reflect.DeepEqual(block.Body.ProposerSlashings, proposerSlashings) {
t.Errorf("Wanted proposer slashing %v, got %v", proposerSlashing, block.Body.ProposerSlashings[0]) t.Errorf("Wanted proposer slashing %v, got %v", proposerSlashings, block.Body.ProposerSlashings)
} }
if len(block.Body.AttesterSlashings) != 1 { if len(block.Body.AttesterSlashings) != int(params.BeaconConfig().MaxAttesterSlashings) {
t.Fatalf("Wanted %d attester slashings, got %d", 1, len(block.Body.AttesterSlashings)) t.Fatalf("Wanted %d attester slashings, got %d", params.BeaconConfig().MaxAttesterSlashings, len(block.Body.AttesterSlashings))
} }
if !reflect.DeepEqual(block.Body.AttesterSlashings[0], attesterSlashing) { if !reflect.DeepEqual(block.Body.AttesterSlashings, attSlashings) {
t.Errorf("Wanted attester slashing %v, got %v", attesterSlashing, block.Body.AttesterSlashings) 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.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig()) params.OverrideBeaconConfig(params.MainnetConfig())
genesis := b.NewGenesisBlock([]byte{}) genesis := testutil.NewBeaconBlock()
if err := db.SaveBlock(context.Background(), genesis); err != nil { if err := db.SaveBlock(context.Background(), genesis); err != nil {
t.Fatalf("Could not save genesis block: %v", err) t.Fatalf("Could not save genesis block: %v", err)
} }
@@ -301,13 +313,9 @@ func TestProposeBlock_OK(t *testing.T) {
HeadFetcher: c, HeadFetcher: c,
BlockNotifier: c.BlockNotifier(), BlockNotifier: c.BlockNotifier(),
} }
req := &ethpb.SignedBeaconBlock{ req := testutil.NewBeaconBlock()
Block: &ethpb.BeaconBlock{ req.Block.Slot = 5
Slot: 5, req.Block.ParentRoot = bytesutil.PadTo([]byte("parent-hash"), 32)
ParentRoot: []byte("parent-hash"),
Body: &ethpb.BeaconBlockBody{},
},
}
if err := db.SaveBlock(ctx, req); err != nil { if err := db.SaveBlock(ctx, req); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -355,7 +363,7 @@ func TestComputeStateRoot_OK(t *testing.T) {
req := &ethpb.SignedBeaconBlock{ req := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{ Block: &ethpb.BeaconBlock{
ProposerIndex: 41, ProposerIndex: 21,
ParentRoot: parentRoot[:], ParentRoot: parentRoot[:],
Slot: 1, Slot: 1,
Body: &ethpb.BeaconBlockBody{ Body: &ethpb.BeaconBlockBody{
@@ -1197,7 +1205,75 @@ func TestDefaultEth1Data_NoBlockExists(t *testing.T) {
// TODO(2312): Add more tests for edge cases and better coverage. // TODO(2312): Add more tests for edge cases and better coverage.
func TestEth1Data(t *testing.T) { 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{ p := &mockPOW.POWChain{
BlockNumberByHeight: map[uint64]*big.Int{ BlockNumberByHeight: map[uint64]*big.Int{
@@ -1214,7 +1290,8 @@ func TestEth1Data(t *testing.T) {
ChainStartFetcher: p, ChainStartFetcher: p,
Eth1InfoFetcher: p, Eth1InfoFetcher: p,
Eth1BlockFetcher: p, Eth1BlockFetcher: p,
DepositFetcher: depositcache.NewDepositCache(), HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 10}},
DepositFetcher: depositCache,
} }
ctx := context.Background() ctx := context.Background()
@@ -1223,8 +1300,10 @@ func TestEth1Data(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if eth1Data.DepositCount != 55 { // Will default to 10 as the current deposit count in the
t.Error("Expected deposit count to be 55") // 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.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig()) params.OverrideBeaconConfig(params.MainnetConfig())
genesis := b.NewGenesisBlock([]byte{}) genesis := testutil.NewBeaconBlock()
if err := db.SaveBlock(context.Background(), genesis); err != nil { if err := db.SaveBlock(context.Background(), genesis); err != nil {
t.Fatalf("Could not save genesis block: %v", err) t.Fatalf("Could not save genesis block: %v", err)
} }

View File

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

View File

@@ -11,7 +11,6 @@ import (
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache" "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" "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing" mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
@@ -136,7 +135,7 @@ func TestValidatorStatus_Pending(t *testing.T) {
ctx := context.Background() ctx := context.Background()
pubKey := pubKey(1) pubKey := pubKey(1)
block := blk.NewGenesisBlock([]byte{}) block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) 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. // Active because activation epoch <= current epoch < exit epoch.
activeEpoch := helpers.ActivationExitEpoch(0) activeEpoch := helpers.ActivationExitEpoch(0)
block := blk.NewGenesisBlock([]byte{}) block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) t.Fatalf("Could not save genesis block: %v", err)
} }
@@ -301,7 +300,7 @@ func TestValidatorStatus_Exiting(t *testing.T) {
epoch := helpers.SlotToEpoch(slot) epoch := helpers.SlotToEpoch(slot)
exitEpoch := helpers.ActivationExitEpoch(epoch) exitEpoch := helpers.ActivationExitEpoch(epoch)
withdrawableEpoch := exitEpoch + params.BeaconConfig().MinValidatorWithdrawabilityDelay withdrawableEpoch := exitEpoch + params.BeaconConfig().MinValidatorWithdrawabilityDelay
block := blk.NewGenesisBlock([]byte{}) block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) 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 . // Exit slashed because slashed is true, exit epoch is =< current epoch and withdrawable epoch > epoch .
slot := uint64(10000) slot := uint64(10000)
epoch := helpers.SlotToEpoch(slot) epoch := helpers.SlotToEpoch(slot)
block := blk.NewGenesisBlock([]byte{}) block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) 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. // Exit because only exit epoch is =< current epoch.
slot := uint64(10000) slot := uint64(10000)
epoch := helpers.SlotToEpoch(slot) epoch := helpers.SlotToEpoch(slot)
block := blk.NewGenesisBlock([]byte{}) block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) 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) genesisRoot, err := stateutil.BlockRoot(block.Block)
if err != nil { if err != nil {
t.Fatalf("Could not get signing root %v", err) t.Fatalf("Could not get signing root %v", err)
@@ -655,7 +654,7 @@ func TestValidatorStatus_CorrectActivationQueue(t *testing.T) {
ctx := context.Background() ctx := context.Background()
pbKey := pubKey(5) pbKey := pubKey(5)
block := blk.NewGenesisBlock([]byte{}) block := testutil.NewBeaconBlock()
if err := db.SaveBlock(ctx, block); err != nil { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) 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 { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) 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) t.Fatalf("Could not get the deposit block slot %v", err)
} }
expected := uint64(53) expected := uint64(69)
if resp != expected { if resp != expected {
t.Errorf("Wanted %v, got %v", expected, resp) 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 { if err := db.SaveBlock(ctx, block); err != nil {
t.Fatalf("Could not save genesis block: %v", err) 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) genesisRoot, err := stateutil.BlockRoot(block.Block)
if err != nil { if err != nil {
t.Fatalf("Could not get signing root %v", err) t.Fatalf("Could not get signing root %v", err)
@@ -995,7 +994,7 @@ func TestMultipleValidatorStatus_Pubkeys(t *testing.T) {
}, },
{ {
Status: ethpb.ValidatorStatus_DEPOSITED, Status: ethpb.ValidatorStatus_DEPOSITED,
DepositInclusionSlot: 53, DepositInclusionSlot: 69,
ActivationEpoch: 18446744073709551615, ActivationEpoch: 18446744073709551615,
}, },
{ {
@@ -1059,7 +1058,7 @@ func TestMultipleValidatorStatus_Indices(t *testing.T) {
}, },
} }
stateObj, err := stateTrie.InitializeFromProtoUnsafe(beaconState) stateObj, err := stateTrie.InitializeFromProtoUnsafe(beaconState)
block := blk.NewGenesisBlock([]byte{}) block := testutil.NewBeaconBlock()
genesisRoot, err := stateutil.BlockRoot(block.Block) genesisRoot, err := stateutil.BlockRoot(block.Block)
if err != nil { if err != nil {
t.Fatalf("Could not get signing root %v", err) 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" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil" "github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
//pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" //pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/params"
@@ -245,23 +246,30 @@ func TestLastAncestorState_CanGet(t *testing.T) {
db := testDB.SetupDB(t) db := testDB.SetupDB(t)
service := New(db, cache.NewStateSummaryCache()) service := New(db, cache.NewStateSummaryCache())
b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: []byte{'a'}} b0 := testutil.NewBeaconBlock()
r0, err := ssz.HashTreeRoot(b0) b0.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32)
r0, err := ssz.HashTreeRoot(b0.Block)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
b1 := &ethpb.BeaconBlock{Slot: 1, ParentRoot: r0[:]} b1 := testutil.NewBeaconBlock()
r1, err := ssz.HashTreeRoot(b1) b1.Block.Slot = 1
b1.Block.ParentRoot = bytesutil.PadTo(r0[:], 32)
r1, err := ssz.HashTreeRoot(b1.Block)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
b2 := &ethpb.BeaconBlock{Slot: 2, ParentRoot: r1[:]} b2 := testutil.NewBeaconBlock()
r2, err := ssz.HashTreeRoot(b2) b2.Block.Slot = 2
b2.Block.ParentRoot = bytesutil.PadTo(r1[:], 32)
r2, err := ssz.HashTreeRoot(b2.Block)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
b3 := &ethpb.BeaconBlock{Slot: 3, ParentRoot: r2[:]} b3 := testutil.NewBeaconBlock()
r3, err := ssz.HashTreeRoot(b3) b3.Block.Slot = 3
b3.Block.ParentRoot = bytesutil.PadTo(r2[:], 32)
r3, err := ssz.HashTreeRoot(b3.Block)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -271,16 +279,16 @@ func TestLastAncestorState_CanGet(t *testing.T) {
t.Fatal(err) 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) 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) 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) 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) t.Fatal(err)
} }
if err := service.beaconDB.SaveState(ctx, b1State, r1); err != nil { if err := service.beaconDB.SaveState(ctx, b1State, r1); err != nil {

View File

@@ -179,7 +179,7 @@ func TestLoadBlocks_FirstBranch(t *testing.T) {
beaconDB: db, beaconDB: db,
} }
roots, savedBlocks, err := tree1(db, []byte{'A'}) roots, savedBlocks, err := tree1(db, bytesutil.PadTo([]byte{'A'}, 32))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -190,15 +190,18 @@ func TestLoadBlocks_FirstBranch(t *testing.T) {
} }
wanted := []*ethpb.SignedBeaconBlock{ wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[8]}, savedBlocks[8],
{Block: savedBlocks[6]}, savedBlocks[6],
{Block: savedBlocks[4]}, savedBlocks[4],
{Block: savedBlocks[2]}, savedBlocks[2],
{Block: savedBlocks[1]}, savedBlocks[1],
{Block: savedBlocks[0]}, 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{ wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[5]}, savedBlocks[5],
{Block: savedBlocks[3]}, savedBlocks[3],
{Block: savedBlocks[1]}, savedBlocks[1],
{Block: savedBlocks[0]}, 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{ wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[7]}, savedBlocks[7],
{Block: savedBlocks[6]}, savedBlocks[6],
{Block: savedBlocks[4]}, savedBlocks[4],
{Block: savedBlocks[2]}, savedBlocks[2],
{Block: savedBlocks[1]}, savedBlocks[1],
{Block: savedBlocks[0]}, 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{ wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[6]}, savedBlocks[6],
{Block: savedBlocks[5]}, savedBlocks[5],
{Block: savedBlocks[1]}, savedBlocks[1],
{Block: savedBlocks[0]}, 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, beaconDB: db,
} }
roots, savedBlocks, err := tree3(db, []byte{'A'}) roots, savedBlocks, err := tree3(db, bytesutil.PadTo([]byte{'A'}, 32))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -306,12 +318,15 @@ func TestLoadBlocks_SameEndSlots(t *testing.T) {
} }
wanted := []*ethpb.SignedBeaconBlock{ wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[2]}, savedBlocks[2],
{Block: savedBlocks[1]}, savedBlocks[1],
{Block: savedBlocks[0]}, 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, beaconDB: db,
} }
roots, savedBlocks, err := tree4(db, []byte{'A'}) roots, savedBlocks, err := tree4(db, bytesutil.PadTo([]byte{'A'}, 32))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -333,11 +348,14 @@ func TestLoadBlocks_SameEndSlotsWith2blocks(t *testing.T) {
} }
wanted := []*ethpb.SignedBeaconBlock{ wanted := []*ethpb.SignedBeaconBlock{
{Block: savedBlocks[1]}, savedBlocks[1],
{Block: savedBlocks[0]}, 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, beaconDB: db,
} }
roots, _, err := tree1(db, []byte{'A'}) roots, _, err := tree1(db, bytesutil.PadTo([]byte{'A'}, 32))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@@ -661,7 +679,7 @@ func TestProcessStateUpToSlot_CanProcess(t *testing.T) {
// B0 - B1 - - B3 -- B5 // B0 - B1 - - B3 -- B5
// \- B2 -- B4 -- B6 ----- B8 // \- B2 -- B4 -- B6 ----- B8
// \- B7 // \- 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} b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
r0, err := ssz.HashTreeRoot(b0) r0, err := ssz.HashTreeRoot(b0)
if err != nil { if err != nil {
@@ -709,15 +727,20 @@ func tree1(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
} }
st := testutil.NewBeaconState() st := testutil.NewBeaconState()
returnedBlocks := []*ethpb.SignedBeaconBlock{}
for _, b := range []*ethpb.BeaconBlock{b0, b1, b2, b3, b4, b5, b6, b7, b8} { 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 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 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: // tree2 constructs the following tree:
@@ -726,7 +749,7 @@ func tree1(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
// \- B2 // \- B2
// \- B2 // \- B2
// \- B2 -- B3 // \- 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} b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
r0, err := ssz.HashTreeRoot(b0) r0, err := ssz.HashTreeRoot(b0)
if err != nil { if err != nil {
@@ -764,15 +787,21 @@ func tree2(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
} }
st := testutil.NewBeaconState() st := testutil.NewBeaconState()
returnedBlocks := []*ethpb.SignedBeaconBlock{}
for _, b := range []*ethpb.BeaconBlock{b0, b1, b21, b22, b23, b24, b3} { 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 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 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: // tree3 constructs the following tree:
@@ -781,7 +810,7 @@ func tree2(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
// \- B2 // \- B2
// \- B2 // \- 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} b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
r0, err := ssz.HashTreeRoot(b0) r0, err := ssz.HashTreeRoot(b0)
if err != nil { if err != nil {
@@ -814,16 +843,22 @@ func tree3(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
} }
st := testutil.NewBeaconState() st := testutil.NewBeaconState()
returnedBlocks := []*ethpb.SignedBeaconBlock{}
for _, b := range []*ethpb.BeaconBlock{b0, b1, b21, b22, b23, b24} { 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 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 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: // tree4 constructs the following tree:
@@ -832,7 +867,7 @@ func tree3(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
// \- B2 // \- B2
// \- B2 // \- 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} b0 := &ethpb.BeaconBlock{Slot: 0, ParentRoot: genesisRoot}
r0, err := ssz.HashTreeRoot(b0) r0, err := ssz.HashTreeRoot(b0)
if err != nil { if err != nil {
@@ -860,14 +895,20 @@ func tree4(db db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.BeaconBlock
} }
st := testutil.NewBeaconState() st := testutil.NewBeaconState()
returnedBlocks := []*ethpb.SignedBeaconBlock{}
for _, b := range []*ethpb.BeaconBlock{b0, b21, b22, b23, b24} { 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 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 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", "service.go",
"subscriber.go", "subscriber.go",
"subscriber_beacon_aggregate_proof.go", "subscriber_beacon_aggregate_proof.go",
"subscriber_beacon_attestation.go",
"subscriber_beacon_blocks.go", "subscriber_beacon_blocks.go",
"subscriber_committee_index_beacon_attestation.go",
"subscriber_handlers.go", "subscriber_handlers.go",
"utils.go", "utils.go",
"validate_aggregate_proof.go", "validate_aggregate_proof.go",
"validate_attester_slashing.go", "validate_attester_slashing.go",
"validate_beacon_attestation.go",
"validate_beacon_blocks.go", "validate_beacon_blocks.go",
"validate_committee_index_beacon_attestation.go",
"validate_proposer_slashing.go", "validate_proposer_slashing.go",
"validate_voluntary_exit.go", "validate_voluntary_exit.go",
], ],
@@ -63,7 +63,6 @@ go_library(
"//beacon-chain/state/stateutil:go_default_library", "//beacon-chain/state/stateutil:go_default_library",
"//proto/beacon/p2p/v1:go_default_library", "//proto/beacon/p2p/v1:go_default_library",
"//shared:go_default_library", "//shared:go_default_library",
"//shared/attestationutil:go_default_library",
"//shared/bls:go_default_library", "//shared/bls:go_default_library",
"//shared/bytesutil:go_default_library", "//shared/bytesutil:go_default_library",
"//shared/featureconfig:go_default_library", "//shared/featureconfig:go_default_library",
@@ -109,15 +108,15 @@ go_test(
"rpc_test.go", "rpc_test.go",
"service_test.go", "service_test.go",
"subscriber_beacon_aggregate_proof_test.go", "subscriber_beacon_aggregate_proof_test.go",
"subscriber_beacon_attestation_test.go",
"subscriber_beacon_blocks_test.go", "subscriber_beacon_blocks_test.go",
"subscriber_committee_index_beacon_attestation_test.go",
"subscriber_test.go", "subscriber_test.go",
"sync_test.go", "sync_test.go",
"utils_test.go", "utils_test.go",
"validate_aggregate_proof_test.go", "validate_aggregate_proof_test.go",
"validate_attester_slashing_test.go", "validate_attester_slashing_test.go",
"validate_beacon_attestation_test.go",
"validate_beacon_blocks_test.go", "validate_beacon_blocks_test.go",
"validate_committee_index_beacon_attestation_test.go",
"validate_proposer_slashing_test.go", "validate_proposer_slashing_test.go",
"validate_voluntary_exit_test.go", "validate_voluntary_exit_test.go",
], ],

View File

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

View File

@@ -5,6 +5,7 @@ import (
"testing" "testing"
p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/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) { func TestRegularSync_generateErrorResponse(t *testing.T) {
@@ -24,11 +25,11 @@ func TestRegularSync_generateErrorResponse(t *testing.T) {
if b[0] != responseCodeServerError { if b[0] != responseCodeServerError {
t.Errorf("The first byte was not the status code. Got %#x wanted %#x", b, responseCodeServerError) t.Errorf("The first byte was not the status code. Got %#x wanted %#x", b, responseCodeServerError)
} }
msg := make([]byte, 0) msg := &pb.ErrorResponse{}
if err := r.p2p.Encoding().DecodeWithLength(buf, &msg); err != nil { if err := r.p2p.Encoding().DecodeWithLength(buf, msg); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if string(msg) != "something bad happened" { if string(msg.Message) != "something bad happened" {
t.Errorf("Received the wrong message: %v", msg) 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) resp := make([]*eth.SignedBeaconBlock, 0, req.Count)
for { for i := uint64(0); ; i++ {
blk, err := prysmsync.ReadChunkedBlock(stream, f.p2p) blk, err := prysmsync.ReadChunkedBlock(stream, f.p2p)
if err == io.EOF { if err == io.EOF {
break break
} }
// exit if more than max request blocks are returned
if i >= params.BeaconNetworkConfig().MaxRequestBlocks {
break
}
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -89,7 +89,7 @@ func (r *Service) updateMetrics() {
if err != nil { if err != nil {
log.WithError(err).Errorf("Could not compute fork digest") 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 := p2p.GossipTypeMapping[reflect.TypeOf(&pb.Attestation{})]
attTopic += r.p2p.Encoding().ProtocolSuffix() attTopic += r.p2p.Encoding().ProtocolSuffix()
for _, committeeIdx := range indices { for _, committeeIdx := range indices {
@@ -99,7 +99,7 @@ func (r *Service) updateMetrics() {
// We update all other gossip topics. // We update all other gossip topics.
for topic := range p2p.GossipTopicMappings { for topic := range p2p.GossipTopicMappings {
// We already updated attestation subnet topics. // We already updated attestation subnet topics.
if strings.Contains(topic, "committee_index") { if strings.Contains(topic, "beacon_attestation") {
continue continue
} }
topic += r.p2p.Encoding().ProtocolSuffix() 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 { if err := s.sendRecentBeaconBlocksRequest(ctx, req, pid); err != nil {
traceutil.AnnotateError(span, err) traceutil.AnnotateError(span, err)
log.Errorf("Could not send recent block request: %v", 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 { if err != nil {
t.Fatal(err) 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{ aggregateAndProof := &ethpb.AggregateAttestationAndProof{
SelectionProof: sig.Marshal(), SelectionProof: sig.Marshal(),
Aggregate: att, Aggregate: att,
AggregatorIndex: 33, AggregatorIndex: aggregatorIndex,
} }
attesterDomain, err = helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainAggregateAndProof, beaconState.GenesisValidatorRoot()) attesterDomain, err = helpers.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainAggregateAndProof, beaconState.GenesisValidatorRoot())
if err != nil { if err != nil {
@@ -187,7 +189,7 @@ func TestProcessPendingAtts_HasBlockSaveAggregatedAtt(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) 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 { if err := beaconState.SetGenesisTime(uint64(time.Now().Unix())); err != nil {
t.Fatal(err) t.Fatal(err)

View File

@@ -75,7 +75,7 @@ func (r *Service) processPendingBlocks(ctx context.Context) error {
"currentSlot": b.Block.Slot, "currentSlot": b.Block.Slot,
"parentRoot": hex.EncodeToString(bytesutil.Trunc(b.Block.ParentRoot)), "parentRoot": hex.EncodeToString(bytesutil.Trunc(b.Block.ParentRoot)),
}).Info("Requesting parent block") }).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 // 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. // have a head slot newer than the block slot we are requesting.

View File

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

View File

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

View File

@@ -10,6 +10,7 @@ import (
"github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/protocol" "github.com/libp2p/go-libp2p-core/protocol"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" 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" db "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/flags" "github.com/prysmaticlabs/prysm/beacon-chain/flags"
p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing" 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). // 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") pcl := protocol.ID("/testing")
var wg sync.WaitGroup 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). // 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") pcl := protocol.ID("/testing")
var wg sync.WaitGroup 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") pcl := protocol.ID("/testing")
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -270,7 +273,7 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
} }
capacity := int64(flags.Get().BlockBatchLimit * 3) 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{ req := &pb.BeaconBlocksByRangeRequest{
StartSlot: 100, StartSlot: 100,
@@ -301,7 +304,7 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
} }
capacity := int64(flags.Get().BlockBatchLimit * 3) 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{ req := &pb.BeaconBlocksByRangeRequest{
StartSlot: 100, StartSlot: 100,
@@ -336,7 +339,7 @@ func TestRPCBeaconBlocksByRange_RPCHandlerRateLimitOverflow(t *testing.T) {
} }
capacity := int64(flags.Get().BlockBatchLimit * flags.Get().BlockBatchLimitBurstFactor) 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{ req := &pb.BeaconBlocksByRangeRequest{
StartSlot: 100, StartSlot: 100,

View File

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

View File

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

View File

@@ -66,6 +66,7 @@ type blockchainService interface {
blockchain.AttestationReceiver blockchain.AttestationReceiver
blockchain.TimeFetcher blockchain.TimeFetcher
blockchain.GenesisFetcher blockchain.GenesisFetcher
blockchain.CanonicalFetcher
} }
// Service is responsible for handling all run time p2p related operations as the // 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" "github.com/libp2p/go-libp2p-core/peer"
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
pb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" 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/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/messagehandler" "github.com/prysmaticlabs/prysm/shared/messagehandler"
@@ -68,15 +67,16 @@ func (r *Service) registerSubscribers() {
r.attesterSlashingSubscriber, r.attesterSlashingSubscriber,
) )
if featureconfig.Get().DisableDynamicCommitteeSubnets { if featureconfig.Get().DisableDynamicCommitteeSubnets {
r.subscribeDynamic( for i := uint64(0); i < params.BeaconNetworkConfig().AttestationSubnetCount; i++ {
"/eth2/%x/committee_index%d_beacon_attestation", r.subscribe(
r.committeesCount, /* determineSubsLen */ fmt.Sprintf("/eth2/%%x/beacon_attestation_%d", i),
r.validateCommitteeIndexBeaconAttestation, /* validator */ r.validateCommitteeIndexBeaconAttestation, /* validator */
r.committeeIndexBeaconAttestationSubscriber, /* message handler */ r.committeeIndexBeaconAttestationSubscriber, /* message handler */
) )
}
} else { } else {
r.subscribeDynamicWithSubnets( r.subscribeDynamicWithSubnets(
"/eth2/%x/committee_index%d_beacon_attestation", "/eth2/%x/beacon_attestation_%d",
r.validateCommitteeIndexBeaconAttestation, /* validator */ r.validateCommitteeIndexBeaconAttestation, /* validator */
r.committeeIndexBeaconAttestationSubscriber, /* message handler */ r.committeeIndexBeaconAttestationSubscriber, /* message handler */
) )
@@ -211,9 +211,9 @@ func (r *Service) subscribeDynamicWithSubnets(
} }
// Persistent subscriptions from validators // Persistent subscriptions from validators
persistentSubs := r.persistentCommitteeIndices() persistentSubs := r.persistentSubnetIndices()
// Update desired topic indices for aggregator // Update desired topic indices for aggregator
wantedSubs := r.aggregatorCommitteeIndices(currentSlot) wantedSubs := r.aggregatorSubnetIndices(currentSlot)
// Combine subscriptions to get all requested subscriptions // Combine subscriptions to get all requested subscriptions
wantedSubs = sliceutil.SetUint64(append(persistentSubs, wantedSubs...)) wantedSubs = sliceutil.SetUint64(append(persistentSubs, wantedSubs...))
@@ -225,7 +225,7 @@ func (r *Service) subscribeDynamicWithSubnets(
r.subscribeAggregatorSubnet(subscriptions, idx, base, digest, validate, handle) r.subscribeAggregatorSubnet(subscriptions, idx, base, digest, validate, handle)
} }
// find desired subs for attesters // find desired subs for attesters
attesterSubs := r.attesterCommitteeIndices(currentSlot) attesterSubs := r.attesterSubnetIndices(currentSlot)
for _, idx := range attesterSubs { for _, idx := range attesterSubs {
r.lookupAttesterSubnets(digest, idx) 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. // revalidate that our currently connected subnets are valid.
func (r *Service) reValidateSubscriptions(subscriptions map[uint64]*pubsub.Subscription, func (r *Service) reValidateSubscriptions(subscriptions map[uint64]*pubsub.Subscription,
wantedSubs []uint64, topicFormat string, digest [4]byte) { 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 { if a.Message.Aggregate == nil || a.Message.Aggregate.Data == nil {
return errors.New("nil aggregate") 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 // Broadcast the aggregated attestation on a feed to notify other services in the beacon node
// of a received aggregated attestation. // of a received aggregated attestation.

View File

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

View File

@@ -105,7 +105,7 @@ func TestService_committeeIndexBeaconAttestationSubscriber_ValidMessage(t *testi
} }
att.Signature = sKeys[16].Sign(attRoot[:]).Marshal() 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) 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/helpers"
"github.com/prysmaticlabs/prysm/beacon-chain/core/state" "github.com/prysmaticlabs/prysm/beacon-chain/core/state"
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/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/bls"
"github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig" "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 { 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")) traceutil.AnnotateError(span, errors.Wrapf(err, "Could not validate index in committee"))
return pubsub.ValidationReject return pubsub.ValidationReject
@@ -169,7 +168,7 @@ func (r *Service) setAggregatorIndexEpochSeen(epoch uint64, aggregatorIndex uint
r.seenAttestationCache.Add(string(b), true) 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 { func validateIndexInCommittee(ctx context.Context, s *stateTrie.BeaconState, a *ethpb.Attestation, validatorIndex uint64) error {
ctx, span := trace.StartSpan(ctx, "sync.validateIndexInCommittee") ctx, span := trace.StartSpan(ctx, "sync.validateIndexInCommittee")
defer span.End() defer span.End()
@@ -178,9 +177,8 @@ func validateIndexInCommittee(ctx context.Context, s *stateTrie.BeaconState, a *
if err != nil { if err != nil {
return err return err
} }
attestingIndices := attestationutil.AttestingIndices(a.AggregationBits, committee)
var withinCommittee bool var withinCommittee bool
for _, i := range attestingIndices { for _, i := range committee {
if validatorIndex == i { if validatorIndex == i {
withinCommittee = true withinCommittee = true
break break
@@ -188,7 +186,7 @@ func validateIndexInCommittee(ctx context.Context, s *stateTrie.BeaconState, a *
} }
if !withinCommittee { if !withinCommittee {
return fmt.Errorf("validator index %d is not within the committee: %v", return fmt.Errorf("validator index %d is not within the committee: %v",
validatorIndex, attestingIndices) validatorIndex, committee)
} }
return nil 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) { func TestVerifySelection_NotAnAggregator(t *testing.T) {
ctx := context.Background() ctx := context.Background()
params.UseMinimalConfig() params.UseMinimalConfig()
@@ -400,11 +431,11 @@ func TestValidateAggregateAndProofWithNewStateMgmt_CanValidate(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
sig := privKeys[33].Sign(slotRoot[:]) sig := privKeys[22].Sign(slotRoot[:])
aggregateAndProof := &ethpb.AggregateAttestationAndProof{ aggregateAndProof := &ethpb.AggregateAttestationAndProof{
SelectionProof: sig.Marshal(), SelectionProof: sig.Marshal(),
Aggregate: att, Aggregate: att,
AggregatorIndex: 33, AggregatorIndex: 22,
} }
signedAggregateAndProof := &ethpb.SignedAggregateAttestationAndProof{Message: aggregateAndProof} signedAggregateAndProof := &ethpb.SignedAggregateAttestationAndProof{Message: aggregateAndProof}
@@ -416,7 +447,7 @@ func TestValidateAggregateAndProofWithNewStateMgmt_CanValidate(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
aggreSig := privKeys[33].Sign(signingRoot[:]).Marshal() aggreSig := privKeys[22].Sign(signingRoot[:]).Marshal()
signedAggregateAndProof.Signature = aggreSig[:] signedAggregateAndProof.Signature = aggreSig[:]
if err := beaconState.SetGenesisTime(uint64(time.Now().Unix())); err != nil { if err := beaconState.SetGenesisTime(uint64(time.Now().Unix())); err != nil {
@@ -524,11 +555,11 @@ func TestVerifyIndexInCommittee_SeenAggregatorEpoch(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
sig := privKeys[33].Sign(slotRoot[:]) sig := privKeys[22].Sign(slotRoot[:])
aggregateAndProof := &ethpb.AggregateAttestationAndProof{ aggregateAndProof := &ethpb.AggregateAttestationAndProof{
SelectionProof: sig.Marshal(), SelectionProof: sig.Marshal(),
Aggregate: att, Aggregate: att,
AggregatorIndex: 33, AggregatorIndex: 22,
} }
signedAggregateAndProof := &ethpb.SignedAggregateAttestationAndProof{Message: aggregateAndProof} signedAggregateAndProof := &ethpb.SignedAggregateAttestationAndProof{Message: aggregateAndProof}
@@ -540,7 +571,7 @@ func TestVerifyIndexInCommittee_SeenAggregatorEpoch(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
aggreSig := privKeys[33].Sign(signingRoot[:]).Marshal() aggreSig := privKeys[22].Sign(signingRoot[:]).Marshal()
signedAggregateAndProof.Signature = aggreSig[:] signedAggregateAndProof.Signature = aggreSig[:]
if err := beaconState.SetGenesisTime(uint64(time.Now().Unix())); err != nil { if err := beaconState.SetGenesisTime(uint64(time.Now().Unix())); err != nil {

View File

@@ -10,6 +10,7 @@ import (
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" eth "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "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/beacon-chain/p2p"
"github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/featureconfig"
@@ -19,7 +20,7 @@ import (
// Validation // Validation
// - The attestation's committee index (attestation.data.index) is for the correct subnet. // - 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. // - 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). // - 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. // - The signature of attestation is valid.
@@ -57,6 +58,11 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
if att.Data == nil { if att.Data == nil {
return pubsub.ValidationReject 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. // Verify this the first attestation received for the participating validator for the slot.
if s.hasSeenCommitteeIndicesSlot(att.Data.Slot, att.Data.CommitteeIndex, att.AggregationBits) { if s.hasSeenCommitteeIndicesSlot(att.Data.Slot, att.Data.CommitteeIndex, att.AggregationBits) {
return pubsub.ValidationIgnore return pubsub.ValidationIgnore
@@ -69,12 +75,34 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
traceutil.AnnotateError(span, err) traceutil.AnnotateError(span, err)
return pubsub.ValidationIgnore 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 return pubsub.ValidationIgnore
} }
// Attestation must be unaggregated. // Attestation must be unaggregated and the bit index must exist in the range of committee indices.
if att.AggregationBits == nil || att.AggregationBits.Count() != 1 { // 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 return pubsub.ValidationReject
} }
@@ -95,12 +123,6 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p
return pubsub.ValidationIgnore 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.. // Attestation's signature is a valid BLS signature and belongs to correct public key..
if !featureconfig.Get().DisableStrictAttestationPubsubVerification { if !featureconfig.Get().DisableStrictAttestationPubsubVerification {
if err := blocks.VerifyAttestation(ctx, preState, att); err != nil { 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