mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-07-26 16:35:18 -04:00
refactoring trade protocol
This commit is contained in:
parent
7e55b7325a
commit
5da272bdbf
96 changed files with 2074 additions and 2702 deletions
|
@ -166,6 +166,7 @@ public class MainController implements Initializable, NavigationController
|
||||||
return childController;
|
return childController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Private methods
|
// Private methods
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -173,7 +174,8 @@ public class MainController implements Initializable, NavigationController
|
||||||
private void init()
|
private void init()
|
||||||
{
|
{
|
||||||
messageFacade.init();
|
messageFacade.init();
|
||||||
messageFacade.addTakeOfferRequestListener(this::onTakeOfferRequested);
|
|
||||||
|
trading.addTakeOfferRequestListener(this::onTakeOfferRequested);
|
||||||
|
|
||||||
walletFacade.addDownloadListener(new WalletFacade.DownloadListener()
|
walletFacade.addDownloadListener(new WalletFacade.DownloadListener()
|
||||||
{
|
{
|
||||||
|
|
|
@ -194,7 +194,7 @@ public class OrderBookController implements Initializable, ChildController
|
||||||
|
|
||||||
private boolean isRegistered()
|
private boolean isRegistered()
|
||||||
{
|
{
|
||||||
return user.getAccountID() != null;
|
return user.getAccountId() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean areSettingsValid()
|
private boolean areSettingsValid()
|
||||||
|
|
|
@ -17,7 +17,8 @@ import io.bitsquare.msg.MessageFacade;
|
||||||
import io.bitsquare.trade.Offer;
|
import io.bitsquare.trade.Offer;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.Trading;
|
import io.bitsquare.trade.Trading;
|
||||||
import io.bitsquare.trade.payment.taker.TakerAsSellerProtocolListener;
|
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocol;
|
||||||
|
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocolListener;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
@ -173,8 +174,6 @@ public class TakerOfferController implements Initializable, ChildController
|
||||||
amountTextField.setEditable(false);
|
amountTextField.setEditable(false);
|
||||||
trading.takeOffer(amount, offer, new TakerAsSellerProtocolListener()
|
trading.takeOffer(amount, offer, new TakerAsSellerProtocolListener()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDepositTxPublished(String depositTxId)
|
public void onDepositTxPublished(String depositTxId)
|
||||||
{
|
{
|
||||||
|
@ -197,7 +196,7 @@ public class TakerOfferController implements Initializable, ChildController
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTradeCompleted(Trade trade, String payoutTxId)
|
public void onPayoutTxPublished(Trade trade, String payoutTxId)
|
||||||
{
|
{
|
||||||
accordion.setExpandedPane(summaryTitledPane);
|
accordion.setExpandedPane(summaryTitledPane);
|
||||||
summaryPaidTextField.setText(BtcFormatter.formatSatoshis(trade.getTradeAmount()));
|
summaryPaidTextField.setText(BtcFormatter.formatSatoshis(trade.getTradeAmount()));
|
||||||
|
@ -207,10 +206,32 @@ public class TakerOfferController implements Initializable, ChildController
|
||||||
summaryDepositTxIdTextField.setText(depositTxId);
|
summaryDepositTxIdTextField.setText(depositTxId);
|
||||||
summaryPayoutTxIdTextField.setText(payoutTxId);
|
summaryPayoutTxIdTextField.setText(payoutTxId);
|
||||||
}
|
}
|
||||||
}, (task) -> {
|
|
||||||
//log.trace(task.toString());
|
@Override
|
||||||
}, throwable -> {
|
public void onFault(Throwable throwable, TakerAsSellerProtocol.State state)
|
||||||
log.error(throwable.toString());
|
{
|
||||||
|
log.error("Error while executing trade process at state: " + state + " / " + throwable);
|
||||||
|
Popups.openErrorPopup("Error while executing trade process", "Error while executing trade process at state: " + state + " / " + throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWaitingForPeerResponse(TakerAsSellerProtocol.State state)
|
||||||
|
{
|
||||||
|
log.debug("Waiting for peers response at state " + state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted(TakerAsSellerProtocol.State state)
|
||||||
|
{
|
||||||
|
log.debug("Trade protocol completed at state " + state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTakeOfferRequestRejected(Trade trade)
|
||||||
|
{
|
||||||
|
log.error("Take offer request rejected");
|
||||||
|
Popups.openErrorPopup("Take offer request rejected", "Your take offer request has been rejected. It might be that the offerer got another request shortly before your request arrived.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -220,7 +241,7 @@ public class TakerOfferController implements Initializable, ChildController
|
||||||
@FXML
|
@FXML
|
||||||
public void onReceivedFiat()
|
public void onReceivedFiat()
|
||||||
{
|
{
|
||||||
trading.releaseBTC(tradeId);
|
trading.onFiatReceived(tradeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
|
|
@ -172,7 +172,7 @@ public class TakerTradeController implements Initializable, ChildController
|
||||||
gridPane.add(isOnlineCheckerHolder, 2, row);
|
gridPane.add(isOnlineCheckerHolder, 2, row);
|
||||||
|
|
||||||
//TODO
|
//TODO
|
||||||
messageFacade.pingPeer(offer.getMessagePubKeyAsHex());
|
// messageFacade.pingPeer(offer.getMessagePubKeyAsHex());
|
||||||
checkOnlineStatusTimer = Utilities.setTimeout(1000, (AnimationTimer animationTimer) -> {
|
checkOnlineStatusTimer = Utilities.setTimeout(1000, (AnimationTimer animationTimer) -> {
|
||||||
setIsOnlineStatus(true);
|
setIsOnlineStatus(true);
|
||||||
//noinspection ReturnOfNull
|
//noinspection ReturnOfNull
|
||||||
|
@ -316,7 +316,7 @@ public class TakerTradeController implements Initializable, ChildController
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTradeCompleted(String hashAsString)
|
public void onPayoutTxPublished(String hashAsString)
|
||||||
{
|
{
|
||||||
showSummary(hashAsString);
|
showSummary(hashAsString);
|
||||||
}
|
}
|
||||||
|
@ -359,7 +359,7 @@ public class TakerTradeController implements Initializable, ChildController
|
||||||
private void releaseBTC()
|
private void releaseBTC()
|
||||||
{
|
{
|
||||||
processStepBar.next();
|
processStepBar.next();
|
||||||
trading.releaseBTC(trade.getId());
|
trading.onFiatReceived(trade.getId());
|
||||||
|
|
||||||
nextButton.setText("Close");
|
nextButton.setText("Close");
|
||||||
nextButton.setOnAction(e -> close());
|
nextButton.setOnAction(e -> close());
|
||||||
|
|
|
@ -7,7 +7,6 @@ import io.bitsquare.gui.NavigationController;
|
||||||
import io.bitsquare.gui.util.Icons;
|
import io.bitsquare.gui.util.Icons;
|
||||||
import io.bitsquare.trade.Offer;
|
import io.bitsquare.trade.Offer;
|
||||||
import io.bitsquare.trade.Trading;
|
import io.bitsquare.trade.Trading;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -109,14 +108,8 @@ public class OfferController implements Initializable, ChildController, Hibernat
|
||||||
|
|
||||||
|
|
||||||
private void removeOffer(OfferListItem offerListItem)
|
private void removeOffer(OfferListItem offerListItem)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
trading.removeOffer(offerListItem.getOffer());
|
trading.removeOffer(offerListItem.getOffer());
|
||||||
} catch (IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
offerListItems.remove(offerListItem);
|
offerListItems.remove(offerListItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,20 +152,16 @@ public class PendingTradeController implements Initializable, ChildController, H
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
trading.getNewTradeProperty().addListener(new ChangeListener<String>()
|
trading.getNewTradeProperty().addListener((observableValue, oldTradeId, newTradeId) -> {
|
||||||
{
|
Trade newTrade = trading.getTrade(newTradeId);
|
||||||
@Override
|
if (newTrade != null)
|
||||||
public void changed(ObservableValue<? extends String> observableValue, String oldTradeUid, String newTradeUid)
|
|
||||||
{
|
|
||||||
Trade newTrade = trading.getTrades().get(newTradeUid);
|
|
||||||
tradeItems.add(new PendingTradesListItem(newTrade));
|
tradeItems.add(new PendingTradesListItem(newTrade));
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
initCopyIcons();
|
initCopyIcons();
|
||||||
|
|
||||||
// select
|
// select
|
||||||
Optional<PendingTradesListItem> currentTradeItemOptional = tradeItems.stream().filter((e) -> e.getTrade().getId().equals(trading.getCurrentPendingTrade().getId())).findFirst();
|
Optional<PendingTradesListItem> currentTradeItemOptional = tradeItems.stream().filter((e) -> e.getTrade().getId().equals(trading.getPendingTrade().getId())).findFirst();
|
||||||
if (currentTradeItemOptional.isPresent())
|
if (currentTradeItemOptional.isPresent())
|
||||||
openTradesTable.getSelectionModel().select(currentTradeItemOptional.get());
|
openTradesTable.getSelectionModel().select(currentTradeItemOptional.get());
|
||||||
|
|
||||||
|
@ -183,7 +179,7 @@ public class PendingTradeController implements Initializable, ChildController, H
|
||||||
|
|
||||||
public void bankTransferInited()
|
public void bankTransferInited()
|
||||||
{
|
{
|
||||||
trading.onUIEventBankTransferInited(currentTrade.getId());
|
trading.bankTransferInited(currentTrade.getId());
|
||||||
bankTransferInitedButton.setDisable(true);
|
bankTransferInitedButton.setDisable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,6 @@ import com.google.inject.Inject;
|
||||||
import io.bitsquare.BitSquare;
|
import io.bitsquare.BitSquare;
|
||||||
import io.bitsquare.msg.listeners.*;
|
import io.bitsquare.msg.listeners.*;
|
||||||
import io.bitsquare.trade.Offer;
|
import io.bitsquare.trade.Offer;
|
||||||
import io.bitsquare.trade.payment.offerer.OffererAsBuyerProtocol;
|
|
||||||
import io.bitsquare.trade.payment.offerer.messages.*;
|
|
||||||
import io.bitsquare.trade.payment.taker.TakerAsSellerProtocol;
|
|
||||||
import io.bitsquare.trade.payment.taker.listeners.GetPeerAddressListener;
|
|
||||||
import io.bitsquare.trade.payment.taker.messages.PayoutTxPublishedMessage;
|
|
||||||
import io.bitsquare.trade.payment.taker.messages.RequestOffererPublishDepositTxMessage;
|
|
||||||
import io.bitsquare.trade.payment.taker.messages.RequestTakeOfferMessage;
|
|
||||||
import io.bitsquare.trade.payment.taker.messages.TakeOfferFeePayedMessage;
|
|
||||||
import io.bitsquare.user.Arbitrator;
|
import io.bitsquare.user.Arbitrator;
|
||||||
import io.bitsquare.util.DSAKeyUtil;
|
import io.bitsquare.util.DSAKeyUtil;
|
||||||
import io.bitsquare.util.FileUtil;
|
import io.bitsquare.util.FileUtil;
|
||||||
|
@ -29,7 +21,6 @@ import net.tomp2p.p2p.Peer;
|
||||||
import net.tomp2p.p2p.PeerMaker;
|
import net.tomp2p.p2p.PeerMaker;
|
||||||
import net.tomp2p.peers.Number160;
|
import net.tomp2p.peers.Number160;
|
||||||
import net.tomp2p.peers.PeerAddress;
|
import net.tomp2p.peers.PeerAddress;
|
||||||
import net.tomp2p.rpc.ObjectDataReply;
|
|
||||||
import net.tomp2p.storage.Data;
|
import net.tomp2p.storage.Data;
|
||||||
import net.tomp2p.storage.StorageDisk;
|
import net.tomp2p.storage.StorageDisk;
|
||||||
import net.tomp2p.utils.Utils;
|
import net.tomp2p.utils.Utils;
|
||||||
|
@ -44,19 +35,18 @@ import org.slf4j.LoggerFactory;
|
||||||
@SuppressWarnings({"EmptyMethod", "ConstantConditions"})
|
@SuppressWarnings({"EmptyMethod", "ConstantConditions"})
|
||||||
public class MessageFacade
|
public class MessageFacade
|
||||||
{
|
{
|
||||||
private static final String PING = "ping";
|
|
||||||
private static final String PONG = "pong";
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MessageFacade.class);
|
private static final Logger log = LoggerFactory.getLogger(MessageFacade.class);
|
||||||
|
// private static final String PING = "ping";
|
||||||
|
// private static final String PONG = "pong";
|
||||||
private static final int MASTER_PEER_PORT = 5000;
|
private static final int MASTER_PEER_PORT = 5000;
|
||||||
|
|
||||||
private final List<OrderBookListener> orderBookListeners = new ArrayList<>();
|
private final List<OrderBookListener> orderBookListeners = new ArrayList<>();
|
||||||
private final List<TakeOfferRequestListener> takeOfferRequestListeners = new ArrayList<>();
|
|
||||||
private final List<ArbitratorListener> arbitratorListeners = new ArrayList<>();
|
private final List<ArbitratorListener> arbitratorListeners = new ArrayList<>();
|
||||||
|
|
||||||
private final Map<String, TakerAsSellerProtocol> takerPaymentProtocols = new HashMap<>();
|
private final List<IncomingTradeMessageListener> incomingTradeMessageListeners = new ArrayList<>();
|
||||||
private final Map<String, OffererAsBuyerProtocol> offererAsBuyerProtocols = new HashMap<>();
|
|
||||||
|
|
||||||
private final List<PingPeerListener> pingPeerListeners = new ArrayList<>();
|
|
||||||
|
// private final List<PingPeerListener> pingPeerListeners = new ArrayList<>();
|
||||||
private final BooleanProperty isDirty = new SimpleBooleanProperty(false);
|
private final BooleanProperty isDirty = new SimpleBooleanProperty(false);
|
||||||
private Peer myPeer;
|
private Peer myPeer;
|
||||||
|
|
||||||
|
@ -71,17 +61,9 @@ public class MessageFacade
|
||||||
@Inject
|
@Inject
|
||||||
public MessageFacade()
|
public MessageFacade()
|
||||||
{
|
{
|
||||||
/* try
|
|
||||||
{
|
|
||||||
masterPeer = BootstrapMasterPeer.GET_INSTANCE(MASTER_PEER_PORT);
|
|
||||||
} catch (Exception e)
|
|
||||||
{
|
|
||||||
if (masterPeer != null)
|
|
||||||
masterPeer.shutdown();
|
|
||||||
System.err.println("masterPeer already instantiated by another app. " + e.getMessage());
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Public Methods
|
// Public Methods
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -115,6 +97,146 @@ public class MessageFacade
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Find peer address
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void getPeerAddress(String pubKeyAsHex, GetPeerAddressListener listener)
|
||||||
|
{
|
||||||
|
final Number160 location = Number160.createHash(pubKeyAsHex);
|
||||||
|
final FutureDHT getPeerAddressFuture = myPeer.get(location).start();
|
||||||
|
getPeerAddressFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void operationComplete(BaseFuture baseFuture) throws Exception
|
||||||
|
{
|
||||||
|
if (baseFuture.isSuccess() && getPeerAddressFuture.getData() != null)
|
||||||
|
{
|
||||||
|
final PeerAddress peerAddress = (PeerAddress) getPeerAddressFuture.getData().getObject();
|
||||||
|
Platform.runLater(() -> listener.onResult(peerAddress));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Platform.runLater(() -> listener.onFailed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Publish offer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void addOffer(Offer offer) throws IOException
|
||||||
|
{
|
||||||
|
log.trace("addOffer");
|
||||||
|
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
|
||||||
|
final Number160 contentKey = Number160.createHash(offer.getId());
|
||||||
|
final Data offerData = new Data(offer);
|
||||||
|
//offerData.setTTLSeconds(5);
|
||||||
|
final FutureDHT addFuture = myPeer.put(locationKey).setData(contentKey, offerData).start();
|
||||||
|
//final FutureDHT addFuture = myPeer.add(locationKey).setData(offerData).start();
|
||||||
|
addFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void operationComplete(BaseFuture future) throws Exception
|
||||||
|
{
|
||||||
|
Platform.runLater(() -> onOfferAdded(offerData, future.isSuccess(), locationKey));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onOfferAdded(Data offerData, boolean success, Number160 locationKey)
|
||||||
|
{
|
||||||
|
log.trace("onOfferAdded");
|
||||||
|
setDirty(locationKey);
|
||||||
|
orderBookListeners.stream().forEach(orderBookListener -> orderBookListener.onOfferAdded(offerData, success));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get offers
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void getOffers(String currency)
|
||||||
|
{
|
||||||
|
log.trace("getOffers");
|
||||||
|
final Number160 locationKey = Number160.createHash(currency);
|
||||||
|
final FutureDHT getOffersFuture = myPeer.get(locationKey).setAll().start();
|
||||||
|
getOffersFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void operationComplete(BaseFuture future) throws Exception
|
||||||
|
{
|
||||||
|
final Map<Number160, Data> dataMap = getOffersFuture.getDataMap();
|
||||||
|
Platform.runLater(() -> onOffersReceived(dataMap, future.isSuccess()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onOffersReceived(Map<Number160, Data> dataMap, boolean success)
|
||||||
|
{
|
||||||
|
log.trace("onOffersReceived");
|
||||||
|
orderBookListeners.stream().forEach(orderBookListener -> orderBookListener.onOffersReceived(dataMap, success));
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Remove offer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void removeOffer(Offer offer)
|
||||||
|
{
|
||||||
|
log.trace("removeOffer");
|
||||||
|
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
|
||||||
|
Number160 contentKey = Number160.createHash(offer.getId());
|
||||||
|
log.debug("removeOffer");
|
||||||
|
FutureDHT removeFuture = myPeer.remove(locationKey).setReturnResults().setContentKey(contentKey).start();
|
||||||
|
removeFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void operationComplete(BaseFuture future) throws Exception
|
||||||
|
{
|
||||||
|
Platform.runLater(() -> onOfferRemoved(removeFuture.getData(), future.isSuccess(), locationKey));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onOfferRemoved(Data data, boolean success, Number160 locationKey)
|
||||||
|
{
|
||||||
|
log.trace("onOfferRemoved");
|
||||||
|
setDirty(locationKey);
|
||||||
|
orderBookListeners.stream().forEach(orderBookListener -> orderBookListener.onOfferRemoved(data, success));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Trade process
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void sendTradeMessage(PeerAddress peerAddress, TradeMessage tradeMessage, OutgoingTradeMessageListener listener)
|
||||||
|
{
|
||||||
|
final PeerConnection peerConnection = myPeer.createPeerConnection(peerAddress, 10);
|
||||||
|
final FutureResponse sendFuture = myPeer.sendDirect(peerConnection).setObject(tradeMessage).start();
|
||||||
|
sendFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void operationComplete(BaseFuture baseFuture) throws Exception
|
||||||
|
{
|
||||||
|
if (sendFuture.isSuccess())
|
||||||
|
Platform.runLater(() -> listener.onResult());
|
||||||
|
else
|
||||||
|
Platform.runLater(() -> listener.onFailed());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Reputation
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void setupReputationRoot() throws IOException
|
public void setupReputationRoot() throws IOException
|
||||||
{
|
{
|
||||||
String pubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(getPubKey()); // out message ID
|
String pubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(getPubKey()); // out message ID
|
||||||
|
@ -149,6 +271,7 @@ public class MessageFacade
|
||||||
myPeer.put(locationKey).setData(contentKey, reputationData).start();
|
myPeer.put(locationKey).setData(contentKey, reputationData).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Arbitrators
|
// Arbitrators
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -199,100 +322,11 @@ public class MessageFacade
|
||||||
arbitratorListener.onArbitratorsReceived(dataMap, success);
|
arbitratorListener.onArbitratorsReceived(dataMap, success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Publish offer
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//TODO use Offer and do proper serialisation here
|
|
||||||
public void addOffer(Offer offer) throws IOException
|
|
||||||
{
|
|
||||||
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
|
|
||||||
final Number160 contentKey = Number160.createHash(offer.getId());
|
|
||||||
final Data offerData = new Data(offer);
|
|
||||||
//offerData.setTTLSeconds(5);
|
|
||||||
final FutureDHT addFuture = myPeer.put(locationKey).setData(contentKey, offerData).start();
|
|
||||||
//final FutureDHT addFuture = myPeer.add(locationKey).setData(offerData).start();
|
|
||||||
addFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void operationComplete(BaseFuture future) throws Exception
|
|
||||||
{
|
|
||||||
Platform.runLater(() -> onOfferAdded(offerData, future.isSuccess(), locationKey));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onOfferAdded(Data offerData, boolean success, Number160 locationKey)
|
|
||||||
{
|
|
||||||
setDirty(locationKey);
|
|
||||||
|
|
||||||
for (OrderBookListener orderBookListener : orderBookListeners)
|
|
||||||
orderBookListener.onOfferAdded(offerData, success);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Get offers
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public void getOffers(String currency)
|
|
||||||
{
|
|
||||||
final Number160 locationKey = Number160.createHash(currency);
|
|
||||||
final FutureDHT getOffersFuture = myPeer.get(locationKey).setAll().start();
|
|
||||||
getOffersFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void operationComplete(BaseFuture future) throws Exception
|
|
||||||
{
|
|
||||||
final Map<Number160, Data> dataMap = getOffersFuture.getDataMap();
|
|
||||||
Platform.runLater(() -> onOffersReceived(dataMap, future.isSuccess()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onOffersReceived(Map<Number160, Data> dataMap, boolean success)
|
|
||||||
{
|
|
||||||
for (OrderBookListener orderBookListener : orderBookListeners)
|
|
||||||
orderBookListener.onOffersReceived(dataMap, success);
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Remove offer
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public void removeOffer(Offer offer)
|
|
||||||
{
|
|
||||||
Number160 locationKey = Number160.createHash(offer.getCurrency().getCurrencyCode());
|
|
||||||
Number160 contentKey = Number160.createHash(offer.getId());
|
|
||||||
log.debug("removeOffer");
|
|
||||||
FutureDHT removeFuture = myPeer.remove(locationKey).setReturnResults().setContentKey(contentKey).start();
|
|
||||||
removeFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void operationComplete(BaseFuture future) throws Exception
|
|
||||||
{
|
|
||||||
Data data = removeFuture.getData();
|
|
||||||
Platform.runLater(() -> onOfferRemoved(data, future.isSuccess(), locationKey));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onOfferRemoved(Data data, boolean success, Number160 locationKey)
|
|
||||||
{
|
|
||||||
log.debug("onOfferRemoved");
|
|
||||||
setDirty(locationKey);
|
|
||||||
|
|
||||||
for (OrderBookListener orderBookListener : orderBookListeners)
|
|
||||||
orderBookListener.onOfferRemoved(data, success);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Check dirty flag for a location key
|
// Check dirty flag for a location key
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// TODO just temp...
|
||||||
public BooleanProperty getIsDirtyProperty()
|
public BooleanProperty getIsDirtyProperty()
|
||||||
{
|
{
|
||||||
return isDirty;
|
return isDirty;
|
||||||
|
@ -312,11 +346,7 @@ public class MessageFacade
|
||||||
{
|
{
|
||||||
Object object = data.getObject();
|
Object object = data.getObject();
|
||||||
if (object instanceof Long)
|
if (object instanceof Long)
|
||||||
{
|
Platform.runLater(() -> onGetDirtyFlag((Long) object));
|
||||||
final long lastTimeStamp = (Long) object;
|
|
||||||
//System.out.println("getDirtyFlag " + lastTimeStamp);
|
|
||||||
Platform.runLater(() -> onGetDirtyFlag(lastTimeStamp));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,149 +456,12 @@ public class MessageFacade
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Find peer address
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
public void getPeerAddress(String pubKeyAsHex, GetPeerAddressListener listener)
|
|
||||||
{
|
|
||||||
final Number160 location = Number160.createHash(pubKeyAsHex);
|
|
||||||
final FutureDHT getPeerAddressFuture = myPeer.get(location).start();
|
|
||||||
getPeerAddressFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void operationComplete(BaseFuture baseFuture) throws Exception
|
|
||||||
{
|
|
||||||
if (baseFuture.isSuccess() && getPeerAddressFuture.getData() != null)
|
|
||||||
{
|
|
||||||
final PeerAddress peerAddress = (PeerAddress) getPeerAddressFuture.getData().getObject();
|
|
||||||
Platform.runLater(() -> listener.onResult(peerAddress));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Platform.runLater(() -> listener.onFailed());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Trade process
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public void sendTradingMessage(final PeerAddress peerAddress, TradeMessage tradeMessage, TradeMessageListener listener)
|
|
||||||
{
|
|
||||||
final PeerConnection peerConnection = myPeer.createPeerConnection(peerAddress, 10);
|
|
||||||
final FutureResponse sendFuture = myPeer.sendDirect(peerConnection).setObject(tradeMessage).start();
|
|
||||||
sendFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void operationComplete(BaseFuture baseFuture) throws Exception
|
|
||||||
{
|
|
||||||
if (sendFuture.isSuccess())
|
|
||||||
{
|
|
||||||
Platform.runLater(() -> listener.onResult());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Platform.runLater(() -> listener.onFailed());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendTradeMessage(PeerAddress peerAddress, TradeMessage tradeMessage, TradeMessageListener listener)
|
|
||||||
{
|
|
||||||
final PeerConnection peerConnection = myPeer.createPeerConnection(peerAddress, 10);
|
|
||||||
final FutureResponse sendFuture = myPeer.sendDirect(peerConnection).setObject(tradeMessage).start();
|
|
||||||
sendFuture.addListener(new BaseFutureAdapter<BaseFuture>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void operationComplete(BaseFuture baseFuture) throws Exception
|
|
||||||
{
|
|
||||||
if (sendFuture.isSuccess())
|
|
||||||
{
|
|
||||||
Platform.runLater(() -> onSendTradingMessageResult(listener));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Platform.runLater(() -> onSendTradingMessageFailed(listener));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onSendTradingMessageResult(TradeMessageListener listener)
|
|
||||||
{
|
|
||||||
listener.onResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onSendTradingMessageFailed(TradeMessageListener listener)
|
|
||||||
{
|
|
||||||
listener.onFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Process incoming tradingMessage
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private void processTradingMessage(TradeMessage tradeMessage, PeerAddress sender)
|
|
||||||
{
|
|
||||||
// log.trace("processTradingMessage TradeId " + tradeMessage.getTradeId());
|
|
||||||
log.trace("processTradingMessage instance " + tradeMessage.getClass().getSimpleName());
|
|
||||||
log.trace("processTradingMessage instance " + tradeMessage.getClass().getName());
|
|
||||||
log.trace("processTradingMessage instance " + tradeMessage.getClass().getCanonicalName());
|
|
||||||
log.trace("processTradingMessage instance " + tradeMessage.getClass().getTypeName());
|
|
||||||
|
|
||||||
if (tradeMessage instanceof RequestTakeOfferMessage)
|
|
||||||
{
|
|
||||||
takeOfferRequestListeners.stream().forEach(e -> e.onTakeOfferRequested(tradeMessage.getTradeId(), sender));
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof AcceptTakeOfferRequestMessage)
|
|
||||||
{
|
|
||||||
takerPaymentProtocols.get(tradeMessage.getTradeId()).onAcceptTakeOfferRequestMessage();
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof RejectTakeOfferRequestMessage)
|
|
||||||
{
|
|
||||||
takerPaymentProtocols.get(tradeMessage.getTradeId()).onRejectTakeOfferRequestMessage();
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof TakeOfferFeePayedMessage)
|
|
||||||
{
|
|
||||||
offererAsBuyerProtocols.get(tradeMessage.getTradeId()).onTakeOfferFeePayedMessage((TakeOfferFeePayedMessage) tradeMessage);
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof RequestTakerDepositPaymentMessage)
|
|
||||||
{
|
|
||||||
takerPaymentProtocols.get(tradeMessage.getTradeId()).onRequestTakerDepositPaymentMessage((RequestTakerDepositPaymentMessage) tradeMessage);
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage)
|
|
||||||
{
|
|
||||||
offererAsBuyerProtocols.get(tradeMessage.getTradeId()).onRequestOffererPublishDepositTxMessage((RequestOffererPublishDepositTxMessage) tradeMessage);
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof DepositTxPublishedMessage)
|
|
||||||
{
|
|
||||||
takerPaymentProtocols.get(tradeMessage.getTradeId()).onDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof BankTransferInitedMessage)
|
|
||||||
{
|
|
||||||
takerPaymentProtocols.get(tradeMessage.getTradeId()).onBankTransferInitedMessage((BankTransferInitedMessage) tradeMessage);
|
|
||||||
}
|
|
||||||
else if (tradeMessage instanceof PayoutTxPublishedMessage)
|
|
||||||
{
|
|
||||||
offererAsBuyerProtocols.get(tradeMessage.getTradeId()).onPayoutTxPublishedMessage((PayoutTxPublishedMessage) tradeMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Ping peer
|
// Ping peer
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//TODO not working anymore...
|
//TODO not working anymore...
|
||||||
public void pingPeer(String publicKeyAsHex)
|
/* public void pingPeer(String publicKeyAsHex)
|
||||||
{
|
{
|
||||||
Number160 location = Number160.createHash(publicKeyAsHex);
|
Number160 location = Number160.createHash(publicKeyAsHex);
|
||||||
final FutureDHT getPeerAddressFuture = myPeer.get(location).start();
|
final FutureDHT getPeerAddressFuture = myPeer.get(location).start();
|
||||||
|
@ -587,7 +480,6 @@ public class MessageFacade
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void onAddressFoundPingPeer(PeerAddress peerAddress)
|
private void onAddressFoundPingPeer(PeerAddress peerAddress)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -626,16 +518,7 @@ public class MessageFacade
|
||||||
for (PingPeerListener pingPeerListener : pingPeerListeners)
|
for (PingPeerListener pingPeerListener : pingPeerListeners)
|
||||||
pingPeerListener.onPingPeerResult(success);
|
pingPeerListener.onPingPeerResult(success);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Misc
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public PublicKey getPubKey()
|
|
||||||
{
|
|
||||||
return keyPair.getPublic();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -652,37 +535,7 @@ public class MessageFacade
|
||||||
orderBookListeners.remove(listener);
|
orderBookListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTakeOfferRequestListener(TakeOfferRequestListener listener)
|
/* public void addPingPeerListener(PingPeerListener listener)
|
||||||
{
|
|
||||||
takeOfferRequestListeners.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeTakeOfferRequestListener(TakeOfferRequestListener listener)
|
|
||||||
{
|
|
||||||
takeOfferRequestListeners.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTakerPaymentProtocol(TakerAsSellerProtocol protocol)
|
|
||||||
{
|
|
||||||
takerPaymentProtocols.put(protocol.getId(), protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeTakerPaymentProtocol(TakerAsSellerProtocol protocol)
|
|
||||||
{
|
|
||||||
takerPaymentProtocols.remove(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addOffererPaymentProtocol(OffererAsBuyerProtocol protocol)
|
|
||||||
{
|
|
||||||
offererAsBuyerProtocols.put(protocol.getId(), protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeOffererPaymentProtocol(OffererAsBuyerProtocol protocol)
|
|
||||||
{
|
|
||||||
offererAsBuyerProtocols.remove(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addPingPeerListener(PingPeerListener listener)
|
|
||||||
{
|
{
|
||||||
pingPeerListeners.add(listener);
|
pingPeerListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
@ -690,7 +543,7 @@ public class MessageFacade
|
||||||
public void removePingPeerListener(PingPeerListener listener)
|
public void removePingPeerListener(PingPeerListener listener)
|
||||||
{
|
{
|
||||||
pingPeerListeners.remove(listener);
|
pingPeerListeners.remove(listener);
|
||||||
}
|
} */
|
||||||
|
|
||||||
public void addArbitratorListener(ArbitratorListener listener)
|
public void addArbitratorListener(ArbitratorListener listener)
|
||||||
{
|
{
|
||||||
|
@ -702,6 +555,44 @@ public class MessageFacade
|
||||||
arbitratorListeners.remove(listener);
|
arbitratorListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addIncomingTradeMessageListener(IncomingTradeMessageListener listener)
|
||||||
|
{
|
||||||
|
incomingTradeMessageListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeIncomingTradeMessageListener(IncomingTradeMessageListener listener)
|
||||||
|
{
|
||||||
|
incomingTradeMessageListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Getters
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public PublicKey getPubKey()
|
||||||
|
{
|
||||||
|
return keyPair.getPublic();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Incoming message handler
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void onMessage(Object request, PeerAddress sender)
|
||||||
|
{
|
||||||
|
if (request instanceof TradeMessage)
|
||||||
|
{
|
||||||
|
incomingTradeMessageListeners.stream().forEach(e -> e.onMessage((TradeMessage) request, sender));
|
||||||
|
}
|
||||||
|
/* else
|
||||||
|
{
|
||||||
|
for (OrderBookListener orderBookListener : orderBookListeners)
|
||||||
|
orderBookListener.onMessage(request);
|
||||||
|
} */
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Private Methods
|
// Private Methods
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -739,6 +630,18 @@ public class MessageFacade
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupReplyHandler()
|
||||||
|
{
|
||||||
|
myPeer.setObjectDataReply((sender, request) -> {
|
||||||
|
if (!sender.equals(myPeer.getPeerAddress()))
|
||||||
|
Platform.runLater(() -> onMessage(request, sender));
|
||||||
|
else
|
||||||
|
log.error("Received msg from myself. That should never happen.");
|
||||||
|
//noinspection ReturnOfNull
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void setupStorage()
|
private void setupStorage()
|
||||||
{
|
{
|
||||||
myPeer.getPeerBean().setStorage(new StorageDisk(FileUtil.getDirectory(BitSquare.ID + "_tomP2P").getAbsolutePath()));
|
myPeer.getPeerBean().setStorage(new StorageDisk(FileUtil.getDirectory(BitSquare.ID + "_tomP2P").getAbsolutePath()));
|
||||||
|
@ -752,49 +655,4 @@ public class MessageFacade
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Incoming message handler
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private void setupReplyHandler()
|
|
||||||
{
|
|
||||||
/* myPeer.setObjectDataReply((sender, request) -> {
|
|
||||||
if (!sender.equals(myPeer.getPeerAddress()))
|
|
||||||
{
|
|
||||||
Platform.runLater(() -> onMessage(request, sender));
|
|
||||||
}
|
|
||||||
//noinspection ReturnOfNull
|
|
||||||
return null;
|
|
||||||
}); */
|
|
||||||
|
|
||||||
//noinspection Convert2Lambda
|
|
||||||
myPeer.setObjectDataReply(new ObjectDataReply()
|
|
||||||
{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object reply(PeerAddress sender, Object request) throws Exception
|
|
||||||
{
|
|
||||||
if (!sender.equals(myPeer.getPeerAddress()))
|
|
||||||
{
|
|
||||||
Platform.runLater(() -> onMessage(request, sender));
|
|
||||||
}
|
|
||||||
//noinspection ReturnOfNull
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onMessage(Object request, PeerAddress sender)
|
|
||||||
{
|
|
||||||
if (request instanceof TradeMessage)
|
|
||||||
{
|
|
||||||
processTradingMessage((TradeMessage) request, sender);
|
|
||||||
}
|
|
||||||
/* else
|
|
||||||
{
|
|
||||||
for (OrderBookListener orderBookListener : orderBookListeners)
|
|
||||||
orderBookListener.onMessage(request);
|
|
||||||
} */
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.taker.listeners;
|
package io.bitsquare.msg.listeners;
|
||||||
|
|
||||||
import net.tomp2p.peers.PeerAddress;
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package io.bitsquare.msg.listeners;
|
||||||
|
|
||||||
|
import io.bitsquare.msg.TradeMessage;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
|
||||||
|
public interface IncomingTradeMessageListener
|
||||||
|
{
|
||||||
|
void onMessage(TradeMessage tradeMessage, PeerAddress sender);
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package io.bitsquare.msg.listeners;
|
package io.bitsquare.msg.listeners;
|
||||||
|
|
||||||
public interface TradeMessageListener
|
public interface OutgoingTradeMessageListener
|
||||||
{
|
{
|
||||||
void onFailed();
|
void onFailed();
|
||||||
|
|
|
@ -167,7 +167,7 @@ public class Offer implements Serializable
|
||||||
return collateral;
|
return collateral;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBankAccountUID()
|
public String getBankAccountId()
|
||||||
{
|
{
|
||||||
return bankAccountUID;
|
return bankAccountUID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import java.math.BigInteger;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
|
||||||
@SuppressWarnings("SameParameterValue")
|
|
||||||
public class Trade implements Serializable
|
public class Trade implements Serializable
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = -8275323072940974077L;
|
private static final long serialVersionUID = -8275323072940974077L;
|
||||||
|
@ -22,7 +21,6 @@ public class Trade implements Serializable
|
||||||
private String takerSignature;
|
private String takerSignature;
|
||||||
private Transaction depositTransaction;
|
private Transaction depositTransaction;
|
||||||
private Transaction payoutTransaction;
|
private Transaction payoutTransaction;
|
||||||
|
|
||||||
private State state = State.OPEN;
|
private State state = State.OPEN;
|
||||||
|
|
||||||
public Trade(Offer offer)
|
public Trade(Offer offer)
|
||||||
|
@ -30,15 +28,16 @@ public class Trade implements Serializable
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContractTakerSignature(String takerSignature)
|
|
||||||
{
|
|
||||||
this.takerSignature = takerSignature;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Setters
|
// Setters
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void setContractTakerSignature(String takerSignature)
|
||||||
|
{
|
||||||
|
this.takerSignature = takerSignature;
|
||||||
|
}
|
||||||
|
|
||||||
public void setTakeOfferFeeTxID(String takeOfferFeeTxID)
|
public void setTakeOfferFeeTxID(String takeOfferFeeTxID)
|
||||||
{
|
{
|
||||||
this.takeOfferFeeTxID = takeOfferFeeTxID;
|
this.takeOfferFeeTxID = takeOfferFeeTxID;
|
||||||
|
|
|
@ -8,55 +8,61 @@ import io.bitsquare.btc.BlockChainFacade;
|
||||||
import io.bitsquare.btc.WalletFacade;
|
import io.bitsquare.btc.WalletFacade;
|
||||||
import io.bitsquare.crypto.CryptoFacade;
|
import io.bitsquare.crypto.CryptoFacade;
|
||||||
import io.bitsquare.msg.MessageFacade;
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.msg.TradeMessage;
|
||||||
|
import io.bitsquare.msg.listeners.TakeOfferRequestListener;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
import io.bitsquare.trade.payment.offerer.OffererAsBuyerProtocol;
|
import io.bitsquare.trade.protocol.messages.offerer.*;
|
||||||
import io.bitsquare.trade.payment.offerer.OffererAsBuyerProtocolListener;
|
import io.bitsquare.trade.protocol.messages.taker.PayoutTxPublishedMessage;
|
||||||
import io.bitsquare.trade.payment.taker.TakerAsSellerProtocol;
|
import io.bitsquare.trade.protocol.messages.taker.RequestOffererPublishDepositTxMessage;
|
||||||
import io.bitsquare.trade.payment.taker.TakerAsSellerProtocolListener;
|
import io.bitsquare.trade.protocol.messages.taker.RequestTakeOfferMessage;
|
||||||
|
import io.bitsquare.trade.protocol.messages.taker.TakeOfferFeePayedMessage;
|
||||||
|
import io.bitsquare.trade.protocol.offerer.OffererAsBuyerProtocol;
|
||||||
|
import io.bitsquare.trade.protocol.offerer.OffererAsBuyerProtocolListener;
|
||||||
|
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocol;
|
||||||
|
import io.bitsquare.trade.protocol.taker.TakerAsSellerProtocolListener;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
import io.nucleo.scheduler.worker.Worker;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
import net.tomp2p.peers.PeerAddress;
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents trade domain. Keeps complexity of process apart from view controller
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("EmptyMethod")
|
|
||||||
public class Trading
|
public class Trading
|
||||||
{
|
{
|
||||||
private static final Logger log = LoggerFactory.getLogger(Trading.class);
|
private static final Logger log = LoggerFactory.getLogger(Trading.class);
|
||||||
private final Map<String, TakerAsSellerProtocol> takerPaymentProtocols = new HashMap<>();
|
|
||||||
private final Map<String, OffererAsBuyerProtocol> offererPaymentProtocols = new HashMap<>();
|
|
||||||
private final String storageKey;
|
|
||||||
private final User user;
|
|
||||||
|
|
||||||
|
private final String storageKey = this.getClass().getName();
|
||||||
|
|
||||||
|
private final User user;
|
||||||
private final Storage storage;
|
private final Storage storage;
|
||||||
private final MessageFacade messageFacade;
|
private final MessageFacade messageFacade;
|
||||||
private final BlockChainFacade blockChainFacade;
|
private final BlockChainFacade blockChainFacade;
|
||||||
private final WalletFacade walletFacade;
|
private final WalletFacade walletFacade;
|
||||||
private final CryptoFacade cryptoFacade;
|
private final CryptoFacade cryptoFacade;
|
||||||
|
|
||||||
|
private final List<TakeOfferRequestListener> takeOfferRequestListeners = new ArrayList<>();
|
||||||
|
private final Map<String, TakerAsSellerProtocol> takerAsSellerProtocolMap = new HashMap<>();
|
||||||
|
private final Map<String, OffererAsBuyerProtocol> offererAsBuyerProtocolMap = new HashMap<>();
|
||||||
|
|
||||||
private final StringProperty newTradeProperty = new SimpleStringProperty();
|
private final StringProperty newTradeProperty = new SimpleStringProperty();
|
||||||
|
|
||||||
private Map<String, Offer> offers = new HashMap<>();
|
private final Map<String, Offer> offers;
|
||||||
|
private final Map<String, Trade> trades;
|
||||||
|
|
||||||
private Map<String, Trade> trades = new HashMap<>();
|
private Trade pendingTrade;
|
||||||
private Trade currentPendingTrade;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Inject
|
@Inject
|
||||||
public Trading(User user,
|
public Trading(User user,
|
||||||
Storage storage,
|
Storage storage,
|
||||||
|
@ -72,36 +78,55 @@ public class Trading
|
||||||
this.walletFacade = walletFacade;
|
this.walletFacade = walletFacade;
|
||||||
this.cryptoFacade = cryptoFacade;
|
this.cryptoFacade = cryptoFacade;
|
||||||
|
|
||||||
storageKey = this.getClass().getName();
|
|
||||||
|
|
||||||
Object offersObject = storage.read(storageKey + ".offers");
|
Object offersObject = storage.read(storageKey + ".offers");
|
||||||
if (offersObject instanceof HashMap)
|
if (offersObject instanceof HashMap)
|
||||||
offers = (Map<String, Offer>) offersObject;
|
offers = (Map<String, Offer>) offersObject;
|
||||||
|
else
|
||||||
|
offers = new HashMap<>();
|
||||||
|
|
||||||
Object tradesObject = storage.read(storageKey + ".trades");
|
Object tradesObject = storage.read(storageKey + ".trades");
|
||||||
if (tradesObject instanceof HashMap)
|
if (tradesObject instanceof HashMap)
|
||||||
trades = (Map<String, Trade>) tradesObject;
|
trades = (Map<String, Trade>) tradesObject;
|
||||||
|
else
|
||||||
|
trades = new HashMap<>();
|
||||||
|
|
||||||
messageFacade.addTakeOfferRequestListener((offerId, sender) -> createOffererAsBuyerProtocol(offerId, sender));
|
messageFacade.addIncomingTradeMessageListener(this::onIncomingTradeMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Public Methods
|
// Public Methods
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void cleanup()
|
public void cleanup()
|
||||||
{
|
{
|
||||||
|
messageFacade.removeIncomingTradeMessageListener(this::onIncomingTradeMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveOffers()
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Event Listeners
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void addTakeOfferRequestListener(TakeOfferRequestListener listener)
|
||||||
{
|
{
|
||||||
storage.write(storageKey + ".offers", offers);
|
takeOfferRequestListeners.add(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeTakeOfferRequestListener(TakeOfferRequestListener listener)
|
||||||
|
{
|
||||||
|
takeOfferRequestListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Manage offers
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void addOffer(Offer offer) throws IOException
|
public void addOffer(Offer offer) throws IOException
|
||||||
{
|
{
|
||||||
if (offers.containsKey(offer.getId()))
|
if (offers.containsKey(offer.getId()))
|
||||||
throw new IllegalStateException("offers contains already a offer with the ID " + offer.getId());
|
throw new IllegalStateException("offers contains already an offer with the ID " + offer.getId());
|
||||||
|
|
||||||
offers.put(offer.getId(), offer);
|
offers.put(offer.getId(), offer);
|
||||||
saveOffers();
|
saveOffers();
|
||||||
|
@ -109,22 +134,44 @@ public class Trading
|
||||||
messageFacade.addOffer(offer);
|
messageFacade.addOffer(offer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeOffer(Offer offer) throws IOException
|
public void removeOffer(Offer offer)
|
||||||
{
|
{
|
||||||
|
if (!offers.containsKey(offer.getId()))
|
||||||
|
throw new IllegalStateException("offers does not contain the offer with the ID " + offer.getId());
|
||||||
|
|
||||||
offers.remove(offer.getId());
|
offers.remove(offer.getId());
|
||||||
saveOffers();
|
saveOffers();
|
||||||
|
|
||||||
messageFacade.removeOffer(offer);
|
messageFacade.removeOffer(offer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Trade takeOffer(BigInteger amount, Offer offer, TakerAsSellerProtocolListener listener)
|
||||||
|
{
|
||||||
|
Trade trade = createTrade(offer);
|
||||||
|
trade.setTradeAmount(amount);
|
||||||
|
|
||||||
|
TakerAsSellerProtocol takerAsSellerProtocol = new TakerAsSellerProtocol(trade, listener, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user);
|
||||||
|
takerAsSellerProtocolMap.put(trade.getId(), takerAsSellerProtocol);
|
||||||
|
takerAsSellerProtocol.start();
|
||||||
|
|
||||||
|
return trade;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Manage trades
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public Trade createTrade(Offer offer)
|
public Trade createTrade(Offer offer)
|
||||||
{
|
{
|
||||||
|
if (trades.containsKey(offer.getId()))
|
||||||
|
throw new IllegalStateException("trades contains already an trade with the ID " + offer.getId());
|
||||||
|
|
||||||
Trade trade = new Trade(offer);
|
Trade trade = new Trade(offer);
|
||||||
trades.put(offer.getId(), trade);
|
trades.put(offer.getId(), trade);
|
||||||
//TODO for testing
|
saveTrades();
|
||||||
//storage.write(storageKey + ".trades", trades);
|
|
||||||
|
|
||||||
|
// for updating UIs
|
||||||
this.newTradeProperty.set(trade.getId());
|
this.newTradeProperty.set(trade.getId());
|
||||||
|
|
||||||
return trade;
|
return trade;
|
||||||
|
@ -132,39 +179,39 @@ public class Trading
|
||||||
|
|
||||||
public void removeTrade(Trade trade)
|
public void removeTrade(Trade trade)
|
||||||
{
|
{
|
||||||
|
if (!trades.containsKey(trade.getId()))
|
||||||
|
throw new IllegalStateException("trades does not contain the trade with the ID " + trade.getId());
|
||||||
|
|
||||||
trades.remove(trade.getId());
|
trades.remove(trade.getId());
|
||||||
storage.write(storageKey + ".trades", trades);
|
saveTrades();
|
||||||
|
|
||||||
|
// for updating UIs
|
||||||
|
this.newTradeProperty.set(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public final StringProperty getNewTradeProperty()
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
{
|
// Trading protocols
|
||||||
return this.newTradeProperty;
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
}
|
|
||||||
|
|
||||||
public Trade takeOffer(BigInteger amount, Offer offer, TakerAsSellerProtocolListener listener, WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
private void createOffererAsBuyerProtocol(String offerId, PeerAddress sender)
|
||||||
{
|
|
||||||
Trade trade = createTrade(offer);
|
|
||||||
trade.setTradeAmount(amount);
|
|
||||||
|
|
||||||
TakerAsSellerProtocol takerPaymentProtocol = new TakerAsSellerProtocol(trade, listener, resultHandler, faultHandler, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user);
|
|
||||||
takerPaymentProtocols.put(trade.getId(), takerPaymentProtocol);
|
|
||||||
|
|
||||||
return trade;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void createOffererAsBuyerProtocol(String offerId, PeerAddress sender)
|
|
||||||
{
|
{
|
||||||
log.trace("createOffererAsBuyerProtocol offerId = " + offerId);
|
log.trace("createOffererAsBuyerProtocol offerId = " + offerId);
|
||||||
|
if (offers.containsKey(offerId))
|
||||||
|
{
|
||||||
Offer offer = offers.get(offerId);
|
Offer offer = offers.get(offerId);
|
||||||
if (offer != null && offers.containsKey(offer.getId()))
|
|
||||||
{
|
|
||||||
offers.remove(offer);
|
|
||||||
|
|
||||||
currentPendingTrade = createTrade(offer);
|
Trade trade = createTrade(offer);
|
||||||
OffererAsBuyerProtocolListener listener = new OffererAsBuyerProtocolListener()
|
pendingTrade = trade;
|
||||||
|
|
||||||
|
OffererAsBuyerProtocol offererAsBuyerProtocol = new OffererAsBuyerProtocol(trade, sender, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user, new OffererAsBuyerProtocolListener()
|
||||||
{
|
{
|
||||||
|
@Override
|
||||||
|
public void onOfferAccepted(Offer offer)
|
||||||
|
{
|
||||||
|
removeOffer(offer);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDepositTxPublished(String depositTxID)
|
public void onDepositTxPublished(String depositTxID)
|
||||||
{
|
{
|
||||||
|
@ -181,8 +228,8 @@ public class Trading
|
||||||
public void onPayoutTxPublished(String payoutTxAsHex)
|
public void onPayoutTxPublished(String payoutTxAsHex)
|
||||||
{
|
{
|
||||||
Transaction payoutTx = new Transaction(walletFacade.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
|
Transaction payoutTx = new Transaction(walletFacade.getWallet().getParams(), Utils.parseAsHexOrBase58(payoutTxAsHex));
|
||||||
currentPendingTrade.setPayoutTransaction(payoutTx);
|
trade.setPayoutTransaction(payoutTx);
|
||||||
currentPendingTrade.setState(Trade.State.COMPLETED);
|
trade.setState(Trade.State.COMPLETED);
|
||||||
log.debug("trading onPayoutTxPublishedMessage");
|
log.debug("trading onPayoutTxPublishedMessage");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,27 +239,9 @@ public class Trading
|
||||||
log.trace("trading onDepositTxConfirmedInBlockchain");
|
log.trace("trading onDepositTxConfirmedInBlockchain");
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
});
|
||||||
|
this.offererAsBuyerProtocolMap.put(trade.getId(), offererAsBuyerProtocol);
|
||||||
WorkerResultHandler resultHandler = new WorkerResultHandler()
|
offererAsBuyerProtocol.start();
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult(Worker worker)
|
|
||||||
{
|
|
||||||
//log.trace("onResult " + worker.toString());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
WorkerFaultHandler faultHandler = new WorkerFaultHandler()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onFault(Throwable throwable)
|
|
||||||
{
|
|
||||||
log.error("onFault " + throwable);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
OffererAsBuyerProtocol offererAsBuyerProtocol = new OffererAsBuyerProtocol(currentPendingTrade, sender, messageFacade, walletFacade, blockChainFacade, cryptoFacade, user, resultHandler, faultHandler, listener);
|
|
||||||
offererPaymentProtocols.put(currentPendingTrade.getId(), offererAsBuyerProtocol);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -220,35 +249,89 @@ public class Trading
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void bankTransferInited(String tradeUID)
|
||||||
public void onUIEventBankTransferInited(String tradeUID)
|
|
||||||
{
|
{
|
||||||
offererPaymentProtocols.get(tradeUID).onUIEventBankTransferInited();
|
offererAsBuyerProtocolMap.get(tradeUID).onUIEventBankTransferInited();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFiatReceived(String tradeUID)
|
||||||
|
{
|
||||||
|
takerAsSellerProtocolMap.get(tradeUID).onUIEventFiatReceived();
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Process incoming tradeMessages
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void onIncomingTradeMessage(TradeMessage tradeMessage, PeerAddress sender)
|
||||||
|
{
|
||||||
|
// log.trace("processTradingMessage TradeId " + tradeMessage.getTradeId());
|
||||||
|
log.trace("processTradingMessage instance " + tradeMessage.getClass().getSimpleName());
|
||||||
|
log.trace("processTradingMessage instance " + tradeMessage.getClass().getName());
|
||||||
|
log.trace("processTradingMessage instance " + tradeMessage.getClass().getCanonicalName());
|
||||||
|
log.trace("processTradingMessage instance " + tradeMessage.getClass().getTypeName());
|
||||||
|
|
||||||
|
String tradeId = tradeMessage.getTradeId();
|
||||||
|
|
||||||
|
if (tradeMessage instanceof RequestTakeOfferMessage)
|
||||||
|
{
|
||||||
|
createOffererAsBuyerProtocol(tradeId, sender);
|
||||||
|
takeOfferRequestListeners.stream().forEach(e -> e.onTakeOfferRequested(tradeId, sender));
|
||||||
|
}
|
||||||
|
else if (tradeMessage instanceof AcceptTakeOfferRequestMessage)
|
||||||
|
{
|
||||||
|
takerAsSellerProtocolMap.get(tradeId).onAcceptTakeOfferRequestMessage();
|
||||||
|
}
|
||||||
|
else if (tradeMessage instanceof RejectTakeOfferRequestMessage)
|
||||||
|
{
|
||||||
|
takerAsSellerProtocolMap.get(tradeId).onRejectTakeOfferRequestMessage();
|
||||||
|
}
|
||||||
|
else if (tradeMessage instanceof TakeOfferFeePayedMessage)
|
||||||
|
{
|
||||||
|
offererAsBuyerProtocolMap.get(tradeId).onTakeOfferFeePayedMessage((TakeOfferFeePayedMessage) tradeMessage);
|
||||||
|
}
|
||||||
|
else if (tradeMessage instanceof RequestTakerDepositPaymentMessage)
|
||||||
|
{
|
||||||
|
takerAsSellerProtocolMap.get(tradeId).onRequestTakerDepositPaymentMessage((RequestTakerDepositPaymentMessage) tradeMessage);
|
||||||
|
}
|
||||||
|
else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage)
|
||||||
|
{
|
||||||
|
offererAsBuyerProtocolMap.get(tradeId).onRequestOffererPublishDepositTxMessage((RequestOffererPublishDepositTxMessage) tradeMessage);
|
||||||
|
}
|
||||||
|
else if (tradeMessage instanceof DepositTxPublishedMessage)
|
||||||
|
{
|
||||||
|
takerAsSellerProtocolMap.get(tradeId).onDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
|
||||||
|
}
|
||||||
|
else if (tradeMessage instanceof BankTransferInitedMessage)
|
||||||
|
{
|
||||||
|
takerAsSellerProtocolMap.get(tradeId).onBankTransferInitedMessage((BankTransferInitedMessage) tradeMessage);
|
||||||
|
}
|
||||||
|
else if (tradeMessage instanceof PayoutTxPublishedMessage)
|
||||||
|
{
|
||||||
|
offererAsBuyerProtocolMap.get(tradeId).onPayoutTxPublishedMessage((PayoutTxPublishedMessage) tradeMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Trade process
|
// Utils
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public boolean isOfferAlreadyInTrades(Offer offer)
|
||||||
// 6
|
|
||||||
public void releaseBTC(String tradeUID)
|
|
||||||
{
|
{
|
||||||
takerPaymentProtocols.get(tradeUID).onUIEventFiatReceived();
|
return trades.containsKey(offer.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Getters
|
// Getters
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
public Map<String, Trade> getTrades()
|
public Map<String, Trade> getTrades()
|
||||||
{
|
{
|
||||||
return trades;
|
return trades;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Map<String, Offer> getOffers()
|
public Map<String, Offer> getOffers()
|
||||||
{
|
{
|
||||||
return offers;
|
return offers;
|
||||||
|
@ -259,14 +342,37 @@ public class Trading
|
||||||
return offers.get(offerId);
|
return offers.get(offerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Trade getPendingTrade()
|
||||||
public boolean isOfferAlreadyInTrades(Offer offer)
|
|
||||||
{
|
{
|
||||||
return trades.containsKey(offer.getId());
|
return pendingTrade;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Trade getCurrentPendingTrade()
|
public final StringProperty getNewTradeProperty()
|
||||||
{
|
{
|
||||||
return currentPendingTrade;
|
return this.newTradeProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Private
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void saveOffers()
|
||||||
|
{
|
||||||
|
storage.write(storageKey + ".offers", offers);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveTrades()
|
||||||
|
{
|
||||||
|
storage.write(storageKey + ".trades", trades);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Trade getTrade(String tradeId)
|
||||||
|
{
|
||||||
|
if (trades.containsKey(tradeId))
|
||||||
|
return trades.get(trades);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,14 +76,8 @@ public class OrderBook implements OrderBookListener
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeOffer(Offer offer)
|
public void removeOffer(Offer offer)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
trading.removeOffer(offer);
|
trading.removeOffer(offer);
|
||||||
} catch (IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyFilter(OrderBookFilter orderBookFilter)
|
public void applyFilter(OrderBookFilter orderBookFilter)
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package io.bitsquare.trade.payment;
|
|
||||||
|
|
||||||
import io.bitsquare.msg.MessageFacade;
|
|
||||||
import io.bitsquare.trade.Offer;
|
|
||||||
import io.bitsquare.trade.Trade;
|
|
||||||
import io.nucleo.scheduler.model.PropertyProviderModel;
|
|
||||||
import net.tomp2p.peers.PeerAddress;
|
|
||||||
|
|
||||||
public class PaymentModel extends PropertyProviderModel
|
|
||||||
{
|
|
||||||
public final MessageFacade messageFacade;
|
|
||||||
public final Offer offer;
|
|
||||||
public PeerAddress peerAddress;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructor
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public PaymentModel(MessageFacade messageFacade, Trade trade)
|
|
||||||
{
|
|
||||||
this.messageFacade = messageFacade;
|
|
||||||
this.offer = trade.getOffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.trade.payment.offerer.OffererAsBuyerProtocol;
|
|
||||||
import io.nucleo.scheduler.tasks.AbstractTask;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public abstract class AbstractOffererAsBuyerTask extends AbstractTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AbstractOffererAsBuyerTask.class);
|
|
||||||
|
|
||||||
protected OffererAsBuyerProtocol sharedModel;
|
|
||||||
|
|
||||||
public AbstractOffererAsBuyerTask(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
addResultHandlers(resultHandler);
|
|
||||||
addFaultHandlers(faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setModel(Object model)
|
|
||||||
{
|
|
||||||
sharedModel = (OffererAsBuyerProtocol) model;
|
|
||||||
super.setModel(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import com.google.bitcoin.core.InsufficientMoneyException;
|
|
||||||
import com.google.bitcoin.core.Transaction;
|
|
||||||
import com.google.bitcoin.core.Utils;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class CreateDepositTx extends AbstractOffererAsBuyerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(CreateDepositTx.class);
|
|
||||||
|
|
||||||
public CreateDepositTx(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
sharedModel.setOffererPubKey(sharedModel.getWalletFacade().getAddressInfoByTradeID(sharedModel.getTrade().getId()).getPubKeyAsHexString());
|
|
||||||
Transaction tx = sharedModel.getWalletFacade().offererCreatesMSTxAndAddPayment(sharedModel.getTrade().getCollateralAmount(),
|
|
||||||
sharedModel.getOffererPubKey(),
|
|
||||||
sharedModel.getTakerMultiSigPubKey(),
|
|
||||||
sharedModel.getTrade().getOffer().getArbitrator().getPubKeyAsHex(),
|
|
||||||
sharedModel.getTrade().getId());
|
|
||||||
|
|
||||||
sharedModel.setPreparedOffererDepositTxAsHex(Utils.bytesToHexString(tx.bitcoinSerialize()));
|
|
||||||
sharedModel.setOffererTxOutIndex(tx.getInput(0).getOutpoint().getIndex());
|
|
||||||
complete();
|
|
||||||
} catch (InsufficientMoneyException e)
|
|
||||||
{
|
|
||||||
log.error("Create deposit tx failed due InsufficientMoneyException " + e);
|
|
||||||
failed(new Exception("Create deposit tx failed due InsufficientMoneyException " + e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.msg.listeners.TradeMessageListener;
|
|
||||||
import io.bitsquare.trade.Trade;
|
|
||||||
import io.bitsquare.trade.payment.offerer.messages.AcceptTakeOfferRequestMessage;
|
|
||||||
import io.bitsquare.trade.payment.offerer.messages.RejectTakeOfferRequestMessage;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class HandleTakeOfferRequest extends AbstractOffererAsBuyerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(HandleTakeOfferRequest.class);
|
|
||||||
|
|
||||||
public HandleTakeOfferRequest(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
if (sharedModel.getTrade().getState() == Trade.State.OPEN)
|
|
||||||
{
|
|
||||||
AcceptTakeOfferRequestMessage msg = new AcceptTakeOfferRequestMessage(sharedModel.getTrade().getId());
|
|
||||||
sharedModel.getMessageFacade().sendTradeMessage(sharedModel.peerAddress, msg, new TradeMessageListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult()
|
|
||||||
{
|
|
||||||
log.trace("AcceptTakeOfferRequestMessage successfully arrived at peer");
|
|
||||||
sharedModel.getTrade().setState(Trade.State.ACCEPTED);
|
|
||||||
sharedModel.getMessageFacade().removeOffer(sharedModel.getTrade().getOffer());
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed()
|
|
||||||
{
|
|
||||||
log.error("AcceptTakeOfferRequestMessage failed to arrive at peer");
|
|
||||||
failed(new Exception("AcceptTakeOfferRequestMessage failed to arrive at peer"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RejectTakeOfferRequestMessage msg = new RejectTakeOfferRequestMessage(sharedModel.getTrade().getId());
|
|
||||||
sharedModel.getMessageFacade().sendTradeMessage(sharedModel.peerAddress, msg, new TradeMessageListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult()
|
|
||||||
{
|
|
||||||
log.trace("RejectTakeOfferRequestMessage successfully arrived at peer");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed()
|
|
||||||
{
|
|
||||||
log.error("RejectTakeOfferRequestMessage failed to arrive at peer");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.error("Offer not marked as open.");
|
|
||||||
failed(new Exception("Offer not marked as open."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.msg.listeners.TradeMessageListener;
|
|
||||||
import io.bitsquare.trade.payment.offerer.messages.RequestTakerDepositPaymentMessage;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class RequestTakerDepositPayment extends AbstractOffererAsBuyerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(RequestTakerDepositPayment.class);
|
|
||||||
|
|
||||||
public RequestTakerDepositPayment(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
|
|
||||||
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(sharedModel.getTrade().getId(),
|
|
||||||
sharedModel.getUser().getBankAccount(sharedModel.getTrade().getOffer().getBankAccountUID()),
|
|
||||||
sharedModel.getUser().getAccountID(),
|
|
||||||
sharedModel.getOffererPubKey(),
|
|
||||||
sharedModel.getPreparedOffererDepositTxAsHex(),
|
|
||||||
sharedModel.getOffererTxOutIndex());
|
|
||||||
sharedModel.getMessageFacade().sendTradeMessage(sharedModel.peerAddress, tradeMessage, new TradeMessageListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult()
|
|
||||||
{
|
|
||||||
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed()
|
|
||||||
{
|
|
||||||
log.error("RequestTakerDepositPaymentMessage failed to arrive at peer");
|
|
||||||
failed(new Exception("RequestTakerDepositPaymentMessage failed to arrive at peer"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import com.google.bitcoin.core.Utils;
|
|
||||||
import io.bitsquare.msg.listeners.TradeMessageListener;
|
|
||||||
import io.bitsquare.trade.payment.offerer.messages.DepositTxPublishedMessage;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class SendDepositTxIdToTaker extends AbstractOffererAsBuyerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SendDepositTxIdToTaker.class);
|
|
||||||
|
|
||||||
public SendDepositTxIdToTaker(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(sharedModel.getTrade().getId(), Utils.bytesToHexString(sharedModel.getTrade().getDepositTransaction().bitcoinSerialize()));
|
|
||||||
sharedModel.getMessageFacade().sendTradeMessage(sharedModel.peerAddress, tradeMessage, new TradeMessageListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult()
|
|
||||||
{
|
|
||||||
log.trace("DepositTxPublishedMessage successfully arrived at peer");
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed()
|
|
||||||
{
|
|
||||||
log.error("DepositTxPublishedMessage failed to arrive at peer");
|
|
||||||
failed(new Exception("DepositTxPublishedMessage failed to arrive at peer"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import com.google.bitcoin.core.Transaction;
|
|
||||||
import com.google.bitcoin.core.TransactionConfidence;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class SetupListenerForBlockChainConfirmation extends AbstractOffererAsBuyerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);
|
|
||||||
|
|
||||||
public SetupListenerForBlockChainConfirmation(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
//TODO
|
|
||||||
// sharedModel.offererPaymentProtocolListener.onDepositTxConfirmedInBlockchain();
|
|
||||||
|
|
||||||
Transaction tx = sharedModel.getTrade().getDepositTransaction();
|
|
||||||
tx.getConfidence().addEventListener(new TransactionConfidence.Listener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onConfidenceChanged(Transaction tx, ChangeReason reason)
|
|
||||||
{
|
|
||||||
log.trace("onConfidenceChanged " + tx.getConfidence());
|
|
||||||
if (reason == ChangeReason.SEEN_PEERS)
|
|
||||||
{
|
|
||||||
sharedModel.getListener().onDepositTxConfirmedUpdate(tx.getConfidence());
|
|
||||||
}
|
|
||||||
if (reason == ChangeReason.TYPE && tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
|
|
||||||
{
|
|
||||||
sharedModel.getListener().onDepositTxConfirmedInBlockchain();
|
|
||||||
tx.getConfidence().removeEventListener(this);
|
|
||||||
log.trace("Tx is in blockchain");
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import com.google.bitcoin.core.Transaction;
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class SignAndPublishDepositTx extends AbstractOffererAsBuyerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTx.class);
|
|
||||||
|
|
||||||
public SignAndPublishDepositTx(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
sharedModel.getWalletFacade().offererSignAndPublishTx(sharedModel.getPreparedOffererDepositTxAsHex(),
|
|
||||||
sharedModel.getSignedTakerDepositTxAsHex(),
|
|
||||||
sharedModel.getTxConnOutAsHex(),
|
|
||||||
sharedModel.getTxScriptSigAsHex(),
|
|
||||||
sharedModel.getOffererTxOutIndex(),
|
|
||||||
sharedModel.getTakerTxOutIndex(),
|
|
||||||
new FutureCallback<Transaction>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Transaction transaction)
|
|
||||||
{
|
|
||||||
log.trace("offererSignAndPublishTx succeeded " + transaction);
|
|
||||||
sharedModel.getTrade().setDepositTransaction(transaction);
|
|
||||||
sharedModel.getListener().onDepositTxPublished(transaction.getHashAsString());
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable t)
|
|
||||||
{
|
|
||||||
log.error("offererSignAndPublishTx failed:" + t);
|
|
||||||
failed(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("offererSignAndPublishTx failed:" + e);
|
|
||||||
failed(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.trade.Contract;
|
|
||||||
import io.bitsquare.util.Utilities;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class VerifyAndSignContract extends AbstractOffererAsBuyerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(VerifyAndSignContract.class);
|
|
||||||
|
|
||||||
public VerifyAndSignContract(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
Contract contract = new Contract(sharedModel.getTrade().getOffer(),
|
|
||||||
sharedModel.getTrade().getTradeAmount(),
|
|
||||||
sharedModel.getTrade().getTakeOfferFeeTxId(),
|
|
||||||
sharedModel.getUser().getAccountID(),
|
|
||||||
sharedModel.getPeersAccountId(),
|
|
||||||
sharedModel.getUser().getCurrentBankAccount(),
|
|
||||||
sharedModel.getPeersBankAccount(),
|
|
||||||
sharedModel.getTrade().getOffer().getMessagePubKeyAsHex(),
|
|
||||||
sharedModel.getTakerMessagePubKey());
|
|
||||||
|
|
||||||
String contractAsJson = Utilities.objectToJson(contract);
|
|
||||||
// log.trace("Offerer contract created: " + contract);
|
|
||||||
// log.trace("Offerers contractAsJson: " + contractAsJson);
|
|
||||||
// log.trace("Takers contractAsJson: " + sharedModel.peersContractAsJson);
|
|
||||||
if (contractAsJson.equals(sharedModel.getPeersContractAsJson()))
|
|
||||||
{
|
|
||||||
log.trace("The 2 contracts as json does match");
|
|
||||||
String signature = sharedModel.getCryptoFacade().signContract(sharedModel.getWalletFacade().getRegistrationAddressInfo().getKey(), contractAsJson);
|
|
||||||
sharedModel.getTrade().setContract(contract);
|
|
||||||
sharedModel.getTrade().setContractAsJson(contractAsJson);
|
|
||||||
sharedModel.getTrade().setContractTakerSignature(signature);
|
|
||||||
//log.trace("signature: " + signature);
|
|
||||||
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO use diff output as feedback ?
|
|
||||||
log.error("Contracts are not matching.");
|
|
||||||
log.error("Offerers contractAsJson: " + contractAsJson);
|
|
||||||
log.error("Takers contractAsJson: " + sharedModel.getPeersContractAsJson());
|
|
||||||
|
|
||||||
failed(new Exception("Contracts are not matching"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class VerifyTakeOfferFeePayment extends AbstractOffererAsBuyerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(VerifyTakeOfferFeePayment.class);
|
|
||||||
|
|
||||||
public VerifyTakeOfferFeePayment(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
//TODO mocked yet, need a confidence listeners
|
|
||||||
int numOfPeersSeenTx = sharedModel.getWalletFacade().getNumOfPeersSeenTx(sharedModel.getTakeOfferFeeTxId());
|
|
||||||
if (numOfPeersSeenTx > 2)
|
|
||||||
{
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class VerifyTakerAccount extends AbstractOffererAsBuyerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(VerifyTakerAccount.class);
|
|
||||||
|
|
||||||
public VerifyTakerAccount(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
//TODO mocked yet
|
|
||||||
if (sharedModel.getBlockChainFacade().verifyAccountRegistration())
|
|
||||||
{
|
|
||||||
if (sharedModel.getBlockChainFacade().isAccountBlackListed(sharedModel.getPeersAccountId(), sharedModel.getPeersBankAccount()))
|
|
||||||
{
|
|
||||||
log.error("Taker is blacklisted");
|
|
||||||
failed(new Exception("Taker is blacklisted"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log.error("Account registration validation for peer failed.");
|
|
||||||
failed(new Exception("Account registration validation for peer failed."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker;
|
|
||||||
|
|
||||||
import io.bitsquare.trade.Trade;
|
|
||||||
|
|
||||||
public interface TakerAsSellerProtocolListener
|
|
||||||
{
|
|
||||||
void onDepositTxPublished(String depositTxId);
|
|
||||||
|
|
||||||
void onBankTransferInited(String tradeId);
|
|
||||||
|
|
||||||
void onTradeCompleted(Trade trade, String hashAsString);
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.trade.payment.taker.TakerAsSellerProtocol;
|
|
||||||
import io.nucleo.scheduler.tasks.AbstractTask;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public abstract class AbstractTakerAsSellerTask extends AbstractTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AbstractTakerAsSellerTask.class);
|
|
||||||
|
|
||||||
protected TakerAsSellerProtocol sharedModel;
|
|
||||||
|
|
||||||
public AbstractTakerAsSellerTask(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
addResultHandlers(resultHandler);
|
|
||||||
addFaultHandlers(faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setModel(Object model)
|
|
||||||
{
|
|
||||||
sharedModel = (TakerAsSellerProtocol) model;
|
|
||||||
super.setModel(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.trade.Contract;
|
|
||||||
import io.bitsquare.trade.Trade;
|
|
||||||
import io.bitsquare.util.Utilities;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class CreateAndSignContract extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(CreateAndSignContract.class);
|
|
||||||
|
|
||||||
public CreateAndSignContract(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
Trade trade = sharedModel.getTrade();
|
|
||||||
Contract contract = new Contract(trade.getOffer(),
|
|
||||||
trade.getTradeAmount(),
|
|
||||||
trade.getTakeOfferFeeTxId(),
|
|
||||||
sharedModel.getPeersAccountId(),
|
|
||||||
sharedModel.getUser().getAccountID(),
|
|
||||||
sharedModel.getPeersBankAccount(),
|
|
||||||
sharedModel.getUser().getCurrentBankAccount(),
|
|
||||||
trade.getOffer().getMessagePubKeyAsHex(),
|
|
||||||
sharedModel.getUser().getMessagePubKeyAsHex()
|
|
||||||
);
|
|
||||||
|
|
||||||
String contractAsJson = Utilities.objectToJson(contract);
|
|
||||||
String signature = sharedModel.getCryptoFacade().signContract(sharedModel.getWalletFacade().getRegistrationAddressInfo().getKey(), contractAsJson);
|
|
||||||
//log.trace("contract: " + contract);
|
|
||||||
//log.debug("contractAsJson: " + contractAsJson);
|
|
||||||
//log.trace("contract signature: " + signature);
|
|
||||||
|
|
||||||
trade.setContract(contract);
|
|
||||||
trade.setContractAsJson(contractAsJson);
|
|
||||||
trade.setContractTakerSignature(signature);
|
|
||||||
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.trade.payment.taker.listeners.GetPeerAddressListener;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import net.tomp2p.peers.PeerAddress;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class GetPeerAddress extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class);
|
|
||||||
|
|
||||||
public GetPeerAddress(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
sharedModel.getMessageFacade().getPeerAddress(sharedModel.getTrade().getOffer().getMessagePubKeyAsHex(), new GetPeerAddressListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult(PeerAddress address)
|
|
||||||
{
|
|
||||||
log.trace("Received address = " + address.toString());
|
|
||||||
sharedModel.setPeerAddress(address);
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed()
|
|
||||||
{
|
|
||||||
log.error("Lookup for peer address failed.");
|
|
||||||
failed(new Exception("Lookup for peer address failed."));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import com.google.bitcoin.core.InsufficientMoneyException;
|
|
||||||
import io.bitsquare.trade.Trade;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class PayDeposit extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PayDeposit.class);
|
|
||||||
|
|
||||||
public PayDeposit(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Trade trade = sharedModel.getTrade();
|
|
||||||
BigInteger collateralAmount = trade.getCollateralAmount();
|
|
||||||
sharedModel.setSignedTakerDepositTx(sharedModel.getWalletFacade().takerAddPaymentAndSignTx(trade.getTradeAmount().add(collateralAmount),
|
|
||||||
trade.getTradeAmount().add(collateralAmount).add(collateralAmount),
|
|
||||||
sharedModel.getOffererPubKey(),
|
|
||||||
sharedModel.getWalletFacade().getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString(),
|
|
||||||
trade.getOffer().getArbitrator().getPubKeyAsHex(),
|
|
||||||
sharedModel.getPreparedOffererDepositTxAsHex(),
|
|
||||||
trade.getId()));
|
|
||||||
|
|
||||||
log.trace("sharedModel.signedTakerDepositTx: " + sharedModel.getSignedTakerDepositTx());
|
|
||||||
sharedModel.setTakerTxOutIndex(sharedModel.getSignedTakerDepositTx().getInput(1).getOutpoint().getIndex());
|
|
||||||
|
|
||||||
complete();
|
|
||||||
} catch (InsufficientMoneyException e)
|
|
||||||
{
|
|
||||||
log.error("Pay deposit failed due InsufficientMoneyException " + e);
|
|
||||||
failed(new Exception("Pay deposit failed due InsufficientMoneyException " + e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import com.google.bitcoin.core.InsufficientMoneyException;
|
|
||||||
import com.google.bitcoin.core.Transaction;
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class PayTakeOfferFee extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PayTakeOfferFee.class);
|
|
||||||
|
|
||||||
public PayTakeOfferFee(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
sharedModel.getWalletFacade().payTakeOfferFee(sharedModel.getTrade().getId(), new FutureCallback<Transaction>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Transaction transaction)
|
|
||||||
{
|
|
||||||
log.debug("Take offer fee paid successfully. Transaction ID = " + transaction.getHashAsString());
|
|
||||||
sharedModel.getTrade().setTakeOfferFeeTxID(transaction.getHashAsString());
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable t)
|
|
||||||
{
|
|
||||||
log.error("Take offer fee paid failed with exception: " + t);
|
|
||||||
failed(new Exception("Take offer fee paid failed with exception: " + t));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (InsufficientMoneyException e)
|
|
||||||
{
|
|
||||||
log.error("Take offer fee paid failed due InsufficientMoneyException " + e);
|
|
||||||
failed(new Exception("Take offer fee paid failed due InsufficientMoneyException " + e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.msg.listeners.TradeMessageListener;
|
|
||||||
import io.bitsquare.trade.payment.taker.messages.RequestTakeOfferMessage;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class RequestTakeOffer extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(RequestTakeOffer.class);
|
|
||||||
|
|
||||||
public RequestTakeOffer(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
RequestTakeOfferMessage msg = new RequestTakeOfferMessage(sharedModel.getTrade().getId());
|
|
||||||
sharedModel.getMessageFacade().sendTradingMessage(sharedModel.getPeerAddress(), msg, new TradeMessageListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult()
|
|
||||||
{
|
|
||||||
log.trace("RequestTakeOfferMessage successfully arrived at peer");
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed()
|
|
||||||
{
|
|
||||||
log.error("RequestTakeOfferMessage failed to arrive at peer");
|
|
||||||
failed(new Exception("RequestTakeOfferMessage failed to arrive at peer"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.msg.listeners.TradeMessageListener;
|
|
||||||
import io.bitsquare.trade.payment.taker.messages.PayoutTxPublishedMessage;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class SendPayoutTxToOfferer extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxToOfferer.class);
|
|
||||||
|
|
||||||
public SendPayoutTxToOfferer(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(sharedModel.getTrade().getId(), sharedModel.getPayoutTxAsHex());
|
|
||||||
sharedModel.getMessageFacade().sendTradeMessage(sharedModel.getPeerAddress(), tradeMessage, new TradeMessageListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult()
|
|
||||||
{
|
|
||||||
log.trace("PayoutTxPublishedMessage successfully arrived at peer");
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed()
|
|
||||||
{
|
|
||||||
log.error("PayoutTxPublishedMessage failed to arrive at peer");
|
|
||||||
failed(new Exception("PayoutTxPublishedMessage failed to arrive at peer"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import com.google.bitcoin.core.Utils;
|
|
||||||
import io.bitsquare.msg.listeners.TradeMessageListener;
|
|
||||||
import io.bitsquare.trade.payment.taker.messages.RequestOffererPublishDepositTxMessage;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class SendSignedTakerDepositTxAsHex extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class);
|
|
||||||
|
|
||||||
public SendSignedTakerDepositTxAsHex(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
|
|
||||||
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(sharedModel.getTrade().getId(),
|
|
||||||
sharedModel.getUser().getCurrentBankAccount(),
|
|
||||||
sharedModel.getUser().getAccountID(),
|
|
||||||
sharedModel.getUser().getMessagePubKeyAsHex(),
|
|
||||||
Utils.bytesToHexString(sharedModel.getSignedTakerDepositTx().bitcoinSerialize()),
|
|
||||||
Utils.bytesToHexString(sharedModel.getSignedTakerDepositTx().getInput(1).getScriptBytes()),
|
|
||||||
Utils.bytesToHexString(sharedModel.getSignedTakerDepositTx().getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize()),
|
|
||||||
sharedModel.getTrade().getContractAsJson(),
|
|
||||||
sharedModel.getTrade().getTakerSignature(),
|
|
||||||
sharedModel.getWalletFacade().getAddressInfoByTradeID(sharedModel.getTrade().getId()).getAddressString(),
|
|
||||||
sharedModel.getTakerTxOutIndex(),
|
|
||||||
sharedModel.getOffererTxOutIndex()
|
|
||||||
);
|
|
||||||
sharedModel.getMessageFacade().sendTradeMessage(sharedModel.getPeerAddress(), tradeMessage, new TradeMessageListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult()
|
|
||||||
{
|
|
||||||
log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer");
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed()
|
|
||||||
{
|
|
||||||
log.error("RequestOffererDepositPublicationMessage failed to arrive at peer");
|
|
||||||
failed(new Exception("RequestOffererDepositPublicationMessage failed to arrive at peer"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import io.bitsquare.msg.listeners.TradeMessageListener;
|
|
||||||
import io.bitsquare.trade.payment.taker.messages.TakeOfferFeePayedMessage;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class SendTakeOfferFeePayedTxId extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SendTakeOfferFeePayedTxId.class);
|
|
||||||
|
|
||||||
public SendTakeOfferFeePayedTxId(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
|
|
||||||
TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(sharedModel.getTrade().getId(),
|
|
||||||
sharedModel.getTrade().getTakeOfferFeeTxId(),
|
|
||||||
sharedModel.getTrade().getTradeAmount(),
|
|
||||||
sharedModel.getWalletFacade().getAddressInfoByTradeID(sharedModel.getTrade().getId()).getPubKeyAsHexString());
|
|
||||||
|
|
||||||
sharedModel.getMessageFacade().sendTradeMessage(sharedModel.getPeerAddress(), msg, new TradeMessageListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onResult()
|
|
||||||
{
|
|
||||||
log.trace("TakeOfferFeePayedMessage successfully arrived at peer");
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailed()
|
|
||||||
{
|
|
||||||
log.error("TakeOfferFeePayedMessage failed to arrive at peer");
|
|
||||||
failed(new Exception("TakeOfferFeePayedMessage failed to arrive at peer"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import com.google.bitcoin.core.Transaction;
|
|
||||||
import com.google.bitcoin.core.Utils;
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class SignAndPublishPayoutTx extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SignAndPublishPayoutTx.class);
|
|
||||||
|
|
||||||
public SignAndPublishPayoutTx(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String depositTxAsHex = sharedModel.getDepositTxAsHex();
|
|
||||||
String offererSignatureR = sharedModel.getOffererSignatureR();
|
|
||||||
String offererSignatureS = sharedModel.getOffererSignatureS();
|
|
||||||
BigInteger offererPaybackAmount = sharedModel.getOffererPaybackAmount();
|
|
||||||
BigInteger takerPaybackAmount = sharedModel.getTakerPaybackAmount();
|
|
||||||
String offererPayoutAddress = sharedModel.getOffererPayoutAddress();
|
|
||||||
|
|
||||||
sharedModel.getWalletFacade().takerSignsAndSendsTx(depositTxAsHex,
|
|
||||||
offererSignatureR,
|
|
||||||
offererSignatureS,
|
|
||||||
offererPaybackAmount,
|
|
||||||
takerPaybackAmount,
|
|
||||||
offererPayoutAddress,
|
|
||||||
sharedModel.getTrade().getId(),
|
|
||||||
new FutureCallback<Transaction>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Transaction transaction)
|
|
||||||
{
|
|
||||||
log.debug("takerSignsAndSendsTx " + transaction);
|
|
||||||
sharedModel.getListener().onTradeCompleted(sharedModel.getTrade(), transaction.getHashAsString());
|
|
||||||
sharedModel.setPayoutTxAsHex(Utils.bytesToHexString(transaction.bitcoinSerialize()));
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable t)
|
|
||||||
{
|
|
||||||
log.error("Exception at takerSignsAndSendsTx " + t);
|
|
||||||
failed(t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("Exception at takerSignsAndSendsTx " + e);
|
|
||||||
failed(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package io.bitsquare.trade.payment.taker.tasks;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class VerifyOffererAccount extends AbstractTakerAsSellerTask
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(VerifyOffererAccount.class);
|
|
||||||
|
|
||||||
public VerifyOffererAccount(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
|
|
||||||
//TODO mocked yet
|
|
||||||
if (sharedModel.getBlockChainFacade().verifyAccountRegistration())
|
|
||||||
{
|
|
||||||
if (sharedModel.getBlockChainFacade().isAccountBlackListed(sharedModel.getPeersAccountId(), sharedModel.getPeersBankAccount()))
|
|
||||||
{
|
|
||||||
log.error("Offerer is blacklisted");
|
|
||||||
failed(new Exception("Offerer is blacklisted"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log.error("Account Registration for peer failed.");
|
|
||||||
failed(new Exception("Account Registration for peer failed."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.offerer.messages;
|
package io.bitsquare.trade.protocol.messages.offerer;
|
||||||
|
|
||||||
import io.bitsquare.msg.TradeMessage;
|
import io.bitsquare.msg.TradeMessage;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.offerer.messages;
|
package io.bitsquare.trade.protocol.messages.offerer;
|
||||||
|
|
||||||
import io.bitsquare.msg.TradeMessage;
|
import io.bitsquare.msg.TradeMessage;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.offerer.messages;
|
package io.bitsquare.trade.protocol.messages.offerer;
|
||||||
|
|
||||||
import io.bitsquare.msg.TradeMessage;
|
import io.bitsquare.msg.TradeMessage;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.offerer.messages;
|
package io.bitsquare.trade.protocol.messages.offerer;
|
||||||
|
|
||||||
import io.bitsquare.msg.TradeMessage;
|
import io.bitsquare.msg.TradeMessage;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.offerer.messages;
|
package io.bitsquare.trade.protocol.messages.offerer;
|
||||||
|
|
||||||
import io.bitsquare.bank.BankAccount;
|
import io.bitsquare.bank.BankAccount;
|
||||||
import io.bitsquare.msg.TradeMessage;
|
import io.bitsquare.msg.TradeMessage;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.taker.messages;
|
package io.bitsquare.trade.protocol.messages.taker;
|
||||||
|
|
||||||
import io.bitsquare.msg.TradeMessage;
|
import io.bitsquare.msg.TradeMessage;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.taker.messages;
|
package io.bitsquare.trade.protocol.messages.taker;
|
||||||
|
|
||||||
import io.bitsquare.bank.BankAccount;
|
import io.bitsquare.bank.BankAccount;
|
||||||
import io.bitsquare.msg.TradeMessage;
|
import io.bitsquare.msg.TradeMessage;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.taker.messages;
|
package io.bitsquare.trade.protocol.messages.taker;
|
||||||
|
|
||||||
import io.bitsquare.msg.TradeMessage;
|
import io.bitsquare.msg.TradeMessage;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.taker.messages;
|
package io.bitsquare.trade.protocol.messages.taker;
|
||||||
|
|
||||||
import io.bitsquare.msg.TradeMessage;
|
import io.bitsquare.msg.TradeMessage;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -32,7 +32,7 @@ public class TakeOfferFeePayedMessage implements Serializable, TradeMessage
|
||||||
return tradeAmount;
|
return tradeAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTakeOfferFeeTxID()
|
public String getTakeOfferFeeTxId()
|
||||||
{
|
{
|
||||||
return takeOfferFeeTxID;
|
return takeOfferFeeTxID;
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.process;
|
package io.bitsquare.trade.protocol.mock;
|
||||||
|
|
||||||
//TODO not used but let it for reference until all use cases are impl.
|
//TODO not used but let it for reference until all use cases are impl.
|
||||||
class BuyOffererPaymentProcess extends PaymentProcess
|
class BuyOffererPaymentProcess extends PaymentProcess
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.process;
|
package io.bitsquare.trade.protocol.mock;
|
||||||
|
|
||||||
//TODO not used but let it for reference until all use cases are impl.
|
//TODO not used but let it for reference until all use cases are impl.
|
||||||
public class BuyTakerPaymentProcess extends PaymentProcess
|
public class BuyTakerPaymentProcess extends PaymentProcess
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.process;
|
package io.bitsquare.trade.protocol.mock;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import io.bitsquare.btc.BlockChainFacade;
|
import io.bitsquare.btc.BlockChainFacade;
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.process;
|
package io.bitsquare.trade.protocol.mock;
|
||||||
|
|
||||||
//TODO not used but let it for reference until all use cases are impl.
|
//TODO not used but let it for reference until all use cases are impl.
|
||||||
class SellOffererPaymentProcess extends PaymentProcess
|
class SellOffererPaymentProcess extends PaymentProcess
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.process;
|
package io.bitsquare.trade.protocol.mock;
|
||||||
|
|
||||||
//TODO not used but let it for reference until all use cases are impl.
|
//TODO not used but let it for reference until all use cases are impl.
|
||||||
class SellTakerPaymentProcess extends PaymentProcess
|
class SellTakerPaymentProcess extends PaymentProcess
|
|
@ -1,26 +1,27 @@
|
||||||
package io.bitsquare.trade.payment.offerer;
|
package io.bitsquare.trade.protocol.offerer;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.ECKey;
|
||||||
|
import com.google.bitcoin.core.Transaction;
|
||||||
import io.bitsquare.bank.BankAccount;
|
import io.bitsquare.bank.BankAccount;
|
||||||
import io.bitsquare.btc.BlockChainFacade;
|
import io.bitsquare.btc.BlockChainFacade;
|
||||||
import io.bitsquare.btc.WalletFacade;
|
import io.bitsquare.btc.WalletFacade;
|
||||||
import io.bitsquare.crypto.CryptoFacade;
|
import io.bitsquare.crypto.CryptoFacade;
|
||||||
import io.bitsquare.msg.MessageFacade;
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.trade.Contract;
|
||||||
|
import io.bitsquare.trade.Offer;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.payment.offerer.tasks.*;
|
import io.bitsquare.trade.protocol.messages.taker.PayoutTxPublishedMessage;
|
||||||
import io.bitsquare.trade.payment.taker.messages.PayoutTxPublishedMessage;
|
import io.bitsquare.trade.protocol.messages.taker.RequestOffererPublishDepositTxMessage;
|
||||||
import io.bitsquare.trade.payment.taker.messages.RequestOffererPublishDepositTxMessage;
|
import io.bitsquare.trade.protocol.messages.taker.TakeOfferFeePayedMessage;
|
||||||
import io.bitsquare.trade.payment.taker.messages.TakeOfferFeePayedMessage;
|
import io.bitsquare.trade.protocol.tasks.offerer.*;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
import io.nucleo.scheduler.SequenceScheduler;
|
import java.math.BigInteger;
|
||||||
import io.nucleo.scheduler.worker.Worker;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import net.tomp2p.peers.PeerAddress;
|
import net.tomp2p.peers.PeerAddress;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.*;
|
||||||
|
|
||||||
//TODO refactor to process based pattern
|
//TODO refactor to process based pattern
|
||||||
public class OffererAsBuyerProtocol
|
public class OffererAsBuyerProtocol
|
||||||
{
|
{
|
||||||
|
@ -31,19 +32,22 @@ public class OffererAsBuyerProtocol
|
||||||
private final String id;
|
private final String id;
|
||||||
private final Trade trade;
|
private final Trade trade;
|
||||||
private final OffererAsBuyerProtocolListener listener;
|
private final OffererAsBuyerProtocolListener listener;
|
||||||
private final WorkerResultHandler resultHandler;
|
|
||||||
private final WorkerFaultHandler faultHandler;
|
|
||||||
private final MessageFacade messageFacade;
|
private final MessageFacade messageFacade;
|
||||||
private final WalletFacade walletFacade;
|
private final WalletFacade walletFacade;
|
||||||
private final BlockChainFacade blockChainFacade;
|
private final BlockChainFacade blockChainFacade;
|
||||||
private final CryptoFacade cryptoFacade;
|
private final CryptoFacade cryptoFacade;
|
||||||
private final User user;
|
private final User user;
|
||||||
|
private final String tradeId;
|
||||||
|
private final Offer offer;
|
||||||
|
|
||||||
|
|
||||||
// private
|
// private
|
||||||
private final SequenceScheduler scheduler_1;
|
private State state;
|
||||||
|
|
||||||
// data written/read by tasks
|
// data written/read by tasks
|
||||||
private String preparedOffererDepositTxAsHex;
|
private String preparedOffererDepositTxAsHex;
|
||||||
private long offererTxOutIndex;
|
private long offererTxOutIndex;
|
||||||
private String offererPubKey;
|
|
||||||
// data written by messages, read by tasks
|
// data written by messages, read by tasks
|
||||||
private String takeOfferFeeTxId;
|
private String takeOfferFeeTxId;
|
||||||
private String takerMultiSigPubKey;
|
private String takerMultiSigPubKey;
|
||||||
|
@ -56,14 +60,6 @@ public class OffererAsBuyerProtocol
|
||||||
private String txConnOutAsHex;
|
private String txConnOutAsHex;
|
||||||
private String txScriptSigAsHex;
|
private String txScriptSigAsHex;
|
||||||
private long takerTxOutIndex;
|
private long takerTxOutIndex;
|
||||||
private SequenceScheduler scheduler_2;
|
|
||||||
private SequenceScheduler scheduler_3;
|
|
||||||
private SequenceScheduler scheduler_4;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructor
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public OffererAsBuyerProtocol(Trade trade,
|
public OffererAsBuyerProtocol(Trade trade,
|
||||||
PeerAddress peerAddress,
|
PeerAddress peerAddress,
|
||||||
|
@ -72,15 +68,11 @@ public class OffererAsBuyerProtocol
|
||||||
BlockChainFacade blockChainFacade,
|
BlockChainFacade blockChainFacade,
|
||||||
CryptoFacade cryptoFacade,
|
CryptoFacade cryptoFacade,
|
||||||
User user,
|
User user,
|
||||||
WorkerResultHandler resultHandler,
|
|
||||||
WorkerFaultHandler faultHandler,
|
|
||||||
OffererAsBuyerProtocolListener listener)
|
OffererAsBuyerProtocolListener listener)
|
||||||
{
|
{
|
||||||
this.trade = trade;
|
this.trade = trade;
|
||||||
this.peerAddress = peerAddress;
|
this.peerAddress = peerAddress;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.resultHandler = resultHandler;
|
|
||||||
this.faultHandler = faultHandler;
|
|
||||||
this.messageFacade = messageFacade;
|
this.messageFacade = messageFacade;
|
||||||
this.walletFacade = walletFacade;
|
this.walletFacade = walletFacade;
|
||||||
this.blockChainFacade = blockChainFacade;
|
this.blockChainFacade = blockChainFacade;
|
||||||
|
@ -89,43 +81,166 @@ public class OffererAsBuyerProtocol
|
||||||
|
|
||||||
id = trade.getId();
|
id = trade.getId();
|
||||||
|
|
||||||
messageFacade.addOffererPaymentProtocol(this);
|
tradeId = trade.getId();
|
||||||
|
offer = trade.getOffer();
|
||||||
|
|
||||||
log.debug("OffererAsBuyerProtocol created");
|
state = State.Start;
|
||||||
|
}
|
||||||
|
|
||||||
List<Worker> tasks = new ArrayList<>();
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
tasks.add(new HandleTakeOfferRequest(resultHandler, faultHandler));
|
// Constructor
|
||||||
scheduler_1 = new SequenceScheduler(tasks, this);
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
scheduler_1.execute();
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Instantiation is triggered by an incoming message from peer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
HandleTakeOfferRequest.run(this::onResultHandleTakeOfferRequest, this::onFaultHandleTakeOfferRequest, peerAddress, messageFacade, trade.getState(), tradeId);
|
||||||
|
state = State.HandleTakeOfferRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tasks
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onResultHandleTakeOfferRequest(Trade.State tradeState)
|
||||||
|
{
|
||||||
|
checkState(tradeState == Trade.State.ACCEPTED);
|
||||||
|
|
||||||
|
listener.onOfferAccepted(offer);
|
||||||
|
trade.setState(tradeState);
|
||||||
|
|
||||||
|
messageFacade.removeOffer(offer);
|
||||||
|
|
||||||
|
// waiting for incoming msg from peer (-> onTakeOfferFeePayedMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultHandleTakeOfferRequest(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTakeOfferFeePayedMessage(TakeOfferFeePayedMessage message)
|
public void onTakeOfferFeePayedMessage(TakeOfferFeePayedMessage message)
|
||||||
{
|
{
|
||||||
log.debug("onTakeOfferFeePayedMessage");
|
log.debug("onTakeOfferFeePayedMessage");
|
||||||
getTrade().setTakeOfferFeeTxID(message.getTakeOfferFeeTxID());
|
|
||||||
getTrade().setTradeAmount(message.getTradeAmount());
|
|
||||||
|
|
||||||
takeOfferFeeTxId = message.getTakeOfferFeeTxID();
|
checkState(state == State.HandleTakeOfferRequest);
|
||||||
takerMultiSigPubKey = message.getTakerMultiSigPubKey();
|
|
||||||
|
|
||||||
if (scheduler_1.getHasCompleted())
|
String takeOfferFeeTxId = message.getTakeOfferFeeTxId();
|
||||||
{
|
BigInteger tradeAmount = message.getTradeAmount();
|
||||||
List<Worker> tasks = new ArrayList<>();
|
String takerMultiSigPubKey = message.getTakerMultiSigPubKey();
|
||||||
tasks.add(new VerifyTakeOfferFeePayment(getResultHandler(), getFaultHandler()));
|
|
||||||
tasks.add(new CreateDepositTx(getResultHandler(), getFaultHandler()));
|
// validate input
|
||||||
tasks.add(new RequestTakerDepositPayment(getResultHandler(), getFaultHandler()));
|
checkNotNull(takeOfferFeeTxId);
|
||||||
scheduler_2 = new SequenceScheduler(tasks, this);
|
checkArgument(takeOfferFeeTxId.length() > 0);
|
||||||
scheduler_2.execute();
|
|
||||||
|
checkNotNull(tradeAmount);
|
||||||
|
// TODO make validator for amounts with testing against trades amount range
|
||||||
|
//checkArgument(bigIntegerValidator.isValue(tradeAmount).inRangeOf(trade.getMinAmount(), trade.getAmount()));
|
||||||
|
|
||||||
|
checkNotNull(takerMultiSigPubKey);
|
||||||
|
checkArgument(takerMultiSigPubKey.length() > 0);
|
||||||
|
|
||||||
|
state = State.onTakeOfferFeePayedMessage;
|
||||||
|
|
||||||
|
this.takeOfferFeeTxId = takeOfferFeeTxId;
|
||||||
|
this.takerMultiSigPubKey = takerMultiSigPubKey;
|
||||||
|
trade.setTakeOfferFeeTxID(takeOfferFeeTxId);
|
||||||
|
trade.setTradeAmount(tradeAmount);
|
||||||
|
|
||||||
|
sequence2();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Incoming message from peer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void sequence2()
|
||||||
{
|
{
|
||||||
log.error("scheduler_1 has not completed yet.");
|
VerifyTakeOfferFeePayment.run(this::onResultVerifyTakeOfferFeePayment, this::onFaultVerifyTakeOfferFeePayment, walletFacade, takeOfferFeeTxId);
|
||||||
|
state = State.VerifyTakeOfferFeePayment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tasks
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onResultVerifyTakeOfferFeePayment()
|
||||||
|
{
|
||||||
|
BigInteger collateralAmount = trade.getCollateralAmount();
|
||||||
|
String arbitratorPubKeyAsHex = offer.getArbitrator().getPubKeyAsHex();
|
||||||
|
|
||||||
|
CreateDepositTx.run(this::onResultCreateDepositTx,
|
||||||
|
this::onFaultCreateDepositTx,
|
||||||
|
walletFacade,
|
||||||
|
tradeId,
|
||||||
|
collateralAmount,
|
||||||
|
takerMultiSigPubKey,
|
||||||
|
arbitratorPubKeyAsHex);
|
||||||
|
|
||||||
|
state = State.CreateDepositTx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultVerifyTakeOfferFeePayment(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResultCreateDepositTx(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex)
|
||||||
|
{
|
||||||
|
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
|
||||||
|
this.offererTxOutIndex = offererTxOutIndex;
|
||||||
|
|
||||||
|
BankAccount bankAccount = user.getBankAccount(trade.getOffer().getBankAccountId());
|
||||||
|
String accountId = user.getAccountId();
|
||||||
|
|
||||||
|
RequestTakerDepositPayment.run(this::onResultRequestTakerDepositPayment,
|
||||||
|
this::onFaultRequestTakerDepositPayment,
|
||||||
|
peerAddress,
|
||||||
|
messageFacade,
|
||||||
|
tradeId,
|
||||||
|
bankAccount,
|
||||||
|
accountId,
|
||||||
|
offererPubKey,
|
||||||
|
preparedOffererDepositTxAsHex,
|
||||||
|
offererTxOutIndex);
|
||||||
|
|
||||||
|
state = State.RequestTakerDepositPayment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultCreateDepositTx(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResultRequestTakerDepositPayment()
|
||||||
|
{
|
||||||
|
// waiting for incoming msg from peer (-> onRequestOffererPublishDepositTxMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultRequestTakerDepositPayment(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message)
|
public void onRequestOffererPublishDepositTxMessage(RequestOffererPublishDepositTxMessage message)
|
||||||
{
|
{
|
||||||
log.debug("onRequestOffererPublishDepositTxMessage");
|
log.debug("onRequestOffererPublishDepositTxMessage");
|
||||||
|
|
||||||
|
checkState(state == State.RequestTakerDepositPayment);
|
||||||
|
|
||||||
|
checkNotNull(message);
|
||||||
|
|
||||||
|
//TODO validation
|
||||||
|
|
||||||
|
state = State.onRequestOffererPublishDepositTxMessage;
|
||||||
|
|
||||||
|
//TODO
|
||||||
takerPayoutAddress = message.getTakerPayoutAddress();
|
takerPayoutAddress = message.getTakerPayoutAddress();
|
||||||
peersAccountId = message.getAccountId();
|
peersAccountId = message.getAccountId();
|
||||||
peersBankAccount = message.getBankAccount();
|
peersBankAccount = message.getBankAccount();
|
||||||
|
@ -136,50 +251,172 @@ public class OffererAsBuyerProtocol
|
||||||
txScriptSigAsHex = message.getTxScriptSigAsHex();
|
txScriptSigAsHex = message.getTxScriptSigAsHex();
|
||||||
takerTxOutIndex = message.getTakerTxOutIndex();
|
takerTxOutIndex = message.getTakerTxOutIndex();
|
||||||
|
|
||||||
if (scheduler_2.getHasCompleted())
|
sequence3();
|
||||||
{
|
|
||||||
List<Worker> tasks = new ArrayList<>();
|
|
||||||
tasks.add(new VerifyTakerAccount(getResultHandler(), getFaultHandler()));
|
|
||||||
tasks.add(new VerifyAndSignContract(getResultHandler(), getFaultHandler()));
|
|
||||||
tasks.add(new SignAndPublishDepositTx(getResultHandler(), getFaultHandler()));
|
|
||||||
tasks.add(new SendDepositTxIdToTaker(getResultHandler(), getFaultHandler()));
|
|
||||||
tasks.add(new SetupListenerForBlockChainConfirmation(getResultHandler(), getFaultHandler()));
|
|
||||||
scheduler_3 = new SequenceScheduler(tasks, this);
|
|
||||||
scheduler_3.execute();
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Incoming message from peer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void sequence3()
|
||||||
{
|
{
|
||||||
log.error("scheduler_2 has not completed yet.");
|
VerifyTakerAccount.run(this::onResultVerifyTakerAccount, this::onFaultVerifyTakerAccount, blockChainFacade, peersAccountId, peersBankAccount);
|
||||||
|
state = State.VerifyTakerAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tasks
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onResultVerifyTakerAccount()
|
||||||
|
{
|
||||||
|
String accountId = user.getAccountId();
|
||||||
|
BigInteger tradeAmount = trade.getTradeAmount();
|
||||||
|
String messagePubKeyAsHex = user.getMessagePubKeyAsHex();
|
||||||
|
BankAccount bankAccount = user.getBankAccount(offer.getBankAccountId());
|
||||||
|
ECKey registrationKey = walletFacade.getRegistrationAddressInfo().getKey();
|
||||||
|
|
||||||
|
VerifyAndSignContract.run(this::onResultVerifyAndSignContract,
|
||||||
|
this::onFaultVerifyAndSignContract,
|
||||||
|
cryptoFacade,
|
||||||
|
accountId,
|
||||||
|
tradeAmount,
|
||||||
|
takeOfferFeeTxId,
|
||||||
|
messagePubKeyAsHex,
|
||||||
|
offer,
|
||||||
|
peersAccountId,
|
||||||
|
bankAccount,
|
||||||
|
peersBankAccount,
|
||||||
|
takerMessagePubKey,
|
||||||
|
peersContractAsJson,
|
||||||
|
registrationKey);
|
||||||
|
|
||||||
|
state = State.VerifyAndSignContract;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultVerifyTakerAccount(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResultVerifyAndSignContract(Contract contract, String contractAsJson, String signature)
|
||||||
|
{
|
||||||
|
trade.setContract(contract);
|
||||||
|
trade.setContractAsJson(contractAsJson);
|
||||||
|
trade.setContractTakerSignature(signature);
|
||||||
|
|
||||||
|
SignAndPublishDepositTx.run(this::onResultSignAndPublishDepositTx,
|
||||||
|
this::onFaultSignAndPublishDepositTx,
|
||||||
|
walletFacade,
|
||||||
|
preparedOffererDepositTxAsHex,
|
||||||
|
signedTakerDepositTxAsHex,
|
||||||
|
txConnOutAsHex,
|
||||||
|
txScriptSigAsHex,
|
||||||
|
offererTxOutIndex,
|
||||||
|
takerTxOutIndex);
|
||||||
|
state = State.SignAndPublishDepositTx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultVerifyAndSignContract(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResultSignAndPublishDepositTx(Transaction transaction)
|
||||||
|
{
|
||||||
|
trade.setDepositTransaction(transaction);
|
||||||
|
listener.onDepositTxPublished(transaction.getHashAsString());
|
||||||
|
|
||||||
|
SendDepositTxIdToTaker.run(this::onResultSendDepositTxIdToTaker, this::onFaultSendDepositTxIdToTaker, peerAddress, messageFacade, trade);
|
||||||
|
state = State.SendDepositTxIdToTaker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultSignAndPublishDepositTx(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResultSendDepositTxIdToTaker()
|
||||||
|
{
|
||||||
|
SetupListenerForBlockChainConfirmation.run(this::onResultSetupListenerForBlockChainConfirmation, this::onFaultSetupListenerForBlockChainConfirmation, trade.getDepositTransaction(), listener);
|
||||||
|
state = State.SetupListenerForBlockChainConfirmation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultSendDepositTxIdToTaker(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResultSetupListenerForBlockChainConfirmation()
|
||||||
|
{
|
||||||
|
// waiting for UI event (-> bankTransferInited)
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultSetupListenerForBlockChainConfirmation(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
// Triggered from UI event: Button click "Bank transfer inited"
|
// Triggered from UI event: Button click "Bank transfer inited"
|
||||||
public void onUIEventBankTransferInited()
|
public void onUIEventBankTransferInited()
|
||||||
{
|
{
|
||||||
log.debug("onUIEventBankTransferInited");
|
log.debug("bankTransferInited");
|
||||||
|
|
||||||
if (scheduler_3.getHasCompleted())
|
|
||||||
|
if (state == State.SetupListenerForBlockChainConfirmation)
|
||||||
{
|
{
|
||||||
List<Worker> tasks = new ArrayList<>();
|
state = State.onUIEventBankTransferInited;
|
||||||
tasks.add(new SendSignedPayoutTx(getResultHandler(), getFaultHandler()));
|
sequence4();
|
||||||
scheduler_4 = new SequenceScheduler(tasks, this);
|
|
||||||
scheduler_4.execute();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.error("scheduler_3 has not completed yet.");
|
log.error("Invalid state. Actual state is: " + state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UI event
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void sequence4()
|
||||||
|
{
|
||||||
|
SendSignedPayoutTx.run(this::onResultSendSignedPayoutTx, this::onFaultSendSignedPayoutTx, peerAddress, messageFacade, walletFacade, trade, takerPayoutAddress);
|
||||||
|
state = State.SendSignedPayoutTx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tasks
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onResultSendSignedPayoutTx()
|
||||||
|
{ // waiting for incoming msg from peer (-> onPayoutTxPublishedMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFaultSendSignedPayoutTx(Throwable throwable)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
public void onPayoutTxPublishedMessage(PayoutTxPublishedMessage tradeMessage)
|
public void onPayoutTxPublishedMessage(PayoutTxPublishedMessage tradeMessage)
|
||||||
{
|
{
|
||||||
log.debug("onPayoutTxPublishedMessage");
|
log.debug("onPayoutTxPublishedMessage");
|
||||||
|
if (state == State.SendSignedPayoutTx)
|
||||||
|
{
|
||||||
|
state = State.onPayoutTxPublishedMessage;
|
||||||
listener.onPayoutTxPublished(tradeMessage.getPayoutTxAsHex());
|
listener.onPayoutTxPublished(tradeMessage.getPayoutTxAsHex());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.error("Invalid state. Actual state is: " + state);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Getters, Setters
|
// Incoming message from peer
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public String getId()
|
public String getId()
|
||||||
|
@ -187,134 +424,35 @@ public class OffererAsBuyerProtocol
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTakeOfferFeeTxId()
|
|
||||||
{
|
|
||||||
return takeOfferFeeTxId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTakerMultiSigPubKey()
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
{
|
// Getters, Setters
|
||||||
return takerMultiSigPubKey;
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
}
|
|
||||||
|
|
||||||
public String getTakerPayoutAddress()
|
enum State
|
||||||
{
|
{
|
||||||
return takerPayoutAddress;
|
Start,
|
||||||
}
|
HandleTakeOfferRequest,
|
||||||
|
|
||||||
public String getPeersAccountId()
|
onTakeOfferFeePayedMessage,
|
||||||
{
|
|
||||||
return peersAccountId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BankAccount getPeersBankAccount()
|
VerifyTakeOfferFeePayment,
|
||||||
{
|
CreateDepositTx,
|
||||||
return peersBankAccount;
|
RequestTakerDepositPayment,
|
||||||
}
|
|
||||||
|
|
||||||
public String getTakerMessagePubKey()
|
onRequestOffererPublishDepositTxMessage,
|
||||||
{
|
|
||||||
return takerMessagePubKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPeersContractAsJson()
|
VerifyTakerAccount,
|
||||||
{
|
VerifyAndSignContract,
|
||||||
return peersContractAsJson;
|
SignAndPublishDepositTx,
|
||||||
}
|
SendDepositTxIdToTaker,
|
||||||
|
SetupListenerForBlockChainConfirmation,
|
||||||
|
|
||||||
public String getSignedTakerDepositTxAsHex()
|
onUIEventBankTransferInited,
|
||||||
{
|
|
||||||
return signedTakerDepositTxAsHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTxConnOutAsHex()
|
SendSignedPayoutTx,
|
||||||
{
|
|
||||||
return txConnOutAsHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTxScriptSigAsHex()
|
onPayoutTxPublishedMessage
|
||||||
{
|
|
||||||
return txScriptSigAsHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTakerTxOutIndex()
|
|
||||||
{
|
|
||||||
return takerTxOutIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPreparedOffererDepositTxAsHex()
|
|
||||||
{
|
|
||||||
return preparedOffererDepositTxAsHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPreparedOffererDepositTxAsHex(String preparedOffererDepositTxAsHex)
|
|
||||||
{
|
|
||||||
this.preparedOffererDepositTxAsHex = preparedOffererDepositTxAsHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getOffererTxOutIndex()
|
|
||||||
{
|
|
||||||
return offererTxOutIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOffererTxOutIndex(long offererTxOutIndex)
|
|
||||||
{
|
|
||||||
this.offererTxOutIndex = offererTxOutIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOffererPubKey()
|
|
||||||
{
|
|
||||||
return offererPubKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOffererPubKey(String offererPubKey)
|
|
||||||
{
|
|
||||||
this.offererPubKey = offererPubKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Trade getTrade()
|
|
||||||
{
|
|
||||||
return trade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OffererAsBuyerProtocolListener getListener()
|
|
||||||
{
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkerResultHandler getResultHandler()
|
|
||||||
{
|
|
||||||
return resultHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WorkerFaultHandler getFaultHandler()
|
|
||||||
{
|
|
||||||
return faultHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageFacade getMessageFacade()
|
|
||||||
{
|
|
||||||
return messageFacade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WalletFacade getWalletFacade()
|
|
||||||
{
|
|
||||||
return walletFacade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockChainFacade getBlockChainFacade()
|
|
||||||
{
|
|
||||||
return blockChainFacade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CryptoFacade getCryptoFacade()
|
|
||||||
{
|
|
||||||
return cryptoFacade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public User getUser()
|
|
||||||
{
|
|
||||||
return user;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -506,7 +644,7 @@ public class OffererAsBuyerProtocol
|
||||||
|
|
||||||
// offererPaymentProtocolListener.onProgress(getProgress());
|
// offererPaymentProtocolListener.onProgress(getProgress());
|
||||||
|
|
||||||
BankAccount bankAccount = user.getBankAccount(offer.getBankAccountUID());
|
BankAccount bankAccount = user.getBankAccount(offer.getBankAccountId());
|
||||||
String accountID = user.getAccountId();
|
String accountID = user.getAccountId();
|
||||||
|
|
||||||
TradeMessageOld tradeMessage = new TradeMessageOld(TradeMessageType.REQUEST_TAKER_DEPOSIT_PAYMENT, trade.getId(), bankAccount, accountID, offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
|
TradeMessageOld tradeMessage = new TradeMessageOld(TradeMessageType.REQUEST_TAKER_DEPOSIT_PAYMENT, trade.getId(), bankAccount, accountID, offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
|
||||||
|
@ -566,8 +704,8 @@ public class OffererAsBuyerProtocol
|
||||||
Contract contract = new Contract(offer,
|
Contract contract = new Contract(offer,
|
||||||
trade.getTradeAmount(),
|
trade.getTradeAmount(),
|
||||||
trade.getTakeOfferFeeTxId(),
|
trade.getTakeOfferFeeTxId(),
|
||||||
user.getAccountID(),
|
user.getAccountId(),
|
||||||
requestTradeMessage.getAccountID(),
|
requestTradeMessage.getAccountId(),
|
||||||
user.getCurrentBankAccount(),
|
user.getCurrentBankAccount(),
|
||||||
requestTradeMessage.getBankAccount(),
|
requestTradeMessage.getBankAccount(),
|
||||||
offer.getMessagePubKeyAsHex(),
|
offer.getMessagePubKeyAsHex(),
|
|
@ -1,9 +1,12 @@
|
||||||
package io.bitsquare.trade.payment.offerer;
|
package io.bitsquare.trade.protocol.offerer;
|
||||||
|
|
||||||
import com.google.bitcoin.core.TransactionConfidence;
|
import com.google.bitcoin.core.TransactionConfidence;
|
||||||
|
import io.bitsquare.trade.Offer;
|
||||||
|
|
||||||
public interface OffererAsBuyerProtocolListener
|
public interface OffererAsBuyerProtocolListener
|
||||||
{
|
{
|
||||||
|
void onOfferAccepted(Offer offer);
|
||||||
|
|
||||||
void onDepositTxPublished(String depositTxID);
|
void onDepositTxPublished(String depositTxID);
|
||||||
|
|
||||||
void onDepositTxConfirmedInBlockchain();
|
void onDepositTxConfirmedInBlockchain();
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.trade.payment.taker;
|
package io.bitsquare.trade.protocol.taker;
|
||||||
|
|
||||||
import com.google.bitcoin.core.Transaction;
|
import com.google.bitcoin.core.Transaction;
|
||||||
import io.bitsquare.bank.BankAccount;
|
import io.bitsquare.bank.BankAccount;
|
||||||
|
@ -6,42 +6,36 @@ import io.bitsquare.btc.BlockChainFacade;
|
||||||
import io.bitsquare.btc.WalletFacade;
|
import io.bitsquare.btc.WalletFacade;
|
||||||
import io.bitsquare.crypto.CryptoFacade;
|
import io.bitsquare.crypto.CryptoFacade;
|
||||||
import io.bitsquare.msg.MessageFacade;
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.trade.Offer;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.payment.offerer.messages.BankTransferInitedMessage;
|
import io.bitsquare.trade.protocol.messages.offerer.BankTransferInitedMessage;
|
||||||
import io.bitsquare.trade.payment.offerer.messages.DepositTxPublishedMessage;
|
import io.bitsquare.trade.protocol.messages.offerer.DepositTxPublishedMessage;
|
||||||
import io.bitsquare.trade.payment.offerer.messages.RequestTakerDepositPaymentMessage;
|
import io.bitsquare.trade.protocol.messages.offerer.RequestTakerDepositPaymentMessage;
|
||||||
import io.bitsquare.trade.payment.taker.tasks.*;
|
import io.bitsquare.trade.protocol.tasks.taker.*;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
import io.nucleo.scheduler.SequenceScheduler;
|
|
||||||
import io.nucleo.scheduler.worker.Worker;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import net.tomp2p.peers.PeerAddress;
|
import net.tomp2p.peers.PeerAddress;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
//TODO use states
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
@SuppressWarnings("ConstantConditions")
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
import static io.bitsquare.util.Validator.*;
|
||||||
|
|
||||||
public class TakerAsSellerProtocol
|
public class TakerAsSellerProtocol
|
||||||
{
|
{
|
||||||
private static final Logger log = LoggerFactory.getLogger(TakerAsSellerProtocol.class);
|
private static final Logger log = LoggerFactory.getLogger(TakerAsSellerProtocol.class);
|
||||||
|
|
||||||
// provided data
|
// provided data
|
||||||
private final String id;
|
|
||||||
private final Trade trade;
|
private final Trade trade;
|
||||||
private final TakerAsSellerProtocolListener listener;
|
private final TakerAsSellerProtocolListener listener;
|
||||||
private final WorkerResultHandler resultHandler;
|
|
||||||
private final WorkerFaultHandler faultHandler;
|
|
||||||
private final MessageFacade messageFacade;
|
private final MessageFacade messageFacade;
|
||||||
private final WalletFacade walletFacade;
|
private final WalletFacade walletFacade;
|
||||||
private final BlockChainFacade blockChainFacade;
|
private final BlockChainFacade blockChainFacade;
|
||||||
private final CryptoFacade cryptoFacade;
|
private final CryptoFacade cryptoFacade;
|
||||||
private final User user;
|
private final User user;
|
||||||
// private
|
private final String id;
|
||||||
private final SequenceScheduler scheduler_1;
|
private final Offer offer;
|
||||||
|
private final String tradeId;
|
||||||
// written/read by task
|
// written/read by task
|
||||||
private String payoutTxAsHex;
|
private String payoutTxAsHex;
|
||||||
private PeerAddress peerAddress;
|
private PeerAddress peerAddress;
|
||||||
|
@ -59,20 +53,11 @@ public class TakerAsSellerProtocol
|
||||||
private BigInteger offererPaybackAmount;
|
private BigInteger offererPaybackAmount;
|
||||||
private BigInteger takerPaybackAmount;
|
private BigInteger takerPaybackAmount;
|
||||||
private String offererPayoutAddress;
|
private String offererPayoutAddress;
|
||||||
private int currentStep = 0;
|
//private
|
||||||
private SequenceScheduler scheduler_2;
|
private State state;
|
||||||
private SequenceScheduler scheduler_3;
|
|
||||||
private SequenceScheduler scheduler_4;
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructor
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public TakerAsSellerProtocol(Trade trade,
|
public TakerAsSellerProtocol(Trade trade,
|
||||||
TakerAsSellerProtocolListener listener,
|
TakerAsSellerProtocolListener listener,
|
||||||
WorkerResultHandler resultHandler,
|
|
||||||
WorkerFaultHandler faultHandler,
|
|
||||||
MessageFacade messageFacade,
|
MessageFacade messageFacade,
|
||||||
WalletFacade walletFacade,
|
WalletFacade walletFacade,
|
||||||
BlockChainFacade blockChainFacade,
|
BlockChainFacade blockChainFacade,
|
||||||
|
@ -81,96 +66,211 @@ public class TakerAsSellerProtocol
|
||||||
{
|
{
|
||||||
this.trade = trade;
|
this.trade = trade;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
this.resultHandler = resultHandler;
|
|
||||||
this.faultHandler = faultHandler;
|
|
||||||
this.messageFacade = messageFacade;
|
this.messageFacade = messageFacade;
|
||||||
this.walletFacade = walletFacade;
|
this.walletFacade = walletFacade;
|
||||||
this.blockChainFacade = blockChainFacade;
|
this.blockChainFacade = blockChainFacade;
|
||||||
this.cryptoFacade = cryptoFacade;
|
this.cryptoFacade = cryptoFacade;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
|
||||||
|
offer = trade.getOffer();
|
||||||
|
tradeId = trade.getId();
|
||||||
|
|
||||||
id = trade.getId();
|
id = trade.getId();
|
||||||
|
state = State.Init;
|
||||||
|
}
|
||||||
|
|
||||||
log.debug("TakerAsSellerProtocol created");
|
|
||||||
|
|
||||||
messageFacade.addTakerPaymentProtocol(this);
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructor
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// start with first task sequence
|
// generic fault handler
|
||||||
List<Worker> tasks = new ArrayList<>();
|
public void onFault(Throwable throwable)
|
||||||
tasks.add(new GetPeerAddress(resultHandler, faultHandler));
|
{
|
||||||
tasks.add(new RequestTakeOffer(resultHandler, faultHandler));
|
listener.onFault(throwable, state);
|
||||||
scheduler_1 = new SequenceScheduler(tasks, this);
|
}
|
||||||
scheduler_1.execute();
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
String messagePubKeyAsHex = validString(offer.getMessagePubKeyAsHex());
|
||||||
|
|
||||||
|
GetPeerAddress.run(this::onResultGetPeerAddress, this::onFault, messageFacade, messagePubKeyAsHex);
|
||||||
|
state = State.GetPeerAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tasks
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onResultGetPeerAddress(PeerAddress peerAddress)
|
||||||
|
{
|
||||||
|
this.peerAddress = validPeerAddress(peerAddress);
|
||||||
|
|
||||||
|
RequestTakeOffer.run(this::onResultRequestTakeOffer, this::onFault, this.peerAddress, messageFacade, tradeId);
|
||||||
|
state = State.RequestTakeOffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResultRequestTakeOffer()
|
||||||
|
{
|
||||||
|
listener.onWaitingForPeerResponse(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onAcceptTakeOfferRequestMessage()
|
public void onAcceptTakeOfferRequestMessage()
|
||||||
{
|
{
|
||||||
log.debug("onAcceptTakeOfferRequestMessage");
|
log.debug("onAcceptTakeOfferRequestMessage");
|
||||||
if (scheduler_1.getHasCompleted())
|
checkState(state == State.RequestTakeOffer);
|
||||||
{
|
|
||||||
List<Worker> tasks = new ArrayList<>();
|
PayTakeOfferFee.run(this::onResultPayTakeOfferFee, this::onFault, walletFacade, tradeId);
|
||||||
tasks.add(new PayTakeOfferFee(resultHandler, faultHandler));
|
state = State.PayTakeOfferFee;
|
||||||
tasks.add(new SendTakeOfferFeePayedTxId(resultHandler, faultHandler));
|
|
||||||
scheduler_2 = new SequenceScheduler(tasks, this);
|
|
||||||
scheduler_2.execute();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log.error("scheduler_1 has not completed yet.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Incoming message from peer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// OR
|
||||||
public void onRejectTakeOfferRequestMessage()
|
public void onRejectTakeOfferRequestMessage()
|
||||||
{
|
{
|
||||||
log.debug("onRejectTakeOfferRequestMessage");
|
log.debug("onRejectTakeOfferRequestMessage");
|
||||||
if (scheduler_1.getHasCompleted())
|
checkState(state == State.RequestTakeOffer);
|
||||||
{
|
|
||||||
//TODO
|
state = State.onRejectTakeOfferRequestMessage;
|
||||||
|
listener.onTakeOfferRequestRejected(trade);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
public void onResultPayTakeOfferFee(Transaction transaction)
|
||||||
{
|
{
|
||||||
log.error("scheduler_1 has not completed yet.");
|
checkNotNull(transaction);
|
||||||
|
String transactionId = validString(transaction.getHashAsString());
|
||||||
|
|
||||||
|
trade.setTakeOfferFeeTxID(transactionId);
|
||||||
|
|
||||||
|
String takeOfferFeeTxId = trade.getTakeOfferFeeTxId();
|
||||||
|
BigInteger tradeAmount = trade.getTradeAmount();
|
||||||
|
String pubKeyAsHexString = walletFacade.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
|
||||||
|
|
||||||
|
SendTakeOfferFeePayedTxId.run(this::onResultSendTakeOfferFeePayedTxId,
|
||||||
|
this::onFault,
|
||||||
|
peerAddress,
|
||||||
|
messageFacade,
|
||||||
|
tradeId,
|
||||||
|
takeOfferFeeTxId,
|
||||||
|
tradeAmount,
|
||||||
|
pubKeyAsHexString);
|
||||||
|
state = State.SendTakeOfferFeePayedTxId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tasks
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onResultSendTakeOfferFeePayedTxId()
|
||||||
|
{
|
||||||
|
listener.onWaitingForPeerResponse(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onRequestTakerDepositPaymentMessage(RequestTakerDepositPaymentMessage message)
|
public void onRequestTakerDepositPaymentMessage(RequestTakerDepositPaymentMessage message)
|
||||||
{
|
{
|
||||||
log.debug("onRequestTakerDepositPaymentMessage");
|
log.debug("onRequestTakerDepositPaymentMessage");
|
||||||
peersAccountId = message.getAccountID();
|
|
||||||
peersBankAccount = message.getBankAccount();
|
|
||||||
offererPubKey = message.getOffererPubKey();
|
|
||||||
preparedOffererDepositTxAsHex = message.getPreparedOffererDepositTxAsHex();
|
|
||||||
offererTxOutIndex = message.getOffererTxOutIndex();
|
|
||||||
|
|
||||||
if (scheduler_2.getHasCompleted())
|
checkState(state == State.SendTakeOfferFeePayedTxId);
|
||||||
{
|
|
||||||
List<Worker> tasks = new ArrayList<>();
|
peersAccountId = validString(message.getAccountID());
|
||||||
tasks.add(new VerifyOffererAccount(resultHandler, faultHandler));
|
peersBankAccount = checkNotNull(message.getBankAccount());
|
||||||
tasks.add(new CreateAndSignContract(resultHandler, faultHandler));
|
offererPubKey = validString(message.getOffererPubKey());
|
||||||
tasks.add(new PayDeposit(resultHandler, faultHandler));
|
preparedOffererDepositTxAsHex = validString(message.getPreparedOffererDepositTxAsHex());
|
||||||
tasks.add(new SendSignedTakerDepositTxAsHex(resultHandler, faultHandler));
|
offererTxOutIndex = validNonNegativeLong(message.getOffererTxOutIndex());
|
||||||
scheduler_3 = new SequenceScheduler(tasks, this);
|
|
||||||
scheduler_3.execute();
|
VerifyOffererAccount.run(this::onResultVerifyOffererAccount,
|
||||||
|
this::onFault,
|
||||||
|
blockChainFacade,
|
||||||
|
peersAccountId,
|
||||||
|
peersBankAccount);
|
||||||
|
state = State.VerifyOffererAccount;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Incoming message from peer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onResultVerifyOffererAccount()
|
||||||
{
|
{
|
||||||
log.error("scheduler_2 has not completed yet.");
|
CreateAndSignContract.run(this::onResultCreateAndSignContract,
|
||||||
|
this::onFault,
|
||||||
|
cryptoFacade,
|
||||||
|
trade,
|
||||||
|
user,
|
||||||
|
peersAccountId,
|
||||||
|
peersBankAccount,
|
||||||
|
walletFacade.getRegistrationAddressInfo().getKey());
|
||||||
|
state = State.CreateAndSignContract;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tasks
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onResultCreateAndSignContract()
|
||||||
|
{
|
||||||
|
PayDeposit.run(this::onResultPayDeposit, this::onFault, walletFacade, trade, offererPubKey, preparedOffererDepositTxAsHex);
|
||||||
|
state = State.PayDeposit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResultPayDeposit(Transaction signedTakerDepositTx, long takerTxOutIndex)
|
||||||
|
{
|
||||||
|
SendSignedTakerDepositTxAsHex.run(this::onResultSendSignedTakerDepositTxAsHex,
|
||||||
|
this::onFault,
|
||||||
|
peerAddress,
|
||||||
|
messageFacade,
|
||||||
|
walletFacade,
|
||||||
|
trade,
|
||||||
|
user,
|
||||||
|
signedTakerDepositTx,
|
||||||
|
takerTxOutIndex,
|
||||||
|
offererTxOutIndex);
|
||||||
|
state = State.SendSignedTakerDepositTxAsHex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResultSendSignedTakerDepositTxAsHex()
|
||||||
|
{
|
||||||
|
listener.onWaitingForPeerResponse(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// informational, does only trigger UI feedback/update
|
// informational, does only trigger UI feedback/update
|
||||||
public void onDepositTxPublishedMessage(DepositTxPublishedMessage message)
|
public void onDepositTxPublishedMessage(DepositTxPublishedMessage message)
|
||||||
{
|
{
|
||||||
log.debug("onDepositTxPublishedMessage");
|
log.debug("onDepositTxPublishedMessage");
|
||||||
String txID = getWalletFacade().takerCommitDepositTx(message.getDepositTxAsHex());
|
if (state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal())
|
||||||
listener.onDepositTxPublished(txID);
|
{
|
||||||
|
state = State.onDepositTxPublishedMessage;
|
||||||
|
|
||||||
|
listener.onDepositTxPublished(walletFacade.takerCommitDepositTx(message.getDepositTxAsHex()));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.error("Invalid state. Actual state is: " + state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Incoming message from peer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// informational, store data for later, does only trigger UI feedback/update
|
// informational, store data for later, does only trigger UI feedback/update
|
||||||
public void onBankTransferInitedMessage(BankTransferInitedMessage tradeMessage)
|
public void onBankTransferInitedMessage(BankTransferInitedMessage tradeMessage)
|
||||||
{
|
{
|
||||||
log.debug("onBankTransferInitedMessage");
|
log.debug("onBankTransferInitedMessage");
|
||||||
|
|
||||||
|
if (state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal())
|
||||||
|
{
|
||||||
|
state = State.onBankTransferInitedMessage;
|
||||||
|
|
||||||
depositTxAsHex = tradeMessage.getDepositTxAsHex();
|
depositTxAsHex = tradeMessage.getDepositTxAsHex();
|
||||||
offererSignatureR = tradeMessage.getOffererSignatureR();
|
offererSignatureR = tradeMessage.getOffererSignatureR();
|
||||||
offererSignatureS = tradeMessage.getOffererSignatureS();
|
offererSignatureS = tradeMessage.getOffererSignatureS();
|
||||||
|
@ -180,164 +280,87 @@ public class TakerAsSellerProtocol
|
||||||
|
|
||||||
listener.onBankTransferInited(tradeMessage.getTradeId());
|
listener.onBankTransferInited(tradeMessage.getTradeId());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.error("Invalid state. Actual state is: " + state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// User clicked the "bank transfer received" button, so we release the funds for pay out
|
// User clicked the "bank transfer received" button, so we release the funds for pay out
|
||||||
public void onUIEventFiatReceived()
|
public void onUIEventFiatReceived()
|
||||||
{
|
{
|
||||||
log.debug("onUIEventFiatReceived");
|
log.debug("onUIEventFiatReceived");
|
||||||
if (scheduler_3.getHasCompleted())
|
|
||||||
|
if (state.ordinal() > State.SendSignedTakerDepositTxAsHex.ordinal() && state.ordinal() < State.SignAndPublishPayoutTx.ordinal())
|
||||||
{
|
{
|
||||||
List<Worker> tasks = new ArrayList<>();
|
state = State.onUIEventFiatReceived;
|
||||||
tasks.add(new SignAndPublishPayoutTx(resultHandler, faultHandler));
|
|
||||||
tasks.add(new SendPayoutTxToOfferer(resultHandler, faultHandler));
|
SignAndPublishPayoutTx.run(this::onResultSignAndPublishPayoutTx,
|
||||||
scheduler_4 = new SequenceScheduler(tasks, this);
|
this::onFault,
|
||||||
scheduler_4.execute();
|
walletFacade,
|
||||||
|
trade,
|
||||||
|
depositTxAsHex,
|
||||||
|
offererSignatureR,
|
||||||
|
offererSignatureS,
|
||||||
|
offererPaybackAmount,
|
||||||
|
takerPaybackAmount,
|
||||||
|
offererPayoutAddress);
|
||||||
|
state = State.SignAndPublishPayoutTx;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log.error("scheduler_3 has not completed yet.");
|
log.error("Invalid state. Actual state is: " + state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onResultSignAndPublishPayoutTx(Transaction transaction, String payoutTxAsHex)
|
||||||
|
{
|
||||||
|
listener.onPayoutTxPublished(trade, transaction.getHashAsString());
|
||||||
|
|
||||||
|
SendPayoutTxToOfferer.run(this::onResultSendPayoutTxToOfferer, this::onFault, peerAddress, messageFacade, trade, payoutTxAsHex);
|
||||||
|
state = State.SendPayoutTxToOfferer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Tasks
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onResultSendPayoutTxToOfferer()
|
||||||
|
{
|
||||||
|
checkState(state == State.SendPayoutTxToOfferer);
|
||||||
|
listener.onCompleted(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Getters, Setters
|
// Getters, Setters
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public String getId()
|
public enum State
|
||||||
{
|
{
|
||||||
return id;
|
Init,
|
||||||
|
GetPeerAddress,
|
||||||
|
RequestTakeOffer,
|
||||||
|
PayTakeOfferFee,
|
||||||
|
onRejectTakeOfferRequestMessage,
|
||||||
|
SendTakeOfferFeePayedTxId,
|
||||||
|
VerifyOffererAccount,
|
||||||
|
CreateAndSignContract,
|
||||||
|
PayDeposit,
|
||||||
|
SendSignedTakerDepositTxAsHex,
|
||||||
|
onDepositTxPublishedMessage,
|
||||||
|
onBankTransferInitedMessage,
|
||||||
|
onUIEventFiatReceived,
|
||||||
|
SignAndPublishPayoutTx,
|
||||||
|
SendPayoutTxToOfferer
|
||||||
}
|
}
|
||||||
|
|
||||||
public Trade getTrade()
|
|
||||||
{
|
|
||||||
return trade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TakerAsSellerProtocolListener getListener()
|
|
||||||
{
|
|
||||||
return listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageFacade getMessageFacade()
|
|
||||||
{
|
|
||||||
return messageFacade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WalletFacade getWalletFacade()
|
|
||||||
{
|
|
||||||
return walletFacade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockChainFacade getBlockChainFacade()
|
|
||||||
{
|
|
||||||
return blockChainFacade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CryptoFacade getCryptoFacade()
|
|
||||||
{
|
|
||||||
return cryptoFacade;
|
|
||||||
}
|
|
||||||
|
|
||||||
public User getUser()
|
|
||||||
{
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PeerAddress getPeerAddress()
|
|
||||||
{
|
|
||||||
return peerAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPeerAddress(PeerAddress peerAddress)
|
|
||||||
{
|
|
||||||
this.peerAddress = peerAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Transaction getSignedTakerDepositTx()
|
|
||||||
{
|
|
||||||
return signedTakerDepositTx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSignedTakerDepositTx(Transaction signedTakerDepositTx)
|
|
||||||
{
|
|
||||||
this.signedTakerDepositTx = signedTakerDepositTx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTakerTxOutIndex()
|
|
||||||
{
|
|
||||||
return takerTxOutIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTakerTxOutIndex(long takerTxOutIndex)
|
|
||||||
{
|
|
||||||
this.takerTxOutIndex = takerTxOutIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPeersAccountId()
|
|
||||||
{
|
|
||||||
return peersAccountId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BankAccount getPeersBankAccount()
|
|
||||||
{
|
|
||||||
return peersBankAccount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOffererPubKey()
|
|
||||||
{
|
|
||||||
return offererPubKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPreparedOffererDepositTxAsHex()
|
|
||||||
{
|
|
||||||
return preparedOffererDepositTxAsHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getOffererTxOutIndex()
|
|
||||||
{
|
|
||||||
return offererTxOutIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDepositTxAsHex()
|
|
||||||
{
|
|
||||||
return depositTxAsHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOffererSignatureR()
|
|
||||||
{
|
|
||||||
return offererSignatureR;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOffererSignatureS()
|
|
||||||
{
|
|
||||||
return offererSignatureS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getOffererPaybackAmount()
|
|
||||||
{
|
|
||||||
return offererPaybackAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BigInteger getTakerPaybackAmount()
|
|
||||||
{
|
|
||||||
return takerPaybackAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOffererPayoutAddress()
|
|
||||||
{
|
|
||||||
return offererPayoutAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPayoutTxAsHex()
|
|
||||||
{
|
|
||||||
return payoutTxAsHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPayoutTxAsHex(String payoutTxAsHex)
|
|
||||||
{
|
|
||||||
this.payoutTxAsHex = payoutTxAsHex;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Step 1.1
|
// Step 1.1
|
||||||
|
@ -774,7 +797,7 @@ public class TakerAsSellerProtocol
|
||||||
{
|
{
|
||||||
System.out.println("######### 3.12 onSuccess walletFacade.takerSignsAndSendsTx " + transaction);
|
System.out.println("######### 3.12 onSuccess walletFacade.takerSignsAndSendsTx " + transaction);
|
||||||
log.debug("3.12 onSuccess walletFacade.takerSignsAndSendsTx " + transaction);
|
log.debug("3.12 onSuccess walletFacade.takerSignsAndSendsTx " + transaction);
|
||||||
listener.onTradeCompleted(transaction.getHashAsString());
|
listener.onPayoutTxPublished(transaction.getHashAsString());
|
||||||
|
|
||||||
sendPayoutTxToOfferer(Utils.bytesToHexString(transaction.bitcoinSerialize()));
|
sendPayoutTxToOfferer(Utils.bytesToHexString(transaction.bitcoinSerialize()));
|
||||||
}
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package io.bitsquare.trade.protocol.taker;
|
||||||
|
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
|
|
||||||
|
public interface TakerAsSellerProtocolListener
|
||||||
|
{
|
||||||
|
void onDepositTxPublished(String depositTxId);
|
||||||
|
|
||||||
|
void onBankTransferInited(String tradeId);
|
||||||
|
|
||||||
|
void onPayoutTxPublished(Trade trade, String hashAsString);
|
||||||
|
|
||||||
|
void onFault(Throwable throwable, TakerAsSellerProtocol.State state);
|
||||||
|
|
||||||
|
void onWaitingForPeerResponse(TakerAsSellerProtocol.State state);
|
||||||
|
|
||||||
|
void onCompleted(TakerAsSellerProtocol.State state);
|
||||||
|
|
||||||
|
void onTakeOfferRequestRejected(Trade trade);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks;
|
||||||
|
|
||||||
|
public interface FaultHandler
|
||||||
|
{
|
||||||
|
void onFault(Throwable throwable);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks;
|
||||||
|
|
||||||
|
public interface ResultHandler
|
||||||
|
{
|
||||||
|
void onResult();
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.InsufficientMoneyException;
|
||||||
|
import com.google.bitcoin.core.Transaction;
|
||||||
|
import com.google.bitcoin.core.Utils;
|
||||||
|
import io.bitsquare.btc.WalletFacade;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class CreateDepositTx
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(CreateDepositTx.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler,
|
||||||
|
FaultHandler faultHandler,
|
||||||
|
WalletFacade walletFacade,
|
||||||
|
String tradeId,
|
||||||
|
BigInteger collateralAmount,
|
||||||
|
String takerMultiSigPubKey,
|
||||||
|
String arbitratorPubKeyAsHex)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String offererPubKey = walletFacade.getAddressInfoByTradeID(tradeId).getPubKeyAsHexString();
|
||||||
|
Transaction transaction = walletFacade.offererCreatesMSTxAndAddPayment(collateralAmount,
|
||||||
|
offererPubKey,
|
||||||
|
takerMultiSigPubKey,
|
||||||
|
arbitratorPubKeyAsHex,
|
||||||
|
tradeId);
|
||||||
|
|
||||||
|
String preparedOffererDepositTxAsHex = Utils.bytesToHexString(transaction.bitcoinSerialize());
|
||||||
|
long offererTxOutIndex = transaction.getInput(0).getOutpoint().getIndex();
|
||||||
|
|
||||||
|
resultHandler.onResult(offererPubKey, preparedOffererDepositTxAsHex, offererTxOutIndex);
|
||||||
|
} catch (InsufficientMoneyException e)
|
||||||
|
{
|
||||||
|
log.error("Create deposit tx faultHandler.onFault due InsufficientMoneyException " + e);
|
||||||
|
faultHandler.onFault(new Exception("Create deposit tx faultHandler.onFault due InsufficientMoneyException " + e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultHandler
|
||||||
|
{
|
||||||
|
void onResult(String offererPubKey, String preparedOffererDepositTxAsHex, long offererTxOutIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.messages.offerer.AcceptTakeOfferRequestMessage;
|
||||||
|
import io.bitsquare.trade.protocol.messages.offerer.RejectTakeOfferRequestMessage;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class HandleTakeOfferRequest
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(HandleTakeOfferRequest.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade.State tradeState, String tradeId)
|
||||||
|
{
|
||||||
|
if (tradeState == Trade.State.OPEN)
|
||||||
|
{
|
||||||
|
messageFacade.sendTradeMessage(peerAddress, new AcceptTakeOfferRequestMessage(tradeId), new OutgoingTradeMessageListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onResult()
|
||||||
|
{
|
||||||
|
log.trace("AcceptTakeOfferRequestMessage successfully arrived at peer");
|
||||||
|
resultHandler.onResult(Trade.State.ACCEPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailed()
|
||||||
|
{
|
||||||
|
log.error("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer");
|
||||||
|
faultHandler.onFault(new Exception("AcceptTakeOfferRequestMessage faultHandler.onFault to arrive at peer"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RejectTakeOfferRequestMessage msg = new RejectTakeOfferRequestMessage(tradeId);
|
||||||
|
messageFacade.sendTradeMessage(peerAddress, msg, new OutgoingTradeMessageListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onResult()
|
||||||
|
{
|
||||||
|
log.trace("RejectTakeOfferRequestMessage successfully arrived at peer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailed()
|
||||||
|
{
|
||||||
|
log.error("RejectTakeOfferRequestMessage faultHandler.onFault to arrive at peer");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
log.error("Offer not marked as open.");
|
||||||
|
faultHandler.onFault(new Exception("Offer not marked as open."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultHandler
|
||||||
|
{
|
||||||
|
void onResult(Trade.State tradeState);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
|
import io.bitsquare.bank.BankAccount;
|
||||||
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
|
||||||
|
import io.bitsquare.trade.protocol.messages.offerer.RequestTakerDepositPaymentMessage;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class RequestTakerDepositPayment
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RequestTakerDepositPayment.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler,
|
||||||
|
FaultHandler faultHandler,
|
||||||
|
PeerAddress peerAddress,
|
||||||
|
MessageFacade messageFacade,
|
||||||
|
String tradeId,
|
||||||
|
BankAccount bankAccount,
|
||||||
|
String accountId,
|
||||||
|
String offererPubKey,
|
||||||
|
String preparedOffererDepositTxAsHex,
|
||||||
|
long offererTxOutIndex)
|
||||||
|
{
|
||||||
|
RequestTakerDepositPaymentMessage tradeMessage = new RequestTakerDepositPaymentMessage(tradeId,
|
||||||
|
bankAccount,
|
||||||
|
accountId,
|
||||||
|
offererPubKey,
|
||||||
|
preparedOffererDepositTxAsHex,
|
||||||
|
offererTxOutIndex);
|
||||||
|
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onResult()
|
||||||
|
{
|
||||||
|
log.trace("RequestTakerDepositPaymentMessage successfully arrived at peer");
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailed()
|
||||||
|
{
|
||||||
|
log.error("RequestTakerDepositPaymentMessage faultHandler.onFault to arrive at peer");
|
||||||
|
faultHandler.onFault(new Exception("RequestTakerDepositPaymentMessage faultHandler.onFault to arrive at peer"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.Utils;
|
||||||
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.messages.offerer.DepositTxPublishedMessage;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class SendDepositTxIdToTaker
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SendDepositTxIdToTaker.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade trade)
|
||||||
|
{
|
||||||
|
DepositTxPublishedMessage tradeMessage = new DepositTxPublishedMessage(trade.getId(), Utils.bytesToHexString(trade.getDepositTransaction().bitcoinSerialize()));
|
||||||
|
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onResult()
|
||||||
|
{
|
||||||
|
log.trace("DepositTxPublishedMessage successfully arrived at peer");
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailed()
|
||||||
|
{
|
||||||
|
log.error("DepositTxPublishedMessage faultHandler.onFault to arrive at peer");
|
||||||
|
faultHandler.onFault(new Exception("DepositTxPublishedMessage faultHandler.onFault to arrive at peer"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,55 +1,57 @@
|
||||||
package io.bitsquare.trade.payment.offerer.tasks;
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
import com.google.bitcoin.core.ECKey;
|
import com.google.bitcoin.core.ECKey;
|
||||||
import com.google.bitcoin.core.Transaction;
|
import com.google.bitcoin.core.Transaction;
|
||||||
import io.bitsquare.msg.listeners.TradeMessageListener;
|
import io.bitsquare.btc.WalletFacade;
|
||||||
import io.bitsquare.trade.payment.offerer.messages.BankTransferInitedMessage;
|
import io.bitsquare.msg.MessageFacade;
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.messages.offerer.BankTransferInitedMessage;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import javafx.util.Pair;
|
import javafx.util.Pair;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class SendSignedPayoutTx extends AbstractOffererAsBuyerTask
|
public class SendSignedPayoutTx
|
||||||
{
|
{
|
||||||
private static final Logger log = LoggerFactory.getLogger(SendSignedPayoutTx.class);
|
private static final Logger log = LoggerFactory.getLogger(SendSignedPayoutTx.class);
|
||||||
|
|
||||||
public SendSignedPayoutTx(WorkerResultHandler resultHandler, WorkerFaultHandler faultHandler)
|
public static void run(ResultHandler resultHandler,
|
||||||
|
FaultHandler faultHandler,
|
||||||
|
PeerAddress peerAddress,
|
||||||
|
MessageFacade messageFacade,
|
||||||
|
WalletFacade walletFacade,
|
||||||
|
Trade trade,
|
||||||
|
String takerPayoutAddress)
|
||||||
{
|
{
|
||||||
super(resultHandler, faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
log.trace("execute");
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Transaction depositTransaction = sharedModel.getTrade().getDepositTransaction();
|
Transaction depositTransaction = trade.getDepositTransaction();
|
||||||
BigInteger collateral = sharedModel.getTrade().getCollateralAmount();
|
BigInteger collateral = trade.getCollateralAmount();
|
||||||
BigInteger offererPaybackAmount = sharedModel.getTrade().getTradeAmount().add(collateral);
|
BigInteger offererPaybackAmount = trade.getTradeAmount().add(collateral);
|
||||||
BigInteger takerPaybackAmount = collateral;
|
BigInteger takerPaybackAmount = collateral;
|
||||||
|
|
||||||
log.trace("offererPaybackAmount " + offererPaybackAmount);
|
log.trace("offererPaybackAmount " + offererPaybackAmount);
|
||||||
log.trace("takerPaybackAmount " + takerPaybackAmount);
|
log.trace("takerPaybackAmount " + takerPaybackAmount);
|
||||||
log.trace("depositTransaction.getHashAsString() " + depositTransaction.getHashAsString());
|
log.trace("depositTransaction.getHashAsString() " + depositTransaction.getHashAsString());
|
||||||
log.trace("takerPayoutAddress " + sharedModel.getTakerPayoutAddress());
|
log.trace("takerPayoutAddress " + takerPayoutAddress);
|
||||||
|
|
||||||
Pair<ECKey.ECDSASignature, String> result = sharedModel.getWalletFacade().offererCreatesAndSignsPayoutTx(depositTransaction.getHashAsString(),
|
Pair<ECKey.ECDSASignature, String> result = walletFacade.offererCreatesAndSignsPayoutTx(depositTransaction.getHashAsString(),
|
||||||
offererPaybackAmount,
|
offererPaybackAmount,
|
||||||
takerPaybackAmount,
|
takerPaybackAmount,
|
||||||
sharedModel.getTakerPayoutAddress(),
|
takerPayoutAddress,
|
||||||
sharedModel.getTrade().getId());
|
trade.getId());
|
||||||
|
|
||||||
ECKey.ECDSASignature offererSignature = result.getKey();
|
ECKey.ECDSASignature offererSignature = result.getKey();
|
||||||
String offererSignatureR = offererSignature.r.toString();
|
String offererSignatureR = offererSignature.r.toString();
|
||||||
String offererSignatureS = offererSignature.s.toString();
|
String offererSignatureS = offererSignature.s.toString();
|
||||||
String depositTxAsHex = result.getValue();
|
String depositTxAsHex = result.getValue();
|
||||||
String offererPayoutAddress = sharedModel.getWalletFacade().getAddressInfoByTradeID(sharedModel.getTrade().getId()).getAddressString();
|
String offererPayoutAddress = walletFacade.getAddressInfoByTradeID(trade.getId()).getAddressString();
|
||||||
|
|
||||||
BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(sharedModel.getTrade().getId(),
|
BankTransferInitedMessage tradeMessage = new BankTransferInitedMessage(trade.getId(),
|
||||||
depositTxAsHex,
|
depositTxAsHex,
|
||||||
offererSignatureR,
|
offererSignatureR,
|
||||||
offererSignatureS,
|
offererSignatureS,
|
||||||
|
@ -64,28 +66,27 @@ public class SendSignedPayoutTx extends AbstractOffererAsBuyerTask
|
||||||
log.trace("takerPaybackAmount " + takerPaybackAmount);
|
log.trace("takerPaybackAmount " + takerPaybackAmount);
|
||||||
log.trace("offererPayoutAddress " + offererPayoutAddress);
|
log.trace("offererPayoutAddress " + offererPayoutAddress);
|
||||||
|
|
||||||
sharedModel.getMessageFacade().sendTradeMessage(sharedModel.peerAddress, tradeMessage, new TradeMessageListener()
|
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void onResult()
|
public void onResult()
|
||||||
{
|
{
|
||||||
log.trace("BankTransferInitedMessage successfully arrived at peer");
|
log.trace("BankTransferInitedMessage successfully arrived at peer");
|
||||||
complete();
|
resultHandler.onResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailed()
|
public void onFailed()
|
||||||
{
|
{
|
||||||
log.error("BankTransferInitedMessage failed to arrive at peer");
|
log.error("BankTransferInitedMessage faultHandler.onFault to arrive at peer");
|
||||||
failed(new Exception("BankTransferInitedMessage failed to arrive at peer"));
|
faultHandler.onFault(new Exception("BankTransferInitedMessage faultHandler.onFault to arrive at peer"));
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Exception e)
|
} catch (Exception e)
|
||||||
{
|
{
|
||||||
log.error("Exception at OffererCreatesAndSignsPayoutTx " + e);
|
log.error("Exception at OffererCreatesAndSignsPayoutTx " + e);
|
||||||
failed(e);
|
faultHandler.onFault(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.Transaction;
|
||||||
|
import com.google.bitcoin.core.TransactionConfidence;
|
||||||
|
import io.bitsquare.trade.protocol.offerer.OffererAsBuyerProtocolListener;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class SetupListenerForBlockChainConfirmation
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SetupListenerForBlockChainConfirmation.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, Transaction depositTransaction, OffererAsBuyerProtocolListener listener)
|
||||||
|
{ //TODO
|
||||||
|
// sharedModel.offererPaymentProtocolListener.onDepositTxConfirmedInBlockchain();
|
||||||
|
|
||||||
|
depositTransaction.getConfidence().addEventListener(new TransactionConfidence.Listener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onConfidenceChanged(Transaction tx, ChangeReason reason)
|
||||||
|
{
|
||||||
|
log.trace("onConfidenceChanged " + tx.getConfidence());
|
||||||
|
if (reason == ChangeReason.SEEN_PEERS)
|
||||||
|
{
|
||||||
|
listener.onDepositTxConfirmedUpdate(tx.getConfidence());
|
||||||
|
}
|
||||||
|
if (reason == ChangeReason.TYPE && tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING)
|
||||||
|
{
|
||||||
|
listener.onDepositTxConfirmedInBlockchain();
|
||||||
|
depositTransaction.getConfidence().removeEventListener(this);
|
||||||
|
log.trace("Tx is in blockchain");
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.Transaction;
|
||||||
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
import io.bitsquare.btc.WalletFacade;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class SignAndPublishDepositTx
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SignAndPublishDepositTx.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler,
|
||||||
|
FaultHandler faultHandler,
|
||||||
|
WalletFacade walletFacade,
|
||||||
|
String preparedOffererDepositTxAsHex,
|
||||||
|
String signedTakerDepositTxAsHex,
|
||||||
|
String txConnOutAsHex,
|
||||||
|
String txScriptSigAsHex,
|
||||||
|
long offererTxOutIndex,
|
||||||
|
long takerTxOutIndex)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
walletFacade.offererSignAndPublishTx(preparedOffererDepositTxAsHex,
|
||||||
|
signedTakerDepositTxAsHex,
|
||||||
|
txConnOutAsHex,
|
||||||
|
txScriptSigAsHex,
|
||||||
|
offererTxOutIndex,
|
||||||
|
takerTxOutIndex,
|
||||||
|
new FutureCallback<Transaction>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Transaction transaction)
|
||||||
|
{
|
||||||
|
log.trace("offererSignAndPublishTx succeeded " + transaction);
|
||||||
|
resultHandler.onResult(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t)
|
||||||
|
{
|
||||||
|
log.error("offererSignAndPublishTx faultHandler.onFault:" + t);
|
||||||
|
faultHandler.onFault(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
log.error("offererSignAndPublishTx faultHandler.onFault:" + e);
|
||||||
|
faultHandler.onFault(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultHandler
|
||||||
|
{
|
||||||
|
void onResult(Transaction transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.ECKey;
|
||||||
|
import io.bitsquare.bank.BankAccount;
|
||||||
|
import io.bitsquare.crypto.CryptoFacade;
|
||||||
|
import io.bitsquare.trade.Contract;
|
||||||
|
import io.bitsquare.trade.Offer;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.util.Utilities;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class VerifyAndSignContract
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(VerifyAndSignContract.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler,
|
||||||
|
FaultHandler faultHandler,
|
||||||
|
CryptoFacade cryptoFacade,
|
||||||
|
String accountId,
|
||||||
|
BigInteger tradeAmount,
|
||||||
|
String takeOfferFeeTxId,
|
||||||
|
String messagePubKeyAsHex,
|
||||||
|
Offer offer,
|
||||||
|
String peersAccountId,
|
||||||
|
BankAccount bankAccount,
|
||||||
|
BankAccount peersBankAccount,
|
||||||
|
String takerMessagePubKey,
|
||||||
|
String peersContractAsJson,
|
||||||
|
ECKey registrationKey)
|
||||||
|
{
|
||||||
|
Contract contract = new Contract(offer,
|
||||||
|
tradeAmount,
|
||||||
|
takeOfferFeeTxId,
|
||||||
|
accountId,
|
||||||
|
peersAccountId,
|
||||||
|
bankAccount,
|
||||||
|
peersBankAccount,
|
||||||
|
messagePubKeyAsHex,
|
||||||
|
takerMessagePubKey);
|
||||||
|
|
||||||
|
String contractAsJson = Utilities.objectToJson(contract);
|
||||||
|
// log.trace("Offerer contract created: " + contract);
|
||||||
|
// log.trace("Offerers contractAsJson: " + contractAsJson);
|
||||||
|
// log.trace("Takers contractAsJson: " + sharedModel.peersContractAsJson);
|
||||||
|
if (contractAsJson.equals(peersContractAsJson))
|
||||||
|
{
|
||||||
|
log.trace("The 2 contracts as json does match");
|
||||||
|
String signature = cryptoFacade.signContract(registrationKey, contractAsJson);
|
||||||
|
//log.trace("signature: " + signature);
|
||||||
|
|
||||||
|
resultHandler.onResult(contract, contractAsJson, signature);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO use diff output as feedback ?
|
||||||
|
log.error("Contracts are not matching.");
|
||||||
|
log.error("Offerers contractAsJson: " + contractAsJson);
|
||||||
|
log.error("Takers contractAsJson: " + peersContractAsJson);
|
||||||
|
|
||||||
|
faultHandler.onFault(new Exception("Contracts are not matching"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultHandler
|
||||||
|
{
|
||||||
|
void onResult(Contract contract, String contractAsJson, String signature);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
|
import io.bitsquare.btc.WalletFacade;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class VerifyTakeOfferFeePayment
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(VerifyTakeOfferFeePayment.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, WalletFacade walletFacade, String takeOfferFeeTxId)
|
||||||
|
{ //TODO mocked yet, need a confidence listeners
|
||||||
|
int numOfPeersSeenTx = walletFacade.getNumOfPeersSeenTx(takeOfferFeeTxId);
|
||||||
|
if (numOfPeersSeenTx > 2)
|
||||||
|
{
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.offerer;
|
||||||
|
|
||||||
|
import io.bitsquare.bank.BankAccount;
|
||||||
|
import io.bitsquare.btc.BlockChainFacade;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class VerifyTakerAccount
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(VerifyTakerAccount.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
|
||||||
|
{
|
||||||
|
//TODO mocked yet
|
||||||
|
if (blockChainFacade.verifyAccountRegistration())
|
||||||
|
{
|
||||||
|
if (blockChainFacade.isAccountBlackListed(peersAccountId, peersBankAccount))
|
||||||
|
{
|
||||||
|
log.error("Taker is blacklisted");
|
||||||
|
faultHandler.onFault(new Exception("Taker is blacklisted"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.error("Account registration validation for peer faultHandler.onFault.");
|
||||||
|
faultHandler.onFault(new Exception("Account registration validation for peer faultHandler.onFault."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.ECKey;
|
||||||
|
import io.bitsquare.bank.BankAccount;
|
||||||
|
import io.bitsquare.crypto.CryptoFacade;
|
||||||
|
import io.bitsquare.trade.Contract;
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import io.bitsquare.user.User;
|
||||||
|
import io.bitsquare.util.Utilities;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class CreateAndSignContract
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(CreateAndSignContract.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler,
|
||||||
|
FaultHandler faultHandler,
|
||||||
|
CryptoFacade cryptoFacade,
|
||||||
|
Trade trade,
|
||||||
|
User user,
|
||||||
|
String peersAccountId,
|
||||||
|
BankAccount peersBankAccount,
|
||||||
|
ECKey registrationKey)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Contract contract = new Contract(trade.getOffer(),
|
||||||
|
trade.getTradeAmount(),
|
||||||
|
trade.getTakeOfferFeeTxId(),
|
||||||
|
peersAccountId,
|
||||||
|
user.getAccountId(),
|
||||||
|
peersBankAccount,
|
||||||
|
user.getCurrentBankAccount(),
|
||||||
|
trade.getOffer().getMessagePubKeyAsHex(),
|
||||||
|
user.getMessagePubKeyAsHex()
|
||||||
|
);
|
||||||
|
|
||||||
|
String contractAsJson = Utilities.objectToJson(contract);
|
||||||
|
String signature = cryptoFacade.signContract(registrationKey, contractAsJson);
|
||||||
|
//log.trace("contract: " + contract);
|
||||||
|
//log.debug("contractAsJson: " + contractAsJson);
|
||||||
|
//log.trace("contract signature: " + signature);
|
||||||
|
|
||||||
|
trade.setContract(contract);
|
||||||
|
trade.setContractAsJson(contractAsJson);
|
||||||
|
trade.setContractTakerSignature(signature);
|
||||||
|
|
||||||
|
resultHandler.onResult();
|
||||||
|
} catch (Throwable t)
|
||||||
|
{
|
||||||
|
log.error("Exception at sign contract " + t);
|
||||||
|
faultHandler.onFault(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.msg.listeners.GetPeerAddressListener;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class GetPeerAddress
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(GetPeerAddress.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, MessageFacade messageFacade, String messagePubKeyAsHex)
|
||||||
|
{
|
||||||
|
messageFacade.getPeerAddress(messagePubKeyAsHex, new GetPeerAddressListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onResult(PeerAddress peerAddress)
|
||||||
|
{
|
||||||
|
log.trace("Received address = " + peerAddress.toString());
|
||||||
|
resultHandler.onResult(peerAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailed()
|
||||||
|
{
|
||||||
|
log.error("Lookup for peer address faultHandler.onFault.");
|
||||||
|
faultHandler.onFault(new Exception("Lookup for peer address faultHandler.onFault."));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultHandler
|
||||||
|
{
|
||||||
|
void onResult(PeerAddress peerAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.InsufficientMoneyException;
|
||||||
|
import com.google.bitcoin.core.Transaction;
|
||||||
|
import io.bitsquare.btc.WalletFacade;
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class PayDeposit
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(PayDeposit.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, WalletFacade walletFacade, Trade trade, String offererPubKey, String preparedOffererDepositTxAsHex)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
BigInteger collateralAmount = trade.getCollateralAmount();
|
||||||
|
Transaction signedTakerDepositTx = walletFacade.takerAddPaymentAndSignTx(trade.getTradeAmount().add(collateralAmount),
|
||||||
|
trade.getTradeAmount().add(collateralAmount).add(collateralAmount),
|
||||||
|
offererPubKey,
|
||||||
|
walletFacade.getAddressInfoByTradeID(trade.getId()).getPubKeyAsHexString(),
|
||||||
|
trade.getOffer().getArbitrator().getPubKeyAsHex(),
|
||||||
|
preparedOffererDepositTxAsHex,
|
||||||
|
trade.getId());
|
||||||
|
|
||||||
|
log.trace("sharedModel.signedTakerDepositTx: " + signedTakerDepositTx);
|
||||||
|
long takerTxOutIndex = signedTakerDepositTx.getInput(1).getOutpoint().getIndex();
|
||||||
|
|
||||||
|
resultHandler.onResult(signedTakerDepositTx, takerTxOutIndex);
|
||||||
|
} catch (InsufficientMoneyException e)
|
||||||
|
{
|
||||||
|
log.error("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e);
|
||||||
|
faultHandler.onFault(new Exception("Pay deposit faultHandler.onFault due InsufficientMoneyException " + e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultHandler
|
||||||
|
{
|
||||||
|
void onResult(Transaction signedTakerDepositTx, long takerTxOutIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.InsufficientMoneyException;
|
||||||
|
import com.google.bitcoin.core.Transaction;
|
||||||
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
import io.bitsquare.btc.WalletFacade;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class PayTakeOfferFee
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(PayTakeOfferFee.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, WalletFacade walletFacade, String tradeId)
|
||||||
|
{
|
||||||
|
log.trace("execute");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
walletFacade.payTakeOfferFee(tradeId, new FutureCallback<Transaction>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Transaction transaction)
|
||||||
|
{
|
||||||
|
log.debug("Take offer fee paid successfully. Transaction ID = " + transaction.getHashAsString());
|
||||||
|
resultHandler.onResult(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t)
|
||||||
|
{
|
||||||
|
log.error("Take offer fee paid faultHandler.onFault with exception: " + t);
|
||||||
|
faultHandler.onFault(new Exception("Take offer fee paid faultHandler.onFault with exception: " + t));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (InsufficientMoneyException e)
|
||||||
|
{
|
||||||
|
log.error("Take offer fee paid faultHandler.onFault due InsufficientMoneyException " + e);
|
||||||
|
faultHandler.onFault(new Exception("Take offer fee paid faultHandler.onFault due InsufficientMoneyException " + e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultHandler
|
||||||
|
{
|
||||||
|
void onResult(Transaction transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
|
||||||
|
import io.bitsquare.trade.protocol.messages.taker.RequestTakeOfferMessage;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class RequestTakeOffer
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(RequestTakeOffer.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, String tradeId)
|
||||||
|
{
|
||||||
|
messageFacade.sendTradeMessage(peerAddress, new RequestTakeOfferMessage(tradeId), new OutgoingTradeMessageListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onResult()
|
||||||
|
{
|
||||||
|
log.trace("RequestTakeOfferMessage successfully arrived at peer");
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailed()
|
||||||
|
{
|
||||||
|
log.error("RequestTakeOfferMessage faultHandler.onFault to arrive at peer");
|
||||||
|
faultHandler.onFault(new Exception("RequestTakeOfferMessage faultHandler.onFault to arrive at peer"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.messages.taker.PayoutTxPublishedMessage;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class SendPayoutTxToOfferer
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SendPayoutTxToOfferer.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, PeerAddress peerAddress, MessageFacade messageFacade, Trade trade, String payoutTxAsHex)
|
||||||
|
{
|
||||||
|
PayoutTxPublishedMessage tradeMessage = new PayoutTxPublishedMessage(trade.getId(), payoutTxAsHex);
|
||||||
|
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onResult()
|
||||||
|
{
|
||||||
|
log.trace("PayoutTxPublishedMessage successfully arrived at peer");
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailed()
|
||||||
|
{
|
||||||
|
log.error("PayoutTxPublishedMessage faultHandler.onFault to arrive at peer");
|
||||||
|
faultHandler.onFault(new Exception("PayoutTxPublishedMessage faultHandler.onFault to arrive at peer"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.Transaction;
|
||||||
|
import com.google.bitcoin.core.Utils;
|
||||||
|
import io.bitsquare.btc.WalletFacade;
|
||||||
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.messages.taker.RequestOffererPublishDepositTxMessage;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import io.bitsquare.user.User;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class SendSignedTakerDepositTxAsHex
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SendSignedTakerDepositTxAsHex.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler,
|
||||||
|
FaultHandler faultHandler,
|
||||||
|
PeerAddress peerAddress,
|
||||||
|
MessageFacade messageFacade,
|
||||||
|
WalletFacade walletFacade,
|
||||||
|
Trade trade,
|
||||||
|
User user,
|
||||||
|
Transaction signedTakerDepositTx,
|
||||||
|
long takerTxOutIndex,
|
||||||
|
long offererTxOutIndex)
|
||||||
|
{
|
||||||
|
RequestOffererPublishDepositTxMessage tradeMessage = new RequestOffererPublishDepositTxMessage(trade.getId(),
|
||||||
|
user.getCurrentBankAccount(),
|
||||||
|
user.getAccountId(),
|
||||||
|
user.getMessagePubKeyAsHex(),
|
||||||
|
Utils.bytesToHexString(signedTakerDepositTx.bitcoinSerialize()),
|
||||||
|
Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getScriptBytes()),
|
||||||
|
Utils.bytesToHexString(signedTakerDepositTx.getInput(1).getConnectedOutput().getParentTransaction().bitcoinSerialize()),
|
||||||
|
trade.getContractAsJson(),
|
||||||
|
trade.getTakerSignature(),
|
||||||
|
walletFacade.getAddressInfoByTradeID(trade.getId()).getAddressString(),
|
||||||
|
takerTxOutIndex,
|
||||||
|
offererTxOutIndex);
|
||||||
|
messageFacade.sendTradeMessage(peerAddress, tradeMessage, new OutgoingTradeMessageListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onResult()
|
||||||
|
{
|
||||||
|
log.trace("RequestOffererDepositPublicationMessage successfully arrived at peer");
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailed()
|
||||||
|
{
|
||||||
|
log.error("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer");
|
||||||
|
faultHandler.onFault(new Exception("RequestOffererDepositPublicationMessage faultHandler.onFault to arrive at peer"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import io.bitsquare.msg.MessageFacade;
|
||||||
|
import io.bitsquare.msg.listeners.OutgoingTradeMessageListener;
|
||||||
|
import io.bitsquare.trade.protocol.messages.taker.TakeOfferFeePayedMessage;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class SendTakeOfferFeePayedTxId
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SendTakeOfferFeePayedTxId.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler,
|
||||||
|
FaultHandler faultHandler,
|
||||||
|
PeerAddress peerAddress,
|
||||||
|
MessageFacade messageFacade,
|
||||||
|
String tradeId,
|
||||||
|
String takeOfferFeeTxId,
|
||||||
|
BigInteger tradeAmount,
|
||||||
|
String pubKeyAsHexString)
|
||||||
|
{
|
||||||
|
TakeOfferFeePayedMessage msg = new TakeOfferFeePayedMessage(tradeId,
|
||||||
|
takeOfferFeeTxId,
|
||||||
|
tradeAmount,
|
||||||
|
pubKeyAsHexString);
|
||||||
|
|
||||||
|
messageFacade.sendTradeMessage(peerAddress, msg, new OutgoingTradeMessageListener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onResult()
|
||||||
|
{
|
||||||
|
log.trace("TakeOfferFeePayedMessage successfully arrived at peer");
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailed()
|
||||||
|
{
|
||||||
|
log.error("TakeOfferFeePayedMessage faultHandler.onFault to arrive at peer");
|
||||||
|
faultHandler.onFault(new Exception("TakeOfferFeePayedMessage faultHandler.onFault to arrive at peer"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import com.google.bitcoin.core.Transaction;
|
||||||
|
import com.google.bitcoin.core.Utils;
|
||||||
|
import com.google.common.util.concurrent.FutureCallback;
|
||||||
|
import io.bitsquare.btc.WalletFacade;
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class SignAndPublishPayoutTx
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SignAndPublishPayoutTx.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler,
|
||||||
|
FaultHandler faultHandler,
|
||||||
|
WalletFacade walletFacade,
|
||||||
|
Trade trade,
|
||||||
|
String depositTxAsHex,
|
||||||
|
String offererSignatureR,
|
||||||
|
String offererSignatureS,
|
||||||
|
BigInteger offererPaybackAmount,
|
||||||
|
BigInteger takerPaybackAmount,
|
||||||
|
String offererPayoutAddress
|
||||||
|
)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
walletFacade.takerSignsAndSendsTx(depositTxAsHex,
|
||||||
|
offererSignatureR,
|
||||||
|
offererSignatureS,
|
||||||
|
offererPaybackAmount,
|
||||||
|
takerPaybackAmount,
|
||||||
|
offererPayoutAddress,
|
||||||
|
trade.getId(),
|
||||||
|
new FutureCallback<Transaction>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Transaction transaction)
|
||||||
|
{
|
||||||
|
log.debug("takerSignsAndSendsTx " + transaction);
|
||||||
|
String payoutTxAsHex = Utils.bytesToHexString(transaction.bitcoinSerialize());
|
||||||
|
resultHandler.onResult(transaction, payoutTxAsHex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t)
|
||||||
|
{
|
||||||
|
log.error("Exception at takerSignsAndSendsTx " + t);
|
||||||
|
faultHandler.onFault(t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
log.error("Exception at takerSignsAndSendsTx " + e);
|
||||||
|
faultHandler.onFault(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ResultHandler
|
||||||
|
{
|
||||||
|
void onResult(Transaction transaction, String payoutTxAsHex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package io.bitsquare.trade.protocol.tasks.taker;
|
||||||
|
|
||||||
|
import io.bitsquare.bank.BankAccount;
|
||||||
|
import io.bitsquare.btc.BlockChainFacade;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.FaultHandler;
|
||||||
|
import io.bitsquare.trade.protocol.tasks.ResultHandler;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class VerifyOffererAccount
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(VerifyOffererAccount.class);
|
||||||
|
|
||||||
|
public static void run(ResultHandler resultHandler, FaultHandler faultHandler, BlockChainFacade blockChainFacade, String peersAccountId, BankAccount peersBankAccount)
|
||||||
|
{
|
||||||
|
//TODO mocked yet
|
||||||
|
if (blockChainFacade.verifyAccountRegistration())
|
||||||
|
{
|
||||||
|
if (blockChainFacade.isAccountBlackListed(peersAccountId, peersBankAccount))
|
||||||
|
{
|
||||||
|
log.error("Offerer is blacklisted");
|
||||||
|
faultHandler.onFault(new Exception("Offerer is blacklisted"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultHandler.onResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log.error("Account Registration for peer faultHandler.onFault.");
|
||||||
|
faultHandler.onFault(new Exception("Account Registration for peer faultHandler.onFault."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ public class User implements Serializable
|
||||||
{
|
{
|
||||||
if (savedUser != null)
|
if (savedUser != null)
|
||||||
{
|
{
|
||||||
accountID = savedUser.getAccountID();
|
accountID = savedUser.getAccountId();
|
||||||
messagePubKeyAsHex = savedUser.getMessagePubKeyAsHex();
|
messagePubKeyAsHex = savedUser.getMessagePubKeyAsHex();
|
||||||
isOnline = savedUser.getIsOnline();
|
isOnline = savedUser.getIsOnline();
|
||||||
bankAccounts = savedUser.getBankAccounts();
|
bankAccounts = savedUser.getBankAccounts();
|
||||||
|
@ -92,7 +92,7 @@ public class User implements Serializable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String getAccountID()
|
public String getAccountId()
|
||||||
{
|
{
|
||||||
return accountID;
|
return accountID;
|
||||||
}
|
}
|
||||||
|
|
34
src/main/java/io/bitsquare/util/Validator.java
Normal file
34
src/main/java/io/bitsquare/util/Validator.java
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package io.bitsquare.util;
|
||||||
|
|
||||||
|
import net.tomp2p.peers.PeerAddress;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
public class Validator
|
||||||
|
{
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(Validator.class);
|
||||||
|
|
||||||
|
public static String validString(String value)
|
||||||
|
{
|
||||||
|
checkNotNull(value);
|
||||||
|
checkArgument(value.length() > 0);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long validNonNegativeLong(long value)
|
||||||
|
{
|
||||||
|
checkArgument(value >= 0);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PeerAddress validPeerAddress(PeerAddress value)
|
||||||
|
{
|
||||||
|
checkNotNull(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,37 +0,0 @@
|
||||||
package io.nucleo.scheduler;
|
|
||||||
|
|
||||||
import com.sun.istack.internal.NotNull;
|
|
||||||
import io.nucleo.scheduler.worker.AbstractWorker;
|
|
||||||
import io.nucleo.scheduler.worker.Worker;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class AbstractScheduler extends AbstractWorker implements WorkerResultHandler, WorkerFaultHandler
|
|
||||||
{
|
|
||||||
protected List<Worker> workerElements = new ArrayList<>();
|
|
||||||
|
|
||||||
public void setWorkers(@NotNull List<Worker> workerElements)
|
|
||||||
{
|
|
||||||
this.workerElements = workerElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void executeWorker(Worker worker)
|
|
||||||
{
|
|
||||||
((AbstractWorker) worker).setModel(model);
|
|
||||||
worker.addResultHandlers(this);
|
|
||||||
worker.addFaultHandlers(this);
|
|
||||||
worker.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onResult()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onFault(Throwable throwable)
|
|
||||||
{
|
|
||||||
failed(throwable);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
package io.nucleo.scheduler;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.tasks.AbstractDependencyManagedTask;
|
|
||||||
import io.nucleo.scheduler.worker.AbstractWorker;
|
|
||||||
import io.nucleo.scheduler.worker.Worker;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not tested yet as not used...
|
|
||||||
*/
|
|
||||||
public class DependencyManagedScheduler extends AbstractScheduler
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(DependencyManagedScheduler.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
if (workerElements.size() > 0)
|
|
||||||
workerElements.stream().forEach(this::executeWorker);
|
|
||||||
else
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void executeWorker(Worker worker)
|
|
||||||
{
|
|
||||||
((AbstractWorker) worker).setModel(model);
|
|
||||||
if (((AbstractDependencyManagedTask) worker).areAllDependenciesAvailable())
|
|
||||||
{
|
|
||||||
worker.addResultHandlers(this);
|
|
||||||
worker.addFaultHandlers(this);
|
|
||||||
worker.execute();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResult(Worker worker)
|
|
||||||
{
|
|
||||||
Predicate<Worker> notCompleted = w -> !w.getHasCompleted();
|
|
||||||
if (workerElements.stream().filter(notCompleted).count() == 0)
|
|
||||||
complete();
|
|
||||||
else
|
|
||||||
execute();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package io.nucleo.scheduler;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.worker.Worker;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Not tested yet as not used...
|
|
||||||
*/
|
|
||||||
public class ParallelScheduler extends AbstractScheduler
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(ParallelScheduler.class);
|
|
||||||
private long numberOfChildrenCompleted;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
if (workerElements.size() > 0)
|
|
||||||
workerElements.stream().forEach(this::executeWorker);
|
|
||||||
else
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResult(Worker worker)
|
|
||||||
{
|
|
||||||
Predicate<Worker> notCompleted = w -> !w.getHasCompleted();
|
|
||||||
if (workerElements.stream().filter(notCompleted).count() == 0)
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package io.nucleo.scheduler;
|
|
||||||
|
|
||||||
import com.sun.istack.internal.NotNull;
|
|
||||||
import io.nucleo.scheduler.worker.Worker;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SequenceScheduler extends AbstractScheduler
|
|
||||||
{
|
|
||||||
private Iterator<Worker> workerIterator;
|
|
||||||
|
|
||||||
public SequenceScheduler(List<Worker> workerElements, Object model)
|
|
||||||
{
|
|
||||||
setWorkers(workerElements);
|
|
||||||
setModel(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SequenceScheduler()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWorkers(@NotNull List<Worker> workerElements)
|
|
||||||
{
|
|
||||||
workerIterator = new LinkedList<>(workerElements).iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
if (workerIterator != null && workerIterator.hasNext())
|
|
||||||
executeWorker(workerIterator.next());
|
|
||||||
else
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResult(Worker worker)
|
|
||||||
{
|
|
||||||
execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package io.nucleo.scheduler.example;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.model.PropertyProviderModel;
|
|
||||||
|
|
||||||
public class ExamplePropertyProviderModel extends PropertyProviderModel
|
|
||||||
{
|
|
||||||
public final Object flashVars;
|
|
||||||
public Object user;
|
|
||||||
|
|
||||||
public ExamplePropertyProviderModel(Object flashVars)
|
|
||||||
{
|
|
||||||
this.flashVars = flashVars;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package io.nucleo.scheduler.example;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.worker.Worker;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerFaultHandler;
|
|
||||||
import io.nucleo.scheduler.worker.WorkerResultHandler;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public class SchedulerTestRunner implements WorkerResultHandler, WorkerFaultHandler
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(SchedulerTestRunner.class);
|
|
||||||
private static SchedulerTestRunner schedulerTestRunner;
|
|
||||||
|
|
||||||
public SchedulerTestRunner()
|
|
||||||
{
|
|
||||||
/* Map<Object, Object> flashVars = new HashMap<>();
|
|
||||||
flashVars.put("userName", "bully");
|
|
||||||
|
|
||||||
Object model = new ExamplePropertyProviderModel(flashVars);
|
|
||||||
ExampleAS3Scheduler exampleScheduler = new ExampleAS3Scheduler();
|
|
||||||
|
|
||||||
exampleScheduler.setModel(model);
|
|
||||||
exampleScheduler.setResultHandler(() -> {
|
|
||||||
log.debug("setResultHandler ");
|
|
||||||
});
|
|
||||||
exampleScheduler.setFaultHandler((throwable) -> {
|
|
||||||
log.debug("setFaultHandler ");
|
|
||||||
});
|
|
||||||
exampleScheduler.execute(); */
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args)
|
|
||||||
{
|
|
||||||
schedulerTestRunner = new SchedulerTestRunner();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFault(Throwable throwable)
|
|
||||||
{
|
|
||||||
log.debug("onFault " + this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResult(Worker worker)
|
|
||||||
{
|
|
||||||
log.debug("onResult " + this);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
package io.nucleo.scheduler.model;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
public abstract class PropertyProviderModel
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PropertyProviderModel.class);
|
|
||||||
|
|
||||||
public PropertyProviderModel()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean areAllDependenciesAvailable(List<String> propertyNames)
|
|
||||||
{
|
|
||||||
Predicate<String> isPropertyNotNull = (propertyName) -> read(propertyName) != null;
|
|
||||||
return propertyNames.stream().allMatch(isPropertyNotNull);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object read(String key)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return getField(key).get(this);
|
|
||||||
} catch (IllegalAccessException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
// Private
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
private Field getField(String key)
|
|
||||||
{
|
|
||||||
Class clazz = this.getClass();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Field field = clazz.getDeclaredField(key);
|
|
||||||
field.setAccessible(true); // make sure a private field is accessible for reflection
|
|
||||||
return field;
|
|
||||||
} catch (Exception e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
package io.nucleo.scheduler.tasks;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.model.PropertyProviderModel;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base class for all tasks using a IPropertyProviderModel instance as a shared model.
|
|
||||||
*/
|
|
||||||
public abstract class AbstractDependencyManagedTask extends AbstractTask
|
|
||||||
{
|
|
||||||
private PropertyProviderModel propertyProviderModel;
|
|
||||||
private List<String> readDependencyKeys = new ArrayList<>();
|
|
||||||
|
|
||||||
public AbstractDependencyManagedTask()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
// IRunnable implementation
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setModel(Object model)
|
|
||||||
{
|
|
||||||
propertyProviderModel = (PropertyProviderModel) model;
|
|
||||||
|
|
||||||
super.setModel(model);
|
|
||||||
|
|
||||||
initReadDependencies();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
// Abstract Methods
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To be overwritten in subclasses
|
|
||||||
* Used to read the needed data objects for the task.
|
|
||||||
* Typically stored as instance variable in the task.
|
|
||||||
*/
|
|
||||||
protected void initReadDependencies()
|
|
||||||
{
|
|
||||||
// user = read(IUser);
|
|
||||||
// channel = read("channel");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
// Final protected
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
final protected Object read(String key)
|
|
||||||
{
|
|
||||||
readDependencyKeys.add(key);
|
|
||||||
|
|
||||||
return propertyProviderModel.read(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean areAllDependenciesAvailable()
|
|
||||||
{
|
|
||||||
return propertyProviderModel.areAllDependenciesAvailable(readDependencyKeys);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package io.nucleo.scheduler.tasks;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.worker.AbstractWorker;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base class for all tasks.
|
|
||||||
*/
|
|
||||||
public abstract class AbstractTask extends AbstractWorker
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AbstractTask.class);
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package io.nucleo.scheduler.worker;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class AbstractWorker implements Worker
|
|
||||||
{
|
|
||||||
protected List<WorkerResultHandler> resultHandlers = new ArrayList<>();
|
|
||||||
protected List<WorkerFaultHandler> faultHandlers = new ArrayList<>();
|
|
||||||
protected Object model;
|
|
||||||
protected boolean hasFailed;
|
|
||||||
protected boolean hasCompleted;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
abstract public void execute();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addResultHandlers(WorkerResultHandler resultHandler)
|
|
||||||
{
|
|
||||||
resultHandlers.add(resultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addFaultHandlers(WorkerFaultHandler faultHandler)
|
|
||||||
{
|
|
||||||
faultHandlers.add(faultHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setModel(Object model)
|
|
||||||
{
|
|
||||||
this.model = model;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getHasCompleted()
|
|
||||||
{
|
|
||||||
return hasCompleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void complete()
|
|
||||||
{
|
|
||||||
hasCompleted = true;
|
|
||||||
resultHandlers.stream().forEach(e -> e.onResult(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void failed(Throwable throwable)
|
|
||||||
{
|
|
||||||
hasFailed = true;
|
|
||||||
faultHandlers.stream().forEach(e -> e.onFault(throwable));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void destroy()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package io.nucleo.scheduler.worker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The base interface for all runnable objects (tasks, schedulers)
|
|
||||||
*/
|
|
||||||
public interface Worker
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Starts the execution.
|
|
||||||
*/
|
|
||||||
void execute();
|
|
||||||
|
|
||||||
void addResultHandlers(WorkerResultHandler resultHandler);
|
|
||||||
|
|
||||||
void addFaultHandlers(WorkerFaultHandler faultHandler);
|
|
||||||
|
|
||||||
boolean getHasCompleted();
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
package io.nucleo.scheduler.worker;
|
|
||||||
|
|
||||||
public interface WorkerFaultHandler
|
|
||||||
{
|
|
||||||
void onFault(Throwable throwable);
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
package io.nucleo.scheduler.worker;
|
|
||||||
|
|
||||||
public interface WorkerResultHandler
|
|
||||||
{
|
|
||||||
void onResult(Worker worker);
|
|
||||||
}
|
|
|
@ -3,7 +3,6 @@ package io.bitsquare;
|
||||||
import io.bitsquare.btc.BtcValidatorTest;
|
import io.bitsquare.btc.BtcValidatorTest;
|
||||||
import io.bitsquare.gui.util.BitSquareConverterTest;
|
import io.bitsquare.gui.util.BitSquareConverterTest;
|
||||||
import io.bitsquare.gui.util.BitSquareValidatorTest;
|
import io.bitsquare.gui.util.BitSquareValidatorTest;
|
||||||
import io.nucleo.scheduler.SequenceSchedulerTest;
|
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Suite;
|
import org.junit.runners.Suite;
|
||||||
|
|
||||||
|
@ -12,7 +11,6 @@ import org.junit.runners.Suite;
|
||||||
BtcValidatorTest.class,
|
BtcValidatorTest.class,
|
||||||
BitSquareConverterTest.class,
|
BitSquareConverterTest.class,
|
||||||
BitSquareValidatorTest.class,
|
BitSquareValidatorTest.class,
|
||||||
SequenceSchedulerTest.class
|
|
||||||
})
|
})
|
||||||
|
|
||||||
public class BitSquareTestSuite
|
public class BitSquareTestSuite
|
||||||
|
|
|
@ -1,228 +0,0 @@
|
||||||
package io.nucleo.scheduler;
|
|
||||||
|
|
||||||
import io.nucleo.scheduler.tasks.SyncWorker1;
|
|
||||||
import io.nucleo.scheduler.tasks.SyncWorker2;
|
|
||||||
import io.nucleo.scheduler.worker.Worker;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
public class SequenceSchedulerTest
|
|
||||||
{
|
|
||||||
private final boolean[] hasCompleted = new boolean[1];
|
|
||||||
private final boolean[] hasFailed = new boolean[1];
|
|
||||||
private final boolean[] worker1HasCompleted = new boolean[1];
|
|
||||||
private final boolean[] worker1HasFailed = new boolean[1];
|
|
||||||
private final boolean[] worker2HasCompleted = new boolean[1];
|
|
||||||
private final boolean[] worker2HasFailed = new boolean[1];
|
|
||||||
private SequenceScheduler sequenceScheduler;
|
|
||||||
private Map<String, String> model = new HashMap<>();
|
|
||||||
private List<Worker> workerList = new ArrayList<>();
|
|
||||||
private Throwable worker1Throwable;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp()
|
|
||||||
{
|
|
||||||
sequenceScheduler = new SequenceScheduler();
|
|
||||||
sequenceScheduler.addResultHandlers((worker) -> {
|
|
||||||
hasCompleted[0] = true;
|
|
||||||
});
|
|
||||||
sequenceScheduler.addFaultHandlers(throwable -> {
|
|
||||||
hasFailed[0] = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() throws Exception
|
|
||||||
{
|
|
||||||
hasCompleted[0] = false;
|
|
||||||
hasFailed[0] = false;
|
|
||||||
workerList.clear();
|
|
||||||
model.clear();
|
|
||||||
worker1Throwable = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEmpty()
|
|
||||||
{
|
|
||||||
sequenceScheduler.execute();
|
|
||||||
assertTrue(sequenceScheduler.getHasCompleted());
|
|
||||||
assertTrue(hasCompleted[0]);
|
|
||||||
assertFalse(hasFailed[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEmpty2()
|
|
||||||
{
|
|
||||||
sequenceScheduler.setWorkers(workerList);
|
|
||||||
sequenceScheduler.execute();
|
|
||||||
assertTrue(sequenceScheduler.getHasCompleted());
|
|
||||||
assertTrue(hasCompleted[0]);
|
|
||||||
assertFalse(hasFailed[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOneWithCompleted()
|
|
||||||
{
|
|
||||||
Worker worker1 = getWorker1(false);
|
|
||||||
workerList.add(worker1);
|
|
||||||
sequenceScheduler.setWorkers(workerList);
|
|
||||||
sequenceScheduler.execute();
|
|
||||||
|
|
||||||
assertTrue(sequenceScheduler.getHasCompleted());
|
|
||||||
assertTrue(hasCompleted[0]);
|
|
||||||
assertFalse(hasFailed[0]);
|
|
||||||
|
|
||||||
assertTrue(worker1.getHasCompleted());
|
|
||||||
assertTrue(worker1HasCompleted[0]);
|
|
||||||
assertFalse(worker1HasFailed[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOneWithFailed()
|
|
||||||
{
|
|
||||||
Worker worker1 = getWorker1(true);
|
|
||||||
workerList.add(worker1);
|
|
||||||
sequenceScheduler.setWorkers(workerList);
|
|
||||||
sequenceScheduler.execute();
|
|
||||||
|
|
||||||
assertFalse(sequenceScheduler.getHasCompleted());
|
|
||||||
assertFalse(hasCompleted[0]);
|
|
||||||
assertTrue(hasFailed[0]);
|
|
||||||
|
|
||||||
assertFalse(worker1.getHasCompleted());
|
|
||||||
assertFalse(worker1HasCompleted[0]);
|
|
||||||
assertTrue(worker1HasFailed[0]);
|
|
||||||
assertEquals(SyncWorker1.ERR_MSG, worker1Throwable.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Test
|
|
||||||
public void testTwoCompleted()
|
|
||||||
{
|
|
||||||
Worker worker1 = getWorker1(false);
|
|
||||||
Worker worker2 = getWorker2(false);
|
|
||||||
workerList.add(worker1);
|
|
||||||
workerList.add(worker2);
|
|
||||||
sequenceScheduler.setWorkers(workerList);
|
|
||||||
sequenceScheduler.execute();
|
|
||||||
|
|
||||||
assertTrue(sequenceScheduler.getHasCompleted());
|
|
||||||
assertTrue(hasCompleted[0]);
|
|
||||||
assertFalse(hasFailed[0]);
|
|
||||||
|
|
||||||
assertTrue(worker1.getHasCompleted());
|
|
||||||
assertTrue(worker1HasCompleted[0]);
|
|
||||||
assertFalse(worker1HasFailed[0]);
|
|
||||||
|
|
||||||
assertTrue(worker2.getHasCompleted());
|
|
||||||
assertTrue(worker2HasCompleted[0]);
|
|
||||||
assertFalse(worker2HasFailed[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTwoReverseOrder()
|
|
||||||
{
|
|
||||||
model.put("worker1State", "");
|
|
||||||
model.put("worker2State", "");
|
|
||||||
Worker worker1 = getWorker1(false);
|
|
||||||
Worker worker2 = getWorker2(false);
|
|
||||||
workerList.add(worker2);
|
|
||||||
workerList.add(worker1);
|
|
||||||
sequenceScheduler.setWorkers(workerList);
|
|
||||||
sequenceScheduler.setModel(model);
|
|
||||||
sequenceScheduler.execute();
|
|
||||||
|
|
||||||
assertEquals(SyncWorker1.STATE, model.get("worker1State"));
|
|
||||||
assertEquals(SyncWorker2.STATE, model.get("worker2State"));
|
|
||||||
|
|
||||||
assertTrue(sequenceScheduler.getHasCompleted());
|
|
||||||
assertTrue(hasCompleted[0]);
|
|
||||||
assertFalse(hasFailed[0]);
|
|
||||||
|
|
||||||
assertTrue(worker1.getHasCompleted());
|
|
||||||
assertTrue(worker1HasCompleted[0]);
|
|
||||||
assertFalse(worker1HasFailed[0]);
|
|
||||||
|
|
||||||
assertTrue(worker2.getHasCompleted());
|
|
||||||
assertTrue(worker2HasCompleted[0]);
|
|
||||||
assertFalse(worker2HasFailed[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTwoFirstFailed()
|
|
||||||
{
|
|
||||||
Worker worker1 = getWorker1(true);
|
|
||||||
Worker worker2 = getWorker2(false);
|
|
||||||
workerList.add(worker1);
|
|
||||||
workerList.add(worker2);
|
|
||||||
sequenceScheduler.setWorkers(workerList);
|
|
||||||
sequenceScheduler.execute();
|
|
||||||
|
|
||||||
assertFalse(sequenceScheduler.getHasCompleted());
|
|
||||||
assertFalse(hasCompleted[0]);
|
|
||||||
assertTrue(hasFailed[0]);
|
|
||||||
|
|
||||||
assertFalse(worker1.getHasCompleted());
|
|
||||||
assertFalse(worker1HasCompleted[0]);
|
|
||||||
assertTrue(worker1HasFailed[0]);
|
|
||||||
|
|
||||||
assertFalse(worker2.getHasCompleted());
|
|
||||||
assertFalse(worker2HasCompleted[0]);
|
|
||||||
assertFalse(worker2HasFailed[0]); // second has not been executed and is not failed!
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTwoSecondFailed()
|
|
||||||
{
|
|
||||||
Worker worker1 = getWorker1(false);
|
|
||||||
Worker worker2 = getWorker2(true);
|
|
||||||
workerList.add(worker1);
|
|
||||||
workerList.add(worker2);
|
|
||||||
sequenceScheduler.setWorkers(workerList);
|
|
||||||
sequenceScheduler.execute();
|
|
||||||
|
|
||||||
assertFalse(sequenceScheduler.getHasCompleted());
|
|
||||||
assertFalse(hasCompleted[0]);
|
|
||||||
assertTrue(hasFailed[0]);
|
|
||||||
|
|
||||||
assertTrue(worker1.getHasCompleted());
|
|
||||||
assertTrue(worker1HasCompleted[0]);
|
|
||||||
assertFalse(worker1HasFailed[0]);
|
|
||||||
|
|
||||||
assertFalse(worker2.getHasCompleted());
|
|
||||||
assertFalse(worker2HasCompleted[0]);
|
|
||||||
assertTrue(worker2HasFailed[0]); // second has not been executed and is not failed!
|
|
||||||
}
|
|
||||||
|
|
||||||
private Worker getWorker1(boolean letItFail)
|
|
||||||
{
|
|
||||||
Worker worker1 = new SyncWorker1(letItFail);
|
|
||||||
worker1.addResultHandlers((worker) -> {
|
|
||||||
worker1HasCompleted[0] = true;
|
|
||||||
});
|
|
||||||
worker1.addFaultHandlers(throwable -> {
|
|
||||||
worker1HasFailed[0] = true;
|
|
||||||
worker1Throwable = throwable;
|
|
||||||
});
|
|
||||||
return worker1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Worker getWorker2(boolean letItFail)
|
|
||||||
{
|
|
||||||
Worker worker2 = new SyncWorker2(letItFail);
|
|
||||||
worker2.addResultHandlers((worker) -> {
|
|
||||||
worker2HasCompleted[0] = true;
|
|
||||||
});
|
|
||||||
worker2.addFaultHandlers(throwable -> {
|
|
||||||
worker2HasFailed[0] = true;
|
|
||||||
});
|
|
||||||
return worker2;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package io.nucleo.scheduler.tasks;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class SyncWorker1 extends AbstractTask
|
|
||||||
{
|
|
||||||
|
|
||||||
public static String ERR_MSG = "Failure message";
|
|
||||||
public static String STATE = "ok";
|
|
||||||
private boolean letItFail;
|
|
||||||
|
|
||||||
public SyncWorker1(boolean letItFail)
|
|
||||||
{
|
|
||||||
|
|
||||||
this.letItFail = letItFail;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
System.out.println("execute " + this);
|
|
||||||
if (model != null) ((Map<String, String>) model).put("worker1State", STATE);
|
|
||||||
if (letItFail)
|
|
||||||
failed(new Exception(ERR_MSG));
|
|
||||||
else
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package io.nucleo.scheduler.tasks;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class SyncWorker2 extends AbstractTask
|
|
||||||
{
|
|
||||||
public static String ERR_MSG = "Failure message";
|
|
||||||
public static String STATE = "ok";
|
|
||||||
private boolean letItFail;
|
|
||||||
|
|
||||||
public SyncWorker2(boolean letItFail)
|
|
||||||
{
|
|
||||||
this.letItFail = letItFail;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void execute()
|
|
||||||
{
|
|
||||||
System.out.println("execute " + this);
|
|
||||||
if (model != null) ((Map<String, String>) model).put("worker2State", STATE);
|
|
||||||
if (letItFail)
|
|
||||||
failed(new Exception(ERR_MSG));
|
|
||||||
else
|
|
||||||
complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Add table
Add a link
Reference in a new issue