mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 01:41:11 +01:00
Implement BitcoinCoreSeedListDiscovery method
- Update bitcoin core seed list to upstream version - Use IpV4 and onion addresses from it Our users are still protected because we connect to IpV4 addresses through Tor. This improves connectivity because Bitcoin Core creates an ephemeral onion service on each startup.
This commit is contained in:
parent
cbe3ead0d5
commit
c959f7b52c
124
p2p/src/main/java/bisq/network/BitcoinCoreSeedListDiscovery.java
Normal file
124
p2p/src/main/java/bisq/network/BitcoinCoreSeedListDiscovery.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package bisq.network;
|
||||||
|
|
||||||
|
import org.bitcoinj.net.discovery.PeerDiscovery;
|
||||||
|
import org.bitcoinj.net.discovery.PeerDiscoveryException;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static bisq.network.Socks5MultiDiscovery.SOCKS5_DISCOVER_ADDR;
|
||||||
|
import static bisq.network.Socks5MultiDiscovery.SOCKS5_DISCOVER_ONION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BitcoinCoreSeedListDiscovery delivers the list of known Bitcoin .onion seeds shipped
|
||||||
|
* in Bitcoin Core.
|
||||||
|
*/
|
||||||
|
public class BitcoinCoreSeedListDiscovery implements PeerDiscovery {
|
||||||
|
private final int discoveryMode;
|
||||||
|
|
||||||
|
public BitcoinCoreSeedListDiscovery(int discoveryMode) {
|
||||||
|
this.discoveryMode = discoveryMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetSocketAddress[] getPeers(long services,
|
||||||
|
long timeoutValue,
|
||||||
|
TimeUnit timeoutUnit) throws PeerDiscoveryException {
|
||||||
|
try (BufferedReader bufferedReader = openStreamToBitcoinCoreSeedList()) {
|
||||||
|
return extractSeedNodes(bufferedReader.lines())
|
||||||
|
.filter(address -> !address.isEmpty())
|
||||||
|
.map(this::mapToInetSocketAddress)
|
||||||
|
.toArray(InetSocketAddress[]::new);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new PeerDiscoveryException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedReader openStreamToBitcoinCoreSeedList() {
|
||||||
|
ClassLoader classLoader = getClass().getClassLoader();
|
||||||
|
InputStream inputStream = classLoader.getResourceAsStream("bitcoin_core_nodes_main.txt");
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IllegalStateException("Bitcoin Core seed nodes list missing in resources.");
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
|
||||||
|
return new BufferedReader(inputStreamReader);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<String> extractSeedNodes(Stream<String> lines) {
|
||||||
|
return lines.filter(this::isSupportedAddress)
|
||||||
|
.map(this::removeComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InetSocketAddress mapToInetSocketAddress(String address) {
|
||||||
|
// '<hostname>:port'
|
||||||
|
String[] hostnameAndPort = address.split(":");
|
||||||
|
if (hostnameAndPort.length != 2) {
|
||||||
|
throw new IllegalStateException("Invalid address: " + address);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int port = Integer.parseInt(hostnameAndPort[1]);
|
||||||
|
return InetSocketAddress.createUnresolved(hostnameAndPort[0], port);
|
||||||
|
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new IllegalStateException("Invalid port number in address: " + address, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String removeComment(String line) {
|
||||||
|
// '<ip>:port # AS<no>'
|
||||||
|
return line.contains("#") ? line.split("#")[0].trim() : line;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSupportedAddress(String line) {
|
||||||
|
if (!includeIpV4Addresses() && isIpV4Address(line)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!includeOnionAddresses() && isOnionAddress(line)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !isIpV6Address(line) && !isI2PAddress(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean includeIpV4Addresses() {
|
||||||
|
return (discoveryMode & SOCKS5_DISCOVER_ADDR) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean includeOnionAddresses() {
|
||||||
|
return (discoveryMode & SOCKS5_DISCOVER_ONION) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIpV4Address(String line) {
|
||||||
|
// '123.456.789.012:1234 # AS1234'
|
||||||
|
return Pattern.matches("^\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+.+", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIpV6Address(String line) {
|
||||||
|
return line.startsWith("[") && line.contains(":");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOnionAddress(String line) {
|
||||||
|
return line.endsWith(".onion:8333");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isI2PAddress(String line) {
|
||||||
|
return line.endsWith(".b32.i2p:0");
|
||||||
|
}
|
||||||
|
}
|
1748
p2p/src/main/resources/bitcoin_core_nodes_main.txt
Normal file
1748
p2p/src/main/resources/bitcoin_core_nodes_main.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,62 @@
|
|||||||
|
package bisq.network;
|
||||||
|
|
||||||
|
import org.bitcoinj.net.discovery.PeerDiscoveryException;
|
||||||
|
|
||||||
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
public class BitcoinCoreSeedListDiscoveryTest {
|
||||||
|
@Test
|
||||||
|
void allTest() throws PeerDiscoveryException {
|
||||||
|
int mode = Socks5MultiDiscovery.SOCKS5_DISCOVER_ALL;
|
||||||
|
BitcoinCoreSeedListDiscovery bitcoinCoreSeedListDiscovery = new BitcoinCoreSeedListDiscovery(mode);
|
||||||
|
InetSocketAddress[] peers = bitcoinCoreSeedListDiscovery
|
||||||
|
.getPeers(0L, 0L, TimeUnit.MILLISECONDS);
|
||||||
|
assertTrue(peers.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void onlyIpV4Test() throws PeerDiscoveryException {
|
||||||
|
int mode = Socks5MultiDiscovery.SOCKS5_DISCOVER_ADDR;
|
||||||
|
BitcoinCoreSeedListDiscovery bitcoinCoreSeedListDiscovery = new BitcoinCoreSeedListDiscovery(mode);
|
||||||
|
InetSocketAddress[] peers = bitcoinCoreSeedListDiscovery
|
||||||
|
.getPeers(0L, 0L, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
assertTrue(peers.length > 0);
|
||||||
|
assertTrue(
|
||||||
|
Arrays.stream(peers)
|
||||||
|
.allMatch(this::isIpV4Address)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void onlyOnionTest() throws PeerDiscoveryException {
|
||||||
|
int mode = Socks5MultiDiscovery.SOCKS5_DISCOVER_ONION;
|
||||||
|
BitcoinCoreSeedListDiscovery bitcoinCoreSeedListDiscovery = new BitcoinCoreSeedListDiscovery(mode);
|
||||||
|
InetSocketAddress[] peers = bitcoinCoreSeedListDiscovery
|
||||||
|
.getPeers(0L, 0L, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
assertTrue(peers.length > 0);
|
||||||
|
assertTrue(
|
||||||
|
Arrays.stream(peers)
|
||||||
|
.allMatch(socketAddress -> socketAddress.getHostName().endsWith(".onion"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIpV4Address(InetSocketAddress socketAddress) {
|
||||||
|
try {
|
||||||
|
return InetAddress.getByName(socketAddress.getHostName()) instanceof Inet4Address;
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user