github.com/okex/exchain@v1.8.0/libs/tendermint/node/node_test.go (about)

     1  package node
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"os"
     8  	"syscall"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	dbm "github.com/okex/exchain/libs/tm-db"
    16  
    17  	"github.com/okex/exchain/libs/tendermint/abci/example/kvstore"
    18  	cfg "github.com/okex/exchain/libs/tendermint/config"
    19  	"github.com/okex/exchain/libs/tendermint/crypto/ed25519"
    20  	"github.com/okex/exchain/libs/tendermint/evidence"
    21  	"github.com/okex/exchain/libs/tendermint/libs/log"
    22  	tmrand "github.com/okex/exchain/libs/tendermint/libs/rand"
    23  	mempl "github.com/okex/exchain/libs/tendermint/mempool"
    24  	"github.com/okex/exchain/libs/tendermint/p2p"
    25  	p2pmock "github.com/okex/exchain/libs/tendermint/p2p/mock"
    26  	"github.com/okex/exchain/libs/tendermint/privval"
    27  	"github.com/okex/exchain/libs/tendermint/proxy"
    28  	sm "github.com/okex/exchain/libs/tendermint/state"
    29  	"github.com/okex/exchain/libs/tendermint/types"
    30  	tmtime "github.com/okex/exchain/libs/tendermint/types/time"
    31  	"github.com/okex/exchain/libs/tendermint/version"
    32  )
    33  
    34  func TestNodeStartStop(t *testing.T) {
    35  	config := cfg.ResetTestRoot("node_node_test")
    36  	defer os.RemoveAll(config.RootDir)
    37  
    38  	// create & start node
    39  	n, err := DefaultNewNode(config, log.TestingLogger())
    40  	require.NoError(t, err)
    41  	err = n.Start()
    42  	require.NoError(t, err)
    43  
    44  	t.Logf("Started node %v", n.sw.NodeInfo())
    45  
    46  	// wait for the node to produce a block
    47  	blocksSub, err := n.EventBus().Subscribe(context.Background(), "node_test", types.EventQueryNewBlock)
    48  	require.NoError(t, err)
    49  	select {
    50  	case <-blocksSub.Out():
    51  	case <-blocksSub.Cancelled():
    52  		t.Fatal("blocksSub was cancelled")
    53  	case <-time.After(10 * time.Second):
    54  		t.Fatal("timed out waiting for the node to produce a block")
    55  	}
    56  
    57  	// stop the node
    58  	go func() {
    59  		n.Stop()
    60  	}()
    61  
    62  	select {
    63  	case <-n.Quit():
    64  	case <-time.After(5 * time.Second):
    65  		pid := os.Getpid()
    66  		p, err := os.FindProcess(pid)
    67  		if err != nil {
    68  			panic(err)
    69  		}
    70  		err = p.Signal(syscall.SIGABRT)
    71  		fmt.Println(err)
    72  		t.Fatal("timed out waiting for shutdown")
    73  	}
    74  }
    75  
    76  func TestSplitAndTrimEmpty(t *testing.T) {
    77  	testCases := []struct {
    78  		s        string
    79  		sep      string
    80  		cutset   string
    81  		expected []string
    82  	}{
    83  		{"a,b,c", ",", " ", []string{"a", "b", "c"}},
    84  		{" a , b , c ", ",", " ", []string{"a", "b", "c"}},
    85  		{" a, b, c ", ",", " ", []string{"a", "b", "c"}},
    86  		{" a, ", ",", " ", []string{"a"}},
    87  		{"   ", ",", " ", []string{}},
    88  	}
    89  
    90  	for _, tc := range testCases {
    91  		assert.Equal(t, tc.expected, splitAndTrimEmpty(tc.s, tc.sep, tc.cutset), "%s", tc.s)
    92  	}
    93  }
    94  
    95  func TestNodeDelayedStart(t *testing.T) {
    96  	config := cfg.ResetTestRoot("node_delayed_start_test")
    97  	defer os.RemoveAll(config.RootDir)
    98  	now := tmtime.Now()
    99  
   100  	config.Instrumentation.Prometheus = false
   101  	// create & start node
   102  	n, err := DefaultNewNode(config, log.TestingLogger())
   103  	n.GenesisDoc().GenesisTime = now.Add(2 * time.Second)
   104  	require.NoError(t, err)
   105  
   106  	err = n.Start()
   107  	require.NoError(t, err)
   108  	defer n.Stop()
   109  
   110  	startTime := tmtime.Now()
   111  	assert.Equal(t, true, startTime.After(n.GenesisDoc().GenesisTime))
   112  }
   113  
   114  func TestNodeSetAppVersion(t *testing.T) {
   115  	config := cfg.ResetTestRoot("node_app_version_test")
   116  	defer os.RemoveAll(config.RootDir)
   117  
   118  	config.Instrumentation.Prometheus = false
   119  	// create & start node
   120  	n, err := DefaultNewNode(config, log.TestingLogger())
   121  	require.NoError(t, err)
   122  
   123  	// default config uses the kvstore app
   124  	var appVersion version.Protocol = kvstore.ProtocolVersion
   125  
   126  	// check version is set in state
   127  	state := sm.LoadState(n.stateDB)
   128  	assert.Equal(t, state.Version.Consensus.App, appVersion)
   129  
   130  	// check version is set in node info
   131  	assert.Equal(t, n.nodeInfo.(p2p.DefaultNodeInfo).ProtocolVersion.App, appVersion)
   132  }
   133  
   134  func TestNodeSetPrivValTCP(t *testing.T) {
   135  	addr := "tcp://" + testFreeAddr(t)
   136  
   137  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   138  	defer os.RemoveAll(config.RootDir)
   139  	config.BaseConfig.PrivValidatorListenAddr = addr
   140  
   141  	dialer := privval.DialTCPFn(addr, 100*time.Millisecond, ed25519.GenPrivKey())
   142  	dialerEndpoint := privval.NewSignerDialerEndpoint(
   143  		log.TestingLogger(),
   144  		dialer,
   145  	)
   146  	privval.SignerDialerEndpointTimeoutReadWrite(100 * time.Millisecond)(dialerEndpoint)
   147  
   148  	signerServer := privval.NewSignerServer(
   149  		dialerEndpoint,
   150  		config.ChainID(),
   151  		types.NewMockPV(),
   152  	)
   153  
   154  	go func() {
   155  		err := signerServer.Start()
   156  		if err != nil {
   157  			panic(err)
   158  		}
   159  	}()
   160  	defer signerServer.Stop()
   161  
   162  	config.Instrumentation.Prometheus = false
   163  	n, err := DefaultNewNode(config, log.TestingLogger())
   164  	require.NoError(t, err)
   165  	assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
   166  }
   167  
   168  // address without a protocol must result in error
   169  func TestPrivValidatorListenAddrNoProtocol(t *testing.T) {
   170  	addrNoPrefix := testFreeAddr(t)
   171  
   172  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   173  	defer os.RemoveAll(config.RootDir)
   174  	config.BaseConfig.PrivValidatorListenAddr = addrNoPrefix
   175  
   176  	_, err := DefaultNewNode(config, log.TestingLogger())
   177  	assert.Error(t, err)
   178  }
   179  
   180  func TestNodeSetPrivValIPC(t *testing.T) {
   181  	tmpfile := "/tmp/kms." + tmrand.Str(6) + ".sock"
   182  	defer os.Remove(tmpfile) // clean up
   183  
   184  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   185  	defer os.RemoveAll(config.RootDir)
   186  	config.BaseConfig.PrivValidatorListenAddr = "unix://" + tmpfile
   187  
   188  	dialer := privval.DialUnixFn(tmpfile)
   189  	dialerEndpoint := privval.NewSignerDialerEndpoint(
   190  		log.TestingLogger(),
   191  		dialer,
   192  	)
   193  	privval.SignerDialerEndpointTimeoutReadWrite(100 * time.Millisecond)(dialerEndpoint)
   194  
   195  	pvsc := privval.NewSignerServer(
   196  		dialerEndpoint,
   197  		config.ChainID(),
   198  		types.NewMockPV(),
   199  	)
   200  
   201  	go func() {
   202  		err := pvsc.Start()
   203  		require.NoError(t, err)
   204  	}()
   205  	defer pvsc.Stop()
   206  
   207  	config.Instrumentation.Prometheus = false
   208  	n, err := DefaultNewNode(config, log.TestingLogger())
   209  	require.NoError(t, err)
   210  	assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
   211  }
   212  
   213  // testFreeAddr claims a free port so we don't block on listener being ready.
   214  func testFreeAddr(t *testing.T) string {
   215  	ln, err := net.Listen("tcp", "127.0.0.1:0")
   216  	require.NoError(t, err)
   217  	defer ln.Close()
   218  
   219  	return fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.TCPAddr).Port)
   220  }
   221  
   222  // create a proposal block using real and full
   223  // mempool and evidence pool and validate it.
   224  func TestCreateProposalBlock(t *testing.T) {
   225  	config := cfg.ResetTestRoot("node_create_proposal")
   226  	defer os.RemoveAll(config.RootDir)
   227  	config.Instrumentation.Prometheus = false
   228  	cc := proxy.NewLocalClientCreator(kvstore.NewApplication())
   229  	proxyApp := proxy.NewAppConns(cc)
   230  	err := proxyApp.Start()
   231  	require.Nil(t, err)
   232  	defer proxyApp.Stop()
   233  
   234  	logger := log.TestingLogger()
   235  
   236  	var height int64 = 1
   237  	state, stateDB := state(1, height)
   238  	maxBytes := 16384
   239  	state.ConsensusParams.Block.MaxBytes = int64(maxBytes)
   240  	proposerAddr, _ := state.Validators.GetByIndex(0)
   241  
   242  	// Make Mempool
   243  	memplMetrics := mempl.PrometheusMetrics("node_test")
   244  	mempool := mempl.NewCListMempool(
   245  		config.Mempool,
   246  		proxyApp.Mempool(),
   247  		state.LastBlockHeight,
   248  		mempl.WithMetrics(memplMetrics),
   249  		mempl.WithPreCheck(sm.TxPreCheck(state)),
   250  		mempl.WithPostCheck(sm.TxPostCheck(state)),
   251  	)
   252  	mempool.SetLogger(logger)
   253  
   254  	// Make EvidencePool
   255  	types.RegisterMockEvidencesGlobal() // XXX!
   256  	evidence.RegisterMockEvidences()
   257  	evidenceDB := dbm.NewMemDB()
   258  	evidencePool := evidence.NewPool(stateDB, evidenceDB)
   259  	evidencePool.SetLogger(logger)
   260  
   261  	// fill the evidence pool with more evidence
   262  	// than can fit in a block
   263  	minEvSize := 12
   264  	numEv := (maxBytes / types.MaxEvidenceBytesDenominator) / minEvSize
   265  	for i := 0; i < numEv; i++ {
   266  		ev := types.NewMockRandomEvidence(1, time.Now(), proposerAddr, tmrand.Bytes(minEvSize))
   267  		err := evidencePool.AddEvidence(ev)
   268  		assert.NoError(t, err)
   269  	}
   270  
   271  	// fill the mempool with more txs
   272  	// than can fit in a block
   273  	txLength := 1000
   274  	for i := 0; i < maxBytes/txLength; i++ {
   275  		tx := tmrand.Bytes(txLength)
   276  		err := mempool.CheckTx(tx, nil, mempl.TxInfo{})
   277  		assert.NoError(t, err)
   278  	}
   279  
   280  	blockExec := sm.NewBlockExecutor(
   281  		stateDB,
   282  		logger,
   283  		proxyApp.Consensus(),
   284  		mempool,
   285  		evidencePool,
   286  	)
   287  
   288  	commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
   289  	block, _ := blockExec.CreateProposalBlock(
   290  		height,
   291  		state, commit,
   292  		proposerAddr,
   293  	)
   294  
   295  	err = blockExec.ValidateBlock(state, block)
   296  	assert.NoError(t, err)
   297  }
   298  
   299  func TestNodeNewNodeCustomReactors(t *testing.T) {
   300  	config := cfg.ResetTestRoot("node_new_node_custom_reactors_test")
   301  	defer os.RemoveAll(config.RootDir)
   302  	config.Instrumentation.Prometheus = false
   303  
   304  	cr := p2pmock.NewReactor()
   305  	customBlockchainReactor := p2pmock.NewReactor()
   306  
   307  	nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
   308  	require.NoError(t, err)
   309  
   310  	n, err := NewNode(config,
   311  		privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()),
   312  		nodeKey,
   313  		proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
   314  		DefaultGenesisDocProviderFunc(config),
   315  		DefaultDBProvider,
   316  		DefaultMetricsProvider(config.Instrumentation),
   317  		log.TestingLogger(),
   318  		CustomReactors(map[string]p2p.Reactor{"FOO": cr, "BLOCKCHAIN": customBlockchainReactor}),
   319  	)
   320  	require.NoError(t, err)
   321  
   322  	err = n.Start()
   323  	require.NoError(t, err)
   324  	defer n.Stop()
   325  
   326  	assert.True(t, cr.IsRunning())
   327  	assert.Equal(t, cr, n.Switch().Reactor("FOO"))
   328  
   329  	assert.True(t, customBlockchainReactor.IsRunning())
   330  	assert.Equal(t, customBlockchainReactor, n.Switch().Reactor("BLOCKCHAIN"))
   331  }
   332  
   333  func state(nVals int, height int64) (sm.State, dbm.DB) {
   334  	vals := make([]types.GenesisValidator, nVals)
   335  	for i := 0; i < nVals; i++ {
   336  		secret := []byte(fmt.Sprintf("test%d", i))
   337  		pk := ed25519.GenPrivKeyFromSecret(secret)
   338  		vals[i] = types.GenesisValidator{
   339  			Address: pk.PubKey().Address(),
   340  			PubKey:  pk.PubKey(),
   341  			Power:   1000,
   342  			Name:    fmt.Sprintf("test%d", i),
   343  		}
   344  	}
   345  	s, _ := sm.MakeGenesisState(&types.GenesisDoc{
   346  		ChainID:    "test-chain",
   347  		Validators: vals,
   348  		AppHash:    nil,
   349  	})
   350  
   351  	// save validators to db for 2 heights
   352  	stateDB := dbm.NewMemDB()
   353  	sm.SaveState(stateDB, s)
   354  
   355  	for i := 1; i < int(height); i++ {
   356  		s.LastBlockHeight++
   357  		s.LastValidators = s.Validators.Copy()
   358  		sm.SaveState(stateDB, s)
   359  	}
   360  	return s, stateDB
   361  }