From 7fc153ed2a8071481078c7e8bf5d4fa44e8f0037 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 3 Aug 2021 22:28:16 +0300 Subject: [PATCH] network: only ask mempool for intersections with received Inv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of the time on healthy network we see new transactions appearing that are not present in the mempool. Once they get into mempool we don't ask for them again when some other peer sends an Inv with them. Then these transactions are usually added into block, removed from mempool and no one actually sends them again to us. Some stale nodes can do that, but it's not very likely to happen. At the receiving end at the same time it's quite expensive to do full chain HasTransaction() query, so if we can avoid doing that it's always good. Here it technically allows resending old transaction that will be re-requested and an attempt to add it to mempool will be made. But it'll inevitably fail because the same HasTransaction() check is done there too. One can try to maliciously flood the node with stale transactions but it doesn't differ from flooding it with any other invalid transactions, so there is no new attack vector added. Baseline, 4 nodes with 10 workers: RPS 6902.296 6465.662 6856.044 6785.515 6157.024 ≈ 6633 ± 4.26% TPS 6468.431 6218.867 6610.565 6288.596 5790.556 ≈ 6275 ± 4.44% CPU % 50.231 42.925 49.481 48.396 42.662 ≈ 46.7 ± 7.01% Mem MB 2856.841 2684.103 2756.195 2733.485 2422.787 ≈ 2691 ± 5.40% Patched: RPS 7176.784 7014.511 6139.663 7191.280 7080.852 ≈ 6921 ± 5.72% ↑ 4.34% TPS 6945.409 6562.756 5927.050 6681.187 6821.794 ≈ 6588 ± 5.38% ↑ 4.99% CPU % 44.400 43.842 40.418 49.211 49.370 ≈ 45.4 ± 7.53% ↓ 2.78% Mem MB 2693.414 2640.602 2472.007 2731.482 2707.879 ≈ 2649 ± 3.53% ↓ 1.56% --- pkg/network/server.go | 9 +++++---- pkg/network/server_test.go | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pkg/network/server.go b/pkg/network/server.go index 74e9b5502..5b8032de8 100644 --- a/pkg/network/server.go +++ b/pkg/network/server.go @@ -68,6 +68,7 @@ type ( chain blockchainer.Blockchainer bQueue *blockQueue consensus consensus.Service + mempool *mempool.Pool notaryRequestPool *mempool.Pool extensiblePool *extpool.Pool notaryFeer NotaryFeer @@ -138,6 +139,7 @@ func newServerFromConstructors(config ServerConfig, chain blockchainer.Blockchai unregister: make(chan peerDrop), peers: make(map[Peer]bool), syncReached: atomic.NewBool(false), + mempool: chain.GetMemPool(), extensiblePool: extpool.New(chain, config.ExtensiblePoolSize), log: log, transactions: make(chan *transaction.Transaction, 64), @@ -655,7 +657,7 @@ func (s *Server) handlePong(p Peer, pong *payload.Ping) error { func (s *Server) handleInvCmd(p Peer, inv *payload.Inventory) error { reqHashes := make([]util.Uint256, 0) var typExists = map[payload.InventoryType]func(util.Uint256) bool{ - payload.TXType: s.chain.HasTransaction, + payload.TXType: s.mempool.ContainsKey, payload.BlockType: s.chain.HasBlock, payload.ExtensibleType: func(h util.Uint256) bool { cp := s.extensiblePool.Get(h) @@ -688,7 +690,7 @@ func (s *Server) handleInvCmd(p Peer, inv *payload.Inventory) error { // handleMempoolCmd handles getmempool command. func (s *Server) handleMempoolCmd(p Peer) error { - txs := s.chain.GetMemPool().GetVerifiedTransactions() + txs := s.mempool.GetVerifiedTransactions() hs := make([]util.Uint256, 0, payload.MaxHashesCount) for i := range txs { hs = append(hs, txs[i].Hash()) @@ -1247,8 +1249,7 @@ func (s *Server) initStaleMemPools() { threshold = cfg.ValidatorsCount * 2 } - mp := s.chain.GetMemPool() - mp.SetResendThreshold(uint32(threshold), s.broadcastTX) + s.mempool.SetResendThreshold(uint32(threshold), s.broadcastTX) if s.chain.P2PSigExtensionsEnabled() { s.notaryRequestPool.SetResendThreshold(uint32(threshold), s.broadcastP2PNotaryRequestPayload) } diff --git a/pkg/network/server_test.go b/pkg/network/server_test.go index d70618b54..0c9c9a358 100644 --- a/pkg/network/server_test.go +++ b/pkg/network/server_test.go @@ -694,7 +694,7 @@ func TestInv(t *testing.T) { }) t.Run("transaction", func(t *testing.T) { tx := newDummyTx() - s.chain.(*fakechain.FakeChain).PutTx(tx) + require.NoError(t, s.chain.GetMemPool().Add(tx, s.chain)) hs := []util.Uint256{random.Uint256(), tx.Hash(), random.Uint256()} s.testHandleMessage(t, p, CMDInv, &payload.Inventory{ Type: payload.TXType,