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  }