github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/discv5/table_test.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:44</date>
    10  //</624342657614745600>
    11  
    12  
    13  package discv5
    14  
    15  import (
    16  	"crypto/ecdsa"
    17  	"fmt"
    18  	"math/rand"
    19  
    20  	"net"
    21  	"reflect"
    22  	"testing"
    23  	"testing/quick"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/crypto"
    28  )
    29  
    30  type nullTransport struct{}
    31  
    32  func (nullTransport) sendPing(remote *Node, remoteAddr *net.UDPAddr) []byte { return []byte{1} }
    33  func (nullTransport) sendPong(remote *Node, pingHash []byte)                {}
    34  func (nullTransport) sendFindnode(remote *Node, target NodeID)              {}
    35  func (nullTransport) sendNeighbours(remote *Node, nodes []*Node)            {}
    36  func (nullTransport) localAddr() *net.UDPAddr                               { return new(net.UDPAddr) }
    37  func (nullTransport) Close()                                                {}
    38  
    39  //func测试表_pingreplace(t*testing.t)
    40  //doit:=func(newnodeisresponding,lastinbuckettisresponding bool)
    41  //传输:=newPingRecorder())
    42  //tab,:=newTable(传输,节点ID,&net.udpaddr)
    43  //延迟tab.close()
    44  //Pinsender:=新节点(musthexid(“A502AF0F59B2AAB774695408C79E9CA312D2793CC997E44FC55EDA62F0150BBB8C59A6F9269BA3A081518B62699EE807C7C19C20125DDFCCCA872608AF9E370”),net.ip,99,99)
    45  //
    46  ////填满发送方的桶。
    47  //最后:=FillBucket(tab,253)
    48  //
    49  ////此绑定调用应替换最后一个节点
    50  ////如果节点没有响应,则在其存储桶中。
    51  //transport.responding[last.id]=上次BucketisResponding
    52  //transport.responding[pinsender.id]=新节点响应
    53  //tab.bond(真,pinsender.id,&net.udpaddr,0)
    54  //
    55  ////第一个ping转到发送方(绑定pingback)
    56  //如果!transport.pinged[pingender.id]
    57  //t.error(“表没有ping回发送方”)
    58  //}
    59  //如果newnodeisresponding
    60  ////第二个ping转到bucket中最早的节点
    61  //看它是否还活着。
    62  //如果!transport.pinged[上一个.id]
    63  //t.error(“table did not ping last node in bucket”)。
    64  //}
    65  //}
    66  //
    67  //tab.mutex.lock()。
    68  //延迟tab.mutex.unlock()
    69  //如果l:=len(tab.buckets[253].entries);l!= BukStige{
    70  //t.errorf(“绑定后的存储桶大小错误:得到%d,想要%d”,l,bucket size)
    71  //}
    72  //
    73  //如果最后一个问题是响应!新节点响应
    74  //如果!包含(tab.buckets[253].entries,last.id)
    75  //t.error(“删除最后一个条目”)
    76  //}
    77  //如果包含(tab.buckets[253].entries,pinsender.id)
    78  //t.error(“添加新条目”)
    79  //}
    80  //}否则{
    81  //如果包含(tab.buckets[253].entries,last.id)
    82  //t.error(“最后一项未删除”)
    83  //}
    84  //如果!包含(tab.buckets[253].entries,pinsender.id)
    85  //t.error(“未添加新条目”)
    86  //}
    87  //}
    88  //}
    89  //
    90  //doit(真,真)
    91  //doit(假,真)
    92  //doit(对,错)
    93  //doit(假,假)
    94  //}
    95  
    96  func TestBucket_bumpNoDuplicates(t *testing.T) {
    97  	t.Parallel()
    98  	cfg := &quick.Config{
    99  		MaxCount: 1000,
   100  		Rand:     rand.New(rand.NewSource(time.Now().Unix())),
   101  		Values: func(args []reflect.Value, rand *rand.Rand) {
   102  //生成节点的随机列表。这将是存储桶的内容。
   103  			n := rand.Intn(bucketSize-1) + 1
   104  			nodes := make([]*Node, n)
   105  			for i := range nodes {
   106  				nodes[i] = nodeAtDistance(common.Hash{}, 200)
   107  			}
   108  			args[0] = reflect.ValueOf(nodes)
   109  //生成随机凹凸位置。
   110  			bumps := make([]int, rand.Intn(100))
   111  			for i := range bumps {
   112  				bumps[i] = rand.Intn(len(nodes))
   113  			}
   114  			args[1] = reflect.ValueOf(bumps)
   115  		},
   116  	}
   117  
   118  	prop := func(nodes []*Node, bumps []int) (ok bool) {
   119  		b := &bucket{entries: make([]*Node, len(nodes))}
   120  		copy(b.entries, nodes)
   121  		for i, pos := range bumps {
   122  			b.bump(b.entries[pos])
   123  			if hasDuplicates(b.entries) {
   124  				t.Logf("bucket has duplicates after %d/%d bumps:", i+1, len(bumps))
   125  				for _, n := range b.entries {
   126  					t.Logf("  %p", n)
   127  				}
   128  				return false
   129  			}
   130  		}
   131  		return true
   132  	}
   133  	if err := quick.Check(prop, cfg); err != nil {
   134  		t.Error(err)
   135  	}
   136  }
   137  
   138  //FillBucket将节点插入给定的bucket,直到
   139  //它已经满了。节点的ID与
   140  //散列。
   141  func fillBucket(tab *Table, ld int) (last *Node) {
   142  	b := tab.buckets[ld]
   143  	for len(b.entries) < bucketSize {
   144  		b.entries = append(b.entries, nodeAtDistance(tab.self.sha, ld))
   145  	}
   146  	return b.entries[bucketSize-1]
   147  }
   148  
   149  //nodeAtDistance为其创建logDist(base,n.sha)=ld的节点。
   150  //节点的ID与n.sha不对应。
   151  func nodeAtDistance(base common.Hash, ld int) (n *Node) {
   152  	n = new(Node)
   153  	n.sha = hashAtDistance(base, ld)
   154  copy(n.ID[:], n.sha[:]) //确保节点仍然具有唯一的ID
   155  	return n
   156  }
   157  
   158  type pingRecorder struct{ responding, pinged map[NodeID]bool }
   159  
   160  func newPingRecorder() *pingRecorder {
   161  	return &pingRecorder{make(map[NodeID]bool), make(map[NodeID]bool)}
   162  }
   163  
   164  func (t *pingRecorder) findnode(toid NodeID, toaddr *net.UDPAddr, target NodeID) ([]*Node, error) {
   165  	panic("findnode called on pingRecorder")
   166  }
   167  func (t *pingRecorder) close() {}
   168  func (t *pingRecorder) waitping(from NodeID) error {
   169  return nil //远程总是ping
   170  }
   171  func (t *pingRecorder) ping(toid NodeID, toaddr *net.UDPAddr) error {
   172  	t.pinged[toid] = true
   173  	if t.responding[toid] {
   174  		return nil
   175  	} else {
   176  		return errTimeout
   177  	}
   178  }
   179  
   180  func TestTable_closest(t *testing.T) {
   181  	t.Parallel()
   182  
   183  	test := func(test *closeTest) bool {
   184  //对于任何节点表、目标和n
   185  		tab := newTable(test.Self, &net.UDPAddr{})
   186  		tab.stuff(test.All)
   187  
   188  //检查doclosest(target,n)是否返回节点
   189  		result := tab.closest(test.Target, test.N).entries
   190  		if hasDuplicates(result) {
   191  			t.Errorf("result contains duplicates")
   192  			return false
   193  		}
   194  		if !sortedByDistanceTo(test.Target, result) {
   195  			t.Errorf("result is not sorted by distance to target")
   196  			return false
   197  		}
   198  
   199  //检查结果数是否为min(n,tablen)
   200  		wantN := test.N
   201  		if tab.count < test.N {
   202  			wantN = tab.count
   203  		}
   204  		if len(result) != wantN {
   205  			t.Errorf("wrong number of nodes: got %d, want %d", len(result), wantN)
   206  			return false
   207  		} else if len(result) == 0 {
   208  return true //不需要检查距离
   209  		}
   210  
   211  //检查结果节点与目标的距离是否最小。
   212  		for _, b := range tab.buckets {
   213  			for _, n := range b.entries {
   214  				if contains(result, n.ID) {
   215  continue //不要对结果中的节点运行下面的检查
   216  				}
   217  				farthestResult := result[len(result)-1].sha
   218  				if distcmp(test.Target, n.sha, farthestResult) < 0 {
   219  					t.Errorf("table contains node that is closer to target but it's not in result")
   220  					t.Logf("  Target:          %v", test.Target)
   221  					t.Logf("  Farthest Result: %v", farthestResult)
   222  					t.Logf("  ID:              %v", n.ID)
   223  					return false
   224  				}
   225  			}
   226  		}
   227  		return true
   228  	}
   229  	if err := quick.Check(test, quickcfg()); err != nil {
   230  		t.Error(err)
   231  	}
   232  }
   233  
   234  func TestTable_ReadRandomNodesGetAll(t *testing.T) {
   235  	cfg := &quick.Config{
   236  		MaxCount: 200,
   237  		Rand:     rand.New(rand.NewSource(time.Now().Unix())),
   238  		Values: func(args []reflect.Value, rand *rand.Rand) {
   239  			args[0] = reflect.ValueOf(make([]*Node, rand.Intn(1000)))
   240  		},
   241  	}
   242  	test := func(buf []*Node) bool {
   243  		tab := newTable(NodeID{}, &net.UDPAddr{})
   244  		for i := 0; i < len(buf); i++ {
   245  			ld := cfg.Rand.Intn(len(tab.buckets))
   246  			tab.stuff([]*Node{nodeAtDistance(tab.self.sha, ld)})
   247  		}
   248  		gotN := tab.readRandomNodes(buf)
   249  		if gotN != tab.count {
   250  			t.Errorf("wrong number of nodes, got %d, want %d", gotN, tab.count)
   251  			return false
   252  		}
   253  		if hasDuplicates(buf[:gotN]) {
   254  			t.Errorf("result contains duplicates")
   255  			return false
   256  		}
   257  		return true
   258  	}
   259  	if err := quick.Check(test, cfg); err != nil {
   260  		t.Error(err)
   261  	}
   262  }
   263  
   264  type closeTest struct {
   265  	Self   NodeID
   266  	Target common.Hash
   267  	All    []*Node
   268  	N      int
   269  }
   270  
   271  func (*closeTest) Generate(rand *rand.Rand, size int) reflect.Value {
   272  	t := &closeTest{
   273  		Self:   gen(NodeID{}, rand).(NodeID),
   274  		Target: gen(common.Hash{}, rand).(common.Hash),
   275  		N:      rand.Intn(bucketSize),
   276  	}
   277  	for _, id := range gen([]NodeID{}, rand).([]NodeID) {
   278  		t.All = append(t.All, &Node{ID: id})
   279  	}
   280  	return reflect.ValueOf(t)
   281  }
   282  
   283  func hasDuplicates(slice []*Node) bool {
   284  	seen := make(map[NodeID]bool)
   285  	for i, e := range slice {
   286  		if e == nil {
   287  			panic(fmt.Sprintf("nil *Node at %d", i))
   288  		}
   289  		if seen[e.ID] {
   290  			return true
   291  		}
   292  		seen[e.ID] = true
   293  	}
   294  	return false
   295  }
   296  
   297  func sortedByDistanceTo(distbase common.Hash, slice []*Node) bool {
   298  	var last common.Hash
   299  	for i, e := range slice {
   300  		if i > 0 && distcmp(distbase, e.sha, last) < 0 {
   301  			return false
   302  		}
   303  		last = e.sha
   304  	}
   305  	return true
   306  }
   307  
   308  func contains(ns []*Node, id NodeID) bool {
   309  	for _, n := range ns {
   310  		if n.ID == id {
   311  			return true
   312  		}
   313  	}
   314  	return false
   315  }
   316  
   317  //Gen包装速度快,价值高,使用方便。
   318  //它生成给定值类型的随机值。
   319  func gen(typ interface{}, rand *rand.Rand) interface{} {
   320  	v, ok := quick.Value(reflect.TypeOf(typ), rand)
   321  	if !ok {
   322  		panic(fmt.Sprintf("couldn't generate random value of type %T", typ))
   323  	}
   324  	return v.Interface()
   325  }
   326  
   327  func newkey() *ecdsa.PrivateKey {
   328  	key, err := crypto.GenerateKey()
   329  	if err != nil {
   330  		panic("couldn't generate key: " + err.Error())
   331  	}
   332  	return key
   333  }
   334