Skip to content

Commit 4a9d319

Browse files
authoredMay 22, 2024··
Merge pull request #367 from libp2p/1.1.1
2 parents 8561858 + a651ac7 commit 4a9d319

File tree

22 files changed

+630
-41
lines changed

22 files changed

+630
-41
lines changed
 

‎.github/ISSUE_TEMPLATE/bug_report.yml

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Bug Report
2+
description: Create a bug report for jvm-libp2p
3+
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: |
8+
Thank you for filing a bug report!
9+
- type: textarea
10+
attributes:
11+
label: Summary
12+
description: Please provide a short summary of the bug, along with any information you feel relevant to replicate the bug.
13+
validations:
14+
required: true
15+
- type: textarea
16+
attributes:
17+
label: Expected behavior
18+
description: Describe what you expect to happen.
19+
validations:
20+
required: true
21+
- type: textarea
22+
attributes:
23+
label: Actual behavior
24+
description: Describe what actually happens.
25+
validations:
26+
required: true
27+
- type: textarea
28+
attributes:
29+
label: Relevant log output
30+
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
31+
render: shell
32+
validations:
33+
required: false
34+
- type: textarea
35+
attributes:
36+
label: Possible Solution
37+
description: Suggest a fix/reason for the bug, or ideas how to implement the addition or change.
38+
validations:
39+
required: false
40+
- type: textarea
41+
attributes:
42+
label: Version
43+
description: Which version of libp2p are you using? libp2p version (version number, commit, or branch)
44+
validations:
45+
required: false
46+
- type: dropdown
47+
attributes:
48+
label: Would you like to work on fixing this bug ?
49+
description: Any contribution towards fixing the bug is greatly appreciated. We are more than happy to provide help on the process.
50+
options:
51+
- "Yes"
52+
- "No"
53+
- Maybe
54+
validations:
55+
required: true

