mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-23 23:06:39 +01:00
Adjust code to work with BitcoinJ 0.14.4.1
This commit is contained in:
parent
9ab7cff156
commit
b805a795dd
32 changed files with 227 additions and 352 deletions
|
@ -395,13 +395,6 @@ public class Utilities {
|
||||||
Thread.currentThread().setName(name + "-" + new Random().nextInt(10000));
|
Thread.currentThread().setName(name + "-" + new Random().nextInt(10000));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void overwriteWithRandomBytes(byte[] bytes) {
|
|
||||||
Random random = new Random();
|
|
||||||
for (int i = 0; i < bytes.length; i++) {
|
|
||||||
bytes[i] = (byte) random.nextInt(Integer.MAX_VALUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isDirectory(String path) {
|
public static boolean isDirectory(String path) {
|
||||||
return new File(path).isDirectory();
|
return new File(path).isDirectory();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bitcoinj.core.Wallet;
|
|
||||||
import org.bitcoinj.crypto.DeterministicKey;
|
import org.bitcoinj.crypto.DeterministicKey;
|
||||||
|
import org.bitcoinj.wallet.Wallet;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -110,7 +110,9 @@ public class SeedPeersSocks5Dns implements PeerDiscovery {
|
||||||
* Returns an array containing all the Bitcoin nodes within the list.
|
* Returns an array containing all the Bitcoin nodes within the list.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress[] getPeers(long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException {
|
public InetSocketAddress[] getPeers(long services, long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException {
|
||||||
|
if (services != 0)
|
||||||
|
throw new PeerDiscoveryException("DNS seeds cannot filter by services: " + services);
|
||||||
try {
|
try {
|
||||||
return allPeers();
|
return allPeers();
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
|
|
|
@ -22,11 +22,7 @@ import org.bitcoinj.crypto.ChildNumber;
|
||||||
import org.bitcoinj.crypto.DeterministicKey;
|
import org.bitcoinj.crypto.DeterministicKey;
|
||||||
import org.bitcoinj.crypto.HDUtils;
|
import org.bitcoinj.crypto.HDUtils;
|
||||||
import org.bitcoinj.crypto.KeyCrypter;
|
import org.bitcoinj.crypto.KeyCrypter;
|
||||||
import org.bitcoinj.store.UnreadableWalletException;
|
import org.bitcoinj.wallet.*;
|
||||||
import org.bitcoinj.wallet.DeterministicKeyChain;
|
|
||||||
import org.bitcoinj.wallet.DeterministicSeed;
|
|
||||||
import org.bitcoinj.wallet.KeyChainFactory;
|
|
||||||
import org.bitcoinj.wallet.Protos;
|
|
||||||
|
|
||||||
class BisqKeyChainFactory implements KeyChainFactory {
|
class BisqKeyChainFactory implements KeyChainFactory {
|
||||||
private final boolean useBitcoinDeterministicKeyChain;
|
private final boolean useBitcoinDeterministicKeyChain;
|
||||||
|
|
|
@ -25,23 +25,20 @@ import java.security.SecureRandom;
|
||||||
|
|
||||||
class BisqKeyChainGroup extends KeyChainGroup {
|
class BisqKeyChainGroup extends KeyChainGroup {
|
||||||
private final boolean useBitcoinDeterministicKeyChain;
|
private final boolean useBitcoinDeterministicKeyChain;
|
||||||
private final int lookaheadSize;
|
|
||||||
|
|
||||||
public boolean isUseBitcoinDeterministicKeyChain() {
|
public boolean isUseBitcoinDeterministicKeyChain() {
|
||||||
return useBitcoinDeterministicKeyChain;
|
return useBitcoinDeterministicKeyChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BisqKeyChainGroup(NetworkParameters params, boolean useBitcoinDeterministicKeyChain, int lookaheadSize) {
|
public BisqKeyChainGroup(NetworkParameters params, boolean useBitcoinDeterministicKeyChain) {
|
||||||
super(params);
|
super(params);
|
||||||
this.useBitcoinDeterministicKeyChain = useBitcoinDeterministicKeyChain;
|
this.useBitcoinDeterministicKeyChain = useBitcoinDeterministicKeyChain;
|
||||||
this.lookaheadSize = lookaheadSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BisqKeyChainGroup(NetworkParameters params, DeterministicKeyChain chain, boolean useBitcoinDeterministicKeyChain, int lookaheadSize) {
|
public BisqKeyChainGroup(NetworkParameters params, DeterministicKeyChain chain, boolean useBitcoinDeterministicKeyChain) {
|
||||||
super(params, chain);
|
super(params, chain);
|
||||||
|
|
||||||
this.useBitcoinDeterministicKeyChain = useBitcoinDeterministicKeyChain;
|
this.useBitcoinDeterministicKeyChain = useBitcoinDeterministicKeyChain;
|
||||||
this.lookaheadSize = lookaheadSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -52,7 +49,6 @@ class BisqKeyChainGroup extends KeyChainGroup {
|
||||||
@Override
|
@Override
|
||||||
public void createAndActivateNewHDChain() {
|
public void createAndActivateNewHDChain() {
|
||||||
DeterministicKeyChain chain = useBitcoinDeterministicKeyChain ? new BtcDeterministicKeyChain(new SecureRandom()) : new BsqDeterministicKeyChain(new SecureRandom());
|
DeterministicKeyChain chain = useBitcoinDeterministicKeyChain ? new BtcDeterministicKeyChain(new SecureRandom()) : new BsqDeterministicKeyChain(new SecureRandom());
|
||||||
chain.setLookaheadSize(lookaheadSize);
|
|
||||||
addAndActivateHDChain(chain);
|
addAndActivateHDChain(chain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.bitcoinj.wallet.DeterministicKeyChain;
|
||||||
import org.bitcoinj.wallet.DeterministicSeed;
|
import org.bitcoinj.wallet.DeterministicSeed;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.spongycastle.crypto.params.KeyParameter;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
@ -33,8 +34,7 @@ class BsqDeterministicKeyChain extends DeterministicKeyChain {
|
||||||
|
|
||||||
// See https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
// See https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
|
||||||
// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
// https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
||||||
// We use 142 (0x8000008E) as coin_type for BSQ
|
// We have registered 142 (0x8000008E) as coin_type for BSQ
|
||||||
// TODO register
|
|
||||||
public static final ImmutableList<ChildNumber> BIP44_BSQ_ACCOUNT_PATH = ImmutableList.of(
|
public static final ImmutableList<ChildNumber> BIP44_BSQ_ACCOUNT_PATH = ImmutableList.of(
|
||||||
new ChildNumber(44, true),
|
new ChildNumber(44, true),
|
||||||
new ChildNumber(142, true),
|
new ChildNumber(142, true),
|
||||||
|
@ -56,6 +56,20 @@ class BsqDeterministicKeyChain extends DeterministicKeyChain {
|
||||||
super(seed);
|
super(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeterministicKeyChain toEncrypted(KeyCrypter keyCrypter, KeyParameter aesKey) {
|
||||||
|
return new BsqDeterministicKeyChain(keyCrypter, aesKey, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DeterministicKeyChain makeKeyChainFromSeed(DeterministicSeed seed) {
|
||||||
|
return new BsqDeterministicKeyChain(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BsqDeterministicKeyChain(KeyCrypter crypter, KeyParameter aesKey, DeterministicKeyChain chain) {
|
||||||
|
super(crypter, aesKey, chain);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ImmutableList<ChildNumber> getAccountPath() {
|
protected ImmutableList<ChildNumber> getAccountPath() {
|
||||||
return BIP44_BSQ_ACCOUNT_PATH;
|
return BIP44_BSQ_ACCOUNT_PATH;
|
||||||
|
|
|
@ -17,71 +17,13 @@
|
||||||
|
|
||||||
package io.bisq.core.btc.wallet;
|
package io.bisq.core.btc.wallet;
|
||||||
|
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
import org.bitcoinj.wallet.KeyChainGroup;
|
import org.bitcoinj.wallet.KeyChainGroup;
|
||||||
import org.slf4j.Logger;
|
import org.bitcoinj.wallet.Wallet;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
|
||||||
|
|
||||||
public class BsqWallet extends Wallet {
|
public class BsqWallet extends Wallet {
|
||||||
private static final Logger log = LoggerFactory.getLogger(BsqWallet.class);
|
|
||||||
|
|
||||||
public BsqWallet(NetworkParameters params, KeyChainGroup keyChainGroup) {
|
public BsqWallet(NetworkParameters params, KeyChainGroup keyChainGroup) {
|
||||||
super(params, keyChainGroup);
|
super(params, keyChainGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the spendable candidates from the {@link UTXOProvider} based on keys that the wallet contains.
|
|
||||||
*
|
|
||||||
* @return The list of candidates.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected List<TransactionOutput> calculateAllSpendCandidatesFromUTXOProvider(boolean excludeImmatureCoinbases) {
|
|
||||||
checkState(lock.isHeldByCurrentThread());
|
|
||||||
UTXOProvider utxoProvider = checkNotNull(vUTXOProvider, "No UTXO provider has been set");
|
|
||||||
// We might get duplicate outputs from the provider and from our pending tx outputs
|
|
||||||
// To avoid duplicate entries we use a set.
|
|
||||||
Set<TransactionOutput> candidates = new HashSet<>();
|
|
||||||
try {
|
|
||||||
int chainHeight = utxoProvider.getChainHeadHeight();
|
|
||||||
for (UTXO output : getStoredOutputsFromUTXOProvider()) {
|
|
||||||
boolean coinbase = output.isCoinbase();
|
|
||||||
int depth = chainHeight - output.getHeight() + 1; // the current depth of the output (1 = same as head).
|
|
||||||
// Do not try and spend coinbases that were mined too recently, the protocol forbids it.
|
|
||||||
if (!excludeImmatureCoinbases || !coinbase || depth >= params.getSpendableCoinbaseDepth()) {
|
|
||||||
candidates.add(new FreeStandingTransactionOutput(params, output, chainHeight));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (UTXOProviderException e) {
|
|
||||||
throw new RuntimeException("UTXO provider error", e);
|
|
||||||
}
|
|
||||||
// We need to handle the pending transactions that we know about.
|
|
||||||
for (Transaction tx : pending.values()) {
|
|
||||||
// Remove the spent outputs.
|
|
||||||
for (TransactionInput input : tx.getInputs()) {
|
|
||||||
TransactionOutput connectedOutput = input.getConnectedOutput();
|
|
||||||
if (connectedOutput != null && connectedOutput.isMine(this)) {
|
|
||||||
candidates.remove(connectedOutput);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add change outputs. Do not try and spend coinbases that were mined too recently, the protocol forbids it.
|
|
||||||
|
|
||||||
// We might get outputs from pending tx which we already got form the UTXP provider.
|
|
||||||
// As we use a set it will not lead to duplicate entries.
|
|
||||||
if (!excludeImmatureCoinbases || tx.isMature()) {
|
|
||||||
candidates.addAll(tx.getOutputs().stream()
|
|
||||||
.filter(output -> output.isAvailableForSpending() && output.isMine(this))
|
|
||||||
.collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ArrayList<>(candidates);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.*;
|
||||||
import org.bitcoinj.script.Script;
|
import org.bitcoinj.script.Script;
|
||||||
import org.bitcoinj.wallet.CoinSelection;
|
import org.bitcoinj.wallet.CoinSelection;
|
||||||
|
import org.bitcoinj.wallet.SendRequest;
|
||||||
|
import org.bitcoinj.wallet.Wallet;
|
||||||
|
import org.bitcoinj.wallet.listeners.AbstractWalletEventListener;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -275,9 +278,10 @@ public class BsqWalletService extends WalletService {
|
||||||
"The amount is too low (dust limit).");
|
"The amount is too low (dust limit).");
|
||||||
tx.addOutput(receiverAmount, new Address(params, receiverAddress));
|
tx.addOutput(receiverAmount, new Address(params, receiverAddress));
|
||||||
|
|
||||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
|
SendRequest sendRequest = SendRequest.forTx(tx);
|
||||||
sendRequest.fee = Coin.ZERO;
|
sendRequest.fee = Coin.ZERO;
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
sendRequest.shuffleOutputs = false;
|
sendRequest.shuffleOutputs = false;
|
||||||
sendRequest.signInputs = false;
|
sendRequest.signInputs = false;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.*;
|
||||||
import org.bitcoinj.params.RegTestParams;
|
import org.bitcoinj.params.RegTestParams;
|
||||||
import org.bitcoinj.wallet.CoinSelection;
|
import org.bitcoinj.wallet.CoinSelection;
|
||||||
|
import org.bitcoinj.wallet.Wallet;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.bitcoinj.wallet.DeterministicKeyChain;
|
||||||
import org.bitcoinj.wallet.DeterministicSeed;
|
import org.bitcoinj.wallet.DeterministicSeed;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.spongycastle.crypto.params.KeyParameter;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
@ -56,6 +57,19 @@ class BtcDeterministicKeyChain extends DeterministicKeyChain {
|
||||||
super(seed);
|
super(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeterministicKeyChain toEncrypted(KeyCrypter keyCrypter, KeyParameter aesKey) {
|
||||||
|
return new BtcDeterministicKeyChain(keyCrypter, aesKey, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DeterministicKeyChain makeKeyChainFromSeed(DeterministicSeed seed) {
|
||||||
|
return new BtcDeterministicKeyChain(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BtcDeterministicKeyChain(KeyCrypter crypter, KeyParameter aesKey, DeterministicKeyChain chain) {
|
||||||
|
super(crypter, aesKey, chain);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ImmutableList<ChildNumber> getAccountPath() {
|
protected ImmutableList<ChildNumber> getAccountPath() {
|
||||||
return BIP44_BTC_ACCOUNT_PATH;
|
return BIP44_BTC_ACCOUNT_PATH;
|
||||||
|
|
|
@ -31,6 +31,8 @@ import org.bitcoinj.core.*;
|
||||||
import org.bitcoinj.crypto.DeterministicKey;
|
import org.bitcoinj.crypto.DeterministicKey;
|
||||||
import org.bitcoinj.crypto.KeyCrypterScrypt;
|
import org.bitcoinj.crypto.KeyCrypterScrypt;
|
||||||
import org.bitcoinj.script.ScriptBuilder;
|
import org.bitcoinj.script.ScriptBuilder;
|
||||||
|
import org.bitcoinj.wallet.SendRequest;
|
||||||
|
import org.bitcoinj.wallet.Wallet;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -201,14 +203,16 @@ public class BtcWalletService extends WalletService {
|
||||||
tx.addOutput(forcedChangeValue, changeAddress);
|
tx.addOutput(forcedChangeValue, changeAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
|
SendRequest sendRequest = SendRequest.forTx(tx);
|
||||||
sendRequest.shuffleOutputs = false;
|
sendRequest.shuffleOutputs = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
// signInputs needs to be false as it would try to sign all inputs (BSQ inputs are not in this wallet)
|
// signInputs needs to be false as it would try to sign all inputs (BSQ inputs are not in this wallet)
|
||||||
sendRequest.signInputs = false;
|
sendRequest.signInputs = false;
|
||||||
sendRequest.ensureMinRequiredFee = false;
|
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
|
||||||
sendRequest.fee = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs);
|
sendRequest.fee = txFeePerByte.multiply(txSizeWithUnsignedInputs + sigSizePerInput * numInputs);
|
||||||
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
|
|
||||||
sendRequest.coinSelector = coinSelector;
|
sendRequest.coinSelector = coinSelector;
|
||||||
sendRequest.changeAddress = changeAddress;
|
sendRequest.changeAddress = changeAddress;
|
||||||
wallet.completeTx(sendRequest);
|
wallet.completeTx(sendRequest);
|
||||||
|
@ -461,7 +465,7 @@ public class BtcWalletService extends WalletService {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
int txSize = 0;
|
int txSize = 0;
|
||||||
Transaction tx;
|
Transaction tx;
|
||||||
Wallet.SendRequest sendRequest;
|
SendRequest sendRequest;
|
||||||
Coin txFeeForWithdrawalPerByte = getTxFeeForWithdrawalPerByte();
|
Coin txFeeForWithdrawalPerByte = getTxFeeForWithdrawalPerByte();
|
||||||
do {
|
do {
|
||||||
counter++;
|
counter++;
|
||||||
|
@ -472,9 +476,10 @@ public class BtcWalletService extends WalletService {
|
||||||
newTransaction.clearOutputs();
|
newTransaction.clearOutputs();
|
||||||
newTransaction.addOutput(amount.subtract(fee), toAddress);
|
newTransaction.addOutput(amount.subtract(fee), toAddress);
|
||||||
|
|
||||||
sendRequest = Wallet.SendRequest.forTx(newTransaction);
|
sendRequest = SendRequest.forTx(newTransaction);
|
||||||
sendRequest.fee = fee;
|
sendRequest.fee = fee;
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
sendRequest.coinSelector = new BtcCoinSelector(toAddress);
|
sendRequest.coinSelector = new BtcCoinSelector(toAddress);
|
||||||
sendRequest.changeAddress = toAddress;
|
sendRequest.changeAddress = toAddress;
|
||||||
|
@ -491,9 +496,10 @@ public class BtcWalletService extends WalletService {
|
||||||
|
|
||||||
Wallet.SendResult sendResult = null;
|
Wallet.SendResult sendResult = null;
|
||||||
try {
|
try {
|
||||||
sendRequest = Wallet.SendRequest.forTx(newTransaction);
|
sendRequest = SendRequest.forTx(newTransaction);
|
||||||
sendRequest.fee = fee;
|
sendRequest.fee = fee;
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
sendRequest.coinSelector = new BtcCoinSelector(toAddress);
|
sendRequest.coinSelector = new BtcCoinSelector(toAddress);
|
||||||
sendRequest.changeAddress = toAddress;
|
sendRequest.changeAddress = toAddress;
|
||||||
|
@ -506,9 +512,10 @@ public class BtcWalletService extends WalletService {
|
||||||
newTransaction.clearOutputs();
|
newTransaction.clearOutputs();
|
||||||
newTransaction.addOutput(amount, toAddress);
|
newTransaction.addOutput(amount, toAddress);
|
||||||
|
|
||||||
sendRequest = Wallet.SendRequest.forTx(newTransaction);
|
sendRequest = SendRequest.forTx(newTransaction);
|
||||||
sendRequest.fee = fee;
|
sendRequest.fee = fee;
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
sendRequest.coinSelector = new BtcCoinSelector(toAddress, false);
|
sendRequest.coinSelector = new BtcCoinSelector(toAddress, false);
|
||||||
sendRequest.changeAddress = toAddress;
|
sendRequest.changeAddress = toAddress;
|
||||||
|
@ -584,7 +591,7 @@ public class BtcWalletService extends WalletService {
|
||||||
if (fee.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) < 0)
|
if (fee.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) < 0)
|
||||||
fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
|
fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
|
||||||
|
|
||||||
Wallet.SendRequest sendRequest = getSendRequest(fromAddress, toAddress, amount, fee, aesKey, context);
|
SendRequest sendRequest = getSendRequest(fromAddress, toAddress, amount, fee, aesKey, context);
|
||||||
wallet.completeTx(sendRequest);
|
wallet.completeTx(sendRequest);
|
||||||
tx = sendRequest.tx;
|
tx = sendRequest.tx;
|
||||||
txSize = tx.bitcoinSerialize().length;
|
txSize = tx.bitcoinSerialize().length;
|
||||||
|
@ -634,7 +641,7 @@ public class BtcWalletService extends WalletService {
|
||||||
fee = txFeeForWithdrawalPerByte.multiply(txSize);
|
fee = txFeeForWithdrawalPerByte.multiply(txSize);
|
||||||
if (fee.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) < 0)
|
if (fee.compareTo(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE) < 0)
|
||||||
fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
|
fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE;
|
||||||
Wallet.SendRequest sendRequest = getSendRequestForMultipleAddresses(fromAddresses, toAddress, amount, fee, null, aesKey);
|
SendRequest sendRequest = getSendRequestForMultipleAddresses(fromAddresses, toAddress, amount, fee, null, aesKey);
|
||||||
wallet.completeTx(sendRequest);
|
wallet.completeTx(sendRequest);
|
||||||
tx = sendRequest.tx;
|
tx = sendRequest.tx;
|
||||||
txSize = tx.bitcoinSerialize().length;
|
txSize = tx.bitcoinSerialize().length;
|
||||||
|
@ -664,7 +671,7 @@ public class BtcWalletService extends WalletService {
|
||||||
AddressEntry.Context context,
|
AddressEntry.Context context,
|
||||||
FutureCallback<Transaction> callback) throws AddressFormatException,
|
FutureCallback<Transaction> callback) throws AddressFormatException,
|
||||||
AddressEntryException, InsufficientMoneyException {
|
AddressEntryException, InsufficientMoneyException {
|
||||||
Wallet.SendRequest sendRequest = getSendRequest(fromAddress, toAddress, receiverAmount, fee, aesKey, context);
|
SendRequest sendRequest = getSendRequest(fromAddress, toAddress, receiverAmount, fee, aesKey, context);
|
||||||
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
|
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
|
||||||
Futures.addCallback(sendResult.broadcastComplete, callback);
|
Futures.addCallback(sendResult.broadcastComplete, callback);
|
||||||
|
|
||||||
|
@ -681,7 +688,7 @@ public class BtcWalletService extends WalletService {
|
||||||
FutureCallback<Transaction> callback) throws AddressFormatException,
|
FutureCallback<Transaction> callback) throws AddressFormatException,
|
||||||
AddressEntryException, InsufficientMoneyException {
|
AddressEntryException, InsufficientMoneyException {
|
||||||
|
|
||||||
Wallet.SendRequest request = getSendRequestForMultipleAddresses(fromAddresses, toAddress, receiverAmount, fee, changeAddress, aesKey);
|
SendRequest request = getSendRequestForMultipleAddresses(fromAddresses, toAddress, receiverAmount, fee, changeAddress, aesKey);
|
||||||
Wallet.SendResult sendResult = wallet.sendCoins(request);
|
Wallet.SendResult sendResult = wallet.sendCoins(request);
|
||||||
Futures.addCallback(sendResult.broadcastComplete, callback);
|
Futures.addCallback(sendResult.broadcastComplete, callback);
|
||||||
|
|
||||||
|
@ -689,21 +696,22 @@ public class BtcWalletService extends WalletService {
|
||||||
return sendResult.tx.getHashAsString();
|
return sendResult.tx.getHashAsString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Wallet.SendRequest getSendRequest(String fromAddress,
|
private SendRequest getSendRequest(String fromAddress,
|
||||||
String toAddress,
|
String toAddress,
|
||||||
Coin amount,
|
Coin amount,
|
||||||
Coin fee,
|
Coin fee,
|
||||||
@Nullable KeyParameter aesKey,
|
@Nullable KeyParameter aesKey,
|
||||||
AddressEntry.Context context) throws AddressFormatException,
|
AddressEntry.Context context) throws AddressFormatException,
|
||||||
AddressEntryException {
|
AddressEntryException {
|
||||||
Transaction tx = new Transaction(params);
|
Transaction tx = new Transaction(params);
|
||||||
Preconditions.checkArgument(Restrictions.isAboveDust(amount, fee),
|
Preconditions.checkArgument(Restrictions.isAboveDust(amount, fee),
|
||||||
"The amount is too low (dust limit).");
|
"The amount is too low (dust limit).");
|
||||||
tx.addOutput(amount.subtract(fee), new Address(params, toAddress));
|
tx.addOutput(amount.subtract(fee), new Address(params, toAddress));
|
||||||
|
|
||||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
|
SendRequest sendRequest = SendRequest.forTx(tx);
|
||||||
sendRequest.fee = fee;
|
sendRequest.fee = fee;
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
sendRequest.shuffleOutputs = false;
|
sendRequest.shuffleOutputs = false;
|
||||||
Optional<AddressEntry> addressEntry = findAddressEntry(fromAddress, context);
|
Optional<AddressEntry> addressEntry = findAddressEntry(fromAddress, context);
|
||||||
|
@ -717,21 +725,22 @@ public class BtcWalletService extends WalletService {
|
||||||
return sendRequest;
|
return sendRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Wallet.SendRequest getSendRequestForMultipleAddresses(Set<String> fromAddresses,
|
private SendRequest getSendRequestForMultipleAddresses(Set<String> fromAddresses,
|
||||||
String toAddress,
|
String toAddress,
|
||||||
Coin amount,
|
Coin amount,
|
||||||
Coin fee,
|
Coin fee,
|
||||||
@Nullable String changeAddress,
|
@Nullable String changeAddress,
|
||||||
@Nullable KeyParameter aesKey) throws
|
@Nullable KeyParameter aesKey) throws
|
||||||
AddressFormatException, AddressEntryException {
|
AddressFormatException, AddressEntryException {
|
||||||
Transaction tx = new Transaction(params);
|
Transaction tx = new Transaction(params);
|
||||||
checkArgument(Restrictions.isAboveDust(amount),
|
checkArgument(Restrictions.isAboveDust(amount),
|
||||||
"The amount is too low (dust limit).");
|
"The amount is too low (dust limit).");
|
||||||
tx.addOutput(amount.subtract(fee), new Address(params, toAddress));
|
tx.addOutput(amount.subtract(fee), new Address(params, toAddress));
|
||||||
|
|
||||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tx);
|
SendRequest sendRequest = SendRequest.forTx(tx);
|
||||||
sendRequest.fee = fee;
|
sendRequest.fee = fee;
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
sendRequest.shuffleOutputs = false;
|
sendRequest.shuffleOutputs = false;
|
||||||
Set<AddressEntry> addressEntries = fromAddresses.stream()
|
Set<AddressEntry> addressEntries = fromAddresses.stream()
|
||||||
|
|
|
@ -22,7 +22,6 @@ import com.google.common.util.concurrent.FutureCallback;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import io.bisq.common.app.Log;
|
import io.bisq.common.app.Log;
|
||||||
import io.bisq.common.util.Utilities;
|
|
||||||
import io.bisq.core.btc.AddressEntry;
|
import io.bisq.core.btc.AddressEntry;
|
||||||
import io.bisq.core.btc.InsufficientFundsException;
|
import io.bisq.core.btc.InsufficientFundsException;
|
||||||
import io.bisq.core.btc.data.InputsAndChangeOutput;
|
import io.bisq.core.btc.data.InputsAndChangeOutput;
|
||||||
|
@ -37,6 +36,8 @@ import org.bitcoinj.crypto.DeterministicKey;
|
||||||
import org.bitcoinj.crypto.TransactionSignature;
|
import org.bitcoinj.crypto.TransactionSignature;
|
||||||
import org.bitcoinj.script.Script;
|
import org.bitcoinj.script.Script;
|
||||||
import org.bitcoinj.script.ScriptBuilder;
|
import org.bitcoinj.script.ScriptBuilder;
|
||||||
|
import org.bitcoinj.wallet.SendRequest;
|
||||||
|
import org.bitcoinj.wallet.Wallet;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -125,10 +126,6 @@ public class TradeWalletService {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void setAesKey(@Nullable KeyParameter newAesKey) {
|
void setAesKey(@Nullable KeyParameter newAesKey) {
|
||||||
// Overwrite first with random bytes before setting to null
|
|
||||||
if (newAesKey == null && this.aesKey != null)
|
|
||||||
Utilities.overwriteWithRandomBytes(this.aesKey.getKey());
|
|
||||||
|
|
||||||
this.aesKey = newAesKey;
|
this.aesKey = newAesKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +173,7 @@ public class TradeWalletService {
|
||||||
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to
|
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to
|
||||||
// wait for 1 confirmation)
|
// wait for 1 confirmation)
|
||||||
// In case of double spend we will detect later in the trade process and use a ban score to penalize bad behaviour (not impl. yet)
|
// In case of double spend we will detect later in the trade process and use a ban score to penalize bad behaviour (not impl. yet)
|
||||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(tradingFeeTx);
|
SendRequest sendRequest = SendRequest.forTx(tradingFeeTx);
|
||||||
sendRequest.shuffleOutputs = false;
|
sendRequest.shuffleOutputs = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
if (useSavingsWallet)
|
if (useSavingsWallet)
|
||||||
|
@ -184,8 +181,10 @@ public class TradeWalletService {
|
||||||
else
|
else
|
||||||
sendRequest.coinSelector = new BtcCoinSelector(fundingAddress);
|
sendRequest.coinSelector = new BtcCoinSelector(fundingAddress);
|
||||||
// We use a fixed fee
|
// We use a fixed fee
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
|
||||||
sendRequest.fee = txFee;
|
sendRequest.fee = txFee;
|
||||||
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
|
|
||||||
// Change is optional in case of overpay or use of funds from savings wallet
|
// Change is optional in case of overpay or use of funds from savings wallet
|
||||||
sendRequest.changeAddress = changeAddress;
|
sendRequest.changeAddress = changeAddress;
|
||||||
|
@ -243,7 +242,7 @@ public class TradeWalletService {
|
||||||
// In case of double spend we will detect later in the trade process and use a ban score to penalize bad behaviour (not impl. yet)
|
// In case of double spend we will detect later in the trade process and use a ban score to penalize bad behaviour (not impl. yet)
|
||||||
|
|
||||||
// WalletService.printTx("preparedBsqTx", preparedBsqTx);
|
// WalletService.printTx("preparedBsqTx", preparedBsqTx);
|
||||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(preparedBsqTx);
|
SendRequest sendRequest = SendRequest.forTx(preparedBsqTx);
|
||||||
sendRequest.shuffleOutputs = false;
|
sendRequest.shuffleOutputs = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
if (useSavingsWallet)
|
if (useSavingsWallet)
|
||||||
|
@ -251,8 +250,10 @@ public class TradeWalletService {
|
||||||
else
|
else
|
||||||
sendRequest.coinSelector = new BtcCoinSelector(fundingAddress);
|
sendRequest.coinSelector = new BtcCoinSelector(fundingAddress);
|
||||||
// We use a fixed fee
|
// We use a fixed fee
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
|
||||||
sendRequest.fee = txFee;
|
sendRequest.fee = txFee;
|
||||||
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
|
|
||||||
sendRequest.signInputs = false;
|
sendRequest.signInputs = false;
|
||||||
|
|
||||||
// Change is optional in case of overpay or use of funds from savings wallet
|
// Change is optional in case of overpay or use of funds from savings wallet
|
||||||
|
@ -1166,12 +1167,13 @@ public class TradeWalletService {
|
||||||
private void addAvailableInputsAndChangeOutputs(Transaction transaction, Address address, Address changeAddress, Coin txFee) throws WalletException {
|
private void addAvailableInputsAndChangeOutputs(Transaction transaction, Address address, Address changeAddress, Coin txFee) throws WalletException {
|
||||||
try {
|
try {
|
||||||
// Lets let the framework do the work to find the right inputs
|
// Lets let the framework do the work to find the right inputs
|
||||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.forTx(transaction);
|
SendRequest sendRequest = SendRequest.forTx(transaction);
|
||||||
sendRequest.shuffleOutputs = false;
|
sendRequest.shuffleOutputs = false;
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
// We use a fixed fee
|
// We use a fixed fee
|
||||||
sendRequest.feePerKb = Coin.ZERO;
|
|
||||||
sendRequest.fee = txFee;
|
sendRequest.fee = txFee;
|
||||||
|
sendRequest.feePerKb = Coin.ZERO;
|
||||||
|
sendRequest.ensureMinRequiredFee = false;
|
||||||
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to wait for 1 confirmation)
|
// we allow spending of unconfirmed tx (double spend risk is low and usability would suffer if we need to wait for 1 confirmation)
|
||||||
sendRequest.coinSelector = new BtcCoinSelector(address);
|
sendRequest.coinSelector = new BtcCoinSelector(address);
|
||||||
// We use always the same address in a trade for all transactions
|
// We use always the same address in a trade for all transactions
|
||||||
|
|
|
@ -24,6 +24,8 @@ import com.google.common.util.concurrent.Futures;
|
||||||
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
|
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
|
||||||
import io.bisq.core.btc.ProxySocketFactory;
|
import io.bisq.core.btc.ProxySocketFactory;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.*;
|
||||||
|
import org.bitcoinj.core.listeners.DownloadProgressTracker;
|
||||||
|
import org.bitcoinj.core.listeners.PeerDataEventListener;
|
||||||
import org.bitcoinj.net.BlockingClientManager;
|
import org.bitcoinj.net.BlockingClientManager;
|
||||||
import org.bitcoinj.net.discovery.DnsDiscovery;
|
import org.bitcoinj.net.discovery.DnsDiscovery;
|
||||||
import org.bitcoinj.net.discovery.PeerDiscovery;
|
import org.bitcoinj.net.discovery.PeerDiscovery;
|
||||||
|
@ -33,11 +35,7 @@ import org.bitcoinj.params.TestNet3Params;
|
||||||
import org.bitcoinj.store.BlockStore;
|
import org.bitcoinj.store.BlockStore;
|
||||||
import org.bitcoinj.store.BlockStoreException;
|
import org.bitcoinj.store.BlockStoreException;
|
||||||
import org.bitcoinj.store.SPVBlockStore;
|
import org.bitcoinj.store.SPVBlockStore;
|
||||||
import org.bitcoinj.store.WalletProtobufSerializer;
|
import org.bitcoinj.wallet.*;
|
||||||
import org.bitcoinj.wallet.DeterministicKeyChain;
|
|
||||||
import org.bitcoinj.wallet.DeterministicSeed;
|
|
||||||
import org.bitcoinj.wallet.KeyChainGroup;
|
|
||||||
import org.bitcoinj.wallet.Protos;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -91,15 +89,13 @@ public class WalletConfig extends AbstractIdleService {
|
||||||
private volatile File vBsqWalletFile;
|
private volatile File vBsqWalletFile;
|
||||||
@Nullable
|
@Nullable
|
||||||
private DeterministicSeed seed;
|
private DeterministicSeed seed;
|
||||||
private int btcWalletLookaheadSize = -1;
|
|
||||||
private int bsqWalletLookaheadSize = -1;
|
|
||||||
|
|
||||||
private volatile BlockChain vChain;
|
private volatile BlockChain vChain;
|
||||||
private volatile BlockStore vStore;
|
private volatile BlockStore vStore;
|
||||||
private volatile PeerGroup vPeerGroup;
|
private volatile PeerGroup vPeerGroup;
|
||||||
private boolean useAutoSave = true;
|
private boolean useAutoSave = true;
|
||||||
private PeerAddress[] peerAddresses;
|
private PeerAddress[] peerAddresses;
|
||||||
private PeerEventListener downloadListener;
|
private PeerDataEventListener downloadListener;
|
||||||
private boolean autoStop = true;
|
private boolean autoStop = true;
|
||||||
private InputStream checkpoints;
|
private InputStream checkpoints;
|
||||||
private boolean blockingStartup = true;
|
private boolean blockingStartup = true;
|
||||||
|
@ -108,8 +104,6 @@ public class WalletConfig extends AbstractIdleService {
|
||||||
private String version;
|
private String version;
|
||||||
@Nullable
|
@Nullable
|
||||||
private PeerDiscovery discovery;
|
private PeerDiscovery discovery;
|
||||||
private long bloomFilterTweak = 0;
|
|
||||||
private double bloomFilterFPRate = -1;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -226,12 +220,7 @@ public class WalletConfig extends AbstractIdleService {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public WalletConfig setDownloadListener(PeerDataEventListener listener) {
|
||||||
* 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 WalletConfig setDownloadListener(PeerEventListener listener) {
|
|
||||||
this.downloadListener = listener;
|
this.downloadListener = listener;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -298,26 +287,6 @@ public class WalletConfig extends AbstractIdleService {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WalletConfig setBloomFilterFalsePositiveRate(double bloomFilterFPRate) {
|
|
||||||
this.bloomFilterFPRate = bloomFilterFPRate;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WalletConfig setBloomFilterTweak(long bloomFilterTweak) {
|
|
||||||
this.bloomFilterTweak = bloomFilterTweak;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WalletConfig setBtcWalletLookaheadSize(int lookaheadSize) {
|
|
||||||
this.btcWalletLookaheadSize = lookaheadSize;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WalletConfig setBsqWalletLookaheadSize(int lookaheadSize) {
|
|
||||||
this.bsqWalletLookaheadSize = lookaheadSize;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Override this to return wallet extensions if any are necessary.</p>
|
* <p>Override this to return wallet extensions if any are necessary.</p>
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -388,18 +357,18 @@ public class WalletConfig extends AbstractIdleService {
|
||||||
boolean shouldReplayWallet = (vBtcWalletFile.exists() && !chainFileExists) || seed != null;
|
boolean shouldReplayWallet = (vBtcWalletFile.exists() && !chainFileExists) || seed != null;
|
||||||
BisqKeyChainGroup keyChainGroup;
|
BisqKeyChainGroup keyChainGroup;
|
||||||
if (seed != null)
|
if (seed != null)
|
||||||
keyChainGroup = new BisqKeyChainGroup(params, new BtcDeterministicKeyChain(seed), true, btcWalletLookaheadSize);
|
keyChainGroup = new BisqKeyChainGroup(params, new BtcDeterministicKeyChain(seed), true);
|
||||||
else
|
else
|
||||||
keyChainGroup = new BisqKeyChainGroup(params, true, btcWalletLookaheadSize);
|
keyChainGroup = new BisqKeyChainGroup(params, true);
|
||||||
vBtcWallet = createOrLoadWallet(vBtcWalletFile, shouldReplayWallet, keyChainGroup, false);
|
vBtcWallet = createOrLoadWallet(vBtcWalletFile, shouldReplayWallet, keyChainGroup, false, seed);
|
||||||
|
|
||||||
// BSQ walelt
|
// BSQ walelt
|
||||||
vBsqWalletFile = new File(directory, bsqWalletFileName);
|
vBsqWalletFile = new File(directory, bsqWalletFileName);
|
||||||
if (seed != null)
|
if (seed != null)
|
||||||
keyChainGroup = new BisqKeyChainGroup(params, new BsqDeterministicKeyChain(seed), false, bsqWalletLookaheadSize);
|
keyChainGroup = new BisqKeyChainGroup(params, new BsqDeterministicKeyChain(seed), false);
|
||||||
else
|
else
|
||||||
keyChainGroup = new BisqKeyChainGroup(params, new BsqDeterministicKeyChain(vBtcWallet.getKeyChainSeed()), false, bsqWalletLookaheadSize);
|
keyChainGroup = new BisqKeyChainGroup(params, new BsqDeterministicKeyChain(vBtcWallet.getKeyChainSeed()), false);
|
||||||
vBsqWallet = createOrLoadWallet(vBsqWalletFile, shouldReplayWallet, keyChainGroup, true);
|
vBsqWallet = createOrLoadWallet(vBsqWalletFile, shouldReplayWallet, keyChainGroup, true, seed);
|
||||||
|
|
||||||
// Initiate Bitcoin network objects (block store, blockchain and peer group)
|
// Initiate Bitcoin network objects (block store, blockchain and peer group)
|
||||||
vStore = provideBlockStore(chainFile);
|
vStore = provideBlockStore(chainFile);
|
||||||
|
@ -438,12 +407,6 @@ public class WalletConfig extends AbstractIdleService {
|
||||||
vChain = new BlockChain(params, vStore);
|
vChain = new BlockChain(params, vStore);
|
||||||
vPeerGroup = createPeerGroup();
|
vPeerGroup = createPeerGroup();
|
||||||
|
|
||||||
if (bloomFilterFPRate != -1)
|
|
||||||
vPeerGroup.setBloomFilterFalsePositiveRate(bloomFilterFPRate);
|
|
||||||
|
|
||||||
if (bloomFilterTweak != 0)
|
|
||||||
vPeerGroup.setBloomFilterTweak(bloomFilterTweak);
|
|
||||||
|
|
||||||
if (this.userAgent != null)
|
if (this.userAgent != null)
|
||||||
vPeerGroup.setUserAgent(userAgent, version);
|
vPeerGroup.setUserAgent(userAgent, version);
|
||||||
|
|
||||||
|
@ -475,7 +438,7 @@ public class WalletConfig extends AbstractIdleService {
|
||||||
Futures.addCallback(vPeerGroup.startAsync(), new FutureCallback() {
|
Futures.addCallback(vPeerGroup.startAsync(), new FutureCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(@Nullable Object result) {
|
public void onSuccess(@Nullable Object result) {
|
||||||
final PeerEventListener listener = downloadListener == null ?
|
final PeerDataEventListener listener = downloadListener == null ?
|
||||||
new DownloadProgressTracker() : downloadListener;
|
new DownloadProgressTracker() : downloadListener;
|
||||||
vPeerGroup.startBlockChainDownload(listener);
|
vPeerGroup.startBlockChainDownload(listener);
|
||||||
}
|
}
|
||||||
|
@ -493,8 +456,11 @@ public class WalletConfig extends AbstractIdleService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Wallet createOrLoadWallet(File walletFile, boolean shouldReplayWallet,
|
private Wallet createOrLoadWallet(File walletFile, boolean shouldReplayWallet,
|
||||||
BisqKeyChainGroup keyChainGroup, boolean isBsqWallet)
|
BisqKeyChainGroup keyChainGroup, boolean isBsqWallet, DeterministicSeed seed)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
|
maybeMoveOldWalletOutOfTheWay(walletFile, seed);
|
||||||
|
|
||||||
Wallet wallet;
|
Wallet wallet;
|
||||||
if (walletFile.exists()) {
|
if (walletFile.exists()) {
|
||||||
wallet = loadWallet(walletFile, shouldReplayWallet, keyChainGroup.isUseBitcoinDeterministicKeyChain());
|
wallet = loadWallet(walletFile, shouldReplayWallet, keyChainGroup.isUseBitcoinDeterministicKeyChain());
|
||||||
|
@ -509,6 +475,22 @@ public class WalletConfig extends AbstractIdleService {
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void maybeMoveOldWalletOutOfTheWay(File vWalletFile, DeterministicSeed restoreFromSeed) {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Wallet loadWallet(File walletFile, boolean shouldReplayWallet, boolean useBitcoinDeterministicKeyChain) throws Exception {
|
private Wallet loadWallet(File walletFile, boolean shouldReplayWallet, boolean useBitcoinDeterministicKeyChain) throws Exception {
|
||||||
Wallet wallet;
|
Wallet wallet;
|
||||||
FileInputStream walletStream = new FileInputStream(walletFile);
|
FileInputStream walletStream = new FileInputStream(walletFile);
|
||||||
|
|
|
@ -21,7 +21,6 @@ import com.google.common.util.concurrent.FutureCallback;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import io.bisq.common.handlers.ErrorMessageHandler;
|
import io.bisq.common.handlers.ErrorMessageHandler;
|
||||||
import io.bisq.common.handlers.ResultHandler;
|
import io.bisq.common.handlers.ResultHandler;
|
||||||
import io.bisq.common.util.Utilities;
|
|
||||||
import io.bisq.core.btc.exceptions.TransactionVerificationException;
|
import io.bisq.core.btc.exceptions.TransactionVerificationException;
|
||||||
import io.bisq.core.btc.exceptions.WalletException;
|
import io.bisq.core.btc.exceptions.WalletException;
|
||||||
import io.bisq.core.btc.listeners.AddressConfidenceListener;
|
import io.bisq.core.btc.listeners.AddressConfidenceListener;
|
||||||
|
@ -38,6 +37,8 @@ import org.bitcoinj.script.Script;
|
||||||
import org.bitcoinj.signers.TransactionSigner;
|
import org.bitcoinj.signers.TransactionSigner;
|
||||||
import org.bitcoinj.utils.Threading;
|
import org.bitcoinj.utils.Threading;
|
||||||
import org.bitcoinj.wallet.*;
|
import org.bitcoinj.wallet.*;
|
||||||
|
import org.bitcoinj.wallet.listeners.AbstractWalletEventListener;
|
||||||
|
import org.bitcoinj.wallet.listeners.WalletEventListener;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -104,8 +105,6 @@ public abstract class WalletService {
|
||||||
|
|
||||||
void decryptWallet(@NotNull KeyParameter key) {
|
void decryptWallet(@NotNull KeyParameter key) {
|
||||||
wallet.decrypt(key);
|
wallet.decrypt(key);
|
||||||
// Overwrite first with random bytes before setting to null
|
|
||||||
Utilities.overwriteWithRandomBytes(key.getKey());
|
|
||||||
aesKey = null;
|
aesKey = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +312,7 @@ public abstract class WalletService {
|
||||||
List<TransactionConfidence> transactionConfidenceList = getOutputsWithConnectedOutputs(tx)
|
List<TransactionConfidence> transactionConfidenceList = getOutputsWithConnectedOutputs(tx)
|
||||||
.stream()
|
.stream()
|
||||||
.filter(WalletUtils::isOutputScriptConvertableToAddress)
|
.filter(WalletUtils::isOutputScriptConvertableToAddress)
|
||||||
.filter(output -> address.equals(WalletUtils.getAddressFromOutput(output)))
|
.filter(output -> address != null && address.equals(WalletUtils.getAddressFromOutput(output)))
|
||||||
.map(o -> tx.getConfidence())
|
.map(o -> tx.getConfidence())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
return getMostRecentConfidence(transactionConfidenceList);
|
return getMostRecentConfidence(transactionConfidenceList);
|
||||||
|
@ -375,6 +374,7 @@ public abstract class WalletService {
|
||||||
Coin balance = Coin.ZERO;
|
Coin balance = Coin.ZERO;
|
||||||
for (TransactionOutput output : transactionOutputs) {
|
for (TransactionOutput output : transactionOutputs) {
|
||||||
if (WalletUtils.isOutputScriptConvertableToAddress(output) &&
|
if (WalletUtils.isOutputScriptConvertableToAddress(output) &&
|
||||||
|
address != null &&
|
||||||
address.equals(WalletUtils.getAddressFromOutput(output)))
|
address.equals(WalletUtils.getAddressFromOutput(output)))
|
||||||
balance = balance.add(output.getValue());
|
balance = balance.add(output.getValue());
|
||||||
}
|
}
|
||||||
|
@ -387,6 +387,7 @@ public abstract class WalletService {
|
||||||
int outputs = 0;
|
int outputs = 0;
|
||||||
for (TransactionOutput output : transactionOutputs) {
|
for (TransactionOutput output : transactionOutputs) {
|
||||||
if (WalletUtils.isOutputScriptConvertableToAddress(output) &&
|
if (WalletUtils.isOutputScriptConvertableToAddress(output) &&
|
||||||
|
address != null &&
|
||||||
address.equals(WalletUtils.getAddressFromOutput(output)))
|
address.equals(WalletUtils.getAddressFromOutput(output)))
|
||||||
outputs++;
|
outputs++;
|
||||||
}
|
}
|
||||||
|
@ -408,7 +409,8 @@ public abstract class WalletService {
|
||||||
|
|
||||||
public void emptyWallet(String toAddress, KeyParameter aesKey, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler)
|
public void emptyWallet(String toAddress, KeyParameter aesKey, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler)
|
||||||
throws InsufficientMoneyException, AddressFormatException {
|
throws InsufficientMoneyException, AddressFormatException {
|
||||||
Wallet.SendRequest sendRequest = Wallet.SendRequest.emptyWallet(new Address(params, toAddress));
|
SendRequest sendRequest = SendRequest.emptyWallet(Address.fromBase58(params, toAddress));
|
||||||
|
sendRequest.fee = Coin.ZERO;
|
||||||
sendRequest.feePerKb = getTxFeeForWithdrawalPerByte().multiply(1000);
|
sendRequest.feePerKb = getTxFeeForWithdrawalPerByte().multiply(1000);
|
||||||
sendRequest.aesKey = aesKey;
|
sendRequest.aesKey = aesKey;
|
||||||
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
|
Wallet.SendResult sendResult = wallet.sendCoins(sendRequest);
|
||||||
|
@ -550,11 +552,7 @@ public abstract class WalletService {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public static void printTx(String tracePrefix, Transaction tx) {
|
public static void printTx(String tracePrefix, Transaction tx) {
|
||||||
int size = tx.bitcoinSerialize().length;
|
log.info("\n" + tracePrefix + ":\n" + tx.toString());
|
||||||
log.info("\n" + tracePrefix + ":\n" +
|
|
||||||
tx.toString() +
|
|
||||||
"Satoshi/byte: " + (tx.getFee() != null ? tx.getFee().value / size : "No fee set yet") +
|
|
||||||
" (size: " + size + ")");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@ import com.google.inject.Inject;
|
||||||
import io.bisq.common.handlers.ExceptionHandler;
|
import io.bisq.common.handlers.ExceptionHandler;
|
||||||
import io.bisq.common.handlers.ResultHandler;
|
import io.bisq.common.handlers.ResultHandler;
|
||||||
import io.bisq.core.crypto.ScryptUtil;
|
import io.bisq.core.crypto.ScryptUtil;
|
||||||
import org.bitcoinj.core.Wallet;
|
|
||||||
import org.bitcoinj.crypto.KeyCrypter;
|
import org.bitcoinj.crypto.KeyCrypter;
|
||||||
import org.bitcoinj.crypto.KeyCrypterScrypt;
|
import org.bitcoinj.crypto.KeyCrypterScrypt;
|
||||||
import org.bitcoinj.wallet.DeterministicSeed;
|
import org.bitcoinj.wallet.DeterministicSeed;
|
||||||
|
import org.bitcoinj.wallet.Wallet;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.spongycastle.crypto.params.KeyParameter;
|
import org.spongycastle.crypto.params.KeyParameter;
|
||||||
|
|
|
@ -40,9 +40,11 @@ import io.bisq.network.Socks5ProxyProvider;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.*;
|
||||||
|
import org.bitcoinj.core.listeners.DownloadProgressTracker;
|
||||||
import org.bitcoinj.params.RegTestParams;
|
import org.bitcoinj.params.RegTestParams;
|
||||||
import org.bitcoinj.utils.Threading;
|
import org.bitcoinj.utils.Threading;
|
||||||
import org.bitcoinj.wallet.DeterministicSeed;
|
import org.bitcoinj.wallet.DeterministicSeed;
|
||||||
|
import org.bitcoinj.wallet.Wallet;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -105,7 +107,6 @@ public class WalletsSetup {
|
||||||
PersistenceProtoResolver persistenceProtoResolver,
|
PersistenceProtoResolver persistenceProtoResolver,
|
||||||
@Named(BtcOptionKeys.WALLET_DIR) File appDir,
|
@Named(BtcOptionKeys.WALLET_DIR) File appDir,
|
||||||
@Named(BtcOptionKeys.SOCKS5_DISCOVER_MODE) String socks5DiscoverModeString) {
|
@Named(BtcOptionKeys.SOCKS5_DISCOVER_MODE) String socks5DiscoverModeString) {
|
||||||
|
|
||||||
this.regTestHost = regTestHost;
|
this.regTestHost = regTestHost;
|
||||||
this.addressEntryList = addressEntryList;
|
this.addressEntryList = addressEntryList;
|
||||||
this.userAgent = userAgent;
|
this.userAgent = userAgent;
|
||||||
|
@ -117,6 +118,7 @@ public class WalletsSetup {
|
||||||
WalletUtils.setBitcoinNetwork(bisqEnvironment.getBitcoinNetwork());
|
WalletUtils.setBitcoinNetwork(bisqEnvironment.getBitcoinNetwork());
|
||||||
params = WalletUtils.getParameters();
|
params = WalletUtils.getParameters();
|
||||||
walletDir = new File(appDir, "bitcoin");
|
walletDir = new File(appDir, "bitcoin");
|
||||||
|
PeerGroup.setIgnoreHttpSeeds(true);
|
||||||
|
|
||||||
storage = new Storage<>(walletDir, persistenceProtoResolver);
|
storage = new Storage<>(walletDir, persistenceProtoResolver);
|
||||||
LongPersistable nonce = storage.initAndGetPersistedWithFileName("BloomFilterNonce");
|
LongPersistable nonce = storage.initAndGetPersistedWithFileName("BloomFilterNonce");
|
||||||
|
@ -152,7 +154,8 @@ public class WalletsSetup {
|
||||||
final Socks5Proxy socks5Proxy = preferences.getUseTorForBitcoinJ() ? socks5ProxyProvider.getSocks5Proxy() : null;
|
final Socks5Proxy socks5Proxy = preferences.getUseTorForBitcoinJ() ? socks5ProxyProvider.getSocks5Proxy() : null;
|
||||||
log.debug("Use socks5Proxy for bitcoinj: " + socks5Proxy);
|
log.debug("Use socks5Proxy for bitcoinj: " + socks5Proxy);
|
||||||
|
|
||||||
walletConfig = new WalletConfig(params, socks5Proxy, walletDir, BTC_WALLET_FILE_NAME, BSQ_WALLET_FILE_NAME, SPV_CHAIN_FILE_NAME) {
|
walletConfig = new WalletConfig(params, socks5Proxy, walletDir, BTC_WALLET_FILE_NAME,
|
||||||
|
BSQ_WALLET_FILE_NAME, SPV_CHAIN_FILE_NAME) {
|
||||||
@Override
|
@Override
|
||||||
protected void onSetupCompleted() {
|
protected void onSetupCompleted() {
|
||||||
//We are here in the btcj thread Thread[ STARTING,5,main]
|
//We are here in the btcj thread Thread[ STARTING,5,main]
|
||||||
|
@ -164,47 +167,15 @@ public class WalletsSetup {
|
||||||
if (preferences.getBitcoinNodes() != null && !preferences.getBitcoinNodes().isEmpty())
|
if (preferences.getBitcoinNodes() != null && !preferences.getBitcoinNodes().isEmpty())
|
||||||
peerGroup.setAddPeersFromAddressMessage(false);
|
peerGroup.setAddPeersFromAddressMessage(false);
|
||||||
|
|
||||||
peerGroup.addEventListener(new PeerEventListener() {
|
peerGroup.addConnectedEventListener((peer, peerCount) -> {
|
||||||
@Override
|
// We get called here on our user thread
|
||||||
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
|
numPeers.set(peerCount);
|
||||||
}
|
connectedPeers.set(peerGroup.getConnectedPeers());
|
||||||
|
});
|
||||||
@Override
|
peerGroup.addDisconnectedEventListener((peer, peerCount) -> {
|
||||||
public void onBlocksDownloaded(Peer peer, Block block, FilteredBlock filteredBlock, int blocksLeft) {
|
// We get called here on our user thread
|
||||||
}
|
numPeers.set(peerCount);
|
||||||
|
connectedPeers.set(peerGroup.getConnectedPeers());
|
||||||
@Override
|
|
||||||
public void onChainDownloadStarted(Peer peer, int blocksLeft) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPeerConnected(Peer peer, int peerCount) {
|
|
||||||
// We get called here on our user thread
|
|
||||||
numPeers.set(peerCount);
|
|
||||||
connectedPeers.set(peerGroup.getConnectedPeers());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
|
||||||
// We get called here on our user thread
|
|
||||||
numPeers.set(peerCount);
|
|
||||||
connectedPeers.set(peerGroup.getConnectedPeers());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Message onPreMessageReceived(Peer peer, Message m) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTransaction(Peer peer, Transaction t) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public List<Message> getData(Peer peer, GetDataMessage m) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Map to user thread
|
// Map to user thread
|
||||||
|
@ -219,9 +190,7 @@ public class WalletsSetup {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
configBloomfilter();
|
|
||||||
configPeerNodes(socks5Proxy);
|
configPeerNodes(socks5Proxy);
|
||||||
|
|
||||||
walletConfig.setDownloadListener(downloadListener)
|
walletConfig.setDownloadListener(downloadListener)
|
||||||
.setBlockingStartup(false)
|
.setBlockingStartup(false)
|
||||||
.setUserAgent(userAgent.getName(), userAgent.getVersion());
|
.setUserAgent(userAgent.getName(), userAgent.getVersion());
|
||||||
|
@ -233,7 +202,7 @@ public class WalletsSetup {
|
||||||
@Override
|
@Override
|
||||||
public void failed(@NotNull Service.State from, @NotNull Throwable failure) {
|
public void failed(@NotNull Service.State from, @NotNull Throwable failure) {
|
||||||
walletConfig = null;
|
walletConfig = null;
|
||||||
log.error("walletAppKit failed");
|
log.error("Service failure from state: {}; failure={}", from, failure);
|
||||||
timeoutTimer.stop();
|
timeoutTimer.stop();
|
||||||
UserThread.execute(() -> exceptionHandler.handleException(failure));
|
UserThread.execute(() -> exceptionHandler.handleException(failure));
|
||||||
}
|
}
|
||||||
|
@ -296,45 +265,6 @@ public class WalletsSetup {
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configBloomfilter() {
|
|
||||||
// Bloom filters in BitcoinJ are completely broken
|
|
||||||
// See: https://jonasnick.github.io/blog/2015/02/12/privacy-in-bitcoinj/
|
|
||||||
// Here are a few improvements to fix a few vulnerabilities.
|
|
||||||
|
|
||||||
// bisq's BitcoinJ fork has added a bloomFilterTweak (nonce) setter to reuse the same seed avoiding the trivial vulnerability
|
|
||||||
// by getting the real pub keys by intersections of several filters sent at each startup.
|
|
||||||
walletConfig.setBloomFilterTweak(bloomFilterTweak);
|
|
||||||
|
|
||||||
// Avoid the simple attack (see: https://jonasnick.github.io/blog/2015/02/12/privacy-in-bitcoinj/) due to the
|
|
||||||
// default implementation using both pubkey and hash of pubkey. We have set a insertPubKey flag in BasicKeyChain to default false.
|
|
||||||
|
|
||||||
// Default only 266 keys are generated (2 * 100+33 -> 100 external and 100 internal keys + buffers of 30%). That would trigger new bloom filters when we are reaching
|
|
||||||
// the threshold. To avoid reaching the threshold we create much more keys which are unlikely to cause update of the
|
|
||||||
// filter for most users. With lookaheadSize of 500 we get 1333 keys (500*1.3=666 666 external and 666 internal keys) which should be enough for most users to
|
|
||||||
// never need to update a bloom filter, which would weaken privacy.
|
|
||||||
// As we use 2 wallets (BTC, BSQ) we generate 1333 + 266 keys in total.
|
|
||||||
walletConfig.setBtcWalletLookaheadSize(100);
|
|
||||||
walletConfig.setBsqWalletLookaheadSize(100);
|
|
||||||
|
|
||||||
// Calculation is derived from: https://www.reddit.com/r/Bitcoin/comments/2vrx6n/privacy_in_bitcoinj_android_wallet_multibit_hive/coknjuz
|
|
||||||
// No. of false positives (56M keys in the blockchain):
|
|
||||||
// First attempt for FP rate:
|
|
||||||
// FP rate = 0,0001; No. of false positives: 0,0001 * 56 000 000 = 5600
|
|
||||||
// We have 1333keys: 1333 / (5600 + 1333) = 0.19 -> 19 % probability that a pub key is in our wallet
|
|
||||||
// After tests I found out that the bandwidth consumption varies widely related to the generated filter.
|
|
||||||
// About 20- 40 MB for upload and 30-130 MB for download at first start up (spv chain).
|
|
||||||
// Afterwards its about 1 MB for upload and 20-80 MB for download.
|
|
||||||
// Probably better then a high FP rate would be to include foreign pubKeyHashes which are tested to not be used
|
|
||||||
// in many transactions. If we had a pool of 100 000 such keys (2 MB data dump) to random select 4000 we could mix it with our
|
|
||||||
// 1000 own keys and get a similar probability rate as with the current setup but less variation in bandwidth
|
|
||||||
// consumption.
|
|
||||||
|
|
||||||
// For now to reduce risks with high bandwidth consumption we reduce the FP rate by half.
|
|
||||||
// FP rate = 0,00005; No. of false positives: 0,00005 * 56 000 000 = 2800
|
|
||||||
// 1333 / (2800 + 1333) = 0.32 -> 32 % probability that a pub key is in our wallet
|
|
||||||
walletConfig.setBloomFilterFalsePositiveRate(0.00005);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void configPeerNodes(Socks5Proxy socks5Proxy) {
|
private void configPeerNodes(Socks5Proxy socks5Proxy) {
|
||||||
String btcNodes = preferences.getBitcoinNodes();
|
String btcNodes = preferences.getBitcoinNodes();
|
||||||
log.debug("btcNodes: " + btcNodes);
|
log.debug("btcNodes: " + btcNodes);
|
||||||
|
|
|
@ -42,6 +42,7 @@ import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.Sha256Hash;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -79,9 +80,13 @@ public class ProcessModel implements Model, Serializable {
|
||||||
private String accountId;
|
private String accountId;
|
||||||
private PubKeyRing pubKeyRing;
|
private PubKeyRing pubKeyRing;
|
||||||
|
|
||||||
// Mutable
|
// Transient/Mutable
|
||||||
|
transient private Transaction takeOfferFeeTx;
|
||||||
@Setter
|
@Setter
|
||||||
transient private TradeMsg tradeMessage;
|
transient private TradeMsg tradeMessage;
|
||||||
|
|
||||||
|
// Mutable
|
||||||
|
private String takeOfferFeeTxId;
|
||||||
@Setter
|
@Setter
|
||||||
private byte[] payoutTxSignature;
|
private byte[] payoutTxSignature;
|
||||||
@Setter
|
@Setter
|
||||||
|
@ -98,8 +103,6 @@ public class ProcessModel implements Model, Serializable {
|
||||||
@Setter
|
@Setter
|
||||||
private String changeOutputAddress;
|
private String changeOutputAddress;
|
||||||
@Setter
|
@Setter
|
||||||
private Transaction takeOfferFeeTx;
|
|
||||||
@Setter
|
|
||||||
private boolean useSavingsWallet;
|
private boolean useSavingsWallet;
|
||||||
@Setter
|
@Setter
|
||||||
private long fundsNeededForTradeAsLong;
|
private long fundsNeededForTradeAsLong;
|
||||||
|
@ -166,7 +169,6 @@ public class ProcessModel implements Model, Serializable {
|
||||||
return paymentAccount != null ? paymentAccount.getPaymentAccountPayload() : null;
|
return paymentAccount != null ? paymentAccount.getPaymentAccountPayload() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean isPeersPaymentAccountDataAreBanned(PaymentAccountPayload paymentAccountPayload,
|
public boolean isPeersPaymentAccountDataAreBanned(PaymentAccountPayload paymentAccountPayload,
|
||||||
PaymentAccountFilter[] appliedPaymentAccountFilter) {
|
PaymentAccountFilter[] appliedPaymentAccountFilter) {
|
||||||
return filterManager.getFilter() != null &&
|
return filterManager.getFilter() != null &&
|
||||||
|
@ -195,4 +197,15 @@ public class ProcessModel implements Model, Serializable {
|
||||||
public Coin getFundsNeededForTradeAsLong() {
|
public Coin getFundsNeededForTradeAsLong() {
|
||||||
return Coin.valueOf(fundsNeededForTradeAsLong);
|
return Coin.valueOf(fundsNeededForTradeAsLong);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Transaction getTakeOfferFeeTx() {
|
||||||
|
if (takeOfferFeeTx == null)
|
||||||
|
takeOfferFeeTx = bsqWalletService.getTransaction(Sha256Hash.wrap(takeOfferFeeTxId));
|
||||||
|
return takeOfferFeeTx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTakeOfferFeeTx(Transaction takeOfferFeeTx) {
|
||||||
|
this.takeOfferFeeTx = takeOfferFeeTx;
|
||||||
|
takeOfferFeeTxId = takeOfferFeeTx.getHashAsString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,9 +137,6 @@
|
||||||
<urn>
|
<urn>
|
||||||
com.google.inject:guice:3.0:jar:null:compile:9d84f15fe35e2c716a02979fb62f50a29f38aefa
|
com.google.inject:guice:3.0:jar:null:compile:9d84f15fe35e2c716a02979fb62f50a29f38aefa
|
||||||
</urn>
|
</urn>
|
||||||
<urn>
|
|
||||||
com.google.protobuf:protobuf-java:2.5.0:jar:null:compile:a10732c76bfacdbd633a7eb0f7968b1059a65dfa
|
|
||||||
</urn>
|
|
||||||
<urn>
|
<urn>
|
||||||
com.google.zxing:core:2.0:jar:null:compile:001a5b8ccf93ca2fb7c40a94417f8485e3c8b4a6
|
com.google.zxing:core:2.0:jar:null:compile:001a5b8ccf93ca2fb7c40a94417f8485e3c8b4a6
|
||||||
</urn>
|
</urn>
|
||||||
|
@ -265,6 +262,9 @@
|
||||||
<urn>
|
<urn>
|
||||||
org.springframework:spring-test:4.1.1.RELEASE:jar:null:test:406ce9c05253f7dd75ac3f31170c71cca7419d8a
|
org.springframework:spring-test:4.1.1.RELEASE:jar:null:test:406ce9c05253f7dd75ac3f31170c71cca7419d8a
|
||||||
</urn>
|
</urn>
|
||||||
|
<urn>
|
||||||
|
com.google.protobuf:protobuf-java:3.2.0:jar:null:compile:62ccf171a106ff6791507f2d5364c275f9a3131d
|
||||||
|
</urn>
|
||||||
|
|
||||||
<!-- A check for the rules themselves -->
|
<!-- A check for the rules themselves -->
|
||||||
<urn>
|
<urn>
|
||||||
|
|
|
@ -32,7 +32,6 @@ import javafx.scene.control.TextField;
|
||||||
import javafx.scene.control.Tooltip;
|
import javafx.scene.control.Tooltip;
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.uri.BitcoinURI;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -156,8 +155,7 @@ public class AddressTextField extends AnchorPane {
|
||||||
log.warn("Amount must not be negative");
|
log.warn("Amount must not be negative");
|
||||||
setAmountAsCoin(Coin.ZERO);
|
setAmountAsCoin(Coin.ZERO);
|
||||||
}
|
}
|
||||||
|
return GUIUtil.getBitcoinURI(address.get(), amountAsCoin.get(),
|
||||||
return address.get() != null ? BitcoinURI.convertToBitcoinURI(address.get(), amountAsCoin.get(),
|
paymentLabel.get());
|
||||||
paymentLabel.get(), null) : "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
package io.bisq.gui.main.dao.wallet.receive;
|
package io.bisq.gui.main.dao.wallet.receive;
|
||||||
|
|
||||||
import io.bisq.common.UserThread;
|
|
||||||
import io.bisq.common.app.DevEnv;
|
import io.bisq.common.app.DevEnv;
|
||||||
import io.bisq.common.locale.Res;
|
import io.bisq.common.locale.Res;
|
||||||
import io.bisq.core.btc.wallet.BsqWalletService;
|
import io.bisq.core.btc.wallet.BsqWalletService;
|
||||||
|
@ -26,37 +25,21 @@ import io.bisq.gui.common.view.FxmlView;
|
||||||
import io.bisq.gui.components.AddressTextField;
|
import io.bisq.gui.components.AddressTextField;
|
||||||
import io.bisq.gui.components.InputTextField;
|
import io.bisq.gui.components.InputTextField;
|
||||||
import io.bisq.gui.main.dao.wallet.BsqBalanceUtil;
|
import io.bisq.gui.main.dao.wallet.BsqBalanceUtil;
|
||||||
import io.bisq.gui.main.overlays.windows.QRCodeWindow;
|
|
||||||
import io.bisq.gui.util.BsqFormatter;
|
import io.bisq.gui.util.BsqFormatter;
|
||||||
import io.bisq.gui.util.GUIUtil;
|
|
||||||
import io.bisq.gui.util.Layout;
|
import io.bisq.gui.util.Layout;
|
||||||
import javafx.geometry.Insets;
|
|
||||||
import javafx.scene.control.TextField;
|
|
||||||
import javafx.scene.control.Tooltip;
|
|
||||||
import javafx.scene.image.Image;
|
|
||||||
import javafx.scene.image.ImageView;
|
|
||||||
import javafx.scene.layout.GridPane;
|
import javafx.scene.layout.GridPane;
|
||||||
import net.glxn.qrgen.QRCode;
|
|
||||||
import net.glxn.qrgen.image.ImageType;
|
|
||||||
import org.bitcoinj.core.Address;
|
|
||||||
import org.bitcoinj.core.Coin;
|
|
||||||
import org.bitcoinj.uri.BitcoinURI;
|
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static io.bisq.gui.util.FormBuilder.*;
|
import static io.bisq.gui.util.FormBuilder.*;
|
||||||
|
|
||||||
@FxmlView
|
@FxmlView
|
||||||
public class BsqReceiveView extends ActivatableView<GridPane, Void> {
|
public class BsqReceiveView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
private ImageView qrCodeImageView;
|
|
||||||
private AddressTextField addressTextField;
|
private AddressTextField addressTextField;
|
||||||
private InputTextField amountTextField;
|
private InputTextField amountTextField;
|
||||||
private TextField balanceTextField;
|
|
||||||
private final BsqWalletService bsqWalletService;
|
private final BsqWalletService bsqWalletService;
|
||||||
private final BsqFormatter bsqFormatter;
|
private final BsqFormatter bsqFormatter;
|
||||||
private final BsqBalanceUtil bsqBalanceUtil;
|
private final BsqBalanceUtil bsqBalanceUtil;
|
||||||
|
@ -84,14 +67,6 @@ public class BsqReceiveView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
addTitledGroupBg(root, ++gridRow, 3, Res.get("dao.wallet.receive.fundYourWallet"), Layout.GROUP_DISTANCE);
|
addTitledGroupBg(root, ++gridRow, 3, Res.get("dao.wallet.receive.fundYourWallet"), Layout.GROUP_DISTANCE);
|
||||||
|
|
||||||
qrCodeImageView = new ImageView();
|
|
||||||
qrCodeImageView.setStyle("-fx-cursor: hand;");
|
|
||||||
Tooltip.install(qrCodeImageView, new Tooltip(Res.get("shared.openLargeQRWindow")));
|
|
||||||
GridPane.setRowIndex(qrCodeImageView, gridRow);
|
|
||||||
GridPane.setColumnIndex(qrCodeImageView, 1);
|
|
||||||
GridPane.setMargin(qrCodeImageView, new Insets(Layout.FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0));
|
|
||||||
root.getChildren().add(qrCodeImageView);
|
|
||||||
|
|
||||||
addressTextField = addLabelAddressTextField(root, ++gridRow, Res.getWithCol("shared.address")).second;
|
addressTextField = addLabelAddressTextField(root, ++gridRow, Res.getWithCol("shared.address")).second;
|
||||||
addressTextField.setPaymentLabel(paymentLabelString);
|
addressTextField.setPaymentLabel(paymentLabelString);
|
||||||
|
|
||||||
|
@ -106,47 +81,15 @@ public class BsqReceiveView extends ActivatableView<GridPane, Void> {
|
||||||
|
|
||||||
amountTextFieldSubscription = EasyBind.subscribe(amountTextField.textProperty(), t -> {
|
amountTextFieldSubscription = EasyBind.subscribe(amountTextField.textProperty(), t -> {
|
||||||
addressTextField.setAmountAsCoin(bsqFormatter.parseToCoin(t));
|
addressTextField.setAmountAsCoin(bsqFormatter.parseToCoin(t));
|
||||||
updateQRCode();
|
|
||||||
});
|
});
|
||||||
qrCodeImageView.setOnMouseClicked(e -> GUIUtil.showFeeInfoBeforeExecute(
|
|
||||||
() -> UserThread.runAfter(
|
|
||||||
() -> new QRCodeWindow(getBitcoinURI()).show(),
|
|
||||||
200, TimeUnit.MILLISECONDS)));
|
|
||||||
addressTextField.setAddress(bsqFormatter.getBsqAddressStringFromAddress(bsqWalletService.freshReceiveAddress()));
|
addressTextField.setAddress(bsqFormatter.getBsqAddressStringFromAddress(bsqWalletService.freshReceiveAddress()));
|
||||||
updateQRCode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
bsqBalanceUtil.deactivate();
|
bsqBalanceUtil.deactivate();
|
||||||
|
|
||||||
qrCodeImageView.setOnMouseClicked(null);
|
|
||||||
amountTextFieldSubscription.unsubscribe();
|
amountTextFieldSubscription.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateQRCode() {
|
|
||||||
if (addressTextField.getAddress() != null && !addressTextField.getAddress().isEmpty()) {
|
|
||||||
final byte[] imageBytes = QRCode
|
|
||||||
.from(getBitcoinURI())
|
|
||||||
.withSize(150, 150) // code has 41 elements 8 px is border with 150 we get 3x scale and min. border
|
|
||||||
.to(ImageType.PNG)
|
|
||||||
.stream()
|
|
||||||
.toByteArray();
|
|
||||||
Image qrImage = new Image(new ByteArrayInputStream(imageBytes));
|
|
||||||
qrCodeImageView.setImage(qrImage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Coin getAmountAsCoin() {
|
|
||||||
return bsqFormatter.parseToCoin(amountTextField.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getBitcoinURI() {
|
|
||||||
Address addressFromBsqAddress = bsqFormatter.getAddressFromBsqAddress(addressTextField.getAddress());
|
|
||||||
return BitcoinURI.convertToBitcoinURI(addressFromBsqAddress,
|
|
||||||
getAmountAsCoin(),
|
|
||||||
paymentLabelString,
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,6 @@ import net.glxn.qrgen.QRCode;
|
||||||
import net.glxn.qrgen.image.ImageType;
|
import net.glxn.qrgen.image.ImageType;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.uri.BitcoinURI;
|
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
@ -294,10 +293,9 @@ public class DepositView extends ActivatableView<VBox, Void> {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private String getBitcoinURI() {
|
private String getBitcoinURI() {
|
||||||
return BitcoinURI.convertToBitcoinURI(addressTextField.getAddress(),
|
return GUIUtil.getBitcoinURI(addressTextField.getAddress(),
|
||||||
getAmountAsCoin(),
|
getAmountAsCoin(),
|
||||||
paymentLabelString,
|
paymentLabelString);
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -58,8 +58,13 @@ import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.util.Callback;
|
import javafx.util.Callback;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.ECKey;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
|
import org.bitcoinj.core.TransactionConfidence;
|
||||||
import org.bitcoinj.script.Script;
|
import org.bitcoinj.script.Script;
|
||||||
|
import org.bitcoinj.wallet.Wallet;
|
||||||
|
import org.bitcoinj.wallet.listeners.WalletEventListener;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
|
@ -54,7 +54,11 @@ import javafx.scene.control.*;
|
||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.util.Callback;
|
import javafx.util.Callback;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.bitcoinj.core.*;
|
import org.bitcoinj.core.AddressFormatException;
|
||||||
|
import org.bitcoinj.core.Coin;
|
||||||
|
import org.bitcoinj.core.InsufficientMoneyException;
|
||||||
|
import org.bitcoinj.core.Transaction;
|
||||||
|
import org.bitcoinj.wallet.Wallet;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.spongycastle.crypto.params.KeyParameter;
|
import org.spongycastle.crypto.params.KeyParameter;
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,6 @@ import javafx.stage.Window;
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
import net.glxn.qrgen.QRCode;
|
import net.glxn.qrgen.QRCode;
|
||||||
import net.glxn.qrgen.image.ImageType;
|
import net.glxn.qrgen.image.ImageType;
|
||||||
import org.bitcoinj.uri.BitcoinURI;
|
|
||||||
import org.controlsfx.control.PopOver;
|
import org.controlsfx.control.PopOver;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
|
@ -1067,8 +1066,8 @@ public class CreateOfferView extends ActivatableViewAndModel<AnchorPane, CreateO
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private String getBitcoinURI() {
|
private String getBitcoinURI() {
|
||||||
return model.getAddressAsString() != null ? BitcoinURI.convertToBitcoinURI(model.getAddressAsString(), model.dataModel.getMissingCoin().get(),
|
return GUIUtil.getBitcoinURI(addressTextField.getAddress(), model.dataModel.getMissingCoin().get(),
|
||||||
model.getPaymentLabel(), null) : "";
|
model.getPaymentLabel());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAmountPriceFields() {
|
private void addAmountPriceFields() {
|
||||||
|
|
|
@ -61,7 +61,6 @@ import javafx.util.StringConverter;
|
||||||
import net.glxn.qrgen.QRCode;
|
import net.glxn.qrgen.QRCode;
|
||||||
import net.glxn.qrgen.image.ImageType;
|
import net.glxn.qrgen.image.ImageType;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.uri.BitcoinURI;
|
|
||||||
import org.controlsfx.control.PopOver;
|
import org.controlsfx.control.PopOver;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
import org.fxmisc.easybind.Subscription;
|
import org.fxmisc.easybind.Subscription;
|
||||||
|
@ -955,9 +954,9 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private String getBitcoinURI() {
|
private String getBitcoinURI() {
|
||||||
String addressString = model.dataModel.getAddressEntry().getAddressString();
|
return GUIUtil.getBitcoinURI(model.dataModel.getAddressEntry().getAddressString(),
|
||||||
return addressString != null ? BitcoinURI.convertToBitcoinURI(addressString, model.dataModel.missingCoin.get(),
|
model.dataModel.missingCoin.get(),
|
||||||
model.getPaymentLabel(), null) : "";
|
model.getPaymentLabel());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAmountPriceFields() {
|
private void addAmountPriceFields() {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import io.bisq.common.persistence.ListPersistable;
|
||||||
import io.bisq.common.proto.PersistenceProtoResolver;
|
import io.bisq.common.proto.PersistenceProtoResolver;
|
||||||
import io.bisq.common.storage.Storage;
|
import io.bisq.common.storage.Storage;
|
||||||
import io.bisq.common.util.Utilities;
|
import io.bisq.common.util.Utilities;
|
||||||
|
import io.bisq.core.btc.wallet.WalletUtils;
|
||||||
import io.bisq.core.payment.PaymentAccount;
|
import io.bisq.core.payment.PaymentAccount;
|
||||||
import io.bisq.core.user.DontShowAgainLookup;
|
import io.bisq.core.user.DontShowAgainLookup;
|
||||||
import io.bisq.core.user.Preferences;
|
import io.bisq.core.user.Preferences;
|
||||||
|
@ -50,8 +51,10 @@ import javafx.stage.FileChooser;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.util.StringConverter;
|
import javafx.util.StringConverter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.bitcoinj.core.Address;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.core.TransactionConfidence;
|
import org.bitcoinj.core.TransactionConfidence;
|
||||||
|
import org.bitcoinj.uri.BitcoinURI;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -382,4 +385,11 @@ public class GUIUtil {
|
||||||
component.setPrefHeight(available - initialOccupiedHeight.get());
|
component.setPrefHeight(available - initialOccupiedHeight.get());
|
||||||
}, 100, TimeUnit.MILLISECONDS);
|
}, 100, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getBitcoinURI(String address, Coin amount, String label) {
|
||||||
|
return address != null ?
|
||||||
|
BitcoinURI.convertToBitcoinURI(Address.fromBase58(WalletUtils.getParameters(),
|
||||||
|
address), amount, label, null) :
|
||||||
|
"";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,4 +75,14 @@ public class IOPParams extends NetworkParameters {
|
||||||
public boolean hasMaxMoney() {
|
public boolean hasMaxMoney() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BitcoinSerializer getSerializer(boolean parseRetain) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getProtocolVersionNum(ProtocolVersion version) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,4 +75,14 @@ public class PivxParams extends NetworkParameters {
|
||||||
public boolean hasMaxMoney() {
|
public boolean hasMaxMoney() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BitcoinSerializer getSerializer(boolean parseRetain) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getProtocolVersionNum(ProtocolVersion version) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,9 @@ public class Socks5DnsDiscovery extends MultiplexingDiscovery {
|
||||||
* Returns peer addresses. The actual DNS lookup is performed here.
|
* Returns peer addresses. The actual DNS lookup is performed here.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress[] getPeers(long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException {
|
public InetSocketAddress[] getPeers(long services, long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException {
|
||||||
|
if (services != 0)
|
||||||
|
throw new PeerDiscoveryException("DNS seeds cannot filter by services: " + services);
|
||||||
try {
|
try {
|
||||||
InetSocketAddress addr = new InetSocketAddress(DnsLookupTor.lookup(proxy, hostname), params.getPort());
|
InetSocketAddress addr = new InetSocketAddress(DnsLookupTor.lookup(proxy, hostname), params.getPort());
|
||||||
return new InetSocketAddress[]{addr};
|
return new InetSocketAddress[]{addr};
|
||||||
|
|
|
@ -69,11 +69,10 @@ public class Socks5MultiDiscovery implements PeerDiscovery {
|
||||||
* Returns an array containing all the Bitcoin nodes that have been discovered.
|
* Returns an array containing all the Bitcoin nodes that have been discovered.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress[] getPeers(long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException {
|
public InetSocketAddress[] getPeers(long services, long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException {
|
||||||
ArrayList<InetSocketAddress> list = new ArrayList<>();
|
ArrayList<InetSocketAddress> list = new ArrayList<>();
|
||||||
|
|
||||||
for (PeerDiscovery discovery : discoveryList) {
|
for (PeerDiscovery discovery : discoveryList) {
|
||||||
list.addAll(Arrays.asList(discovery.getPeers(timeoutValue, timeoutUnit)));
|
list.addAll(Arrays.asList(discovery.getPeers(services, timeoutValue, timeoutUnit)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.toArray(new InetSocketAddress[list.size()]);
|
return list.toArray(new InetSocketAddress[list.size()]);
|
||||||
|
|
|
@ -110,7 +110,9 @@ public class Socks5SeedOnionDiscovery implements PeerDiscovery {
|
||||||
* Returns an array containing all the Bitcoin nodes within the list.
|
* Returns an array containing all the Bitcoin nodes within the list.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress[] getPeers(long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException {
|
public InetSocketAddress[] getPeers(long services, long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException {
|
||||||
|
if (services != 0)
|
||||||
|
throw new PeerDiscoveryException("DNS seeds cannot filter by services: " + services);
|
||||||
return seedAddrs;
|
return seedAddrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -97,7 +97,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bitcoinj</groupId>
|
<groupId>org.bitcoinj</groupId>
|
||||||
<artifactId>bitcoinj-core</artifactId>
|
<artifactId>bitcoinj-core</artifactId>
|
||||||
<version>0.13.1.11</version>
|
<version>0.14.4.1</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>com.google.code.findbugs</groupId>
|
<groupId>com.google.code.findbugs</groupId>
|
||||||
|
|
Loading…
Add table
Reference in a new issue