github.com/devwanda/aphelion-staking@v0.33.9/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/devwanda/aphelion-staking/abci/example/kvstore"
    18  	cfg "github.com/devwanda/aphelion-staking/config"
    19  	"github.com/devwanda/aphelion-staking/crypto/ed25519"
    20  	"github.com/devwanda/aphelion-staking/evidence"
    21  	"github.com/devwanda/aphelion-staking/libs/log"
    22  	tmrand "github.com/devwanda/aphelion-staking/libs/rand"
    23  	mempl "github.com/devwanda/aphelion-staking/mempool"
    24  	"github.com/devwanda/aphelion-staking/p2p"
    25  	p2pmock "github.com/devwanda/aphelion-staking/p2p/mock"
    26  	"github.com/devwanda/aphelion-staking/privval"
    27  	"github.com/devwanda/aphelion-staking/proxy"
    28  	sm "github.com/devwanda/aphelion-staking/state"
    29  	"github.com/devwanda/aphelion-staking/types"
    30  	tmtime "github.com/devwanda/aphelion-staking/types/time"
    31  	"github.com/devwanda/aphelion-staking/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  	// create & start node
   101  	n, err := DefaultNewNode(config, log.TestingLogger())
   102  	n.GenesisDoc().GenesisTime = now.Add(2 * time.Second)
   103  	require.NoError(t, err)
   104  
   105  	err = n.Start()
   106  	require.NoError(t, err)
   107  	defer n.Stop()
   108  
   109  	startTime := tmtime.Now()
   110  	assert.Equal(t, true, startTime.After(n.GenesisDoc().GenesisTime))
   111  }
   112  
   113  func TestNodeSetAppVersion(t *testing.T) {
   114  	config := cfg.ResetTestRoot("node_app_version_test")
   115  	defer os.RemoveAll(config.RootDir)
   116  
   117  	// create & start node
   118  	n, err := DefaultNewNode(config, log.TestingLogger())
   119  	require.NoError(t, err)
   120  
   121  	// default config uses the kvstore app
   122  	var appVersion version.Protocol = kvstore.ProtocolVersion
   123  
   124  	// check version is set in state
   125  	state := sm.LoadState(n.stateDB)
   126  	assert.Equal(t, state.Version.Consensus.App, appVersion)
   127  
   128  	// check version is set in node info
   129  	assert.Equal(t, n.nodeInfo.(p2p.DefaultNodeInfo).ProtocolVersion.App, appVersion)
   130  }
   131  
   132  func TestNodeSetPrivValTCP(t *testing.T) {
   133  	addr := "tcp://" + testFreeAddr(t)
   134  
   135  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   136  	defer os.RemoveAll(config.RootDir)
   137  	config.BaseConfig.PrivValidatorListenAddr = addr
   138  
   139  	dialer := privval.DialTCPFn(addr, 100*time.Millisecond, ed25519.GenPrivKey())
   140  	dialerEndpoint := privval.NewSignerDialerEndpoint(
   141  		log.TestingLogger(),
   142  		dialer,
   143  	)
   144  	privval.SignerDialerEndpointTimeoutReadWrite(100 * time.Millisecond)(dialerEndpoint)
   145  
   146  	signerServer := privval.NewSignerServer(
   147  		dialerEndpoint,
   148  		config.ChainID(),
   149  		types.NewMockPV(),
   150  	)
   151  
   152  	go func() {
   153  		err := signerServer.Start()
   154  		if err != nil {
   155  			panic(err)
   156  		}
   157  	}()
   158  	defer signerServer.Stop()
   159  
   160  	n, err := DefaultNewNode(config, log.TestingLogger())
   161  	require.NoError(t, err)
   162  	assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
   163  }
   164  
   165  // address without a protocol must result in error
   166  func TestPrivValidatorListenAddrNoProtocol(t *testing.T) {
   167  	addrNoPrefix := testFreeAddr(t)
   168  
   169  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   170  	defer os.RemoveAll(config.RootDir)
   171  	config.BaseConfig.PrivValidatorListenAddr = addrNoPrefix
   172  
   173  	_, err := DefaultNewNode(config, log.TestingLogger())
   174  	assert.Error(t, err)
   175  }
   176  
   177  func TestNodeSetPrivValIPC(t *testing.T) {
   178  	tmpfile := "/tmp/kms." + tmrand.Str(6) + ".sock"
   179  	defer os.Remove(tmpfile) // clean up
   180  
   181  	config := cfg.ResetTestRoot("node_priv_val_tcp_test")
   182  	defer os.RemoveAll(config.RootDir)
   183  	config.BaseConfig.PrivValidatorListenAddr = "unix://" + tmpfile
   184  
   185  	dialer := privval.DialUnixFn(tmpfile)
   186  	dialerEndpoint := privval.NewSignerDialerEndpoint(
   187  		log.TestingLogger(),
   188  		dialer,
   189  	)
   190  	privval.SignerDialerEndpointTimeoutReadWrite(100 * time.Millisecond)(dialerEndpoint)
   191  
   192  	pvsc := privval.NewSignerServer(
   193  		dialerEndpoint,
   194  		config.ChainID(),
   195  		types.NewMockPV(),
   196  	)
   197  
   198  	go func() {
   199  		err := pvsc.Start()
   200  		require.NoError(t, err)
   201  	}()
   202  	defer pvsc.Stop()
   203  
   204  	n, err := DefaultNewNode(config, log.TestingLogger())
   205  	require.NoError(t, err)
   206  	assert.IsType(t, &privval.RetrySignerClient{}, n.PrivValidator())
   207  }
   208  
   209  // testFreeAddr claims a free port so we don't block on listener being ready.
   210  func testFreeAddr(t *testing.T) string {
   211  	ln, err := net.Listen("tcp", "127.0.0.1:0")
   212  	require.NoError(t, err)
   213  	defer ln.Close()
   214  
   215  	return fmt.Sprintf("127.0.0.1:%d", ln.Addr().(*net.TCPAddr).Port)
   216  }
   217  
   218  // create a proposal block using real and full
   219  // mempool and evidence pool and validate it.
   220  func TestCreateProposalBlock(t *testing.T) {
   221  	config := cfg.ResetTestRoot("node_create_proposal")
   222  	defer os.RemoveAll(config.RootDir)
   223  	cc := proxy.NewLocalClientCreator(kvstore.NewApplication())
   224  	proxyApp := proxy.NewAppConns(cc)
   225  	err := proxyApp.Start()
   226  	require.Nil(t, err)
   227  	defer proxyApp.Stop()
   228  
   229  	logger := log.TestingLogger()
   230  
   231  	var height int64 = 1
   232  	state, stateDB := state(1, height)
   233  	maxBytes := 16384
   234  	state.ConsensusParams.Block.MaxBytes = int64(maxBytes)
   235  	proposerAddr, _ := state.Validators.GetByIndex(0)
   236  
   237  	// Make Mempool
   238  	memplMetrics := mempl.PrometheusMetrics("node_test")
   239  	mempool := mempl.NewCListMempool(
   240  		config.Mempool,
   241  		proxyApp.Mempool(),
   242  		state.LastBlockHeight,
   243  		mempl.WithMetrics(memplMetrics),
   244  		mempl.WithPreCheck(sm.TxPreCheck(state)),
   245  		mempl.WithPostCheck(sm.TxPostCheck(state)),
   246  	)
   247  	mempool.SetLogger(logger)
   248  
   249  	// Make EvidencePool
   250  	types.RegisterMockEvidencesGlobal() // XXX!
   251  	evidence.RegisterMockEvidences()
   252  	evidenceDB := dbm.NewMemDB()
   253  	evidencePool := evidence.NewPool(stateDB, evidenceDB)
   254  	evidencePool.SetLogger(logger)
   255  
   256  	// fill the evidence pool with more evidence
   257  	// than can fit in a block
   258  	minEvSize := 12
   259  	numEv := (maxBytes / types.MaxEvidenceBytesDenominator) / minEvSize
   260  	for i := 0; i < numEv; i++ {
   261  		ev := types.NewMockRandomEvidence(1, time.Now(), proposerAddr, tmrand.Bytes(minEvSize))
   262  		err := evidencePool.AddEvidence(ev)
   263  		assert.NoError(t, err)
   264  	}
   265  
   266  	// fill the mempool with more txs
   267  	// than can fit in a block
   268  	txLength := 1000
   269  	for i := 0; i < maxBytes/txLength; i++ {
   270  		tx := tmrand.Bytes(txLength)
   271  		err := mempool.CheckTx(tx, nil, mempl.TxInfo{})
   272  		assert.NoError(t, err)
   273  	}
   274  
   275  	blockExec := sm.NewBlockExecutor(
   276  		stateDB,
   277  		logger,
   278  		proxyApp.Consensus(),
   279  		mempool,
   280  		evidencePool,
   281  	)
   282  
   283  	commit := types.NewCommit(height-1, 0, types.BlockID{}, nil)
   284  	block, _ := blockExec.CreateProposalBlock(
   285  		height,
   286  		state, commit,
   287  		proposerAddr,
   288  	)
   289  
   290  	err = blockExec.ValidateBlock(state, block)
   291  	assert.NoError(t, err)
   292  }
   293  
   294  func TestNodeNewNodeCustomReactors(t *testing.T) {
   295  	config := cfg.ResetTestRoot("node_new_node_custom_reactors_test")
   296  	defer os.RemoveAll(config.RootDir)
   297  
   298  	cr := p2pmock.NewReactor()
   299  	customBlockchainReactor := p2pmock.NewReactor()
   300  
   301  	nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
   302  	require.NoError(t, err)
   303  
   304  	n, err := NewNode(config,
   305  		privval.LoadOrGenFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile()),
   306  		nodeKey,
   307  		proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
   308  		DefaultGenesisDocProviderFunc(config),
   309  		DefaultDBProvider,
   310  		DefaultMetricsProvider(config.Instrumentation),
   311  		log.TestingLogger(),
   312  		CustomReactors(map[string]p2p.Reactor{"FOO": cr, "BLOCKCHAIN": customBlockchainReactor}),
   313  	)
   314  	require.NoError(t, err)
   315  
   316  	err = n.Start()
   317  	require.NoError(t, err)
   318  	defer n.Stop()
   319  
   320  	assert.True(t, cr.IsRunning())
   321  	assert.Equal(t, cr, n.Switch().Reactor("FOO"))
   322  
   323  	assert.True(t, customBlockchainReactor.IsRunning())
   324  	assert.Equal(t, customBlockchainReactor, n.Switch().Reactor("BLOCKCHAIN"))
   325  }
   326  
   327  func state(nVals int, height int64) (sm.State, dbm.DB) {
   328  	vals := make([]types.GenesisValidator, nVals)
   329  	for i := 0; i < nVals; i++ {
   330  		secret := []byte(fmt.Sprintf("test%d", i))
   331  		pk := ed25519.GenPrivKeyFromSecret(secret)
   332  		vals[i] = types.GenesisValidator{
   333  			Address: pk.PubKey().Address(),
   334  			PubKey:  pk.PubKey(),
   335  			Power:   1000,
   336  			Name:    fmt.Sprintf("test%d", i),
   337  		}
   338  	}
   339  	s, _ := sm.MakeGenesisState(&types.GenesisDoc{
   340  		ChainID:    "test-chain",
   341  		Validators: vals,
   342  		AppHash:    nil,
   343  	})
   344  
   345  	// save validators to db for 2 heights
   346  	stateDB := dbm.NewMemDB()
   347  	sm.SaveState(stateDB, s)
   348  
   349  	for i := 1; i < int(height); i++ {
   350  		s.LastBlockHeight++
   351  		s.LastValidators = s.Validators.Copy()
   352  		sm.SaveState(stateDB, s)
   353  	}
   354  	return s, stateDB
   355  }