github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/discover/table_util_test.go (about)

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