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 }