github.com/okex/exchain@v1.8.0/libs/tendermint/mempool/clist_mempool_test.go (about) 1 package mempool 2 3 import ( 4 "crypto/rand" 5 "encoding/binary" 6 "fmt" 7 "math/big" 8 mrand "math/rand" 9 "os" 10 "strconv" 11 "sync" 12 "testing" 13 "time" 14 15 "github.com/okex/exchain/libs/tendermint/libs/clist" 16 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 20 amino "github.com/tendermint/go-amino" 21 22 "github.com/okex/exchain/libs/tendermint/abci/example/counter" 23 "github.com/okex/exchain/libs/tendermint/abci/example/kvstore" 24 abci "github.com/okex/exchain/libs/tendermint/abci/types" 25 cfg "github.com/okex/exchain/libs/tendermint/config" 26 "github.com/okex/exchain/libs/tendermint/libs/log" 27 tmrand "github.com/okex/exchain/libs/tendermint/libs/rand" 28 "github.com/okex/exchain/libs/tendermint/proxy" 29 "github.com/okex/exchain/libs/tendermint/types" 30 ) 31 32 const ( 33 BlockMaxTxNum = 300 34 ) 35 36 // A cleanupFunc cleans up any config / test files created for a particular 37 // test. 38 type cleanupFunc func() 39 40 func newMempoolWithApp(cc proxy.ClientCreator) (*CListMempool, cleanupFunc) { 41 return newMempoolWithAppAndConfig(cc, cfg.ResetTestRoot("mempool_test")) 42 } 43 44 func newMempoolWithAppAndConfig(cc proxy.ClientCreator, config *cfg.Config) (*CListMempool, cleanupFunc) { 45 appConnMem, _ := cc.NewABCIClient() 46 appConnMem.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "mempool")) 47 err := appConnMem.Start() 48 if err != nil { 49 panic(err) 50 } 51 mempool := NewCListMempool(config.Mempool, appConnMem, 0) 52 mempool.SetLogger(log.TestingLogger()) 53 return mempool, func() { os.RemoveAll(config.RootDir) } 54 } 55 56 func ensureNoFire(t *testing.T, ch <-chan struct{}, timeoutMS int) { 57 timer := time.NewTimer(time.Duration(timeoutMS) * time.Millisecond) 58 select { 59 case <-ch: 60 t.Fatal("Expected not to fire") 61 case <-timer.C: 62 } 63 } 64 65 func ensureFire(t *testing.T, ch <-chan struct{}, timeoutMS int) { 66 timer := time.NewTimer(time.Duration(timeoutMS) * time.Millisecond) 67 select { 68 case <-ch: 69 case <-timer.C: 70 t.Fatal("Expected to fire") 71 } 72 } 73 74 func checkTxs(t *testing.T, mempool Mempool, count int, peerID uint16) types.Txs { 75 txs := make(types.Txs, count) 76 txInfo := TxInfo{SenderID: peerID} 77 for i := 0; i < count; i++ { 78 txBytes := make([]byte, 20) 79 txs[i] = txBytes 80 _, err := rand.Read(txBytes) 81 if err != nil { 82 t.Error(err) 83 } 84 if err := mempool.CheckTx(txBytes, nil, txInfo); err != nil { 85 // Skip invalid txs. 86 // TestMempoolFilters will fail otherwise. It asserts a number of txs 87 // returned. 88 if IsPreCheckError(err) { 89 continue 90 } 91 t.Fatalf("CheckTx failed: %v while checking #%d tx", err, i) 92 } 93 } 94 return txs 95 } 96 97 func TestReapMaxBytesMaxGas(t *testing.T) { 98 app := kvstore.NewApplication() 99 cc := proxy.NewLocalClientCreator(app) 100 mempool, cleanup := newMempoolWithApp(cc) 101 defer cleanup() 102 103 // Ensure gas calculation behaves as expected 104 checkTxs(t, mempool, 1, UnknownPeerID) 105 tx0 := mempool.TxsFront().Value.(*mempoolTx) 106 // assert that kv store has gas wanted = 1. 107 require.Equal(t, app.CheckTx(abci.RequestCheckTx{Tx: tx0.tx}).GasWanted, int64(1), "KVStore had a gas value neq to 1") 108 require.Equal(t, tx0.gasLimit, int64(1), "transactions gas was set incorrectly") 109 // ensure each tx is 20 bytes long 110 require.Equal(t, len(tx0.tx), 20, "Tx is longer than 20 bytes") 111 mempool.Flush() 112 assert.Zero(t, mempool.Size()) 113 114 // each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs. 115 // each tx has 20 bytes + amino overhead = 21 bytes, 1 gas 116 tests := []struct { 117 numTxsToCreate int 118 maxBytes int64 119 maxGas int64 120 expectedNumTxs int 121 }{ 122 {20, -1, -1, 20}, 123 {20, -1, 0, 1}, 124 {20, -1, 10, 10}, 125 {20, -1, 30, 20}, 126 {20, 0, -1, 0}, 127 {20, 0, 10, 0}, 128 {20, 10, 10, 0}, 129 {20, 22, 10, 1}, 130 {20, 220, -1, 10}, 131 {20, 220, 5, 5}, 132 {20, 220, 10, 10}, 133 {20, 220, 15, 10}, 134 {20, 20000, -1, 20}, 135 {20, 20000, 5, 5}, 136 {20, 20000, 30, 20}, 137 {2000, -1, -1, 300}, 138 } 139 for tcIndex, tt := range tests { 140 checkTxs(t, mempool, tt.numTxsToCreate, UnknownPeerID) 141 got := mempool.ReapMaxBytesMaxGas(tt.maxBytes, tt.maxGas) 142 assert.Equal(t, tt.expectedNumTxs, len(got), "Got %d txs, expected %d, tc #%d", 143 len(got), tt.expectedNumTxs, tcIndex) 144 mempool.Flush() 145 assert.Zero(t, mempool.Size()) 146 } 147 } 148 149 func TestMempoolFilters(t *testing.T) { 150 app := kvstore.NewApplication() 151 cc := proxy.NewLocalClientCreator(app) 152 mempool, cleanup := newMempoolWithApp(cc) 153 defer cleanup() 154 emptyTxArr := []types.Tx{[]byte{}} 155 156 nopPreFilter := func(tx types.Tx) error { return nil } 157 nopPostFilter := func(tx types.Tx, res *abci.ResponseCheckTx) error { return nil } 158 159 // each table driven test creates numTxsToCreate txs with checkTx, and at the end clears all remaining txs. 160 // each tx has 20 bytes + amino overhead = 21 bytes, 1 gas 161 tests := []struct { 162 numTxsToCreate int 163 preFilter PreCheckFunc 164 postFilter PostCheckFunc 165 expectedNumTxs int 166 }{ 167 {10, nopPreFilter, nopPostFilter, 10}, 168 {10, PreCheckAminoMaxBytes(10), nopPostFilter, 0}, 169 {10, PreCheckAminoMaxBytes(20), nopPostFilter, 0}, 170 {10, PreCheckAminoMaxBytes(22), nopPostFilter, 10}, 171 {10, nopPreFilter, PostCheckMaxGas(-1), 10}, 172 {10, nopPreFilter, PostCheckMaxGas(0), 0}, 173 {10, nopPreFilter, PostCheckMaxGas(1), 10}, 174 {10, nopPreFilter, PostCheckMaxGas(3000), 10}, 175 {10, PreCheckAminoMaxBytes(10), PostCheckMaxGas(20), 0}, 176 {10, PreCheckAminoMaxBytes(30), PostCheckMaxGas(20), 10}, 177 {10, PreCheckAminoMaxBytes(22), PostCheckMaxGas(1), 10}, 178 {10, PreCheckAminoMaxBytes(22), PostCheckMaxGas(0), 0}, 179 } 180 for tcIndex, tt := range tests { 181 mempool.Update(1, emptyTxArr, abciResponses(len(emptyTxArr), abci.CodeTypeOK), tt.preFilter, tt.postFilter) 182 checkTxs(t, mempool, tt.numTxsToCreate, UnknownPeerID) 183 require.Equal(t, tt.expectedNumTxs, mempool.Size(), "mempool had the incorrect size, on test case %d", tcIndex) 184 mempool.Flush() 185 } 186 } 187 188 func TestMempoolUpdate(t *testing.T) { 189 app := kvstore.NewApplication() 190 cc := proxy.NewLocalClientCreator(app) 191 mempool, cleanup := newMempoolWithApp(cc) 192 defer cleanup() 193 194 // 1. Adds valid txs to the cache 195 { 196 mempool.Update(1, []types.Tx{[]byte{0x01}}, abciResponses(1, abci.CodeTypeOK), nil, nil) 197 err := mempool.CheckTx([]byte{0x01}, nil, TxInfo{}) 198 if assert.Error(t, err) { 199 assert.Equal(t, ErrTxInCache, err) 200 } 201 } 202 203 // 2. Removes valid txs from the mempool 204 { 205 err := mempool.CheckTx([]byte{0x02}, nil, TxInfo{}) 206 require.NoError(t, err) 207 mempool.Update(1, []types.Tx{[]byte{0x02}}, abciResponses(1, abci.CodeTypeOK), nil, nil) 208 assert.Zero(t, mempool.Size()) 209 } 210 211 // 3. Removes invalid transactions from the cache and the mempool (if present) 212 { 213 err := mempool.CheckTx([]byte{0x03}, nil, TxInfo{}) 214 require.NoError(t, err) 215 mempool.Update(1, []types.Tx{[]byte{0x03}}, abciResponses(1, 1), nil, nil) 216 assert.Zero(t, mempool.Size()) 217 218 err = mempool.CheckTx([]byte{0x03}, nil, TxInfo{}) 219 assert.NoError(t, err) 220 } 221 } 222 223 func TestTxsAvailable(t *testing.T) { 224 app := kvstore.NewApplication() 225 cc := proxy.NewLocalClientCreator(app) 226 mempool, cleanup := newMempoolWithApp(cc) 227 defer cleanup() 228 mempool.EnableTxsAvailable() 229 230 timeoutMS := 500 231 232 // with no txs, it shouldnt fire 233 ensureNoFire(t, mempool.TxsAvailable(), timeoutMS) 234 235 // send a bunch of txs, it should only fire once 236 txs := checkTxs(t, mempool, 100, UnknownPeerID) 237 ensureFire(t, mempool.TxsAvailable(), timeoutMS) 238 ensureNoFire(t, mempool.TxsAvailable(), timeoutMS) 239 240 // call update with half the txs. 241 // it should fire once now for the new height 242 // since there are still txs left 243 committedTxs, txs := txs[:50], txs[50:] 244 if err := mempool.Update(1, committedTxs, abciResponses(len(committedTxs), abci.CodeTypeOK), nil, nil); err != nil { 245 t.Error(err) 246 } 247 ensureFire(t, mempool.TxsAvailable(), timeoutMS) 248 ensureNoFire(t, mempool.TxsAvailable(), timeoutMS) 249 250 // send a bunch more txs. we already fired for this height so it shouldnt fire again 251 moreTxs := checkTxs(t, mempool, 50, UnknownPeerID) 252 ensureNoFire(t, mempool.TxsAvailable(), timeoutMS) 253 254 // now call update with all the txs. it should not fire as there are no txs left 255 committedTxs = append(txs, moreTxs...) //nolint: gocritic 256 if err := mempool.Update(2, committedTxs, abciResponses(len(committedTxs), abci.CodeTypeOK), nil, nil); err != nil { 257 t.Error(err) 258 } 259 ensureNoFire(t, mempool.TxsAvailable(), timeoutMS) 260 261 // send a bunch more txs, it should only fire once 262 checkTxs(t, mempool, 100, UnknownPeerID) 263 ensureFire(t, mempool.TxsAvailable(), timeoutMS) 264 ensureNoFire(t, mempool.TxsAvailable(), timeoutMS) 265 } 266 267 func TestSerialReap(t *testing.T) { 268 app := counter.NewApplication(true) 269 app.SetOption(abci.RequestSetOption{Key: "serial", Value: "on"}) 270 cc := proxy.NewLocalClientCreator(app) 271 272 mempool, cleanup := newMempoolWithApp(cc) 273 defer cleanup() 274 mempool.config.MaxTxNumPerBlock = 10000 275 276 appConnCon, _ := cc.NewABCIClient() 277 appConnCon.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "consensus")) 278 err := appConnCon.Start() 279 require.Nil(t, err) 280 281 cacheMap := make(map[string]struct{}) 282 deliverTxsRange := func(start, end int) { 283 // Deliver some txs. 284 for i := start; i < end; i++ { 285 286 // This will succeed 287 txBytes := make([]byte, 8) 288 binary.BigEndian.PutUint64(txBytes, uint64(i)) 289 err := mempool.CheckTx(txBytes, nil, TxInfo{}) 290 _, cached := cacheMap[string(txBytes)] 291 if cached { 292 require.NotNil(t, err, "expected error for cached tx") 293 } else { 294 require.Nil(t, err, "expected no err for uncached tx") 295 } 296 cacheMap[string(txBytes)] = struct{}{} 297 298 // Duplicates are cached and should return error 299 err = mempool.CheckTx(txBytes, nil, TxInfo{}) 300 require.NotNil(t, err, "Expected error after CheckTx on duplicated tx") 301 } 302 } 303 304 reapCheck := func(exp int) { 305 txs := mempool.ReapMaxBytesMaxGas(-1, -1) 306 require.Equal(t, len(txs), exp, fmt.Sprintf("Expected to reap %v txs but got %v", exp, len(txs))) 307 } 308 309 updateRange := func(start, end int) { 310 txs := make([]types.Tx, 0) 311 for i := start; i < end; i++ { 312 txBytes := make([]byte, 8) 313 binary.BigEndian.PutUint64(txBytes, uint64(i)) 314 txs = append(txs, txBytes) 315 } 316 if err := mempool.Update(0, txs, abciResponses(len(txs), abci.CodeTypeOK), nil, nil); err != nil { 317 t.Error(err) 318 } 319 } 320 321 commitRange := func(start, end int) { 322 // Deliver some txs. 323 for i := start; i < end; i++ { 324 txBytes := make([]byte, 8) 325 binary.BigEndian.PutUint64(txBytes, uint64(i)) 326 res, err := appConnCon.DeliverTxSync(abci.RequestDeliverTx{Tx: txBytes}) 327 if err != nil { 328 t.Errorf("client error committing tx: %v", err) 329 } 330 if res.IsErr() { 331 t.Errorf("error committing tx. Code:%v result:%X log:%v", 332 res.Code, res.Data, res.Log) 333 } 334 } 335 res, err := appConnCon.CommitSync(abci.RequestCommit{}) 336 if err != nil { 337 t.Errorf("client error committing: %v", err) 338 } 339 if len(res.Data) != 8 { 340 t.Errorf("error committing. Hash:%X", res.Data) 341 } 342 } 343 344 //---------------------------------------- 345 346 // Deliver some txs. 347 deliverTxsRange(0, 100) 348 349 // Reap the txs. 350 reapCheck(100) 351 352 // Reap again. We should get the same amount 353 reapCheck(100) 354 355 // Deliver 0 to 999, we should reap 900 new txs 356 // because 100 were already counted. 357 deliverTxsRange(0, 1000) 358 359 // Reap the txs. 360 reapCheck(BlockMaxTxNum) 361 362 // Reap again. We should get the same amount 363 reapCheck(BlockMaxTxNum) 364 365 // Commit from the conensus AppConn 366 commitRange(0, BlockMaxTxNum) 367 updateRange(0, BlockMaxTxNum) 368 369 // We should have 500 left. 370 reapCheck(BlockMaxTxNum) 371 372 // Deliver 100 invalid txs and 100 valid txs 373 deliverTxsRange(900, 1100) 374 375 // We should have 300 now. 376 reapCheck(BlockMaxTxNum) 377 } 378 379 // Size of the amino encoded TxMessage is the length of the 380 // encoded byte array, plus 1 for the struct field, plus 4 381 // for the amino prefix. 382 func txMessageSize(tx types.Tx) int { 383 return amino.ByteSliceSize(tx) + 1 + 4 384 } 385 386 func TestMempoolMaxMsgSize(t *testing.T) { 387 app := kvstore.NewApplication() 388 cc := proxy.NewLocalClientCreator(app) 389 mempl, cleanup := newMempoolWithApp(cc) 390 defer cleanup() 391 392 maxTxSize := mempl.config.MaxTxBytes 393 maxMsgSize := calcMaxMsgSize(maxTxSize) 394 395 testCases := []struct { 396 len int 397 err bool 398 }{ 399 // check small txs. no error 400 {10, false}, 401 {1000, false}, 402 {1000000, false}, 403 404 // check around maxTxSize 405 // changes from no error to error 406 {maxTxSize - 2, false}, 407 {maxTxSize - 1, false}, 408 {maxTxSize, false}, 409 {maxTxSize + 1, true}, 410 {maxTxSize + 2, true}, 411 412 // check around maxMsgSize. all error 413 {maxMsgSize - 1, true}, 414 {maxMsgSize, true}, 415 {maxMsgSize + 1, true}, 416 } 417 418 for i, testCase := range testCases { 419 caseString := fmt.Sprintf("case %d, len %d", i, testCase.len) 420 421 tx := tmrand.Bytes(testCase.len) 422 err := mempl.CheckTx(tx, nil, TxInfo{}) 423 msg := &TxMessage{tx, ""} 424 encoded := cdc.MustMarshalBinaryBare(msg) 425 require.Equal(t, len(encoded), txMessageSize(tx), caseString) 426 if !testCase.err { 427 require.True(t, len(encoded) <= maxMsgSize, caseString) 428 require.NoError(t, err, caseString) 429 } else { 430 require.True(t, len(encoded) > maxMsgSize, caseString) 431 require.Equal(t, err, ErrTxTooLarge{maxTxSize, testCase.len}, caseString) 432 } 433 } 434 435 } 436 437 func TestMempoolTxsBytes(t *testing.T) { 438 app := kvstore.NewApplication() 439 cc := proxy.NewLocalClientCreator(app) 440 config := cfg.ResetTestRoot("mempool_test") 441 config.Mempool.MaxTxsBytes = 10 442 mempool, cleanup := newMempoolWithAppAndConfig(cc, config) 443 defer cleanup() 444 445 // 1. zero by default 446 assert.EqualValues(t, 0, mempool.TxsBytes()) 447 448 // 2. len(tx) after CheckTx 449 err := mempool.CheckTx([]byte{0x01}, nil, TxInfo{}) 450 require.NoError(t, err) 451 assert.EqualValues(t, 1, mempool.TxsBytes()) 452 453 // 3. zero again after tx is removed by Update 454 mempool.Update(1, []types.Tx{[]byte{0x01}}, abciResponses(1, abci.CodeTypeOK), nil, nil) 455 assert.EqualValues(t, 0, mempool.TxsBytes()) 456 457 // 4. zero after Flush 458 err = mempool.CheckTx([]byte{0x02, 0x03}, nil, TxInfo{}) 459 require.NoError(t, err) 460 assert.EqualValues(t, 2, mempool.TxsBytes()) 461 462 mempool.Flush() 463 assert.EqualValues(t, 0, mempool.TxsBytes()) 464 465 // 5. ErrMempoolIsFull is returned when/if MaxTxsBytes limit is reached. 466 err = mempool.CheckTx([]byte{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}, nil, TxInfo{}) 467 require.NoError(t, err) 468 err = mempool.CheckTx([]byte{0x05}, nil, TxInfo{}) 469 if assert.Error(t, err) { 470 assert.IsType(t, ErrMempoolIsFull{}, err) 471 } 472 473 // 6. zero after tx is rechecked and removed due to not being valid anymore 474 app2 := counter.NewApplication(true) 475 cc = proxy.NewLocalClientCreator(app2) 476 mempool, cleanup = newMempoolWithApp(cc) 477 defer cleanup() 478 479 txBytes := make([]byte, 8) 480 binary.BigEndian.PutUint64(txBytes, uint64(0)) 481 482 err = mempool.CheckTx(txBytes, nil, TxInfo{}) 483 require.NoError(t, err) 484 assert.EqualValues(t, 8, mempool.TxsBytes()) 485 486 appConnCon, _ := cc.NewABCIClient() 487 appConnCon.SetLogger(log.TestingLogger().With("module", "abci-client", "connection", "consensus")) 488 err = appConnCon.Start() 489 require.Nil(t, err) 490 defer appConnCon.Stop() 491 res, err := appConnCon.DeliverTxSync(abci.RequestDeliverTx{Tx: txBytes}) 492 require.NoError(t, err) 493 require.EqualValues(t, 0, res.Code) 494 res2, err := appConnCon.CommitSync(abci.RequestCommit{}) 495 require.NoError(t, err) 496 require.NotEmpty(t, res2.Data) 497 // Pretend like we committed nothing so txBytes gets rechecked and removed. 498 // our config recheck flag default is false so cannot rechecked to remove unavailable txs 499 // add config to check whether to assert mempool txsbytes 500 height := int64(1) 501 mempool.Update(height, []types.Tx{}, abciResponses(0, abci.CodeTypeOK), nil, nil) 502 if cfg.DynamicConfig.GetMempoolRecheck() || height%cfg.DynamicConfig.GetMempoolForceRecheckGap() == 0 { 503 assert.EqualValues(t, 0, mempool.TxsBytes()) 504 } else { 505 assert.EqualValues(t, len(txBytes), mempool.TxsBytes()) 506 } 507 } 508 509 func abciResponses(n int, code uint32) []*abci.ResponseDeliverTx { 510 responses := make([]*abci.ResponseDeliverTx, 0, n) 511 for i := 0; i < n; i++ { 512 responses = append(responses, &abci.ResponseDeliverTx{Code: code}) 513 } 514 return responses 515 } 516 517 func TestAddAndSortTx(t *testing.T) { 518 app := kvstore.NewApplication() 519 cc := proxy.NewLocalClientCreator(app) 520 config := cfg.ResetTestRoot("mempool_test") 521 config.Mempool.SortTxByGp = true 522 mempool, cleanup := newMempoolWithAppAndConfig(cc, config) 523 defer cleanup() 524 525 //tx := &mempoolTx{height: 1, gasWanted: 1, tx:[]byte{0x01}} 526 testCases := []struct { 527 Tx *mempoolTx 528 }{ 529 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("1"), from: "18", realTx: abci.MockTx{GasPrice: big.NewInt(3780)}}}, 530 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("2"), from: "6", realTx: abci.MockTx{GasPrice: big.NewInt(5853)}}}, 531 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("3"), from: "7", realTx: abci.MockTx{GasPrice: big.NewInt(8315)}}}, 532 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("4"), from: "10", realTx: abci.MockTx{GasPrice: big.NewInt(9526)}}}, 533 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("5"), from: "15", realTx: abci.MockTx{GasPrice: big.NewInt(9140)}}}, 534 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("6"), from: "9", realTx: abci.MockTx{GasPrice: big.NewInt(9227)}}}, 535 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("7"), from: "3", realTx: abci.MockTx{GasPrice: big.NewInt(761)}}}, 536 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("8"), from: "18", realTx: abci.MockTx{GasPrice: big.NewInt(9740)}}}, 537 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("9"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(6574)}}}, 538 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("10"), from: "8", realTx: abci.MockTx{GasPrice: big.NewInt(9656)}}}, 539 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("11"), from: "12", realTx: abci.MockTx{GasPrice: big.NewInt(6554)}}}, 540 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("12"), from: "16", realTx: abci.MockTx{GasPrice: big.NewInt(5609)}}}, 541 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("13"), from: "6", realTx: abci.MockTx{GasPrice: big.NewInt(2791), Nonce: 1}}}, 542 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("14"), from: "18", realTx: abci.MockTx{GasPrice: big.NewInt(2698), Nonce: 1}}}, 543 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("15"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(6925), Nonce: 1}}}, 544 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("16"), from: "3", realTx: abci.MockTx{GasPrice: big.NewInt(3171)}}}, 545 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("17"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(2965), Nonce: 2}}}, 546 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("18"), from: "19", realTx: abci.MockTx{GasPrice: big.NewInt(2484)}}}, 547 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("19"), from: "13", realTx: abci.MockTx{GasPrice: big.NewInt(9722)}}}, 548 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("20"), from: "7", realTx: abci.MockTx{GasPrice: big.NewInt(4236), Nonce: 1}}}, 549 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("21"), from: "18", realTx: abci.MockTx{GasPrice: big.NewInt(1780)}}}, 550 } 551 552 for _, exInfo := range testCases { 553 mempool.addTx(exInfo.Tx) 554 } 555 require.Equal(t, 18, mempool.txs.Len(), fmt.Sprintf("Expected to txs length %v but got %v", 18, mempool.txs.Len())) 556 557 // The txs in mempool should sorted, the output should be (head -> tail): 558 // 559 //Address: 18 , GasPrice: 9740 , Nonce: 0 560 //Address: 13 , GasPrice: 9722 , Nonce: 0 561 //Address: 8 , GasPrice: 9656 , Nonce: 0 562 //Address: 10 , GasPrice: 9526 , Nonce: 0 563 //Address: 9 , GasPrice: 9227 , Nonce: 0 564 //Address: 15 , GasPrice: 9140 , Nonce: 0 565 //Address: 7 , GasPrice: 8315 , Nonce: 0 566 //Address: 1 , GasPrice: 6574 , Nonce: 0 567 //Address: 1 , GasPrice: 6925 , Nonce: 1 568 //Address: 12 , GasPrice: 6554 , Nonce: 0 569 //Address: 6 , GasPrice: 5853 , Nonce: 0 570 //Address: 16 , GasPrice: 5609 , Nonce: 0 571 //Address: 7 , GasPrice: 4236 , Nonce: 1 572 //Address: 3 , GasPrice: 3171 , Nonce: 0 573 //Address: 1 , GasPrice: 2965 , Nonce: 2 574 //Address: 6 , GasPrice: 2791 , Nonce: 1 575 //Address: 18 , GasPrice: 2698 , Nonce: 1 576 //Address: 19 , GasPrice: 2484 , Nonce: 0 577 578 require.Equal(t, 3, mempool.GetUserPendingTxsCnt("1")) 579 require.Equal(t, 1, mempool.GetUserPendingTxsCnt("15")) 580 require.Equal(t, 2, mempool.GetUserPendingTxsCnt("18")) 581 582 require.Equal(t, "18", mempool.txs.Front().Address) 583 require.Equal(t, big.NewInt(9740), mempool.txs.Front().GasPrice) 584 require.Equal(t, uint64(0), mempool.txs.Front().Nonce) 585 586 require.Equal(t, "19", mempool.txs.Back().Address) 587 require.Equal(t, big.NewInt(2484), mempool.txs.Back().GasPrice) 588 require.Equal(t, uint64(0), mempool.txs.Back().Nonce) 589 590 require.Equal(t, true, checkTx(mempool.txs.Front())) 591 592 addressList := mempool.GetAddressList() 593 for _, addr := range addressList { 594 require.Equal(t, true, checkAccNonce(addr, mempool.txs.Front())) 595 } 596 597 txs := mempool.ReapMaxBytesMaxGas(-1, -1) 598 require.Equal(t, 18, len(txs), fmt.Sprintf("Expected to reap %v txs but got %v", 18, len(txs))) 599 600 mempool.Flush() 601 require.Equal(t, 0, mempool.txs.Len()) 602 require.Equal(t, 0, mempool.txs.BroadcastLen()) 603 require.Equal(t, 0, len(mempool.GetAddressList())) 604 605 } 606 607 func TestReplaceTx(t *testing.T) { 608 app := kvstore.NewApplication() 609 cc := proxy.NewLocalClientCreator(app) 610 config := cfg.ResetTestRoot("mempool_test") 611 mempool, cleanup := newMempoolWithAppAndConfig(cc, config) 612 defer cleanup() 613 614 //tx := &mempoolTx{height: 1, gasWanted: 1, tx:[]byte{0x01}} 615 testCases := []struct { 616 Tx *mempoolTx 617 }{ 618 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("10000"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(9740)}}}, 619 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("10001"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(5853), Nonce: 1}}}, 620 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("10002"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(8315), Nonce: 2}}}, 621 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("10003"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(9526), Nonce: 3}}}, 622 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("10004"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(9140), Nonce: 4}}}, 623 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("10002"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(9227), Nonce: 2}}}, 624 } 625 626 for _, exInfo := range testCases { 627 mempool.addTx(exInfo.Tx) 628 } 629 require.Equal(t, 5, mempool.txs.Len(), fmt.Sprintf("Expected to txs length %v but got %v", 5, mempool.txs.Len())) 630 631 var nonces []uint64 632 var gasPrices []uint64 633 for e := mempool.txs.Front(); e != nil; e = e.Next() { 634 nonces = append(nonces, e.Nonce) 635 gasPrices = append(gasPrices, e.GasPrice.Uint64()) 636 } 637 638 require.Equal(t, []uint64{0, 1, 2, 3, 4}, nonces) 639 require.Equal(t, []uint64{9740, 5853, 9227, 9526, 9140}, gasPrices) 640 } 641 642 func TestAddAndSortTxByRandom(t *testing.T) { 643 app := kvstore.NewApplication() 644 cc := proxy.NewLocalClientCreator(app) 645 config := cfg.ResetTestRoot("mempool_test") 646 mempool, cleanup := newMempoolWithAppAndConfig(cc, config) 647 defer cleanup() 648 649 AddrNonce := make(map[string]int) 650 for i := 0; i < 1000; i++ { 651 mempool.addTx(generateNode(AddrNonce, i)) 652 } 653 654 require.Equal(t, true, checkTx(mempool.txs.Front())) 655 addressList := mempool.GetAddressList() 656 for _, addr := range addressList { 657 require.Equal(t, true, checkAccNonce(addr, mempool.txs.Front())) 658 } 659 } 660 661 func TestReapUserTxs(t *testing.T) { 662 app := kvstore.NewApplication() 663 cc := proxy.NewLocalClientCreator(app) 664 config := cfg.ResetTestRoot("mempool_test") 665 mempool, cleanup := newMempoolWithAppAndConfig(cc, config) 666 defer cleanup() 667 668 //tx := &mempoolTx{height: 1, gasWanted: 1, tx:[]byte{0x01}} 669 testCases := []struct { 670 Tx *mempoolTx 671 }{ 672 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("1"), from: "18", realTx: abci.MockTx{GasPrice: big.NewInt(9740)}}}, 673 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("2"), from: "6", realTx: abci.MockTx{GasPrice: big.NewInt(5853)}}}, 674 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("3"), from: "7", realTx: abci.MockTx{GasPrice: big.NewInt(8315)}}}, 675 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("4"), from: "10", realTx: abci.MockTx{GasPrice: big.NewInt(9526)}}}, 676 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("5"), from: "15", realTx: abci.MockTx{GasPrice: big.NewInt(9140)}}}, 677 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("6"), from: "9", realTx: abci.MockTx{GasPrice: big.NewInt(9227)}}}, 678 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("7"), from: "3", realTx: abci.MockTx{GasPrice: big.NewInt(761)}}}, 679 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("8"), from: "18", realTx: abci.MockTx{GasPrice: big.NewInt(3780)}}}, 680 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("9"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(6574)}}}, 681 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("10"), from: "8", realTx: abci.MockTx{GasPrice: big.NewInt(9656)}}}, 682 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("11"), from: "12", realTx: abci.MockTx{GasPrice: big.NewInt(6554)}}}, 683 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("12"), from: "16", realTx: abci.MockTx{GasPrice: big.NewInt(5609)}}}, 684 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("13"), from: "6", realTx: abci.MockTx{GasPrice: big.NewInt(2791), Nonce: 1}}}, 685 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("14"), from: "18", realTx: abci.MockTx{GasPrice: big.NewInt(2698), Nonce: 1}}}, 686 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("15"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(6925), Nonce: 1}}}, 687 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("16"), from: "3", realTx: abci.MockTx{GasPrice: big.NewInt(3171)}}}, 688 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("17"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(2965), Nonce: 2}}}, 689 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("18"), from: "19", realTx: abci.MockTx{GasPrice: big.NewInt(2484)}}}, 690 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("19"), from: "13", realTx: abci.MockTx{GasPrice: big.NewInt(9722)}}}, 691 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("20"), from: "7", realTx: abci.MockTx{GasPrice: big.NewInt(4236), Nonce: 1}}}, 692 } 693 694 for _, exInfo := range testCases { 695 mempool.addTx(exInfo.Tx) 696 } 697 require.Equal(t, 18, mempool.txs.Len(), fmt.Sprintf("Expected to txs length %v but got %v", 18, 698 mempool.txs.Len())) 699 700 require.Equal(t, 3, mempool.ReapUserTxsCnt("1"), fmt.Sprintf("Expected to txs length of %s "+ 701 "is %v but got %v", "1", 3, mempool.ReapUserTxsCnt("1"))) 702 703 require.Equal(t, 0, mempool.ReapUserTxsCnt("111"), fmt.Sprintf("Expected to txs length of %s "+ 704 "is %v but got %v", "111", 0, mempool.ReapUserTxsCnt("111"))) 705 706 require.Equal(t, 3, len(mempool.ReapUserTxs("1", -1)), fmt.Sprintf("Expected to txs length "+ 707 "of %s is %v but got %v", "1", 3, len(mempool.ReapUserTxs("1", -1)))) 708 709 require.Equal(t, 3, len(mempool.ReapUserTxs("1", 100)), fmt.Sprintf("Expected to txs length "+ 710 "of %s is %v but got %v", "1", 3, len(mempool.ReapUserTxs("1", 100)))) 711 712 require.Equal(t, 0, len(mempool.ReapUserTxs("111", -1)), fmt.Sprintf("Expected to txs length "+ 713 "of %s is %v but got %v", "111", 0, len(mempool.ReapUserTxs("111", -1)))) 714 715 require.Equal(t, 0, len(mempool.ReapUserTxs("111", 100)), fmt.Sprintf("Expected to txs length "+ 716 "of %s is %v but got %v", "111", 0, len(mempool.ReapUserTxs("111", 100)))) 717 } 718 719 func generateNode(addrNonce map[string]int, idx int) *mempoolTx { 720 mrand.Seed(time.Now().UnixNano()) 721 addr := strconv.Itoa(mrand.Int()%1000 + 1) 722 gasPrice := mrand.Int()%100000 + 1 723 724 nonce := 0 725 if n, ok := addrNonce[addr]; ok { 726 if gasPrice%177 == 0 { 727 nonce = n - 1 728 } else { 729 nonce = n 730 } 731 } 732 addrNonce[addr] = nonce + 1 733 734 tx := &mempoolTx{ 735 height: 1, 736 gasWanted: int64(idx), 737 tx: []byte(strconv.Itoa(idx)), 738 from: addr, 739 realTx: abci.MockTx{ 740 GasPrice: big.NewInt(int64(gasPrice)), 741 Nonce: uint64(nonce), 742 }, 743 } 744 745 return tx 746 } 747 748 func checkAccNonce(addr string, head *clist.CElement) bool { 749 nonce := uint64(0) 750 751 for head != nil { 752 if head.Address == addr { 753 if head.Nonce != nonce { 754 return false 755 } 756 nonce++ 757 } 758 759 head = head.Next() 760 } 761 762 return true 763 } 764 765 func checkTx(head *clist.CElement) bool { 766 for head != nil { 767 next := head.Next() 768 if next == nil { 769 break 770 } 771 772 if head.Address == next.Address { 773 if head.Nonce >= next.Nonce { 774 return false 775 } 776 } else { 777 if head.GasPrice.Cmp(next.GasPrice) < 0 { 778 return false 779 } 780 } 781 782 head = head.Next() 783 } 784 785 return true 786 } 787 788 func TestMultiPriceBump(t *testing.T) { 789 tests := []struct { 790 rawPrice *big.Int 791 priceBump uint64 792 targetPrice *big.Int 793 }{ 794 {big.NewInt(1), 0, big.NewInt(1)}, 795 {big.NewInt(10), 1, big.NewInt(10)}, 796 {big.NewInt(100), 0, big.NewInt(100)}, 797 {big.NewInt(100), 5, big.NewInt(105)}, 798 {big.NewInt(100), 50, big.NewInt(150)}, 799 {big.NewInt(100), 150, big.NewInt(250)}, 800 } 801 for _, tt := range tests { 802 require.True(t, tt.targetPrice.Cmp(MultiPriceBump(tt.rawPrice, int64(tt.priceBump))) == 0) 803 } 804 } 805 806 func TestAddAndSortTxConcurrency(t *testing.T) { 807 app := kvstore.NewApplication() 808 cc := proxy.NewLocalClientCreator(app) 809 config := cfg.ResetTestRoot("mempool_test") 810 config.Mempool.SortTxByGp = true 811 mempool, cleanup := newMempoolWithAppAndConfig(cc, config) 812 defer cleanup() 813 814 //tx := &mempoolTx{height: 1, gasWanted: 1, tx:[]byte{0x01}} 815 type Case struct { 816 Tx *mempoolTx 817 } 818 819 testCases := []Case{ 820 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("1"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(3780)}}}, 821 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("2"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(3780), Nonce: 1}}}, 822 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("3"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(5315), Nonce: 2}}}, 823 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("4"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(4526), Nonce: 3}}}, 824 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("5"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(2140), Nonce: 4}}}, 825 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("6"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(4227), Nonce: 5}}}, 826 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("7"), from: "2", realTx: abci.MockTx{GasPrice: big.NewInt(2161)}}}, 827 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("8"), from: "2", realTx: abci.MockTx{GasPrice: big.NewInt(5740), Nonce: 1}}}, 828 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("9"), from: "2", realTx: abci.MockTx{GasPrice: big.NewInt(6574), Nonce: 2}}}, 829 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("10"), from: "2", realTx: abci.MockTx{GasPrice: big.NewInt(9630), Nonce: 3}}}, 830 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("11"), from: "2", realTx: abci.MockTx{GasPrice: big.NewInt(6554), Nonce: 4}}}, 831 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("12"), from: "2", realTx: abci.MockTx{GasPrice: big.NewInt(5609), Nonce: 2}}}, 832 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("13"), from: "3", realTx: abci.MockTx{GasPrice: big.NewInt(2791)}}}, 833 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("14"), from: "3", realTx: abci.MockTx{GasPrice: big.NewInt(2698), Nonce: 1}}}, 834 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("15"), from: "2", realTx: abci.MockTx{GasPrice: big.NewInt(6925), Nonce: 3}}}, 835 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("16"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(4171), Nonce: 3}}}, 836 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("17"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(2965), Nonce: 2}}}, 837 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("18"), from: "3", realTx: abci.MockTx{GasPrice: big.NewInt(2484), Nonce: 2}}}, 838 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("19"), from: "3", realTx: abci.MockTx{GasPrice: big.NewInt(9722), Nonce: 1}}}, 839 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("20"), from: "2", realTx: abci.MockTx{GasPrice: big.NewInt(4236), Nonce: 3}}}, 840 {&mempoolTx{height: 1, gasWanted: 1, tx: []byte("21"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(8780), Nonce: 4}}}, 841 } 842 843 var wait sync.WaitGroup 844 for _, exInfo := range testCases { 845 wait.Add(1) 846 go func(p Case) { 847 mempool.addTx(p.Tx) 848 wait.Done() 849 }(exInfo) 850 } 851 852 wait.Wait() 853 } 854 855 func TestTxID(t *testing.T) { 856 var bytes = make([]byte, 256) 857 for i := 0; i < 10; i++ { 858 _, err := rand.Read(bytes) 859 require.NoError(t, err) 860 require.Equal(t, amino.HexEncodeToStringUpper(bytes), fmt.Sprintf("%X", bytes)) 861 } 862 } 863 864 func BenchmarkTxID(b *testing.B) { 865 var bytes = make([]byte, 256) 866 _, _ = rand.Read(bytes) 867 var res string 868 b.Run("fmt", func(b *testing.B) { 869 b.ReportAllocs() 870 for i := 0; i < b.N; i++ { 871 res = fmt.Sprintf("%X", bytes) 872 } 873 }) 874 b.Run("amino", func(b *testing.B) { 875 b.ReportAllocs() 876 for i := 0; i < b.N; i++ { 877 res = amino.HexEncodeToStringUpper(bytes) 878 } 879 }) 880 _ = res 881 } 882 883 func TestReplaceTxWithMultiAddrs(t *testing.T) { 884 app := kvstore.NewApplication() 885 cc := proxy.NewLocalClientCreator(app) 886 config := cfg.ResetTestRoot("mempool_test") 887 mempool, cleanup := newMempoolWithAppAndConfig(cc, config) 888 defer cleanup() 889 890 tx1 := &mempoolTx{height: 1, gasWanted: 1, tx: []byte("10002"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(9740), Nonce: 1}} 891 mempool.addTx(tx1) 892 tx2 := &mempoolTx{height: 1, gasWanted: 1, tx: []byte("90000"), from: "2", realTx: abci.MockTx{GasPrice: big.NewInt(10717), Nonce: 1}} 893 mempool.addTx(tx2) 894 tx3 := &mempoolTx{height: 1, gasWanted: 1, tx: []byte("90000"), from: "3", realTx: abci.MockTx{GasPrice: big.NewInt(10715), Nonce: 1}} 895 mempool.addTx(tx3) 896 tx4 := &mempoolTx{height: 1, gasWanted: 1, tx: []byte("10001"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(10716), Nonce: 2}} 897 mempool.addTx(tx4) 898 tx5 := &mempoolTx{height: 1, gasWanted: 1, tx: []byte("10001"), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(10712), Nonce: 1}} 899 mempool.addTx(tx5) 900 901 var nonces []uint64 902 for e := mempool.txs.Front(); e != nil; e = e.Next() { 903 if e.Address == "1" { 904 nonces = append(nonces, e.Nonce) 905 } 906 } 907 require.Equal(t, []uint64{1, 2}, nonces) 908 } 909 910 func BenchmarkMempoolLogUpdate(b *testing.B) { 911 logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "benchmark") 912 var options []log.Option 913 options = append(options, log.AllowErrorWith("module", "benchmark")) 914 logger = log.NewFilter(logger, options...) 915 916 mem := &CListMempool{height: 123456, logger: logger} 917 addr := "address" 918 nonce := uint64(123456) 919 920 b.Run("pool", func(b *testing.B) { 921 b.ReportAllocs() 922 for i := 0; i < b.N; i++ { 923 mem.logUpdate(addr, nonce) 924 } 925 }) 926 927 b.Run("logger", func(b *testing.B) { 928 b.ReportAllocs() 929 for i := 0; i < b.N; i++ { 930 mem.logger.Debug("mempool update", "address", addr, "nonce", nonce) 931 } 932 }) 933 } 934 935 func BenchmarkMempoolLogAddTx(b *testing.B) { 936 logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "benchmark") 937 var options []log.Option 938 options = append(options, log.AllowErrorWith("module", "benchmark")) 939 logger = log.NewFilter(logger, options...) 940 941 mem := &CListMempool{height: 123456, logger: logger, txs: NewBaseTxQueue()} 942 tx := []byte("tx") 943 944 memTx := &mempoolTx{ 945 height: mem.Height(), 946 tx: tx, 947 } 948 949 r := &abci.Response_CheckTx{} 950 951 b.Run("pool", func(b *testing.B) { 952 b.ReportAllocs() 953 for i := 0; i < b.N; i++ { 954 mem.logAddTx(memTx, r) 955 } 956 }) 957 958 b.Run("logger", func(b *testing.B) { 959 b.ReportAllocs() 960 for i := 0; i < b.N; i++ { 961 mem.logger.Info("Added good transaction", 962 "tx", txIDStringer{tx, mem.height}, 963 "res", r, 964 "height", memTx.height, 965 "total", mem.Size(), 966 ) 967 } 968 }) 969 } 970 971 func TestTxOrTxHashToKey(t *testing.T) { 972 var tx = make([]byte, 256) 973 rand.Read(tx) 974 975 old := types.GetVenusHeight() 976 977 types.UnittestOnlySetMilestoneVenusHeight(1) 978 979 venus := types.GetVenusHeight() 980 txhash := types.Tx(tx).Hash(venus) 981 982 require.Equal(t, txKey(tx), txOrTxHashToKey(tx, nil, venus)) 983 require.Equal(t, txKey(tx), txOrTxHashToKey(tx, txhash, venus)) 984 require.Equal(t, txKey(tx), txOrTxHashToKey(tx, txhash, venus-1)) 985 require.Equal(t, txKey(tx), txOrTxHashToKey(tx, types.Tx(tx).Hash(venus-1), venus-1)) 986 require.NotEqual(t, txKey(tx), txOrTxHashToKey(tx, types.Tx(tx).Hash(venus-1), venus)) 987 988 types.UnittestOnlySetMilestoneVenusHeight(old) 989 } 990 991 func TestCListMempool_GetEnableDeleteMinGPTx(t *testing.T) { 992 993 testCases := []struct { 994 name string 995 prepare func(mempool *CListMempool, tt *testing.T) 996 execFunc func(mempool *CListMempool, tt *testing.T) 997 }{ 998 { 999 name: "normal mempool is full add tx failed, disableDeleteMinGPTx", 1000 prepare: func(mempool *CListMempool, tt *testing.T) { 1001 mempool.Flush() 1002 err := mempool.CheckTx([]byte{0x01}, nil, TxInfo{}) 1003 require.NoError(tt, err) 1004 }, 1005 execFunc: func(mempool *CListMempool, tt *testing.T) { 1006 err := mempool.CheckTx([]byte{0x02}, nil, TxInfo{}) 1007 require.Error(tt, err) 1008 _, ok := err.(ErrMempoolIsFull) 1009 require.True(t, ok) 1010 }, 1011 }, 1012 { 1013 name: "normal mempool is full add tx failed, enableDeleteMinGPTx", 1014 prepare: func(mempool *CListMempool, tt *testing.T) { 1015 mempool.Flush() 1016 err := mempool.CheckTx([]byte{0x02}, nil, TxInfo{}) 1017 require.NoError(tt, err) 1018 moc := cfg.MockDynamicConfig{} 1019 moc.SetEnableDeleteMinGPTx(true) 1020 cfg.SetDynamicConfig(moc) 1021 }, 1022 execFunc: func(mempool *CListMempool, tt *testing.T) { 1023 err := mempool.CheckTx([]byte{0x03}, nil, TxInfo{}) 1024 require.NoError(tt, err) 1025 require.Equal(tt, 1, mempool.Size()) 1026 tx := mempool.txs.Back().Value.(*mempoolTx).tx 1027 require.Equal(tt, byte(0x02), tx[0]) 1028 }, 1029 }, 1030 } 1031 1032 for _, tc := range testCases { 1033 t.Run(tc.name, func(tt *testing.T) { 1034 app := kvstore.NewApplication() 1035 cc := proxy.NewLocalClientCreator(app) 1036 mempool, cleanup := newMempoolWithApp(cc) 1037 mempool.config.MaxTxsBytes = 1 // in unit test we only use tx bytes to control mempool weather full 1038 defer cleanup() 1039 1040 tc.prepare(mempool, tt) 1041 tc.execFunc(mempool, tt) 1042 }) 1043 } 1044 1045 } 1046 1047 func TestConsumePendingtxConcurrency(t *testing.T) { 1048 1049 app := kvstore.NewApplication() 1050 cc := proxy.NewLocalClientCreator(app) 1051 mem, cleanup := newMempoolWithApp(cc) 1052 defer cleanup() 1053 mem.pendingPool = newPendingPool(500000, 3, 10, 500000) 1054 1055 for i := 0; i < 10000; i++ { 1056 mem.pendingPool.addTx(&mempoolTx{height: 1, gasWanted: 1, tx: []byte(strconv.Itoa(i)), from: "1", realTx: abci.MockTx{GasPrice: big.NewInt(3780), Nonce: uint64(i)}}) 1057 } 1058 wg := &sync.WaitGroup{} 1059 wg.Add(1) 1060 startWg := &sync.WaitGroup{} 1061 startWg.Add(1) 1062 go func() { 1063 startWg.Wait() 1064 mem.consumePendingTx("1", 0) 1065 wg.Done() 1066 }() 1067 startWg.Done() 1068 mem.consumePendingTx("1", 5000) 1069 wg.Wait() 1070 require.Equal(t, 0, mem.pendingPool.Size()) 1071 } 1072 1073 func TestCheckAndGetWrapCMTx(t *testing.T) { 1074 wCMTx := &types.WrapCMTx{Tx: []byte("123456"), Nonce: 2} 1075 wdata, err := cdc.MarshalJSON(wCMTx) 1076 assert.NoError(t, err) 1077 1078 testcase := []struct { 1079 tx types.Tx 1080 txInfo TxInfo 1081 res *types.WrapCMTx 1082 }{ 1083 { 1084 tx: []byte("123"), 1085 txInfo: TxInfo{wrapCMTx: &types.WrapCMTx{Tx: []byte("123"), Nonce: 1}}, 1086 res: &types.WrapCMTx{Tx: []byte("123"), Nonce: 1}, 1087 }, 1088 { 1089 tx: []byte("123"), 1090 txInfo: TxInfo{}, 1091 res: nil, 1092 }, 1093 { 1094 tx: wdata, 1095 txInfo: TxInfo{}, 1096 res: wCMTx, 1097 }, 1098 } 1099 1100 clistMem := &CListMempool{} 1101 for _, tc := range testcase { 1102 re := clistMem.CheckAndGetWrapCMTx(tc.tx, tc.txInfo) 1103 if re != nil { 1104 assert.Equal(t, *re, *tc.res) 1105 } else { 1106 assert.Equal(t, re, tc.res) 1107 } 1108 } 1109 }