github.com/vipernet-xyz/tm@v0.34.24/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/vipernet-xyz/tm/abci/example/kvstore"
    18  	cfg "github.com/vipernet-xyz/tm/config"
    19  	"github.com/vipernet-xyz/tm/crypto/ed25519"
    20  	"github.com/vipernet-xyz/tm/evidence"
    21  	"github.com/vipernet-xyz/tm/libs/log"
    22  	tmrand "github.com/vipernet-xyz/tm/libs/rand"
    23  	mempl "github.com/vipernet-xyz/tm/mempool"
    24  	mempoolv0 "github.com/vipernet-xyz/tm/mempool/v0"
    25  	mempoolv1 "github.com/vipernet-xyz/tm/mempool/v1"
    26  	"github.com/vipernet-xyz/tm/p2p"
    27  	"github.com/vipernet-xyz/tm/p2p/conn"
    28  	p2pmock "github.com/vipernet-xyz/tm/p2p/mock"
    29  	"github.com/vipernet-xyz/tm/privval"
    30  	"github.com/vipernet-xyz/tm/proxy"
    31  	sm "github.com/vipernet-xyz/tm/state"
    32  	"github.com/vipernet-xyz/tm/store"
    33  	"github.com/vipernet-xyz/tm/types"
    34  	tmtime "github.com/vipernet-xyz/tm/types/time"
    35  )
    36  
    37  func TestNodeStartStop(t *testing.T) {
    38  	config := cfg.ResetTestRoot("node_node_test")
    39  	defer os.RemoveAll(config.RootDir)
    40  
    41  	// create & start node
    42  	n, err := DefaultNewNode(config, log.TestingLogger())
    43  	require.NoError(t, err)
    44  	err = n.Start()
    45  	require.NoError(t, err)
    46  
    47  	t.Logf("Started node %v", n.sw.NodeInfo())
    48  
    49  	// wait for the node to produce a block
    50  	blocksSub, err := n.EventBus().Subscribe(context.Background(), "node_test", types.EventQueryNewBlock)
    51  	require.NoError(t, err)
    52  	select {
    53  	case <-blocksSub.Out():
    54  	case <-blocksSub.Cancelled():
    55  		t.Fatal("blocksSub was cancelled")
    56  	case <-time.After(10 * time.Second):
    57  		t.Fatal("timed out waiting for the node to produce a block")
    58  	}
    59  
    60  	// stop the node
    61  	go func() {
    62  		err = n.Stop()
    63  		require.NoError(t, err)
    64  	}()
    65  
    66  	select {
    67  	case <-n.Quit():
    68  	case <-time.After(5 * time.Second):
    69  		pid := os.Getpid()
    70  		p, err := os.FindProcess(pid)
    71  		if err != nil {
    72  			panic(err)
    73  		}
    74  		err = p.Signal(syscall.SIGABRT)
    75  		fmt.Println(err)
    76  		t.Fatal("timed out waiting for shutdown")
    77  	}
    78  }
    79  
    80  func TestSplitAndTrimEmpty(t *testing.T) {
    81  	testCases := []struct {
    82  		s        string
    83  		sep      string
    84  		cutset   string
    85  		expected []string
    86  	}{
    87  		{"a,b,c", ",", " ", []string{"a", "b", "c"}},
    88  		{" a , b , c ", ",", " ", []string{"a", "b", "c"}},
    89  		{" a, b, c ", ",", " ", []string{"a", "b", "c"}},
    90  		{" a, ", ",", " ", []string{"a"}},
    91  		{"   ", ",", " ", []string{}},
    92  	}
    93  
    94  	for _, tc := range testCases {
    95  		assert.Equal(t, tc.expected, splitAndTrimEmpty(tc.s, tc.sep, tc.cutset), "%s", tc.s)
    96  	}
    97  }
    98  
    99  func TestNodeDelayedStart(t *testing.T) {
   100  	config := cfg.ResetTestRoot("node_delayed_start_test")
   101  	defer os.RemoveAll(config.RootDir)
   102  	now := tmtime.Now()
   103  
   104  	// create & start node
   105  	n, err := DefaultNewNode(config, log.TestingLogger())
   106  	n.GenesisDoc().GenesisTime = now.Add(2 * time.Second)
   107  	require.NoError(t, err)
   108  
   109  	err = n.Start()
   110  	require.NoError(t, err)
   111  	defer n.Stop() //nolint:errcheck // ignore for tests
   112  
   113  	startTime := tmtime.Now()
   114  	assert.Equal(t, true, startTime.After(n.GenesisDoc().GenesisTime))
   115  }
   116  
   117  func TestNodeSetAppVersion(t *testing.T) {
   118  	config := cfg.ResetTestRoot("node_app_version_test")
   119  	defer os.RemoveAll(config.RootDir)
   120  
   121  	// create & start node
   122  	n, err := DefaultNewNode(config, log.TestingLogger())
   123  	require.NoError(t, err)
   124  
   125  	// default config uses the kvstore app
   126  	var appVersion uint64 = kvstore.ProtocolVersion
   127  
   128  	// check version is set in state
   129  	state, err := n.stateStore.Load()
   130  	require.NoError(t, err)
   131  	assert.Equal(t, state.Version.Consensus.App, appVersion)
   132  
   133  	// check version is set in node info
   134  	assert.Equal(t, n.nodeInfo.(p2p.DefaultNodeInfo).ProtocolVersion.App, appVersion)
   135  }
   136  
   137  func TestNodeSetPrivValTCP(t *testing.T) {
   138  	addr := "tcp://" + testFreeAddr(t)
   139  
   140  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   141  	defer os.RemoveAll(config.RootDir)
   142  	config.BaseConfig.PrivValidatorListenAddr = addr
   143  
   144  	dialer := privval.DialTCPFn(addr, 100*time.Millisecond, ed25519.GenPrivKey())
   145  	dialerEndpoint := privval.NewSignerDialerEndpoint(
   146  		log.TestingLogger(),
   147  		dialer,
   148  	)
   149  	privval.SignerDialerEndpointTimeoutReadWrite(100 * time.Millisecond)(dialerEndpoint)
   150  
   151  	signerServer := privval.NewSignerServer(
   152  		dialerEndpoint,
   153  		config.ChainID(),
   154  		types.NewMockPV(),
   155  	)
   156  
   157  	go func() {
   158  		err := signerServer.Start()
   159  		if err != nil {
   160  			panic(err)
   161  		}
   162  	}()
   163  	defer signerServer.Stop() //nolint:errcheck // ignore for tests
   164  
   165  	n, err := DefaultNewNode(config, log.TestingLogger())
   166  	require.NoError(t, err)
   167  	assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
   168  }
   169  
   170  // address without a protocol must result in error
   171  func TestPrivValidatorListenAddrNoProtocol(t *testing.T) {
   172  	addrNoPrefix := testFreeAddr(t)
   173  
   174  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   175  	defer os.RemoveAll(config.RootDir)
   176  	config.BaseConfig.PrivValidatorListenAddr = addrNoPrefix
   177  
   178  	_, err := DefaultNewNode(config, log.TestingLogger())
   179  	assert.Error(t, err)
   180  }
   181  
   182  func TestNodeSetPrivValIPC(t *testing.T) {
   183  	tmpfile := "/tmp/kms." + tmrand.Str(6) + ".sock"
   184  	defer os.Remove(tmpfile) // clean up
   185  
   186  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   187  	defer os.RemoveAll(config.RootDir)
   188  	config.BaseConfig.PrivValidatorListenAddr = "unix://" + tmpfile
   189  
   190  	dialer := privval.DialUnixFn(tmpfile)
   191  	dialerEndpoint := privval.NewSignerDialerEndpoint(
   192  		log.TestingLogger(),
   193  		dialer,
   194  	)
   195  	privval.SignerDialerEndpointTimeoutReadWrite(100 * time.Millisecond)(dialerEndpoint)
   196  
   197  	pvsc := privval.NewSignerServer(
   198  		dialerEndpoint,
   199  		config.ChainID(),
   200  		types.NewMockPV(),
   201  	)
   202  
   203  	go func() {
   204  		err := pvsc.Start()
   205  		require.NoError(t, err)
   206  	}()
   207  	defer pvsc.Stop() //nolint:errcheck // ignore for tests
   208  
   209  	n, err := DefaultNewNode(config, log.TestingLogger())
   210  	require.NoError(t, err)
   211  	assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
   212  }
   213  
   214  // testFreeAddr claims a free port so we don't block on listener being ready.
   215  func testFreeAddr(t *testing.T) string {
   216  	ln, err := net.Listen("tcp", "127.0.0.1:0")
   217  	require.NoError(t, err)
   218  	defer ln.Close()
   219  
   220  	return fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.TCPAddr).Port)
   221  }
   222  
   223  // create a proposal block using real and full
   224  // mempool and evidence pool and validate it.
   225  func TestCreateProposalBlock(t *testing.T) {
   226  	config := cfg.ResetTestRoot("node_create_proposal")
   227  	defer os.RemoveAll(config.RootDir)
   228  	cc := proxy.NewLocalClientCreator(kvstore.NewApplication())
   229  	proxyApp := proxy.NewAppConns(cc)
   230  	err := proxyApp.Start()
   231  	require.Nil(t, err)
   232  	defer proxyApp.Stop() //nolint:errcheck // ignore for tests
   233  
   234  	logger := log.TestingLogger()
   235  
   236  	var height int64 = 1
   237  	state, stateDB, privVals := state(1, height)
   238  	stateStore := sm.NewStore(stateDB, sm.StoreOptions{
   239  		DiscardABCIResponses: false,
   240  	})
   241  	maxBytes := 16384
   242  	var partSize uint32 = 256
   243  	maxEvidenceBytes := int64(maxBytes / 2)
   244  	state.ConsensusParams.Block.MaxBytes = int64(maxBytes)
   245  	state.ConsensusParams.Evidence.MaxBytes = maxEvidenceBytes
   246  	proposerAddr, _ := state.Validators.GetByIndex(0)
   247  
   248  	// Make Mempool
   249  	memplMetrics := mempl.NopMetrics()
   250  	var mempool mempl.Mempool
   251  
   252  	switch config.Mempool.Version {
   253  	case cfg.MempoolV0:
   254  		mempool = mempoolv0.NewCListMempool(config.Mempool,
   255  			proxyApp.Mempool(),
   256  			state.LastBlockHeight,
   257  			mempoolv0.WithMetrics(memplMetrics),
   258  			mempoolv0.WithPreCheck(sm.TxPreCheck(state)),
   259  			mempoolv0.WithPostCheck(sm.TxPostCheck(state)))
   260  	case cfg.MempoolV1:
   261  		mempool = mempoolv1.NewTxMempool(logger,
   262  			config.Mempool,
   263  			proxyApp.Mempool(),
   264  			state.LastBlockHeight,
   265  			mempoolv1.WithMetrics(memplMetrics),
   266  			mempoolv1.WithPreCheck(sm.TxPreCheck(state)),
   267  			mempoolv1.WithPostCheck(sm.TxPostCheck(state)),
   268  		)
   269  	}
   270  
   271  	// Make EvidencePool
   272  	evidenceDB := dbm.NewMemDB()
   273  	blockStore := store.NewBlockStore(dbm.NewMemDB())
   274  	evidencePool, err := evidence.NewPool(evidenceDB, stateStore, blockStore)
   275  	require.NoError(t, err)
   276  	evidencePool.SetLogger(logger)
   277  
   278  	// fill the evidence pool with more evidence
   279  	// than can fit in a block
   280  	var currentBytes int64
   281  	for currentBytes <= maxEvidenceBytes {
   282  		ev := types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(), privVals[0], "test-chain")
   283  		currentBytes += int64(len(ev.Bytes()))
   284  		evidencePool.ReportConflictingVotes(ev.VoteA, ev.VoteB)
   285  	}
   286  
   287  	evList, size := evidencePool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
   288  	require.Less(t, size, state.ConsensusParams.Evidence.MaxBytes+1)
   289  	evData := &types.EvidenceData{Evidence: evList}
   290  	require.EqualValues(t, size, evData.ByteSize())
   291  
   292  	// fill the mempool with more txs
   293  	// than can fit in a block
   294  	txLength := 100
   295  	for i := 0; i <= maxBytes/txLength; i++ {
   296  		tx := tmrand.Bytes(txLength)
   297  		err := mempool.CheckTx(tx, nil, mempl.TxInfo{})
   298  		assert.NoError(t, err)
   299  	}
   300  
   301  	blockExec := sm.NewBlockExecutor(
   302  		stateStore,
   303  		logger,
   304  		proxyApp.Consensus(),
   305  		mempool,
   306  		evidencePool,
   307  	)
   308  
   309  	commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
   310  	block, _ := blockExec.CreateProposalBlock(
   311  		height,
   312  		state, commit,
   313  		proposerAddr,
   314  	)
   315  
   316  	// check that the part set does not exceed the maximum block size
   317  	partSet := block.MakePartSet(partSize)
   318  	assert.Less(t, partSet.ByteSize(), int64(maxBytes))
   319  
   320  	partSetFromHeader := types.NewPartSetFromHeader(partSet.Header())
   321  	for partSetFromHeader.Count() < partSetFromHeader.Total() {
   322  		added, err := partSetFromHeader.AddPart(partSet.GetPart(int(partSetFromHeader.Count())))
   323  		require.NoError(t, err)
   324  		require.True(t, added)
   325  	}
   326  	assert.EqualValues(t, partSetFromHeader.ByteSize(), partSet.ByteSize())
   327  
   328  	err = blockExec.ValidateBlock(state, block)
   329  	assert.NoError(t, err)
   330  }
   331  
   332  func TestMaxProposalBlockSize(t *testing.T) {
   333  	config := cfg.ResetTestRoot("node_create_proposal")
   334  	defer os.RemoveAll(config.RootDir)
   335  	cc := proxy.NewLocalClientCreator(kvstore.NewApplication())
   336  	proxyApp := proxy.NewAppConns(cc)
   337  	err := proxyApp.Start()
   338  	require.Nil(t, err)
   339  	defer proxyApp.Stop() //nolint:errcheck // ignore for tests
   340  
   341  	logger := log.TestingLogger()
   342  
   343  	var height int64 = 1
   344  	state, stateDB, _ := state(1, height)
   345  	stateStore := sm.NewStore(stateDB, sm.StoreOptions{
   346  		DiscardABCIResponses: false,
   347  	})
   348  	var maxBytes int64 = 16384
   349  	var partSize uint32 = 256
   350  	state.ConsensusParams.Block.MaxBytes = maxBytes
   351  	proposerAddr, _ := state.Validators.GetByIndex(0)
   352  
   353  	// Make Mempool
   354  	memplMetrics := mempl.NopMetrics()
   355  	var mempool mempl.Mempool
   356  	switch config.Mempool.Version {
   357  	case cfg.MempoolV0:
   358  		mempool = mempoolv0.NewCListMempool(config.Mempool,
   359  			proxyApp.Mempool(),
   360  			state.LastBlockHeight,
   361  			mempoolv0.WithMetrics(memplMetrics),
   362  			mempoolv0.WithPreCheck(sm.TxPreCheck(state)),
   363  			mempoolv0.WithPostCheck(sm.TxPostCheck(state)))
   364  	case cfg.MempoolV1:
   365  		mempool = mempoolv1.NewTxMempool(logger,
   366  			config.Mempool,
   367  			proxyApp.Mempool(),
   368  			state.LastBlockHeight,
   369  			mempoolv1.WithMetrics(memplMetrics),
   370  			mempoolv1.WithPreCheck(sm.TxPreCheck(state)),
   371  			mempoolv1.WithPostCheck(sm.TxPostCheck(state)),
   372  		)
   373  	}
   374  
   375  	// fill the mempool with one txs just below the maximum size
   376  	txLength := int(types.MaxDataBytesNoEvidence(maxBytes, 1))
   377  	tx := tmrand.Bytes(txLength - 4) // to account for the varint
   378  	err = mempool.CheckTx(tx, nil, mempl.TxInfo{})
   379  	assert.NoError(t, err)
   380  
   381  	blockExec := sm.NewBlockExecutor(
   382  		stateStore,
   383  		logger,
   384  		proxyApp.Consensus(),
   385  		mempool,
   386  		sm.EmptyEvidencePool{},
   387  	)
   388  
   389  	commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
   390  	block, _ := blockExec.CreateProposalBlock(
   391  		height,
   392  		state, commit,
   393  		proposerAddr,
   394  	)
   395  
   396  	pb, err := block.ToProto()
   397  	require.NoError(t, err)
   398  	assert.Less(t, int64(pb.Size()), maxBytes)
   399  
   400  	// check that the part set does not exceed the maximum block size
   401  	partSet := block.MakePartSet(partSize)
   402  	assert.EqualValues(t, partSet.ByteSize(), int64(pb.Size()))
   403  }
   404  
   405  func TestNodeNewNodeCustomReactors(t *testing.T) {
   406  	config := cfg.ResetTestRoot("node_new_node_custom_reactors_test")
   407  	defer os.RemoveAll(config.RootDir)
   408  
   409  	cr := p2pmock.NewReactor()
   410  	cr.Channels = []*conn.ChannelDescriptor{
   411  		{
   412  			ID:                  byte(0x31),
   413  			Priority:            5,
   414  			SendQueueCapacity:   100,
   415  			RecvMessageCapacity: 100,
   416  		},
   417  	}
   418  	customBlockchainReactor := p2pmock.NewReactor()
   419  
   420  	nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
   421  	require.NoError(t, err)
   422  
   423  	n, err := NewNode(config,
   424  		privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()),
   425  		nodeKey,
   426  		proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
   427  		DefaultGenesisDocProviderFunc(config),
   428  		DefaultDBProvider,
   429  		DefaultMetricsProvider(config.Instrumentation),
   430  		log.TestingLogger(),
   431  		CustomReactors(map[string]p2p.Reactor{"FOO": cr, "BLOCKCHAIN": customBlockchainReactor}),
   432  	)
   433  	require.NoError(t, err)
   434  
   435  	err = n.Start()
   436  	require.NoError(t, err)
   437  	defer n.Stop() //nolint:errcheck // ignore for tests
   438  
   439  	assert.True(t, cr.IsRunning())
   440  	assert.Equal(t, cr, n.Switch().Reactor("FOO"))
   441  
   442  	assert.True(t, customBlockchainReactor.IsRunning())
   443  	assert.Equal(t, customBlockchainReactor, n.Switch().Reactor("BLOCKCHAIN"))
   444  
   445  	channels := n.NodeInfo().(p2p.DefaultNodeInfo).Channels
   446  	assert.Contains(t, channels, mempl.MempoolChannel)
   447  	assert.Contains(t, channels, cr.Channels[0].ID)
   448  }
   449  
   450  func state(nVals int, height int64) (sm.State, dbm.DB, []types.PrivValidator) {
   451  	privVals := make([]types.PrivValidator, nVals)
   452  	vals := make([]types.GenesisValidator, nVals)
   453  	for i := 0; i < nVals; i++ {
   454  		privVal := types.NewMockPV()
   455  		privVals[i] = privVal
   456  		vals[i] = types.GenesisValidator{
   457  			Address: privVal.PrivKey.PubKey().Address(),
   458  			PubKey:  privVal.PrivKey.PubKey(),
   459  			Power:   1000,
   460  			Name:    fmt.Sprintf("test%d", i),
   461  		}
   462  	}
   463  	s, _ := sm.MakeGenesisState(&types.GenesisDoc{
   464  		ChainID:    "test-chain",
   465  		Validators: vals,
   466  		AppHash:    nil,
   467  	})
   468  
   469  	// save validators to db for 2 heights
   470  	stateDB := dbm.NewMemDB()
   471  	stateStore := sm.NewStore(stateDB, sm.StoreOptions{
   472  		DiscardABCIResponses: false,
   473  	})
   474  	if err := stateStore.Save(s); err != nil {
   475  		panic(err)
   476  	}
   477  
   478  	for i := 1; i < int(height); i++ {
   479  		s.LastBlockHeight++
   480  		s.LastValidators = s.Validators.Copy()
   481  		if err := stateStore.Save(s); err != nil {
   482  			panic(err)
   483  		}
   484  	}
   485  	return s, stateDB, privVals
   486  }