github.com/amazechain/amc@v0.1.3/internal/p2p/utils.go (about)

     1  package p2p
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/ecdsa"
     6  	"crypto/rand"
     7  	"encoding/base64"
     8  	"encoding/binary"
     9  	"encoding/hex"
    10  	"fmt"
    11  	"github.com/amazechain/amc/api/protocol/sync_pb"
    12  	"github.com/amazechain/amc/conf"
    13  	"github.com/amazechain/amc/internal/p2p/enr"
    14  	"github.com/amazechain/amc/utils"
    15  	"net"
    16  	"os"
    17  	"path"
    18  	"time"
    19  
    20  	"github.com/libp2p/go-libp2p/core/crypto"
    21  	"github.com/pkg/errors"
    22  )
    23  
    24  const keyPath = "network-keys"
    25  
    26  const seqPath = "network-seq"
    27  
    28  const dialTimeout = 1 * time.Second
    29  
    30  // SerializeENR takes the enr record in its key-value form and serializes it.
    31  func SerializeENR(record *enr.Record) (string, error) {
    32  	if record == nil {
    33  		return "", errors.New("could not serialize nil record")
    34  	}
    35  	buf := bytes.NewBuffer([]byte{})
    36  	if err := record.EncodeRLP(buf); err != nil {
    37  		return "", errors.Wrap(err, "could not encode ENR record to bytes")
    38  	}
    39  	enrString := base64.RawURLEncoding.EncodeToString(buf.Bytes())
    40  	return enrString, nil
    41  }
    42  
    43  func getSeqNumber(cfg *conf.P2PConfig) (*sync_pb.Ping, error) {
    44  	defaultSeqPath := path.Join(cfg.DataDir, seqPath)
    45  
    46  	_, err := os.Stat(defaultSeqPath)
    47  	defaultKeysExist := !os.IsNotExist(err)
    48  	if err != nil && defaultKeysExist {
    49  		log.Error("Error reading network seqNumber from file", "err", err)
    50  		return nil, err
    51  	}
    52  
    53  	if defaultKeysExist {
    54  		src, err := os.ReadFile(defaultSeqPath) // #nosec G304
    55  		if err != nil {
    56  			log.Error("Error reading network seqNumber from file", "err", err)
    57  			return nil, err
    58  		}
    59  		//dst := make([]byte, hex.DecodedLen(len(src)))
    60  		//_, err = hex.Decode(dst, src)
    61  		//if err != nil {
    62  		//	return nil, errors.Wrap(err, "failed to decode hex string")
    63  		//}
    64  
    65  		seqNumber := binary.LittleEndian.Uint64(src)
    66  		if seqNumber > 0 {
    67  			log.Info("Load seq number from file", "seqNumber", seqNumber)
    68  			return &sync_pb.Ping{SeqNumber: seqNumber}, nil
    69  		}
    70  
    71  	}
    72  	return &sync_pb.Ping{SeqNumber: 0}, nil
    73  }
    74  
    75  func saveSeqNumber(cfg *conf.P2PConfig, seqNumber *sync_pb.Ping) error {
    76  
    77  	defaultSeqPath := path.Join(cfg.DataDir, seqPath)
    78  
    79  	b := make([]byte, 8)
    80  	binary.LittleEndian.PutUint64(b, seqNumber.SeqNumber)
    81  
    82  	if err := os.WriteFile(defaultSeqPath, b, 0600); err != nil {
    83  		log.Error("Failed to save p2p seq number", "err", err)
    84  		return err
    85  	}
    86  	log.Info("Wrote seq number to file", "seqNumber", seqNumber.SeqNumber)
    87  	return nil
    88  }
    89  
    90  // Determines a private key for p2p networking from the p2p service's
    91  // configuration struct. If no key is found, it generates a new one.
    92  func privKey(cfg *conf.P2PConfig) (*ecdsa.PrivateKey, error) {
    93  	defaultKeyPath := path.Join(cfg.DataDir, keyPath)
    94  	privateKeyPath := cfg.PrivateKey
    95  
    96  	// PrivateKey cli flag takes highest precedence.
    97  	if privateKeyPath != "" {
    98  		return privKeyFromFile(cfg.PrivateKey)
    99  	}
   100  
   101  	_, err := os.Stat(defaultKeyPath)
   102  	defaultKeysExist := !os.IsNotExist(err)
   103  	if err != nil && defaultKeysExist {
   104  		return nil, err
   105  	}
   106  	// Default keys have the next highest precedence, if they exist.
   107  	if defaultKeysExist {
   108  		return privKeyFromFile(defaultKeyPath)
   109  	}
   110  	// There are no keys on the filesystem, so we need to generate one.
   111  	priv, _, err := crypto.GenerateSecp256k1Key(rand.Reader)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	// If the StaticPeerID flag is set, save the generated key as the default
   116  	// key, so that it will be used by default on the next node start.
   117  	if cfg.StaticPeerID {
   118  		rawbytes, err := priv.Raw()
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  		dst := make([]byte, hex.EncodedLen(len(rawbytes)))
   123  		hex.Encode(dst, rawbytes)
   124  		if err := os.WriteFile(defaultKeyPath, dst, 0600); err != nil {
   125  			return nil, err
   126  		}
   127  		log.Info("Wrote network key to file")
   128  		// Read the key from the defaultKeyPath file just written
   129  		// for the strongest guarantee that the next start will be the same as this one.
   130  		return privKeyFromFile(defaultKeyPath)
   131  	}
   132  	return utils.ConvertFromInterfacePrivKey(priv)
   133  }
   134  
   135  // Retrieves a p2p networking private key from a file path.
   136  func privKeyFromFile(path string) (*ecdsa.PrivateKey, error) {
   137  	src, err := os.ReadFile(path) // #nosec G304
   138  	if err != nil {
   139  		log.Error("Error reading private key from file", "err", err)
   140  		return nil, err
   141  	}
   142  	dst := make([]byte, hex.DecodedLen(len(src)))
   143  	_, err = hex.Decode(dst, src)
   144  	if err != nil {
   145  		return nil, errors.Wrap(err, "failed to decode hex string")
   146  	}
   147  	unmarshalledKey, err := crypto.UnmarshalSecp256k1PrivateKey(dst)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	return utils.ConvertFromInterfacePrivKey(unmarshalledKey)
   152  }
   153  
   154  // Attempt to dial an address to verify its connectivity
   155  func verifyConnectivity(addr string, port int, protocol string) {
   156  	if addr != "" {
   157  		a := net.JoinHostPort(addr, fmt.Sprintf("%d", port))
   158  
   159  		conn, err := net.DialTimeout(protocol, a, dialTimeout)
   160  		if err != nil {
   161  			log.Warn("IP address is not accessible", "err", err, "protocol", protocol, "address", a)
   162  			return
   163  		}
   164  		if err := conn.Close(); err != nil {
   165  			log.Debug("Could not close connection", "err", err)
   166  		}
   167  	}
   168  }