‎.github/ISSUE_TEMPLATE/config.yml

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
blank_issues_enabled: true
2+
contact_links:
3+
- name: Technical Questions
4+
url: https://github.com/libp2p/jvm-libp2p/discussions/new?category=q-a
5+
about: Please ask technical questions in the jvm-libp2p Github Discussions forum.
6+
- name: Community-wide libp2p Discussion
7+
url: https://discuss.libp2p.io
8+
about: Discussions and questions about the libp2p community.
+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Enhancement
2+
description: Suggest an improvement to an existing jvm-libp2p feature.
3+
body:
4+
- type: textarea
5+
attributes:
6+
label: Description
7+
description: Describe the enhancement that you are proposing.
8+
validations:
9+
required: true
10+
- type: textarea
11+
attributes:
12+
label: Motivation
13+
description: Explain why this enhancement is beneficial.
14+
validations:
15+
required: true
16+
- type: textarea
17+
attributes:
18+
label: Current Implementation
19+
description: Describe the current implementation.
20+
validations:
21+
required: true
22+
- type: dropdown
23+
attributes:
24+
label: Are you planning to do it yourself in a pull request ?
25+
description: Any contribution is greatly appreciated. We are more than happy to provide help on the process.
26+
options:
27+
- "Yes"
28+
- "No"
29+
- Maybe
30+
validations:
31+
required: true
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Feature request
2+
description: Suggest a new feature in jvm-libp2p
3+
body:
4+
- type: markdown
5+
attributes:
6+
value: |
7+
If you'd like to suggest a feature related to libp2p but not specifically related to the JVM implementation, please file an issue at https://github.com/libp2p/specs instead.
8+
- type: textarea
9+
attributes:
10+
label: Description
11+
description: Briefly describe the feature that you are requesting.
12+
validations:
13+
required: true
14+
- type: textarea
15+
attributes:
16+
label: Motivation
17+
description: Explain why this feature is needed.
18+
validations:
19+
required: true
20+
- type: textarea
21+
attributes:
22+
label: Requirements
23+
description: Write a list of what you want this feature to do.
24+
placeholder: "1."
25+
validations:
26+
required: true
27+
- type: textarea
28+
attributes:
29+
label: Open questions
30+
description: Use this section to ask any questions that are related to the feature.
31+
validations:
32+
required: false
33+
- type: dropdown
34+
attributes:
35+
label: Are you planning to do it yourself in a pull request ?
36+
description: Any contribution is greatly appreciated. We are more than happy to provide help on the process.
37+
options:
38+
- "Yes"
39+
- "No"
40+
- Maybe
41+
validations:
42+
required: true

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ List of components in the Libp2p spec and their JVM implementation status
2828
| **Stream Multiplexing** | [yamux](https://github.com/libp2p/specs/blob/master/yamux/README.md) | :lemon: |
2929
| | [mplex](https://github.com/libp2p/specs/blob/master/mplex/README.md) | :green_apple: |
3030
| **NAT Traversal** | [circuit-relay-v2](https://github.com/libp2p/specs/blob/master/relay/circuit-v2.md) | :lemon: |
31-
| | [autonat](https://github.com/libp2p/specs/tree/master/autonat) | |
31+
| | [autonat](https://github.com/libp2p/specs/tree/master/autonat) | :lemon: |
3232
| | [hole-punching](https://github.com/libp2p/specs/blob/master/connections/hole-punching.md) | |
3333
| **Discovery** | [bootstrap](https://github.com/libp2p/specs/blob/master/kad-dht/README.md#bootstrap-process) | |
3434
| | random-walk | |

‎build.gradle.kts

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ plugins {
1818
id("io.gitlab.arturbosch.detekt").version("1.22.0")
1919
id("java")
2020
id("maven-publish")
21-
id("org.jetbrains.dokka").version("1.9.0")
21+
id("org.jetbrains.dokka").version("1.9.20")
2222
id("com.diffplug.spotless").version("6.21.0")
2323
id("java-test-fixtures")
2424
id("io.spring.dependency-management").version("1.1.3")
@@ -37,7 +37,7 @@ configure(
3737
}
3838
) {
3939
group = "io.libp2p"
40-
version = "1.1.0-RELEASE"
40+
version = "1.1.1-RELEASE"
4141

4242
apply(plugin = "kotlin")
4343
apply(plugin = "idea")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package io.libp2p.protocol.autonat;
2+
3+
import com.google.protobuf.*;
4+
import io.libp2p.core.*;
5+
import io.libp2p.core.Stream;
6+
import io.libp2p.core.multiformats.*;
7+
import io.libp2p.core.multistream.*;
8+
import io.libp2p.protocol.*;
9+
import io.libp2p.protocol.autonat.pb.*;
10+
import java.io.*;
11+
import java.net.*;
12+
import java.util.*;
13+
import java.util.concurrent.*;
14+
import java.util.stream.*;
15+
import org.jetbrains.annotations.*;
16+
17+
public class AutonatProtocol extends ProtobufProtocolHandler<AutonatProtocol.AutoNatController> {
18+
19+
public static class Binding extends StrictProtocolBinding<AutoNatController> {
20+
public Binding() {
21+
super("/libp2p/autonat/v1.0.0", new AutonatProtocol());
22+
}
23+
}
24+
25+
public interface AutoNatController {
26+
CompletableFuture<Autonat.Message> rpc(Autonat.Message req);
27+
28+
default CompletableFuture<Autonat.Message.DialResponse> requestDial(
29+
PeerId ourId, List<Multiaddr> us) {
30+
if (us.isEmpty())
31+
throw new IllegalStateException("Requested autonat dial with no addresses!");
32+
return rpc(Autonat.Message.newBuilder()
33+
.setType(Autonat.Message.MessageType.DIAL)
34+
.setDial(
35+
Autonat.Message.Dial.newBuilder()
36+
.setPeer(
37+
Autonat.Message.PeerInfo.newBuilder()
38+
.addAllAddrs(
39+
us.stream()
40+
.map(a -> ByteString.copyFrom(a.serialize()))
41+
.collect(Collectors.toList()))
42+
.setId(ByteString.copyFrom(ourId.getBytes()))))
43+
.build())
44+
.thenApply(msg -> msg.getDialResponse());
45+
}
46+
}
47+
48+
public static class Sender implements ProtocolMessageHandler<Autonat.Message>, AutoNatController {
49+
private final Stream stream;
50+
private final LinkedBlockingDeque<CompletableFuture<Autonat.Message>> queue =
51+
new LinkedBlockingDeque<>();
52+
53+
public Sender(Stream stream) {
54+
this.stream = stream;
55+
}
56+
57+
@Override
58+
public void onMessage(@NotNull Stream stream, Autonat.Message msg) {
59+
queue.poll().complete(msg);
60+
}
61+
62+
public CompletableFuture<Autonat.Message> rpc(Autonat.Message req) {
63+
CompletableFuture<Autonat.Message> res = new CompletableFuture<>();
64+
queue.add(res);
65+
stream.writeAndFlush(req);
66+
return res;
67+
}
68+
}
69+
70+
private static boolean sameIP(Multiaddr a, Multiaddr b) {
71+
if (a.has(Protocol.IP4))
72+
return a.getFirstComponent(Protocol.IP4).equals(b.getFirstComponent(Protocol.IP4));
73+
if (a.has(Protocol.IP6))
74+
return a.getFirstComponent(Protocol.IP6).equals(b.getFirstComponent(Protocol.IP6));
75+
return false;
76+
}
77+
78+
private static boolean reachableIP(Multiaddr a) {
79+
try {
80+
if (a.has(Protocol.IP4))
81+
return InetAddress.getByName(a.getFirstComponent(Protocol.IP4).getStringValue())
82+
.isReachable(1000);
83+
if (a.has(Protocol.IP6))
84+
return InetAddress.getByName(a.getFirstComponent(Protocol.IP6).getStringValue())
85+
.isReachable(1000);
86+
} catch (IOException e) {
87+
}
88+
return false;
89+
}
90+
91+
public static class Receiver
92+
implements ProtocolMessageHandler<Autonat.Message>, AutoNatController {
93+
private final Stream p2pstream;
94+
95+
public Receiver(Stream p2pstream) {
96+
this.p2pstream = p2pstream;
97+
}
98+
99+
@Override
100+
public void onMessage(@NotNull Stream stream, Autonat.Message msg) {
101+
switch (msg.getType()) {
102+
case DIAL:
103+
{
104+
Autonat.Message.Dial dial = msg.getDial();
105+
PeerId peerId = new PeerId(dial.getPeer().getId().toByteArray());
106+
List<Multiaddr> requestedDials =
107+
dial.getPeer().getAddrsList().stream()
108+
.map(s -> Multiaddr.deserialize(s.toByteArray()))
109+
.collect(Collectors.toList());
110+
PeerId streamPeerId = stream.remotePeerId();
111+
if (!peerId.equals(streamPeerId)) {
112+
p2pstream.close();
113+
return;
114+
}
115+
116+
Multiaddr remote = stream.getConnection().remoteAddress();
117+
Optional<Multiaddr> reachable =
118+
requestedDials.stream()
119+
.filter(a -> sameIP(a, remote))
120+
.filter(a -> !a.has(Protocol.P2PCIRCUIT))
121+
.filter(a -> reachableIP(a))
122+
.findAny();
123+
Autonat.Message.Builder resp =
124+
Autonat.Message.newBuilder().setType(Autonat.Message.MessageType.DIAL_RESPONSE);
125+
if (reachable.isPresent()) {
126+
resp =
127+
resp.setDialResponse(
128+
Autonat.Message.DialResponse.newBuilder()
129+
.setStatus(Autonat.Message.ResponseStatus.OK)
130+
.setAddr(ByteString.copyFrom(reachable.get().serialize())));
131+
} else {
132+
resp =
133+
resp.setDialResponse(
134+
Autonat.Message.DialResponse.newBuilder()
135+
.setStatus(Autonat.Message.ResponseStatus.E_DIAL_ERROR));
136+
}
137+
p2pstream.writeAndFlush(resp);
138+
}
139+
default:
140+
{
141+
}
142+
}
143+
}
144+
145+
public CompletableFuture<Autonat.Message> rpc(Autonat.Message msg) {
146+
return CompletableFuture.failedFuture(
147+
new IllegalStateException("Cannot send form a receiver!"));
148+
}
149+
}
150+
151+
private static final int TRAFFIC_LIMIT = 2 * 1024;
152+
153+
public AutonatProtocol() {
154+
super(Autonat.Message.getDefaultInstance(), TRAFFIC_LIMIT, TRAFFIC_LIMIT);
155+
}
156+
157+
@NotNull
158+
@Override
159+
protected CompletableFuture<AutoNatController> onStartInitiator(@NotNull Stream stream) {
160+
Sender replyPropagator = new Sender(stream);
161+
stream.pushHandler(replyPropagator);
162+
return CompletableFuture.completedFuture(replyPropagator);
163+
}
164+
165+
@NotNull
166+
@Override
167+
protected CompletableFuture<AutoNatController> onStartResponder(@NotNull Stream stream) {
168+
Receiver dialer = new Receiver(stream);
169+
stream.pushHandler(dialer);
170+
return CompletableFuture.completedFuture(dialer);
171+
}
172+
}

‎libp2p/src/main/kotlin/io/libp2p/discovery/MDnsDiscovery.kt

+8-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,14 @@ class MDnsDiscovery(
7676
val address = host.listenAddresses().find {
7777
it.has(Protocol.IP4)
7878
}
79-
val str = address?.getFirstComponent(Protocol.TCP)?.stringValue!!
79+
val ipv6OnlyAddress = if (address == null) {
80+
host.listenAddresses().find {
81+
it.has(Protocol.IP6)
82+
}
83+
} else {
84+
address
85+
}
86+
val str = ipv6OnlyAddress?.getFirstComponent(Protocol.TCP)?.stringValue!!
8087
return Integer.parseInt(str)
8188
}
8289

‎libp2p/src/main/kotlin/io/libp2p/pubsub/AbstractRouter.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,11 @@ abstract class AbstractRouter(
323323

324324
override fun getPeerTopics(): CompletableFuture<Map<PeerId, Set<Topic>>> {
325325
return submitOnEventThread {
326-
peersTopics.asFirstToSecondMap().mapKeys { it.key.peerId }
326+
peersTopics.asFirstToSecondMap()
327+
.map { (key, value) ->
328+
key.peerId to value.toSet()
329+
}
330+
.toMap()
327331
}
328332
}
329333

‎libp2p/src/main/kotlin/io/libp2p/pubsub/gossip/GossipRouter.kt

+7-3
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ open class GossipRouter(
317317
}
318318

319319
private fun handleIHave(msg: Rpc.ControlIHave, peer: PeerHandler) {
320+
// we ignore IHAVE gossip for unknown topics
321+
if (msg.hasTopicID() && !mesh.containsKey(msg.topicID)) {
322+
return
323+
}
320324
val peerScore = score.score(peer.peerId)
321325
// we ignore IHAVE gossip from any peer whose score is below the gossip threshold
322326
if (peerScore < scoreParams.gossipThreshold) return
@@ -544,7 +548,7 @@ open class GossipRouter(
544548

545549
peers.shuffled(random)
546550
.take(max((params.gossipFactor * peers.size).toInt(), params.DLazy))
547-
.forEach { enqueueIhave(it, shuffledMessageIds) }
551+
.forEach { enqueueIhave(it, shuffledMessageIds, topic) }
548552
}
549553

550554
private fun graft(peer: PeerHandler, topic: Topic) {
@@ -587,8 +591,8 @@ open class GossipRouter(
587591
private fun enqueueIwant(peer: PeerHandler, messageIds: List<MessageId>) =
588592
pendingRpcParts.getQueue(peer).addIWants(messageIds)
589593

590-
private fun enqueueIhave(peer: PeerHandler, messageIds: List<MessageId>) =
591-
pendingRpcParts.getQueue(peer).addIHaves(messageIds)
594+
private fun enqueueIhave(peer: PeerHandler, messageIds: List<MessageId>, topic: Topic) =
595+
pendingRpcParts.getQueue(peer).addIHaves(messageIds, topic)
592596

593597
data class AcceptRequestsWhitelistEntry(val whitelistedTill: Long, val messagesAccepted: Int = 0) {
594598
fun incrementMessageCount() = AcceptRequestsWhitelistEntry(whitelistedTill, messagesAccepted + 1)

0 commit comments

Comments
 (0)
Please sign in to comment.