mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Use state for open offer
This commit is contained in:
parent
5768b93cdf
commit
f68030e488
@ -33,6 +33,7 @@ import org.bitcoinj.core.TransactionInput;
|
|||||||
import org.bitcoinj.core.TransactionOutPoint;
|
import org.bitcoinj.core.TransactionOutPoint;
|
||||||
import org.bitcoinj.core.TransactionOutput;
|
import org.bitcoinj.core.TransactionOutput;
|
||||||
import org.bitcoinj.core.Utils;
|
import org.bitcoinj.core.Utils;
|
||||||
|
import org.bitcoinj.core.VerificationException;
|
||||||
import org.bitcoinj.core.Wallet;
|
import org.bitcoinj.core.Wallet;
|
||||||
import org.bitcoinj.crypto.TransactionSignature;
|
import org.bitcoinj.crypto.TransactionSignature;
|
||||||
import org.bitcoinj.kits.WalletAppKit;
|
import org.bitcoinj.kits.WalletAppKit;
|
||||||
@ -375,23 +376,17 @@ public class TradeWalletService {
|
|||||||
Futures.addCallback(broadcastComplete, callback);
|
Futures.addCallback(broadcastComplete, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns local transaction which has a different state as the serialized depositTx we get from the offerer
|
// Returns local transaction which has a different state as the serialized publishedOffererDepositTx we get from the offerer
|
||||||
public Transaction takerCommitsDepositTx(Transaction depositTx) throws WalletException {
|
public Transaction takerCommitsDepositTx(Transaction publishedOffererDepositTx) throws VerificationException {
|
||||||
log.trace("takerCommitsDepositTx called");
|
log.trace("takerCommitsDepositTx called");
|
||||||
log.trace("depositTx " + depositTx.toString());
|
log.trace("publishedOffererDepositTx " + publishedOffererDepositTx.toString());
|
||||||
|
|
||||||
// We need to recreate the tx we get a null pointer otherwise
|
// We need to recreate the tx we get a null pointer otherwise
|
||||||
Transaction localDepositTx = new Transaction(params, depositTx.bitcoinSerialize());
|
Transaction depositTx = new Transaction(params, publishedOffererDepositTx.bitcoinSerialize());
|
||||||
|
log.trace("depositTx " + depositTx.toString());
|
||||||
|
|
||||||
try {
|
wallet.receivePending(depositTx, null, true);
|
||||||
// TODO check if that is correct
|
return depositTx;
|
||||||
wallet.receivePending(depositTx, null, true);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
log.error(t.getMessage());
|
|
||||||
t.printStackTrace();
|
|
||||||
throw new WalletException(t);
|
|
||||||
}
|
|
||||||
return localDepositTx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] offererCreatesAndSignsPayoutTx(Transaction depositTx,
|
public byte[] offererCreatesAndSignsPayoutTx(Transaction depositTx,
|
||||||
|
@ -112,7 +112,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||||||
sortList();
|
sortList();
|
||||||
|
|
||||||
// select either currentPendingTrade or first in the list
|
// select either currentPendingTrade or first in the list
|
||||||
if (tradeManager.getCurrentPendingTrade() != null) {
|
/*if (tradeManager.getCurrentPendingTrade() != null) {
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
PendingTradesListItem item = list.get(i);
|
PendingTradesListItem item = list.get(i);
|
||||||
if (tradeManager.getCurrentPendingTrade().getId().equals(item.getTrade().getId())) {
|
if (tradeManager.getCurrentPendingTrade().getId().equals(item.getTrade().getId())) {
|
||||||
@ -122,7 +122,8 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (list.size() > 0) {
|
else */
|
||||||
|
if (list.size() > 0) {
|
||||||
selectTrade(list.get(0));
|
selectTrade(list.get(0));
|
||||||
selectedIndex.set(0);
|
selectedIndex.set(0);
|
||||||
}
|
}
|
||||||
|
@ -113,8 +113,8 @@ class OfferBookDataModel implements Activatable, DataModel {
|
|||||||
btcCode.unbind();
|
btcCode.unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
void cancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
tradeManager.removeOpenOffer(offer, resultHandler, errorMessageHandler);
|
tradeManager.cancelOpenOffer(offer, resultHandler, errorMessageHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculateVolume() {
|
void calculateVolume() {
|
||||||
|
@ -471,7 +471,7 @@ public class OfferBookView extends ActivatableViewAndModel<GridPane, OfferBookVi
|
|||||||
if (model.isMyOffer(offer)) {
|
if (model.isMyOffer(offer)) {
|
||||||
iconView.setId("image-remove");
|
iconView.setId("image-remove");
|
||||||
title = "Remove";
|
title = "Remove";
|
||||||
button.setOnAction(event -> model.removeOpenOffer(item
|
button.setOnAction(event -> model.cancelOpenOffer(item
|
||||||
.getOffer()));
|
.getOffer()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -102,8 +102,8 @@ class OfferBookViewModel extends ActivatableWithDataModel<OfferBookDataModel> im
|
|||||||
(newValue)));
|
(newValue)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeOpenOffer(Offer offer) {
|
void cancelOpenOffer(Offer offer) {
|
||||||
dataModel.removeOpenOffer(offer,
|
dataModel.cancelOpenOffer(offer,
|
||||||
() -> {
|
() -> {
|
||||||
// visual feedback?
|
// visual feedback?
|
||||||
log.debug("Remove offer was successful");
|
log.debug("Remove offer was successful");
|
||||||
|
@ -46,7 +46,7 @@ public class Trade implements Serializable {
|
|||||||
COMPLETED,
|
COMPLETED,
|
||||||
FAILED
|
FAILED
|
||||||
}
|
}
|
||||||
|
|
||||||
public static enum ProcessState {
|
public static enum ProcessState {
|
||||||
INIT,
|
INIT,
|
||||||
TAKE_OFFER_FEE_PUBLISH_FAILED,
|
TAKE_OFFER_FEE_PUBLISH_FAILED,
|
||||||
@ -74,6 +74,8 @@ public class Trade implements Serializable {
|
|||||||
private final Offer offer;
|
private final Offer offer;
|
||||||
private final Date date;
|
private final Date date;
|
||||||
private ProcessState processState;
|
private ProcessState processState;
|
||||||
|
private LifeCycleState lifeCycleState;
|
||||||
|
|
||||||
private Coin tradeAmount;
|
private Coin tradeAmount;
|
||||||
private Contract contract;
|
private Contract contract;
|
||||||
private String contractAsJson;
|
private String contractAsJson;
|
||||||
@ -88,7 +90,8 @@ public class Trade implements Serializable {
|
|||||||
// access. Only use the accessor not the private field.
|
// access. Only use the accessor not the private field.
|
||||||
transient private ObjectProperty<Coin> _tradeAmount;
|
transient private ObjectProperty<Coin> _tradeAmount;
|
||||||
transient private ObjectProperty<Fiat> _tradeVolume;
|
transient private ObjectProperty<Fiat> _tradeVolume;
|
||||||
transient private ObjectProperty<ProcessState> _state;
|
transient private ObjectProperty<ProcessState> _processState;
|
||||||
|
transient private ObjectProperty<LifeCycleState> _lifeCycleState;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -154,6 +157,10 @@ public class Trade implements Serializable {
|
|||||||
processStateProperty().set(processState);
|
processStateProperty().set(processState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLifeCycleState(LifeCycleState lifeCycleState) {
|
||||||
|
this.lifeCycleState = lifeCycleState;
|
||||||
|
lifeCycleStateProperty().set(lifeCycleState);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Getters
|
// Getters
|
||||||
@ -183,6 +190,10 @@ public class Trade implements Serializable {
|
|||||||
return processState;
|
return processState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LifeCycleState getLifeCycleState() {
|
||||||
|
return lifeCycleState;
|
||||||
|
}
|
||||||
|
|
||||||
public Coin getSecurityDeposit() {
|
public Coin getSecurityDeposit() {
|
||||||
return offer.getSecurityDeposit();
|
return offer.getSecurityDeposit();
|
||||||
}
|
}
|
||||||
@ -224,10 +235,17 @@ public class Trade implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ObjectProperty<ProcessState> processStateProperty() {
|
public ObjectProperty<ProcessState> processStateProperty() {
|
||||||
if (_state == null)
|
if (_processState == null)
|
||||||
_state = new SimpleObjectProperty<>(processState);
|
_processState = new SimpleObjectProperty<>(processState);
|
||||||
|
|
||||||
return _state;
|
return _processState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectProperty<LifeCycleState> lifeCycleStateProperty() {
|
||||||
|
if (_lifeCycleState == null)
|
||||||
|
_lifeCycleState = new SimpleObjectProperty<>(lifeCycleState);
|
||||||
|
|
||||||
|
return _lifeCycleState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,17 +31,13 @@ import io.bitsquare.p2p.AddressService;
|
|||||||
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
||||||
import io.bitsquare.p2p.MailboxMessage;
|
import io.bitsquare.p2p.MailboxMessage;
|
||||||
import io.bitsquare.p2p.MailboxService;
|
import io.bitsquare.p2p.MailboxService;
|
||||||
import io.bitsquare.p2p.Message;
|
|
||||||
import io.bitsquare.p2p.MessageService;
|
import io.bitsquare.p2p.MessageService;
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
|
||||||
import io.bitsquare.persistence.Persistence;
|
import io.bitsquare.persistence.Persistence;
|
||||||
import io.bitsquare.trade.handlers.TradeResultHandler;
|
import io.bitsquare.trade.handlers.TradeResultHandler;
|
||||||
import io.bitsquare.trade.handlers.TransactionResultHandler;
|
import io.bitsquare.trade.handlers.TransactionResultHandler;
|
||||||
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
|
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityModel;
|
||||||
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityProtocol;
|
import io.bitsquare.trade.protocol.availability.CheckOfferAvailabilityProtocol;
|
||||||
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
|
|
||||||
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
|
|
||||||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
|
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
|
||||||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
|
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
@ -69,8 +65,6 @@ import javafx.collections.ObservableMap;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
public class TradeManager {
|
public class TradeManager {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TradeManager.class);
|
private static final Logger log = LoggerFactory.getLogger(TradeManager.class);
|
||||||
|
|
||||||
@ -90,12 +84,9 @@ public class TradeManager {
|
|||||||
private final Map<String, OffererAsBuyerProtocol> offererAsBuyerProtocolMap = new HashMap<>();
|
private final Map<String, OffererAsBuyerProtocol> offererAsBuyerProtocolMap = new HashMap<>();
|
||||||
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
|
private final Map<String, CheckOfferAvailabilityProtocol> checkOfferAvailabilityProtocolMap = new HashMap<>();
|
||||||
|
|
||||||
private final ObservableMap<String, Trade> openOfferTrades = FXCollections.observableHashMap();
|
private final Map<String, Trade> trades = new HashMap<>();
|
||||||
private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap();
|
|
||||||
private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap();
|
|
||||||
private final Map<String, MailboxMessage> mailboxMessages = new HashMap<>();
|
|
||||||
|
|
||||||
private Trade currentPendingTrade;
|
private final Map<String, MailboxMessage> mailboxMessages = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -119,19 +110,9 @@ public class TradeManager {
|
|||||||
this.encryptionService = encryptionService;
|
this.encryptionService = encryptionService;
|
||||||
this.offerBookService = offerBookService;
|
this.offerBookService = offerBookService;
|
||||||
|
|
||||||
Serializable openOfferTradesObject = persistence.read(this, "openOfferTrades");
|
Serializable tradesObject = persistence.read(this, "trades");
|
||||||
if (openOfferTradesObject instanceof Map<?, ?>) {
|
if (tradesObject instanceof Map<?, ?>) {
|
||||||
openOfferTrades.putAll((Map<String, Trade>) openOfferTradesObject);
|
trades.putAll((Map<String, Trade>) tradesObject);
|
||||||
}
|
|
||||||
|
|
||||||
Serializable pendingTradesObject = persistence.read(this, "pendingTrades");
|
|
||||||
if (pendingTradesObject instanceof Map<?, ?>) {
|
|
||||||
pendingTrades.putAll((Map<String, Trade>) pendingTradesObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
Serializable closedTradesObject = persistence.read(this, "closedTrades");
|
|
||||||
if (closedTradesObject instanceof Map<?, ?>) {
|
|
||||||
closedTrades.putAll((Map<String, Trade>) closedTradesObject);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,10 +124,7 @@ public class TradeManager {
|
|||||||
// When all services are initialized we create the protocols for our open offers and persisted not completed pendingTrades
|
// When all services are initialized we create the protocols for our open offers and persisted not completed pendingTrades
|
||||||
// BuyerAcceptsOfferProtocol listens for take offer requests, so we need to instantiate it early.
|
// BuyerAcceptsOfferProtocol listens for take offer requests, so we need to instantiate it early.
|
||||||
public void onAllServicesInitialized() {
|
public void onAllServicesInitialized() {
|
||||||
for (Map.Entry<String, Trade> entry : openOfferTrades.entrySet()) {
|
for (Map.Entry<String, Trade> entry : trades.entrySet()) {
|
||||||
createOffererAsBuyerProtocol(entry.getValue());
|
|
||||||
}
|
|
||||||
for (Map.Entry<String, Trade> entry : pendingTrades.entrySet()) {
|
|
||||||
// We continue an interrupted trade.
|
// We continue an interrupted trade.
|
||||||
// TODO if the peer has changed its IP address, we need to make another findPeer request. At the moment we use the peer stored in trade to
|
// TODO if the peer has changed its IP address, we need to make another findPeer request. At the moment we use the peer stored in trade to
|
||||||
// continue the trade, but that might fail.
|
// continue the trade, but that might fail.
|
||||||
@ -164,8 +142,6 @@ public class TradeManager {
|
|||||||
decryptMailboxMessages(encryptedMailboxMessages);
|
decryptMailboxMessages(encryptedMailboxMessages);
|
||||||
emptyMailbox();
|
emptyMailbox();
|
||||||
});
|
});
|
||||||
|
|
||||||
messageService.addMessageHandler(this::handleMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMyOffer(Offer offer) {
|
public boolean isMyOffer(Offer offer) {
|
||||||
@ -206,9 +182,8 @@ public class TradeManager {
|
|||||||
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
|
PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(
|
||||||
model,
|
model,
|
||||||
(transaction) -> {
|
(transaction) -> {
|
||||||
Trade trade = new Trade(offer);
|
Trade trade = createTrade(offer);
|
||||||
openOfferTrades.put(trade.getId(), trade);
|
trade.setLifeCycleState(Trade.LifeCycleState.OPEN_OFFER);
|
||||||
persistOpenOffers();
|
|
||||||
createOffererAsBuyerProtocol(trade);
|
createOffererAsBuyerProtocol(trade);
|
||||||
resultHandler.handleResult(transaction);
|
resultHandler.handleResult(transaction);
|
||||||
},
|
},
|
||||||
@ -218,6 +193,11 @@ public class TradeManager {
|
|||||||
placeOfferProtocol.placeOffer();
|
placeOfferProtocol.placeOffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void cancelOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
|
trades.get(offer.getId()).setLifeCycleState(Trade.LifeCycleState.CANCELED);
|
||||||
|
removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
|
||||||
|
}
|
||||||
|
|
||||||
public void removeOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
public void removeOpenOffer(Offer offer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
|
||||||
removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
|
removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
|
||||||
}
|
}
|
||||||
@ -274,7 +254,7 @@ public class TradeManager {
|
|||||||
// TODO remove if check when persistence is impl.
|
// TODO remove if check when persistence is impl.
|
||||||
if (offererAsBuyerProtocolMap.containsKey(tradeId)) {
|
if (offererAsBuyerProtocolMap.containsKey(tradeId)) {
|
||||||
offererAsBuyerProtocolMap.get(tradeId).onFiatPaymentStarted();
|
offererAsBuyerProtocolMap.get(tradeId).onFiatPaymentStarted();
|
||||||
persistPendingTrades();
|
persistTrades();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +263,8 @@ public class TradeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onWithdrawAtTradeCompleted(Trade trade) {
|
public void onWithdrawAtTradeCompleted(Trade trade) {
|
||||||
closeTrade(trade);
|
trade.setLifeCycleState(Trade.LifeCycleState.COMPLETED);
|
||||||
|
removeFromProtocolMap(trade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -296,51 +277,27 @@ public class TradeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Message handler
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Offerer handles those requests
|
|
||||||
private void handleMessage(Message message, Peer sender) {
|
|
||||||
if (message instanceof RequestIsOfferAvailableMessage) {
|
|
||||||
String offerId = ((RequestIsOfferAvailableMessage) message).offerId;
|
|
||||||
checkNotNull(offerId);
|
|
||||||
|
|
||||||
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offerId, isOfferOpen(offerId));
|
|
||||||
messageService.sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
|
|
||||||
@Override
|
|
||||||
public void handleResult() {
|
|
||||||
// Offerer does not do anything at that moment. Peer might only watch the offer and does nto start a trade.
|
|
||||||
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleFault() {
|
|
||||||
log.warn("Sending ReportOfferAvailabilityMessage failed.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Getters
|
// Getters
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public ObservableMap<String, Trade> getOpenOfferTrades() {
|
public ObservableMap<String, Trade> getOpenOfferTrades() {
|
||||||
return openOfferTrades;
|
ObservableMap<String, Trade> list = FXCollections.observableHashMap();
|
||||||
|
list.putAll(trades);
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableMap<String, Trade> getPendingTrades() {
|
public ObservableMap<String, Trade> getPendingTrades() {
|
||||||
return pendingTrades;
|
ObservableMap<String, Trade> list = FXCollections.observableHashMap();
|
||||||
|
list.putAll(trades);
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableMap<String, Trade> getClosedTrades() {
|
public ObservableMap<String, Trade> getClosedTrades() {
|
||||||
return closedTrades;
|
ObservableMap<String, Trade> list = FXCollections.observableHashMap();
|
||||||
}
|
list.putAll(trades);
|
||||||
|
return list;
|
||||||
public Trade getCurrentPendingTrade() {
|
|
||||||
return currentPendingTrade;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -359,21 +316,17 @@ public class TradeManager {
|
|||||||
String offerId = offer.getId();
|
String offerId = offer.getId();
|
||||||
offerBookService.removeOffer(offer,
|
offerBookService.removeOffer(offer,
|
||||||
() -> {
|
() -> {
|
||||||
if (openOfferTrades.containsKey(offerId)) {
|
offer.setState(Offer.State.REMOVED);
|
||||||
openOfferTrades.remove(offerId);
|
trades.remove(offerId);
|
||||||
disposeCheckOfferAvailabilityRequest(offer);
|
|
||||||
persistOpenOffers();
|
|
||||||
if (removeFromBuyerAcceptsOfferProtocolMap && offererAsBuyerProtocolMap.containsKey(offerId)) {
|
|
||||||
offererAsBuyerProtocolMap.get(offerId).cleanup();
|
|
||||||
offererAsBuyerProtocolMap.remove(offerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
resultHandler.handleResult();
|
disposeCheckOfferAvailabilityRequest(offer);
|
||||||
}
|
persistTrades();
|
||||||
else {
|
if (removeFromBuyerAcceptsOfferProtocolMap && offererAsBuyerProtocolMap.containsKey(offerId)) {
|
||||||
log.error("Locally stored offers does not contain the offer with the ID " + offerId);
|
offererAsBuyerProtocolMap.get(offerId).cleanup();
|
||||||
errorMessageHandler.handleErrorMessage("Locally stored offers does not contain the offer with the ID " + offerId);
|
offererAsBuyerProtocolMap.remove(offerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resultHandler.handleResult();
|
||||||
},
|
},
|
||||||
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
|
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
|
||||||
}
|
}
|
||||||
@ -408,15 +361,9 @@ public class TradeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Trade createTrade(Offer offer) {
|
private Trade createTrade(Offer offer) {
|
||||||
if (pendingTrades.containsKey(offer.getId()))
|
|
||||||
log.error("That must never happen: Trades contains already an trade with the ID " + offer.getId());
|
|
||||||
|
|
||||||
Trade trade = new Trade(offer);
|
Trade trade = new Trade(offer);
|
||||||
pendingTrades.put(offer.getId(), trade);
|
trades.put(trade.getId(), trade);
|
||||||
persistPendingTrades();
|
persistTrades();
|
||||||
|
|
||||||
currentPendingTrade = trade;
|
|
||||||
|
|
||||||
return trade;
|
return trade;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,11 +379,12 @@ public class TradeManager {
|
|||||||
case FIAT_PAYMENT_STARTED:
|
case FIAT_PAYMENT_STARTED:
|
||||||
case FIAT_PAYMENT_RECEIVED:
|
case FIAT_PAYMENT_RECEIVED:
|
||||||
case PAYOUT_PUBLISHED:
|
case PAYOUT_PUBLISHED:
|
||||||
persistPendingTrades();
|
persistTrades();
|
||||||
break;
|
break;
|
||||||
case MESSAGE_SENDING_FAILED:
|
case MESSAGE_SENDING_FAILED:
|
||||||
case FAULT:
|
case FAULT:
|
||||||
closeTrade(trade);
|
trade.setLifeCycleState(Trade.LifeCycleState.FAILED);
|
||||||
|
removeFromProtocolMap(trade);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.warn("Unhandled trade state: " + newValue);
|
log.warn("Unhandled trade state: " + newValue);
|
||||||
@ -484,30 +432,25 @@ public class TradeManager {
|
|||||||
case INIT:
|
case INIT:
|
||||||
break;
|
break;
|
||||||
case TAKE_OFFER_FEE_TX_CREATED:
|
case TAKE_OFFER_FEE_TX_CREATED:
|
||||||
persistPendingTrades();
|
persistTrades();
|
||||||
break;
|
break;
|
||||||
case DEPOSIT_PUBLISHED:
|
case DEPOSIT_PUBLISHED:
|
||||||
removeOpenOffer(trade.getOffer(),
|
removeOpenOffer(trade.getOffer(),
|
||||||
() -> log.debug("remove offer was successful"),
|
() -> log.debug("remove offer was successful"),
|
||||||
(message) -> log.error(message),
|
(message) -> log.error(message),
|
||||||
false);
|
false);
|
||||||
|
|
||||||
// after we have published the deposit tx we add that trade to the pendingTrades
|
|
||||||
if (pendingTrades.containsKey(trade.getId()))
|
|
||||||
log.error("That must never happen: Trades contains already an trade with the ID " + trade.getId());
|
|
||||||
pendingTrades.put(trade.getId(), trade);
|
|
||||||
persistPendingTrades();
|
|
||||||
break;
|
break;
|
||||||
case DEPOSIT_CONFIRMED:
|
case DEPOSIT_CONFIRMED:
|
||||||
case FIAT_PAYMENT_STARTED:
|
case FIAT_PAYMENT_STARTED:
|
||||||
case FIAT_PAYMENT_RECEIVED:
|
case FIAT_PAYMENT_RECEIVED:
|
||||||
case PAYOUT_PUBLISHED:
|
case PAYOUT_PUBLISHED:
|
||||||
persistPendingTrades();
|
persistTrades();
|
||||||
break;
|
break;
|
||||||
case TAKE_OFFER_FEE_PUBLISH_FAILED:
|
case TAKE_OFFER_FEE_PUBLISH_FAILED:
|
||||||
case MESSAGE_SENDING_FAILED:
|
case MESSAGE_SENDING_FAILED:
|
||||||
case FAULT:
|
case FAULT:
|
||||||
closeTrade(trade);
|
trade.setLifeCycleState(Trade.LifeCycleState.FAILED);
|
||||||
|
removeFromProtocolMap(trade);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.warn("Unhandled trade state: " + newValue);
|
log.warn("Unhandled trade state: " + newValue);
|
||||||
@ -523,12 +466,7 @@ public class TradeManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeTrade(Trade trade) {
|
private void removeFromProtocolMap(Trade trade) {
|
||||||
if (pendingTrades.containsKey(trade.getId())) {
|
|
||||||
pendingTrades.remove(trade.getId());
|
|
||||||
persistPendingTrades();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (takerAsSellerProtocolMap.containsKey(trade.getId())) {
|
if (takerAsSellerProtocolMap.containsKey(trade.getId())) {
|
||||||
takerAsSellerProtocolMap.get(trade.getId()).cleanup();
|
takerAsSellerProtocolMap.get(trade.getId()).cleanup();
|
||||||
takerAsSellerProtocolMap.remove(trade.getId());
|
takerAsSellerProtocolMap.remove(trade.getId());
|
||||||
@ -537,11 +475,6 @@ public class TradeManager {
|
|||||||
offererAsBuyerProtocolMap.get(trade.getId()).cleanup();
|
offererAsBuyerProtocolMap.get(trade.getId()).cleanup();
|
||||||
offererAsBuyerProtocolMap.remove(trade.getId());
|
offererAsBuyerProtocolMap.remove(trade.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!closedTrades.containsKey(trade.getId())) {
|
|
||||||
closedTrades.put(trade.getId(), trade);
|
|
||||||
persistClosedTrades();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -587,21 +520,8 @@ public class TradeManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isOfferOpen(String offerId) {
|
private void persistTrades() {
|
||||||
return openOfferTrades.containsKey(offerId)
|
persistence.write(this, "trades", (Map<String, Trade>) new HashMap<>(trades));
|
||||||
&& (openOfferTrades.get(offerId).getOffer().getState() == Offer.State.UNKNOWN
|
|
||||||
|| openOfferTrades.get(offerId).getOffer().getState() == Offer.State.AVAILABLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void persistOpenOffers() {
|
|
||||||
persistence.write(this, "openOfferTrades", (Map<String, Trade>) new HashMap<>(openOfferTrades));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void persistPendingTrades() {
|
|
||||||
persistence.write(this, "pendingTrades", (Map<String, Trade>) new HashMap<>(pendingTrades));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void persistClosedTrades() {
|
|
||||||
persistence.write(this, "closedTrades", (Map<String, Trade>) new HashMap<>(closedTrades));
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -17,15 +17,15 @@
|
|||||||
|
|
||||||
package io.bitsquare.trade.protocol.availability.messages;
|
package io.bitsquare.trade.protocol.availability.messages;
|
||||||
|
|
||||||
import io.bitsquare.trade.protocol.trade.messages.OfferMessage;
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class RequestIsOfferAvailableMessage extends OfferMessage implements Serializable {
|
public class RequestIsOfferAvailableMessage extends TradeMessage implements Serializable {
|
||||||
private static final long serialVersionUID = 4630151440192191798L;
|
private static final long serialVersionUID = 4630151440192191798L;
|
||||||
|
|
||||||
public RequestIsOfferAvailableMessage(String offerId) {
|
public RequestIsOfferAvailableMessage(String tradeId) {
|
||||||
super.offerId = offerId;
|
super.tradeId = tradeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,6 +22,10 @@ import io.bitsquare.p2p.MailboxMessage;
|
|||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.MessageHandler;
|
import io.bitsquare.p2p.MessageHandler;
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
|
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||||
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailabilityMessage;
|
||||||
|
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
|
import io.bitsquare.trade.protocol.trade.messages.PayoutTxPublishedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage;
|
import io.bitsquare.trade.protocol.trade.messages.RequestDepositTxInputsMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.RequestOffererPublishDepositTxMessage;
|
import io.bitsquare.trade.protocol.trade.messages.RequestOffererPublishDepositTxMessage;
|
||||||
@ -96,13 +100,42 @@ public class OffererAsBuyerProtocol {
|
|||||||
// Incoming message handling
|
// Incoming message handling
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// OpenOffer requests
|
||||||
|
private void handleRequestIsOfferAvailableMessage(RequestIsOfferAvailableMessage tradeMessage, Peer sender) {
|
||||||
|
try {
|
||||||
|
checkTradeId(model.id, tradeMessage);
|
||||||
|
|
||||||
|
// We don't store anything in the model as we might be in a trade process and receive that request from another peer who wants to take the offer
|
||||||
|
// at the same time
|
||||||
|
boolean isOfferOpen = model.trade.getLifeCycleState() == Trade.LifeCycleState.OPEN_OFFER;
|
||||||
|
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(model.id, isOfferOpen);
|
||||||
|
model.messageService.sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
|
||||||
|
@Override
|
||||||
|
public void handleResult() {
|
||||||
|
// Offerer does not do anything at that moment. Peer might only watch the offer and does not start a trade.
|
||||||
|
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleFault() {
|
||||||
|
log.warn("Sending ReportOfferAvailabilityMessage failed.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// We don't handle the error as we might be in a trade process with another trader
|
||||||
|
t.printStackTrace();
|
||||||
|
log.warn("Exception at handleRequestIsOfferAvailableMessage " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trade started
|
||||||
private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage, Peer taker) {
|
private void handleRequestDepositTxInputsMessage(RequestDepositTxInputsMessage tradeMessage, Peer taker) {
|
||||||
checkTradeId(model.id, tradeMessage);
|
checkTradeId(model.id, tradeMessage);
|
||||||
model.setTradeMessage(tradeMessage);
|
model.setTradeMessage(tradeMessage);
|
||||||
model.trade.setTradingPeer(taker);
|
model.trade.setTradingPeer(taker);
|
||||||
|
|
||||||
TaskRunner<OffererAsBuyerModel> taskRunner = new TaskRunner<>(model,
|
TaskRunner<OffererAsBuyerModel> taskRunner = new TaskRunner<>(model,
|
||||||
() -> log.debug("sequence at handleTakeOfferFeePayedMessage completed"),
|
() -> log.debug("taskRunner at handleTakeOfferFeePayedMessage completed"),
|
||||||
(errorMessage) -> handleTaskRunnerFault(errorMessage));
|
(errorMessage) -> handleTaskRunnerFault(errorMessage));
|
||||||
taskRunner.addTasks(
|
taskRunner.addTasks(
|
||||||
ProcessRequestDepositTxInputsMessage.class,
|
ProcessRequestDepositTxInputsMessage.class,
|
||||||
@ -137,7 +170,7 @@ public class OffererAsBuyerProtocol {
|
|||||||
// User clicked the "bank transfer started" button
|
// User clicked the "bank transfer started" button
|
||||||
public void onFiatPaymentStarted() {
|
public void onFiatPaymentStarted() {
|
||||||
TaskRunner<OffererAsBuyerModel> taskRunner = new TaskRunner<>(model,
|
TaskRunner<OffererAsBuyerModel> taskRunner = new TaskRunner<>(model,
|
||||||
() -> log.debug("sequence at handleBankTransferStartedUIEvent completed"),
|
() -> log.debug("taskRunner at handleBankTransferStartedUIEvent completed"),
|
||||||
(errorMessage) -> handleTaskRunnerFault(errorMessage));
|
(errorMessage) -> handleTaskRunnerFault(errorMessage));
|
||||||
taskRunner.addTasks(
|
taskRunner.addTasks(
|
||||||
CreateAndSignPayoutTx.class,
|
CreateAndSignPayoutTx.class,
|
||||||
@ -157,7 +190,7 @@ public class OffererAsBuyerProtocol {
|
|||||||
|
|
||||||
TaskRunner<OffererAsBuyerModel> taskRunner = new TaskRunner<>(model,
|
TaskRunner<OffererAsBuyerModel> taskRunner = new TaskRunner<>(model,
|
||||||
() -> {
|
() -> {
|
||||||
log.debug("sequence at handlePayoutTxPublishedMessage completed");
|
log.debug("taskRunner at handlePayoutTxPublishedMessage completed");
|
||||||
// we are done!
|
// we are done!
|
||||||
model.onComplete();
|
model.onComplete();
|
||||||
},
|
},
|
||||||
@ -179,10 +212,12 @@ public class OffererAsBuyerProtocol {
|
|||||||
nonEmptyStringOf(tradeMessage.tradeId);
|
nonEmptyStringOf(tradeMessage.tradeId);
|
||||||
|
|
||||||
if (tradeMessage.tradeId.equals(model.id)) {
|
if (tradeMessage.tradeId.equals(model.id)) {
|
||||||
if (tradeMessage instanceof RequestDepositTxInputsMessage) {
|
if (tradeMessage instanceof RequestIsOfferAvailableMessage) {
|
||||||
|
handleRequestIsOfferAvailableMessage((RequestIsOfferAvailableMessage) tradeMessage, sender);
|
||||||
|
}
|
||||||
|
else if (tradeMessage instanceof RequestDepositTxInputsMessage) {
|
||||||
handleRequestDepositTxInputsMessage((RequestDepositTxInputsMessage) tradeMessage, sender);
|
handleRequestDepositTxInputsMessage((RequestDepositTxInputsMessage) tradeMessage, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) {
|
else if (tradeMessage instanceof RequestOffererPublishDepositTxMessage) {
|
||||||
handleRequestOffererPublishDepositTxMessage((RequestOffererPublishDepositTxMessage) tradeMessage);
|
handleRequestOffererPublishDepositTxMessage((RequestOffererPublishDepositTxMessage) tradeMessage);
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import io.bitsquare.common.taskrunner.TaskRunner;
|
|||||||
import io.bitsquare.trade.protocol.trade.taker.models.TakerAsSellerModel;
|
import io.bitsquare.trade.protocol.trade.taker.models.TakerAsSellerModel;
|
||||||
|
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
|
import org.bitcoinj.core.VerificationException;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -36,12 +37,13 @@ public class TakerCommitDepositTx extends Task<TakerAsSellerModel> {
|
|||||||
@Override
|
@Override
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
try {
|
try {
|
||||||
// We need to put the tx into our wallet to have a fully setup tx
|
// To access tx confidence we need to add that tx into our wallet.
|
||||||
Transaction localDepositTx = model.tradeWalletService.takerCommitsDepositTx(model.trade.getDepositTx());
|
Transaction depositTx = model.tradeWalletService.takerCommitsDepositTx(model.trade.getDepositTx());
|
||||||
model.trade.setDepositTx(localDepositTx);
|
|
||||||
|
model.trade.setDepositTx(depositTx);
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (VerificationException t) {
|
||||||
failed(t);
|
failed(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user