github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/p2p/fork.go (about) 1 package p2p 2 3 import ( 4 "bytes" 5 "fmt" 6 "math" 7 "time" 8 9 "github.com/ethereum/go-ethereum/p2p/enode" 10 "github.com/ethereum/go-ethereum/p2p/enr" 11 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 12 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 13 "github.com/prysmaticlabs/prysm/shared/p2putils" 14 "github.com/prysmaticlabs/prysm/shared/params" 15 "github.com/prysmaticlabs/prysm/shared/timeutils" 16 "github.com/sirupsen/logrus" 17 ) 18 19 // ENR key used for Ethereum consensus-related fork data. 20 var eth2ENRKey = params.BeaconNetworkConfig().ETH2Key 21 22 // ForkDigest returns the current fork digest of 23 // the node. 24 func (s *Service) forkDigest() ([4]byte, error) { 25 if s.currentForkDigest != [4]byte{} { 26 return s.currentForkDigest, nil 27 } 28 fd, err := p2putils.CreateForkDigest(s.genesisTime, s.genesisValidatorsRoot) 29 if err != nil { 30 s.currentForkDigest = fd 31 } 32 return fd, err 33 } 34 35 // Compares fork ENRs between an incoming peer's record and our node's 36 // local record values for current and next fork version/epoch. 37 func (s *Service) compareForkENR(record *enr.Record) error { 38 currentRecord := s.dv5Listener.LocalNode().Node().Record() 39 peerForkENR, err := forkEntry(record) 40 if err != nil { 41 return err 42 } 43 currentForkENR, err := forkEntry(currentRecord) 44 if err != nil { 45 return err 46 } 47 enrString, err := SerializeENR(record) 48 if err != nil { 49 return err 50 } 51 // Clients SHOULD connect to peers with current_fork_digest, next_fork_version, 52 // and next_fork_epoch that match local values. 53 if !bytes.Equal(peerForkENR.CurrentForkDigest, currentForkENR.CurrentForkDigest) { 54 return fmt.Errorf( 55 "fork digest of peer with ENR %s: %v, does not match local value: %v", 56 enrString, 57 peerForkENR.CurrentForkDigest, 58 currentForkENR.CurrentForkDigest, 59 ) 60 } 61 // Clients MAY connect to peers with the same current_fork_version but a 62 // different next_fork_version/next_fork_epoch. Unless ENRForkID is manually 63 // updated to matching prior to the earlier next_fork_epoch of the two clients, 64 // these type of connecting clients will be unable to successfully interact 65 // starting at the earlier next_fork_epoch. 66 if peerForkENR.NextForkEpoch != currentForkENR.NextForkEpoch { 67 log.WithFields(logrus.Fields{ 68 "peerNextForkEpoch": peerForkENR.NextForkEpoch, 69 "peerENR": enrString, 70 }).Debug("Peer matches fork digest but has different next fork epoch") 71 } 72 if !bytes.Equal(peerForkENR.NextForkVersion, currentForkENR.NextForkVersion) { 73 log.WithFields(logrus.Fields{ 74 "peerNextForkVersion": peerForkENR.NextForkVersion, 75 "peerENR": enrString, 76 }).Debug("Peer matches fork digest but has different next fork version") 77 } 78 return nil 79 } 80 81 // Adds a fork entry as an ENR record under the Ethereum consensus EnrKey for 82 // the local node. The fork entry is an ssz-encoded enrForkID type 83 // which takes into account the current fork version from the current 84 // epoch to create a fork digest, the next fork version, 85 // and the next fork epoch. 86 func addForkEntry( 87 node *enode.LocalNode, 88 genesisTime time.Time, 89 genesisValidatorsRoot []byte, 90 ) (*enode.LocalNode, error) { 91 digest, err := p2putils.CreateForkDigest(genesisTime, genesisValidatorsRoot) 92 if err != nil { 93 return nil, err 94 } 95 currentSlot := helpers.SlotsSince(genesisTime) 96 currentEpoch := helpers.SlotToEpoch(currentSlot) 97 if timeutils.Now().Before(genesisTime) { 98 currentEpoch = 0 99 } 100 fork, err := p2putils.Fork(currentEpoch) 101 if err != nil { 102 return nil, err 103 } 104 105 nextForkEpoch := params.BeaconConfig().NextForkEpoch 106 nextForkVersion := params.BeaconConfig().NextForkVersion 107 // Set to the current fork version if our next fork is not planned. 108 if nextForkEpoch == math.MaxUint64 { 109 nextForkVersion = fork.CurrentVersion 110 } 111 enrForkID := &pb.ENRForkID{ 112 CurrentForkDigest: digest[:], 113 NextForkVersion: nextForkVersion, 114 NextForkEpoch: nextForkEpoch, 115 } 116 enc, err := enrForkID.MarshalSSZ() 117 if err != nil { 118 return nil, err 119 } 120 forkEntry := enr.WithEntry(eth2ENRKey, enc) 121 node.Set(forkEntry) 122 return node, nil 123 } 124 125 // Retrieves an enrForkID from an ENR record by key lookup 126 // under the Ethereum consensus EnrKey 127 func forkEntry(record *enr.Record) (*pb.ENRForkID, error) { 128 sszEncodedForkEntry := make([]byte, 16) 129 entry := enr.WithEntry(eth2ENRKey, &sszEncodedForkEntry) 130 err := record.Load(entry) 131 if err != nil { 132 return nil, err 133 } 134 forkEntry := &pb.ENRForkID{} 135 if err := forkEntry.UnmarshalSSZ(sszEncodedForkEntry); err != nil { 136 return nil, err 137 } 138 return forkEntry, nil 139 }