github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/eth/helper_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  // This file contains some shares testing functionality, common to  multiple
    18  // different files and modules being tested.
    19  
    20  package eth
    21  
    22  import (
    23  	"crypto/ecdsa"
    24  	"crypto/rand"
    25  	"math/big"
    26  	"sync"
    27  	"testing"
    28  
    29  	"github.com/ethereumproject/go-ethereum/common"
    30  	"github.com/ethereumproject/go-ethereum/core"
    31  	"github.com/ethereumproject/go-ethereum/core/types"
    32  	"github.com/ethereumproject/go-ethereum/crypto"
    33  	"github.com/ethereumproject/go-ethereum/eth/downloader"
    34  	"github.com/ethereumproject/go-ethereum/ethdb"
    35  	"github.com/ethereumproject/go-ethereum/event"
    36  	"github.com/ethereumproject/go-ethereum/p2p"
    37  	"github.com/ethereumproject/go-ethereum/p2p/discover"
    38  )
    39  
    40  var (
    41  	testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    42  	testBank       = core.GenesisAccount{
    43  		Address: crypto.PubkeyToAddress(testBankKey.PublicKey),
    44  		Balance: big.NewInt(1000000),
    45  	}
    46  )
    47  
    48  // newTestProtocolManager creates a new protocol manager for testing purposes,
    49  // with the given number of blocks already known, and potential notification
    50  // channels for different events.
    51  func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase, error) {
    52  	var (
    53  		evmux       = new(event.TypeMux)
    54  		pow         = new(core.FakePow)
    55  		db, _       = ethdb.NewMemDatabase()
    56  		genesis     = core.WriteGenesisBlockForTesting(db, testBank)
    57  		chainConfig = &core.ChainConfig{
    58  			Forks: []*core.Fork{
    59  				{
    60  					Name:  "Homestead",
    61  					Block: big.NewInt(0),
    62  				},
    63  			},
    64  		}
    65  		blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux)
    66  	)
    67  
    68  	chain, _ := core.GenerateChain(core.DefaultConfigMorden.ChainConfig, genesis, db, blocks, generator)
    69  	if res := blockchain.InsertChain(chain); res.Error != nil {
    70  		panic(res.Error)
    71  	}
    72  
    73  	pm, err := NewProtocolManager(chainConfig, mode, NetworkId, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
    74  	if err != nil {
    75  		return nil, nil, err
    76  	}
    77  	pm.Start(1000)
    78  	return pm, db, nil
    79  }
    80  
    81  // newTestProtocolManagerMust creates a new protocol manager for testing purposes,
    82  // with the given number of blocks already known, and potential notification
    83  // channels for different events. In case of an error, the constructor force-
    84  // fails the test.
    85  func newTestProtocolManagerMust(t *testing.T, mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase) {
    86  	pm, db, err := newTestProtocolManager(mode, blocks, generator, newtx)
    87  	if err != nil {
    88  		t.Fatalf("Failed to create protocol manager: %v", err)
    89  	}
    90  	return pm, db
    91  }
    92  
    93  // testTxPool is a fake, helper transaction pool for testing purposes
    94  type testTxPool struct {
    95  	txFeed event.Feed
    96  	pool   []*types.Transaction        // Collection of all transactions
    97  	added  chan<- []*types.Transaction // Notification channel for new transactions
    98  
    99  	lock sync.RWMutex // Protects the transaction pool
   100  }
   101  
   102  // AddTransactions appends a batch of transactions to the pool, and notifies any
   103  // listeners if the addition channel is non nil
   104  func (p *testTxPool) AddTransactions(txs []*types.Transaction) {
   105  	p.lock.Lock()
   106  	defer p.lock.Unlock()
   107  
   108  	p.pool = append(p.pool, txs...)
   109  	if p.added != nil {
   110  		p.added <- txs
   111  	}
   112  }
   113  
   114  // GetTransactions returns all the transactions known to the pool
   115  func (p *testTxPool) GetTransactions() types.Transactions {
   116  	p.lock.RLock()
   117  	defer p.lock.RUnlock()
   118  
   119  	txs := make([]*types.Transaction, len(p.pool))
   120  	copy(txs, p.pool)
   121  
   122  	return txs
   123  }
   124  
   125  // newTestTransaction create a new dummy transaction.
   126  func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction {
   127  	tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize))
   128  	tx, _ = tx.SignECDSA(from)
   129  	return tx
   130  }
   131  
   132  // testPeer is a simulated peer to allow testing direct network calls.
   133  type testPeer struct {
   134  	net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging
   135  	app *p2p.MsgPipeRW    // Application layer reader/writer to simulate the local side
   136  	*peer
   137  }
   138  
   139  // newTestPeer creates a new peer registered at the given protocol manager.
   140  func newTestPeer(name string, version int, pm *ProtocolManager, shake bool) (*testPeer, <-chan error) {
   141  	// Create a message pipe to communicate through
   142  	app, net := p2p.MsgPipe()
   143  
   144  	// Generate a random id and create the peer
   145  	var id discover.NodeID
   146  	rand.Read(id[:])
   147  
   148  	peer := pm.newPeer(version, p2p.NewPeer(id, name, nil), net)
   149  
   150  	// Start the peer on a new thread
   151  	errc := make(chan error, 1)
   152  	go func() {
   153  		select {
   154  		case pm.newPeerCh <- peer:
   155  			errc <- pm.handle(peer)
   156  		case <-pm.quitSync:
   157  			errc <- p2p.DiscQuitting
   158  		}
   159  	}()
   160  	tp := &testPeer{app: app, net: net, peer: peer}
   161  	// Execute any implicitly requested handshakes and return
   162  	if shake {
   163  		td, head, genesis := pm.blockchain.Status()
   164  		tp.handshake(nil, td, head, genesis)
   165  	}
   166  	return tp, errc
   167  }
   168  
   169  // handshake simulates a trivial handshake that expects the same state from the
   170  // remote side as we are simulating locally.
   171  func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, genesis common.Hash) {
   172  	msg := &statusData{
   173  		ProtocolVersion: uint32(p.version),
   174  		NetworkId:       uint32(NetworkId),
   175  		TD:              td,
   176  		CurrentBlock:    head,
   177  		GenesisBlock:    genesis,
   178  	}
   179  	if err := p2p.ExpectMsg(p.app, StatusMsg, msg); err != nil {
   180  		t.Fatalf("status recv: %v", err)
   181  	}
   182  	if s, err := p2p.Send(p.app, StatusMsg, msg); err != nil {
   183  		t.Fatalf("status send: %v", err)
   184  	} else if s <= 0 {
   185  		t.Errorf("got: %v, want: >0", s)
   186  	}
   187  }
   188  
   189  // close terminates the local side of the peer, notifying the remote protocol
   190  // manager of termination.
   191  func (p *testPeer) close() {
   192  	p.app.Close()
   193  }