github.com/codingfuture/orig-energi3@v0.8.4/energi/service/checkpoints_test.go (about)

     1  // Copyright 2019 The Energi Core Authors
     2  // This file is part of the Energi Core library.
     3  //
     4  // The Energi Core 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 Energi Core 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 Energi Core library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package service
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"fmt"
    22  	"net"
    23  	"reflect"
    24  	"sync"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/accounts/keystore"
    29  	"github.com/ethereum/go-ethereum/common"
    30  	"github.com/ethereum/go-ethereum/core"
    31  	"github.com/ethereum/go-ethereum/crypto"
    32  	"github.com/ethereum/go-ethereum/eth"
    33  
    34  	// "github.com/ethereum/go-ethereum/log"
    35  	"github.com/ethereum/go-ethereum/node"
    36  	"github.com/ethereum/go-ethereum/p2p"
    37  	"github.com/ethereum/go-ethereum/p2p/nat"
    38  	"github.com/ethereum/go-ethereum/params"
    39  	"github.com/stretchr/testify/assert"
    40  
    41  	energi_testutils "energi.world/core/gen3/energi/common/testutils"
    42  	energi_params "energi.world/core/gen3/energi/params"
    43  )
    44  
    45  var sentCheckPoints = &testCheckPoints{}
    46  
    47  type testCheckPoints struct {
    48  	mtx sync.RWMutex
    49  	cps []*core.CheckpointInfo
    50  }
    51  
    52  func (c *testCheckPoints) add(info *core.CheckpointInfo) {
    53  	c.mtx.Lock()
    54  	defer c.mtx.Unlock()
    55  
    56  	if len(c.cps) == 0 {
    57  		c.cps = []*core.CheckpointInfo{info}
    58  		return
    59  	}
    60  
    61  	// check for duplicates
    62  	for _, oldCps := range c.cps {
    63  		if reflect.DeepEqual(oldCps, info) {
    64  			return
    65  		}
    66  	}
    67  	c.cps = append(c.cps, info)
    68  }
    69  
    70  func (c *testCheckPoints) find(cp core.Checkpoint) bool {
    71  	c.mtx.RLock()
    72  	defer c.mtx.RUnlock()
    73  
    74  	for _, oldCps := range c.cps {
    75  		if oldCps.Checkpoint.Number == cp.Number && oldCps.Checkpoint.Hash == cp.Hash {
    76  			return true
    77  		}
    78  	}
    79  	return false
    80  }
    81  
    82  func TestCheckpointsService(t *testing.T) {
    83  	// log.Root().SetHandler(log.StdoutHandler)
    84  
    85  	// initialize tx Description Map
    86  	txDesc = txDescription{
    87  		descMap: make(map[common.Hash]string),
    88  	}
    89  
    90  	withErr := func(msg string, err error) {
    91  		if err != nil {
    92  			panic(fmt.Errorf("%v error: %v", msg, err))
    93  		}
    94  	}
    95  
    96  	delegatedPOS := []common.Address{
    97  		energi_params.Energi_MigrationContract,
    98  		params.EnergiTestnetChainConfig.Energi.CPPSigner,
    99  	}
   100  
   101  	nodesInfo = make([]nodeConfig, 0, totalNetworkNodes)
   102  	signers = make(map[common.Address]*ecdsa.PrivateKey, totalNetworkNodes)
   103  	mnAddrToOwners = make(map[common.Address]*ecdsa.PrivateKey, 2)
   104  	allocs := core.DefaultPrealloc()
   105  
   106  	// generate private keys for all nodes.
   107  	for index := 0; index < totalNetworkNodes; index++ {
   108  		key, accAddr := accountGen()
   109  		signers[accAddr] = key
   110  		allocs[accAddr] = core.GenesisAccount{Balance: balance}
   111  
   112  		var isMasternode bool
   113  		// select masternodes
   114  		switch index {
   115  		case 0, 1, 2, 3, 4: // accounts at indexes 0 to 4 are masternodes.
   116  			isMasternode = true
   117  
   118  			// Create the masternode owners and pre-assign them a balance.
   119  			mnOwnerKey, mnOwnerAddr := accountGen()
   120  			mnAddrToOwners[accAddr] = mnOwnerKey
   121  			allocs[mnOwnerAddr] = core.GenesisAccount{Balance: balance}
   122  
   123  		default: // rest of the account belong to enodes.
   124  			isMasternode = false
   125  		}
   126  
   127  		nodesInfo = append(nodesInfo, nodeConfig{
   128  			isMN:    isMasternode,
   129  			address: accAddr,
   130  		})
   131  	}
   132  
   133  	delPoSKeys := make([]*ecdsa.PrivateKey, 0, len(delegatedPOS))
   134  	delPoSAddr := make([]common.Address, 0, len(delegatedPOS))
   135  	// Map signer addresses to existing node private keys for signer accounts.
   136  	for _, addr := range delegatedPOS {
   137  		privKey, accAddr := accountGen()
   138  		allocs[accAddr] = core.GenesisAccount{Balance: balance}
   139  
   140  		delPoSAddr = append(delPoSAddr, accAddr)
   141  		delPoSKeys = append(delPoSKeys, privKey)
   142  
   143  		switch addr {
   144  		case energi_params.Energi_MigrationContract:
   145  			mgSigner = accAddr
   146  
   147  		case params.EnergiTestnetChainConfig.Energi.CPPSigner:
   148  			cpSigner = accAddr
   149  		}
   150  	}
   151  
   152  	for index := 0; index < totalNetworkNodes; index++ {
   153  		var err error
   154  		var node *node.Node
   155  		nConfig := nodesInfo[index]
   156  		key := signers[nConfig.address]
   157  
   158  		switch nConfig.isMN {
   159  		case true:
   160  			node, err = energiServices(key, allocs)
   161  
   162  		default: // rest of the account belong to enodes.
   163  			node, err = newNode(key, allocs)
   164  		}
   165  
   166  		msg := fmt.Sprintf("Creating node with Address: %v failed", nConfig.address.Hash().String())
   167  		withErr(msg, err)
   168  
   169  		// Now assign the node to the node config.
   170  		nodesInfo[index].stack = node
   171  	}
   172  
   173  	// Add the delegetedPoS Addresses to the signer map
   174  	for i, addr := range delPoSAddr {
   175  		signers[addr] = delPoSKeys[i]
   176  	}
   177  
   178  	// Add the masternode owners
   179  	for _, ownerKey := range mnAddrToOwners {
   180  		ownerAddr := crypto.PubkeyToAddress(ownerKey.PublicKey)
   181  		signers[ownerAddr] = ownerKey
   182  	}
   183  
   184  	migrations := energi_testutils.NewTestGen2Migration()
   185  	// Create a gen2 migration tempfile
   186  	err := migrations.PrepareTestGen2Migration(params.EnergiTestnetChainConfig.ChainID.Uint64())
   187  	withErr("Creating the Gen2 snapshot failed", err)
   188  
   189  	migrationFile = migrations.TempFileName()
   190  
   191  	injectAccount := func(store *keystore.KeyStore, privKey *ecdsa.PrivateKey) {
   192  		account, err := store.ImportECDSA(privKey, accountPass)
   193  		withErr("Failed to Inject new account", err)
   194  
   195  		// Unlock the account for staking
   196  		err = store.Unlock(account, accountPass, true)
   197  		withErr("Failed to Unlock new account for staking", err)
   198  	}
   199  
   200  	// Boot up the entire protocol while importing the accounts into respective nodes.
   201  	for _, data := range nodesInfo {
   202  		err = data.stack.Start()
   203  		withErr("Failed to start the protocol stack", err)
   204  
   205  		srv := data.stack.Server()
   206  		addr, _ := net.ResolveUDPAddr("udp", srv.ListenAddr)
   207  		conn, _ := net.ListenUDP("udp", addr)
   208  		realAdr := conn.LocalAddr().(*net.UDPAddr)
   209  		quit := make(chan struct{})
   210  		if !realAdr.IP.IsLoopback() && srv.NAT != nil {
   211  			go nat.Map(srv.NAT, quit, "udp", realAdr.Port, realAdr.Port, "ethereum discovery")
   212  		}
   213  
   214  		// trigger external IP Address to be set.
   215  		srv.NAT.ExternalIP()
   216  
   217  		var ethService *eth.Ethereum
   218  		data.stack.Service(&ethService)
   219  
   220  		store := data.stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   221  		// inject the main node personal account
   222  		injectAccount(store, signers[data.address])
   223  
   224  		// Add delegated POS accounts to every node.
   225  		for i, addr := range delPoSAddr {
   226  			injectAccount(store, signers[addr])
   227  
   228  			contractAddr := delegatedPOS[i]
   229  			ethService.AddDPoS(contractAddr, crypto.PubkeyToAddress(signers[addr].PublicKey))
   230  		}
   231  	}
   232  
   233  	listenToCheckpointsTest(t)
   234  
   235  	// Clean Up
   236  	migrations.CleanUp()
   237  
   238  	// Stop the entire protocol for all nodesInfo.
   239  	for _, data := range nodesInfo {
   240  		err = data.stack.Stop()
   241  		withErr("Failed to stop the protocol stack", err)
   242  	}
   243  }
   244  
   245  // networkEvents receives all new changes that are mdae to the network.
   246  func networkEvents(
   247  	quitCh chan struct{},
   248  	isSignedCPP chan struct{},
   249  	ethService *eth.Ethereum,
   250  	cpService *CheckpointService,
   251  ) {
   252  	bc := ethService.BlockChain()
   253  	txpool := ethService.TxPool()
   254  
   255  	chainHeadCh := make(chan core.ChainHeadEvent, chainHeadChanSize)
   256  	headSub := bc.SubscribeChainHeadEvent(chainHeadCh)
   257  	defer headSub.Unsubscribe()
   258  
   259  	txEventCh := make(chan core.NewTxsEvent, 10)
   260  	txSub := txpool.SubscribeNewTxsEvent(txEventCh)
   261  	defer txSub.Unsubscribe()
   262  
   263  	evt := cpService.eth.EventMux().Subscribe(CheckpointProposalEvent{})
   264  	defer evt.Unsubscribe()
   265  
   266  	//---
   267  	for {
   268  		select {
   269  		case <-quitCh:
   270  			return
   271  		case ev := <-chainHeadCh:
   272  			fmt.Println(" _____ New Block Mined _____")
   273  
   274  			for _, tx := range ev.Block.Transactions() {
   275  				fmt.Printf("\t BlockNo: %v, Tx Desc: %v, Tx Hash: %v, Nonce: %v, GasPrice: %v, Gas: %v, To Address: %v \n",
   276  					ev.Block.Number(), checkTxDesc(tx), tx.Hash().String(), tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To().Hash().String())
   277  			}
   278  		case txEvent := <-txEventCh:
   279  			for _, tx := range txEvent.Txs {
   280  				fmt.Printf("\t\t _____ (%s) Tx Announced  %v _____ \n", checkTxDesc(tx), tx.Hash().String())
   281  			}
   282  
   283  		case ev := <-evt.Chan():
   284  			if ev == nil {
   285  				return
   286  			}
   287  			switch ev.Data.(type) {
   288  			case CheckpointProposalEvent:
   289  				if sentCheckPoints.find(ev.Data.(CheckpointProposalEvent).Checkpoint) {
   290  					isSignedCPP <- struct{}{}
   291  				}
   292  			}
   293  
   294  			break
   295  
   296  		// Shutdown
   297  		case <-headSub.Err():
   298  			return
   299  		case <-txSub.Err():
   300  			return
   301  		}
   302  	}
   303  }
   304  
   305  func listenToCheckpointsTest(t *testing.T) {
   306  	miningTimeout := time.After(miningInterval)
   307  
   308  	// masternode mn node picked is at index 1.
   309  	mn := nodesInfo[mnIndex]
   310  	var mnEthService *eth.Ethereum
   311  	mn.stack.Service(&mnEthService)
   312  
   313  	var cpServ *CheckpointService
   314  	mn.stack.Service(&cpServ)
   315  
   316  	quitChan := make(chan struct{}, 1)
   317  	isCPPChan := make(chan struct{}, 1)
   318  	// Listen to the network events
   319  	go networkEvents(quitChan, isCPPChan, mnEthService, cpServ)
   320  
   321  	mnServer := mn.stack.Server()
   322  	peerCh := make(chan *p2p.PeerEvent)
   323  	peerSub := mnServer.SubscribeEvents(peerCh)
   324  	defer close(peerCh)
   325  	defer peerSub.Unsubscribe()
   326  
   327  	// EnableMsg Events.
   328  	mnServer.EnableMsgEvents = true
   329  
   330  	fmt.Println(" _______ ADDING PEERS _____")
   331  	var peers int
   332  	// Add all nodes as peers then start mining in each peer
   333  	for count, data := range nodesInfo {
   334  		if count == mnIndex {
   335  			// Do not add the main masternode as a peer to itself.
   336  			continue
   337  		}
   338  
   339  		mnServer.AddPeer(data.stack.Server().Self())
   340  
   341  		// This is a blocking operation that requires all nodes to be fully added
   342  		// as peers before further progress can be made.
   343  	peerConLoop:
   344  		for {
   345  			select {
   346  			case event := <-peerCh:
   347  				if event.Type == p2p.PeerEventTypeMsgRecv {
   348  					// Allow some delay for the peer to sync.
   349  					time.Sleep(peerSyncDelay)
   350  					break peerConLoop
   351  				}
   352  			case <-time.After(peerConInterval):
   353  				t.Fatal(errTimeout)
   354  				break peerConLoop
   355  			}
   356  		}
   357  
   358  		peers++
   359  	}
   360  
   361  	// On subscription, peerCh has to always be read when full to allow other txs
   362  	// to be announced.
   363  	go func() {
   364  	waitLoop:
   365  		for {
   366  			select {
   367  			case <-peerCh:
   368  			case <-quitChan:
   369  				break waitLoop
   370  			}
   371  		}
   372  	}()
   373  
   374  	// Confirm that all the peers were added to the network.
   375  	assert.Equal(t, peers, mnServer.PeerCount())
   376  
   377  	fmt.Println(" _______ START MINING _____")
   378  	// Add all nodes as peers then start mining in each peer
   379  	for _, data := range nodesInfo {
   380  		var ethService *eth.Ethereum
   381  		data.stack.Service(&ethService)
   382  
   383  		go func() {
   384  			err := ethService.StartMining(2)
   385  			assert.Equal(t, nil, err)
   386  			if err != nil {
   387  				return
   388  			}
   389  
   390  			// If shutting down, exit this goroutine.
   391  			for range quitChan {
   392  				return
   393  			}
   394  		}()
   395  	}
   396  
   397  	fmt.Println(" _______ ACTIVATE MASTERNODES _____")
   398  	err := mnPrepare(nodesInfo)
   399  	assert.Equal(t, nil, err)
   400  
   401  	// The cpp signer node proposes a checkpoint.
   402  	fmt.Println(" _______ PROPOSE CHECKPOINT-1 _____")
   403  	cpInfo, err := cpPropose()
   404  	sentCheckPoints.add(cpInfo)
   405  	assert.Equal(t, nil, err)
   406  
   407  	// Send more txs.
   408  	fmt.Println(" _______ SEND MORE TXS _____")
   409  	err = sendMoreTxs(mn.stack.Server().PrivateKey)
   410  	assert.Equal(t, nil, err)
   411  
   412  	cppsigner := nodesInfo[cpSignerIndex]
   413  	var ethServ *eth.Ethereum
   414  	cppsigner.stack.Service(&ethServ)
   415  
   416  	fmt.Println(" _______ CHECK TX POOL BEFORE WAITING _____")
   417  	{
   418  		// Tx pool according to the main masternode before test.
   419  		pending, queued := ethServ.TxPool().Content()
   420  		txPoolContents(pending, "(BEFORE) ___ CPP Signer Pending")
   421  		txPoolContents(queued, "(BEFORE) ____ CPP Signer queued")
   422  	}
   423  
   424  	{
   425  		// Tx pool according to the cpp signer node before test.
   426  		pending, queued := mnEthService.TxPool().Content()
   427  		txPoolContents(pending, "(BEFORE) ____ MN Pending")
   428  		txPoolContents(queued, "(BEFORE) ____ MN queued")
   429  	}
   430  
   431  	fmt.Println(" _______ PROPOSE CHECKPOINT-2 _____")
   432  	cpInfo, err = cpPropose()
   433  	sentCheckPoints.add(cpInfo)
   434  	assert.Equal(t, nil, err)
   435  
   436  	// Wait for a checkpoint signed by a masternode to be discovered or the max
   437  	// mining interval to expire.
   438  
   439  	select {
   440  	case <-isCPPChan:
   441  		// Test Passed
   442  		fmt.Println(" _______ A checkpoint event by the checkpoint service was found _____")
   443  
   444  	case <-miningTimeout:
   445  		// Test Failed
   446  		t.Fatalf(" _______ Checkpoint event NOT found: checkpoint service failed to send event on time _____")
   447  	}
   448  
   449  	// Now quit the listening of network events.
   450  	quitChan <- struct{}{}
   451  
   452  	fmt.Println(" _______ CHECK TX POOL AFTER WAITING _____")
   453  	{
   454  		// Tx pool according to the main masternode after test.
   455  		pending, queued := mnEthService.TxPool().Content()
   456  		txPoolContents(pending, "(AFTER) ____ MN Pending")
   457  		txPoolContents(queued, "(AFTER) ____ MN queued")
   458  	}
   459  
   460  	{
   461  		// Tx pool according to the cpp signer node after test.
   462  		pending, queued := ethServ.TxPool().Content()
   463  		txPoolContents(pending, "(AFTER) ____ CPP Signer Pending")
   464  		txPoolContents(queued, "(AFTER) ____ CPP Signer queued")
   465  	}
   466  
   467  	fmt.Println(" >>>>>>>> Checkpoint Service Test Complete <<<<<<<<<<")
   468  }