diff --git a/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java b/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java index 08ffd68e42..0cb56fa6a0 100644 --- a/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java +++ b/core/src/main/java/io/bitsquare/app/BitsquareEnvironment.java @@ -80,7 +80,7 @@ public class BitsquareEnvironment extends StandardEnvironment { private final String btcNetworkDir; private final String logLevel, providers; private BitcoinNetwork bitcoinNetwork; - private final String btcNodes, seedNodes, ignoreDevMsg, useTorForBtc, rpcUser, rpcPassword, rpcPort, + private final String btcNodes, seedNodes, ignoreDevMsg, useTorForBtc, rpcUser, rpcPassword, rpcPort, rpcBlockPort, rpcWalletPort, myAddress, banList, dumpStatistics, maxMemory, socks5ProxyBtcAddress, socks5ProxyHttpAddress; public BitsquareEnvironment(OptionSet options) { @@ -162,6 +162,13 @@ public class BitsquareEnvironment extends StandardEnvironment { rpcPort = commandLineProperties.containsProperty(RpcOptionKeys.RPC_PORT) ? (String) commandLineProperties.getProperty(RpcOptionKeys.RPC_PORT) : ""; + rpcBlockPort = commandLineProperties.containsProperty(RpcOptionKeys.RPC_BLOCK_PORT) ? + (String) commandLineProperties.getProperty(RpcOptionKeys.RPC_BLOCK_PORT) : + ""; + rpcWalletPort = commandLineProperties.containsProperty(RpcOptionKeys.RPC_WALLET_PORT) ? + (String) commandLineProperties.getProperty(RpcOptionKeys.RPC_WALLET_PORT) : + ""; + myAddress = commandLineProperties.containsProperty(NetworkOptionKeys.MY_ADDRESS) ? (String) commandLineProperties.getProperty(NetworkOptionKeys.MY_ADDRESS) : ""; @@ -258,6 +265,8 @@ public class BitsquareEnvironment extends StandardEnvironment { setProperty(RpcOptionKeys.RPC_USER, rpcUser); setProperty(RpcOptionKeys.RPC_PASSWORD, rpcPassword); setProperty(RpcOptionKeys.RPC_PORT, rpcPort); + setProperty(RpcOptionKeys.RPC_BLOCK_PORT, rpcBlockPort); + setProperty(RpcOptionKeys.RPC_WALLET_PORT, rpcWalletPort); setProperty(AppOptionKeys.BTC_NODES, btcNodes); setProperty(AppOptionKeys.USE_TOR_FOR_BTC, useTorForBtc); diff --git a/core/src/main/java/io/bitsquare/app/BitsquareExecutable.java b/core/src/main/java/io/bitsquare/app/BitsquareExecutable.java index 3d77a20b6a..aa57fb7caf 100644 --- a/core/src/main/java/io/bitsquare/app/BitsquareExecutable.java +++ b/core/src/main/java/io/bitsquare/app/BitsquareExecutable.java @@ -119,6 +119,10 @@ public abstract class BitsquareExecutable { .withRequiredArg(); parser.accepts(RpcOptionKeys.RPC_PORT, description("Bitcoind rpc port", "")) .withRequiredArg(); + parser.accepts(RpcOptionKeys.RPC_BLOCK_PORT, description("Bitcoind rpc port for block notifications", "")) + .withRequiredArg(); + parser.accepts(RpcOptionKeys.RPC_WALLET_PORT, description("Bitcoind rpc port for wallet notifications", "")) + .withRequiredArg(); parser.accepts(BtcOptionKeys.BTC_NETWORK, description("Bitcoin network", BitcoinNetwork.DEFAULT)) .withRequiredArg() diff --git a/core/src/main/java/io/bitsquare/btc/BitcoinModule.java b/core/src/main/java/io/bitsquare/btc/BitcoinModule.java index 2746c8f48c..f90dac7b51 100644 --- a/core/src/main/java/io/bitsquare/btc/BitcoinModule.java +++ b/core/src/main/java/io/bitsquare/btc/BitcoinModule.java @@ -23,7 +23,10 @@ import io.bitsquare.app.AppOptionKeys; import io.bitsquare.btc.provider.fee.FeeService; import io.bitsquare.btc.provider.price.PriceFeedService; import io.bitsquare.btc.provider.squ.SquUtxoFeedService; -import io.bitsquare.btc.wallet.*; +import io.bitsquare.btc.wallet.BtcWalletService; +import io.bitsquare.btc.wallet.SquWalletService; +import io.bitsquare.btc.wallet.TradeWalletService; +import io.bitsquare.btc.wallet.WalletsSetup; import io.bitsquare.http.HttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -66,7 +69,6 @@ public class BitcoinModule extends AppModule { bind(SquUtxoFeedService.class).in(Singleton.class); bind(PriceFeedService.class).in(Singleton.class); bind(FeeService.class).in(Singleton.class); - bind(SquUTXOProvider.class).in(Singleton.class); } } diff --git a/core/src/main/java/io/bitsquare/btc/wallet/BsDefaultCoinSelector.java b/core/src/main/java/io/bitsquare/btc/wallet/BsDefaultCoinSelector.java index 1c628a855a..59aded6003 100644 --- a/core/src/main/java/io/bitsquare/btc/wallet/BsDefaultCoinSelector.java +++ b/core/src/main/java/io/bitsquare/btc/wallet/BsDefaultCoinSelector.java @@ -45,7 +45,7 @@ public abstract class BsDefaultCoinSelector implements CoinSelector { ArrayList sortedOutputs = new ArrayList(candidates); // When calculating the wallet balance, we may be asked to select all possible coins, if so, avoid sorting // them in order to improve performance. - // TODO: Take in network parameters when instanatiated, and then test against the current network. Or just have a boolean parameter for "give me everything" + // TODO: Take in network parameters when instantiated, and then test against the current network. Or just have a boolean parameter for "give me everything" if (!target.equals(NetworkParameters.MAX_MONEY)) { sortOutputs(sortedOutputs); } diff --git a/core/src/main/java/io/bitsquare/btc/wallet/SquCoinSelector.java b/core/src/main/java/io/bitsquare/btc/wallet/SquCoinSelector.java index 5cebc660d1..3b63224504 100644 --- a/core/src/main/java/io/bitsquare/btc/wallet/SquCoinSelector.java +++ b/core/src/main/java/io/bitsquare/btc/wallet/SquCoinSelector.java @@ -17,13 +17,20 @@ package io.bitsquare.btc.wallet; +import io.bitsquare.dao.blockchain.SquUTXO; import org.bitcoinj.core.Transaction; import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.params.RegTestParams; +import org.bitcoinj.script.Script; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + /** * We use a specialized version of the CoinSelector based on the DefaultCoinSelector implementation. * We lookup for spendable outputs which matches our address of our address. @@ -33,18 +40,26 @@ class SquCoinSelector extends BsDefaultCoinSelector { private final boolean permitForeignPendingTx; + private Map> utxoSetByScriptMap = new HashMap<>(); + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor /////////////////////////////////////////////////////////////////////////////////////////// - public SquCoinSelector() { - this(true); - } - public SquCoinSelector(boolean permitForeignPendingTx) { this.permitForeignPendingTx = permitForeignPendingTx; } + public void setUtxoSet(Set utxoSet) { + utxoSet.stream().forEach(utxo -> { + Script script = utxo.getScript(); + if (!utxoSetByScriptMap.containsKey(script)) + utxoSetByScriptMap.put(script, new HashSet<>()); + + utxoSetByScriptMap.get(script).add(utxo); + }); + } + @Override protected boolean isSelectable(Transaction tx) { TransactionConfidence confidence = tx.getConfidence(); @@ -62,7 +77,12 @@ class SquCoinSelector extends BsDefaultCoinSelector { @Override protected boolean selectOutput(TransactionOutput transactionOutput) { - return (transactionOutput.getScriptPubKey().isSentToAddress() || - transactionOutput.getScriptPubKey().isPayToScriptHash()); + Script scriptPubKey = transactionOutput.getScriptPubKey(); + if (scriptPubKey.isSentToAddress() || scriptPubKey.isPayToScriptHash()) { + return utxoSetByScriptMap.containsKey(scriptPubKey); + } else { + log.warn("transactionOutput.getScriptPubKey() not isSentToAddress or isPayToScriptHash"); + return false; + } } } diff --git a/core/src/main/java/io/bitsquare/btc/wallet/SquUTXOProvider.java b/core/src/main/java/io/bitsquare/btc/wallet/SquUTXOProvider.java deleted file mode 100644 index e730cf3221..0000000000 --- a/core/src/main/java/io/bitsquare/btc/wallet/SquUTXOProvider.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of Bitsquare. - * - * Bitsquare is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Bitsquare is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Bitsquare. If not, see . - */ - -package io.bitsquare.btc.wallet; - -import io.bitsquare.user.Preferences; -import org.bitcoinj.core.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; -import java.util.*; - -public class SquUTXOProvider implements UTXOProvider { - private static final Logger log = LoggerFactory.getLogger(SquUTXOProvider.class); - - private Map> utxoSetByAddressMap = new HashMap<>(); - private NetworkParameters parameters; - - private int chainHeadHeight; - - @Inject - public SquUTXOProvider(Preferences preferences) { - this.parameters = preferences.getBitcoinNetwork().getParameters(); - } - - public void setUtxoSet(Set utxoSet) { - utxoSet.stream().forEach(utxo -> { - String address = utxo.getAddress(); - if (!utxoSetByAddressMap.containsKey(address)) - utxoSetByAddressMap.put(address, new HashSet<>()); - - utxoSetByAddressMap.get(address).add(utxo); - }); - - log.info("utxoSetByAddressMap " + utxoSetByAddressMap.toString()); - } - - @Override - public List getOpenTransactionOutputs(List
addresses) throws UTXOProviderException { - List result = new ArrayList<>(); - addresses.stream() - .filter(address -> utxoSetByAddressMap.containsKey(address.toString())) - .forEach(address -> result.addAll(utxoSetByAddressMap.get(address.toString()))); - return result; - } - - public void setChainHeadHeight(int chainHeadHeight) { - this.chainHeadHeight = chainHeadHeight; - } - - @Override - public int getChainHeadHeight() throws UTXOProviderException { - return chainHeadHeight; - } - - @Override - public NetworkParameters getParams() { - return parameters; - } -} diff --git a/core/src/main/java/io/bitsquare/btc/wallet/SquWalletService.java b/core/src/main/java/io/bitsquare/btc/wallet/SquWalletService.java index 45c69b1990..e03e56787f 100644 --- a/core/src/main/java/io/bitsquare/btc/wallet/SquWalletService.java +++ b/core/src/main/java/io/bitsquare/btc/wallet/SquWalletService.java @@ -52,7 +52,6 @@ public class SquWalletService extends WalletService { private static final Logger log = LoggerFactory.getLogger(SquWalletService.class); private final BlockchainService blockchainService; - private final SquUTXOProvider squUTXOProvider; private final SquCoinSelector squCoinSelector; @@ -63,23 +62,18 @@ public class SquWalletService extends WalletService { @Inject public SquWalletService(WalletsSetup walletsSetup, BlockchainService blockchainService, - SquUTXOProvider squUTXOProvider, Preferences preferences, FeeService feeService) { super(walletsSetup, preferences, feeService); this.blockchainService = blockchainService; - this.squUTXOProvider = squUTXOProvider; - this.squCoinSelector = new SquCoinSelector(); + this.squCoinSelector = new SquCoinSelector(true); walletsSetup.addSetupCompletedHandler(() -> { wallet = walletsSetup.getSquWallet(); wallet.setCoinSelector(squCoinSelector); - //TODO - wallet.setUTXOProvider(squUTXOProvider); - wallet.addEventListener(new BitsquareWalletEventListener()); wallet.addEventListener(new AbstractWalletEventListener() { @Override @@ -167,12 +161,11 @@ public class SquWalletService extends WalletService { } private void applyUtxoSetToUTXOProvider(Map> utxoByTxIdMap) { - squUTXOProvider.setChainHeadHeight(blockchainService.getChainHeadHeight()); - Set utxoSet = new HashSet<>(); + Set utxoSet = new HashSet<>(); utxoByTxIdMap.entrySet().stream() .forEach(e -> e.getValue().entrySet().stream() .forEach(u -> utxoSet.add(u.getValue()))); - squUTXOProvider.setUtxoSet(utxoSet); + squCoinSelector.setUtxoSet(utxoSet); } @@ -253,7 +246,6 @@ public class SquWalletService extends WalletService { public Transaction getPreparedBurnFeeTx(Coin fee) throws WalletException, TransactionVerificationException, InsufficientMoneyException, ChangeBelowDustException { Transaction tx = new Transaction(params); - SquCoinSelector squCoinSelector = new SquCoinSelector(); CoinSelection coinSelection = squCoinSelector.select(fee, getTransactionOutputsFromUtxoProvider()); coinSelection.gathered.stream().forEach(tx::addInput); Coin change = squCoinSelector.getChange(fee, coinSelection); diff --git a/core/src/main/java/io/bitsquare/dao/DaoModule.java b/core/src/main/java/io/bitsquare/dao/DaoModule.java index e7dc6f4604..3b7366e5ea 100644 --- a/core/src/main/java/io/bitsquare/dao/DaoModule.java +++ b/core/src/main/java/io/bitsquare/dao/DaoModule.java @@ -54,6 +54,8 @@ public class DaoModule extends AppModule { bindConstant().annotatedWith(named(RpcOptionKeys.RPC_USER)).to(env.getRequiredProperty(RpcOptionKeys.RPC_USER)); bindConstant().annotatedWith(named(RpcOptionKeys.RPC_PASSWORD)).to(env.getRequiredProperty(RpcOptionKeys.RPC_PASSWORD)); bindConstant().annotatedWith(named(RpcOptionKeys.RPC_PORT)).to(env.getRequiredProperty(RpcOptionKeys.RPC_PORT)); + bindConstant().annotatedWith(named(RpcOptionKeys.RPC_BLOCK_PORT)).to(env.getRequiredProperty(RpcOptionKeys.RPC_BLOCK_PORT)); + bindConstant().annotatedWith(named(RpcOptionKeys.RPC_WALLET_PORT)).to(env.getRequiredProperty(RpcOptionKeys.RPC_WALLET_PORT)); } } diff --git a/core/src/main/java/io/bitsquare/dao/blockchain/BlockchainRpcService.java b/core/src/main/java/io/bitsquare/dao/blockchain/BlockchainRpcService.java index d6b7c961ff..abc7d21e7f 100644 --- a/core/src/main/java/io/bitsquare/dao/blockchain/BlockchainRpcService.java +++ b/core/src/main/java/io/bitsquare/dao/blockchain/BlockchainRpcService.java @@ -62,6 +62,8 @@ public class BlockchainRpcService extends BlockchainService { private final String rpcUser; private final String rpcPassword; private final String rpcPort; + private final String rpcBlockPort; + private final String rpcWalletPort; private final ListeningExecutorService setupExecutorService = Utilities.getListeningExecutorService("BlockchainRpcService.setup", 1, 1, 5); private final ListeningExecutorService rpcRequestsExecutor = Utilities.getListeningExecutorService("BlockchainRpcService.requests", 1, 1, 10); @@ -75,10 +77,14 @@ public class BlockchainRpcService extends BlockchainService { @Inject public BlockchainRpcService(@Named(RpcOptionKeys.RPC_USER) String rpcUser, @Named(RpcOptionKeys.RPC_PASSWORD) String rpcPassword, - @Named(RpcOptionKeys.RPC_PORT) String rpcPort) { + @Named(RpcOptionKeys.RPC_PORT) String rpcPort, + @Named(RpcOptionKeys.RPC_BLOCK_PORT) String rpcBlockPort, + @Named(RpcOptionKeys.RPC_WALLET_PORT) String rpcWalletPort) { this.rpcUser = rpcUser; this.rpcPassword = rpcPassword; this.rpcPort = rpcPort; + this.rpcBlockPort = rpcBlockPort; + this.rpcWalletPort = rpcWalletPort; } @@ -98,9 +104,11 @@ public class BlockchainRpcService extends BlockchainService { try (FileInputStream fileInputStream = new FileInputStream(new File(resource.toURI()))) { try (InputStream inputStream = new BufferedInputStream(fileInputStream)) { nodeConfig.load(inputStream); - nodeConfig.setProperty("node.bitcoind.rpc.port", rpcPort); nodeConfig.setProperty("node.bitcoind.rpc.user", rpcUser); nodeConfig.setProperty("node.bitcoind.rpc.password", rpcPassword); + nodeConfig.setProperty("node.bitcoind.rpc.port", rpcPort); + nodeConfig.setProperty("node.bitcoind.notification.block.port", rpcBlockPort); + nodeConfig.setProperty("node.bitcoind.notification.wallet.port", rpcWalletPort); BtcdClientImpl client = new BtcdClientImpl(httpProvider, nodeConfig); daemon = new BtcdDaemonImpl(client); log.info("Setup took {} ms", System.currentTimeMillis() - startTs); diff --git a/core/src/main/java/io/bitsquare/dao/blockchain/BlockchainRpcServiceMain.java b/core/src/main/java/io/bitsquare/dao/blockchain/BlockchainRpcServiceMain.java index 218fae6d7e..2be90f56d8 100644 --- a/core/src/main/java/io/bitsquare/dao/blockchain/BlockchainRpcServiceMain.java +++ b/core/src/main/java/io/bitsquare/dao/blockchain/BlockchainRpcServiceMain.java @@ -32,7 +32,7 @@ public class BlockchainRpcServiceMain { Log.setLevel(Level.WARN); // regtest uses port 18332, mainnet 8332 - BlockchainRpcService blockchainRpcService = new BlockchainRpcService(args[0], args[1], args[2]); + BlockchainRpcService blockchainRpcService = new BlockchainRpcService(args[0], args[1], args[2], args[3], args[4]); blockchainRpcService.onAllServicesInitialized(); } } diff --git a/core/src/main/java/io/bitsquare/dao/blockchain/RpcOptionKeys.java b/core/src/main/java/io/bitsquare/dao/blockchain/RpcOptionKeys.java index 6aae95c32e..5e5dae96c5 100644 --- a/core/src/main/java/io/bitsquare/dao/blockchain/RpcOptionKeys.java +++ b/core/src/main/java/io/bitsquare/dao/blockchain/RpcOptionKeys.java @@ -4,4 +4,6 @@ public class RpcOptionKeys { public static final String RPC_USER = "rpcUser"; public static final String RPC_PASSWORD = "rpcPassword"; public static final String RPC_PORT = "rpcPort"; + public static final String RPC_BLOCK_PORT = "rpcBlockPort"; + public static final String RPC_WALLET_PORT = "rpcWalletPort"; } diff --git a/core/src/main/resources/btcRpcConfig.properties b/core/src/main/resources/btcRpcConfig.properties index dfc10700e8..5907e36315 100644 --- a/core/src/main/resources/btcRpcConfig.properties +++ b/core/src/main/resources/btcRpcConfig.properties @@ -1,12 +1,14 @@ node.bitcoind.rpc.protocol = http node.bitcoind.rpc.host = 127.0.0.1 node.bitcoind.http.auth_scheme = Basic -node.bitcoind.notification.alert.port = 5158 -node.bitcoind.notification.block.port = 5159 -node.bitcoind.notification.wallet.port = 5160 +#node.bitcoind.notification.alert.port = 5158 + # we pass the port/user/pw via prog arg +#node.bitcoind.notification.block.port = 5159 +#node.bitcoind.notification.wallet.port = 5160 + # regtest # node.bitcoind.rpc.port = 18332 # mainnet