github.com/516108736/tendermint@v0.36.0/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/tendermint/tm-db"
    16  
    17  	"github.com/tendermint/tendermint/abci/example/kvstore"
    18  	cfg "github.com/tendermint/tendermint/config"
    19  	"github.com/tendermint/tendermint/crypto/ed25519"
    20  	"github.com/tendermint/tendermint/evidence"
    21  	"github.com/tendermint/tendermint/libs/log"
    22  	tmrand "github.com/tendermint/tendermint/libs/rand"
    23  	mempl "github.com/tendermint/tendermint/mempool"
    24  	"github.com/tendermint/tendermint/p2p"
    25  	p2pmock "github.com/tendermint/tendermint/p2p/mock"
    26  	"github.com/tendermint/tendermint/privval"
    27  	"github.com/tendermint/tendermint/proxy"
    28  	sm "github.com/tendermint/tendermint/state"
    29  	"github.com/tendermint/tendermint/store"
    30  	"github.com/tendermint/tendermint/types"
    31  	tmtime "github.com/tendermint/tendermint/types/time"
    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  		err = n.Stop()
    60  		require.NoError(t, err)
    61  	}()
    62  
    63  	select {
    64  	case <-n.Quit():
    65  	case <-time.After(5 * time.Second):
    66  		pid := os.Getpid()
    67  		p, err := os.FindProcess(pid)
    68  		if err != nil {
    69  			panic(err)
    70  		}
    71  		err = p.Signal(syscall.SIGABRT)
    72  		fmt.Println(err)
    73  		t.Fatal("timed out waiting for shutdown")
    74  	}
    75  }
    76  
    77  func TestSplitAndTrimEmpty(t *testing.T) {
    78  	testCases := []struct {
    79  		s        string
    80  		sep      string
    81  		cutset   string
    82  		expected []string
    83  	}{
    84  		{"a,b,c", ",", " ", []string{"a", "b", "c"}},
    85  		{" a , b , c ", ",", " ", []string{"a", "b", "c"}},
    86  		{" a, b, c ", ",", " ", []string{"a", "b", "c"}},
    87  		{" a, ", ",", " ", []string{"a"}},
    88  		{"   ", ",", " ", []string{}},
    89  	}
    90  
    91  	for _, tc := range testCases {
    92  		assert.Equal(t, tc.expected, splitAndTrimEmpty(tc.s, tc.sep, tc.cutset), "%s", tc.s)
    93  	}
    94  }
    95  
    96  func TestNodeDelayedStart(t *testing.T) {
    97  	config := cfg.ResetTestRoot("node_delayed_start_test")
    98  	defer os.RemoveAll(config.RootDir)
    99  	now := tmtime.Now()
   100  
   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() //nolint:errcheck // ignore for tests
   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  	// create & start node
   119  	n, err := DefaultNewNode(config, log.TestingLogger())
   120  	require.NoError(t, err)
   121  
   122  	// default config uses the kvstore app
   123  	var appVersion uint64 = kvstore.ProtocolVersion
   124  
   125  	// check version is set in state
   126  	state, err := n.stateStore.Load()
   127  	require.NoError(t, err)
   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() //nolint:errcheck // ignore for tests
   161  
   162  	n, err := DefaultNewNode(config, log.TestingLogger())
   163  	require.NoError(t, err)
   164  	assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
   165  }
   166  
   167  // address without a protocol must result in error
   168  func TestPrivValidatorListenAddrNoProtocol(t *testing.T) {
   169  	addrNoPrefix := testFreeAddr(t)
   170  
   171  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   172  	defer os.RemoveAll(config.RootDir)
   173  	config.BaseConfig.PrivValidatorListenAddr = addrNoPrefix
   174  
   175  	_, err := DefaultNewNode(config, log.TestingLogger())
   176  	assert.Error(t, err)
   177  }
   178  
   179  func TestNodeSetPrivValIPC(t *testing.T) {
   180  	tmpfile := "/tmp/kms." + tmrand.Str(6) + ".sock"
   181  	defer os.Remove(tmpfile) // clean up
   182  
   183  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   184  	defer os.RemoveAll(config.RootDir)
   185  	config.BaseConfig.PrivValidatorListenAddr = "unix://" + tmpfile
   186  
   187  	dialer := privval.DialUnixFn(tmpfile)
   188  	dialerEndpoint := privval.NewSignerDialerEndpoint(
   189  		log.TestingLogger(),
   190  		dialer,
   191  	)
   192  	privval.SignerDialerEndpointTimeoutReadWrite(100 * time.Millisecond)(dialerEndpoint)
   193  
   194  	pvsc := privval.NewSignerServer(
   195  		dialerEndpoint,
   196  		config.ChainID(),
   197  		types.NewMockPV(),
   198  	)
   199  
   200  	go func() {
   201  		err := pvsc.Start()
   202  		require.NoError(t, err)
   203  	}()
   204  	defer pvsc.Stop() //nolint:errcheck // ignore for tests
   205  
   206  	n, err := DefaultNewNode(config, log.TestingLogger())
   207  	require.NoError(t, err)
   208  	assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
   209  }
   210  
   211  // testFreeAddr claims a free port so we don't block on listener being ready.
   212  func testFreeAddr(t *testing.T) string {
   213  	ln, err := net.Listen("tcp", "127.0.0.1:0")
   214  	require.NoError(t, err)
   215  	defer ln.Close()
   216  
   217  	return fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.TCPAddr).Port)
   218  }
   219  
   220  // create a proposal block using real and full
   221  // mempool and evidence pool and validate it.
   222  func TestCreateProposalBlock(t *testing.T) {
   223  	config := cfg.ResetTestRoot("node_create_proposal")
   224  	defer os.RemoveAll(config.RootDir)
   225  	cc := proxy.NewLocalClientCreator(kvstore.NewApplication())
   226  	proxyApp := proxy.NewAppConns(cc)
   227  	err := proxyApp.Start()
   228  	require.Nil(t, err)
   229  	defer proxyApp.Stop() //nolint:errcheck // ignore for tests
   230  
   231  	logger := log.TestingLogger()
   232  
   233  	var height int64 = 1
   234  	state, stateDB, privVals := state(1, height)
   235  	stateStore := sm.NewStore(stateDB)
   236  	maxBytes := 16384
   237  	var partSize uint32 = 256
   238  	maxEvidenceBytes := int64(maxBytes / 2)
   239  	state.ConsensusParams.Block.MaxBytes = int64(maxBytes)
   240  	state.ConsensusParams.Evidence.MaxBytes = maxEvidenceBytes
   241  	proposerAddr, _ := state.Validators.GetByIndex(0)
   242  
   243  	// Make Mempool
   244  	memplMetrics := mempl.PrometheusMetrics("node_test_1")
   245  	mempool := mempl.NewCListMempool(
   246  		config.Mempool,
   247  		proxyApp.Mempool(),
   248  		state.LastBlockHeight,
   249  		mempl.WithMetrics(memplMetrics),
   250  		mempl.WithPreCheck(sm.TxPreCheck(state)),
   251  		mempl.WithPostCheck(sm.TxPostCheck(state)),
   252  	)
   253  	mempool.SetLogger(logger)
   254  
   255  	// Make EvidencePool
   256  	evidenceDB := dbm.NewMemDB()
   257  	blockStore := store.NewBlockStore(dbm.NewMemDB())
   258  	evidencePool, err := evidence.NewPool(evidenceDB, stateStore, blockStore)
   259  	require.NoError(t, err)
   260  	evidencePool.SetLogger(logger)
   261  
   262  	// fill the evidence pool with more evidence
   263  	// than can fit in a block
   264  	var currentBytes int64 = 0
   265  	for currentBytes <= maxEvidenceBytes {
   266  		ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(), privVals[0], "test-chain")
   267  		currentBytes += int64(len(ev.Bytes()))
   268  		evidencePool.ReportConflictingVotes(ev.VoteA, ev.VoteB)
   269  	}
   270  
   271  	evList, size := evidencePool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
   272  	require.Less(t, size, state.ConsensusParams.Evidence.MaxBytes+1)
   273  	evData := &types.EvidenceData{Evidence: evList}
   274  	require.EqualValues(t, size, evData.ByteSize())
   275  
   276  	// fill the mempool with more txs
   277  	// than can fit in a block
   278  	txLength := 100
   279  	for i := 0; i <= maxBytes/txLength; i++ {
   280  		tx := tmrand.Bytes(txLength)
   281  		err := mempool.CheckTx(tx, nil, mempl.TxInfo{})
   282  		assert.NoError(t, err)
   283  	}
   284  
   285  	blockExec := sm.NewBlockExecutor(
   286  		stateStore,
   287  		logger,
   288  		proxyApp.Consensus(),
   289  		mempool,
   290  		evidencePool,
   291  	)
   292  
   293  	commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
   294  	block, _ := blockExec.CreateProposalBlock(
   295  		height,
   296  		state, commit,
   297  		proposerAddr,
   298  	)
   299  
   300  	// check that the part set does not exceed the maximum block size
   301  	partSet := block.MakePartSet(partSize)
   302  	assert.Less(t, partSet.ByteSize(), int64(maxBytes))
   303  
   304  	partSetFromHeader := types.NewPartSetFromHeader(partSet.Header())
   305  	for partSetFromHeader.Count() < partSetFromHeader.Total() {
   306  		added, err := partSetFromHeader.AddPart(partSet.GetPart(int(partSetFromHeader.Count())))
   307  		require.NoError(t, err)
   308  		require.True(t, added)
   309  	}
   310  	assert.EqualValues(t, partSetFromHeader.ByteSize(), partSet.ByteSize())
   311  
   312  	err = blockExec.ValidateBlock(state, block)
   313  	assert.NoError(t, err)
   314  }
   315  
   316  func TestMaxProposalBlockSize(t *testing.T) {
   317  	config := cfg.ResetTestRoot("node_create_proposal")
   318  	defer os.RemoveAll(config.RootDir)
   319  	cc := proxy.NewLocalClientCreator(kvstore.NewApplication())
   320  	proxyApp := proxy.NewAppConns(cc)
   321  	err := proxyApp.Start()
   322  	require.Nil(t, err)
   323  	defer proxyApp.Stop() //nolint:errcheck // ignore for tests
   324  
   325  	logger := log.TestingLogger()
   326  
   327  	var height int64 = 1
   328  	state, stateDB, _ := state(1, height)
   329  	stateStore := sm.NewStore(stateDB)
   330  	var maxBytes int64 = 16384
   331  	var partSize uint32 = 256
   332  	state.ConsensusParams.Block.MaxBytes = maxBytes
   333  	proposerAddr, _ := state.Validators.GetByIndex(0)
   334  
   335  	// Make Mempool
   336  	memplMetrics := mempl.PrometheusMetrics("node_test_2")
   337  	mempool := mempl.NewCListMempool(
   338  		config.Mempool,
   339  		proxyApp.Mempool(),
   340  		state.LastBlockHeight,
   341  		mempl.WithMetrics(memplMetrics),
   342  		mempl.WithPreCheck(sm.TxPreCheck(state)),
   343  		mempl.WithPostCheck(sm.TxPostCheck(state)),
   344  	)
   345  	mempool.SetLogger(logger)
   346  
   347  	// fill the mempool with one txs just below the maximum size
   348  	txLength := int(types.MaxDataBytesNoEvidence(maxBytes, 1))
   349  	tx := tmrand.Bytes(txLength - 4) // to account for the varint
   350  	err = mempool.CheckTx(tx, nil, mempl.TxInfo{})
   351  	assert.NoError(t, err)
   352  
   353  	blockExec := sm.NewBlockExecutor(
   354  		stateStore,
   355  		logger,
   356  		proxyApp.Consensus(),
   357  		mempool,
   358  		sm.EmptyEvidencePool{},
   359  	)
   360  
   361  	commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
   362  	block, _ := blockExec.CreateProposalBlock(
   363  		height,
   364  		state, commit,
   365  		proposerAddr,
   366  	)
   367  
   368  	pb, err := block.ToProto()
   369  	require.NoError(t, err)
   370  	assert.Less(t, int64(pb.Size()), maxBytes)
   371  
   372  	// check that the part set does not exceed the maximum block size
   373  	partSet := block.MakePartSet(partSize)
   374  	assert.EqualValues(t, partSet.ByteSize(), int64(pb.Size()))
   375  }
   376  
   377  func TestNodeNewNodeCustomReactors(t *testing.T) {
   378  	config := cfg.ResetTestRoot("node_new_node_custom_reactors_test")
   379  	defer os.RemoveAll(config.RootDir)
   380  
   381  	cr := p2pmock.NewReactor()
   382  	customBlockchainReactor := p2pmock.NewReactor()
   383  
   384  	nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
   385  	require.NoError(t, err)
   386  
   387  	n, err := NewNode(config,
   388  		privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()),
   389  		nodeKey,
   390  		proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
   391  		DefaultGenesisDocProviderFunc(config),
   392  		DefaultDBProvider,
   393  		DefaultMetricsProvider(config.Instrumentation),
   394  		log.TestingLogger(),
   395  		CustomReactors(map[string]p2p.Reactor{"FOO": cr, "BLOCKCHAIN": customBlockchainReactor}),
   396  	)
   397  	require.NoError(t, err)
   398  
   399  	err = n.Start()
   400  	require.NoError(t, err)
   401  	defer n.Stop() //nolint:errcheck // ignore for tests
   402  
   403  	assert.True(t, cr.IsRunning())
   404  	assert.Equal(t, cr, n.Switch().Reactor("FOO"))
   405  
   406  	assert.True(t, customBlockchainReactor.IsRunning())
   407  	assert.Equal(t, customBlockchainReactor, n.Switch().Reactor("BLOCKCHAIN"))
   408  }
   409  
   410  func state(nVals int, height int64) (sm.State, dbm.DB, []types.PrivValidator) {
   411  	privVals := make([]types.PrivValidator, nVals)
   412  	vals := make([]types.GenesisValidator, nVals)
   413  	for i := 0; i < nVals; i++ {
   414  		privVal := types.NewMockPV()
   415  		privVals[i] = privVal
   416  		vals[i] = types.GenesisValidator{
   417  			Address: privVal.PrivKey.PubKey().Address(),
   418  			PubKey:  privVal.PrivKey.PubKey(),
   419  			Power:   1000,
   420  			Name:    fmt.Sprintf("test%d", i),
   421  		}
   422  	}
   423  	s, _ := sm.MakeGenesisState(&types.GenesisDoc{
   424  		ChainID:    "test-chain",
   425  		Validators: vals,
   426  		AppHash:    nil,
   427  	})
   428  
   429  	// save validators to db for 2 heights
   430  	stateDB := dbm.NewMemDB()
   431  	stateStore := sm.NewStore(stateDB)
   432  	if err := stateStore.Save(s); err != nil {
   433  		panic(err)
   434  	}
   435  
   436  	for i := 1; i < int(height); i++ {
   437  		s.LastBlockHeight++
   438  		s.LastValidators = s.Validators.Copy()
   439  		if err := stateStore.Save(s); err != nil {
   440  			panic(err)
   441  		}
   442  	}
   443  	return s, stateDB, privVals
   444  }