github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/protocols/protocol_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 19:16:41</date>
    10  //</624450106002771968>
    11  
    12  
    13  package protocols
    14  
    15  import (
    16  	"bytes"
    17  	"context"
    18  	"errors"
    19  	"fmt"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/ethereum/go-ethereum/rlp"
    24  
    25  	"github.com/ethereum/go-ethereum/p2p"
    26  	"github.com/ethereum/go-ethereum/p2p/enode"
    27  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    28  	p2ptest "github.com/ethereum/go-ethereum/p2p/testing"
    29  )
    30  
    31  //握手消息类型
    32  type hs0 struct {
    33  	C uint
    34  }
    35  
    36  //用nodeid终止/删除对等机的消息
    37  type kill struct {
    38  	C enode.ID
    39  }
    40  
    41  //断开连接的消息
    42  type drop struct {
    43  }
    44  
    45  ///protochandshake表示协议与模块无关的方面,并且
    46  //第一个消息对等端作为初始交换的一部分发送和接收
    47  type protoHandshake struct {
    48  Version   uint   //本地和远程对等机应具有相同的版本
    49  NetworkID string //本地和远程对等机应具有相同的网络ID
    50  }
    51  
    52  //检查协议握手验证本地和远程协议握手是否匹配
    53  func checkProtoHandshake(testVersion uint, testNetworkID string) func(interface{}) error {
    54  	return func(rhs interface{}) error {
    55  		remote := rhs.(*protoHandshake)
    56  		if remote.NetworkID != testNetworkID {
    57  			return fmt.Errorf("%s (!= %s)", remote.NetworkID, testNetworkID)
    58  		}
    59  
    60  		if remote.Version != testVersion {
    61  			return fmt.Errorf("%d (!= %d)", remote.Version, testVersion)
    62  		}
    63  		return nil
    64  	}
    65  }
    66  
    67  //新协议设置协议
    68  //这里的run函数演示了使用peerpool和handshake的典型协议
    69  //以及注册到处理程序的消息
    70  func newProtocol(pp *p2ptest.TestPeerPool) func(*p2p.Peer, p2p.MsgReadWriter) error {
    71  	spec := &Spec{
    72  		Name:       "test",
    73  		Version:    42,
    74  		MaxMsgSize: 10 * 1024,
    75  		Messages: []interface{}{
    76  			protoHandshake{},
    77  			hs0{},
    78  			kill{},
    79  			drop{},
    80  		},
    81  	}
    82  	return func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
    83  		peer := NewPeer(p, rw, spec)
    84  
    85  //启动一次性协议握手并检查有效性
    86  		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    87  		defer cancel()
    88  		phs := &protoHandshake{42, "420"}
    89  		hsCheck := checkProtoHandshake(phs.Version, phs.NetworkID)
    90  		_, err := peer.Handshake(ctx, phs, hsCheck)
    91  		if err != nil {
    92  			return err
    93  		}
    94  
    95  		lhs := &hs0{42}
    96  //模块握手演示同一类型消息的简单可重复交换
    97  		hs, err := peer.Handshake(ctx, lhs, nil)
    98  		if err != nil {
    99  			return err
   100  		}
   101  
   102  		if rmhs := hs.(*hs0); rmhs.C > lhs.C {
   103  			return fmt.Errorf("handshake mismatch remote %v > local %v", rmhs.C, lhs.C)
   104  		}
   105  
   106  		handle := func(ctx context.Context, msg interface{}) error {
   107  			switch msg := msg.(type) {
   108  
   109  			case *protoHandshake:
   110  				return errors.New("duplicate handshake")
   111  
   112  			case *hs0:
   113  				rhs := msg
   114  				if rhs.C > lhs.C {
   115  					return fmt.Errorf("handshake mismatch remote %v > local %v", rhs.C, lhs.C)
   116  				}
   117  				lhs.C += rhs.C
   118  				return peer.Send(ctx, lhs)
   119  
   120  			case *kill:
   121  //演示使用对等池,终止另一个对等连接作为对消息的响应
   122  				id := msg.C
   123  				pp.Get(id).Drop(errors.New("killed"))
   124  				return nil
   125  
   126  			case *drop:
   127  //对于测试,我们可以在接收到丢弃消息时触发自诱导断开。
   128  				return errors.New("dropped")
   129  
   130  			default:
   131  				return fmt.Errorf("unknown message type: %T", msg)
   132  			}
   133  		}
   134  
   135  		pp.Add(peer)
   136  		defer pp.Remove(peer)
   137  		return peer.Run(handle)
   138  	}
   139  }
   140  
   141  func protocolTester(t *testing.T, pp *p2ptest.TestPeerPool) *p2ptest.ProtocolTester {
   142  	conf := adapters.RandomNodeConfig()
   143  	return p2ptest.NewProtocolTester(t, conf.ID, 2, newProtocol(pp))
   144  }
   145  
   146  func protoHandshakeExchange(id enode.ID, proto *protoHandshake) []p2ptest.Exchange {
   147  
   148  	return []p2ptest.Exchange{
   149  		{
   150  			Expects: []p2ptest.Expect{
   151  				{
   152  					Code: 0,
   153  					Msg:  &protoHandshake{42, "420"},
   154  					Peer: id,
   155  				},
   156  			},
   157  		},
   158  		{
   159  			Triggers: []p2ptest.Trigger{
   160  				{
   161  					Code: 0,
   162  					Msg:  proto,
   163  					Peer: id,
   164  				},
   165  			},
   166  		},
   167  	}
   168  }
   169  
   170  func runProtoHandshake(t *testing.T, proto *protoHandshake, errs ...error) {
   171  	pp := p2ptest.NewTestPeerPool()
   172  	s := protocolTester(t, pp)
   173  //托多:多做一次握手
   174  	node := s.Nodes[0]
   175  	if err := s.TestExchanges(protoHandshakeExchange(node.ID(), proto)...); err != nil {
   176  		t.Fatal(err)
   177  	}
   178  	var disconnects []*p2ptest.Disconnect
   179  	for i, err := range errs {
   180  		disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.Nodes[i].ID(), Error: err})
   181  	}
   182  	if err := s.TestDisconnected(disconnects...); err != nil {
   183  		t.Fatal(err)
   184  	}
   185  }
   186  
   187  type dummyHook struct {
   188  	peer  *Peer
   189  	size  uint32
   190  	msg   interface{}
   191  	send  bool
   192  	err   error
   193  	waitC chan struct{}
   194  }
   195  
   196  type dummyMsg struct {
   197  	Content string
   198  }
   199  
   200  func (d *dummyHook) Send(peer *Peer, size uint32, msg interface{}) error {
   201  	d.peer = peer
   202  	d.size = size
   203  	d.msg = msg
   204  	d.send = true
   205  	return d.err
   206  }
   207  
   208  func (d *dummyHook) Receive(peer *Peer, size uint32, msg interface{}) error {
   209  	d.peer = peer
   210  	d.size = size
   211  	d.msg = msg
   212  	d.send = false
   213  	d.waitC <- struct{}{}
   214  	return d.err
   215  }
   216  
   217  func TestProtocolHook(t *testing.T) {
   218  	testHook := &dummyHook{
   219  		waitC: make(chan struct{}, 1),
   220  	}
   221  	spec := &Spec{
   222  		Name:       "test",
   223  		Version:    42,
   224  		MaxMsgSize: 10 * 1024,
   225  		Messages: []interface{}{
   226  			dummyMsg{},
   227  		},
   228  		Hook: testHook,
   229  	}
   230  
   231  	runFunc := func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
   232  		peer := NewPeer(p, rw, spec)
   233  		ctx := context.TODO()
   234  		err := peer.Send(ctx, &dummyMsg{
   235  			Content: "handshake"})
   236  
   237  		if err != nil {
   238  			t.Fatal(err)
   239  		}
   240  
   241  		handle := func(ctx context.Context, msg interface{}) error {
   242  			return nil
   243  		}
   244  
   245  		return peer.Run(handle)
   246  	}
   247  
   248  	conf := adapters.RandomNodeConfig()
   249  	tester := p2ptest.NewProtocolTester(t, conf.ID, 2, runFunc)
   250  	err := tester.TestExchanges(p2ptest.Exchange{
   251  		Expects: []p2ptest.Expect{
   252  			{
   253  				Code: 0,
   254  				Msg:  &dummyMsg{Content: "handshake"},
   255  				Peer: tester.Nodes[0].ID(),
   256  			},
   257  		},
   258  	})
   259  	if err != nil {
   260  		t.Fatal(err)
   261  	}
   262  	if testHook.msg == nil || testHook.msg.(*dummyMsg).Content != "handshake" {
   263  		t.Fatal("Expected msg to be set, but it is not")
   264  	}
   265  	if !testHook.send {
   266  		t.Fatal("Expected a send message, but it is not")
   267  	}
   268  	if testHook.peer == nil || testHook.peer.ID() != tester.Nodes[0].ID() {
   269  		t.Fatal("Expected peer ID to be set correctly, but it is not")
   270  	}
   271  if testHook.size != 11 { //11是编码消息的长度
   272  		t.Fatalf("Expected size to be %d, but it is %d ", 1, testHook.size)
   273  	}
   274  
   275  	err = tester.TestExchanges(p2ptest.Exchange{
   276  		Triggers: []p2ptest.Trigger{
   277  			{
   278  				Code: 0,
   279  				Msg:  &dummyMsg{Content: "response"},
   280  				Peer: tester.Nodes[1].ID(),
   281  			},
   282  		},
   283  	})
   284  
   285  	<-testHook.waitC
   286  
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	if testHook.msg == nil || testHook.msg.(*dummyMsg).Content != "response" {
   291  		t.Fatal("Expected msg to be set, but it is not")
   292  	}
   293  	if testHook.send {
   294  		t.Fatal("Expected a send message, but it is not")
   295  	}
   296  	if testHook.peer == nil || testHook.peer.ID() != tester.Nodes[1].ID() {
   297  		t.Fatal("Expected peer ID to be set correctly, but it is not")
   298  	}
   299  if testHook.size != 10 { //11是编码消息的长度
   300  		t.Fatalf("Expected size to be %d, but it is %d ", 1, testHook.size)
   301  	}
   302  
   303  	testHook.err = fmt.Errorf("dummy error")
   304  	err = tester.TestExchanges(p2ptest.Exchange{
   305  		Triggers: []p2ptest.Trigger{
   306  			{
   307  				Code: 0,
   308  				Msg:  &dummyMsg{Content: "response"},
   309  				Peer: tester.Nodes[1].ID(),
   310  			},
   311  		},
   312  	})
   313  
   314  	<-testHook.waitC
   315  
   316  	time.Sleep(100 * time.Millisecond)
   317  	err = tester.TestDisconnected(&p2ptest.Disconnect{Peer: tester.Nodes[1].ID(), Error: testHook.err})
   318  	if err != nil {
   319  		t.Fatalf("Expected a specific disconnect error, but got different one: %v", err)
   320  	}
   321  
   322  }
   323  
   324  //我们需要测试,如果钩子没有定义,那么消息基础结构
   325  //(发送、接收)仍然有效
   326  func TestNoHook(t *testing.T) {
   327  //创建测试规范
   328  	spec := createTestSpec()
   329  //随机节点
   330  	id := adapters.RandomNodeConfig().ID
   331  //同辈
   332  	p := p2p.NewPeer(id, "testPeer", nil)
   333  	rw := &dummyRW{}
   334  	peer := NewPeer(p, rw, spec)
   335  	ctx := context.TODO()
   336  	msg := &perBytesMsgSenderPays{Content: "testBalance"}
   337  //发信息
   338  	err := peer.Send(ctx, msg)
   339  	if err != nil {
   340  		t.Fatal(err)
   341  	}
   342  //模拟接收消息
   343  	rw.msg = msg
   344  	peer.handleIncoming(func(ctx context.Context, msg interface{}) error {
   345  		return nil
   346  	})
   347  //一切都应该正常工作,不会导致任何错误。
   348  }
   349  
   350  func TestProtoHandshakeVersionMismatch(t *testing.T) {
   351  	runProtoHandshake(t, &protoHandshake{41, "420"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 41 (!= 42)").Error()))
   352  }
   353  
   354  func TestProtoHandshakeNetworkIDMismatch(t *testing.T) {
   355  	runProtoHandshake(t, &protoHandshake{42, "421"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 421 (!= 420)").Error()))
   356  }
   357  
   358  func TestProtoHandshakeSuccess(t *testing.T) {
   359  	runProtoHandshake(t, &protoHandshake{42, "420"})
   360  }
   361  
   362  func moduleHandshakeExchange(id enode.ID, resp uint) []p2ptest.Exchange {
   363  
   364  	return []p2ptest.Exchange{
   365  		{
   366  			Expects: []p2ptest.Expect{
   367  				{
   368  					Code: 1,
   369  					Msg:  &hs0{42},
   370  					Peer: id,
   371  				},
   372  			},
   373  		},
   374  		{
   375  			Triggers: []p2ptest.Trigger{
   376  				{
   377  					Code: 1,
   378  					Msg:  &hs0{resp},
   379  					Peer: id,
   380  				},
   381  			},
   382  		},
   383  	}
   384  }
   385  
   386  func runModuleHandshake(t *testing.T, resp uint, errs ...error) {
   387  	pp := p2ptest.NewTestPeerPool()
   388  	s := protocolTester(t, pp)
   389  	node := s.Nodes[0]
   390  	if err := s.TestExchanges(protoHandshakeExchange(node.ID(), &protoHandshake{42, "420"})...); err != nil {
   391  		t.Fatal(err)
   392  	}
   393  	if err := s.TestExchanges(moduleHandshakeExchange(node.ID(), resp)...); err != nil {
   394  		t.Fatal(err)
   395  	}
   396  	var disconnects []*p2ptest.Disconnect
   397  	for i, err := range errs {
   398  		disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.Nodes[i].ID(), Error: err})
   399  	}
   400  	if err := s.TestDisconnected(disconnects...); err != nil {
   401  		t.Fatal(err)
   402  	}
   403  }
   404  
   405  func TestModuleHandshakeError(t *testing.T) {
   406  	runModuleHandshake(t, 43, fmt.Errorf("handshake mismatch remote 43 > local 42"))
   407  }
   408  
   409  func TestModuleHandshakeSuccess(t *testing.T) {
   410  	runModuleHandshake(t, 42)
   411  }
   412  
   413  //在多个对等点上测试复杂的交互、中继、丢弃
   414  func testMultiPeerSetup(a, b enode.ID) []p2ptest.Exchange {
   415  
   416  	return []p2ptest.Exchange{
   417  		{
   418  			Label: "primary handshake",
   419  			Expects: []p2ptest.Expect{
   420  				{
   421  					Code: 0,
   422  					Msg:  &protoHandshake{42, "420"},
   423  					Peer: a,
   424  				},
   425  				{
   426  					Code: 0,
   427  					Msg:  &protoHandshake{42, "420"},
   428  					Peer: b,
   429  				},
   430  			},
   431  		},
   432  		{
   433  			Label: "module handshake",
   434  			Triggers: []p2ptest.Trigger{
   435  				{
   436  					Code: 0,
   437  					Msg:  &protoHandshake{42, "420"},
   438  					Peer: a,
   439  				},
   440  				{
   441  					Code: 0,
   442  					Msg:  &protoHandshake{42, "420"},
   443  					Peer: b,
   444  				},
   445  			},
   446  			Expects: []p2ptest.Expect{
   447  				{
   448  					Code: 1,
   449  					Msg:  &hs0{42},
   450  					Peer: a,
   451  				},
   452  				{
   453  					Code: 1,
   454  					Msg:  &hs0{42},
   455  					Peer: b,
   456  				},
   457  			},
   458  		},
   459  
   460  		{Label: "alternative module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{41}, Peer: a},
   461  			{Code: 1, Msg: &hs0{41}, Peer: b}}},
   462  		{Label: "repeated module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{1}, Peer: a}}},
   463  		{Label: "receiving repeated module handshake", Expects: []p2ptest.Expect{{Code: 1, Msg: &hs0{43}, Peer: a}}}}
   464  }
   465  
   466  func runMultiplePeers(t *testing.T, peer int, errs ...error) {
   467  	pp := p2ptest.NewTestPeerPool()
   468  	s := protocolTester(t, pp)
   469  
   470  	if err := s.TestExchanges(testMultiPeerSetup(s.Nodes[0].ID(), s.Nodes[1].ID())...); err != nil {
   471  		t.Fatal(err)
   472  	}
   473  //在一些消息交换之后,我们可以测试状态变化
   474  //在这里,这只是由Peerpool演示的
   475  //握手后,必须将对等方添加到池中
   476  //睡眠时间(1)
   477  	tick := time.NewTicker(10 * time.Millisecond)
   478  	timeout := time.NewTimer(1 * time.Second)
   479  WAIT:
   480  	for {
   481  		select {
   482  		case <-tick.C:
   483  			if pp.Has(s.Nodes[0].ID()) {
   484  				break WAIT
   485  			}
   486  		case <-timeout.C:
   487  			t.Fatal("timeout")
   488  		}
   489  	}
   490  	if !pp.Has(s.Nodes[1].ID()) {
   491  		t.Fatalf("missing peer test-1: %v (%v)", pp, s.Nodes)
   492  	}
   493  
   494  //peer 0发送索引为peer的kill请求<peer>
   495  	err := s.TestExchanges(p2ptest.Exchange{
   496  		Triggers: []p2ptest.Trigger{
   497  			{
   498  				Code: 2,
   499  				Msg:  &kill{s.Nodes[peer].ID()},
   500  				Peer: s.Nodes[0].ID(),
   501  			},
   502  		},
   503  	})
   504  
   505  	if err != nil {
   506  		t.Fatal(err)
   507  	}
   508  
   509  //未被杀死的对等机发送删除请求
   510  	err = s.TestExchanges(p2ptest.Exchange{
   511  		Triggers: []p2ptest.Trigger{
   512  			{
   513  				Code: 3,
   514  				Msg:  &drop{},
   515  				Peer: s.Nodes[(peer+1)%2].ID(),
   516  			},
   517  		},
   518  	})
   519  
   520  	if err != nil {
   521  		t.Fatal(err)
   522  	}
   523  
   524  //检查各个对等机上的实际DiscConnect错误
   525  	var disconnects []*p2ptest.Disconnect
   526  	for i, err := range errs {
   527  		disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.Nodes[i].ID(), Error: err})
   528  	}
   529  	if err := s.TestDisconnected(disconnects...); err != nil {
   530  		t.Fatal(err)
   531  	}
   532  //测试是否已从对等池中删除断开连接的对等机
   533  	if pp.Has(s.Nodes[peer].ID()) {
   534  		t.Fatalf("peer test-%v not dropped: %v (%v)", peer, pp, s.Nodes)
   535  	}
   536  
   537  }
   538  func XTestMultiplePeersDropSelf(t *testing.T) {
   539  	runMultiplePeers(t, 0,
   540  		fmt.Errorf("subprotocol error"),
   541  		fmt.Errorf("Message handler error: (msg code 3): dropped"),
   542  	)
   543  }
   544  
   545  func XTestMultiplePeersDropOther(t *testing.T) {
   546  	runMultiplePeers(t, 1,
   547  		fmt.Errorf("Message handler error: (msg code 3): dropped"),
   548  		fmt.Errorf("subprotocol error"),
   549  	)
   550  }
   551  
   552  //msgreadwriter的虚拟实现
   553  //这允许快速简单的单元测试
   554  //必须建立完整的协议
   555  type dummyRW struct {
   556  	msg  interface{}
   557  	size uint32
   558  	code uint64
   559  }
   560  
   561  func (d *dummyRW) WriteMsg(msg p2p.Msg) error {
   562  	return nil
   563  }
   564  
   565  func (d *dummyRW) ReadMsg() (p2p.Msg, error) {
   566  	enc := bytes.NewReader(d.getDummyMsg())
   567  	return p2p.Msg{
   568  		Code:       d.code,
   569  		Size:       d.size,
   570  		Payload:    enc,
   571  		ReceivedAt: time.Now(),
   572  	}, nil
   573  }
   574  
   575  func (d *dummyRW) getDummyMsg() []byte {
   576  	r, _ := rlp.EncodeToBytes(d.msg)
   577  	var b bytes.Buffer
   578  	wmsg := WrappedMsg{
   579  		Context: b.Bytes(),
   580  		Size:    uint32(len(r)),
   581  		Payload: r,
   582  	}
   583  	rr, _ := rlp.EncodeToBytes(wmsg)
   584  	d.size = uint32(len(rr))
   585  	return rr
   586  }
   587