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