package mempool import ( "fmt" tmsync "github.com/tendermint/tendermint/internal/libs/sync" "github.com/tendermint/tendermint/p2p" ) type mempoolIDs struct { mtx tmsync.RWMutex peerMap map[p2p.NodeID]uint16 nextID uint16 // assumes that a node will never have over 65536 active peers activeIDs map[uint16]struct{} // used to check if a given peerID key is used } func newMempoolIDs() *mempoolIDs { return &mempoolIDs{ peerMap: make(map[p2p.NodeID]uint16), // reserve UnknownPeerID for mempoolReactor.BroadcastTx activeIDs: map[uint16]struct{}{UnknownPeerID: {}}, nextID: 1, } } // ReserveForPeer searches for the next unused ID and assigns it to the provided // peer. func (ids *mempoolIDs) ReserveForPeer(peerID p2p.NodeID) { ids.mtx.Lock() defer ids.mtx.Unlock() curID := ids.nextPeerID() ids.peerMap[peerID] = curID ids.activeIDs[curID] = struct{}{} } // Reclaim returns the ID reserved for the peer back to unused pool. func (ids *mempoolIDs) Reclaim(peerID p2p.NodeID) { ids.mtx.Lock() defer ids.mtx.Unlock() removedID, ok := ids.peerMap[peerID] if ok { delete(ids.activeIDs, removedID) delete(ids.peerMap, peerID) } } // GetForPeer returns an ID reserved for the peer. func (ids *mempoolIDs) GetForPeer(peerID p2p.NodeID) uint16 { ids.mtx.RLock() defer ids.mtx.RUnlock() return ids.peerMap[peerID] } // nextPeerID returns the next unused peer ID to use. We assume that the mutex // is already held. func (ids *mempoolIDs) nextPeerID() uint16 { if len(ids.activeIDs) == maxActiveIDs { panic(fmt.Sprintf("node has maximum %d active IDs and wanted to get one more", maxActiveIDs)) } _, idExists := ids.activeIDs[ids.nextID] for idExists { ids.nextID++ _, idExists = ids.activeIDs[ids.nextID] } curID := ids.nextID ids.nextID++ return curID }