diff --git a/gui/src/main/java/io/bitsquare/app/cli/BootstrapNode.java b/gui/src/main/java/io/bitsquare/app/bootstrap/BootstrapNode.java similarity index 99% rename from gui/src/main/java/io/bitsquare/app/cli/BootstrapNode.java rename to gui/src/main/java/io/bitsquare/app/bootstrap/BootstrapNode.java index 3ac6a27880..6b61548341 100644 --- a/gui/src/main/java/io/bitsquare/app/cli/BootstrapNode.java +++ b/gui/src/main/java/io/bitsquare/app/bootstrap/BootstrapNode.java @@ -15,7 +15,7 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.app.cli; +package io.bitsquare.app.bootstrap; import io.bitsquare.network.Node; diff --git a/gui/src/main/java/io/bitsquare/app/cli/BootstrapNodeMain.java b/gui/src/main/java/io/bitsquare/app/bootstrap/BootstrapNodeMain.java similarity index 97% rename from gui/src/main/java/io/bitsquare/app/cli/BootstrapNodeMain.java rename to gui/src/main/java/io/bitsquare/app/bootstrap/BootstrapNodeMain.java index 186dccbbf4..6f3ddd1fe3 100644 --- a/gui/src/main/java/io/bitsquare/app/cli/BootstrapNodeMain.java +++ b/gui/src/main/java/io/bitsquare/app/bootstrap/BootstrapNodeMain.java @@ -15,7 +15,7 @@ * along with Bitsquare. If not, see . */ -package io.bitsquare.app.cli; +package io.bitsquare.app.bootstrap; import io.bitsquare.app.BitsquareEnvironment; import io.bitsquare.app.BitsquareExecutable; diff --git a/gui/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java b/gui/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java index e8a31672d4..517faa8022 100644 --- a/gui/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java +++ b/gui/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java @@ -58,6 +58,7 @@ public class BitsquareAppMain extends BitsquareExecutable { // We don't want to do the full argument parsing here as that might easily change in update versions // So we only handle the absolute minimum which is APP_NAME, APP_DATA_DIR_KEY and USER_DATA_DIR OptionParser parser = new OptionParser(); + parser.allowsUnrecognizedOptions(); parser.accepts(USER_DATA_DIR_KEY, description("User data directory", DEFAULT_USER_DATA_DIR)) .withRequiredArg(); parser.accepts(APP_NAME_KEY, description("Application name", DEFAULT_APP_NAME)) diff --git a/gui/src/main/java/io/bitsquare/btc/AddressEntry.java b/gui/src/main/java/io/bitsquare/btc/AddressEntry.java index 797a7814ff..16e28f1ab4 100644 --- a/gui/src/main/java/io/bitsquare/btc/AddressEntry.java +++ b/gui/src/main/java/io/bitsquare/btc/AddressEntry.java @@ -24,6 +24,8 @@ import org.bitcoinj.crypto.DeterministicKey; import java.io.Serializable; +import java.util.Arrays; + /** * Is a minimalistic wallet abstraction used to separate transactions between different activities like: * Registration, trade and arbiter deposit. @@ -87,4 +89,16 @@ public class AddressEntry implements Serializable { TRADE, ARBITRATOR_DEPOSIT } + + @Override + public String toString() { + return "AddressEntry{" + + "addressString=" + getAddress().toString() + + "key=" + key + + ", params=" + params + + ", addressContext=" + addressContext + + ", offerId='" + offerId + '\'' + + ", pubKeyHash=" + Arrays.toString(pubKeyHash) + + '}'; + } } diff --git a/gui/src/main/java/io/bitsquare/btc/FeePolicy.java b/gui/src/main/java/io/bitsquare/btc/FeePolicy.java index dfadbe1980..c2fed1861b 100644 --- a/gui/src/main/java/io/bitsquare/btc/FeePolicy.java +++ b/gui/src/main/java/io/bitsquare/btc/FeePolicy.java @@ -55,8 +55,8 @@ public class FeePolicy { takeOfferFeeAddress = "1BVxNn3T12veSK6DgqwU4Hdn7QHcDDRag7"; break; case REGTEST: - createOfferFeeAddress = "n2upbsaKAe4PD3cc4JfS7UCqPC5oNd7Ckg"; - takeOfferFeeAddress = "n2upbsaKAe4PD3cc4JfS7UCqPC5oNd7Ckg"; + createOfferFeeAddress = "mmdXHjPSmLCAShckfQ1jwnLYpbP2pKKF7y"; + takeOfferFeeAddress = "mmdXHjPSmLCAShckfQ1jwnLYpbP2pKKF7y"; break; default: throw new BitsquareException("Unknown bitcoin network: %s", bitcoinNetwork); diff --git a/gui/src/main/java/io/bitsquare/btc/WalletService.java b/gui/src/main/java/io/bitsquare/btc/WalletService.java index b73d59e66d..a5600f5c93 100644 --- a/gui/src/main/java/io/bitsquare/btc/WalletService.java +++ b/gui/src/main/java/io/bitsquare/btc/WalletService.java @@ -534,8 +534,9 @@ public class WalletService { sendRequest.shuffleOutputs = false; // 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 AddressBasedCoinSelector(params, getAddressInfoByTradeID(offerId), true); - sendRequest.changeAddress = getAddressInfoByTradeID(offerId).getAddress(); + AddressEntry addressEntry = getAddressInfoByTradeID(offerId); + sendRequest.coinSelector = new AddressBasedCoinSelector(params, addressEntry, true); + sendRequest.changeAddress = addressEntry.getAddress(); wallet.completeTx(sendRequest); printInputs("payCreateOfferFee", tx); return tx; diff --git a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java index c822a7cff6..996ba9c551 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java +++ b/gui/src/main/java/io/bitsquare/gui/main/MainViewModel.java @@ -160,9 +160,9 @@ class MainViewModel implements ViewModel { error -> log.error(error.toString()), () -> Platform.runLater(() -> setBitcoinNetworkSyncProgress(1.0))); - Observable message = messageService.init(); - message.publish(); - message.subscribe( + Observable messageObservable = messageService.init(); + messageObservable.publish(); + messageObservable.subscribe( state -> Platform.runLater(() -> setBootstrapState(state)), error -> Platform.runLater(() -> { log.error(error.toString()); @@ -173,8 +173,8 @@ class MainViewModel implements ViewModel { }), () -> log.trace("message completed")); - Observable wallet = walletService.initialize(Platform::runLater); - wallet.subscribe( + Observable walletServiceObservable = walletService.initialize(Platform::runLater); + walletServiceObservable.subscribe( next -> { log.trace("wallet next"); }, @@ -186,8 +186,8 @@ class MainViewModel implements ViewModel { log.trace("wallet completed"); }); - Observable updateProcess = this.updateProcess.getProcess(); - updateProcess.subscribe(next -> { + Observable updateProcessObservable = this.updateProcess.getProcess(); + updateProcessObservable.subscribe(next -> { log.trace("updateProcess next"); }, error -> { @@ -197,7 +197,7 @@ class MainViewModel implements ViewModel { log.trace("updateProcess completed"); }); - Observable allTasks = Observable.merge(message, wallet, updateProcess); + Observable allTasks = Observable.merge(messageObservable, walletServiceObservable, updateProcessObservable); allTasks.subscribe( next -> { }, diff --git a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBook.java b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBook.java index d0753a084a..ede8d01773 100644 --- a/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBook.java +++ b/gui/src/main/java/io/bitsquare/gui/main/trade/offerbook/OfferBook.java @@ -21,7 +21,7 @@ import io.bitsquare.bank.BankAccount; import io.bitsquare.locale.Country; import io.bitsquare.locale.CurrencyUtil; import io.bitsquare.offer.Offer; -import io.bitsquare.offer.OfferRepository; +import io.bitsquare.offer.RemoteOfferBook; import io.bitsquare.user.User; import io.bitsquare.util.Utilities; @@ -50,11 +50,11 @@ public class OfferBook { private static final Logger log = LoggerFactory.getLogger(OfferBook.class); - private final OfferRepository offerRepository; + private final RemoteOfferBook remoteOfferBook; private final User user; private final ObservableList offerBookListItems = FXCollections.observableArrayList(); - private final OfferRepository.Listener offerRepositoryListener; + private final RemoteOfferBook.Listener remoteOfferBookListener; private final ChangeListener bankAccountChangeListener; private final ChangeListener invalidationListener; private String fiatCode; @@ -68,14 +68,14 @@ public class OfferBook { /////////////////////////////////////////////////////////////////////////////////////////// @Inject - OfferBook(OfferRepository offerRepository, User user) { - this.offerRepository = offerRepository; + OfferBook(RemoteOfferBook remoteOfferBook, User user) { + this.remoteOfferBook = remoteOfferBook; this.user = user; bankAccountChangeListener = (observableValue, oldValue, newValue) -> setBankAccount(newValue); invalidationListener = (ov, oldValue, newValue) -> requestOffers(); - offerRepositoryListener = new OfferRepository.Listener() { + remoteOfferBookListener = new RemoteOfferBook.Listener() { @Override public void onOfferAdded(Offer offer) { addOfferToOfferBookListItems(offer); @@ -142,15 +142,15 @@ public class OfferBook { private void addListeners() { log.debug("addListeners "); user.currentBankAccountProperty().addListener(bankAccountChangeListener); - offerRepository.addListener(offerRepositoryListener); - offerRepository.invalidationTimestampProperty().addListener(invalidationListener); + remoteOfferBook.addListener(remoteOfferBookListener); + remoteOfferBook.invalidationTimestampProperty().addListener(invalidationListener); } private void removeListeners() { log.debug("removeListeners "); user.currentBankAccountProperty().removeListener(bankAccountChangeListener); - offerRepository.removeListener(offerRepositoryListener); - offerRepository.invalidationTimestampProperty().removeListener(invalidationListener); + remoteOfferBook.removeListener(remoteOfferBookListener); + remoteOfferBook.invalidationTimestampProperty().removeListener(invalidationListener); } private void addOfferToOfferBookListItems(Offer offer) { @@ -160,7 +160,7 @@ public class OfferBook { } private void requestOffers() { - offerRepository.getOffers(fiatCode); + remoteOfferBook.getOffers(fiatCode); } @@ -173,11 +173,11 @@ public class OfferBook { addListeners(); setBankAccount(user.getCurrentBankAccount().get()); pollingTimer = Utilities.setInterval(3000, (animationTimer) -> { - offerRepository.requestInvalidationTimeStampFromDHT(fiatCode); + remoteOfferBook.requestInvalidationTimeStampFromDHT(fiatCode); return null; }); - offerRepository.getOffers(fiatCode); + remoteOfferBook.getOffers(fiatCode); } private void stopPolling() { diff --git a/gui/src/main/java/io/bitsquare/msg/tomp2p/BootstrappedPeerBuilder.java b/gui/src/main/java/io/bitsquare/msg/tomp2p/BootstrappedPeerBuilder.java index 1756ba825c..93d8c016c1 100644 --- a/gui/src/main/java/io/bitsquare/msg/tomp2p/BootstrappedPeerBuilder.java +++ b/gui/src/main/java/io/bitsquare/msg/tomp2p/BootstrappedPeerBuilder.java @@ -68,7 +68,7 @@ import io.netty.util.concurrent.DefaultEventExecutorGroup; /** * Creates a DHT peer and bootstraps to the network via a bootstrap node */ -class BootstrappedPeerBuilder { +public class BootstrappedPeerBuilder { private static final Logger log = LoggerFactory.getLogger(BootstrappedPeerBuilder.class); static final String BOOTSTRAP_NODE_KEY = "bootstrapNode"; diff --git a/gui/src/main/java/io/bitsquare/msg/tomp2p/TomP2PMessageService.java b/gui/src/main/java/io/bitsquare/msg/tomp2p/TomP2PMessageService.java index 7e9323b56d..8dd5be54ab 100644 --- a/gui/src/main/java/io/bitsquare/msg/tomp2p/TomP2PMessageService.java +++ b/gui/src/main/java/io/bitsquare/msg/tomp2p/TomP2PMessageService.java @@ -66,7 +66,7 @@ import rx.Observable; *

* TODO: improve callbacks that Platform.runLater is not necessary. We call usually that methods form teh UI thread. */ -class TomP2PMessageService implements MessageService { +public class TomP2PMessageService implements MessageService { private static final Logger log = LoggerFactory.getLogger(TomP2PMessageService.class); private static final String ARBITRATORS_ROOT = "ArbitratorsRoot"; diff --git a/gui/src/main/java/io/bitsquare/network/BootstrapNodes.java b/gui/src/main/java/io/bitsquare/network/BootstrapNodes.java index bb2713a175..70643018b0 100644 --- a/gui/src/main/java/io/bitsquare/network/BootstrapNodes.java +++ b/gui/src/main/java/io/bitsquare/network/BootstrapNodes.java @@ -30,7 +30,7 @@ public interface BootstrapNodes { Node DEFAULT = DIGITAL_OCEAN_1; /** - * A locally-running {@link io.bitsquare.app.cli.BootstrapNode} instance. + * A locally-running {@link io.bitsquare.app.bootstrap.BootstrapNode} instance. * Typically used only for testing. Not included in results from {@link #all()}. */ Node LOCALHOST = Node.at("localhost", "127.0.0.1"); diff --git a/gui/src/main/java/io/bitsquare/offer/OfferModule.java b/gui/src/main/java/io/bitsquare/offer/OfferModule.java index 227c30656b..dc3be4bbab 100644 --- a/gui/src/main/java/io/bitsquare/offer/OfferModule.java +++ b/gui/src/main/java/io/bitsquare/offer/OfferModule.java @@ -27,10 +27,4 @@ public abstract class OfferModule extends BitsquareModule { super(env); } - @Override - protected void configure() { - bind(OfferRepository.class).to(offerRepository()).asEagerSingleton(); - } - - protected abstract Class offerRepository(); } diff --git a/gui/src/main/java/io/bitsquare/offer/OfferRepository.java b/gui/src/main/java/io/bitsquare/offer/RemoteOfferBook.java similarity index 92% rename from gui/src/main/java/io/bitsquare/offer/OfferRepository.java rename to gui/src/main/java/io/bitsquare/offer/RemoteOfferBook.java index 2b8c60f0c7..a643cc34e1 100644 --- a/gui/src/main/java/io/bitsquare/offer/OfferRepository.java +++ b/gui/src/main/java/io/bitsquare/offer/RemoteOfferBook.java @@ -21,10 +21,13 @@ import io.bitsquare.util.task.FaultHandler; import io.bitsquare.util.task.ResultHandler; import java.util.List; +import java.util.concurrent.Executor; import javafx.beans.property.LongProperty; -public interface OfferRepository { +public interface RemoteOfferBook { + + void setExecutor(Executor executor); void getOffers(String fiatCode); diff --git a/gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferRepository.java b/gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferBook.java similarity index 92% rename from gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferRepository.java rename to gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferBook.java index bfb8c850ff..2ed6c7f756 100644 --- a/gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferRepository.java +++ b/gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferBook.java @@ -19,7 +19,7 @@ package io.bitsquare.offer.tomp2p; import io.bitsquare.msg.tomp2p.TomP2PNode; import io.bitsquare.offer.Offer; -import io.bitsquare.offer.OfferRepository; +import io.bitsquare.offer.RemoteOfferBook; import io.bitsquare.util.task.FaultHandler; import io.bitsquare.util.task.ResultHandler; @@ -28,10 +28,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.Executor; import javax.inject.Inject; -import javafx.application.Platform; import javafx.beans.property.LongProperty; import javafx.beans.property.SimpleLongProperty; @@ -48,20 +48,25 @@ import net.tomp2p.storage.Data; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -class TomP2POfferRepository implements OfferRepository { +public class TomP2POfferBook implements RemoteOfferBook { - private static final Logger log = LoggerFactory.getLogger(TomP2POfferRepository.class); + private static final Logger log = LoggerFactory.getLogger(TomP2POfferBook.class); private final List offerRepositoryListeners = new ArrayList<>(); private final LongProperty invalidationTimestamp = new SimpleLongProperty(0); private final TomP2PNode p2pNode; + private Executor executor; @Inject - public TomP2POfferRepository(TomP2PNode p2pNode) { + public TomP2POfferBook(TomP2PNode p2pNode) { this.p2pNode = p2pNode; } + public void setExecutor(Executor executor) { + this.executor = executor; + } + @Override public void addOffer(Offer offer, ResultHandler resultHandler, FaultHandler faultHandler) { Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode()); @@ -78,13 +83,13 @@ class TomP2POfferRepository implements OfferRepository { @Override public void operationComplete(BaseFuture future) throws Exception { if (future.isSuccess()) { - Platform.runLater(() -> { + executor.execute(() -> { resultHandler.handleResult(); offerRepositoryListeners.stream().forEach(listener -> { try { Object offerDataObject = offerData.object(); if (offerDataObject instanceof Offer) { - log.error("Added offer to DHT with ID: " + offerDataObject); + log.info("Added offer to DHT with ID: " + offerDataObject); listener.onOfferAdded((Offer) offerDataObject); } } catch (ClassNotFoundException | IOException e) { @@ -102,15 +107,11 @@ class TomP2POfferRepository implements OfferRepository { @Override public void exceptionCaught(Throwable ex) throws Exception { - Platform.runLater(() -> { - faultHandler.handleFault("Failed to add offer to DHT", ex); - }); + executor.execute(() -> faultHandler.handleFault("Failed to add offer to DHT", ex)); } }); } catch (IOException ex) { - Platform.runLater(() -> { - faultHandler.handleFault("Failed to add offer to DHT", ex); - }); + executor.execute(() -> faultHandler.handleFault("Failed to add offer to DHT", ex)); } } @@ -130,7 +131,7 @@ class TomP2POfferRepository implements OfferRepository { // it might change in future to something like foundAndRemoved and notFound // See discussion at: https://github.com/tomp2p/TomP2P/issues/57#issuecomment-62069840 - Platform.runLater(() -> { + executor.execute(() -> { offerRepositoryListeners.stream().forEach(listener -> { try { Object offerDataObject = offerData.object(); @@ -182,7 +183,7 @@ class TomP2POfferRepository implements OfferRepository { } } - Platform.runLater(() -> offerRepositoryListeners.stream().forEach(listener -> + executor.execute(() -> offerRepositoryListeners.stream().forEach(listener -> listener.onOffersReceived(offers))); } @@ -193,7 +194,7 @@ class TomP2POfferRepository implements OfferRepository { final Map dataMap = futureGet.dataMap(); if (dataMap == null || dataMap.size() == 0) { log.trace("Get offers from DHT delivered empty dataMap."); - Platform.runLater(() -> offerRepositoryListeners.stream().forEach(listener -> + executor.execute(() -> offerRepositoryListeners.stream().forEach(listener -> listener.onOffersReceived(new ArrayList<>()))); } else { @@ -262,7 +263,7 @@ class TomP2POfferRepository implements OfferRepository { Data data = futureGet.data(); if (data != null && data.object() instanceof Long) { final Object object = data.object(); - Platform.runLater(() -> { + executor.execute(() -> { Long timeStamp = (Long) object; //log.trace("Get invalidationTimestamp from DHT was successful. TimeStamp=" + timeStamp); invalidationTimestamp.set(timeStamp); diff --git a/gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferModule.java b/gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferModule.java index af2262573d..935670be59 100644 --- a/gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferModule.java +++ b/gui/src/main/java/io/bitsquare/offer/tomp2p/TomP2POfferModule.java @@ -17,8 +17,15 @@ package io.bitsquare.offer.tomp2p; +import io.bitsquare.msg.tomp2p.TomP2PNode; import io.bitsquare.offer.OfferModule; -import io.bitsquare.offer.OfferRepository; +import io.bitsquare.offer.RemoteOfferBook; + +import com.google.inject.Provider; + +import javax.inject.Inject; + +import javafx.application.Platform; import org.springframework.core.env.Environment; @@ -29,7 +36,21 @@ public class TomP2POfferModule extends OfferModule { } @Override - public Class offerRepository() { - return TomP2POfferRepository.class; + protected void configure() { + bind(RemoteOfferBook.class).toProvider(RemoteOfferBookProvider.class).asEagerSingleton(); } } + +class RemoteOfferBookProvider implements Provider { + private final TomP2POfferBook remoteOfferBook; + + @Inject + public RemoteOfferBookProvider(TomP2PNode p2pNode) { + remoteOfferBook = new TomP2POfferBook(p2pNode); + remoteOfferBook.setExecutor(Platform::runLater); + } + + public RemoteOfferBook get() { + return remoteOfferBook; + } +} \ No newline at end of file diff --git a/gui/src/main/java/io/bitsquare/trade/TradeManager.java b/gui/src/main/java/io/bitsquare/trade/TradeManager.java index dd89ca4220..04ea0b0f73 100644 --- a/gui/src/main/java/io/bitsquare/trade/TradeManager.java +++ b/gui/src/main/java/io/bitsquare/trade/TradeManager.java @@ -28,10 +28,10 @@ import io.bitsquare.msg.listeners.OutgoingMessageListener; import io.bitsquare.network.Peer; import io.bitsquare.offer.Direction; import io.bitsquare.offer.Offer; -import io.bitsquare.offer.OfferRepository; +import io.bitsquare.offer.RemoteOfferBook; import io.bitsquare.persistence.Persistence; import io.bitsquare.trade.handlers.TransactionResultHandler; -import io.bitsquare.trade.protocol.createoffer.CreateOfferCoordinator; +import io.bitsquare.trade.protocol.createoffer.CreateOfferProtocol; import io.bitsquare.trade.protocol.trade.TradeMessage; import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocol; import io.bitsquare.trade.protocol.trade.offerer.BuyerAcceptsOfferProtocolListener; @@ -83,7 +83,7 @@ public class TradeManager { private final BlockChainService blockChainService; private final WalletService walletService; private final SignatureService signatureService; - private final OfferRepository offerRepository; + private final RemoteOfferBook remoteOfferBook; //TODO store TakerAsSellerProtocol in trade private final Map takerAsSellerProtocolMap = new HashMap<>(); @@ -106,7 +106,7 @@ public class TradeManager { public TradeManager(User user, AccountSettings accountSettings, Persistence persistence, MessageService messageService, BlockChainService blockChainService, WalletService walletService, SignatureService signatureService, - OfferRepository offerRepository) { + RemoteOfferBook remoteOfferBook) { this.user = user; this.accountSettings = accountSettings; this.persistence = persistence; @@ -114,7 +114,7 @@ public class TradeManager { this.blockChainService = blockChainService; this.walletService = walletService; this.signatureService = signatureService; - this.offerRepository = offerRepository; + this.remoteOfferBook = remoteOfferBook; Object offersObject = persistence.read(this, "offers"); if (offersObject instanceof Map) { @@ -172,7 +172,7 @@ public class TradeManager { accountSettings.getAcceptedCountries(), accountSettings.getAcceptedLanguageLocales()); - CreateOfferCoordinator createOfferCoordinator = new CreateOfferCoordinator( + CreateOfferProtocol createOfferCoordinator = new CreateOfferProtocol( offer, walletService, (transactionId) -> { @@ -186,9 +186,9 @@ public class TradeManager { } }, (message, throwable) -> errorMessageHandler.handleErrorMessage(message), - offerRepository); + remoteOfferBook); - createOfferCoordinator.start(); + createOfferCoordinator.createOffer(); } private void addOffer(Offer offer) { @@ -206,7 +206,7 @@ public class TradeManager { offers.remove(offer.getId()); persistOffers(); - offerRepository.removeOffer(offer); + remoteOfferBook.removeOffer(offer); } diff --git a/gui/src/main/java/io/bitsquare/trade/TradeMessage.java b/gui/src/main/java/io/bitsquare/trade/TradeMessage.java new file mode 100644 index 0000000000..bc2e7ff492 --- /dev/null +++ b/gui/src/main/java/io/bitsquare/trade/TradeMessage.java @@ -0,0 +1,29 @@ +/* + * 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.trade; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TradeMessage { + private static final Logger log = LoggerFactory.getLogger(TradeMessage.class); + + public TradeMessage() { + + } +} diff --git a/gui/src/main/java/io/bitsquare/trade/TradeState.java b/gui/src/main/java/io/bitsquare/trade/TradeState.java new file mode 100644 index 0000000000..d3da1acc06 --- /dev/null +++ b/gui/src/main/java/io/bitsquare/trade/TradeState.java @@ -0,0 +1,29 @@ +/* + * 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.trade; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TradeState { + private static final Logger log = LoggerFactory.getLogger(TradeState.class); + + public TradeState() { + + } +} diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/createoffer/CreateOfferCoordinator.java b/gui/src/main/java/io/bitsquare/trade/protocol/createoffer/CreateOfferCoordinator.java deleted file mode 100644 index 9d5f4912b8..0000000000 --- a/gui/src/main/java/io/bitsquare/trade/protocol/createoffer/CreateOfferCoordinator.java +++ /dev/null @@ -1,101 +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.trade.protocol.createoffer; - -import io.bitsquare.btc.WalletService; -import io.bitsquare.offer.Offer; -import io.bitsquare.offer.OfferRepository; -import io.bitsquare.trade.handlers.TransactionResultHandler; -import io.bitsquare.util.task.FaultHandler; - -import org.bitcoinj.core.InsufficientMoneyException; -import org.bitcoinj.core.Transaction; - -import com.google.common.util.concurrent.FutureCallback; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Responsible for coordinating tasks involved in the create offer process. - */ -public class CreateOfferCoordinator { - - private static final Logger log = LoggerFactory.getLogger(CreateOfferCoordinator.class); - - private final Offer offer; - private final WalletService walletService; - private final TransactionResultHandler resultHandler; - private final FaultHandler faultHandler; - private final OfferRepository offerRepository; - - public CreateOfferCoordinator(Offer offer, WalletService walletService, TransactionResultHandler resultHandler, - FaultHandler faultHandler, OfferRepository offerRepository) { - this.offer = offer; - this.walletService = walletService; - this.resultHandler = resultHandler; - this.faultHandler = faultHandler; - this.offerRepository = offerRepository; - } - - public void start() { - try { - offer.validate(); - } catch (Exception ex) { - faultHandler.handleFault("Offer validation failed", ex); - return; - } - - Transaction transaction; - - try { - transaction = walletService.createOfferFeeTx(offer.getId()); - offer.setOfferFeePaymentTxID(transaction.getHashAsString()); - } catch (InsufficientMoneyException ex) { - faultHandler.handleFault( - "Offer fee payment failed because there is insufficient money in the trade wallet", ex); - return; - } catch (Throwable ex) { - faultHandler.handleFault("Offer fee payment failed because of an exception occurred", ex); - return; - } - - try { - walletService.broadcastCreateOfferFeeTx(transaction, new FutureCallback() { - @Override - public void onSuccess(Transaction transaction) { - log.info("sendResult onSuccess:" + transaction); - if (transaction == null) { - faultHandler.handleFault("Offer fee payment failed.", - new Exception("Offer fee payment failed. Transaction = null.")); - return; - } - offerRepository.addOffer(offer, () -> resultHandler.onResult(transaction), faultHandler); - } - - @Override - public void onFailure(Throwable t) { - faultHandler.handleFault("Offer fee payment failed with an exception.", t); - } - }); - } catch (Throwable t) { - faultHandler.handleFault("Offer fee payment failed because an exception occurred.", t); - return; - } - } -} diff --git a/gui/src/main/java/io/bitsquare/trade/protocol/createoffer/CreateOfferProtocol.java b/gui/src/main/java/io/bitsquare/trade/protocol/createoffer/CreateOfferProtocol.java new file mode 100644 index 0000000000..3145def0d8 --- /dev/null +++ b/gui/src/main/java/io/bitsquare/trade/protocol/createoffer/CreateOfferProtocol.java @@ -0,0 +1,146 @@ +/* + * 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.trade.protocol.createoffer; + +import io.bitsquare.btc.WalletService; +import io.bitsquare.offer.Offer; +import io.bitsquare.offer.RemoteOfferBook; +import io.bitsquare.trade.handlers.TransactionResultHandler; +import io.bitsquare.util.task.FaultHandler; + +import org.bitcoinj.core.InsufficientMoneyException; +import org.bitcoinj.core.Transaction; + +import com.google.common.util.concurrent.FutureCallback; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Responsible for coordinating tasks involved in the create offer process. + * Executed on UI thread (single threaded) + */ +public class CreateOfferProtocol { + + private static final Logger log = LoggerFactory.getLogger(CreateOfferProtocol.class); + + private final Offer offer; + private final WalletService walletService; + private final TransactionResultHandler resultHandler; + private final FaultHandler faultHandler; + private final RemoteOfferBook remoteOfferBook; + private int repeatAddOfferCallCounter = 0; + + public CreateOfferProtocol(Offer offer, WalletService walletService, TransactionResultHandler resultHandler, + FaultHandler faultHandler, RemoteOfferBook remoteOfferBook) { + this.offer = offer; + this.walletService = walletService; + this.resultHandler = resultHandler; + this.faultHandler = faultHandler; + this.remoteOfferBook = remoteOfferBook; + } + + public void createOffer() { + try { + validateOffer(); + Transaction transaction = createOfferFeeTx(); + + TransactionResultHandler resultHandler1 = transaction1 -> addOffer(transaction1); + FaultHandler faultHandler1 = (message, throwable) -> faultHandler.handleFault(message, throwable); + broadcastCreateOfferFeeTx(transaction, resultHandler1, faultHandler1); + + } catch (Throwable t) { + } + + } + + // 1. Validate offer data + // Sync + // In case of an error: No rollback activity needed + void validateOffer() throws Exception { + try { + offer.validate(); + } catch (Exception ex) { + faultHandler.handleFault("Offer validation failed", ex); + throw ex; + } + } + + // 2. createOfferFeeTx + // Sync + // In case of an error: No rollback activity needed + Transaction createOfferFeeTx() throws Exception { + try { + return walletService.createOfferFeeTx(offer.getId()); + } catch (InsufficientMoneyException ex) { + faultHandler.handleFault( + "Offer fee payment failed because there is insufficient money in the trade wallet", ex); + throw ex; + } catch (Throwable t) { + faultHandler.handleFault("Offer fee payment failed because of an exception occurred", t); + throw t; + } + } + + // 3. broadcastCreateOfferFeeTx + // Async + // In case of an error: Not sure if there can be an inconsistent state in failure case. Assuming not but need to check further. + void broadcastCreateOfferFeeTx(Transaction transaction, TransactionResultHandler resultHandler1, FaultHandler faultHandler1) throws Exception { + try { + walletService.broadcastCreateOfferFeeTx(transaction, new FutureCallback() { + @Override + public void onSuccess(Transaction transaction) { + log.info("Broadcast of offer fee payment succeeded: transaction = " + transaction.toString()); + if (transaction == null) { + Exception ex = new Exception("Broadcast of offer fee payment failed because transaction = null."); + faultHandler.handleFault("Broadcast of offer fee payment failed.", ex); + } + resultHandler1.onResult(transaction); + } + + @Override + public void onFailure(Throwable t) { + faultHandler1.handleFault("Broadcast of offer fee payment failed with an exception.", t); + } + }); + } catch (Throwable t) { + faultHandler1.handleFault("Broadcast of offer fee payment failed with an exception.", t); + throw t; + } + } + + // 4. addOffer + // Async + // In case of an error: Try again, afterwards give up. + void addOffer(Transaction transaction) { + remoteOfferBook.addOffer(offer, + () -> { + offer.setOfferFeePaymentTxID(transaction.getHashAsString()); + resultHandler.onResult(transaction); + }, + (message, throwable) -> { + repeatAddOfferCallCounter++; + if (repeatAddOfferCallCounter > 1) { + faultHandler.handleFault(message, throwable); + } + else { + addOffer(transaction); + } + }); + } +} diff --git a/gui/src/main/java/io/bitsquare/util/Bytes.java b/gui/src/main/java/io/bitsquare/util/Bytes.java new file mode 100644 index 0000000000..fa6d9edbf1 --- /dev/null +++ b/gui/src/main/java/io/bitsquare/util/Bytes.java @@ -0,0 +1,68 @@ +/* + * 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.util; + +import org.bitcoinj.core.Utils; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; + +import java.util.Arrays; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Bytes { + private static final Logger log = LoggerFactory.getLogger(Bytes.class); + + public final byte[] bytes; + public final String string; + + public Bytes(byte[] bytes) { + this.bytes = Arrays.copyOf(bytes, bytes.length); + this.string = Utils.HEX.encode(bytes); + } + + public Bytes(String string) { + this.string = string; + this.bytes = Utils.HEX.decode(string); + } + + @Override + public String toString() { + return string; + } + + public static class GsonAdapter extends TypeAdapter { + @Override + public Bytes read(JsonReader reader) throws IOException { + return new Bytes(reader.nextString()); + } + + @Override + public void write(JsonWriter out, Bytes value) throws IOException { + if (value == null) + out.nullValue(); + else + out.value(value.string); + } + } +} diff --git a/gui/src/main/java/io/bitsquare/util/Utilities.java b/gui/src/main/java/io/bitsquare/util/Utilities.java index 8c3ddfd277..b784e2d642 100644 --- a/gui/src/main/java/io/bitsquare/util/Utilities.java +++ b/gui/src/main/java/io/bitsquare/util/Utilities.java @@ -25,6 +25,7 @@ import java.awt.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -177,6 +178,30 @@ public class Utilities { return obj; } + /** + * Empty and delete a folder (and subfolders). + * @param folder + * folder to empty + */ + public static void removeDirectory(final File folder) { + // check if folder file is a real folder + if (folder.isDirectory()) { + File[] list = folder.listFiles(); + if (list != null) { + for (int i = 0; i < list.length; i++) { + File tmpF = list[i]; + if (tmpF.isDirectory()) { + removeDirectory(tmpF); + } + tmpF.delete(); + } + } + if (!folder.delete()) { + log.warn("can't delete folder : " + folder); + } + } + } + public static AnimationTimer setTimeout(int delay, Function callback) { AnimationTimer animationTimer = new AnimationTimer() { final long lastTimeStamp = System.currentTimeMillis(); diff --git a/gui/src/main/resources/logback.xml b/gui/src/main/resources/logback.xml index bf5c415ea0..1d2e3cd137 100644 --- a/gui/src/main/resources/logback.xml +++ b/gui/src/main/resources/logback.xml @@ -26,9 +26,9 @@ - - - + + + diff --git a/gui/src/test/java/io/bitsquare/msg/TomP2PTests.java b/gui/src/test/java/io/bitsquare/msg/TomP2PTests.java index f138fc73ea..2021dea704 100644 --- a/gui/src/test/java/io/bitsquare/msg/TomP2PTests.java +++ b/gui/src/test/java/io/bitsquare/msg/TomP2PTests.java @@ -74,7 +74,7 @@ import static org.junit.Assert.*; * Test bootstrapping, DHT operations like put/get/add/remove and sendDirect in both LAN and WAN environment * Test scenarios in direct connection, auto port forwarding or relay mode. *

- * To start a bootstrap node code use the {@link io.bitsquare.app.cli.BootstrapNode} class. + * To start a bootstrap node code use the {@link io.bitsquare.app.bootstrap.BootstrapNode} class. *

* To configure your test environment edit the static fields for id, IP and port. * In the configure method and the connectionType you can define your test scenario. diff --git a/gui/src/test/java/io/bitsquare/trade/protocol/createoffer/CreateOfferProtocolTest.java b/gui/src/test/java/io/bitsquare/trade/protocol/createoffer/CreateOfferProtocolTest.java new file mode 100644 index 0000000000..6fb09fb6e6 --- /dev/null +++ b/gui/src/test/java/io/bitsquare/trade/protocol/createoffer/CreateOfferProtocolTest.java @@ -0,0 +1,318 @@ +/* + * 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.trade.protocol.createoffer; + +import io.bitsquare.arbitrator.Arbitrator; +import io.bitsquare.bank.BankAccountType; +import io.bitsquare.btc.BitcoinNetwork; +import io.bitsquare.btc.FeePolicy; +import io.bitsquare.btc.UserAgent; +import io.bitsquare.btc.WalletService; +import io.bitsquare.locale.CountryUtil; +import io.bitsquare.locale.LanguageUtil; +import io.bitsquare.msg.tomp2p.BootstrappedPeerBuilder; +import io.bitsquare.msg.tomp2p.TomP2PMessageService; +import io.bitsquare.msg.tomp2p.TomP2PNode; +import io.bitsquare.network.BootstrapState; +import io.bitsquare.network.Node; +import io.bitsquare.offer.Direction; +import io.bitsquare.offer.Offer; +import io.bitsquare.offer.RemoteOfferBook; +import io.bitsquare.offer.tomp2p.TomP2POfferBook; +import io.bitsquare.persistence.Persistence; +import io.bitsquare.trade.handlers.TransactionResultHandler; +import io.bitsquare.user.User; +import io.bitsquare.util.DSAKeyUtil; +import io.bitsquare.util.task.FaultHandler; + +import org.bitcoinj.core.Address; +import org.bitcoinj.core.Coin; +import org.bitcoinj.core.Transaction; +import org.bitcoinj.utils.Threading; + +import java.io.File; +import java.io.IOException; + +import java.util.Arrays; +import java.util.Currency; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import rx.Observable; + +import static org.junit.Assert.*; + +/** + * That test is ignored for automated testing as it needs custom setup. + *

+ * It uses RegTest mode of Bitcoin network and localhost TomP2P network. + *

+ * 1. Need a first run to get the wallet receiving address. + * 2. Fund that from regtest Bitcoin Core client. + * 3. Create a block on regtest Bitcoin Core (setgenerate true) to get the balance. + * 4. Start BootstrapNodeMain at localhost with program args: --node.name localhost + */ +@Ignore +public class CreateOfferProtocolTest { + private static final Logger log = LoggerFactory.getLogger(CreateOfferProtocolTest.class); + + private WalletService walletService; + private TomP2PMessageService messageService; + private RemoteOfferBook remoteOfferBook; + private final File dir = new File("./temp"); + private final static String OFFER_ID = "offerID"; + private Address address; + + @Before + public void setup() throws InterruptedException { + CountDownLatch countDownLatch = new CountDownLatch(1); + dir.mkdirs(); + + Persistence persistence = new Persistence(dir, "prefs"); + persistence.init(); + + // messageService + Node bootstrapNode = Node.at("localhost", "127.0.0.1"); + User user = new User(); + user.applyPersistedUser(null); + BootstrappedPeerBuilder bootstrappedPeerBuilder = new BootstrappedPeerBuilder(Node.DEFAULT_PORT, false, bootstrapNode, ""); + TomP2PNode p2pNode = new TomP2PNode(bootstrappedPeerBuilder); + messageService = new TomP2PMessageService(user, p2pNode); + + Observable messageObservable = messageService.init(); + messageObservable.publish(); + messageObservable.subscribe( + state -> log.trace("state changed: " + state), + error -> { + log.error(error.toString()); + }, + () -> { + log.trace("message completed"); + + remoteOfferBook = new TomP2POfferBook(p2pNode); + remoteOfferBook.setExecutor(Threading.SAME_THREAD); + } + ); + bootstrappedPeerBuilder.start(); + + // WalletService + walletService = new WalletService(BitcoinNetwork.REGTEST, + new FeePolicy(BitcoinNetwork.REGTEST), + null, + persistence, + new UserAgent("", ""), + dir, + "Tests" + ); + + Observable walletServiceObservable = walletService.initialize(Threading.SAME_THREAD); + walletServiceObservable.subscribe( + next -> { + // log.trace("wallet next"); + }, + error -> { + log.trace("wallet error"); + }, + () -> { + log.trace("wallet complete"); + }); + + Observable allTasks = Observable.merge(messageObservable, walletServiceObservable); + allTasks.subscribe( + next -> { + //log.trace("next"); + }, + error -> log.error(error.toString()), + () -> { + log.trace("wallet completed"); + // 1. Use that address for funding the trading wallet + address = walletService.getAddressInfoByTradeID(OFFER_ID).getAddress(); + log.info("address for funding wallet = " + address.toString());//muoTvFHJmQwPKYoA8Fr7t87UCSfZM4fciG + log.info("Balance = " + walletService.getBalanceForAddress(address)); + countDownLatch.countDown(); + }); + + countDownLatch.await(); + } + + @After + public void shutDown() throws IOException, InterruptedException { + walletService.shutDown(); + messageService.shutDown(); + } + + @Test + public void validateOfferTest() throws InterruptedException { + try { + Offer offer = getOffer(); + getCreateOfferCoordinator(offer).validateOffer(); + assertTrue(true); + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void createOfferFeeTxTest() throws InterruptedException { + try { + Offer offer = getOffer(); + Transaction transaction = getCreateOfferCoordinator(offer).createOfferFeeTx(); + assertNotNull(transaction); + } catch (Exception e) { + log.info("address for funding wallet = " + address.toString()); + log.info("Balance = " + walletService.getBalanceForAddress(address)); + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void broadcastCreateOfferFeeTxTest() throws InterruptedException { + try { + log.info("Balance pre = " + walletService.getBalanceForAddress(address)); + Offer offer = getOffer(); + TransactionResultHandler resultHandler = transaction -> assertNotNull(transaction); + FaultHandler faultHandler = (message, throwable) -> { + log.error(message); + throwable.printStackTrace(); + fail(throwable.getMessage()); + }; + CreateOfferProtocol createOfferCoordinator = getCreateOfferCoordinator(offer); + Transaction transaction = createOfferCoordinator.createOfferFeeTx(); + createOfferCoordinator.broadcastCreateOfferFeeTx(transaction, resultHandler, faultHandler); + log.info("Balance post = " + walletService.getBalanceForAddress(address)); + + } catch (Exception e) { + log.info("address for funding wallet = " + address.toString()); + log.info("Balance = " + walletService.getBalanceForAddress(address)); + e.printStackTrace(); + fail(e.getMessage()); + } + } + + @Test + public void addOfferTest() throws InterruptedException { + CountDownLatch countDownLatch = new CountDownLatch(2); + try { + Offer offer = getOffer(); + remoteOfferBook.addListener(new RemoteOfferBook.Listener() { + @Override + public void onOfferAdded(Offer offer1) { + assertEquals("Offer matching", offer.getId(), offer1.getId()); + countDownLatch.countDown(); + } + + @Override + public void onOffersReceived(List offers) { + } + + @Override + public void onOfferRemoved(Offer offer) { + } + }); + + TransactionResultHandler resultHandler = transaction -> { + assertNotNull(transaction); + countDownLatch.countDown(); + }; + FaultHandler faultHandler = (message, throwable) -> { + log.error(message); + throwable.printStackTrace(); + fail(throwable.getMessage()); + countDownLatch.countDown(); + countDownLatch.countDown(); + }; + CreateOfferProtocol createOfferCoordinator = getCreateOfferCoordinator(offer, resultHandler, faultHandler); + Transaction transaction = createOfferCoordinator.createOfferFeeTx(); + createOfferCoordinator.addOffer(transaction); + countDownLatch.await(); + log.info("Finished"); + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + countDownLatch.countDown(); + countDownLatch.countDown(); + } + } + + @Test + public void createOfferTest() throws InterruptedException { + CountDownLatch countDownLatch = new CountDownLatch(1); + TransactionResultHandler resultHandler = transaction -> { + assertNotNull(transaction); + countDownLatch.countDown(); + }; + FaultHandler faultHandler = (message, throwable) -> { + log.error(message); + throwable.printStackTrace(); + fail(throwable.getMessage()); + countDownLatch.countDown(); + countDownLatch.countDown(); + }; + CreateOfferProtocol createOfferCoordinator = getCreateOfferCoordinator(getOffer(), resultHandler, faultHandler); + createOfferCoordinator.createOffer(); + countDownLatch.await(); + } + + + private CreateOfferProtocol getCreateOfferCoordinator(Offer offer) throws InterruptedException { + TransactionResultHandler resultHandler = transaction -> log.debug("result transaction=" + transaction.toString()); + FaultHandler faultHandler = (message, throwable) -> { + log.error(message); + throwable.printStackTrace(); + log.info("Balance = " + walletService.getBalanceForAddress(walletService.getAddressInfoByTradeID(OFFER_ID).getAddress())); + }; + return getCreateOfferCoordinator(offer, resultHandler, faultHandler); + } + + private CreateOfferProtocol getCreateOfferCoordinator(Offer offer, TransactionResultHandler resultHandler, FaultHandler faultHandler) throws + InterruptedException { + return new CreateOfferProtocol(offer, + walletService, + resultHandler, + faultHandler, + remoteOfferBook); + } + + private Offer getOffer() { + return new Offer(OFFER_ID, + DSAKeyUtil.generateKeyPair().getPublic(), + Direction.BUY, + 100L, + Coin.CENT, + Coin.CENT, + BankAccountType.INTERNATIONAL, + Currency.getInstance("EUR"), + CountryUtil.getDefaultCountry(), + "bankAccountUID", + Arrays.asList(new Arbitrator()), + Coin.CENT, + Arrays.asList(CountryUtil.getDefaultCountry()), + Arrays.asList(LanguageUtil.getDefaultLanguageLocale()) + ); + } +} diff --git a/net/pom.xml b/net/pom.xml index d4133a39e6..2da859bd74 100644 --- a/net/pom.xml +++ b/net/pom.xml @@ -41,7 +41,7 @@ false - io.bitsquare.app.cli.BootstrapNodeMain + io.bitsquare.app.bootstrap.BootstrapNodeMain