mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Add CreateOfferProtocolTests
This commit is contained in:
parent
86ec3380b2
commit
d832cfe74b
@ -15,7 +15,7 @@
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.app.cli;
|
||||
package io.bitsquare.app.bootstrap;
|
||||
|
||||
import io.bitsquare.network.Node;
|
||||
|
@ -15,7 +15,7 @@
|
||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bitsquare.app.cli;
|
||||
package io.bitsquare.app.bootstrap;
|
||||
|
||||
import io.bitsquare.app.BitsquareEnvironment;
|
||||
import io.bitsquare.app.BitsquareExecutable;
|
@ -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))
|
||||
|
@ -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) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -160,9 +160,9 @@ class MainViewModel implements ViewModel {
|
||||
error -> log.error(error.toString()),
|
||||
() -> Platform.runLater(() -> setBitcoinNetworkSyncProgress(1.0)));
|
||||
|
||||
Observable<BootstrapState> message = messageService.init();
|
||||
message.publish();
|
||||
message.subscribe(
|
||||
Observable<BootstrapState> 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<Object> wallet = walletService.initialize(Platform::runLater);
|
||||
wallet.subscribe(
|
||||
Observable<Object> 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.State> updateProcess = this.updateProcess.getProcess();
|
||||
updateProcess.subscribe(next -> {
|
||||
Observable<UpdateProcess.State> 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 -> {
|
||||
},
|
||||
|
@ -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<OfferBookListItem> offerBookListItems = FXCollections.observableArrayList();
|
||||
private final OfferRepository.Listener offerRepositoryListener;
|
||||
private final RemoteOfferBook.Listener remoteOfferBookListener;
|
||||
private final ChangeListener<BankAccount> bankAccountChangeListener;
|
||||
private final ChangeListener<Number> 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() {
|
||||
|
@ -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";
|
||||
|
@ -66,7 +66,7 @@ import rx.Observable;
|
||||
* <p>
|
||||
* 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";
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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<? extends OfferRepository> offerRepository();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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<Listener> 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<Number640, Data> 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);
|
@ -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<? extends OfferRepository> offerRepository() {
|
||||
return TomP2POfferRepository.class;
|
||||
protected void configure() {
|
||||
bind(RemoteOfferBook.class).toProvider(RemoteOfferBookProvider.class).asEagerSingleton();
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteOfferBookProvider implements Provider<RemoteOfferBook> {
|
||||
private final TomP2POfferBook remoteOfferBook;
|
||||
|
||||
@Inject
|
||||
public RemoteOfferBookProvider(TomP2PNode p2pNode) {
|
||||
remoteOfferBook = new TomP2POfferBook(p2pNode);
|
||||
remoteOfferBook.setExecutor(Platform::runLater);
|
||||
}
|
||||
|
||||
public RemoteOfferBook get() {
|
||||
return remoteOfferBook;
|
||||
}
|
||||
}
|
@ -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<String, SellerTakesOfferProtocol> 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);
|
||||
}
|
||||
|
||||
|
||||
|
29
gui/src/main/java/io/bitsquare/trade/TradeMessage.java
Normal file
29
gui/src/main/java/io/bitsquare/trade/TradeMessage.java
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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() {
|
||||
|
||||
}
|
||||
}
|
29
gui/src/main/java/io/bitsquare/trade/TradeState.java
Normal file
29
gui/src/main/java/io/bitsquare/trade/TradeState.java
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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() {
|
||||
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Transaction>() {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Transaction>() {
|
||||
@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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
68
gui/src/main/java/io/bitsquare/util/Bytes.java
Normal file
68
gui/src/main/java/io/bitsquare/util/Bytes.java
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<Bytes> {
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<AnimationTimer, Void> callback) {
|
||||
AnimationTimer animationTimer = new AnimationTimer() {
|
||||
final long lastTimeStamp = System.currentTimeMillis();
|
||||
|
@ -26,9 +26,9 @@
|
||||
|
||||
<logger name="io.bitsquare" level="TRACE"/>
|
||||
|
||||
<logger name="org.bitcoinj" level="INFO"/>
|
||||
<logger name="net.tomp2p" level="INFO"/>
|
||||
<logger name="com.vinumeris.updatefx" level="TRACE"/>
|
||||
<logger name="org.bitcoinj" level="WARN"/>
|
||||
<logger name="net.tomp2p" level="WARN"/>
|
||||
<logger name="com.vinumeris.updatefx" level="INFO"/>
|
||||
|
||||
|
||||
<logger name="net.tomp2p.message.Encoder" level="WARN"/>
|
||||
|
@ -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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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.
|
||||
* <p/>
|
||||
* It uses RegTest mode of Bitcoin network and localhost TomP2P network.
|
||||
* <p/>
|
||||
* 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, "<unspecified>");
|
||||
TomP2PNode p2pNode = new TomP2PNode(bootstrappedPeerBuilder);
|
||||
messageService = new TomP2PMessageService(user, p2pNode);
|
||||
|
||||
Observable<BootstrapState> 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<Object> 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<Offer> 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())
|
||||
);
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@
|
||||
<minimizeJar>false</minimizeJar>
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>io.bitsquare.app.cli.BootstrapNodeMain</mainClass>
|
||||
<mainClass>io.bitsquare.app.bootstrap.BootstrapNodeMain</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
<filters>
|
||||
|
Loading…
Reference in New Issue
Block a user