github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/neatptc/handler_test.go (about)

     1  package neatptc
     2  
     3  import (
     4  	"math"
     5  	"math/big"
     6  	"math/rand"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/neatlab/neatio/chain/consensus"
    11  	"github.com/neatlab/neatio/chain/core"
    12  	"github.com/neatlab/neatio/chain/core/rawdb"
    13  	"github.com/neatlab/neatio/chain/core/state"
    14  	"github.com/neatlab/neatio/chain/core/types"
    15  	"github.com/neatlab/neatio/neatptc/downloader"
    16  	"github.com/neatlab/neatio/network/p2p"
    17  	"github.com/neatlab/neatio/params"
    18  	"github.com/neatlab/neatio/utilities/common"
    19  	"github.com/neatlab/neatio/utilities/crypto"
    20  )
    21  
    22  func TestProtocolCompatibility(t *testing.T) {
    23  
    24  	tests := []struct {
    25  		version    uint
    26  		mode       downloader.SyncMode
    27  		compatible bool
    28  	}{
    29  		{61, downloader.FullSync, true}, {62, downloader.FullSync, true}, {63, downloader.FullSync, true},
    30  		{61, downloader.FastSync, false}, {62, downloader.FastSync, false}, {63, downloader.FastSync, true},
    31  	}
    32  
    33  	backup := consensus.EthProtocol.Versions
    34  	defer func() { consensus.EthProtocol.Versions = backup }()
    35  
    36  	for i, tt := range tests {
    37  		consensus.EthProtocol.Versions = []uint{tt.version}
    38  
    39  		pm, _, err := newTestProtocolManager(tt.mode, 0, nil, nil)
    40  		if pm != nil {
    41  			defer pm.Stop()
    42  		}
    43  		if (err == nil && !tt.compatible) || (err != nil && tt.compatible) {
    44  			t.Errorf("test %d: compatibility mismatch: have error %v, want compatibility %v", i, err, tt.compatible)
    45  		}
    46  	}
    47  }
    48  
    49  func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) }
    50  func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
    51  
    52  func testGetBlockHeaders(t *testing.T, protocol int) {
    53  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxHashFetch+15, nil, nil)
    54  	peer, _ := newTestPeer("peer", protocol, pm, true)
    55  	defer peer.close()
    56  
    57  	var unknown common.Hash
    58  	for i := range unknown {
    59  		unknown[i] = byte(i)
    60  	}
    61  
    62  	limit := uint64(downloader.MaxHeaderFetch)
    63  	tests := []struct {
    64  		query  *getBlockHeadersData
    65  		expect []common.Hash
    66  	}{
    67  
    68  		{
    69  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
    70  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
    71  		}, {
    72  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1},
    73  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
    74  		},
    75  
    76  		{
    77  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3},
    78  			[]common.Hash{
    79  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
    80  				pm.blockchain.GetBlockByNumber(limit/2 + 1).Hash(),
    81  				pm.blockchain.GetBlockByNumber(limit/2 + 2).Hash(),
    82  			},
    83  		}, {
    84  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
    85  			[]common.Hash{
    86  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
    87  				pm.blockchain.GetBlockByNumber(limit/2 - 1).Hash(),
    88  				pm.blockchain.GetBlockByNumber(limit/2 - 2).Hash(),
    89  			},
    90  		},
    91  
    92  		{
    93  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
    94  			[]common.Hash{
    95  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
    96  				pm.blockchain.GetBlockByNumber(limit/2 + 4).Hash(),
    97  				pm.blockchain.GetBlockByNumber(limit/2 + 8).Hash(),
    98  			},
    99  		}, {
   100  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
   101  			[]common.Hash{
   102  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   103  				pm.blockchain.GetBlockByNumber(limit/2 - 4).Hash(),
   104  				pm.blockchain.GetBlockByNumber(limit/2 - 8).Hash(),
   105  			},
   106  		},
   107  
   108  		{
   109  			&getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1},
   110  			[]common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()},
   111  		}, {
   112  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1},
   113  			[]common.Hash{pm.blockchain.CurrentBlock().Hash()},
   114  		},
   115  
   116  		{
   117  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true},
   118  			pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit),
   119  		},
   120  
   121  		{
   122  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3},
   123  			[]common.Hash{
   124  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   125  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(),
   126  			},
   127  		}, {
   128  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
   129  			[]common.Hash{
   130  				pm.blockchain.GetBlockByNumber(4).Hash(),
   131  				pm.blockchain.GetBlockByNumber(0).Hash(),
   132  			},
   133  		},
   134  
   135  		{
   136  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3},
   137  			[]common.Hash{
   138  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   139  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(),
   140  			},
   141  		}, {
   142  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
   143  			[]common.Hash{
   144  				pm.blockchain.GetBlockByNumber(4).Hash(),
   145  				pm.blockchain.GetBlockByNumber(1).Hash(),
   146  			},
   147  		},
   148  
   149  		{
   150  			&getBlockHeadersData{Origin: hashOrNumber{Number: 2}, Amount: 5, Reverse: true},
   151  			[]common.Hash{
   152  				pm.blockchain.GetBlockByNumber(2).Hash(),
   153  				pm.blockchain.GetBlockByNumber(1).Hash(),
   154  				pm.blockchain.GetBlockByNumber(0).Hash(),
   155  			},
   156  		},
   157  
   158  		{
   159  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1},
   160  			[]common.Hash{
   161  				pm.blockchain.GetBlockByNumber(3).Hash(),
   162  			},
   163  		},
   164  
   165  		{
   166  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(1).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64},
   167  			[]common.Hash{
   168  				pm.blockchain.GetBlockByNumber(1).Hash(),
   169  			},
   170  		},
   171  
   172  		{
   173  			&getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1},
   174  			[]common.Hash{},
   175  		}, {
   176  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1},
   177  			[]common.Hash{},
   178  		},
   179  	}
   180  
   181  	for i, tt := range tests {
   182  
   183  		headers := []*types.Header{}
   184  		for _, hash := range tt.expect {
   185  			headers = append(headers, pm.blockchain.GetBlockByHash(hash).Header())
   186  		}
   187  
   188  		p2p.Send(peer.app, 0x03, tt.query)
   189  		if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   190  			t.Errorf("test %d: headers mismatch: %v", i, err)
   191  		}
   192  
   193  		if tt.query.Origin.Hash == (common.Hash{}) {
   194  			if origin := pm.blockchain.GetBlockByNumber(tt.query.Origin.Number); origin != nil {
   195  				tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0
   196  
   197  				p2p.Send(peer.app, 0x03, tt.query)
   198  				if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   199  					t.Errorf("test %d: headers mismatch: %v", i, err)
   200  				}
   201  			}
   202  		}
   203  	}
   204  }
   205  
   206  func TestGetBlockBodies62(t *testing.T) { testGetBlockBodies(t, 62) }
   207  func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) }
   208  
   209  func testGetBlockBodies(t *testing.T, protocol int) {
   210  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil)
   211  	peer, _ := newTestPeer("peer", protocol, pm, true)
   212  	defer peer.close()
   213  
   214  	limit := downloader.MaxBlockFetch
   215  	tests := []struct {
   216  		random    int
   217  		explicit  []common.Hash
   218  		available []bool
   219  		expected  int
   220  	}{
   221  		{1, nil, nil, 1},
   222  		{10, nil, nil, 10},
   223  		{limit, nil, nil, limit},
   224  		{limit + 1, nil, nil, limit},
   225  		{0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1},
   226  		{0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1},
   227  		{0, []common.Hash{{}}, []bool{false}, 0},
   228  
   229  		{0, []common.Hash{
   230  			{},
   231  			pm.blockchain.GetBlockByNumber(1).Hash(),
   232  			{},
   233  			pm.blockchain.GetBlockByNumber(10).Hash(),
   234  			{},
   235  			pm.blockchain.GetBlockByNumber(100).Hash(),
   236  			{},
   237  		}, []bool{false, true, false, true, false, true, false}, 3},
   238  	}
   239  
   240  	for i, tt := range tests {
   241  
   242  		hashes, seen := []common.Hash{}, make(map[int64]bool)
   243  		bodies := []*blockBody{}
   244  
   245  		for j := 0; j < tt.random; j++ {
   246  			for {
   247  				num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64()))
   248  				if !seen[num] {
   249  					seen[num] = true
   250  
   251  					block := pm.blockchain.GetBlockByNumber(uint64(num))
   252  					hashes = append(hashes, block.Hash())
   253  					if len(bodies) < tt.expected {
   254  						bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   255  					}
   256  					break
   257  				}
   258  			}
   259  		}
   260  		for j, hash := range tt.explicit {
   261  			hashes = append(hashes, hash)
   262  			if tt.available[j] && len(bodies) < tt.expected {
   263  				block := pm.blockchain.GetBlockByHash(hash)
   264  				bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   265  			}
   266  		}
   267  
   268  		p2p.Send(peer.app, 0x05, hashes)
   269  		if err := p2p.ExpectMsg(peer.app, 0x06, bodies); err != nil {
   270  			t.Errorf("test %d: bodies mismatch: %v", i, err)
   271  		}
   272  	}
   273  }
   274  
   275  func TestGetNodeData63(t *testing.T) { testGetNodeData(t, 63) }
   276  
   277  func testGetNodeData(t *testing.T, protocol int) {
   278  
   279  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   280  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   281  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   282  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   283  
   284  	signer := types.HomesteadSigner{}
   285  
   286  	generator := func(i int, block *core.BlockGen) {
   287  		switch i {
   288  		case 0:
   289  
   290  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   291  			block.AddTx(tx)
   292  		case 1:
   293  
   294  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   295  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   296  			block.AddTx(tx1)
   297  			block.AddTx(tx2)
   298  		case 2:
   299  
   300  			block.SetCoinbase(acc2Addr)
   301  			block.SetExtra([]byte("yeehaw"))
   302  		case 3:
   303  
   304  			b2 := block.PrevBlock(1).Header()
   305  			b2.Extra = []byte("foo")
   306  			block.AddUncle(b2)
   307  			b3 := block.PrevBlock(2).Header()
   308  			b3.Extra = []byte("foo")
   309  			block.AddUncle(b3)
   310  		}
   311  	}
   312  
   313  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   314  	peer, _ := newTestPeer("peer", protocol, pm, true)
   315  	defer peer.close()
   316  
   317  	hashes := []common.Hash{}
   318  
   319  	p2p.Send(peer.app, 0x0d, hashes)
   320  	msg, err := peer.app.ReadMsg()
   321  	if err != nil {
   322  		t.Fatalf("failed to read node data response: %v", err)
   323  	}
   324  	if msg.Code != 0x0e {
   325  		t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c)
   326  	}
   327  	var data [][]byte
   328  	if err := msg.Decode(&data); err != nil {
   329  		t.Fatalf("failed to decode response node data: %v", err)
   330  	}
   331  
   332  	for i, want := range hashes {
   333  		if hash := crypto.Keccak256Hash(data[i]); hash != want {
   334  			t.Errorf("data hash mismatch: have %x, want %x", hash, want)
   335  		}
   336  	}
   337  	statedb := rawdb.NewMemoryDatabase()
   338  	for i := 0; i < len(data); i++ {
   339  		statedb.Put(hashes[i].Bytes(), data[i])
   340  	}
   341  	accounts := []common.Address{testBank, acc1Addr, acc2Addr}
   342  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   343  		trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb))
   344  
   345  		for j, acc := range accounts {
   346  			state, _ := pm.blockchain.State()
   347  			bw := state.GetBalance(acc)
   348  			bh := trie.GetBalance(acc)
   349  
   350  			if (bw != nil && bh == nil) || (bw == nil && bh != nil) {
   351  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   352  			}
   353  			if bw != nil && bh != nil && bw.Cmp(bw) != 0 {
   354  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   355  			}
   356  		}
   357  	}
   358  }
   359  
   360  func TestGetReceipt63(t *testing.T) { testGetReceipt(t, 63) }
   361  
   362  func testGetReceipt(t *testing.T, protocol int) {
   363  
   364  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   365  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   366  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   367  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   368  
   369  	signer := types.HomesteadSigner{}
   370  
   371  	generator := func(i int, block *core.BlockGen) {
   372  		switch i {
   373  		case 0:
   374  
   375  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   376  			block.AddTx(tx)
   377  		case 1:
   378  
   379  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   380  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   381  			block.AddTx(tx1)
   382  			block.AddTx(tx2)
   383  		case 2:
   384  
   385  			block.SetCoinbase(acc2Addr)
   386  			block.SetExtra([]byte("yeehaw"))
   387  		case 3:
   388  
   389  			b2 := block.PrevBlock(1).Header()
   390  			b2.Extra = []byte("foo")
   391  			block.AddUncle(b2)
   392  			b3 := block.PrevBlock(2).Header()
   393  			b3.Extra = []byte("foo")
   394  			block.AddUncle(b3)
   395  		}
   396  	}
   397  
   398  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   399  	peer, _ := newTestPeer("peer", protocol, pm, true)
   400  	defer peer.close()
   401  
   402  	hashes, receipts := []common.Hash{}, []types.Receipts{}
   403  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   404  		block := pm.blockchain.GetBlockByNumber(i)
   405  
   406  		hashes = append(hashes, block.Hash())
   407  		receipts = append(receipts, pm.blockchain.GetReceiptsByHash(block.Hash()))
   408  	}
   409  
   410  	p2p.Send(peer.app, 0x0f, hashes)
   411  	if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil {
   412  		t.Errorf("receipts mismatch: %v", err)
   413  	}
   414  }
   415  
   416  func TestDAOChallengeNoVsNo(t *testing.T)       { testDAOChallenge(t, false, false, false) }
   417  func TestDAOChallengeNoVsPro(t *testing.T)      { testDAOChallenge(t, false, true, false) }
   418  func TestDAOChallengeProVsNo(t *testing.T)      { testDAOChallenge(t, true, false, false) }
   419  func TestDAOChallengeProVsPro(t *testing.T)     { testDAOChallenge(t, true, true, false) }
   420  func TestDAOChallengeNoVsTimeout(t *testing.T)  { testDAOChallenge(t, false, false, true) }
   421  func TestDAOChallengeProVsTimeout(t *testing.T) { testDAOChallenge(t, true, true, true) }
   422  
   423  func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool) {
   424  
   425  	if timeout {
   426  		defer func(old time.Duration) { daoChallengeTimeout = old }(daoChallengeTimeout)
   427  		daoChallengeTimeout = 500 * time.Millisecond
   428  	}
   429  
   430  }