github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:44</date>
    10  //</624342660076802048>
    11  
    12  
    13  package protocols
    14  
    15  import (
    16  	"context"
    17  	"errors"
    18  	"fmt"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/ethereum/go-ethereum/p2p"
    23  	"github.com/ethereum/go-ethereum/p2p/discover"
    24  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    25  	p2ptest "github.com/ethereum/go-ethereum/p2p/testing"
    26  )
    27  
    28  //握手消息类型
    29  type hs0 struct {
    30  	C uint
    31  }
    32  
    33  //用nodeid终止/删除对等机的消息
    34  type kill struct {
    35  	C discover.NodeID
    36  }
    37  
    38  //断开连接的消息
    39  type drop struct {
    40  }
    41  
    42  ///protochandshake表示协议与模块无关的方面,并且
    43  //第一个消息对等端作为初始交换的一部分发送和接收
    44  type protoHandshake struct {
    45  Version   uint   //本地和远程对等机应具有相同的版本
    46  NetworkID string //本地和远程对等机应具有相同的网络ID
    47  }
    48  
    49  //检查协议握手验证本地和远程协议握手是否匹配
    50  func checkProtoHandshake(testVersion uint, testNetworkID string) func(interface{}) error {
    51  	return func(rhs interface{}) error {
    52  		remote := rhs.(*protoHandshake)
    53  		if remote.NetworkID != testNetworkID {
    54  			return fmt.Errorf("%s (!= %s)", remote.NetworkID, testNetworkID)
    55  		}
    56  
    57  		if remote.Version != testVersion {
    58  			return fmt.Errorf("%d (!= %d)", remote.Version, testVersion)
    59  		}
    60  		return nil
    61  	}
    62  }
    63  
    64  //新协议设置协议
    65  //这里的run函数演示了使用peerpool和handshake的典型协议
    66  //以及注册到处理程序的消息
    67  func newProtocol(pp *p2ptest.TestPeerPool) func(*p2p.Peer, p2p.MsgReadWriter) error {
    68  	spec := &Spec{
    69  		Name:       "test",
    70  		Version:    42,
    71  		MaxMsgSize: 10 * 1024,
    72  		Messages: []interface{}{
    73  			protoHandshake{},
    74  			hs0{},
    75  			kill{},
    76  			drop{},
    77  		},
    78  	}
    79  	return func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
    80  		peer := NewPeer(p, rw, spec)
    81  
    82  //启动一次性协议握手并检查有效性
    83  		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    84  		defer cancel()
    85  		phs := &protoHandshake{42, "420"}
    86  		hsCheck := checkProtoHandshake(phs.Version, phs.NetworkID)
    87  		_, err := peer.Handshake(ctx, phs, hsCheck)
    88  		if err != nil {
    89  			return err
    90  		}
    91  
    92  		lhs := &hs0{42}
    93  //模块握手演示同一类型消息的简单可重复交换
    94  		hs, err := peer.Handshake(ctx, lhs, nil)
    95  		if err != nil {
    96  			return err
    97  		}
    98  
    99  		if rmhs := hs.(*hs0); rmhs.C > lhs.C {
   100  			return fmt.Errorf("handshake mismatch remote %v > local %v", rmhs.C, lhs.C)
   101  		}
   102  
   103  		handle := func(ctx context.Context, msg interface{}) error {
   104  			switch msg := msg.(type) {
   105  
   106  			case *protoHandshake:
   107  				return errors.New("duplicate handshake")
   108  
   109  			case *hs0:
   110  				rhs := msg
   111  				if rhs.C > lhs.C {
   112  					return fmt.Errorf("handshake mismatch remote %v > local %v", rhs.C, lhs.C)
   113  				}
   114  				lhs.C += rhs.C
   115  				return peer.Send(ctx, lhs)
   116  
   117  			case *kill:
   118  //演示使用对等池,终止另一个对等连接作为对消息的响应
   119  				id := msg.C
   120  				pp.Get(id).Drop(errors.New("killed"))
   121  				return nil
   122  
   123  			case *drop:
   124  //对于测试,我们可以在接收到丢弃消息时触发自诱导断开。
   125  				return errors.New("dropped")
   126  
   127  			default:
   128  				return fmt.Errorf("unknown message type: %T", msg)
   129  			}
   130  		}
   131  
   132  		pp.Add(peer)
   133  		defer pp.Remove(peer)
   134  		return peer.Run(handle)
   135  	}
   136  }
   137  
   138  func protocolTester(t *testing.T, pp *p2ptest.TestPeerPool) *p2ptest.ProtocolTester {
   139  	conf := adapters.RandomNodeConfig()
   140  	return p2ptest.NewProtocolTester(t, conf.ID, 2, newProtocol(pp))
   141  }
   142  
   143  func protoHandshakeExchange(id discover.NodeID, proto *protoHandshake) []p2ptest.Exchange {
   144  
   145  	return []p2ptest.Exchange{
   146  		{
   147  			Expects: []p2ptest.Expect{
   148  				{
   149  					Code: 0,
   150  					Msg:  &protoHandshake{42, "420"},
   151  					Peer: id,
   152  				},
   153  			},
   154  		},
   155  		{
   156  			Triggers: []p2ptest.Trigger{
   157  				{
   158  					Code: 0,
   159  					Msg:  proto,
   160  					Peer: id,
   161  				},
   162  			},
   163  		},
   164  	}
   165  }
   166  
   167  func runProtoHandshake(t *testing.T, proto *protoHandshake, errs ...error) {
   168  	pp := p2ptest.NewTestPeerPool()
   169  	s := protocolTester(t, pp)
   170  //托多:多做一次握手
   171  	id := s.IDs[0]
   172  	if err := s.TestExchanges(protoHandshakeExchange(id, proto)...); err != nil {
   173  		t.Fatal(err)
   174  	}
   175  	var disconnects []*p2ptest.Disconnect
   176  	for i, err := range errs {
   177  		disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.IDs[i], Error: err})
   178  	}
   179  	if err := s.TestDisconnected(disconnects...); err != nil {
   180  		t.Fatal(err)
   181  	}
   182  }
   183  
   184  func TestProtoHandshakeVersionMismatch(t *testing.T) {
   185  	runProtoHandshake(t, &protoHandshake{41, "420"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 41 (!= 42)").Error()))
   186  }
   187  
   188  func TestProtoHandshakeNetworkIDMismatch(t *testing.T) {
   189  	runProtoHandshake(t, &protoHandshake{42, "421"}, errorf(ErrHandshake, errorf(ErrHandler, "(msg code 0): 421 (!= 420)").Error()))
   190  }
   191  
   192  func TestProtoHandshakeSuccess(t *testing.T) {
   193  	runProtoHandshake(t, &protoHandshake{42, "420"})
   194  }
   195  
   196  func moduleHandshakeExchange(id discover.NodeID, resp uint) []p2ptest.Exchange {
   197  
   198  	return []p2ptest.Exchange{
   199  		{
   200  			Expects: []p2ptest.Expect{
   201  				{
   202  					Code: 1,
   203  					Msg:  &hs0{42},
   204  					Peer: id,
   205  				},
   206  			},
   207  		},
   208  		{
   209  			Triggers: []p2ptest.Trigger{
   210  				{
   211  					Code: 1,
   212  					Msg:  &hs0{resp},
   213  					Peer: id,
   214  				},
   215  			},
   216  		},
   217  	}
   218  }
   219  
   220  func runModuleHandshake(t *testing.T, resp uint, errs ...error) {
   221  	pp := p2ptest.NewTestPeerPool()
   222  	s := protocolTester(t, pp)
   223  	id := s.IDs[0]
   224  	if err := s.TestExchanges(protoHandshakeExchange(id, &protoHandshake{42, "420"})...); err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	if err := s.TestExchanges(moduleHandshakeExchange(id, resp)...); err != nil {
   228  		t.Fatal(err)
   229  	}
   230  	var disconnects []*p2ptest.Disconnect
   231  	for i, err := range errs {
   232  		disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.IDs[i], Error: err})
   233  	}
   234  	if err := s.TestDisconnected(disconnects...); err != nil {
   235  		t.Fatal(err)
   236  	}
   237  }
   238  
   239  func TestModuleHandshakeError(t *testing.T) {
   240  	runModuleHandshake(t, 43, fmt.Errorf("handshake mismatch remote 43 > local 42"))
   241  }
   242  
   243  func TestModuleHandshakeSuccess(t *testing.T) {
   244  	runModuleHandshake(t, 42)
   245  }
   246  
   247  //在多个对等点上测试复杂的交互、中继、丢弃
   248  func testMultiPeerSetup(a, b discover.NodeID) []p2ptest.Exchange {
   249  
   250  	return []p2ptest.Exchange{
   251  		{
   252  			Label: "primary handshake",
   253  			Expects: []p2ptest.Expect{
   254  				{
   255  					Code: 0,
   256  					Msg:  &protoHandshake{42, "420"},
   257  					Peer: a,
   258  				},
   259  				{
   260  					Code: 0,
   261  					Msg:  &protoHandshake{42, "420"},
   262  					Peer: b,
   263  				},
   264  			},
   265  		},
   266  		{
   267  			Label: "module handshake",
   268  			Triggers: []p2ptest.Trigger{
   269  				{
   270  					Code: 0,
   271  					Msg:  &protoHandshake{42, "420"},
   272  					Peer: a,
   273  				},
   274  				{
   275  					Code: 0,
   276  					Msg:  &protoHandshake{42, "420"},
   277  					Peer: b,
   278  				},
   279  			},
   280  			Expects: []p2ptest.Expect{
   281  				{
   282  					Code: 1,
   283  					Msg:  &hs0{42},
   284  					Peer: a,
   285  				},
   286  				{
   287  					Code: 1,
   288  					Msg:  &hs0{42},
   289  					Peer: b,
   290  				},
   291  			},
   292  		},
   293  
   294  		{Label: "alternative module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{41}, Peer: a},
   295  			{Code: 1, Msg: &hs0{41}, Peer: b}}},
   296  		{Label: "repeated module handshake", Triggers: []p2ptest.Trigger{{Code: 1, Msg: &hs0{1}, Peer: a}}},
   297  		{Label: "receiving repeated module handshake", Expects: []p2ptest.Expect{{Code: 1, Msg: &hs0{43}, Peer: a}}}}
   298  }
   299  
   300  func runMultiplePeers(t *testing.T, peer int, errs ...error) {
   301  	pp := p2ptest.NewTestPeerPool()
   302  	s := protocolTester(t, pp)
   303  
   304  	if err := s.TestExchanges(testMultiPeerSetup(s.IDs[0], s.IDs[1])...); err != nil {
   305  		t.Fatal(err)
   306  	}
   307  //在一些消息交换之后,我们可以测试状态变化
   308  //在这里,这只是由Peerpool演示的
   309  //握手后,必须将对等方添加到池中
   310  //睡眠时间(1)
   311  	tick := time.NewTicker(10 * time.Millisecond)
   312  	timeout := time.NewTimer(1 * time.Second)
   313  WAIT:
   314  	for {
   315  		select {
   316  		case <-tick.C:
   317  			if pp.Has(s.IDs[0]) {
   318  				break WAIT
   319  			}
   320  		case <-timeout.C:
   321  			t.Fatal("timeout")
   322  		}
   323  	}
   324  	if !pp.Has(s.IDs[1]) {
   325  		t.Fatalf("missing peer test-1: %v (%v)", pp, s.IDs)
   326  	}
   327  
   328  //peer 0发送索引为peer的kill请求<peer>
   329  	err := s.TestExchanges(p2ptest.Exchange{
   330  		Triggers: []p2ptest.Trigger{
   331  			{
   332  				Code: 2,
   333  				Msg:  &kill{s.IDs[peer]},
   334  				Peer: s.IDs[0],
   335  			},
   336  		},
   337  	})
   338  
   339  	if err != nil {
   340  		t.Fatal(err)
   341  	}
   342  
   343  //未被杀死的对等机发送删除请求
   344  	err = s.TestExchanges(p2ptest.Exchange{
   345  		Triggers: []p2ptest.Trigger{
   346  			{
   347  				Code: 3,
   348  				Msg:  &drop{},
   349  				Peer: s.IDs[(peer+1)%2],
   350  			},
   351  		},
   352  	})
   353  
   354  	if err != nil {
   355  		t.Fatal(err)
   356  	}
   357  
   358  //检查各个对等机上的实际DiscConnect错误
   359  	var disconnects []*p2ptest.Disconnect
   360  	for i, err := range errs {
   361  		disconnects = append(disconnects, &p2ptest.Disconnect{Peer: s.IDs[i], Error: err})
   362  	}
   363  	if err := s.TestDisconnected(disconnects...); err != nil {
   364  		t.Fatal(err)
   365  	}
   366  //测试是否已从对等池中删除断开连接的对等机
   367  	if pp.Has(s.IDs[peer]) {
   368  		t.Fatalf("peer test-%v not dropped: %v (%v)", peer, pp, s.IDs)
   369  	}
   370  
   371  }
   372  func XTestMultiplePeersDropSelf(t *testing.T) {
   373  	runMultiplePeers(t, 0,
   374  		fmt.Errorf("subprotocol error"),
   375  		fmt.Errorf("Message handler error: (msg code 3): dropped"),
   376  	)
   377  }
   378  
   379  func XTestMultiplePeersDropOther(t *testing.T) {
   380  	runMultiplePeers(t, 1,
   381  		fmt.Errorf("Message handler error: (msg code 3): dropped"),
   382  		fmt.Errorf("subprotocol error"),
   383  	)
   384  }
   385