github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/intprotocol/handler_test.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package intprotocol
    18  
    19  import (
    20  	"math"
    21  	"math/big"
    22  	"math/rand"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/intfoundation/intchain/common"
    27  	"github.com/intfoundation/intchain/consensus"
    28  	"github.com/intfoundation/intchain/core"
    29  	"github.com/intfoundation/intchain/core/rawdb"
    30  	"github.com/intfoundation/intchain/core/state"
    31  	"github.com/intfoundation/intchain/core/types"
    32  	"github.com/intfoundation/intchain/crypto"
    33  	"github.com/intfoundation/intchain/intprotocol/downloader"
    34  	"github.com/intfoundation/intchain/p2p"
    35  	"github.com/intfoundation/intchain/params"
    36  )
    37  
    38  // Tests that protocol versions and modes of operations are matched up properly.
    39  func TestProtocolCompatibility(t *testing.T) {
    40  	// Define the compatibility chart
    41  	tests := []struct {
    42  		version    uint
    43  		mode       downloader.SyncMode
    44  		compatible bool
    45  	}{
    46  		{61, downloader.FullSync, true}, {62, downloader.FullSync, true}, {63, downloader.FullSync, true},
    47  		{61, downloader.FastSync, false}, {62, downloader.FastSync, false}, {63, downloader.FastSync, true},
    48  	}
    49  	// Make sure anything we screw up is restored
    50  	backup := consensus.EthProtocol.Versions
    51  	defer func() { consensus.EthProtocol.Versions = backup }()
    52  
    53  	// Try all available compatibility configs and check for errors
    54  	for i, tt := range tests {
    55  		consensus.EthProtocol.Versions = []uint{tt.version}
    56  
    57  		pm, _, err := newTestProtocolManager(tt.mode, 0, nil, nil)
    58  		if pm != nil {
    59  			defer pm.Stop()
    60  		}
    61  		if (err == nil && !tt.compatible) || (err != nil && tt.compatible) {
    62  			t.Errorf("test %d: compatibility mismatch: have error %v, want compatibility %v", i, err, tt.compatible)
    63  		}
    64  	}
    65  }
    66  
    67  // Tests that block headers can be retrieved from a remote chain based on user queries.
    68  func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) }
    69  func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
    70  
    71  func testGetBlockHeaders(t *testing.T, protocol int) {
    72  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxHashFetch+15, nil, nil)
    73  	peer, _ := newTestPeer("peer", protocol, pm, true)
    74  	defer peer.close()
    75  
    76  	// Create a "random" unknown hash for testing
    77  	var unknown common.Hash
    78  	for i := range unknown {
    79  		unknown[i] = byte(i)
    80  	}
    81  	// Create a batch of tests for various scenarios
    82  	limit := uint64(downloader.MaxHeaderFetch)
    83  	tests := []struct {
    84  		query  *getBlockHeadersData // The query to execute for header retrieval
    85  		expect []common.Hash        // The hashes of the block whose headers are expected
    86  	}{
    87  		// A single random block should be retrievable by hash and number too
    88  		{
    89  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
    90  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
    91  		}, {
    92  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1},
    93  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
    94  		},
    95  		// Multiple headers should be retrievable in both directions
    96  		{
    97  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3},
    98  			[]common.Hash{
    99  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   100  				pm.blockchain.GetBlockByNumber(limit/2 + 1).Hash(),
   101  				pm.blockchain.GetBlockByNumber(limit/2 + 2).Hash(),
   102  			},
   103  		}, {
   104  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
   105  			[]common.Hash{
   106  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   107  				pm.blockchain.GetBlockByNumber(limit/2 - 1).Hash(),
   108  				pm.blockchain.GetBlockByNumber(limit/2 - 2).Hash(),
   109  			},
   110  		},
   111  		// Multiple headers with skip lists should be retrievable
   112  		{
   113  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
   114  			[]common.Hash{
   115  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   116  				pm.blockchain.GetBlockByNumber(limit/2 + 4).Hash(),
   117  				pm.blockchain.GetBlockByNumber(limit/2 + 8).Hash(),
   118  			},
   119  		}, {
   120  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
   121  			[]common.Hash{
   122  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   123  				pm.blockchain.GetBlockByNumber(limit/2 - 4).Hash(),
   124  				pm.blockchain.GetBlockByNumber(limit/2 - 8).Hash(),
   125  			},
   126  		},
   127  		// The chain endpoints should be retrievable
   128  		{
   129  			&getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1},
   130  			[]common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()},
   131  		}, {
   132  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1},
   133  			[]common.Hash{pm.blockchain.CurrentBlock().Hash()},
   134  		},
   135  		// Ensure protocol limits are honored
   136  		{
   137  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true},
   138  			pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit),
   139  		},
   140  		// Check that requesting more than available is handled gracefully
   141  		{
   142  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3},
   143  			[]common.Hash{
   144  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   145  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(),
   146  			},
   147  		}, {
   148  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
   149  			[]common.Hash{
   150  				pm.blockchain.GetBlockByNumber(4).Hash(),
   151  				pm.blockchain.GetBlockByNumber(0).Hash(),
   152  			},
   153  		},
   154  		// Check that requesting more than available is handled gracefully, even if mid skip
   155  		{
   156  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3},
   157  			[]common.Hash{
   158  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   159  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(),
   160  			},
   161  		}, {
   162  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
   163  			[]common.Hash{
   164  				pm.blockchain.GetBlockByNumber(4).Hash(),
   165  				pm.blockchain.GetBlockByNumber(1).Hash(),
   166  			},
   167  		},
   168  		// Check a corner case where requesting more can iterate past the endpoints
   169  		{
   170  			&getBlockHeadersData{Origin: hashOrNumber{Number: 2}, Amount: 5, Reverse: true},
   171  			[]common.Hash{
   172  				pm.blockchain.GetBlockByNumber(2).Hash(),
   173  				pm.blockchain.GetBlockByNumber(1).Hash(),
   174  				pm.blockchain.GetBlockByNumber(0).Hash(),
   175  			},
   176  		},
   177  		// Check a corner case where skipping overflow loops back into the chain start
   178  		{
   179  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1},
   180  			[]common.Hash{
   181  				pm.blockchain.GetBlockByNumber(3).Hash(),
   182  			},
   183  		},
   184  		// Check a corner case where skipping overflow loops back to the same header
   185  		{
   186  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(1).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64},
   187  			[]common.Hash{
   188  				pm.blockchain.GetBlockByNumber(1).Hash(),
   189  			},
   190  		},
   191  		// Check that non existing headers aren't returned
   192  		{
   193  			&getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1},
   194  			[]common.Hash{},
   195  		}, {
   196  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1},
   197  			[]common.Hash{},
   198  		},
   199  	}
   200  	// Run each of the tests and verify the results against the chain
   201  	for i, tt := range tests {
   202  		// Collect the headers to expect in the response
   203  		headers := []*types.Header{}
   204  		for _, hash := range tt.expect {
   205  			headers = append(headers, pm.blockchain.GetBlockByHash(hash).Header())
   206  		}
   207  		// Send the hash request and verify the response
   208  		p2p.Send(peer.app, 0x03, tt.query)
   209  		if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   210  			t.Errorf("test %d: headers mismatch: %v", i, err)
   211  		}
   212  		// If the test used number origins, repeat with hashes as the too
   213  		if tt.query.Origin.Hash == (common.Hash{}) {
   214  			if origin := pm.blockchain.GetBlockByNumber(tt.query.Origin.Number); origin != nil {
   215  				tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0
   216  
   217  				p2p.Send(peer.app, 0x03, tt.query)
   218  				if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   219  					t.Errorf("test %d: headers mismatch: %v", i, err)
   220  				}
   221  			}
   222  		}
   223  	}
   224  }
   225  
   226  // Tests that block contents can be retrieved from a remote chain based on their hashes.
   227  func TestGetBlockBodies62(t *testing.T) { testGetBlockBodies(t, 62) }
   228  func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) }
   229  
   230  func testGetBlockBodies(t *testing.T, protocol int) {
   231  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil)
   232  	peer, _ := newTestPeer("peer", protocol, pm, true)
   233  	defer peer.close()
   234  
   235  	// Create a batch of tests for various scenarios
   236  	limit := downloader.MaxBlockFetch
   237  	tests := []struct {
   238  		random    int           // Number of blocks to fetch randomly from the chain
   239  		explicit  []common.Hash // Explicitly requested blocks
   240  		available []bool        // Availability of explicitly requested blocks
   241  		expected  int           // Total number of existing blocks to expect
   242  	}{
   243  		{1, nil, nil, 1},             // A single random block should be retrievable
   244  		{10, nil, nil, 10},           // Multiple random blocks should be retrievable
   245  		{limit, nil, nil, limit},     // The maximum possible blocks should be retrievable
   246  		{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned
   247  		{0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1},      // The genesis block should be retrievable
   248  		{0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable
   249  		{0, []common.Hash{{}}, []bool{false}, 0},                                 // A non existent block should not be returned
   250  
   251  		// Existing and non-existing blocks interleaved should not cause problems
   252  		{0, []common.Hash{
   253  			{},
   254  			pm.blockchain.GetBlockByNumber(1).Hash(),
   255  			{},
   256  			pm.blockchain.GetBlockByNumber(10).Hash(),
   257  			{},
   258  			pm.blockchain.GetBlockByNumber(100).Hash(),
   259  			{},
   260  		}, []bool{false, true, false, true, false, true, false}, 3},
   261  	}
   262  	// Run each of the tests and verify the results against the chain
   263  	for i, tt := range tests {
   264  		// Collect the hashes to request, and the response to expect
   265  		hashes, seen := []common.Hash{}, make(map[int64]bool)
   266  		bodies := []*blockBody{}
   267  
   268  		for j := 0; j < tt.random; j++ {
   269  			for {
   270  				num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64()))
   271  				if !seen[num] {
   272  					seen[num] = true
   273  
   274  					block := pm.blockchain.GetBlockByNumber(uint64(num))
   275  					hashes = append(hashes, block.Hash())
   276  					if len(bodies) < tt.expected {
   277  						bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   278  					}
   279  					break
   280  				}
   281  			}
   282  		}
   283  		for j, hash := range tt.explicit {
   284  			hashes = append(hashes, hash)
   285  			if tt.available[j] && len(bodies) < tt.expected {
   286  				block := pm.blockchain.GetBlockByHash(hash)
   287  				bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   288  			}
   289  		}
   290  		// Send the hash request and verify the response
   291  		p2p.Send(peer.app, 0x05, hashes)
   292  		if err := p2p.ExpectMsg(peer.app, 0x06, bodies); err != nil {
   293  			t.Errorf("test %d: bodies mismatch: %v", i, err)
   294  		}
   295  	}
   296  }
   297  
   298  // Tests that the node state database can be retrieved based on hashes.
   299  func TestGetNodeData63(t *testing.T) { testGetNodeData(t, 63) }
   300  
   301  func testGetNodeData(t *testing.T, protocol int) {
   302  	// Define three accounts to simulate transactions with
   303  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   304  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   305  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   306  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   307  
   308  	signer := types.HomesteadSigner{}
   309  	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
   310  	generator := func(i int, block *core.BlockGen) {
   311  		switch i {
   312  		case 0:
   313  			// In block 1, the test bank sends account #1 some ether.
   314  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   315  			block.AddTx(tx)
   316  		case 1:
   317  			// In block 2, the test bank sends some more ether to account #1.
   318  			// acc1Addr passes it on to account #2.
   319  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   320  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   321  			block.AddTx(tx1)
   322  			block.AddTx(tx2)
   323  		case 2:
   324  			// Block 3 is empty but was mined by account #2.
   325  			block.SetCoinbase(acc2Addr)
   326  			block.SetExtra([]byte("yeehaw"))
   327  		case 3:
   328  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   329  			b2 := block.PrevBlock(1).Header()
   330  			b2.Extra = []byte("foo")
   331  			block.AddUncle(b2)
   332  			b3 := block.PrevBlock(2).Header()
   333  			b3.Extra = []byte("foo")
   334  			block.AddUncle(b3)
   335  		}
   336  	}
   337  	// Assemble the test environment
   338  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   339  	peer, _ := newTestPeer("peer", protocol, pm, true)
   340  	defer peer.close()
   341  
   342  	// Fetch for now the entire chain db
   343  	hashes := []common.Hash{}
   344  	//for _, key := range db.Keys() {
   345  	//	if len(key) == len(common.Hash{}) {
   346  	//		hashes = append(hashes, common.BytesToHash(key))
   347  	//	}
   348  	//}
   349  	p2p.Send(peer.app, 0x0d, hashes)
   350  	msg, err := peer.app.ReadMsg()
   351  	if err != nil {
   352  		t.Fatalf("failed to read node data response: %v", err)
   353  	}
   354  	if msg.Code != 0x0e {
   355  		t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c)
   356  	}
   357  	var data [][]byte
   358  	if err := msg.Decode(&data); err != nil {
   359  		t.Fatalf("failed to decode response node data: %v", err)
   360  	}
   361  	// Verify that all hashes correspond to the requested data, and reconstruct a state tree
   362  	for i, want := range hashes {
   363  		if hash := crypto.Keccak256Hash(data[i]); hash != want {
   364  			t.Errorf("data hash mismatch: have %x, want %x", hash, want)
   365  		}
   366  	}
   367  	statedb := rawdb.NewMemoryDatabase()
   368  	for i := 0; i < len(data); i++ {
   369  		statedb.Put(hashes[i].Bytes(), data[i])
   370  	}
   371  	accounts := []common.Address{testBank, acc1Addr, acc2Addr}
   372  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   373  		trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb))
   374  
   375  		for j, acc := range accounts {
   376  			state, _ := pm.blockchain.State()
   377  			bw := state.GetBalance(acc)
   378  			bh := trie.GetBalance(acc)
   379  
   380  			if (bw != nil && bh == nil) || (bw == nil && bh != nil) {
   381  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   382  			}
   383  			if bw != nil && bh != nil && bw.Cmp(bw) != 0 {
   384  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   385  			}
   386  		}
   387  	}
   388  }
   389  
   390  // Tests that the transaction receipts can be retrieved based on hashes.
   391  func TestGetReceipt63(t *testing.T) { testGetReceipt(t, 63) }
   392  
   393  func testGetReceipt(t *testing.T, protocol int) {
   394  	// Define three accounts to simulate transactions with
   395  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   396  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   397  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   398  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   399  
   400  	signer := types.HomesteadSigner{}
   401  	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
   402  	generator := func(i int, block *core.BlockGen) {
   403  		switch i {
   404  		case 0:
   405  			// In block 1, the test bank sends account #1 some ether.
   406  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   407  			block.AddTx(tx)
   408  		case 1:
   409  			// In block 2, the test bank sends some more ether to account #1.
   410  			// acc1Addr passes it on to account #2.
   411  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   412  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   413  			block.AddTx(tx1)
   414  			block.AddTx(tx2)
   415  		case 2:
   416  			// Block 3 is empty but was mined by account #2.
   417  			block.SetCoinbase(acc2Addr)
   418  			block.SetExtra([]byte("yeehaw"))
   419  		case 3:
   420  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   421  			b2 := block.PrevBlock(1).Header()
   422  			b2.Extra = []byte("foo")
   423  			block.AddUncle(b2)
   424  			b3 := block.PrevBlock(2).Header()
   425  			b3.Extra = []byte("foo")
   426  			block.AddUncle(b3)
   427  		}
   428  	}
   429  	// Assemble the test environment
   430  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   431  	peer, _ := newTestPeer("peer", protocol, pm, true)
   432  	defer peer.close()
   433  
   434  	// Collect the hashes to request, and the response to expect
   435  	hashes, receipts := []common.Hash{}, []types.Receipts{}
   436  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   437  		block := pm.blockchain.GetBlockByNumber(i)
   438  
   439  		hashes = append(hashes, block.Hash())
   440  		receipts = append(receipts, pm.blockchain.GetReceiptsByHash(block.Hash()))
   441  	}
   442  	// Send the hash request and verify the response
   443  	p2p.Send(peer.app, 0x0f, hashes)
   444  	if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil {
   445  		t.Errorf("receipts mismatch: %v", err)
   446  	}
   447  }
   448  
   449  // Tests that post intprotocol protocol handshake, DAO fork-enabled clients also execute
   450  // a DAO "challenge" verifying each others' DAO fork headers to ensure they're on
   451  // compatible chains.
   452  func TestDAOChallengeNoVsNo(t *testing.T)       { testDAOChallenge(t, false, false, false) }
   453  func TestDAOChallengeNoVsPro(t *testing.T)      { testDAOChallenge(t, false, true, false) }
   454  func TestDAOChallengeProVsNo(t *testing.T)      { testDAOChallenge(t, true, false, false) }
   455  func TestDAOChallengeProVsPro(t *testing.T)     { testDAOChallenge(t, true, true, false) }
   456  func TestDAOChallengeNoVsTimeout(t *testing.T)  { testDAOChallenge(t, false, false, true) }
   457  func TestDAOChallengeProVsTimeout(t *testing.T) { testDAOChallenge(t, true, true, true) }
   458  
   459  func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool) {
   460  	// Reduce the DAO handshake challenge timeout
   461  	if timeout {
   462  		defer func(old time.Duration) { daoChallengeTimeout = old }(daoChallengeTimeout)
   463  		daoChallengeTimeout = 500 * time.Millisecond
   464  	}
   465  	// Create a DAO aware protocol manager
   466  
   467  	// Connect a new peer and check that we receive the DAO challenge
   468  }