Skip to content

Commit

Permalink
Merge pull request #367 from libp2p/1.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
StefanBratanov authored May 22, 2024
2 parents 8561858 + a651ac7 commit 4a9d319
Show file tree
Hide file tree
Showing 22 changed files with 630 additions and 41 deletions.
55 changes: 55 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Bug Report
description: Create a bug report for jvm-libp2p

body:
- type: markdown
attributes:
value: |
Thank you for filing a bug report!
- type: textarea
attributes:
label: Summary
description: Please provide a short summary of the bug, along with any information you feel relevant to replicate the bug.
validations:
required: true
- type: textarea
attributes:
label: Expected behavior
description: Describe what you expect to happen.
validations:
required: true
- type: textarea
attributes:
label: Actual behavior
description: Describe what actually happens.
validations:
required: true
- type: textarea
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell
validations:
required: false
- type: textarea
attributes:
label: Possible Solution
description: Suggest a fix/reason for the bug, or ideas how to implement the addition or change.
validations:
required: false
- type: textarea
attributes:
label: Version
description: Which version of libp2p are you using? libp2p version (version number, commit, or branch)
validations:
required: false
- type: dropdown
attributes:
label: Would you like to work on fixing this bug ?
description: Any contribution towards fixing the bug is greatly appreciated. We are more than happy to provide help on the process.
options:
- "Yes"
- "No"
- Maybe
validations:
required: true
8 changes: 8 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Technical Questions
url: https://github.com/libp2p/jvm-libp2p/discussions/new?category=q-a
about: Please ask technical questions in the jvm-libp2p Github Discussions forum.
- name: Community-wide libp2p Discussion
url: https://discuss.libp2p.io
about: Discussions and questions about the libp2p community.
31 changes: 31 additions & 0 deletions .github/ISSUE_TEMPLATE/enhancement.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Enhancement
description: Suggest an improvement to an existing jvm-libp2p feature.
body:
- type: textarea
attributes:
label: Description
description: Describe the enhancement that you are proposing.
validations:
required: true
- type: textarea
attributes:
label: Motivation
description: Explain why this enhancement is beneficial.
validations:
required: true
- type: textarea
attributes:
label: Current Implementation
description: Describe the current implementation.
validations:
required: true
- type: dropdown
attributes:
label: Are you planning to do it yourself in a pull request ?
description: Any contribution is greatly appreciated. We are more than happy to provide help on the process.
options:
- "Yes"
- "No"
- Maybe
validations:
required: true
42 changes: 42 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Feature request
description: Suggest a new feature in jvm-libp2p
body:
- type: markdown
attributes:
value: |
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.
- type: textarea
attributes:
label: Description
description: Briefly describe the feature that you are requesting.
validations:
required: true
- type: textarea
attributes:
label: Motivation
description: Explain why this feature is needed.
validations:
required: true
- type: textarea
attributes:
label: Requirements
description: Write a list of what you want this feature to do.
placeholder: "1."
validations:
required: true
- type: textarea
attributes:
label: Open questions
description: Use this section to ask any questions that are related to the feature.
validations:
required: false
- type: dropdown
attributes:
label: Are you planning to do it yourself in a pull request ?
description: Any contribution is greatly appreciated. We are more than happy to provide help on the process.
options:
- "Yes"
- "No"
- Maybe
validations:
required: true
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ List of components in the Libp2p spec and their JVM implementation status
| **Stream Multiplexing** | [yamux](https://github.com/libp2p/specs/blob/master/yamux/README.md) | :lemon: |
| | [mplex](https://github.com/libp2p/specs/blob/master/mplex/README.md) | :green_apple: |
| **NAT Traversal** | [circuit-relay-v2](https://github.com/libp2p/specs/blob/master/relay/circuit-v2.md) | :lemon: |
| | [autonat](https://github.com/libp2p/specs/tree/master/autonat) | |
| | [autonat](https://github.com/libp2p/specs/tree/master/autonat) | :lemon: |
| | [hole-punching](https://github.com/libp2p/specs/blob/master/connections/hole-punching.md) | |
| **Discovery** | [bootstrap](https://github.com/libp2p/specs/blob/master/kad-dht/README.md#bootstrap-process) | |
| | random-walk | |
Expand Down
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ plugins {
id("io.gitlab.arturbosch.detekt").version("1.22.0")
id("java")
id("maven-publish")
id("org.jetbrains.dokka").version("1.9.0")
id("org.jetbrains.dokka").version("1.9.20")
id("com.diffplug.spotless").version("6.21.0")
id("java-test-fixtures")
id("io.spring.dependency-management").version("1.1.3")
Expand All @@ -37,7 +37,7 @@ configure(
}
) {
group = "io.libp2p"
version = "1.1.0-RELEASE"
version = "1.1.1-RELEASE"

apply(plugin = "kotlin")
apply(plugin = "idea")
Expand Down
172 changes: 172 additions & 0 deletions libp2p/src/main/java/io/libp2p/protocol/autonat/AutonatProtocol.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package io.libp2p.protocol.autonat;

import com.google.protobuf.*;
import io.libp2p.core.*;
import io.libp2p.core.Stream;
import io.libp2p.core.multiformats.*;
import io.libp2p.core.multistream.*;
import io.libp2p.protocol.*;
import io.libp2p.protocol.autonat.pb.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
import org.jetbrains.annotations.*;

public class AutonatProtocol extends ProtobufProtocolHandler<AutonatProtocol.AutoNatController> {

public static class Binding extends StrictProtocolBinding<AutoNatController> {
public Binding() {
super("/libp2p/autonat/v1.0.0", new AutonatProtocol());
}
}

public interface AutoNatController {
CompletableFuture<Autonat.Message> rpc(Autonat.Message req);

default CompletableFuture<Autonat.Message.DialResponse> requestDial(
PeerId ourId, List<Multiaddr> us) {
if (us.isEmpty())
throw new IllegalStateException("Requested autonat dial with no addresses!");
return rpc(Autonat.Message.newBuilder()
.setType(Autonat.Message.MessageType.DIAL)
.setDial(
Autonat.Message.Dial.newBuilder()
.setPeer(
Autonat.Message.PeerInfo.newBuilder()
.addAllAddrs(
us.stream()
.map(a -> ByteString.copyFrom(a.serialize()))
.collect(Collectors.toList()))
.setId(ByteString.copyFrom(ourId.getBytes()))))
.build())
.thenApply(msg -> msg.getDialResponse());
}
}

public static class Sender implements ProtocolMessageHandler<Autonat.Message>, AutoNatController {
private final Stream stream;
private final LinkedBlockingDeque<CompletableFuture<Autonat.Message>> queue =
new LinkedBlockingDeque<>();

public Sender(Stream stream) {
this.stream = stream;
}

@Override
public void onMessage(@NotNull Stream stream, Autonat.Message msg) {
queue.poll().complete(msg);
}

public CompletableFuture<Autonat.Message> rpc(Autonat.Message req) {
CompletableFuture<Autonat.Message> res = new CompletableFuture<>();
queue.add(res);
stream.writeAndFlush(req);
return res;
}
}

private static boolean sameIP(Multiaddr a, Multiaddr b) {
if (a.has(Protocol.IP4))
return a.getFirstComponent(Protocol.IP4).equals(b.getFirstComponent(Protocol.IP4));
if (a.has(Protocol.IP6))
return a.getFirstComponent(Protocol.IP6).equals(b.getFirstComponent(Protocol.IP6));
return false;
}

private static boolean reachableIP(Multiaddr a) {
try {
if (a.has(Protocol.IP4))
return InetAddress.getByName(a.getFirstComponent(Protocol.IP4).getStringValue())
.isReachable(1000);
if (a.has(Protocol.IP6))
return InetAddress.getByName(a.getFirstComponent(Protocol.IP6).getStringValue())
.isReachable(1000);
} catch (IOException e) {
}
return false;
}

public static class Receiver
implements ProtocolMessageHandler<Autonat.Message>, AutoNatController {
private final Stream p2pstream;

public Receiver(Stream p2pstream) {
this.p2pstream = p2pstream;
}

@Override
public void onMessage(@NotNull Stream stream, Autonat.Message msg) {
switch (msg.getType()) {
case DIAL:
{
Autonat.Message.Dial dial = msg.getDial();
PeerId peerId = new PeerId(dial.getPeer().getId().toByteArray());
List<Multiaddr> requestedDials =
dial.getPeer().getAddrsList().stream()
.map(s -> Multiaddr.deserialize(s.toByteArray()))
.collect(Collectors.toList());
PeerId streamPeerId = stream.remotePeerId();
if (!peerId.equals(streamPeerId)) {
p2pstream.close();
return;
}

Multiaddr remote = stream.getConnection().remoteAddress();
Optional<Multiaddr> reachable =
requestedDials.stream()
.filter(a -> sameIP(a, remote))
.filter(a -> !a.has(Protocol.P2PCIRCUIT))
.filter(a -> reachableIP(a))
.findAny();
Autonat.Message.Builder resp =
Autonat.Message.newBuilder().setType(Autonat.Message.MessageType.DIAL_RESPONSE);
if (reachable.isPresent()) {
resp =
resp.setDialResponse(
Autonat.Message.DialResponse.newBuilder()
.setStatus(Autonat.Message.ResponseStatus.OK)
.setAddr(ByteString.copyFrom(reachable.get().serialize())));
} else {
resp =
resp.setDialResponse(
Autonat.Message.DialResponse.newBuilder()
.setStatus(Autonat.Message.ResponseStatus.E_DIAL_ERROR));
}
p2pstream.writeAndFlush(resp);
}
default:
{
}
}
}

public CompletableFuture<Autonat.Message> rpc(Autonat.Message msg) {
return CompletableFuture.failedFuture(
new IllegalStateException("Cannot send form a receiver!"));
}
}

private static final int TRAFFIC_LIMIT = 2 * 1024;

public AutonatProtocol() {
super(Autonat.Message.getDefaultInstance(), TRAFFIC_LIMIT, TRAFFIC_LIMIT);
}

@NotNull
@Override
protected CompletableFuture<AutoNatController> onStartInitiator(@NotNull Stream stream) {
Sender replyPropagator = new Sender(stream);
stream.pushHandler(replyPropagator);
return CompletableFuture.completedFuture(replyPropagator);
}

@NotNull
@Override
protected CompletableFuture<AutoNatController> onStartResponder(@NotNull Stream stream) {
Receiver dialer = new Receiver(stream);
stream.pushHandler(dialer);
return CompletableFuture.completedFuture(dialer);
}
}
9 changes: 8 additions & 1 deletion libp2p/src/main/kotlin/io/libp2p/discovery/MDnsDiscovery.kt
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,14 @@ class MDnsDiscovery(
val address = host.listenAddresses().find {
it.has(Protocol.IP4)
}
val str = address?.getFirstComponent(Protocol.TCP)?.stringValue!!
val ipv6OnlyAddress = if (address == null) {
host.listenAddresses().find {
it.has(Protocol.IP6)
}
} else {
address
}
val str = ipv6OnlyAddress?.getFirstComponent(Protocol.TCP)?.stringValue!!
return Integer.parseInt(str)
}

Expand Down
6 changes: 5 additions & 1 deletion libp2p/src/main/kotlin/io/libp2p/pubsub/AbstractRouter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,11 @@ abstract class AbstractRouter(

override fun getPeerTopics(): CompletableFuture<Map<PeerId, Set<Topic>>> {
return submitOnEventThread {
peersTopics.asFirstToSecondMap().mapKeys { it.key.peerId }
peersTopics.asFirstToSecondMap()
.map { (key, value) ->
key.peerId to value.toSet()
}
.toMap()
}
}

Expand Down
10 changes: 7 additions & 3 deletions libp2p/src/main/kotlin/io/libp2p/pubsub/gossip/GossipRouter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,10 @@ open class GossipRouter(
}

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

peers.shuffled(random)
.take(max((params.gossipFactor * peers.size).toInt(), params.DLazy))
.forEach { enqueueIhave(it, shuffledMessageIds) }
.forEach { enqueueIhave(it, shuffledMessageIds, topic) }
}

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

private fun enqueueIhave(peer: PeerHandler, messageIds: List<MessageId>) =
pendingRpcParts.getQueue(peer).addIHaves(messageIds)
private fun enqueueIhave(peer: PeerHandler, messageIds: List<MessageId>, topic: Topic) =
pendingRpcParts.getQueue(peer).addIHaves(messageIds, topic)

data class AcceptRequestsWhitelistEntry(val whitelistedTill: Long, val messagesAccepted: Int = 0) {
fun incrementMessageCount() = AcceptRequestsWhitelistEntry(whitelistedTill, messagesAccepted + 1)
Expand Down
Loading

0 comments on commit 4a9d319

Please sign in to comment.