mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 07:07:43 +01:00
Add code for WalletAppKit to WalletAppKitBitSquare
This commit is contained in:
parent
01dcc4f2dc
commit
d400573e9b
2 changed files with 541 additions and 12 deletions
|
@ -33,7 +33,6 @@ import io.bitsquare.user.Preferences;
|
|||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.crypto.DeterministicKey;
|
||||
import org.bitcoinj.crypto.TransactionSignature;
|
||||
import org.bitcoinj.kits.WalletAppKit;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.script.ScriptBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -98,7 +97,7 @@ public class TradeWalletService {
|
|||
@Nullable
|
||||
private Wallet wallet;
|
||||
@Nullable
|
||||
private WalletAppKit walletAppKit;
|
||||
private WalletAppKitBitSquare walletAppKit;
|
||||
@Nullable
|
||||
private KeyParameter aesKey;
|
||||
private AddressEntryList addressEntryList;
|
||||
|
@ -114,7 +113,7 @@ public class TradeWalletService {
|
|||
}
|
||||
|
||||
// After WalletService is initialized we get the walletAppKit set
|
||||
public void setWalletAppKit(WalletAppKit walletAppKit) {
|
||||
public void setWalletAppKit(WalletAppKitBitSquare walletAppKit) {
|
||||
this.walletAppKit = walletAppKit;
|
||||
wallet = walletAppKit.wallet();
|
||||
}
|
||||
|
|
|
@ -17,37 +17,507 @@
|
|||
|
||||
package io.bitsquare.btc;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.util.concurrent.AbstractIdleService;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.PeerGroup;
|
||||
import org.bitcoinj.kits.WalletAppKit;
|
||||
import com.subgraph.orchid.TorClient;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.net.BlockingClientManager;
|
||||
import org.bitcoinj.net.discovery.DnsDiscovery;
|
||||
import org.bitcoinj.net.discovery.PeerDiscovery;
|
||||
import org.bitcoinj.params.RegTestParams;
|
||||
import org.bitcoinj.protocols.channels.StoredPaymentChannelClientStates;
|
||||
import org.bitcoinj.protocols.channels.StoredPaymentChannelServerStates;
|
||||
import org.bitcoinj.store.BlockStore;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
import org.bitcoinj.store.SPVBlockStore;
|
||||
import org.bitcoinj.store.WalletProtobufSerializer;
|
||||
import org.bitcoinj.wallet.DeterministicSeed;
|
||||
import org.bitcoinj.wallet.KeyChainGroup;
|
||||
import org.bitcoinj.wallet.Protos;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.channels.FileLock;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class WalletAppKitBitSquare extends WalletAppKit {
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
|
||||
/**
|
||||
* Support multiple wallets and usage of Tor proxy.
|
||||
* <p>
|
||||
* Based on code from org.bitcoinj.kits.WalletAppKit but cannot subclass it as there are too many private access methods
|
||||
*/
|
||||
public class WalletAppKitBitSquare extends AbstractIdleService {
|
||||
protected static final Logger log = LoggerFactory.getLogger(WalletAppKitBitSquare.class);
|
||||
|
||||
protected final String filePrefix;
|
||||
protected final NetworkParameters params;
|
||||
protected volatile BlockChain vChain;
|
||||
protected volatile BlockStore vStore;
|
||||
protected volatile Wallet vWallet;
|
||||
protected volatile PeerGroup vPeerGroup;
|
||||
|
||||
protected final File directory;
|
||||
protected volatile File vWalletFile;
|
||||
|
||||
protected boolean useAutoSave = true;
|
||||
protected PeerAddress[] peerAddresses;
|
||||
protected PeerEventListener downloadListener;
|
||||
protected boolean autoStop = true;
|
||||
protected InputStream checkpoints;
|
||||
protected boolean blockingStartup = true;
|
||||
protected boolean useTor = false; // Perhaps in future we can change this to true.
|
||||
protected String userAgent, version;
|
||||
protected WalletProtobufSerializer.WalletFactory walletFactory;
|
||||
@Nullable
|
||||
protected DeterministicSeed restoreFromSeed;
|
||||
@Nullable
|
||||
protected PeerDiscovery discovery;
|
||||
|
||||
protected volatile Context context;
|
||||
private long bloomFilterTweak = 0;
|
||||
private double bloomFilterFPRate = -1;
|
||||
private int lookaheadSize = -1;
|
||||
|
||||
private Socks5Proxy socks5Proxy;
|
||||
|
||||
/**
|
||||
* Creates a new WalletAppKit, with a newly created {@link Context}. Files will be stored in the given directory.
|
||||
* Creates a new WalletAppKitBitSquare, with a newly created {@link Context}. Files will be stored in the given directory.
|
||||
*/
|
||||
public WalletAppKitBitSquare(NetworkParameters params, Socks5Proxy socks5Proxy, File directory, String filePrefix) {
|
||||
super(params, directory, filePrefix);
|
||||
this(new Context(params), directory, filePrefix);
|
||||
//super(params, directory, filePrefix);
|
||||
this.socks5Proxy = socks5Proxy;
|
||||
}
|
||||
|
||||
|
||||
public Socks5Proxy getProxy() {
|
||||
return socks5Proxy;
|
||||
}
|
||||
|
||||
protected PeerGroup createPeerGroup() throws TimeoutException {
|
||||
|
||||
/**
|
||||
* Creates a new WalletAppKitBitSquare, with a newly created {@link Context}. Files will be stored in the given directory.
|
||||
*/
|
||||
public WalletAppKitBitSquare(NetworkParameters params, File directory, String filePrefix) {
|
||||
this(new Context(params), directory, filePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new WalletAppKitBitSquare, with the given {@link Context}. Files will be stored in the given directory.
|
||||
*/
|
||||
public WalletAppKitBitSquare(Context context, File directory, String filePrefix) {
|
||||
this.context = context;
|
||||
this.params = checkNotNull(context.getParams());
|
||||
this.directory = checkNotNull(directory);
|
||||
this.filePrefix = checkNotNull(filePrefix);
|
||||
if (!Utils.isAndroidRuntime()) {
|
||||
InputStream stream = WalletAppKitBitSquare.class.getResourceAsStream("/" + params.getId() + ".checkpoints");
|
||||
if (stream != null)
|
||||
setCheckpoints(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will only connect to the given addresses. Cannot be called after startup.
|
||||
*/
|
||||
public WalletAppKitBitSquare setPeerNodes(PeerAddress... addresses) {
|
||||
checkState(state() == State.NEW, "Cannot call after startup");
|
||||
this.peerAddresses = addresses;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will only connect to localhost. Cannot be called after startup.
|
||||
*/
|
||||
public WalletAppKitBitSquare connectToLocalHost() {
|
||||
try {
|
||||
final InetAddress localHost = InetAddress.getLocalHost();
|
||||
return setPeerNodes(new PeerAddress(localHost, params.getPort()));
|
||||
} catch (UnknownHostException e) {
|
||||
// Borked machine with no loopback adapter configured properly.
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, the wallet will save itself to disk automatically whenever it changes.
|
||||
*/
|
||||
public WalletAppKitBitSquare setAutoSave(boolean value) {
|
||||
checkState(state() == State.NEW, "Cannot call after startup");
|
||||
useAutoSave = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If you want to learn about the sync process, you can provide a listener here. For instance, a
|
||||
* {@link org.bitcoinj.core.DownloadProgressTracker} is a good choice. This has no effect unless setBlockingStartup(false) has been called
|
||||
* too, due to some missing implementation code.
|
||||
*/
|
||||
public WalletAppKitBitSquare setDownloadListener(PeerEventListener listener) {
|
||||
this.downloadListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, will register a shutdown hook to stop the library. Defaults to true.
|
||||
*/
|
||||
public WalletAppKitBitSquare setAutoStop(boolean autoStop) {
|
||||
this.autoStop = autoStop;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set, the file is expected to contain a checkpoints file calculated with BuildCheckpoints. It makes initial
|
||||
* block sync faster for new users - please refer to the documentation on the bitcoinj website for further details.
|
||||
*/
|
||||
public WalletAppKitBitSquare setCheckpoints(InputStream checkpoints) {
|
||||
if (this.checkpoints != null)
|
||||
Utils.closeUnchecked(this.checkpoints);
|
||||
this.checkpoints = checkNotNull(checkpoints);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true (the default) then the startup of this service won't be considered complete until the network has been
|
||||
* brought up, peer connections established and the block chain synchronised. Therefore {@link #startAndWait()} can
|
||||
* potentially take a very long time. If false, then startup is considered complete once the network activity
|
||||
* begins and peer connections/block chain sync will continue in the background.
|
||||
*/
|
||||
public WalletAppKitBitSquare setBlockingStartup(boolean blockingStartup) {
|
||||
this.blockingStartup = blockingStartup;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the string that will appear in the subver field of the version message.
|
||||
*
|
||||
* @param userAgent A short string that should be the name of your app, e.g. "My Wallet"
|
||||
* @param version A short string that contains the version number, e.g. "1.0-BETA"
|
||||
*/
|
||||
public WalletAppKitBitSquare setUserAgent(String userAgent, String version) {
|
||||
this.userAgent = checkNotNull(userAgent);
|
||||
this.version = checkNotNull(version);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If called, then an embedded Tor client library will be used to connect to the P2P network. The user does not need
|
||||
* any additional software for this: it's all pure Java. As of April 2014 <b>this mode is experimental</b>.
|
||||
*/
|
||||
public WalletAppKitBitSquare useTor() {
|
||||
this.useTor = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a seed is set here then any existing wallet that matches the file name will be renamed to a backup name,
|
||||
* the chain file will be deleted, and the wallet object will be instantiated with the given seed instead of
|
||||
* a fresh one being created. This is intended for restoring a wallet from the original seed. To implement restore
|
||||
* you would shut down the existing appkit, if any, then recreate it with the seed given by the user, then start
|
||||
* up the new kit. The next time your app starts it should work as normal (that is, don't keep calling this each
|
||||
* time).
|
||||
*/
|
||||
public WalletAppKitBitSquare restoreWalletFromSeed(DeterministicSeed seed) {
|
||||
this.restoreFromSeed = seed;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the peer discovery class to use. If none is provided then DNS is used, which is a reasonable default.
|
||||
*/
|
||||
public WalletAppKitBitSquare setDiscovery(@Nullable PeerDiscovery discovery) {
|
||||
this.discovery = discovery;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WalletAppKitBitSquare setBloomFilterFalsePositiveRate(double bloomFilterFPRate) {
|
||||
this.bloomFilterFPRate = bloomFilterFPRate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WalletAppKitBitSquare setBloomFilterTweak(long bloomFilterTweak) {
|
||||
this.bloomFilterTweak = bloomFilterTweak;
|
||||
return this;
|
||||
}
|
||||
|
||||
public WalletAppKitBitSquare setLookaheadSize(int lookaheadSize) {
|
||||
this.lookaheadSize = lookaheadSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Override this to return wallet extensions if any are necessary.</p>
|
||||
* <p>
|
||||
* <p>When this is called, chain(), store(), and peerGroup() will return the created objects, however they are not
|
||||
* initialized/started.</p>
|
||||
*/
|
||||
protected List<WalletExtension> provideWalletExtensions() throws Exception {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this to use a {@link BlockStore} that isn't the default of {@link SPVBlockStore}.
|
||||
*/
|
||||
protected BlockStore provideBlockStore(File file) throws BlockStoreException {
|
||||
return new SPVBlockStore(params, file);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is invoked on a background thread after all objects are initialised, but before the peer group
|
||||
* or block chain download is started. You can tweak the objects configuration here.
|
||||
*/
|
||||
protected void onSetupCompleted() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if the spvchain file has an operating system file lock on it. Useful for checking if your app
|
||||
* is already running. If another copy of your app is running and you start the appkit anyway, an exception will
|
||||
* be thrown during the startup process. Returns false if the chain file does not exist or is a directory.
|
||||
*/
|
||||
public boolean isChainFileLocked() throws IOException {
|
||||
RandomAccessFile file2 = null;
|
||||
try {
|
||||
File file = new File(directory, filePrefix + ".spvchain");
|
||||
if (!file.exists())
|
||||
return false;
|
||||
if (file.isDirectory())
|
||||
return false;
|
||||
file2 = new RandomAccessFile(file, "rw");
|
||||
FileLock lock = file2.getChannel().tryLock();
|
||||
if (lock == null)
|
||||
return true;
|
||||
lock.release();
|
||||
return false;
|
||||
} finally {
|
||||
if (file2 != null)
|
||||
file2.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUp() throws Exception {
|
||||
// Runs in a separate thread.
|
||||
Context.propagate(context);
|
||||
if (!directory.exists()) {
|
||||
if (!directory.mkdirs()) {
|
||||
throw new IOException("Could not create directory " + directory.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
log.info("Starting up with directory = {}", directory);
|
||||
try {
|
||||
File chainFile = new File(directory, filePrefix + ".spvchain");
|
||||
boolean chainFileExists = chainFile.exists();
|
||||
vWalletFile = new File(directory, filePrefix + ".wallet");
|
||||
boolean shouldReplayWallet = (vWalletFile.exists() && !chainFileExists) || restoreFromSeed != null;
|
||||
vWallet = createOrLoadWallet(shouldReplayWallet);
|
||||
|
||||
// Initiate Bitcoin network objects (block store, blockchain and peer group)
|
||||
vStore = provideBlockStore(chainFile);
|
||||
if (!chainFileExists || restoreFromSeed != null) {
|
||||
if (checkpoints != null) {
|
||||
// Initialize the chain file with a checkpoint to speed up first-run sync.
|
||||
long time;
|
||||
if (restoreFromSeed != null) {
|
||||
time = restoreFromSeed.getCreationTimeSeconds();
|
||||
if (chainFileExists) {
|
||||
log.info("Deleting the chain file in preparation from restore.");
|
||||
vStore.close();
|
||||
if (!chainFile.delete())
|
||||
throw new IOException("Failed to delete chain file in preparation for restore.");
|
||||
vStore = new SPVBlockStore(params, chainFile);
|
||||
}
|
||||
} else {
|
||||
time = vWallet.getEarliestKeyCreationTime();
|
||||
}
|
||||
if (time > 0)
|
||||
CheckpointManager.checkpoint(params, checkpoints, vStore, time);
|
||||
else
|
||||
log.warn("Creating a new uncheckpointed block store due to a wallet with a creation time of zero: this will result in a very slow chain sync");
|
||||
} else if (chainFileExists) {
|
||||
log.info("Deleting the chain file in preparation from restore.");
|
||||
vStore.close();
|
||||
if (!chainFile.delete())
|
||||
throw new IOException("Failed to delete chain file in preparation for restore.");
|
||||
vStore = new SPVBlockStore(params, chainFile);
|
||||
}
|
||||
}
|
||||
vChain = new BlockChain(params, vStore);
|
||||
vPeerGroup = createPeerGroup();
|
||||
|
||||
if (bloomFilterFPRate != -1)
|
||||
vPeerGroup.setBloomFilterFalsePositiveRate(bloomFilterFPRate);
|
||||
|
||||
if (bloomFilterTweak != 0)
|
||||
vPeerGroup.setBloomFilterTweak(bloomFilterTweak);
|
||||
|
||||
if (this.userAgent != null)
|
||||
vPeerGroup.setUserAgent(userAgent, version);
|
||||
|
||||
// Set up peer addresses or discovery first, so if wallet extensions try to broadcast a transaction
|
||||
// before we're actually connected the broadcast waits for an appropriate number of connections.
|
||||
if (peerAddresses != null) {
|
||||
for (PeerAddress addr : peerAddresses) vPeerGroup.addAddress(addr);
|
||||
vPeerGroup.setMaxConnections(peerAddresses.length);
|
||||
peerAddresses = null;
|
||||
} else if (params != RegTestParams.get() && !useTor) {
|
||||
vPeerGroup.addPeerDiscovery(discovery != null ? discovery : new DnsDiscovery(params));
|
||||
}
|
||||
vChain.addWallet(vWallet);
|
||||
vPeerGroup.addWallet(vWallet);
|
||||
onSetupCompleted();
|
||||
|
||||
if (blockingStartup) {
|
||||
vPeerGroup.start();
|
||||
// Make sure we shut down cleanly.
|
||||
installShutdownHook();
|
||||
completeExtensionInitiations(vPeerGroup);
|
||||
|
||||
// TODO: Be able to use the provided download listener when doing a blocking startup.
|
||||
final DownloadProgressTracker listener = new DownloadProgressTracker();
|
||||
vPeerGroup.startBlockChainDownload(listener);
|
||||
listener.await();
|
||||
} else {
|
||||
Futures.addCallback(vPeerGroup.startAsync(), new FutureCallback() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable Object result) {
|
||||
completeExtensionInitiations(vPeerGroup);
|
||||
final PeerEventListener l = downloadListener == null ? new DownloadProgressTracker() : downloadListener;
|
||||
vPeerGroup.startBlockChainDownload(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (BlockStoreException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Wallet createOrLoadWallet(boolean shouldReplayWallet) throws Exception {
|
||||
Wallet wallet;
|
||||
|
||||
maybeMoveOldWalletOutOfTheWay();
|
||||
|
||||
if (vWalletFile.exists()) {
|
||||
wallet = loadWallet(shouldReplayWallet);
|
||||
} else {
|
||||
wallet = createWallet();
|
||||
wallet.freshReceiveKey();
|
||||
for (WalletExtension e : provideWalletExtensions()) {
|
||||
wallet.addExtension(e);
|
||||
}
|
||||
|
||||
// Currently the only way we can be sure that an extension is aware of its containing wallet is by
|
||||
// deserializing the extension (see WalletExtension#deserializeWalletExtension(Wallet, byte[]))
|
||||
// Hence, we first save and then load wallet to ensure any extensions are correctly initialized.
|
||||
wallet.saveToFile(vWalletFile);
|
||||
wallet = loadWallet(false);
|
||||
}
|
||||
|
||||
if (useAutoSave) wallet.autosaveToFile(vWalletFile, 5, TimeUnit.SECONDS, null);
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
private Wallet loadWallet(boolean shouldReplayWallet) throws Exception {
|
||||
Wallet wallet;
|
||||
FileInputStream walletStream = new FileInputStream(vWalletFile);
|
||||
try {
|
||||
List<WalletExtension> extensions = provideWalletExtensions();
|
||||
WalletExtension[] extArray = extensions.toArray(new WalletExtension[extensions.size()]);
|
||||
Protos.Wallet proto = WalletProtobufSerializer.parseToProto(walletStream);
|
||||
final WalletProtobufSerializer serializer;
|
||||
if (walletFactory != null)
|
||||
serializer = new WalletProtobufSerializer(walletFactory);
|
||||
else
|
||||
serializer = new WalletProtobufSerializer();
|
||||
wallet = serializer.readWallet(params, extArray, proto);
|
||||
if (shouldReplayWallet)
|
||||
wallet.reset();
|
||||
} finally {
|
||||
walletStream.close();
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
|
||||
protected Wallet createWallet() {
|
||||
KeyChainGroup kcg;
|
||||
if (restoreFromSeed != null)
|
||||
kcg = new KeyChainGroup(params, restoreFromSeed);
|
||||
else
|
||||
kcg = new KeyChainGroup(params);
|
||||
|
||||
if (lookaheadSize != -1)
|
||||
kcg.setLookaheadSize(lookaheadSize);
|
||||
|
||||
if (walletFactory != null) {
|
||||
return walletFactory.create(params, kcg);
|
||||
} else {
|
||||
return new Wallet(params, kcg); // default
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeMoveOldWalletOutOfTheWay() {
|
||||
if (restoreFromSeed == null) return;
|
||||
if (!vWalletFile.exists()) return;
|
||||
int counter = 1;
|
||||
File newName;
|
||||
do {
|
||||
newName = new File(vWalletFile.getParent(), "Backup " + counter + " for " + vWalletFile.getName());
|
||||
counter++;
|
||||
} while (newName.exists());
|
||||
log.info("Renaming old wallet file {} to {}", vWalletFile, newName);
|
||||
if (!vWalletFile.renameTo(newName)) {
|
||||
// This should not happen unless something is really messed up.
|
||||
throw new RuntimeException("Failed to rename wallet for restore");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* As soon as the transaction broadcaster han been created we will pass it to the
|
||||
* payment channel extensions
|
||||
*/
|
||||
private void completeExtensionInitiations(TransactionBroadcaster transactionBroadcaster) {
|
||||
StoredPaymentChannelClientStates clientStoredChannels = (StoredPaymentChannelClientStates)
|
||||
vWallet.getExtensions().get(StoredPaymentChannelClientStates.class.getName());
|
||||
if (clientStoredChannels != null) {
|
||||
clientStoredChannels.setTransactionBroadcaster(transactionBroadcaster);
|
||||
}
|
||||
StoredPaymentChannelServerStates serverStoredChannels = (StoredPaymentChannelServerStates)
|
||||
vWallet.getExtensions().get(StoredPaymentChannelServerStates.class.getName());
|
||||
if (serverStoredChannels != null) {
|
||||
serverStoredChannels.setTransactionBroadcaster(transactionBroadcaster);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected PeerGroup createPeerGroup() throws TimeoutException {
|
||||
// no proxy case.
|
||||
if (socks5Proxy == null) {
|
||||
return super.createPeerGroup();
|
||||
if (useTor) {
|
||||
TorClient torClient = new TorClient();
|
||||
torClient.getConfig().setDataDirectory(directory);
|
||||
return PeerGroup.newWithTor(params, vChain, torClient);
|
||||
} else
|
||||
return new PeerGroup(params, vChain);
|
||||
}
|
||||
|
||||
// proxy case.
|
||||
|
@ -65,4 +535,64 @@ public class WalletAppKitBitSquare extends WalletAppKit {
|
|||
|
||||
return peerGroup;
|
||||
}
|
||||
|
||||
private void installShutdownHook() {
|
||||
if (autoStop) Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
WalletAppKitBitSquare.this.stopAsync();
|
||||
WalletAppKitBitSquare.this.awaitTerminated();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutDown() throws Exception {
|
||||
// Runs in a separate thread.
|
||||
try {
|
||||
Context.propagate(context);
|
||||
vPeerGroup.stop();
|
||||
vWallet.saveToFile(vWalletFile);
|
||||
vStore.close();
|
||||
|
||||
vPeerGroup = null;
|
||||
vWallet = null;
|
||||
vStore = null;
|
||||
vChain = null;
|
||||
} catch (BlockStoreException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkParameters params() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public BlockChain chain() {
|
||||
checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete");
|
||||
return vChain;
|
||||
}
|
||||
|
||||
public BlockStore store() {
|
||||
checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete");
|
||||
return vStore;
|
||||
}
|
||||
|
||||
public Wallet wallet() {
|
||||
checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete");
|
||||
return vWallet;
|
||||
}
|
||||
|
||||
public PeerGroup peerGroup() {
|
||||
checkState(state() == State.STARTING || state() == State.RUNNING, "Cannot call until startup is complete");
|
||||
return vPeerGroup;
|
||||
}
|
||||
|
||||
public File directory() {
|
||||
return directory;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue