diff --git a/beacon-chain/p2p/fork.go b/beacon-chain/p2p/fork.go index 5e8a5370f2..f3a279b4ce 100644 --- a/beacon-chain/p2p/fork.go +++ b/beacon-chain/p2p/fork.go @@ -81,11 +81,23 @@ func updateENR(node *enode.LocalNode, entry, next params.NetworkScheduleEntry) e NextForkVersion: next.ForkVersion[:], NextForkEpoch: next.Epoch, } - log. - WithField("CurrentForkDigest", fmt.Sprintf("%#x", enrForkID.CurrentForkDigest)). - WithField("NextForkVersion", fmt.Sprintf("%#x", enrForkID.NextForkVersion)). - WithField("NextForkEpoch", fmt.Sprintf("%d", enrForkID.NextForkEpoch)). - Info("Updating ENR Fork ID") + if entry.Epoch == next.Epoch { + enrForkID.NextForkEpoch = params.BeaconConfig().FarFutureEpoch + } + logFields := logrus.Fields{ + "CurrentForkDigest": fmt.Sprintf("%#x", enrForkID.CurrentForkDigest), + "NextForkVersion": fmt.Sprintf("%#x", enrForkID.NextForkVersion), + "NextForkEpoch": fmt.Sprintf("%d", enrForkID.NextForkEpoch), + } + if params.BeaconConfig().FuluForkEpoch != params.BeaconConfig().FarFutureEpoch { + if entry.ForkDigest == next.ForkDigest { + node.Set(enr.WithEntry(nfdEnrKey, make([]byte, len(next.ForkDigest)))) + } else { + node.Set(enr.WithEntry(nfdEnrKey, next.ForkDigest[:])) + } + logFields["NextForkDigest"] = fmt.Sprintf("%#x", next.ForkDigest) + } + log.WithFields(logFields).Info("Updating ENR Fork ID") enc, err := enrForkID.MarshalSSZ() if err != nil { return err diff --git a/beacon-chain/p2p/fork_test.go b/beacon-chain/p2p/fork_test.go index 8971813fd7..4b0f7f1b05 100644 --- a/beacon-chain/p2p/fork_test.go +++ b/beacon-chain/p2p/fork_test.go @@ -177,3 +177,111 @@ func TestAddForkEntry_NextForkVersion(t *testing.T) { "Wanted Next Fork Version to be equal to last entry in schedule") } + +func TestUpdateENR_FuluForkDigest(t *testing.T) { + setupTest := func(t *testing.T, fuluEnabled bool) (*enode.LocalNode, func()) { + params.SetupTestConfigCleanup(t) + + cfg := params.BeaconConfig().Copy() + if fuluEnabled { + cfg.FuluForkEpoch = 100 + } else { + cfg.FuluForkEpoch = cfg.FarFutureEpoch + } + cfg.FuluForkVersion = []byte{5, 0, 0, 0} + params.OverrideBeaconConfig(cfg) + cfg.InitializeForkSchedule() + + pkey, err := privKey(&Config{DataDir: t.TempDir()}) + require.NoError(t, err, "Could not get private key") + db, err := enode.OpenDB("") + require.NoError(t, err) + + localNode := enode.NewLocalNode(db, pkey) + cleanup := func() { + db.Close() + } + + return localNode, cleanup + } + + tests := []struct { + name string + fuluEnabled bool + currentEntry params.NetworkScheduleEntry + nextEntry params.NetworkScheduleEntry + validateNFD func(t *testing.T, localNode *enode.LocalNode, nextEntry params.NetworkScheduleEntry) + }{ + { + name: "different digests sets nfd to next digest", + fuluEnabled: true, + currentEntry: params.NetworkScheduleEntry{ + Epoch: 50, + ForkDigest: [4]byte{1, 2, 3, 4}, + ForkVersion: [4]byte{1, 0, 0, 0}, + }, + nextEntry: params.NetworkScheduleEntry{ + Epoch: 100, + ForkDigest: [4]byte{5, 6, 7, 8}, // Different from current + ForkVersion: [4]byte{2, 0, 0, 0}, + }, + validateNFD: func(t *testing.T, localNode *enode.LocalNode, nextEntry params.NetworkScheduleEntry) { + var nfdValue []byte + err := localNode.Node().Record().Load(enr.WithEntry(nfdEnrKey, &nfdValue)) + require.NoError(t, err) + assert.DeepEqual(t, nextEntry.ForkDigest[:], nfdValue, "nfd entry should equal next fork digest") + }, + }, + { + name: "same digests sets nfd to empty", + fuluEnabled: true, + currentEntry: params.NetworkScheduleEntry{ + Epoch: 50, + ForkDigest: [4]byte{1, 2, 3, 4}, + ForkVersion: [4]byte{1, 0, 0, 0}, + }, + nextEntry: params.NetworkScheduleEntry{ + Epoch: 100, + ForkDigest: [4]byte{1, 2, 3, 4}, // Same as current + ForkVersion: [4]byte{2, 0, 0, 0}, + }, + validateNFD: func(t *testing.T, localNode *enode.LocalNode, nextEntry params.NetworkScheduleEntry) { + var nfdValue []byte + err := localNode.Node().Record().Load(enr.WithEntry(nfdEnrKey, &nfdValue)) + require.NoError(t, err) + assert.DeepEqual(t, make([]byte, len(nextEntry.ForkDigest)), nfdValue, "nfd entry should be empty bytes when digests are same") + }, + }, + { + name: "fulu disabled does not add nfd field", + fuluEnabled: false, + currentEntry: params.NetworkScheduleEntry{ + Epoch: 50, + ForkDigest: [4]byte{1, 2, 3, 4}, + ForkVersion: [4]byte{1, 0, 0, 0}, + }, + nextEntry: params.NetworkScheduleEntry{ + Epoch: 100, + ForkDigest: [4]byte{5, 6, 7, 8}, // Different from current + ForkVersion: [4]byte{2, 0, 0, 0}, + }, + validateNFD: func(t *testing.T, localNode *enode.LocalNode, nextEntry params.NetworkScheduleEntry) { + var nfdValue []byte + err := localNode.Node().Record().Load(enr.WithEntry(nfdEnrKey, &nfdValue)) + require.ErrorContains(t, "missing ENR key", err, "nfd field should not be present when Fulu fork is disabled") + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + localNode, cleanup := setupTest(t, tt.fuluEnabled) + defer cleanup() + + currentEntry := tt.currentEntry + nextEntry := tt.nextEntry + require.NoError(t, updateENR(localNode, currentEntry, nextEntry)) + tt.validateNFD(t, localNode, nextEntry) + }) + } +} diff --git a/beacon-chain/p2p/subnets.go b/beacon-chain/p2p/subnets.go index 152e10914f..33020eac7b 100644 --- a/beacon-chain/p2p/subnets.go +++ b/beacon-chain/p2p/subnets.go @@ -27,6 +27,8 @@ import ( "github.com/prysmaticlabs/go-bitfield" ) +const nfdEnrKey = "nfd" // The ENR record key for "nfd" (Next Fork Digest). + var ( attestationSubnetCount = params.BeaconConfig().AttestationSubnetCount syncCommsSubnetCount = params.BeaconConfig().SyncCommitteeSubnetCount diff --git a/changelog/kasey_fusaka-nfd.md b/changelog/kasey_fusaka-nfd.md new file mode 100644 index 0000000000..3193f63a93 --- /dev/null +++ b/changelog/kasey_fusaka-nfd.md @@ -0,0 +1,2 @@ +### Added +- Support for fusaka `nfd` enr field, and changes to the semantics of the eth2 field.