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 }