eth/protocols/eth: simplify peer known block/txs caches (#23649)
* Simplify peer known block/txns cache * Address minor changes * Add more minor comments * Minor changes from review
This commit is contained in:
		
							parent
							
								
									3531ca2246
								
							
						
					
					
						commit
						a541fbea18
					
				| @ -75,12 +75,12 @@ type Peer struct { | |||||||
| 	head common.Hash // Latest advertised head block hash
 | 	head common.Hash // Latest advertised head block hash
 | ||||||
| 	td   *big.Int    // Latest advertised head block total difficulty
 | 	td   *big.Int    // Latest advertised head block total difficulty
 | ||||||
| 
 | 
 | ||||||
| 	knownBlocks     mapset.Set             // Set of block hashes known to be known by this peer
 | 	knownBlocks     *knownCache            // Set of block hashes known to be known by this peer
 | ||||||
| 	queuedBlocks    chan *blockPropagation // Queue of blocks to broadcast to the peer
 | 	queuedBlocks    chan *blockPropagation // Queue of blocks to broadcast to the peer
 | ||||||
| 	queuedBlockAnns chan *types.Block      // Queue of blocks to announce to the peer
 | 	queuedBlockAnns chan *types.Block      // Queue of blocks to announce to the peer
 | ||||||
| 
 | 
 | ||||||
| 	txpool      TxPool             // Transaction pool used by the broadcasters for liveness checks
 | 	txpool      TxPool             // Transaction pool used by the broadcasters for liveness checks
 | ||||||
| 	knownTxs    mapset.Set         // Set of transaction hashes known to be known by this peer
 | 	knownTxs    *knownCache        // Set of transaction hashes known to be known by this peer
 | ||||||
| 	txBroadcast chan []common.Hash // Channel used to queue transaction propagation requests
 | 	txBroadcast chan []common.Hash // Channel used to queue transaction propagation requests
 | ||||||
| 	txAnnounce  chan []common.Hash // Channel used to queue transaction announcement requests
 | 	txAnnounce  chan []common.Hash // Channel used to queue transaction announcement requests
 | ||||||
| 
 | 
 | ||||||
| @ -96,8 +96,8 @@ func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter, txpool TxPool) *Pe | |||||||
| 		Peer:            p, | 		Peer:            p, | ||||||
| 		rw:              rw, | 		rw:              rw, | ||||||
| 		version:         version, | 		version:         version, | ||||||
| 		knownTxs:        mapset.NewSet(), | 		knownTxs:        newKnownCache(maxKnownTxs), | ||||||
| 		knownBlocks:     mapset.NewSet(), | 		knownBlocks:     newKnownCache(maxKnownBlocks), | ||||||
| 		queuedBlocks:    make(chan *blockPropagation, maxQueuedBlocks), | 		queuedBlocks:    make(chan *blockPropagation, maxQueuedBlocks), | ||||||
| 		queuedBlockAnns: make(chan *types.Block, maxQueuedBlockAnns), | 		queuedBlockAnns: make(chan *types.Block, maxQueuedBlockAnns), | ||||||
| 		txBroadcast:     make(chan []common.Hash), | 		txBroadcast:     make(chan []common.Hash), | ||||||
| @ -162,9 +162,6 @@ func (p *Peer) KnownTransaction(hash common.Hash) bool { | |||||||
| // never be propagated to this particular peer.
 | // never be propagated to this particular peer.
 | ||||||
| func (p *Peer) markBlock(hash common.Hash) { | func (p *Peer) markBlock(hash common.Hash) { | ||||||
| 	// If we reached the memory allowance, drop a previously known block hash
 | 	// If we reached the memory allowance, drop a previously known block hash
 | ||||||
| 	for p.knownBlocks.Cardinality() >= maxKnownBlocks { |  | ||||||
| 		p.knownBlocks.Pop() |  | ||||||
| 	} |  | ||||||
| 	p.knownBlocks.Add(hash) | 	p.knownBlocks.Add(hash) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -172,9 +169,6 @@ func (p *Peer) markBlock(hash common.Hash) { | |||||||
| // will never be propagated to this particular peer.
 | // will never be propagated to this particular peer.
 | ||||||
| func (p *Peer) markTransaction(hash common.Hash) { | func (p *Peer) markTransaction(hash common.Hash) { | ||||||
| 	// If we reached the memory allowance, drop a previously known transaction hash
 | 	// If we reached the memory allowance, drop a previously known transaction hash
 | ||||||
| 	for p.knownTxs.Cardinality() >= maxKnownTxs { |  | ||||||
| 		p.knownTxs.Pop() |  | ||||||
| 	} |  | ||||||
| 	p.knownTxs.Add(hash) | 	p.knownTxs.Add(hash) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -189,9 +183,6 @@ func (p *Peer) markTransaction(hash common.Hash) { | |||||||
| // tests that directly send messages without having to do the asyn queueing.
 | // tests that directly send messages without having to do the asyn queueing.
 | ||||||
| func (p *Peer) SendTransactions(txs types.Transactions) error { | func (p *Peer) SendTransactions(txs types.Transactions) error { | ||||||
| 	// Mark all the transactions as known, but ensure we don't overflow our limits
 | 	// Mark all the transactions as known, but ensure we don't overflow our limits
 | ||||||
| 	for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(txs)) { |  | ||||||
| 		p.knownTxs.Pop() |  | ||||||
| 	} |  | ||||||
| 	for _, tx := range txs { | 	for _, tx := range txs { | ||||||
| 		p.knownTxs.Add(tx.Hash()) | 		p.knownTxs.Add(tx.Hash()) | ||||||
| 	} | 	} | ||||||
| @ -205,12 +196,7 @@ func (p *Peer) AsyncSendTransactions(hashes []common.Hash) { | |||||||
| 	select { | 	select { | ||||||
| 	case p.txBroadcast <- hashes: | 	case p.txBroadcast <- hashes: | ||||||
| 		// Mark all the transactions as known, but ensure we don't overflow our limits
 | 		// Mark all the transactions as known, but ensure we don't overflow our limits
 | ||||||
| 		for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) { | 		p.knownTxs.Add(hashes...) | ||||||
| 			p.knownTxs.Pop() |  | ||||||
| 		} |  | ||||||
| 		for _, hash := range hashes { |  | ||||||
| 			p.knownTxs.Add(hash) |  | ||||||
| 		} |  | ||||||
| 	case <-p.term: | 	case <-p.term: | ||||||
| 		p.Log().Debug("Dropping transaction propagation", "count", len(hashes)) | 		p.Log().Debug("Dropping transaction propagation", "count", len(hashes)) | ||||||
| 	} | 	} | ||||||
| @ -224,12 +210,7 @@ func (p *Peer) AsyncSendTransactions(hashes []common.Hash) { | |||||||
| // not be managed directly.
 | // not be managed directly.
 | ||||||
| func (p *Peer) sendPooledTransactionHashes(hashes []common.Hash) error { | func (p *Peer) sendPooledTransactionHashes(hashes []common.Hash) error { | ||||||
| 	// Mark all the transactions as known, but ensure we don't overflow our limits
 | 	// Mark all the transactions as known, but ensure we don't overflow our limits
 | ||||||
| 	for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) { | 	p.knownTxs.Add(hashes...) | ||||||
| 		p.knownTxs.Pop() |  | ||||||
| 	} |  | ||||||
| 	for _, hash := range hashes { |  | ||||||
| 		p.knownTxs.Add(hash) |  | ||||||
| 	} |  | ||||||
| 	return p2p.Send(p.rw, NewPooledTransactionHashesMsg, NewPooledTransactionHashesPacket(hashes)) | 	return p2p.Send(p.rw, NewPooledTransactionHashesMsg, NewPooledTransactionHashesPacket(hashes)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -240,12 +221,7 @@ func (p *Peer) AsyncSendPooledTransactionHashes(hashes []common.Hash) { | |||||||
| 	select { | 	select { | ||||||
| 	case p.txAnnounce <- hashes: | 	case p.txAnnounce <- hashes: | ||||||
| 		// Mark all the transactions as known, but ensure we don't overflow our limits
 | 		// Mark all the transactions as known, but ensure we don't overflow our limits
 | ||||||
| 		for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) { | 		p.knownTxs.Add(hashes...) | ||||||
| 			p.knownTxs.Pop() |  | ||||||
| 		} |  | ||||||
| 		for _, hash := range hashes { |  | ||||||
| 			p.knownTxs.Add(hash) |  | ||||||
| 		} |  | ||||||
| 	case <-p.term: | 	case <-p.term: | ||||||
| 		p.Log().Debug("Dropping transaction announcement", "count", len(hashes)) | 		p.Log().Debug("Dropping transaction announcement", "count", len(hashes)) | ||||||
| 	} | 	} | ||||||
| @ -254,12 +230,8 @@ func (p *Peer) AsyncSendPooledTransactionHashes(hashes []common.Hash) { | |||||||
| // ReplyPooledTransactionsRLP is the eth/66 version of SendPooledTransactionsRLP.
 | // ReplyPooledTransactionsRLP is the eth/66 version of SendPooledTransactionsRLP.
 | ||||||
| func (p *Peer) ReplyPooledTransactionsRLP(id uint64, hashes []common.Hash, txs []rlp.RawValue) error { | func (p *Peer) ReplyPooledTransactionsRLP(id uint64, hashes []common.Hash, txs []rlp.RawValue) error { | ||||||
| 	// Mark all the transactions as known, but ensure we don't overflow our limits
 | 	// Mark all the transactions as known, but ensure we don't overflow our limits
 | ||||||
| 	for p.knownTxs.Cardinality() > max(0, maxKnownTxs-len(hashes)) { | 	p.knownTxs.Add(hashes...) | ||||||
| 		p.knownTxs.Pop() | 
 | ||||||
| 	} |  | ||||||
| 	for _, hash := range hashes { |  | ||||||
| 		p.knownTxs.Add(hash) |  | ||||||
| 	} |  | ||||||
| 	// Not packed into PooledTransactionsPacket to avoid RLP decoding
 | 	// Not packed into PooledTransactionsPacket to avoid RLP decoding
 | ||||||
| 	return p2p.Send(p.rw, PooledTransactionsMsg, PooledTransactionsRLPPacket66{ | 	return p2p.Send(p.rw, PooledTransactionsMsg, PooledTransactionsRLPPacket66{ | ||||||
| 		RequestId:                   id, | 		RequestId:                   id, | ||||||
| @ -271,12 +243,8 @@ func (p *Peer) ReplyPooledTransactionsRLP(id uint64, hashes []common.Hash, txs [ | |||||||
| // a hash notification.
 | // a hash notification.
 | ||||||
| func (p *Peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error { | func (p *Peer) SendNewBlockHashes(hashes []common.Hash, numbers []uint64) error { | ||||||
| 	// Mark all the block hashes as known, but ensure we don't overflow our limits
 | 	// Mark all the block hashes as known, but ensure we don't overflow our limits
 | ||||||
| 	for p.knownBlocks.Cardinality() > max(0, maxKnownBlocks-len(hashes)) { | 	p.knownBlocks.Add(hashes...) | ||||||
| 		p.knownBlocks.Pop() | 
 | ||||||
| 	} |  | ||||||
| 	for _, hash := range hashes { |  | ||||||
| 		p.knownBlocks.Add(hash) |  | ||||||
| 	} |  | ||||||
| 	request := make(NewBlockHashesPacket, len(hashes)) | 	request := make(NewBlockHashesPacket, len(hashes)) | ||||||
| 	for i := 0; i < len(hashes); i++ { | 	for i := 0; i < len(hashes); i++ { | ||||||
| 		request[i].Hash = hashes[i] | 		request[i].Hash = hashes[i] | ||||||
| @ -292,9 +260,6 @@ func (p *Peer) AsyncSendNewBlockHash(block *types.Block) { | |||||||
| 	select { | 	select { | ||||||
| 	case p.queuedBlockAnns <- block: | 	case p.queuedBlockAnns <- block: | ||||||
| 		// Mark all the block hash as known, but ensure we don't overflow our limits
 | 		// Mark all the block hash as known, but ensure we don't overflow our limits
 | ||||||
| 		for p.knownBlocks.Cardinality() >= maxKnownBlocks { |  | ||||||
| 			p.knownBlocks.Pop() |  | ||||||
| 		} |  | ||||||
| 		p.knownBlocks.Add(block.Hash()) | 		p.knownBlocks.Add(block.Hash()) | ||||||
| 	default: | 	default: | ||||||
| 		p.Log().Debug("Dropping block announcement", "number", block.NumberU64(), "hash", block.Hash()) | 		p.Log().Debug("Dropping block announcement", "number", block.NumberU64(), "hash", block.Hash()) | ||||||
| @ -304,9 +269,6 @@ func (p *Peer) AsyncSendNewBlockHash(block *types.Block) { | |||||||
| // SendNewBlock propagates an entire block to a remote peer.
 | // SendNewBlock propagates an entire block to a remote peer.
 | ||||||
| func (p *Peer) SendNewBlock(block *types.Block, td *big.Int) error { | func (p *Peer) SendNewBlock(block *types.Block, td *big.Int) error { | ||||||
| 	// Mark all the block hash as known, but ensure we don't overflow our limits
 | 	// Mark all the block hash as known, but ensure we don't overflow our limits
 | ||||||
| 	for p.knownBlocks.Cardinality() >= maxKnownBlocks { |  | ||||||
| 		p.knownBlocks.Pop() |  | ||||||
| 	} |  | ||||||
| 	p.knownBlocks.Add(block.Hash()) | 	p.knownBlocks.Add(block.Hash()) | ||||||
| 	return p2p.Send(p.rw, NewBlockMsg, &NewBlockPacket{ | 	return p2p.Send(p.rw, NewBlockMsg, &NewBlockPacket{ | ||||||
| 		Block: block, | 		Block: block, | ||||||
| @ -320,9 +282,6 @@ func (p *Peer) AsyncSendNewBlock(block *types.Block, td *big.Int) { | |||||||
| 	select { | 	select { | ||||||
| 	case p.queuedBlocks <- &blockPropagation{block: block, td: td}: | 	case p.queuedBlocks <- &blockPropagation{block: block, td: td}: | ||||||
| 		// Mark all the block hash as known, but ensure we don't overflow our limits
 | 		// Mark all the block hash as known, but ensure we don't overflow our limits
 | ||||||
| 		for p.knownBlocks.Cardinality() >= maxKnownBlocks { |  | ||||||
| 			p.knownBlocks.Pop() |  | ||||||
| 		} |  | ||||||
| 		p.knownBlocks.Add(block.Hash()) | 		p.knownBlocks.Add(block.Hash()) | ||||||
| 	default: | 	default: | ||||||
| 		p.Log().Debug("Dropping block propagation", "number", block.NumberU64(), "hash", block.Hash()) | 		p.Log().Debug("Dropping block propagation", "number", block.NumberU64(), "hash", block.Hash()) | ||||||
| @ -465,3 +424,37 @@ func (p *Peer) RequestTxs(hashes []common.Hash) error { | |||||||
| 		GetPooledTransactionsPacket: hashes, | 		GetPooledTransactionsPacket: hashes, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // knownCache is a cache for known hashes.
 | ||||||
|  | type knownCache struct { | ||||||
|  | 	hashes mapset.Set | ||||||
|  | 	max    int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // newKnownCache creates a new knownCache with a max capacity.
 | ||||||
|  | func newKnownCache(max int) *knownCache { | ||||||
|  | 	return &knownCache{ | ||||||
|  | 		max:    max, | ||||||
|  | 		hashes: mapset.NewSet(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Add adds a list of elements to the set.
 | ||||||
|  | func (k *knownCache) Add(hashes ...common.Hash) { | ||||||
|  | 	for k.hashes.Cardinality() > max(0, k.max-len(hashes)) { | ||||||
|  | 		k.hashes.Pop() | ||||||
|  | 	} | ||||||
|  | 	for _, hash := range hashes { | ||||||
|  | 		k.hashes.Add(hash) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Contains returns whether the given item is in the set.
 | ||||||
|  | func (k *knownCache) Contains(hash common.Hash) bool { | ||||||
|  | 	return k.hashes.Contains(hash) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Cardinality returns the number of elements in the set.
 | ||||||
|  | func (k *knownCache) Cardinality() int { | ||||||
|  | 	return k.hashes.Cardinality() | ||||||
|  | } | ||||||
|  | |||||||
| @ -21,7 +21,9 @@ package eth | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"crypto/rand" | 	"crypto/rand" | ||||||
|  | 	"testing" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/common" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p" | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
| 	"github.com/ethereum/go-ethereum/p2p/enode" | 	"github.com/ethereum/go-ethereum/p2p/enode" | ||||||
| ) | ) | ||||||
| @ -59,3 +61,28 @@ func (p *testPeer) close() { | |||||||
| 	p.Peer.Close() | 	p.Peer.Close() | ||||||
| 	p.app.Close() | 	p.app.Close() | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestPeerSet(t *testing.T) { | ||||||
|  | 	size := 5 | ||||||
|  | 	s := newKnownCache(size) | ||||||
|  | 
 | ||||||
|  | 	// add 10 items
 | ||||||
|  | 	for i := 0; i < size*2; i++ { | ||||||
|  | 		s.Add(common.Hash{byte(i)}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if s.Cardinality() != size { | ||||||
|  | 		t.Fatalf("wrong size, expected %d but found %d", size, s.Cardinality()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	vals := []common.Hash{} | ||||||
|  | 	for i := 10; i < 20; i++ { | ||||||
|  | 		vals = append(vals, common.Hash{byte(i)}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// add item in batch
 | ||||||
|  | 	s.Add(vals...) | ||||||
|  | 	if s.Cardinality() < size { | ||||||
|  | 		t.Fatalf("bad size") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user