kraken
1// Copyright (c) 2016-2019 Uber Technologies, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package core15
16import (17"bytes"18"crypto/sha1"19"encoding/hex"20"errors"21"fmt"22"io"23"math/rand"24)
25
26// PeerIDFactory defines the method used to generate a peer id.
27type PeerIDFactory string28
29// RandomPeerIDFactory creates random peer ids.
30const RandomPeerIDFactory PeerIDFactory = "random"31
32// AddrHashPeerIDFactory creates peers ids based on a full "ip:port" address.
33const AddrHashPeerIDFactory PeerIDFactory = "addr_hash"34
35// GeneratePeerID creates a new peer id per the factory policy.
36func (f PeerIDFactory) GeneratePeerID(ip string, port int) (PeerID, error) {37switch f {38case RandomPeerIDFactory:39return RandomPeerID()40case AddrHashPeerIDFactory:41return HashedPeerID(fmt.Sprintf("%s:%d", ip, port))42default:43err := fmt.Errorf("invalid peer id factory: %q", string(f))44return PeerID{}, err45}46}
47
48// ErrInvalidPeerIDLength returns when a string peer id does not decode into 20 bytes.
49var ErrInvalidPeerIDLength = errors.New("peer id has invalid length")50
51// PeerID represents a fixed size peer id.
52type PeerID [20]byte53
54// NewPeerID parses a PeerID from the given string. Must be in hexadecimal notation,
55// encoding exactly 20 bytes.
56func NewPeerID(s string) (PeerID, error) {57b, err := hex.DecodeString(s)58if err != nil {59return PeerID{}, err60}61if len(b) != 20 {62return PeerID{}, ErrInvalidPeerIDLength63}64var p PeerID65copy(p[:], b)66return p, nil67}
68
69// String encodes the PeerID in hexadecimal notation.
70func (p PeerID) String() string {71return hex.EncodeToString(p[:])72}
73
74// LessThan returns whether p is less than o.
75func (p PeerID) LessThan(o PeerID) bool {76return bytes.Compare(p[:], o[:]) == -177}
78
79// RandomPeerID returns a randomly generated PeerID.
80func RandomPeerID() (PeerID, error) {81var p PeerID82_, err := rand.Read(p[:])83return p, err84}
85
86// HashedPeerID returns a PeerID derived from the hash of s.
87func HashedPeerID(s string) (PeerID, error) {88var p PeerID89if s == "" {90return p, errors.New("cannot generate peer id from empty string")91}92h := sha1.New()93io.WriteString(h, s)94copy(p[:], h.Sum(nil))95return p, nil96}
97