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