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