Skip to content
This repository has been archived by the owner on Feb 2, 2021. It is now read-only.

Commit

Permalink
Switch to main network from testnet and start using a Cartographer to…
Browse files Browse the repository at this point in the history
… find XT nodes. Closes #41.
  • Loading branch information
mikehearn committed Jan 5, 2015
1 parent 55904b0 commit 3177ec7
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 158 deletions.
109 changes: 68 additions & 41 deletions client/src/main/java/lighthouse/Main.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lighthouse;

import com.google.common.base.*;
import com.google.common.io.*;
import com.google.common.util.concurrent.*;
import com.vinumeris.crashfx.*;
import com.vinumeris.updatefx.*;
Expand Down Expand Up @@ -40,8 +41,9 @@
import javax.annotation.*;
import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.logging.*;
Expand Down Expand Up @@ -135,6 +137,7 @@ public void start(Stage stage) throws Exception {
setupLogging();
log.info("\n\n{} {} starting up. It is {}\n", APP_NAME, VERSION, LHUtils.nowAsString());
log.info("App dir is {}. We have {} cores.", AppDirectory.dir(), Runtime.getRuntime().availableProcessors());
log.info("Command line arguments are: {}", String.join(" ", getParameters().getRaw()));
// Show the crash dialog for any exceptions that we don't handle and that hit the main loop.
CrashFX.setup();
// Set up the basic window with an empty UI stack, and put a quick splash there.
Expand Down Expand Up @@ -165,7 +168,7 @@ private boolean parseCommandLineArgs() {
"Usage: lighthouse [args] [filename.lighthouse-project...] %n" +
" --use-tor: Enable experimental Tor mode (may freeze up)%n" +
" --slow-gfx: Enable more eyecandy that may stutter on slow GFX cards%n" +
" --net={regtest,main,testnet}: Select Bitcoin network to operate on.%n" +
" --net={regtest,main,test}: Select Bitcoin network to operate on.%n" +
" --name=alice Name is put in titlebar and pledge filenames, useful for testing%n" +
" multiple instances on the same machine.%n" +
" --appdir=/path/to/dir Overrides the usual directory used, useful for testing multiple%n" +
Expand All @@ -181,18 +184,11 @@ private boolean parseCommandLineArgs() {

useTor = getParameters().getUnnamed().contains("--use-tor");

// TODO: Auto-detect adapter and configure this.
slowGFX = !getParameters().getUnnamed().contains("--slow-gfx");

// TODO: Reset to "production"
String netname = "test";
if (getParameters().getNamed().containsKey("net")) // e.g. regtest or testnet
netname = getParameters().getNamed().get("net");
params = NetworkParameters.fromID("org.bitcoin." + netname);
if (params == null) {
informationalAlert("Unknown network ID", "The --net parameter must be production, regtest or testnet");
return false;
}
// Handle network parameters.
if (!selectNetwork()) return false;

demoName = getParameters().getNamed().get("name");
String dir = getParameters().getNamed().get("appdir");
if (dir != null) {
Expand Down Expand Up @@ -224,6 +220,28 @@ private boolean parseCommandLineArgs() {
return true;
}

private boolean selectNetwork() {
String netname = "main";
if (getParameters().getNamed().containsKey("net")) // e.g. regtest or testnet
netname = getParameters().getNamed().get("net");
if (netname.equals("main"))
netname = "production";
params = NetworkParameters.fromID("org.bitcoin." + netname);
if (params == null) {
informationalAlert("Unknown network ID", "The --net parameter must be main, regtest or test");
return false;
}
// When not using testnet, use a subdirectory of the app directory to keep everything in, named after the
// network. This is an upgrade path for alpha testers who have a directory with wallets/blockchains/projects
// all on testnet.
if (!netname.equals("test")) {
Path path = AppDirectory.dir().resolve(netname);
uncheck(() -> Files.createDirectories(path));
AppDirectory.overrideAppDir(path);
}
return true;
}

private static Stopwatch globalStopwatch = Stopwatch.createStarted();
private static ThreadLocal<Stopwatch> threadStopwatch = ThreadLocal.withInitial(Stopwatch::createStarted);
private static ThreadLocal<Long> last = ThreadLocal.withInitial(() -> 0L);
Expand Down Expand Up @@ -335,52 +353,59 @@ protected void onSetupCompleted() {
vPeerGroup.setMinBroadcastConnections(1);
vPeerGroup.setUseLocalhostPeerWhenPossible(false);
} else {
// TODO: Replace this with a DNS seed that crawls for NODE_GETUTXOS (or whatever it's renamed to).
InetSocketAddress[] result = new InetSocketAddress[2];
result[0] = new InetSocketAddress("vinumeris.com", params.getPort());
result[1] = new InetSocketAddress("riker.plan99.net", params.getPort());

if (result[0].getAddress() == null && result[1].getAddress() == null) {
// Just a quick check to see if we can resolve DNS names.
if (new InetSocketAddress("google.com", 80).getAddress() == null) {
log.warn("User appears to be offline");
offline = true;
} else {
PeerDiscovery hardCodedPeers = new PeerDiscovery() {
@Override
public InetSocketAddress[] getPeers(long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException {
return result;
}

@Override
public void shutdown() {
}
};
vPeerGroup.addPeerDiscovery(hardCodedPeers);
vPeerGroup.setMaxConnections(2);
vPeerGroup.setConnectTimeoutMillis(10000);
// Sequence things so we *always* get both hard-coded peers for now.
vPeerGroup.waitForPeersOfVersion(2, GetUTXOsMessage.MIN_PROTOCOL_VERSION).addListener(() -> {
vPeerGroup.addPeerDiscovery(new DnsDiscovery(params));
vPeerGroup.setMaxConnections(6);
}, Threading.SAME_THREAD);
setupPeerGroup();
}
vPeerGroup.addEventListener(new AbstractPeerEventListener() {
@Override
public void onPeerConnected(Peer peer, int peerCount) {
if (peer.getAddress().getAddr().isLoopbackAddress() && !peer.getPeerVersionMessage().isGetUTXOsSupported()) {
// We connected to localhost but it doesn't have what we need.
log.warn("Localhost peer does not have support for NODE_GETUTXOS, ignoring");
// TODO: Once Bitcoin Core fork name is chosen and released, be more specific in this message.
informationalAlert("Local Bitcoin node not usable",
"You have a Bitcoin (Core) node running on your computer, but it doesn't have the protocol support %s needs. %s will still " +
"work but will use the peer to peer network instead, so you won't get upgraded security.",
"work but will use the peer to peer network instead, so you won't get upgraded security. " +
"Try installing Bitcoin XT, which is a modified version of Bitcoin Core that has the upgraded protocol support.",
APP_NAME);
vPeerGroup.setUseLocalhostPeerWhenPossible(false);
vPeerGroup.setMaxConnections(4);
setupPeerGroup();
}
}
});
}
}

private void setupPeerGroup() {
// We need to find some peers that support the getutxo message, so pick two found via the
// vinumeris.com seed with a custom query, then pick another four from the other DNS seeds
// (i.e. any bitcoin peer). There's unfortunately no way to instruct the other seeds to
// search for a subset of the Bitcoin network so that's why we need to use a new more flexible
// HTTP based protocol here. The seed will find Bitcoin XT nodes as people start and stop them.
//
// Hopefully in future more people will run HTTP seeds, then we can use a MultiplexingDiscovery
// to randomly merge their answers and reduce the influence of any one seed. Additionally if
// more people run Bitcoin XT nodes we can bump up the number we search for here to again
// reduce the influence of any one node. But this needs people to help decentralise.
PeerDiscovery disco = new HttpDiscovery(params,
unchecked(() -> new URI("http://main.seed.vinumeris.com:8081/peers?srvmask=3&getutxo=true")),
// auth key used to sign responses.
ECKey.fromPublicOnly(BaseEncoding.base16().decode(
"027a79143a4de36341494d21b6593015af6b2500e720ad2eda1c0b78165f4f38c4".toUpperCase()
)));
vPeerGroup.addPeerDiscovery(disco);
vPeerGroup.setMaxConnections(2);
vPeerGroup.setConnectTimeoutMillis(10000);
vPeerGroup.waitForPeersOfVersion(2, GetUTXOsMessage.MIN_PROTOCOL_VERSION).addListener(() -> {
vPeerGroup.addPeerDiscovery(new DnsDiscovery(params));
vPeerGroup.setMaxConnections(6);
// Six peers is a tradeoff between reliability, trust and need to be gentle with network
// resources. It could be higher and nothing would break though.
}, Threading.SAME_THREAD);
}
};
if (bitcoin.isChainFileLocked()) {
informationalAlert("Already running",
Expand All @@ -399,7 +424,7 @@ public void onPeerConnected(Peer peer, int peerCount) {
} else if (params == TestNet3Params.get()) {
bitcoin.setCheckpoints(getClass().getResourceAsStream("checkpoints.testnet"));
}
bitcoin.setPeerNodes(new PeerAddress[0]) // Hack to prevent WAK adding DnsDiscovery
bitcoin.setPeerNodes() // Hack to prevent WAK adding DnsDiscovery
.setBlockingStartup(false)
.setDownloadListener(MainWindow.bitcoinUIModel.getDownloadListener())
.setUserAgent(APP_NAME, "" + VERSION)
Expand Down Expand Up @@ -470,10 +495,12 @@ public void show() {
if (currentOverlay == null) {
uiStack.getChildren().add(stopClickPane);
uiStack.getChildren().add(ui);
// Workaround for crappy integrated graphics chips.
// Workaround for crappy GPUs and people running inside VMs that don't do OpenGL/D3D.
if (GuiUtils.isSoftwarePipeline()) {
brightnessAdjust(mainUI, 0.9);
} else {
// Gaussian blur a screenshot and then fade it in. This is much faster than animating the radius
// of the blur itself which is intensive even on fast GPUs.
WritableImage image = new WritableImage((int) scene.getWidth(), (int) scene.getHeight());
mainUI.setClip(new Rectangle(scene.getWidth(), scene.getHeight()));
ColorAdjust lighten = new ColorAdjust(0.0, 0.0, 0.7, 0.0);
Expand Down
88 changes: 35 additions & 53 deletions client/src/test/java/lighthouse/model/LighthouseBackendTest.java
Original file line number Diff line number Diff line change
@@ -1,58 +1,40 @@
package lighthouse.model;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.protobuf.ByteString;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import javafx.collections.ObservableList;
import javafx.collections.ObservableMap;
import javafx.collections.ObservableSet;
import javafx.collections.SetChangeListener;
import lighthouse.LighthouseBackend;
import lighthouse.files.AppDirectory;
import lighthouse.files.DiskManager;
import lighthouse.protocol.Ex;
import lighthouse.protocol.LHProtos;
import lighthouse.protocol.Project;
import lighthouse.protocol.TestUtils;
import lighthouse.threading.AffinityExecutor;
import lighthouse.wallet.PledgingWallet;
import com.google.common.collect.*;
import com.google.common.util.concurrent.*;
import com.google.protobuf.*;
import com.sun.net.httpserver.*;
import javafx.collections.*;
import lighthouse.*;
import lighthouse.files.*;
import lighthouse.protocol.*;
import lighthouse.threading.*;
import lighthouse.wallet.*;
import org.bitcoinj.core.*;
import org.bitcoinj.store.BlockStoreException;
import org.bitcoinj.testing.FakeTxBuilder;
import org.bitcoinj.testing.InboundMessageQueuer;
import org.bitcoinj.testing.TestWithPeerGroup;
import org.bitcoinj.utils.BriefLogFormatter;
import org.javatuples.Triplet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
import org.spongycastle.crypto.signers.ECDSASigner;

import javax.annotation.Nullable;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import static java.net.HttpURLConnection.HTTP_OK;
import static lighthouse.LighthouseBackend.Mode.CLIENT;
import org.bitcoinj.core.Message;
import org.bitcoinj.params.*;
import org.bitcoinj.store.*;
import org.bitcoinj.testing.*;
import org.bitcoinj.utils.*;
import org.javatuples.*;
import org.junit.*;
import org.spongycastle.crypto.params.*;
import org.spongycastle.crypto.signers.*;

import javax.annotation.*;
import java.io.*;
import java.math.*;
import java.net.*;
import java.nio.file.*;
import java.time.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;

import static java.net.HttpURLConnection.*;
import static lighthouse.LighthouseBackend.Mode.*;
import static lighthouse.protocol.LHUtils.*;
import static org.bitcoinj.testing.FakeTxBuilder.createFakeBlock;
import static org.bitcoinj.testing.FakeTxBuilder.*;
import static org.junit.Assert.*;

public class LighthouseBackendTest extends TestWithPeerGroup {
Expand Down Expand Up @@ -141,7 +123,7 @@ public Set<LHProtos.Pledge> getPledges() {
public void initCoreState() {
gate = new AffinityExecutor.Gate();
executor = new AffinityExecutor.ServiceAffinityExecutor("test thread");
diskManager = new DiskManager(executor);
diskManager = new DiskManager(TestNet3Params.get(), executor);
backend = new LighthouseBackend(CLIENT, peerGroup, blockChain, pledgingWallet, diskManager, executor);
backend.setMinPeersForUTXOQuery(1);
backend.setMaxJitterSeconds(0);
Expand Down Expand Up @@ -312,7 +294,7 @@ public void serverAndLocalAreDeduped() throws Exception {
executor.service.shutdown();
executor.service.awaitTermination(5, TimeUnit.SECONDS);
executor = new AffinityExecutor.ServiceAffinityExecutor("test thread 2");
diskManager = new DiskManager(executor);
diskManager = new DiskManager(TestNet3Params.get(), executor);
writeProjectToDisk();
backend = new LighthouseBackend(CLIENT, peerGroup, blockChain, pledgingWallet, diskManager, executor);

Expand Down
60 changes: 23 additions & 37 deletions common/src/main/java/lighthouse/LighthouseBackend.java
Original file line number Diff line number Diff line change
@@ -1,48 +1,34 @@
package lighthouse;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
import com.google.protobuf.ByteString;
import javafx.beans.InvalidationListener;
import javafx.beans.property.LongProperty;
import javafx.beans.property.SimpleLongProperty;
import com.google.common.util.concurrent.*;
import com.google.protobuf.*;
import javafx.beans.*;
import javafx.beans.property.*;
import javafx.collections.*;
import lighthouse.files.AppDirectory;
import lighthouse.files.DiskManager;
import lighthouse.files.*;
import lighthouse.protocol.*;
import lighthouse.threading.AffinityExecutor;
import lighthouse.threading.ObservableMirrors;
import lighthouse.wallet.PledgingWallet;
import net.jcip.annotations.GuardedBy;
import lighthouse.threading.*;
import lighthouse.wallet.*;
import net.jcip.annotations.*;
import org.bitcoinj.core.*;
import org.bitcoinj.params.RegTestParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.crypto.params.KeyParameter;

import javax.annotation.Nullable;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.Duration;
import org.bitcoinj.core.ProtocolException;
import org.bitcoinj.params.*;
import org.slf4j.*;
import org.spongycastle.crypto.params.*;

import javax.annotation.*;
import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.time.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.*;

import static com.google.common.base.Preconditions.*;
import static com.google.common.base.Throwables.getRootCause;
import static java.util.stream.Collectors.toMap;
import static com.google.common.base.Throwables.*;
import static java.util.stream.Collectors.*;
import static lighthouse.protocol.LHUtils.*;
import static lighthouse.utils.MoreBindings.mergeSets;
import static lighthouse.utils.MoreBindings.*;

/**
* Exposes observable data about pledges and projects that is based on combining the output of a wallet and
Expand Down Expand Up @@ -132,7 +118,7 @@ public LighthouseBackend(Mode mode, PeerGroup peerGroup, AbstractBlockChain chai
public LighthouseBackend(Mode mode, PeerGroup peerGroup, AbstractBlockChain chain, PledgingWallet wallet, AffinityExecutor.ServiceAffinityExecutor executor) {
// The disk manager should only auto load projects in server mode where we install/change them by dropping them
// into the server directory. But in client mode we always want explicit import.
this(mode, peerGroup, chain, wallet, new DiskManager(executor), executor);
this(mode, peerGroup, chain, wallet, new DiskManager(wallet.getParams(), executor), executor);
}

public LighthouseBackend(Mode mode, PeerGroup peerGroup, AbstractBlockChain chain, PledgingWallet wallet, DiskManager diskManager, AffinityExecutor.ServiceAffinityExecutor executor) {
Expand Down

0 comments on commit 3177ec7

Please sign in to comment.