diff --git a/beacon-chain/blockchain/chain_info.go b/beacon-chain/blockchain/chain_info.go index 31171ec3091..538eb7c6e74 100644 --- a/beacon-chain/blockchain/chain_info.go +++ b/beacon-chain/blockchain/chain_info.go @@ -11,6 +11,7 @@ import ( "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/beacon-chain/state" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/bytesutil" "github.com/prysmaticlabs/prysm/shared/params" ) @@ -19,6 +20,7 @@ import ( type ChainInfoFetcher interface { HeadFetcher FinalizationFetcher + GenesisFetcher } // TimeFetcher retrieves the Eth2 data that's related to time. @@ -27,6 +29,11 @@ type TimeFetcher interface { CurrentSlot() uint64 } +// GenesisFetcher retrieves the eth2 data related to its genesis. +type GenesisFetcher interface { + GenesisValidatorRoot() [32]byte +} + // HeadFetcher defines a common interface for methods in blockchain service which // directly retrieves head related data. type HeadFetcher interface { @@ -178,6 +185,15 @@ func (s *Service) GenesisTime() time.Time { return s.genesisTime } +// GenesisValidatorRoot returns the genesis validator +// root of the chain. +func (s *Service) GenesisValidatorRoot() [32]byte { + if !s.hasHeadState() { + return [32]byte{} + } + return bytesutil.ToBytes32(s.head.state.GenesisValidatorRoot()) +} + // CurrentFork retrieves the latest fork information of the beacon chain. func (s *Service) CurrentFork() *pb.Fork { if !s.hasHeadState() { diff --git a/beacon-chain/blockchain/testing/mock.go b/beacon-chain/blockchain/testing/mock.go index 45613b9e96a..9b242f0aa6b 100644 --- a/beacon-chain/blockchain/testing/mock.go +++ b/beacon-chain/blockchain/testing/mock.go @@ -32,6 +32,7 @@ type ChainService struct { BlocksReceived []*ethpb.SignedBeaconBlock Balance *precompute.Balance Genesis time.Time + ValidatorsRoot [32]byte Fork *pb.Fork DB db.Database stateNotifier statefeed.Notifier @@ -217,6 +218,11 @@ func (ms *ChainService) GenesisTime() time.Time { return ms.Genesis } +// GenesisValidatorRoot mocks the same method in the chain service. +func (ms *ChainService) GenesisValidatorRoot() [32]byte { + return ms.ValidatorsRoot +} + // CurrentSlot mocks the same method in the chain service. func (ms *ChainService) CurrentSlot() uint64 { return uint64(time.Now().Unix()-ms.Genesis.Unix()) / params.BeaconConfig().SecondsPerSlot diff --git a/beacon-chain/core/helpers/BUILD.bazel b/beacon-chain/core/helpers/BUILD.bazel index 15c36397057..bfa53e958ff 100644 --- a/beacon-chain/core/helpers/BUILD.bazel +++ b/beacon-chain/core/helpers/BUILD.bazel @@ -16,14 +16,15 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers", visibility = [ "//beacon-chain:__subpackages__", + "//endtoend/evaluators:__pkg__", "//shared/benchutil/benchmark_files:__subpackages__", - "//shared/testutil:__pkg__", - "//shared/keystore:__pkg__", "//shared/interop:__pkg__", + "//shared/keystore:__pkg__", + "//shared/p2putils:__pkg__", + "//shared/testutil:__pkg__", "//slasher:__subpackages__", "//tools:__subpackages__", "//validator:__subpackages__", - "//endtoend/evaluators:__pkg__", ], deps = [ "//beacon-chain/cache:go_default_library", diff --git a/beacon-chain/p2p/BUILD.bazel b/beacon-chain/p2p/BUILD.bazel index 5b15a220513..b7802b79151 100644 --- a/beacon-chain/p2p/BUILD.bazel +++ b/beacon-chain/p2p/BUILD.bazel @@ -43,6 +43,7 @@ go_library( "//shared/featureconfig:go_default_library", "//shared/hashutil:go_default_library", "//shared/iputils:go_default_library", + "//shared/p2putils:go_default_library", "//shared/params:go_default_library", "//shared/runutil:go_default_library", "//shared/sliceutil:go_default_library", @@ -114,6 +115,7 @@ go_test( "//proto/beacon/p2p/v1:go_default_library", "//proto/testing:go_default_library", "//shared/iputils:go_default_library", + "//shared/p2putils:go_default_library", "//shared/params:go_default_library", "//shared/testutil:go_default_library", "@com_github_ethereum_go_ethereum//p2p/discover:go_default_library", diff --git a/beacon-chain/p2p/broadcaster.go b/beacon-chain/p2p/broadcaster.go index 5f14a1d0c21..86976f8dac4 100644 --- a/beacon-chain/p2p/broadcaster.go +++ b/beacon-chain/p2p/broadcaster.go @@ -22,7 +22,7 @@ var ErrMessageNotMapped = errors.New("message type is not mapped to a PubSub top func (s *Service) Broadcast(ctx context.Context, msg proto.Message) error { ctx, span := trace.StartSpan(ctx, "p2p.Broadcast") defer span.End() - forkDigest, err := s.ForkDigest() + forkDigest, err := s.forkDigest() if err != nil { return err } diff --git a/beacon-chain/p2p/broadcaster_test.go b/beacon-chain/p2p/broadcaster_test.go index 97a434e1f39..acbbb517da3 100644 --- a/beacon-chain/p2p/broadcaster_test.go +++ b/beacon-chain/p2p/broadcaster_test.go @@ -29,6 +29,8 @@ func TestService_Broadcast(t *testing.T) { cfg: &Config{ Encoding: "ssz", }, + genesisTime: time.Now(), + genesisValidatorsRoot: []byte{'A'}, } msg := &testpb.TestSimpleMessage{ @@ -38,7 +40,7 @@ func TestService_Broadcast(t *testing.T) { topic := "/eth2/%x/testing" // Set a test gossip mapping for testpb.TestSimpleMessage. GossipTypeMapping[reflect.TypeOf(msg)] = topic - digest, err := p.ForkDigest() + digest, err := p.forkDigest() if err != nil { t.Fatal(err) } @@ -85,7 +87,10 @@ func TestService_Broadcast(t *testing.T) { } func TestService_Broadcast_ReturnsErr_TopicNotMapped(t *testing.T) { - p := Service{} + p := Service{ + genesisTime: time.Now(), + genesisValidatorsRoot: []byte{'A'}, + } if err := p.Broadcast(context.Background(), &testpb.AddressBook{}); err != ErrMessageNotMapped { t.Fatalf("Expected error %v, got %v", ErrMessageNotMapped, err) } diff --git a/beacon-chain/p2p/discovery_test.go b/beacon-chain/p2p/discovery_test.go index c828d251afc..1eb48a22566 100644 --- a/beacon-chain/p2p/discovery_test.go +++ b/beacon-chain/p2p/discovery_test.go @@ -53,7 +53,9 @@ func TestCreateListener(t *testing.T) { port := 1024 ipAddr, pkey := createAddrAndPrivKey(t) s := &Service{ - cfg: &Config{UDPPort: uint(port)}, + genesisTime: time.Now(), + genesisValidatorsRoot: []byte{'A'}, + cfg: &Config{UDPPort: uint(port)}, } listener := s.createListener(ipAddr, pkey) defer listener.Close() @@ -130,7 +132,10 @@ func TestStartDiscV5_DiscoverAllPeers(t *testing.T) { func TestMultiAddrsConversion_InvalidIPAddr(t *testing.T) { addr := net.ParseIP("invalidIP") _, pkey := createAddrAndPrivKey(t) - s := &Service{} + s := &Service{ + genesisTime: time.Now(), + genesisValidatorsRoot: []byte{'A'}, + } node, err := s.createLocalNode(pkey, addr, 0, 0) if err != nil { t.Fatal(err) @@ -149,6 +154,8 @@ func TestMultiAddrConversion_OK(t *testing.T) { TCPPort: 0, UDPPort: 0, }, + genesisTime: time.Now(), + genesisValidatorsRoot: []byte{'A'}, } listener := s.createListener(ipAddr, pkey) defer listener.Close() diff --git a/beacon-chain/p2p/fork.go b/beacon-chain/p2p/fork.go index e0b6d3cce15..4d80ef2fb47 100644 --- a/beacon-chain/p2p/fork.go +++ b/beacon-chain/p2p/fork.go @@ -10,8 +10,8 @@ import ( "github.com/ethereum/go-ethereum/p2p/enr" "github.com/pkg/errors" "github.com/prysmaticlabs/go-ssz" - "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/p2putils" "github.com/prysmaticlabs/prysm/shared/params" "github.com/sirupsen/logrus" ) @@ -21,8 +21,8 @@ var eth2ENRKey = params.BeaconNetworkConfig().ETH2Key // ForkDigest returns the current fork digest of // the node. -func (s *Service) ForkDigest() ([4]byte, error) { - return createForkDigest(s.genesisTime, s.genesisValidatorsRoot) +func (s *Service) forkDigest() ([4]byte, error) { + return p2putils.CreateForkDigest(s.genesisTime, s.genesisValidatorsRoot) } // Compares fork ENRs between an incoming peer's record and our node's @@ -72,35 +72,6 @@ func (s *Service) compareForkENR(record *enr.Record) error { return nil } -// Creates a fork digest from a genesis time and genesis -// validators root, utilizing the current slot to determine -// the active fork version in the node. -func createForkDigest( - genesisTime time.Time, - genesisValidatorsRoot []byte, -) ([4]byte, error) { - currentSlot := helpers.SlotsSince(genesisTime) - currentEpoch := helpers.SlotToEpoch(currentSlot) - - // We retrieve a list of scheduled forks by epoch. - // We loop through the keys in this map to determine the current - // fork version based on the current, time-based epoch number - // since the genesis time. - currentForkVersion := params.BeaconConfig().GenesisForkVersion - scheduledForks := params.BeaconConfig().ForkVersionSchedule - for epoch, forkVersion := range scheduledForks { - if epoch <= currentEpoch { - currentForkVersion = forkVersion - } - } - - digest, err := helpers.ComputeForkDigest(currentForkVersion, genesisValidatorsRoot) - if err != nil { - return [4]byte{}, err - } - return digest, nil -} - // Adds a fork entry as an ENR record under the eth2EnrKey for // the local node. The fork entry is an ssz-encoded enrForkID type // which takes into account the current fork version from the current @@ -111,7 +82,7 @@ func addForkEntry( genesisTime time.Time, genesisValidatorsRoot []byte, ) (*enode.LocalNode, error) { - digest, err := createForkDigest(genesisTime, genesisValidatorsRoot) + digest, err := p2putils.CreateForkDigest(genesisTime, genesisValidatorsRoot) if err != nil { return nil, err } diff --git a/beacon-chain/p2p/fork_test.go b/beacon-chain/p2p/fork_test.go index 0af93eea16a..e440d1d6603 100644 --- a/beacon-chain/p2p/fork_test.go +++ b/beacon-chain/p2p/fork_test.go @@ -16,6 +16,7 @@ import ( "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" testDB "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" + "github.com/prysmaticlabs/prysm/shared/p2putils" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/testutil" "github.com/sirupsen/logrus" @@ -213,7 +214,7 @@ func TestDiscv5_AddRetrieveForkEntryENR(t *testing.T) { genesisTime := time.Now() genesisValidatorsRoot := make([]byte, 32) - digest, err := createForkDigest(genesisTime, make([]byte, 32)) + digest, err := p2putils.CreateForkDigest(genesisTime, make([]byte, 32)) if err != nil { t.Fatal(err) } diff --git a/beacon-chain/p2p/interfaces.go b/beacon-chain/p2p/interfaces.go index 1ba65008aba..953ca45f25b 100644 --- a/beacon-chain/p2p/interfaces.go +++ b/beacon-chain/p2p/interfaces.go @@ -44,7 +44,6 @@ type ConnectionHandler interface { // EncodingProvider provides p2p network encoding. type EncodingProvider interface { Encoding() encoder.NetworkEncoding - ForkDigest() ([4]byte, error) } // PubSubProvider provides the p2p pubsub protocol. diff --git a/beacon-chain/p2p/testing/p2p.go b/beacon-chain/p2p/testing/p2p.go index f6ee3abed80..5885d9b3f4d 100644 --- a/beacon-chain/p2p/testing/p2p.go +++ b/beacon-chain/p2p/testing/p2p.go @@ -40,6 +40,7 @@ type TestP2P struct { pubsub *pubsub.PubSub BroadcastCalled bool DelaySend bool + Digest [4]byte peers *peers.Status LocalMetadata *pb.MetaData } @@ -257,7 +258,7 @@ func (p *TestP2P) RefreshENR(epoch uint64) { // ForkDigest mocks the p2p func. func (p *TestP2P) ForkDigest() ([4]byte, error) { - return [4]byte{}, nil + return p.Digest, nil } // Metadata mocks the peer's metadata. diff --git a/beacon-chain/sync/BUILD.bazel b/beacon-chain/sync/BUILD.bazel index ca6884522a5..95b6c42b75f 100644 --- a/beacon-chain/sync/BUILD.bazel +++ b/beacon-chain/sync/BUILD.bazel @@ -62,6 +62,7 @@ go_library( "//shared/featureconfig:go_default_library", "//shared/hashutil:go_default_library", "//shared/messagehandler:go_default_library", + "//shared/p2putils:go_default_library", "//shared/params:go_default_library", "//shared/roughtime:go_default_library", "//shared/runutil:go_default_library", diff --git a/beacon-chain/sync/metrics.go b/beacon-chain/sync/metrics.go index ab6fee1d684..8b127651084 100644 --- a/beacon-chain/sync/metrics.go +++ b/beacon-chain/sync/metrics.go @@ -72,8 +72,13 @@ var ( ) func (r *Service) updateMetrics() { + // do not update metrics if genesis time + // has not been initialized + if r.chain.GenesisTime().IsZero() { + return + } // We update the dynamic subnet topics. - digest, err := r.p2p.ForkDigest() + digest, err := r.forkDigest() if err != nil { log.WithError(err).Errorf("Could not compute fork digest") } diff --git a/beacon-chain/sync/rpc_status.go b/beacon-chain/sync/rpc_status.go index e31141a0802..6d9253d4498 100644 --- a/beacon-chain/sync/rpc_status.go +++ b/beacon-chain/sync/rpc_status.go @@ -78,7 +78,7 @@ func (r *Service) sendRPCStatusRequest(ctx context.Context, id peer.ID) error { return err } - forkDigest, err := r.p2p.ForkDigest() + forkDigest, err := r.forkDigest() if err != nil { return err } @@ -179,7 +179,7 @@ func (r *Service) statusRPCHandler(ctx context.Context, msg interface{}, stream return err } - forkDigest, err := r.p2p.ForkDigest() + forkDigest, err := r.forkDigest() if err != nil { return err } @@ -200,7 +200,7 @@ func (r *Service) statusRPCHandler(ctx context.Context, msg interface{}, stream } func (r *Service) validateStatusMessage(msg *pb.Status, stream network.Stream) error { - forkDigest, err := r.p2p.ForkDigest() + forkDigest, err := r.forkDigest() if err != nil { return err } diff --git a/beacon-chain/sync/rpc_status_test.go b/beacon-chain/sync/rpc_status_test.go index 737eaeb6306..c9a81e1e0ba 100644 --- a/beacon-chain/sync/rpc_status_test.go +++ b/beacon-chain/sync/rpc_status_test.go @@ -35,7 +35,11 @@ func TestHelloRPCHandler_Disconnects_OnForkVersionMismatch(t *testing.T) { t.Error("Expected peers to be connected") } - r := &Service{p2p: p1} + r := &Service{p2p: p1, + chain: &mock.ChainService{ + Genesis: time.Now(), + ValidatorsRoot: [32]byte{'A'}, + }} pcl := protocol.ID("/testing") var wg sync.WaitGroup @@ -116,8 +120,14 @@ func TestHelloRPCHandler_ReturnsHelloMessage(t *testing.T) { PreviousVersion: params.BeaconConfig().GenesisForkVersion, CurrentVersion: params.BeaconConfig().GenesisForkVersion, }, + ValidatorsRoot: [32]byte{'A'}, + Genesis: time.Now(), }, } + digest, err := r.forkDigest() + if err != nil { + t.Fatal(err) + } // Setup streams pcl := protocol.ID("/testing") @@ -131,7 +141,7 @@ func TestHelloRPCHandler_ReturnsHelloMessage(t *testing.T) { t.Fatal(err) } expected := &pb.Status{ - ForkDigest: params.BeaconConfig().GenesisForkVersion, + ForkDigest: digest[:], HeadSlot: genesisState.Slot(), HeadRoot: headRoot[:], FinalizedEpoch: 5, @@ -146,7 +156,7 @@ func TestHelloRPCHandler_ReturnsHelloMessage(t *testing.T) { t.Fatal(err) } - err = r.statusRPCHandler(context.Background(), &pb.Status{ForkDigest: params.BeaconConfig().GenesisForkVersion}, stream1) + err = r.statusRPCHandler(context.Background(), &pb.Status{ForkDigest: digest[:]}, stream1) if err != nil { t.Errorf("Unxpected error: %v", err) } @@ -187,12 +197,23 @@ func TestHandshakeHandlers_Roundtrip(t *testing.T) { PreviousVersion: params.BeaconConfig().GenesisForkVersion, CurrentVersion: params.BeaconConfig().GenesisForkVersion, }, + Genesis: time.Now(), + ValidatorsRoot: [32]byte{'A'}, }, ctx: context.Background(), } + p1.Digest, err = r.forkDigest() + if err != nil { + t.Fatal(err) + } + r2 := &Service{ p2p: p2, } + p2.Digest, err = r.forkDigest() + if err != nil { + t.Fatal(err) + } r.Start() @@ -208,7 +229,7 @@ func TestHandshakeHandlers_Roundtrip(t *testing.T) { } log.WithField("status", out).Warn("received status") - resp := &pb.Status{HeadSlot: 100, ForkDigest: params.BeaconConfig().GenesisForkVersion} + resp := &pb.Status{HeadSlot: 100, ForkDigest: p2.Digest[:]} if _, err := stream.Write([]byte{responseCodeSuccess}); err != nil { t.Fatal(err) @@ -331,6 +352,8 @@ func TestStatusRPCRequest_RequestSent(t *testing.T) { PreviousVersion: params.BeaconConfig().GenesisForkVersion, CurrentVersion: params.BeaconConfig().GenesisForkVersion, }, + Genesis: time.Now(), + ValidatorsRoot: [32]byte{'A'}, }, ctx: context.Background(), } @@ -345,8 +368,12 @@ func TestStatusRPCRequest_RequestSent(t *testing.T) { if err := r.p2p.Encoding().DecodeWithLength(stream, out); err != nil { t.Fatal(err) } + digest, err := r.forkDigest() + if err != nil { + t.Fatal(err) + } expected := &pb.Status{ - ForkDigest: params.BeaconConfig().GenesisForkVersion, + ForkDigest: digest[:], HeadSlot: genesisState.Slot(), HeadRoot: headRoot[:], FinalizedEpoch: 5, @@ -407,6 +434,8 @@ func TestStatusRPCRequest_BadPeerHandshake(t *testing.T) { PreviousVersion: params.BeaconConfig().GenesisForkVersion, CurrentVersion: params.BeaconConfig().GenesisForkVersion, }, + Genesis: time.Now(), + ValidatorsRoot: [32]byte{'A'}, }, ctx: context.Background(), } diff --git a/beacon-chain/sync/service.go b/beacon-chain/sync/service.go index af1de1211b5..cf3967ce11b 100644 --- a/beacon-chain/sync/service.go +++ b/beacon-chain/sync/service.go @@ -59,6 +59,7 @@ type blockchainService interface { blockchain.ForkFetcher blockchain.AttestationReceiver blockchain.TimeFetcher + blockchain.GenesisFetcher } // NewRegularSync service. diff --git a/beacon-chain/sync/subscriber.go b/beacon-chain/sync/subscriber.go index 6eecf6e45d3..bb85dbd3fb6 100644 --- a/beacon-chain/sync/subscriber.go +++ b/beacon-chain/sync/subscriber.go @@ -17,6 +17,7 @@ import ( "github.com/prysmaticlabs/prysm/beacon-chain/p2p" "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/messagehandler" + "github.com/prysmaticlabs/prysm/shared/p2putils" "github.com/prysmaticlabs/prysm/shared/params" "github.com/prysmaticlabs/prysm/shared/roughtime" "github.com/prysmaticlabs/prysm/shared/slotutil" @@ -219,7 +220,7 @@ func (r *Service) subscribeDynamicWithSubnets( if base == nil { log.Fatalf("%s is not mapped to any message in GossipTopicMappings", topicFormat) } - digest, err := r.p2p.ForkDigest() + digest, err := r.forkDigest() if err != nil { log.WithError(err).Fatal("Could not compute fork digest") } @@ -267,7 +268,7 @@ func (r *Service) subscribeDynamic(topicFormat string, determineSubsLen func() i if base == nil { log.Fatalf("%s is not mapped to any message in GossipTopicMappings", topicFormat) } - digest, err := r.p2p.ForkDigest() + digest, err := r.forkDigest() if err != nil { log.WithError(err).Fatal("Could not compute fork digest") } @@ -385,9 +386,14 @@ func (r *Service) addDigestToTopic(topic string) string { if !strings.Contains(topic, "%x") { log.Fatal("Topic does not have appropriate formatter for digest") } - digest, err := r.p2p.ForkDigest() + digest, err := r.forkDigest() if err != nil { log.WithError(err).Fatal("Could not compute fork digest") } return fmt.Sprintf(topic, digest) } + +func (r *Service) forkDigest() ([4]byte, error) { + genRoot := r.chain.GenesisValidatorRoot() + return p2putils.CreateForkDigest(r.chain.GenesisTime(), genRoot[:]) +} diff --git a/beacon-chain/sync/subscriber_committee_index_beacon_attestation_test.go b/beacon-chain/sync/subscriber_committee_index_beacon_attestation_test.go index 3d80d799082..364f979fbba 100644 --- a/beacon-chain/sync/subscriber_committee_index_beacon_attestation_test.go +++ b/beacon-chain/sync/subscriber_committee_index_beacon_attestation_test.go @@ -61,6 +61,7 @@ func TestService_committeeIndexBeaconAttestationSubscriber_ValidMessage(t *testi State: s, Genesis: time.Now(), ValidAttestation: true, + ValidatorsRoot: [32]byte{'A'}, }, chainStarted: true, p2p: p, @@ -72,6 +73,10 @@ func TestService_committeeIndexBeaconAttestationSubscriber_ValidMessage(t *testi seenAttestationCache: c, stateSummaryCache: cache.NewStateSummaryCache(), } + p.Digest, err = r.forkDigest() + if err != nil { + t.Fatal(err) + } r.registerSubscribers() r.stateNotifier.StateFeed().Send(&feed.Event{ Type: statefeed.Initialized, diff --git a/beacon-chain/sync/subscriber_test.go b/beacon-chain/sync/subscriber_test.go index b03927a27cc..243ae7df602 100644 --- a/beacon-chain/sync/subscriber_test.go +++ b/beacon-chain/sync/subscriber_test.go @@ -31,6 +31,15 @@ func TestSubscribe_ReceivesValidMessage(t *testing.T) { ctx: context.Background(), p2p: p2p, initialSync: &mockSync.Sync{IsSyncing: false}, + chain: &mockChain.ChainService{ + ValidatorsRoot: [32]byte{'A'}, + Genesis: time.Now(), + }, + } + var err error + p2p.Digest, err = r.forkDigest() + if err != nil { + t.Fatal(err) } topic := "/eth2/%x/voluntary_exit" var wg sync.WaitGroup @@ -61,7 +70,10 @@ func TestSubscribe_ReceivesAttesterSlashing(t *testing.T) { ctx := context.Background() d := db.SetupDB(t) defer db.TeardownDB(t, d) - chainService := &mockChain.ChainService{} + chainService := &mockChain.ChainService{ + Genesis: time.Now(), + ValidatorsRoot: [32]byte{'A'}, + } c, err := lru.New(10) if err != nil { t.Fatal(err) @@ -101,6 +113,10 @@ func TestSubscribe_ReceivesAttesterSlashing(t *testing.T) { if err != nil { t.Fatal(err) } + p2p.Digest, err = r.forkDigest() + if err != nil { + t.Fatal(err) + } p2p.ReceivePubSub(topic, attesterSlashing) if testutil.WaitTimeout(&wg, time.Second) { @@ -115,7 +131,10 @@ func TestSubscribe_ReceivesAttesterSlashing(t *testing.T) { func TestSubscribe_ReceivesProposerSlashing(t *testing.T) { p2p := p2ptest.NewTestP2P(t) ctx := context.Background() - chainService := &mockChain.ChainService{} + chainService := &mockChain.ChainService{ + ValidatorsRoot: [32]byte{'A'}, + Genesis: time.Now(), + } d := db.SetupDB(t) defer db.TeardownDB(t, d) c, err := lru.New(10) @@ -157,6 +176,10 @@ func TestSubscribe_ReceivesProposerSlashing(t *testing.T) { if err := r.db.SaveState(ctx, beaconState, root); err != nil { t.Fatal(err) } + p2p.Digest, err = r.forkDigest() + if err != nil { + t.Fatal(err) + } p2p.ReceivePubSub(topic, proposerSlashing) if testutil.WaitTimeout(&wg, time.Second) { @@ -170,7 +193,10 @@ func TestSubscribe_ReceivesProposerSlashing(t *testing.T) { func TestSubscribe_WaitToSync(t *testing.T) { p2p := p2ptest.NewTestP2P(t) - chainService := &mockChain.ChainService{} + chainService := &mockChain.ChainService{ + Genesis: time.Now(), + ValidatorsRoot: [32]byte{'A'}, + } r := Service{ ctx: context.Background(), p2p: p2p, @@ -217,8 +243,17 @@ func TestSubscribe_HandlesPanic(t *testing.T) { p := p2ptest.NewTestP2P(t) r := Service{ ctx: context.Background(), + chain: &mockChain.ChainService{ + Genesis: time.Now(), + ValidatorsRoot: [32]byte{'A'}, + }, p2p: p, } + var err error + p.Digest, err = r.forkDigest() + if err != nil { + t.Fatal(err) + } topic := p2p.GossipTypeMapping[reflect.TypeOf(&pb.SignedVoluntaryExit{})] var wg sync.WaitGroup diff --git a/beacon-chain/sync/validate_aggregate_proof_test.go b/beacon-chain/sync/validate_aggregate_proof_test.go index d38cffd4b54..143265b211b 100644 --- a/beacon-chain/sync/validate_aggregate_proof_test.go +++ b/beacon-chain/sync/validate_aggregate_proof_test.go @@ -549,11 +549,13 @@ func TestVerifyIndexInCommittee_SeenAggregatorSlot(t *testing.T) { db: db, initialSync: &mockSync.Sync{IsSyncing: false}, chain: &mock.ChainService{Genesis: time.Now(), + ValidatorsRoot: [32]byte{'A'}, State: beaconState, ValidAttestation: true, FinalizedCheckPoint: ðpb.Checkpoint{ Epoch: 0, }}, + attPool: attestations.NewPool(), seenAttestationCache: c, stateSummaryCache: cache.NewStateSummaryCache(), diff --git a/beacon-chain/sync/validate_committee_index_beacon_attestation.go b/beacon-chain/sync/validate_committee_index_beacon_attestation.go index 42e6879c258..51143cbfbf7 100644 --- a/beacon-chain/sync/validate_committee_index_beacon_attestation.go +++ b/beacon-chain/sync/validate_committee_index_beacon_attestation.go @@ -62,7 +62,7 @@ func (s *Service) validateCommitteeIndexBeaconAttestation(ctx context.Context, p } // The attestation's committee index (attestation.data.index) is for the correct subnet. - digest, err := s.p2p.ForkDigest() + digest, err := s.forkDigest() if err != nil { log.WithError(err).Error("Failed to compute fork digest") traceutil.AnnotateError(span, err) diff --git a/beacon-chain/sync/validate_committee_index_beacon_attestation_test.go b/beacon-chain/sync/validate_committee_index_beacon_attestation_test.go index 5c916b1ad51..50b5460a1f3 100644 --- a/beacon-chain/sync/validate_committee_index_beacon_attestation_test.go +++ b/beacon-chain/sync/validate_committee_index_beacon_attestation_test.go @@ -3,6 +3,7 @@ package sync import ( "bytes" "context" + "fmt" "testing" "time" @@ -29,6 +30,7 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) { defer dbtest.TeardownDB(t, db) chain := &mockChain.ChainService{ Genesis: time.Now().Add(time.Duration(-64*int64(params.BeaconConfig().SecondsPerSlot)) * time.Second), // 64 slots ago + ValidatorsRoot: [32]byte{'A'}, ValidAttestation: true, } @@ -45,6 +47,10 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) { seenAttestationCache: c, stateSummaryCache: cache.NewStateSummaryCache(), } + digest, err := s.forkDigest() + if err != nil { + t.Fatal(err) + } blk := ðpb.SignedBeaconBlock{ Block: ðpb.BeaconBlock{ @@ -82,7 +88,7 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) { Slot: 63, }, }, - topic: "/eth2/00000000/committee_index1_beacon_attestation", + topic: fmt.Sprintf("/eth2/%x/committee_index1_beacon_attestation", digest), validAttestationSignature: true, want: true, }, @@ -96,7 +102,7 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) { Slot: 63, }, }, - topic: "/eth2/00000000/committee_index1_beacon_attestation", + topic: fmt.Sprintf("/eth2/%x/committee_index1_beacon_attestation", digest), validAttestationSignature: true, want: false, }, @@ -110,7 +116,7 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) { Slot: 63, }, }, - topic: "/eth2/00000000/committee_index3_beacon_attestation", + topic: fmt.Sprintf("/eth2/%x/committee_index3_beacon_attestation", digest), validAttestationSignature: true, want: false, }, @@ -124,7 +130,7 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) { Slot: 63, }, }, - topic: "/eth2/00000000/committee_index1_beacon_attestation", + topic: fmt.Sprintf("/eth2/%x/committee_index1_beacon_attestation", digest), validAttestationSignature: true, want: false, }, @@ -138,7 +144,7 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) { Slot: 63, }, }, - topic: "/eth2/00000000/committee_index1_beacon_attestation", + topic: fmt.Sprintf("/eth2/%x/committee_index1_beacon_attestation", digest), validAttestationSignature: true, want: false, }, @@ -152,7 +158,7 @@ func TestService_validateCommitteeIndexBeaconAttestation(t *testing.T) { Slot: 63, }, }, - topic: "/eth2/00000000/committee_index1_beacon_attestation", + topic: fmt.Sprintf("/eth2/%x/committee_index1_beacon_attestation", digest), validAttestationSignature: false, want: false, }, diff --git a/shared/p2putils/BUILD.bazel b/shared/p2putils/BUILD.bazel new file mode 100644 index 00000000000..b656065d474 --- /dev/null +++ b/shared/p2putils/BUILD.bazel @@ -0,0 +1,13 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["fork.go"], + importpath = "github.com/prysmaticlabs/prysm/shared/p2putils", + visibility = ["//visibility:public"], + deps = [ + "//beacon-chain/core/helpers:go_default_library", + "//shared/params:go_default_library", + "@com_github_pkg_errors//:go_default_library", + ], +) diff --git a/shared/p2putils/fork.go b/shared/p2putils/fork.go new file mode 100644 index 00000000000..52b2681582c --- /dev/null +++ b/shared/p2putils/fork.go @@ -0,0 +1,44 @@ +package p2putils + +import ( + "time" + + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" + "github.com/prysmaticlabs/prysm/shared/params" +) + +// CreateForkDigest creates a fork digest from a genesis time and genesis +// validators root, utilizing the current slot to determine +// the active fork version in the node. +func CreateForkDigest( + genesisTime time.Time, + genesisValidatorsRoot []byte, +) ([4]byte, error) { + if genesisTime.IsZero() { + return [4]byte{}, errors.New("genesis time is not set") + } + if len(genesisValidatorsRoot) == 0 { + return [4]byte{}, errors.New("genesis validators root is not set") + } + currentSlot := helpers.SlotsSince(genesisTime) + currentEpoch := helpers.SlotToEpoch(currentSlot) + + // We retrieve a list of scheduled forks by epoch. + // We loop through the keys in this map to determine the current + // fork version based on the current, time-based epoch number + // since the genesis time. + currentForkVersion := params.BeaconConfig().GenesisForkVersion + scheduledForks := params.BeaconConfig().ForkVersionSchedule + for epoch, forkVersion := range scheduledForks { + if epoch <= currentEpoch { + currentForkVersion = forkVersion + } + } + + digest, err := helpers.ComputeForkDigest(currentForkVersion, genesisValidatorsRoot) + if err != nil { + return [4]byte{}, err + } + return digest, nil +}