@@ -132,7 +132,7 @@ open class GossipRouter(
132132 private val acceptRequestsWhitelist = mutableMapOf<PeerHandler , AcceptRequestsWhitelistEntry >()
133133 override val pendingRpcParts = PendingRpcPartsMap <GossipRpcPartsQueue > { DefaultGossipRpcPartsQueue (params) }
134134
135- private val peerExtensionSupportMap = mutableMapOf< PeerId , Rpc . ControlExtensions > ()
135+ val gossipExtensionsState = GossipExtensionsState ()
136136
137137 private fun setBackOff (peer : PeerHandler , topic : Topic ) = setBackOff(peer, topic, params.pruneBackoff.toMillis())
138138 private fun setBackOff (peer : PeerHandler , topic : Topic , delay : Long ) {
@@ -159,13 +159,15 @@ open class GossipRouter(
159159 fanout.values.forEach { it.remove(peer) }
160160 acceptRequestsWhitelist - = peer
161161 pendingRpcParts.popQueue(peer) // discard them
162+ gossipExtensionsState.onPeerDisconnected(peer.peerId)
162163 super .onPeerDisconnected(peer)
163164 }
164165
165166 override fun onPeerActive (peer : PeerHandler ) {
166167 super .onPeerActive(peer)
167168 eventBroadcaster.notifyConnected(peer.peerId, peer.getRemoteAddress())
168169 heartbeatTask.hashCode() // force lazy initialization
170+ sendControlExtensions(peer)
169171 }
170172
171173 override fun notifyUnseenMessage (peer : PeerHandler , msg : PubsubMessage ) {
@@ -398,34 +400,56 @@ open class GossipRouter(
398400 ) {
399401 logger.trace(" Received control extension {}" , ctrlExtensions.toString())
400402
401- if (peerExtensionSupportMap[ receivedFrom.peerId] != null ) {
402- // TODO Should downscore peers that send control extension multiple times? (https://github.com/libp2p/jvm-libp2p/issues/437)
403+ if (gossipExtensionsState.hasReceivedControlExtensionsFrom( receivedFrom.peerId) ) {
404+ // TODO Should disconnect peers that send control extension multiple times (https://github.com/libp2p/jvm-libp2p/issues/437)
403405 logger.trace(
404406 " Received another control extension message from peer {}" ,
405407 receivedFrom.peerId
406408 )
407409 return
408410 } else {
409- peerExtensionSupportMap[ receivedFrom.peerId] = ctrlExtensions
411+ gossipExtensionsState.onControlExtensionsMessage(ctrlExtensions, receivedFrom.peerId)
410412 }
411413 }
412414
413415 override fun processExtensions (msg : Rpc .RPC , receivedFrom : PeerHandler ) {
414- val peerSupportedExtensions = peerExtensionSupportMap[receivedFrom.peerId]
415- if (peerSupportedExtensions == null ) {
416+ val peerSupportedExtensions =
417+ gossipExtensionsState.peerSupportedExtensions(receivedFrom.peerId)
418+
419+ // TODO Revisit this logic as part of adding feature flags (https://github.com/libp2p/jvm-libp2p/issues/441)
420+
421+ when {
422+ msg.hasTestExtension() && checkPeerExtensionSupport(
423+ peerSupportedExtensions,
424+ Rpc .ControlExtensions ::hasTestExtension
425+ ) ->
426+ processTestExtensionMessage(msg.testExtension, receivedFrom)
427+
428+ msg.hasPartial() && checkPeerExtensionSupport(
429+ peerSupportedExtensions,
430+ Rpc .ControlExtensions ::hasPartialMessages
431+ ) ->
432+ processPartialMessageExtension(msg.partial, receivedFrom)
433+ }
434+ }
435+
436+ private fun checkPeerExtensionSupport (
437+ peerSavedPreferences : Rpc .ControlExtensions ? ,
438+ checkSupportFunction : (Rpc .ControlExtensions ) -> Boolean
439+ ): Boolean {
440+ if (peerSavedPreferences == null ) {
441+ return false
442+ }
443+
444+ if (! checkSupportFunction.invoke(peerSavedPreferences)) {
416445 logger.trace(
417- " Ignoring extension messages from peer {} - did it send an extension control message?" ,
418- receivedFrom.peerId
446+ " Ignoring extension messages from peer {} - did it send an control extensions message?" ,
447+ peerSavedPreferences
419448 )
420- } else {
421- when {
422- peerSupportedExtensions.hasTestExtension() && msg.hasTestExtension() ->
423- processTestExtensionMessage(msg.testExtension, receivedFrom)
424-
425- peerSupportedExtensions.hasPartialMessages() && msg.hasPartial() ->
426- processPartialMessageExtension(msg.partial, receivedFrom)
427- }
449+ return false
428450 }
451+
452+ return true
429453 }
430454
431455 private fun processTestExtensionMessage (
@@ -578,6 +602,8 @@ open class GossipRouter(
578602 fanout - = topic
579603 lastPublished - = topic
580604 }
605+
606+ activePeers.forEach { sendControlExtensions(it) }
581607 }
582608
583609 override fun unsubscribe (topic : Topic ) {
@@ -778,6 +804,33 @@ open class GossipRouter(
778804 send(peer, iDontWant)
779805 }
780806
807+ private fun sendControlExtensions (peer : PeerHandler ) {
808+ if (! this .protocol.supportsExtensions()) {
809+ logger.trace(
810+ " Protocol does not support extensions. Won't send control extensions message."
811+ )
812+ return
813+ }
814+
815+ if (gossipExtensionsState.hasSentControlExtensionsTo(peer.peerId)) {
816+ logger.trace(
817+ " Already sent control extensions msg to peer {}. Won't send another one." ,
818+ peer.peerId
819+ )
820+ return
821+ }
822+
823+ logger.trace(" Sending control extensions message to peer {}" , peer.peerId)
824+
825+ pendingRpcParts.getQueue(peer).addControlExtensions(
826+ Rpc .ControlExtensions .newBuilder()
827+ .setTestExtension(true )
828+ .setPartialMessages(true )
829+ .build()
830+ )
831+ gossipExtensionsState.registerControlExtensionMessageSentToPeers(peer.peerId)
832+ }
833+
781834 data class AcceptRequestsWhitelistEntry (val whitelistedTill : Long , val messagesAccepted : Int = 0 ) {
782835 fun incrementMessageCount () = AcceptRequestsWhitelistEntry (whitelistedTill, messagesAccepted + 1 )
783836 }
0 commit comments