github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/eth/handler_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:37</date>
    10  //</624450089225555968>
    11  
    12  
    13  package eth
    14  
    15  import (
    16  	"fmt"
    17  	"math"
    18  	"math/big"
    19  	"math/rand"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/ethereum/go-ethereum/common"
    24  	"github.com/ethereum/go-ethereum/consensus/ethash"
    25  	"github.com/ethereum/go-ethereum/core"
    26  	"github.com/ethereum/go-ethereum/core/state"
    27  	"github.com/ethereum/go-ethereum/core/types"
    28  	"github.com/ethereum/go-ethereum/core/vm"
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  	"github.com/ethereum/go-ethereum/eth/downloader"
    31  	"github.com/ethereum/go-ethereum/ethdb"
    32  	"github.com/ethereum/go-ethereum/event"
    33  	"github.com/ethereum/go-ethereum/p2p"
    34  	"github.com/ethereum/go-ethereum/params"
    35  )
    36  
    37  //测试协议版本和操作模式是否正确匹配。
    38  func TestProtocolCompatibility(t *testing.T) {
    39  //定义兼容性图表
    40  	tests := []struct {
    41  		version    uint
    42  		mode       downloader.SyncMode
    43  		compatible bool
    44  	}{
    45  		{61, downloader.FullSync, true}, {62, downloader.FullSync, true}, {63, downloader.FullSync, true},
    46  		{61, downloader.FastSync, false}, {62, downloader.FastSync, false}, {63, downloader.FastSync, true},
    47  	}
    48  //确保我们搞砸的东西都恢复了
    49  	backup := ProtocolVersions
    50  	defer func() { ProtocolVersions = backup }()
    51  
    52  //尝试所有可用的兼容性配置并检查错误
    53  	for i, tt := range tests {
    54  		ProtocolVersions = []uint{tt.version}
    55  
    56  		pm, _, err := newTestProtocolManager(tt.mode, 0, nil, nil)
    57  		if pm != nil {
    58  			defer pm.Stop()
    59  		}
    60  		if (err == nil && !tt.compatible) || (err != nil && tt.compatible) {
    61  			t.Errorf("test %d: compatibility mismatch: have error %v, want compatibility %v", i, err, tt.compatible)
    62  		}
    63  	}
    64  }
    65  
    66  //可以根据用户查询从远程链中检索阻止头的测试。
    67  func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) }
    68  func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
    69  
    70  func testGetBlockHeaders(t *testing.T, protocol int) {
    71  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxHashFetch+15, nil, nil)
    72  	peer, _ := newTestPeer("peer", protocol, pm, true)
    73  	defer peer.close()
    74  
    75  //为测试创建一个“随机”的未知哈希
    76  	var unknown common.Hash
    77  	for i := range unknown {
    78  		unknown[i] = byte(i)
    79  	}
    80  //为各种方案创建一批测试
    81  	limit := uint64(downloader.MaxHeaderFetch)
    82  	tests := []struct {
    83  query  *getBlockHeadersData //要为头检索执行的查询
    84  expect []common.Hash        //应为其头的块的哈希
    85  	}{
    86  //单个随机块也应该可以通过哈希和数字检索。
    87  		{
    88  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
    89  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
    90  		}, {
    91  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1},
    92  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
    93  		},
    94  //应可从两个方向检索多个邮件头
    95  		{
    96  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3},
    97  			[]common.Hash{
    98  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
    99  				pm.blockchain.GetBlockByNumber(limit/2 + 1).Hash(),
   100  				pm.blockchain.GetBlockByNumber(limit/2 + 2).Hash(),
   101  			},
   102  		}, {
   103  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
   104  			[]common.Hash{
   105  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   106  				pm.blockchain.GetBlockByNumber(limit/2 - 1).Hash(),
   107  				pm.blockchain.GetBlockByNumber(limit/2 - 2).Hash(),
   108  			},
   109  		},
   110  //应检索具有跳过列表的多个邮件头
   111  		{
   112  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
   113  			[]common.Hash{
   114  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   115  				pm.blockchain.GetBlockByNumber(limit/2 + 4).Hash(),
   116  				pm.blockchain.GetBlockByNumber(limit/2 + 8).Hash(),
   117  			},
   118  		}, {
   119  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
   120  			[]common.Hash{
   121  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   122  				pm.blockchain.GetBlockByNumber(limit/2 - 4).Hash(),
   123  				pm.blockchain.GetBlockByNumber(limit/2 - 8).Hash(),
   124  			},
   125  		},
   126  //链端点应该是可检索的
   127  		{
   128  			&getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1},
   129  			[]common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()},
   130  		}, {
   131  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1},
   132  			[]common.Hash{pm.blockchain.CurrentBlock().Hash()},
   133  		},
   134  //确保遵守协议限制
   135  		{
   136  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true},
   137  			pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit),
   138  		},
   139  //检查请求是否处理得当
   140  		{
   141  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3},
   142  			[]common.Hash{
   143  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   144  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(),
   145  			},
   146  		}, {
   147  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
   148  			[]common.Hash{
   149  				pm.blockchain.GetBlockByNumber(4).Hash(),
   150  				pm.blockchain.GetBlockByNumber(0).Hash(),
   151  			},
   152  		},
   153  //检查请求是否处理得当,即使中间跳过
   154  		{
   155  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3},
   156  			[]common.Hash{
   157  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   158  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(),
   159  			},
   160  		}, {
   161  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
   162  			[]common.Hash{
   163  				pm.blockchain.GetBlockByNumber(4).Hash(),
   164  				pm.blockchain.GetBlockByNumber(1).Hash(),
   165  			},
   166  		},
   167  //检查一个角情况,在这种情况下,请求更多可以迭代通过端点
   168  		{
   169  			&getBlockHeadersData{Origin: hashOrNumber{Number: 2}, Amount: 5, Reverse: true},
   170  			[]common.Hash{
   171  				pm.blockchain.GetBlockByNumber(2).Hash(),
   172  				pm.blockchain.GetBlockByNumber(1).Hash(),
   173  				pm.blockchain.GetBlockByNumber(0).Hash(),
   174  			},
   175  		},
   176  //检查将溢出循环跳回到链起始处的角情况
   177  		{
   178  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1},
   179  			[]common.Hash{
   180  				pm.blockchain.GetBlockByNumber(3).Hash(),
   181  			},
   182  		},
   183  //检查跳过溢出循环返回同一头的角情况
   184  		{
   185  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(1).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64},
   186  			[]common.Hash{
   187  				pm.blockchain.GetBlockByNumber(1).Hash(),
   188  			},
   189  		},
   190  //检查是否未返回不存在的邮件头
   191  		{
   192  			&getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1},
   193  			[]common.Hash{},
   194  		}, {
   195  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1},
   196  			[]common.Hash{},
   197  		},
   198  	}
   199  //运行每个测试并对照链验证结果
   200  	for i, tt := range tests {
   201  //收集响应中预期的头
   202  		headers := []*types.Header{}
   203  		for _, hash := range tt.expect {
   204  			headers = append(headers, pm.blockchain.GetBlockByHash(hash).Header())
   205  		}
   206  //发送哈希请求并验证响应
   207  		p2p.Send(peer.app, 0x03, tt.query)
   208  		if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   209  			t.Errorf("test %d: headers mismatch: %v", i, err)
   210  		}
   211  //如果测试使用的是数字源,也可以使用哈希进行重复。
   212  		if tt.query.Origin.Hash == (common.Hash{}) {
   213  			if origin := pm.blockchain.GetBlockByNumber(tt.query.Origin.Number); origin != nil {
   214  				tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0
   215  
   216  				p2p.Send(peer.app, 0x03, tt.query)
   217  				if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   218  					t.Errorf("test %d: headers mismatch: %v", i, err)
   219  				}
   220  			}
   221  		}
   222  	}
   223  }
   224  
   225  //可以基于哈希从远程链中检索阻止内容的测试。
   226  func TestGetBlockBodies62(t *testing.T) { testGetBlockBodies(t, 62) }
   227  func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) }
   228  
   229  func testGetBlockBodies(t *testing.T, protocol int) {
   230  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil)
   231  	peer, _ := newTestPeer("peer", protocol, pm, true)
   232  	defer peer.close()
   233  
   234  //为各种方案创建一批测试
   235  	limit := downloader.MaxBlockFetch
   236  	tests := []struct {
   237  random    int           //从链中随机提取的块数
   238  explicit  []common.Hash //显式请求的块
   239  available []bool        //显式请求块的可用性
   240  expected  int           //期望的现有块总数
   241  	}{
   242  {1, nil, nil, 1},             //单个随机块应该是可检索的
   243  {10, nil, nil, 10},           //应可检索多个随机块
   244  {limit, nil, nil, limit},     //最大可能的块应该是可检索的
   245  {limit + 1, nil, nil, limit}, //不应返回超过可能的块计数
   246  {0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1},      //Genesis区块应该是可回收的。
   247  {0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, //链头滑轮应可回收。
   248  {0, []common.Hash{{}}, []bool{false}, 0},                                 //不应返回不存在的块
   249  
   250  //现有和不存在的块交错不应导致问题
   251  		{0, []common.Hash{
   252  			{},
   253  			pm.blockchain.GetBlockByNumber(1).Hash(),
   254  			{},
   255  			pm.blockchain.GetBlockByNumber(10).Hash(),
   256  			{},
   257  			pm.blockchain.GetBlockByNumber(100).Hash(),
   258  			{},
   259  		}, []bool{false, true, false, true, false, true, false}, 3},
   260  	}
   261  //运行每个测试并对照链验证结果
   262  	for i, tt := range tests {
   263  //收集要请求的哈希值和预期的响应
   264  		hashes, seen := []common.Hash{}, make(map[int64]bool)
   265  		bodies := []*blockBody{}
   266  
   267  		for j := 0; j < tt.random; j++ {
   268  			for {
   269  				num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64()))
   270  				if !seen[num] {
   271  					seen[num] = true
   272  
   273  					block := pm.blockchain.GetBlockByNumber(uint64(num))
   274  					hashes = append(hashes, block.Hash())
   275  					if len(bodies) < tt.expected {
   276  						bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   277  					}
   278  					break
   279  				}
   280  			}
   281  		}
   282  		for j, hash := range tt.explicit {
   283  			hashes = append(hashes, hash)
   284  			if tt.available[j] && len(bodies) < tt.expected {
   285  				block := pm.blockchain.GetBlockByHash(hash)
   286  				bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   287  			}
   288  		}
   289  //发送哈希请求并验证响应
   290  		p2p.Send(peer.app, 0x05, hashes)
   291  		if err := p2p.ExpectMsg(peer.app, 0x06, bodies); err != nil {
   292  			t.Errorf("test %d: bodies mismatch: %v", i, err)
   293  		}
   294  	}
   295  }
   296  
   297  //测试可以基于哈希检索节点状态数据库。
   298  func TestGetNodeData63(t *testing.T) { testGetNodeData(t, 63) }
   299  
   300  func testGetNodeData(t *testing.T, protocol int) {
   301  //定义三个科目以模拟交易
   302  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   303  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   304  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   305  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   306  
   307  	signer := types.HomesteadSigner{}
   308  //用一些简单的事务创建一个链生成器(公然从@fjl/chain_markets_test中被盗)
   309  	generator := func(i int, block *core.BlockGen) {
   310  		switch i {
   311  		case 0:
   312  //在块1中,测试银行发送帐户1一些乙醚。
   313  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   314  			block.AddTx(tx)
   315  		case 1:
   316  //在区块2中,测试银行向账户1发送更多乙醚。
   317  //acc1addr将其传递到account_2。
   318  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   319  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   320  			block.AddTx(tx1)
   321  			block.AddTx(tx2)
   322  		case 2:
   323  //区块3为空,但由账户2开采。
   324  			block.SetCoinbase(acc2Addr)
   325  			block.SetExtra([]byte("yeehaw"))
   326  		case 3:
   327  //块4包括块2和3作为叔叔头(带有修改的额外数据)。
   328  			b2 := block.PrevBlock(1).Header()
   329  			b2.Extra = []byte("foo")
   330  			block.AddUncle(b2)
   331  			b3 := block.PrevBlock(2).Header()
   332  			b3.Extra = []byte("foo")
   333  			block.AddUncle(b3)
   334  		}
   335  	}
   336  //组装测试环境
   337  	pm, db := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   338  	peer, _ := newTestPeer("peer", protocol, pm, true)
   339  	defer peer.close()
   340  
   341  //现在获取整个链数据库
   342  	hashes := []common.Hash{}
   343  	for _, key := range db.Keys() {
   344  		if len(key) == len(common.Hash{}) {
   345  			hashes = append(hashes, common.BytesToHash(key))
   346  		}
   347  	}
   348  	p2p.Send(peer.app, 0x0d, hashes)
   349  	msg, err := peer.app.ReadMsg()
   350  	if err != nil {
   351  		t.Fatalf("failed to read node data response: %v", err)
   352  	}
   353  	if msg.Code != 0x0e {
   354  		t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c)
   355  	}
   356  	var data [][]byte
   357  	if err := msg.Decode(&data); err != nil {
   358  		t.Fatalf("failed to decode response node data: %v", err)
   359  	}
   360  //验证所有哈希是否与请求的数据对应,并重建状态树
   361  	for i, want := range hashes {
   362  		if hash := crypto.Keccak256Hash(data[i]); hash != want {
   363  			t.Errorf("data hash mismatch: have %x, want %x", hash, want)
   364  		}
   365  	}
   366  	statedb := ethdb.NewMemDatabase()
   367  	for i := 0; i < len(data); i++ {
   368  		statedb.Put(hashes[i].Bytes(), data[i])
   369  	}
   370  	accounts := []common.Address{testBank, acc1Addr, acc2Addr}
   371  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   372  		trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb))
   373  
   374  		for j, acc := range accounts {
   375  			state, _ := pm.blockchain.State()
   376  			bw := state.GetBalance(acc)
   377  			bh := trie.GetBalance(acc)
   378  
   379  			if (bw != nil && bh == nil) || (bw == nil && bh != nil) {
   380  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   381  			}
   382  			if bw != nil && bh != nil && bw.Cmp(bw) != 0 {
   383  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   384  			}
   385  		}
   386  	}
   387  }
   388  
   389  //测试是否可以基于哈希值检索事务回执。
   390  func TestGetReceipt63(t *testing.T) { testGetReceipt(t, 63) }
   391  
   392  func testGetReceipt(t *testing.T, protocol int) {
   393  //定义三个科目以模拟交易
   394  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   395  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   396  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   397  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   398  
   399  	signer := types.HomesteadSigner{}
   400  //用一些简单的事务创建一个链生成器(公然从@fjl/chain_markets_test中被盗)
   401  	generator := func(i int, block *core.BlockGen) {
   402  		switch i {
   403  		case 0:
   404  //在块1中,测试银行发送帐户1一些乙醚。
   405  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   406  			block.AddTx(tx)
   407  		case 1:
   408  //在区块2中,测试银行向账户1发送更多乙醚。
   409  //acc1addr将其传递到account_2。
   410  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   411  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   412  			block.AddTx(tx1)
   413  			block.AddTx(tx2)
   414  		case 2:
   415  //区块3为空,但由账户2开采。
   416  			block.SetCoinbase(acc2Addr)
   417  			block.SetExtra([]byte("yeehaw"))
   418  		case 3:
   419  //块4包括块2和3作为叔叔头(带有修改的额外数据)。
   420  			b2 := block.PrevBlock(1).Header()
   421  			b2.Extra = []byte("foo")
   422  			block.AddUncle(b2)
   423  			b3 := block.PrevBlock(2).Header()
   424  			b3.Extra = []byte("foo")
   425  			block.AddUncle(b3)
   426  		}
   427  	}
   428  //组装测试环境
   429  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   430  	peer, _ := newTestPeer("peer", protocol, pm, true)
   431  	defer peer.close()
   432  
   433  //收集要请求的哈希值和预期的响应
   434  	hashes, receipts := []common.Hash{}, []types.Receipts{}
   435  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   436  		block := pm.blockchain.GetBlockByNumber(i)
   437  
   438  		hashes = append(hashes, block.Hash())
   439  		receipts = append(receipts, pm.blockchain.GetReceiptsByHash(block.Hash()))
   440  	}
   441  //发送哈希请求并验证响应
   442  	p2p.Send(peer.app, 0x0f, hashes)
   443  	if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil {
   444  		t.Errorf("receipts mismatch: %v", err)
   445  	}
   446  }
   447  
   448  //发布ETH协议握手的测试,启用DAO分叉的客户端也会执行
   449  //一个DAO“挑战”验证彼此的DAO分叉头,以确保它们处于打开状态
   450  //兼容的链条。
   451  func TestDAOChallengeNoVsNo(t *testing.T)       { testDAOChallenge(t, false, false, false) }
   452  func TestDAOChallengeNoVsPro(t *testing.T)      { testDAOChallenge(t, false, true, false) }
   453  func TestDAOChallengeProVsNo(t *testing.T)      { testDAOChallenge(t, true, false, false) }
   454  func TestDAOChallengeProVsPro(t *testing.T)     { testDAOChallenge(t, true, true, false) }
   455  func TestDAOChallengeNoVsTimeout(t *testing.T)  { testDAOChallenge(t, false, false, true) }
   456  func TestDAOChallengeProVsTimeout(t *testing.T) { testDAOChallenge(t, true, true, true) }
   457  
   458  func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool) {
   459  //减少DAO握手挑战超时
   460  	if timeout {
   461  		defer func(old time.Duration) { daoChallengeTimeout = old }(daoChallengeTimeout)
   462  		daoChallengeTimeout = 500 * time.Millisecond
   463  	}
   464  //创建DAO感知协议管理器
   465  	var (
   466  		evmux   = new(event.TypeMux)
   467  		pow     = ethash.NewFaker()
   468  		db      = ethdb.NewMemDatabase()
   469  		config  = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
   470  		gspec   = &core.Genesis{Config: config}
   471  		genesis = gspec.MustCommit(db)
   472  	)
   473  	blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil)
   474  	if err != nil {
   475  		t.Fatalf("failed to create new blockchain: %v", err)
   476  	}
   477  	pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil)
   478  	if err != nil {
   479  		t.Fatalf("failed to start test protocol manager: %v", err)
   480  	}
   481  	pm.Start(1000)
   482  	defer pm.Stop()
   483  
   484  //连接新的对等点并检查我们是否收到DAO挑战
   485  	peer, _ := newTestPeer("peer", eth63, pm, true)
   486  	defer peer.close()
   487  
   488  	challenge := &getBlockHeadersData{
   489  		Origin:  hashOrNumber{Number: config.DAOForkBlock.Uint64()},
   490  		Amount:  1,
   491  		Skip:    0,
   492  		Reverse: false,
   493  	}
   494  	if err := p2p.ExpectMsg(peer.app, GetBlockHeadersMsg, challenge); err != nil {
   495  		t.Fatalf("challenge mismatch: %v", err)
   496  	}
   497  //如果没有模拟超时,则创建一个块以答复质询
   498  	if !timeout {
   499  		blocks, _ := core.GenerateChain(&params.ChainConfig{}, genesis, ethash.NewFaker(), db, 1, func(i int, block *core.BlockGen) {
   500  			if remoteForked {
   501  				block.SetExtra(params.DAOForkBlockExtra)
   502  			}
   503  		})
   504  		if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{blocks[0].Header()}); err != nil {
   505  			t.Fatalf("failed to answer challenge: %v", err)
   506  		}
   507  time.Sleep(100 * time.Millisecond) //睡眠以避免验证与水滴赛跑
   508  	} else {
   509  //否则,等待测试超时通过
   510  		time.Sleep(daoChallengeTimeout + 500*time.Millisecond)
   511  	}
   512  //验证是否根据分叉端维护或删除远程对等机
   513  	if localForked == remoteForked && !timeout {
   514  		if peers := pm.peers.Len(); peers != 1 {
   515  			t.Fatalf("peer count mismatch: have %d, want %d", peers, 1)
   516  		}
   517  	} else {
   518  		if peers := pm.peers.Len(); peers != 0 {
   519  			t.Fatalf("peer count mismatch: have %d, want %d", peers, 0)
   520  		}
   521  	}
   522  }
   523  
   524  func TestBroadcastBlock(t *testing.T) {
   525  	var tests = []struct {
   526  		totalPeers        int
   527  		broadcastExpected int
   528  	}{
   529  		{1, 1},
   530  		{2, 2},
   531  		{3, 3},
   532  		{4, 4},
   533  		{5, 4},
   534  		{9, 4},
   535  		{12, 4},
   536  		{16, 4},
   537  		{26, 5},
   538  		{100, 10},
   539  	}
   540  	for _, test := range tests {
   541  		testBroadcastBlock(t, test.totalPeers, test.broadcastExpected)
   542  	}
   543  }
   544  
   545  func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
   546  	var (
   547  		evmux   = new(event.TypeMux)
   548  		pow     = ethash.NewFaker()
   549  		db      = ethdb.NewMemDatabase()
   550  		config  = &params.ChainConfig{}
   551  		gspec   = &core.Genesis{Config: config}
   552  		genesis = gspec.MustCommit(db)
   553  	)
   554  	blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil)
   555  	if err != nil {
   556  		t.Fatalf("failed to create new blockchain: %v", err)
   557  	}
   558  	pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, nil)
   559  	if err != nil {
   560  		t.Fatalf("failed to start test protocol manager: %v", err)
   561  	}
   562  	pm.Start(1000)
   563  	defer pm.Stop()
   564  	var peers []*testPeer
   565  	for i := 0; i < totalPeers; i++ {
   566  		peer, _ := newTestPeer(fmt.Sprintf("peer %d", i), eth63, pm, true)
   567  		defer peer.close()
   568  		peers = append(peers, peer)
   569  	}
   570  	chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) {})
   571   /*广播块(链[0],真/*传播*/)
   572  
   573   错误:=make(chan错误,totalpeers)
   574   Donech:=制造(Chan结构,totalpeers)
   575   对于u,对等:=范围对等
   576    Go func(P*testpeer)
   577     如果错误:=p2p.expectmsg(p.app,newblockmsg,&newblockdata block:chain[0],td:big.newint(131136));错误!= nIL{
   578      埃尔奇-厄尔
   579     }否则{
   580      Donech<-结构
   581     }
   582    }(对等体)
   583   }
   584   超时:=time.after(300*time.millisecond)
   585   var接收计数int
   586  外部:
   587   对于{
   588    选择{
   589    案例错误=<-错误:
   590     打破外部
   591    案例:DONECH:
   592     接收计数+
   593     如果receivedCount==totalPeers
   594      打破外部
   595     }
   596    案例<超时:
   597     打破外部
   598    }
   599   }
   600   对于u,对等:=范围对等
   601    peer.app.close()。
   602   }
   603   如果犯错!= nIL{
   604    t.errorf(“按对等方匹配块时出错:%v”,err)
   605   }
   606   如果收到账单!=需要广播
   607    t.errorf(“块广播到%d个对等方,应为%d”,ReceivedCount,应为BroadcastExpected)
   608   }
   609  }
   610