github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/p2p/utils.go (about) 1 package p2p 2 3 import ( 4 "bytes" 5 "crypto/ecdsa" 6 "crypto/rand" 7 "encoding/base64" 8 "encoding/hex" 9 "fmt" 10 "io/ioutil" 11 "net" 12 "os" 13 "path" 14 "time" 15 16 gcrypto "github.com/ethereum/go-ethereum/crypto" 17 "github.com/ethereum/go-ethereum/p2p/enr" 18 "github.com/libp2p/go-libp2p-core/crypto" 19 "github.com/pkg/errors" 20 "github.com/prysmaticlabs/go-bitfield" 21 pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 22 "github.com/prysmaticlabs/prysm/shared/fileutil" 23 "github.com/prysmaticlabs/prysm/shared/interfaces" 24 "github.com/prysmaticlabs/prysm/shared/iputils" 25 "github.com/sirupsen/logrus" 26 "google.golang.org/protobuf/proto" 27 ) 28 29 const keyPath = "network-keys" 30 const metaDataPath = "metaData" 31 32 const dialTimeout = 1 * time.Second 33 34 // SerializeENR takes the enr record in its key-value form and serializes it. 35 func SerializeENR(record *enr.Record) (string, error) { 36 if record == nil { 37 return "", errors.New("could not serialize nil record") 38 } 39 buf := bytes.NewBuffer([]byte{}) 40 if err := record.EncodeRLP(buf); err != nil { 41 return "", errors.Wrap(err, "could not encode ENR record to bytes") 42 } 43 enrString := base64.URLEncoding.EncodeToString(buf.Bytes()) 44 return enrString, nil 45 } 46 47 func convertFromInterfacePrivKey(privkey crypto.PrivKey) *ecdsa.PrivateKey { 48 typeAssertedKey := (*ecdsa.PrivateKey)(privkey.(*crypto.Secp256k1PrivateKey)) 49 typeAssertedKey.Curve = gcrypto.S256() // Temporary hack, so libp2p Secp256k1 is recognized as geth Secp256k1 in disc v5.1. 50 return typeAssertedKey 51 } 52 53 func convertToInterfacePrivkey(privkey *ecdsa.PrivateKey) crypto.PrivKey { 54 typeAssertedKey := crypto.PrivKey((*crypto.Secp256k1PrivateKey)(privkey)) 55 return typeAssertedKey 56 } 57 58 func convertToInterfacePubkey(pubkey *ecdsa.PublicKey) crypto.PubKey { 59 typeAssertedKey := crypto.PubKey((*crypto.Secp256k1PublicKey)(pubkey)) 60 return typeAssertedKey 61 } 62 63 // Determines a private key for p2p networking from the p2p service's 64 // configuration struct. If no key is found, it generates a new one. 65 func privKey(cfg *Config) (*ecdsa.PrivateKey, error) { 66 defaultKeyPath := path.Join(cfg.DataDir, keyPath) 67 privateKeyPath := cfg.PrivateKey 68 69 _, err := os.Stat(defaultKeyPath) 70 defaultKeysExist := !os.IsNotExist(err) 71 if err != nil && defaultKeysExist { 72 return nil, err 73 } 74 75 if privateKeyPath == "" && !defaultKeysExist { 76 priv, _, err := crypto.GenerateSecp256k1Key(rand.Reader) 77 if err != nil { 78 return nil, err 79 } 80 convertedKey := convertFromInterfacePrivKey(priv) 81 return convertedKey, nil 82 } 83 if defaultKeysExist && privateKeyPath == "" { 84 privateKeyPath = defaultKeyPath 85 } 86 return privKeyFromFile(privateKeyPath) 87 } 88 89 // Retrieves a p2p networking private key from a file path. 90 func privKeyFromFile(path string) (*ecdsa.PrivateKey, error) { 91 src, err := ioutil.ReadFile(path) 92 if err != nil { 93 log.WithError(err).Error("Error reading private key from file") 94 return nil, err 95 } 96 dst := make([]byte, hex.DecodedLen(len(src))) 97 _, err = hex.Decode(dst, src) 98 if err != nil { 99 return nil, errors.Wrap(err, "failed to decode hex string") 100 } 101 unmarshalledKey, err := crypto.UnmarshalSecp256k1PrivateKey(dst) 102 if err != nil { 103 return nil, err 104 } 105 return convertFromInterfacePrivKey(unmarshalledKey), nil 106 } 107 108 // Retrieves node p2p metadata from a set of configuration values 109 // from the p2p service. 110 // TODO: Figure out how to do a v1/v2 check. 111 func metaDataFromConfig(cfg *Config) (interfaces.Metadata, error) { 112 defaultKeyPath := path.Join(cfg.DataDir, metaDataPath) 113 metaDataPath := cfg.MetaDataDir 114 115 _, err := os.Stat(defaultKeyPath) 116 defaultMetadataExist := !os.IsNotExist(err) 117 if err != nil && defaultMetadataExist { 118 return nil, err 119 } 120 if metaDataPath == "" && !defaultMetadataExist { 121 metaData := &pbp2p.MetaDataV0{ 122 SeqNumber: 0, 123 Attnets: bitfield.NewBitvector64(), 124 } 125 dst, err := proto.Marshal(metaData) 126 if err != nil { 127 return nil, err 128 } 129 if err := fileutil.WriteFile(defaultKeyPath, dst); err != nil { 130 return nil, err 131 } 132 return interfaces.WrappedMetadataV0(metaData), nil 133 } 134 if defaultMetadataExist && metaDataPath == "" { 135 metaDataPath = defaultKeyPath 136 } 137 src, err := ioutil.ReadFile(metaDataPath) 138 if err != nil { 139 log.WithError(err).Error("Error reading metadata from file") 140 return nil, err 141 } 142 metaData := &pbp2p.MetaDataV0{} 143 if err := proto.Unmarshal(src, metaData); err != nil { 144 return nil, err 145 } 146 return interfaces.WrappedMetadataV0(metaData), nil 147 } 148 149 // Retrieves an external ipv4 address and converts into a libp2p formatted value. 150 func ipAddr() net.IP { 151 ip, err := iputils.ExternalIP() 152 if err != nil { 153 log.Fatalf("Could not get IPv4 address: %v", err) 154 } 155 return net.ParseIP(ip) 156 } 157 158 // Attempt to dial an address to verify its connectivity 159 func verifyConnectivity(addr string, port uint, protocol string) { 160 if addr != "" { 161 a := net.JoinHostPort(addr, fmt.Sprintf("%d", port)) 162 fields := logrus.Fields{ 163 "protocol": protocol, 164 "address": a, 165 } 166 conn, err := net.DialTimeout(protocol, a, dialTimeout) 167 if err != nil { 168 log.WithError(err).WithFields(fields).Warn("IP address is not accessible") 169 return 170 } 171 if err := conn.Close(); err != nil { 172 log.WithError(err).Debug("Could not close connection") 173 } 174 } 175 }