github.com/impedro29/bor@v0.1.4/p2p/discover/table_util_test.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package discover
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"encoding/hex"
    22  	"fmt"
    23  	"math/rand"
    24  	"net"
    25  	"sort"
    26  	"sync"
    27  
    28  	"github.com/maticnetwork/bor/crypto"
    29  	"github.com/maticnetwork/bor/log"
    30  	"github.com/maticnetwork/bor/p2p/enode"
    31  	"github.com/maticnetwork/bor/p2p/enr"
    32  )
    33  
    34  var nullNode *enode.Node
    35  
    36  func init() {
    37  	var r enr.Record
    38  	r.Set(enr.IP{0, 0, 0, 0})
    39  	nullNode = enode.SignNull(&r, enode.ID{})
    40  }
    41  
    42  func newTestTable(t transport) (*Table, *enode.DB) {
    43  	db, _ := enode.OpenDB("")
    44  	tab, _ := newTable(t, db, nil, log.Root())
    45  	go tab.loop()
    46  	return tab, db
    47  }
    48  
    49  // nodeAtDistance creates a node for which enode.LogDist(base, n.id) == ld.
    50  func nodeAtDistance(base enode.ID, ld int, ip net.IP) *node {
    51  	var r enr.Record
    52  	r.Set(enr.IP(ip))
    53  	return wrapNode(enode.SignNull(&r, idAtDistance(base, ld)))
    54  }
    55  
    56  // idAtDistance returns a random hash such that enode.LogDist(a, b) == n
    57  func idAtDistance(a enode.ID, n int) (b enode.ID) {
    58  	if n == 0 {
    59  		return a
    60  	}
    61  	// flip bit at position n, fill the rest with random bits
    62  	b = a
    63  	pos := len(a) - n/8 - 1
    64  	bit := byte(0x01) << (byte(n%8) - 1)
    65  	if bit == 0 {
    66  		pos++
    67  		bit = 0x80
    68  	}
    69  	b[pos] = a[pos]&^bit | ^a[pos]&bit // TODO: randomize end bits
    70  	for i := pos + 1; i < len(a); i++ {
    71  		b[i] = byte(rand.Intn(255))
    72  	}
    73  	return b
    74  }
    75  
    76  func intIP(i int) net.IP {
    77  	return net.IP{byte(i), 0, 2, byte(i)}
    78  }
    79  
    80  // fillBucket inserts nodes into the given bucket until it is full.
    81  func fillBucket(tab *Table, n *node) (last *node) {
    82  	ld := enode.LogDist(tab.self().ID(), n.ID())
    83  	b := tab.bucket(n.ID())
    84  	for len(b.entries) < bucketSize {
    85  		b.entries = append(b.entries, nodeAtDistance(tab.self().ID(), ld, intIP(ld)))
    86  	}
    87  	return b.entries[bucketSize-1]
    88  }
    89  
    90  // fillTable adds nodes the table to the end of their corresponding bucket
    91  // if the bucket is not full. The caller must not hold tab.mutex.
    92  func fillTable(tab *Table, nodes []*node) {
    93  	for _, n := range nodes {
    94  		tab.addSeenNode(n)
    95  	}
    96  }
    97  
    98  type pingRecorder struct {
    99  	mu           sync.Mutex
   100  	dead, pinged map[enode.ID]bool
   101  	records      map[enode.ID]*enode.Node
   102  	n            *enode.Node
   103  }
   104  
   105  func newPingRecorder() *pingRecorder {
   106  	var r enr.Record
   107  	r.Set(enr.IP{0, 0, 0, 0})
   108  	n := enode.SignNull(&r, enode.ID{})
   109  
   110  	return &pingRecorder{
   111  		dead:    make(map[enode.ID]bool),
   112  		pinged:  make(map[enode.ID]bool),
   113  		records: make(map[enode.ID]*enode.Node),
   114  		n:       n,
   115  	}
   116  }
   117  
   118  // setRecord updates a node record. Future calls to ping and
   119  // requestENR will return this record.
   120  func (t *pingRecorder) updateRecord(n *enode.Node) {
   121  	t.mu.Lock()
   122  	defer t.mu.Unlock()
   123  	t.records[n.ID()] = n
   124  }
   125  
   126  // Stubs to satisfy the transport interface.
   127  func (t *pingRecorder) Self() *enode.Node           { return nullNode }
   128  func (t *pingRecorder) lookupSelf() []*enode.Node   { return nil }
   129  func (t *pingRecorder) lookupRandom() []*enode.Node { return nil }
   130  func (t *pingRecorder) close()                      {}
   131  
   132  // ping simulates a ping request.
   133  func (t *pingRecorder) ping(n *enode.Node) (seq uint64, err error) {
   134  	t.mu.Lock()
   135  	defer t.mu.Unlock()
   136  
   137  	t.pinged[n.ID()] = true
   138  	if t.dead[n.ID()] {
   139  		return 0, errTimeout
   140  	}
   141  	if t.records[n.ID()] != nil {
   142  		seq = t.records[n.ID()].Seq()
   143  	}
   144  	return seq, nil
   145  }
   146  
   147  // requestENR simulates an ENR request.
   148  func (t *pingRecorder) RequestENR(n *enode.Node) (*enode.Node, error) {
   149  	t.mu.Lock()
   150  	defer t.mu.Unlock()
   151  
   152  	if t.dead[n.ID()] || t.records[n.ID()] == nil {
   153  		return nil, errTimeout
   154  	}
   155  	return t.records[n.ID()], nil
   156  }
   157  
   158  func hasDuplicates(slice []*node) bool {
   159  	seen := make(map[enode.ID]bool)
   160  	for i, e := range slice {
   161  		if e == nil {
   162  			panic(fmt.Sprintf("nil *Node at %d", i))
   163  		}
   164  		if seen[e.ID()] {
   165  			return true
   166  		}
   167  		seen[e.ID()] = true
   168  	}
   169  	return false
   170  }
   171  
   172  func sortedByDistanceTo(distbase enode.ID, slice []*node) bool {
   173  	return sort.SliceIsSorted(slice, func(i, j int) bool {
   174  		return enode.DistCmp(distbase, slice[i].ID(), slice[j].ID()) < 0
   175  	})
   176  }
   177  
   178  func hexEncPrivkey(h string) *ecdsa.PrivateKey {
   179  	b, err := hex.DecodeString(h)
   180  	if err != nil {
   181  		panic(err)
   182  	}
   183  	key, err := crypto.ToECDSA(b)
   184  	if err != nil {
   185  		panic(err)
   186  	}
   187  	return key
   188  }
   189  
   190  func hexEncPubkey(h string) (ret encPubkey) {
   191  	b, err := hex.DecodeString(h)
   192  	if err != nil {
   193  		panic(err)
   194  	}
   195  	if len(b) != len(ret) {
   196  		panic("invalid length")
   197  	}
   198  	copy(ret[:], b)
   199  	return ret
   200  }