Merge branch 'offerlist' into DAO

# Conflicts:
#	core/src/main/java/io/bisq/core/trade/TradableList.java
#	core/src/main/java/io/bisq/core/trade/protocol/ProcessModel.java
#	core/src/test/java/io/bisq/core/util/ProtoBufferUtilitiesTest.java
This commit is contained in:
Manfred Karrer 2017-05-14 14:48:20 +02:00
commit f7ef638b1c
39 changed files with 930 additions and 660 deletions

View file

@ -3,9 +3,17 @@
<component name="ProjectCodeStyleSettingsManager"> <component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS"> <option name="PER_PROJECT_SETTINGS">
<value> <value>
<JavaCodeStyleSettings>
<option name="DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION" value="true" />
</JavaCodeStyleSettings>
<XML> <XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" /> <option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML> </XML>
<codeStyleSettings language="JAVA">
<option name="METHOD_ANNOTATION_WRAP" value="0" />
<option name="CLASS_ANNOTATION_WRAP" value="0" />
<option name="FIELD_ANNOTATION_WRAP" value="0" />
</codeStyleSettings>
</value> </value>
</option> </option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" /> <option name="USE_PER_PROJECT_SETTINGS" value="true" />

View file

@ -38,8 +38,7 @@ public class KeyRing {
// We generate by default a PGP keypair but the user can set his own if he prefers. // We generate by default a PGP keypair but the user can set his own if he prefers.
// Not impl. yet but prepared in data structure // Not impl. yet but prepared in data structure
@Setter @Nullable @Setter
@Nullable
// TODO remove Nullable once impl. // TODO remove Nullable once impl.
private PGPKeyPair pgpKeyPair; private PGPKeyPair pgpKeyPair;

View file

@ -190,13 +190,13 @@ public class FileManager<T extends PersistableEnvelope> {
PrintWriter printWriter = null; PrintWriter printWriter = null;
log.error("persistable.class " + persistable.getClass().getSimpleName()); log.error("persistable.class " + persistable.getClass().getSimpleName());
// log.error("persistable " + persistable); log.error("persistable " + persistable);
PB.PersistableEnvelope protoPersistable = null; PB.PersistableEnvelope protoPersistable = null;
try { try {
protoPersistable = (PB.PersistableEnvelope) persistable.toProtoMessage(); protoPersistable = (PB.PersistableEnvelope) persistable.toProtoMessage();
//log.error("protoPersistable " + protoPersistable); log.error("protoPersistable " + protoPersistable);
} catch (Throwable e) { } catch (Throwable e) {
log.debug("Not protobufferable: {}, {}, {}", persistable.getClass().getSimpleName(), storageFile, e.getStackTrace()); log.error("Not protobufferable: {}, {}, {}", persistable.getClass().getSimpleName(), storageFile, e.getStackTrace());
} }
try { try {

View file

@ -491,8 +491,9 @@ message MailboxStoragePayload {
message OfferPayload { message OfferPayload {
enum Direction { enum Direction {
BUY = 0; PB_ERROR = 0;
SELL = 1; BUY = 1;
SELL = 2;
} }
Direction direction = 1; Direction direction = 1;
@ -574,19 +575,20 @@ message Attachment {
message DisputeResult { message DisputeResult {
enum Winner { enum Winner {
BUYER = 0; PB_ERROR_WINNER = 0;
SELLER = 1; BUYER = 1;
SELLER = 2;
} }
// only append new values as we use the ordinal value
enum Reason { enum Reason {
OTHER = 0; PB_ERROR_REASON = 0;
BUG = 1; OTHER = 1;
USABILITY = 2; BUG = 2;
SCAM = 3; USABILITY = 3;
PROTOCOL_VIOLATION = 4; SCAM = 4;
NO_REPLY = 5; PROTOCOL_VIOLATION = 5;
BANK_PROBLEMS = 6; NO_REPLY = 6;
BANK_PROBLEMS = 7;
} }
string trade_id = 1; string trade_id = 1;
@ -641,14 +643,15 @@ message RawTransactionInput {
} }
enum AvailabilityResult { enum AvailabilityResult {
UNKNOWN_FAILURE = 0; // 0 is the default value when something goes wrong, map it to failure PB_ERROR = 0;
AVAILABLE = 1; UNKNOWN_FAILURE = 1;
OFFER_TAKEN = 2; AVAILABLE = 2;
PRICE_OUT_OF_TOLERANCE = 3; OFFER_TAKEN = 3;
MARKET_PRICE_NOT_AVAILABLE = 4; PRICE_OUT_OF_TOLERANCE = 4;
NO_ARBITRATORS = 5; MARKET_PRICE_NOT_AVAILABLE = 5;
NO_MEDIATORS = 6; NO_ARBITRATORS = 6;
USER_IGNORED = 7; NO_MEDIATORS = 7;
USER_IGNORED = 8;
} }
@ -808,13 +811,17 @@ message PersistableEnvelope {
PersistedEntryMap persisted_entry_map = 8; PersistedEntryMap persisted_entry_map = 8;
TradeStatisticsList trade_statistics_list = 9; TradeStatisticsList trade_statistics_list = 9;
VoteItemsList vote_items_list = 10; VoteItemsList vote_items_list = 10;
OpenOfferList open_offer_list = 11; TradableList tradable_list = 11;
TradeList trade_list = 16;
OpenOfferList open_offer_list = 17;
//TODO
PendingTradeList pending_trade_list = 12; PendingTradeList pending_trade_list = 12;
ClosedTradeList closed_trade_list = 13; ClosedTradeList closed_trade_list = 13;
FailedTradeList failed_trade_list = 14; FailedTradeList failed_trade_list = 14;
BsqChainState bsq_chain_state = 15; BsqChainState bsq_chain_state = 15;
// TODO remove
TradableList tradable_list = 16;
} }
} }
@ -886,12 +893,13 @@ message UserPayload {
message AddressEntry { message AddressEntry {
enum Context { enum Context {
ARBITRATOR = 0; PB_ERROR = 0;
AVAILABLE = 1; ARBITRATOR = 1;
OFFER_FUNDING = 2; AVAILABLE = 2;
RESERVED_FOR_TRADE = 3; OFFER_FUNDING = 3;
MULTI_SIG = 4; RESERVED_FOR_TRADE = 4;
TRADE_PAYOUT = 5; MULTI_SIG = 5;
TRADE_PAYOUT = 6;
} }
string offer_id = 7; string offer_id = 7;
@ -912,12 +920,13 @@ message AddressEntryList {
message Offer { message Offer {
enum State { enum State {
UNDEFINED = 0; PB_ERROR = 0;
OFFER_FEE_PAID = 1; UNKNOWN = 1;
AVAILABLE = 2; OFFER_FEE_PAID = 2;
NOT_AVAILABLE = 3; AVAILABLE = 3;
REMOVED = 4; NOT_AVAILABLE = 4;
MAKER_OFFLINE = 5; REMOVED = 5;
MAKER_OFFLINE = 6;
} }
OfferPayload offer_payload = 1; OfferPayload offer_payload = 1;
@ -925,7 +934,7 @@ message Offer {
message OpenOffer { message OpenOffer {
enum State { enum State {
UNKNOWN_FAILURE = 0; PB_ERROR = 0;
AVAILABLE = 1; AVAILABLE = 1;
RESERVED = 2; RESERVED = 2;
CLOSED = 3; CLOSED = 3;
@ -950,61 +959,76 @@ message TradableList {
repeated Tradable tradable = 1; repeated Tradable tradable = 1;
} }
message OpenOfferList {
repeated OpenOffer open_offer = 1;
}
message TradeList {
repeated Trade trade = 1;
}
message Trade { message Trade {
enum State { enum State {
UNKNOWN_FAILURE = 0; PB_ERROR_STATE = 0;
PREPARATION = 1; PREPARATION = 1;
TAKER_FEE_PAID = 2; TAKER_PUBLISHED_TAKER_FEE_TX = 2;
OFFERER_SENT_PUBLISH_DEPOSIT_TX_REQUEST = 3; MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST = 3;
TAKER_PUBLISHED_DEPOSIT_TX = 4; MAKER_SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST = 4;
DEPOSIT_SEEN_IN_NETWORK = 5; MAKER_STORED_IN_MAILBOX_PUBLISH_DEPOSIT_TX_REQUEST = 5;
TAKER_SENT_DEPOSIT_TX_PUBLISHED_MSG = 6; MAKER_SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST = 6;
OFFERER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG = 7; TAKER_RECEIVED_PUBLISH_DEPOSIT_TX_REQUEST = 7;
DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN = 8; TAKER_PUBLISHED_DEPOSIT_TX = 8;
TAKER_SENT_DEPOSIT_TX_PUBLISHED_MSG = 9;
BUYER_CONFIRMED_FIAT_PAYMENT_INITIATED = 9; TAKER_SAW_ARRIVED_DEPOSIT_TX_PUBLISHED_MSG = 10;
BUYER_SENT_FIAT_PAYMENT_INITIATED_MSG = 10; TAKER_STORED_IN_MAILBOX_DEPOSIT_TX_PUBLISHED_MSG = 11;
SELLER_RECEIVED_FIAT_PAYMENT_INITIATED_MSG = 11; TAKER_SEND_FAILED_DEPOSIT_TX_PUBLISHED_MSG = 12;
MAKER_RECEIVED_DEPOSIT_TX_PUBLISHED_MSG = 13;
SELLER_CONFIRMED_FIAT_PAYMENT_RECEIPT = 12; MAKER_SAW_DEPOSIT_TX_IN_NETWORK = 14;
SELLER_SENT_FIAT_PAYMENT_RECEIPT_MSG = 13; DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN = 15;
BUYER_RECEIVED_FIAT_PAYMENT_RECEIPT_MSG = 14; BUYER_CONFIRMED_IN_UI_FIAT_PAYMENT_INITIATED = 16;
BUYER_SENT_FIAT_PAYMENT_INITIATED_MSG = 17;
BUYER_COMMITTED_PAYOUT_TX = 15; BUYER_SAW_ARRIVED_FIAT_PAYMENT_INITIATED_MSG = 18;
BUYER_STARTED_SEND_PAYOUT_TX = 16; BUYER_STORED_IN_MAILBOX_FIAT_PAYMENT_INITIATED_MSG = 19;
SELLER_RECEIVED_AND_COMMITTED_PAYOUT_TX = 17; BUYER_SEND_FAILED_FIAT_PAYMENT_INITIATED_MSG = 20;
PAYOUT_BROAD_CASTED = 18; SELLER_RECEIVED_FIAT_PAYMENT_INITIATED_MSG = 21;
WITHDRAW_COMPLETED = 19; SELLER_CONFIRMED_IN_UI_FIAT_PAYMENT_RECEIPT = 22;
SELLER_PUBLISHED_PAYOUT_TX = 23;
SELLER_SENT_PAYOUT_TX_PUBLISHED_MSG = 24;
SELLER_SAW_ARRIVED_PAYOUT_TX_PUBLISHED_MSG = 25;
SELLER_STORED_IN_MAILBOX_PAYOUT_TX_PUBLISHED_MSG = 26;
SELLER_SEND_FAILED_PAYOUT_TX_PUBLISHED_MSG = 27;
BUYER_RECEIVED_PAYOUT_TX_PUBLISHED_MSG = 28;
BUYER_SAW_PAYOUT_TX_IN_NETWORK = 29;
WITHDRAW_COMPLETED = 30;
} }
enum Phase { enum Phase {
PHASE_UNKNOWN_FAILURE = 0; PB_ERROR_PHASE = 0;
PHASE_PREPARATION = 1; INIT = 1;
PHASE_TAKER_FEE_PAID = 2; TAKER_FEE_PUBLISHED = 2;
DEPOSIT_REQUESTED = 3; DEPOSIT_PUBLISHED = 3;
DEPOSIT_PAID = 4; DEPOSIT_CONFIRMED = 4;
FIAT_SENT = 5; FIAT_SENT = 5;
FIAT_RECEIVED = 6; FIAT_RECEIVED = 6;
PAYOUT_PAID = 7; PAYOUT_PUBLISHED = 7;
WITHDRAWN = 8; WITHDRAWN = 8;
DISPUT = 9;
} }
enum DisputeState { enum DisputeState {
TRADED_DISPUTE_STATE_UNKNOWN_FAILURE = 0; PB_ERROR_DISPUTE_STATE = 0;
NONE = 1; NO_DISPUTE = 1;
DISPUTE_REQUESTED = 2; DISPUTE_REQUESTED = 2;
DISPUTE_STARTED_BY_PEER = 3; DISPUTE_STARTED_BY_PEER = 3;
DISPUTE_CLOSE = 4; DISPUTE_CLOSED = 4;
} }
enum TradePeriodState { enum TradePeriodState {
TRADE_PERIOD_STATE_UNKNOWN_FAILURE = 0; PB_ERROR_TRADE_PERIOD_STATE = 0;
NORMAL = 1; FIRST_HALF = 1;
HALF_REACHED = 2; SECOND_HALF = 2;
TRADE_PERIOD_OVER = 3; TRADE_PERIOD_OVER = 3;
} }
Offer offer = 1; Offer offer = 1;
ProcessModel process_model = 2; ProcessModel process_model = 2;
string taker_fee_tx_id = 3; string taker_fee_tx_id = 3;
@ -1089,20 +1113,16 @@ message TradeStatisticsList {
repeated TradeStatistics trade_statistics = 1; repeated TradeStatistics trade_statistics = 1;
} }
message OpenOfferList {
repeated OpenOffer open_offer = 1;
}
message PendingTradeList { message PendingTradeList {
repeated PendingTradeList trade = 1; repeated Trade trade = 1;
} }
message ClosedTradeList { message ClosedTradeList {
repeated ClosedTradeList trade = 1; repeated Trade trade = 1;
} }
message FailedTradeList { message FailedTradeList {
repeated FailedTradeList trade = 1; repeated Trade trade = 1;
} }
@ -1116,11 +1136,11 @@ message BsqChainState {
message VoteItem { message VoteItem {
enum VotingType { enum VotingType {
UNKNOWN_FAILURE = 0; PB_ERROR = 0;
CREATE_OFFER_FEE_IN_BTC = 1; MAKER_FEE_IN_BTC = 1;
TAKE_OFFER_FEE_IN_BTC = 2; TAKER_FEE_IN_BTC = 2;
CREATE_OFFER_FEE_IN_BSQ = 3; MAKER_FEE_IN_BSQ = 3;
TAKE_OFFER_FEE_IN_BSQ = 4; TAKER_FEE_IN_BSQ = 4;
CREATE_COMPENSATION_REQUEST_FEE_IN_BSQ = 5; CREATE_COMPENSATION_REQUEST_FEE_IN_BSQ = 5;
VOTING_FEE_IN_BSQ = 6; VOTING_FEE_IN_BSQ = 6;
COMPENSATION_REQUEST_PERIOD_IN_BLOCKS = 7; COMPENSATION_REQUEST_PERIOD_IN_BLOCKS = 7;

View file

@ -9,4 +9,4 @@ public enum AvailabilityResult {
NO_ARBITRATORS, NO_ARBITRATORS,
NO_MEDIATORS, NO_MEDIATORS,
USER_IGNORED USER_IGNORED
} }

View file

@ -45,7 +45,7 @@ public class Offer implements NetworkPayload, PersistablePayload {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public enum State { public enum State {
UNDEFINED, UNKNOWN,
OFFER_FEE_PAID, OFFER_FEE_PAID,
AVAILABLE, AVAILABLE,
NOT_AVAILABLE, NOT_AVAILABLE,
@ -60,9 +60,7 @@ public class Offer implements NetworkPayload, PersistablePayload {
@Getter @Getter
private final OfferPayload offerPayload; private final OfferPayload offerPayload;
@JsonExclude @JsonExclude
transient private Offer.State state = Offer.State.UNDEFINED; transient private Offer.State state = Offer.State.UNKNOWN;
// Those state properties are transient and only used at runtime!
// don't access directly as it might be null; use getStateProperty() which creates an object if not instantiated
@JsonExclude @JsonExclude
@Getter @Getter
transient private ObjectProperty<Offer.State> stateProperty = new SimpleObjectProperty<>(state); transient private ObjectProperty<Offer.State> stateProperty = new SimpleObjectProperty<>(state);
@ -73,8 +71,7 @@ public class Offer implements NetworkPayload, PersistablePayload {
@Getter @Getter
transient private StringProperty errorMessageProperty = new SimpleStringProperty(); transient private StringProperty errorMessageProperty = new SimpleStringProperty();
@JsonExclude @JsonExclude
@Setter @Nullable @Setter
@Nullable
transient private PriceFeedService priceFeedService; transient private PriceFeedService priceFeedService;
@ -205,7 +202,7 @@ public class Offer implements NetworkPayload, PersistablePayload {
} }
public void resetState() { public void resetState() {
setState(Offer.State.UNDEFINED); setState(Offer.State.UNKNOWN);
} }

View file

@ -21,6 +21,7 @@ import io.bisq.common.Timer;
import io.bisq.common.UserThread; import io.bisq.common.UserThread;
import io.bisq.common.storage.Storage; import io.bisq.common.storage.Storage;
import io.bisq.core.trade.Tradable; import io.bisq.core.trade.Tradable;
import io.bisq.core.trade.TradableList;
import io.bisq.generated.protobuffer.PB; import io.bisq.generated.protobuffer.PB;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
@ -47,9 +48,9 @@ public final class OpenOffer implements Tradable {
@Getter @Getter
private State state = State.AVAILABLE; private State state = State.AVAILABLE;
transient private Storage<OpenOfferList> storage; transient private Storage<TradableList<OpenOffer>> storage;
public OpenOffer(Offer offer, Storage<OpenOfferList> storage) { public OpenOffer(Offer offer, Storage<TradableList<OpenOffer>> storage) {
this.offer = offer; this.offer = offer;
this.storage = storage; this.storage = storage;
} }
@ -84,6 +85,7 @@ public final class OpenOffer implements Tradable {
// Getters // Getters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override
public Date getDate() { public Date getDate() {
return offer.getDate(); return offer.getDate();
} }
@ -98,7 +100,7 @@ public final class OpenOffer implements Tradable {
return offer.getShortId(); return offer.getShortId();
} }
public void setStorage(Storage<OpenOfferList> storage) { public void setStorage(Storage<TradableList<OpenOffer>> storage) {
this.storage = storage; this.storage = storage;
} }

View file

@ -39,6 +39,7 @@ import io.bisq.core.offer.messages.OfferAvailabilityResponse;
import io.bisq.core.offer.placeoffer.PlaceOfferModel; import io.bisq.core.offer.placeoffer.PlaceOfferModel;
import io.bisq.core.offer.placeoffer.PlaceOfferProtocol; import io.bisq.core.offer.placeoffer.PlaceOfferProtocol;
import io.bisq.core.provider.price.PriceFeedService; import io.bisq.core.provider.price.PriceFeedService;
import io.bisq.core.trade.TradableList;
import io.bisq.core.trade.closed.ClosedTradableManager; import io.bisq.core.trade.closed.ClosedTradableManager;
import io.bisq.core.trade.handlers.TransactionResultHandler; import io.bisq.core.trade.handlers.TransactionResultHandler;
import io.bisq.core.user.Preferences; import io.bisq.core.user.Preferences;
@ -46,7 +47,6 @@ import io.bisq.core.user.User;
import io.bisq.core.util.Validator; import io.bisq.core.util.Validator;
import io.bisq.network.p2p.*; import io.bisq.network.p2p.*;
import io.bisq.network.p2p.peers.PeerManager; import io.bisq.network.p2p.peers.PeerManager;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -81,12 +81,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
private final ClosedTradableManager closedTradableManager; private final ClosedTradableManager closedTradableManager;
private final PriceFeedService priceFeedService; private final PriceFeedService priceFeedService;
private final Preferences preferences; private final Preferences preferences;
private final Storage<TradableList<OpenOffer>> openOffersStorage;
private final Storage<OpenOfferList> openOffersStorage;
private boolean stopped; private boolean stopped;
private Timer periodicRepublishOffersTimer, periodicRefreshOffersTimer, retryRepublishOffersTimer; private Timer periodicRepublishOffersTimer, periodicRefreshOffersTimer, retryRepublishOffersTimer;
private final OpenOfferList openOfferList = new OpenOfferList(); private TradableList<OpenOffer> openOfferList;
private ObservableList<OpenOffer> observableList;
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@ -127,12 +125,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
@Override @Override
public void readPersisted() { public void readPersisted() {
OpenOfferList persisted = openOffersStorage.initAndGetPersisted(openOfferList); openOfferList = new TradableList<>(openOffersStorage, "OpenOffers");
if (persisted != null) openOfferList.forEach(e -> e.getOffer().setPriceFeedService(priceFeedService));
openOfferList.addAll(persisted.getList());
observableList = FXCollections.observableArrayList(openOfferList.getList());
observableList.forEach(e -> e.getOffer().setPriceFeedService(priceFeedService));
} }
public void onAllServicesInitialized() { public void onAllServicesInitialized() {
@ -168,9 +162,9 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
// we remove own offers from offerbook when we go offline // we remove own offers from offerbook when we go offline
// Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out // Normally we use a delay for broadcasting to the peers, but at shut down we want to get it fast out
final int size = observableList.size(); final int size = openOfferList.size();
if (offerBookService.isBootstrapped()) { if (offerBookService.isBootstrapped()) {
observableList.forEach(openOffer -> offerBookService.removeOfferAtShutDown(openOffer.getOffer().getOfferPayload())); openOfferList.forEach(openOffer -> offerBookService.removeOfferAtShutDown(openOffer.getOffer().getOfferPayload()));
if (completeHandler != null) if (completeHandler != null)
UserThread.runAfter(completeHandler::run, size * 200 + 500, TimeUnit.MILLISECONDS); UserThread.runAfter(completeHandler::run, size * 200 + 500, TimeUnit.MILLISECONDS);
} else { } else {
@ -359,15 +353,15 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
} }
public ObservableList<OpenOffer> getObservableList() { public ObservableList<OpenOffer> getObservableList() {
return observableList; return openOfferList.getObservableList();
} }
public Optional<OpenOffer> findOpenOffer(String offerId) { public Optional<OpenOffer> findOpenOffer(String offerId) {
return observableList.stream().filter(openOffer -> openOffer.getId().equals(offerId)).findAny(); return openOfferList.stream().filter(openOffer -> openOffer.getId().equals(offerId)).findAny();
} }
public Optional<OpenOffer> getOpenOfferById(String offerId) { public Optional<OpenOffer> getOpenOfferById(String offerId) {
return observableList.stream().filter(e -> e.getId().equals(offerId)).findFirst(); return openOfferList.stream().filter(e -> e.getId().equals(offerId)).findFirst();
} }
@ -457,8 +451,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private void republishOffers() { private void republishOffers() {
int size = observableList.size(); int size = openOfferList.size();
final ArrayList<OpenOffer> openOffersList = new ArrayList<>(observableList); final ArrayList<OpenOffer> openOffersList = new ArrayList<>(openOfferList.getList());
Log.traceCall("Number of offer for republish: " + size); Log.traceCall("Number of offer for republish: " + size);
if (!stopped) { if (!stopped) {
stopPeriodicRefreshOffersTimer(); stopPeriodicRefreshOffersTimer();
@ -470,7 +464,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
final long maxDelay = (i + 2) * delay; final long maxDelay = (i + 2) * delay;
final OpenOffer openOffer = openOffersList.get(i); final OpenOffer openOffer = openOffersList.get(i);
UserThread.runAfterRandomDelay(() -> { UserThread.runAfterRandomDelay(() -> {
if (observableList.contains(openOffer)) { if (openOfferList.contains(openOffer)) {
// The openOffer.getId().contains("_") check is because there was once a version // The openOffer.getId().contains("_") check is because there was once a version
// where we encoded the version nr in the offer id with a "_" as separator. // where we encoded the version nr in the offer id with a "_" as separator.
// That caused several issues and was reverted. So if there are still old offers out with that // That caused several issues and was reverted. So if there are still old offers out with that
@ -540,11 +534,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
if (periodicRefreshOffersTimer == null) if (periodicRefreshOffersTimer == null)
periodicRefreshOffersTimer = UserThread.runPeriodically(() -> { periodicRefreshOffersTimer = UserThread.runPeriodically(() -> {
if (!stopped) { if (!stopped) {
int size = observableList.size(); int size = openOfferList.size();
Log.traceCall("Number of offer for refresh: " + size); Log.traceCall("Number of offer for refresh: " + size);
//we clone our list as openOffers might change during our delayed call //we clone our list as openOffers might change during our delayed call
final ArrayList<OpenOffer> openOffersList = new ArrayList<>(observableList); final ArrayList<OpenOffer> openOffersList = new ArrayList<>(openOfferList.getList());
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
// we delay to avoid reaching throttle limits // we delay to avoid reaching throttle limits
// roughly 4 offers per second // roughly 4 offers per second
@ -555,7 +549,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
final OpenOffer openOffer = openOffersList.get(i); final OpenOffer openOffer = openOffersList.get(i);
UserThread.runAfterRandomDelay(() -> { UserThread.runAfterRandomDelay(() -> {
// we need to check if in the meantime the offer has been removed // we need to check if in the meantime the offer has been removed
if (observableList.contains(openOffer)) if (openOfferList.contains(openOffer))
refreshOffer(openOffer); refreshOffer(openOffer);
}, minDelay, maxDelay, TimeUnit.MILLISECONDS); }, minDelay, maxDelay, TimeUnit.MILLISECONDS);
} }

View file

@ -82,7 +82,7 @@ public class OfferAvailabilityProtocol {
public void sendOfferAvailabilityRequest() { public void sendOfferAvailabilityRequest() {
// reset // reset
model.offer.setState(Offer.State.UNDEFINED); model.offer.setState(Offer.State.UNKNOWN);
model.p2PService.addDecryptedDirectMessageListener(decryptedDirectMessageListener); model.p2PService.addDecryptedDirectMessageListener(decryptedDirectMessageListener);
model.setPeerNodeAddress(model.offer.getMakerNodeAddress()); model.setPeerNodeAddress(model.offer.getMakerNodeAddress());

View file

@ -18,10 +18,20 @@
package io.bisq.core.proto; package io.bisq.core.proto;
import io.bisq.common.locale.CurrencyUtil; import io.bisq.common.locale.CurrencyUtil;
import io.bisq.core.arbitration.DisputeResult;
import io.bisq.core.btc.AddressEntry;
import io.bisq.core.dao.vote.VotingType;
import io.bisq.core.offer.AvailabilityResult;
import io.bisq.core.offer.Offer;
import io.bisq.core.offer.OfferPayload;
import io.bisq.core.offer.OpenOffer;
import io.bisq.core.payment.payload.BankAccountPayload; import io.bisq.core.payment.payload.BankAccountPayload;
import io.bisq.core.payment.payload.CountryBasedPaymentAccountPayload; import io.bisq.core.payment.payload.CountryBasedPaymentAccountPayload;
import io.bisq.core.trade.Trade;
import io.bisq.generated.protobuffer.PB; import io.bisq.generated.protobuffer.PB;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ProtoCoreUtil { public class ProtoCoreUtil {
@ -48,4 +58,153 @@ public class ProtoCoreUtil {
CountryBasedPaymentAccountPayload countryBasedPaymentAccountPayload) { CountryBasedPaymentAccountPayload countryBasedPaymentAccountPayload) {
countryBasedPaymentAccountPayload.setCountryCode(protoEntry.getCountryBasedPaymentAccountPayload().getCountryCode()); countryBasedPaymentAccountPayload.setCountryCode(protoEntry.getCountryBasedPaymentAccountPayload().getCountryCode());
} }
// Util for auto generating enum values used in pb definition
public static void printAllEnumsForPB() {
StringBuilder sb = new StringBuilder("\n enum State {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < Trade.State.values().length; i++) {
Trade.State s = Trade.State.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n");
sb.append(" enum Phase {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < Trade.Phase.values().length; i++) {
Trade.Phase s = Trade.Phase.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum DisputeState {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < Trade.DisputeState.values().length; i++) {
Trade.DisputeState s = Trade.DisputeState.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum TradePeriodState {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < Trade.TradePeriodState.values().length; i++) {
Trade.TradePeriodState s = Trade.TradePeriodState.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum VotingType {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < VotingType.values().length; i++) {
VotingType s = VotingType.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum Direction {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < OfferPayload.Direction.values().length; i++) {
OfferPayload.Direction s = OfferPayload.Direction.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum Winner {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < DisputeResult.Winner.values().length; i++) {
DisputeResult.Winner s = DisputeResult.Winner.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum Reason {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < DisputeResult.Reason.values().length; i++) {
DisputeResult.Reason s = DisputeResult.Reason.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum AvailabilityResult {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < AvailabilityResult.values().length; i++) {
AvailabilityResult s = AvailabilityResult.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum Context {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < AddressEntry.Context.values().length; i++) {
AddressEntry.Context s = AddressEntry.Context.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum State {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < Offer.State.values().length; i++) {
Offer.State s = Offer.State.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
sb.append(" enum State {\n");
sb.append(" PB_ERROR = 0;\n");
for (int i = 0; i < OpenOffer.State.values().length; i++) {
OpenOffer.State s = OpenOffer.State.values()[i];
sb.append(" ");
sb.append(s.toString());
sb.append(" = ");
sb.append(s.ordinal() + 1);
sb.append(";\n");
}
sb.append(" }\n\n\n");
log.info(sb.toString());
}
} }

View file

@ -11,7 +11,6 @@ import io.bisq.core.btc.AddressEntryList;
import io.bisq.core.btc.wallet.BtcWalletService; import io.bisq.core.btc.wallet.BtcWalletService;
import io.bisq.core.dao.compensation.CompensationRequestPayload; import io.bisq.core.dao.compensation.CompensationRequestPayload;
import io.bisq.core.offer.OpenOffer; import io.bisq.core.offer.OpenOffer;
import io.bisq.core.offer.OpenOfferList;
import io.bisq.core.payment.PaymentAccount; import io.bisq.core.payment.PaymentAccount;
import io.bisq.core.proto.CoreProtoResolver; import io.bisq.core.proto.CoreProtoResolver;
import io.bisq.core.trade.*; import io.bisq.core.trade.*;
@ -63,9 +62,16 @@ public class CorePersistenceProtoResolver extends CoreProtoResolver implements P
case VIEW_PATH_AS_STRING: case VIEW_PATH_AS_STRING:
return PersistableViewPath.fromProto(proto.getViewPathAsString()); return PersistableViewPath.fromProto(proto.getViewPathAsString());
case OPEN_OFFER_LIST: case OPEN_OFFER_LIST:
return OpenOfferList.fromProto(proto.getOpenOfferList()); return TradableList.fromProto(proto.getOpenOfferList(), openOfferStorage);
case TRADABLE_LIST: case TRADABLE_LIST:
return getTradableList(proto.getTradableList()); return TradableList.fromProto(proto.getTradableList(),
this,
openOfferStorage,
buyerAsMakerTradeStorage,
buyerAsTakerTradeStorage,
sellerAsMakerTradeStorage,
sellerAsTakerTradeStorage,
btcWalletService.get());
case PEER_LIST: case PEER_LIST:
return PeerList.fromProto(proto.getPeerList()); return PeerList.fromProto(proto.getPeerList());
case COMPENSATION_REQUEST_PAYLOAD: case COMPENSATION_REQUEST_PAYLOAD:
@ -84,11 +90,27 @@ public class CorePersistenceProtoResolver extends CoreProtoResolver implements P
} }
} }
// @Override
public Tradable fromProto(PB.Tradable proto, Storage<TradableList<SellerAsMakerTrade>> storage) {
log.error("Convert protobuffer disk proto: {}", proto.getMessageCase());
private PersistableEnvelope getTradableList(PB.TradableList tradableList) { switch (proto.getMessageCase()) {
return TradableList.fromProto(tradableList, openOfferStorage, buyerAsMakerTradeStorage, buyerAsTakerTradeStorage, sellerAsMakerTradeStorage, sellerAsTakerTradeStorage, btcWalletService.get()); case OPEN_OFFER:
return OpenOffer.fromProto(proto.getOpenOffer());
case BUYER_AS_MAKER_TRADE:
return BuyerAsMakerTrade.fromProto(proto.getBuyerAsMakerTrade(), storage, btcWalletService.get());
case BUYER_AS_TAKER_TRADE:
return BuyerAsTakerTrade.fromProto(proto.getBuyerAsTakerTrade(), storage, btcWalletService.get());
case SELLER_AS_MAKER_TRADE:
return SellerAsMakerTrade.fromProto(proto.getSellerAsMakerTrade(), storage, btcWalletService.get());
case SELLER_AS_TAKER_TRADE:
return SellerAsTakerTrade.fromProto(proto.getSellerAsTakerTrade(), storage, btcWalletService.get());
default:
throw new ProtobufferException("Unknown proto message case. messageCase=" + proto.getMessageCase());
}
} }
private Preferences fillPreferences(PB.PersistableEnvelope envelope, Preferences preferences) { private Preferences fillPreferences(PB.PersistableEnvelope envelope, Preferences preferences) {
final PB.Preferences env = envelope.getPreferences(); final PB.Preferences env = envelope.getPreferences();
preferences.setUserLanguage(env.getUserLanguage()); preferences.setUserLanguage(env.getUserLanguage());

View file

@ -52,14 +52,9 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// API // PROTO BUFFER
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void handleTakeOfferRequest(TradeMessage message, NodeAddress taker) {
((MakerProtocol) tradeProtocol).handleTakeOfferRequest(message, taker);
}
@Override @Override
public PB.Tradable toProtoMessage() { public PB.Tradable toProtoMessage() {
return PB.Tradable.newBuilder() return PB.Tradable.newBuilder()
@ -73,4 +68,14 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade {
Coin.valueOf(proto.getTrade().getTakerFeeAsLong()), Coin.valueOf(proto.getTrade().getTakerFeeAsLong()),
proto.getTrade().getIsCurrencyForTakerFeeBtc(), storage, btcWalletService); proto.getTrade().getIsCurrencyForTakerFeeBtc(), storage, btcWalletService);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void handleTakeOfferRequest(TradeMessage message, NodeAddress taker) {
((MakerProtocol) tradeProtocol).handleTakeOfferRequest(message, taker);
}
} }

View file

@ -56,15 +56,9 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade {
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// API // PROTO BUFFER
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void takeAvailableOffer() {
checkArgument(tradeProtocol instanceof TakerProtocol, "tradeProtocol NOT instanceof TakerProtocol");
((TakerProtocol) tradeProtocol).takeAvailableOffer();
}
@Override @Override
public PB.Tradable toProtoMessage() { public PB.Tradable toProtoMessage() {
return PB.Tradable.newBuilder() return PB.Tradable.newBuilder()
@ -81,4 +75,15 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade {
NodeAddress.fromProto(trade.getTradingPeerNodeAddress()), storage, NodeAddress.fromProto(trade.getTradingPeerNodeAddress()), storage,
btcWalletService); btcWalletService);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void takeAvailableOffer() {
checkArgument(tradeProtocol instanceof TakerProtocol, "tradeProtocol NOT instanceof TakerProtocol");
((TakerProtocol) tradeProtocol).takeAvailableOffer();
}
} }

View file

@ -207,30 +207,29 @@ public final class Contract implements NetworkPayload {
return Price.valueOf(offerPayload.getCurrencyCode(), tradePrice); return Price.valueOf(offerPayload.getCurrencyCode(), tradePrice);
} }
@Override @Override public String toString() {
public String toString() {
return "Contract{" + return "Contract{" +
"\n\toffer=" + offerPayload + "\n offerPayload=" + offerPayload +
"\n\ttradeAmount=" + tradeAmount + ",\n tradeAmount=" + tradeAmount +
"\n\ttradePrice=" + tradePrice + ",\n tradePrice=" + tradePrice +
"\n\ttakerFeeTxID='" + takerFeeTxID + '\'' + ",\n takerFeeTxID='" + takerFeeTxID + '\'' +
"\n\tarbitratorAddress=" + arbitratorNodeAddress + ",\n buyerNodeAddress=" + buyerNodeAddress +
"\n\tmediatorNodeAddress=" + mediatorNodeAddress + ",\n sellerNodeAddress=" + sellerNodeAddress +
"\n\tisBuyerMakerAndSellerTaker=" + isBuyerMakerAndSellerTaker + ",\n arbitratorNodeAddress=" + arbitratorNodeAddress +
"\n\tmakerAccountId='" + makerAccountId + '\'' + ",\n mediatorNodeAddress=" + mediatorNodeAddress +
"\n\ttakerAccountId='" + takerAccountId + '\'' + ",\n isBuyerMakerAndSellerTaker=" + isBuyerMakerAndSellerTaker +
"\n\tmakerPaymentAccountPayload=" + makerPaymentAccountPayload + ",\n makerAccountId='" + makerAccountId + '\'' +
"\n\ttakerPaymentAccountPayload=" + takerPaymentAccountPayload + ",\n takerAccountId='" + takerAccountId + '\'' +
"\n\tmakerPubKeyRing=" + makerPubKeyRing + ",\n makerPaymentAccountPayload=" + makerPaymentAccountPayload +
"\n\ttakerPubKeyRing=" + takerPubKeyRing + ",\n takerPaymentAccountPayload=" + takerPaymentAccountPayload +
"\n\tbuyerAddress=" + buyerNodeAddress + ",\n makerPubKeyRing=" + makerPubKeyRing +
"\n\tsellerAddress=" + sellerNodeAddress + ",\n takerPubKeyRing=" + takerPubKeyRing +
"\n\tmakerPayoutAddressString='" + makerPayoutAddressString + '\'' + ",\n makerPayoutAddressString='" + makerPayoutAddressString + '\'' +
"\n\ttakerPayoutAddressString='" + takerPayoutAddressString + '\'' + ",\n takerPayoutAddressString='" + takerPayoutAddressString + '\'' +
"\n\tmakerMultiSigPubKey=" + Hex.toHexString(makerMultiSigPubKey) + ",\n makerMultiSigPubKey=" + Hex.toHexString(makerMultiSigPubKey) +
"\n\ttakerMultiSigPubKey=" + Hex.toHexString(takerMultiSigPubKey) + ",\n takerMultiSigPubKey=" + Hex.toHexString(takerMultiSigPubKey) +
"\n\tBuyerMultiSigPubKey=" + Hex.toHexString(getBuyerMultiSigPubKey()) + ",\n BuyerMultiSigPubKey=" + Hex.toHexString(getBuyerMultiSigPubKey()) +
"\n\tSellerMultiSigPubKey=" + Hex.toHexString(getSellerMultiSigPubKey()) + ",\n SellerMultiSigPubKey=" + Hex.toHexString(getSellerMultiSigPubKey()) +
'}'; "\n}";
} }
} }

View file

@ -15,40 +15,36 @@
* along with bisq. If not, see <http://www.gnu.org/licenses/>. * along with bisq. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.bisq.core.offer; package io.bisq.core.trade;
import com.google.protobuf.Message;
import io.bisq.common.proto.persistable.PersistableEnvelope;
import io.bisq.generated.protobuffer.PB;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.Delegate; import lombok.experimental.Delegate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
public class OpenOfferList implements PersistableEnvelope { public class PendingTradeList /*implements PersistableEnvelope */ {
@Getter @Getter
@Delegate @Delegate
private List<OpenOffer> list = new ArrayList<>(); private List<Trade> list = new ArrayList<>();
public OpenOfferList() { public PendingTradeList() {
} }
public OpenOfferList(List<OpenOffer> list) { public PendingTradeList(List<Trade> list) {
this.list = list; this.list = list;
} }
@Override /* @Override
public Message toProtoMessage() { public Message toProtoMessage() {
return PB.PersistableEnvelope.newBuilder() return PB.PersistableEnvelope.newBuilder()
.setOpenOfferList(PB.OpenOfferList.newBuilder() .setPendingTradeList(PB.PendingTradeList.newBuilder()
.addAllOpenOffer(getList().stream().map(OpenOffer::toProtoMessage).collect(Collectors.toList()))) .addAllTrade(getList().stream().map(Trade::toProtoMessage).collect(Collectors.toList())))
.build(); .build();
} }*/
public static PersistableEnvelope fromProto(PB.OpenOfferList proto) { /* public static PersistableEnvelope fromProto(PB.PendingTradeList proto) {
return new OpenOfferList(proto.getOpenOfferList().stream().map(OpenOffer::fromProto) return new PendingTradeList(proto.getTradeList().stream().map(Trade::fromProto)
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }*/
} }

View file

@ -51,14 +51,9 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// API // PROTO BUFFER
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void handleTakeOfferRequest(TradeMessage message, NodeAddress taker) {
((MakerProtocol) tradeProtocol).handleTakeOfferRequest(message, taker);
}
@Override @Override
public PB.Tradable toProtoMessage() { public PB.Tradable toProtoMessage() {
return PB.Tradable.newBuilder() return PB.Tradable.newBuilder()
@ -72,4 +67,14 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade
Coin.valueOf(trade.getTxFeeAsLong()), Coin.valueOf(trade.getTakerFeeAsLong()), Coin.valueOf(trade.getTxFeeAsLong()), Coin.valueOf(trade.getTakerFeeAsLong()),
trade.getIsCurrencyForTakerFeeBtc(), storage, btcWalletService); trade.getIsCurrencyForTakerFeeBtc(), storage, btcWalletService);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void handleTakeOfferRequest(TradeMessage message, NodeAddress taker) {
((MakerProtocol) tradeProtocol).handleTakeOfferRequest(message, taker);
}
} }

View file

@ -56,16 +56,9 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// API // PROTO BUFFER
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void takeAvailableOffer() {
checkArgument(tradeProtocol instanceof TakerProtocol, "tradeProtocol NOT instanceof TakerProtocol");
((TakerProtocol) tradeProtocol).takeAvailableOffer();
}
@Override @Override
public PB.Tradable toProtoMessage() { public PB.Tradable toProtoMessage() {
return PB.Tradable.newBuilder() return PB.Tradable.newBuilder()
@ -80,4 +73,15 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade
trade.getIsCurrencyForTakerFeeBtc(), trade.getTradePrice(), trade.getIsCurrencyForTakerFeeBtc(), trade.getTradePrice(),
NodeAddress.fromProto(trade.getTradingPeerNodeAddress()), storage, btcWalletService); NodeAddress.fromProto(trade.getTradingPeerNodeAddress()), storage, btcWalletService);
} }
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void takeAvailableOffer() {
checkArgument(tradeProtocol instanceof TakerProtocol, "tradeProtocol NOT instanceof TakerProtocol");
((TakerProtocol) tradeProtocol).takeAvailableOffer();
}
} }

View file

@ -18,11 +18,12 @@
package io.bisq.core.trade; package io.bisq.core.trade;
import com.google.protobuf.Message; import com.google.protobuf.Message;
import io.bisq.common.proto.ProtoUtil; import io.bisq.common.proto.ProtoCollectionUtil;
import io.bisq.common.proto.persistable.PersistableEnvelope; import io.bisq.common.proto.persistable.PersistableEnvelope;
import io.bisq.common.storage.Storage; import io.bisq.common.storage.Storage;
import io.bisq.core.btc.wallet.BtcWalletService; import io.bisq.core.btc.wallet.BtcWalletService;
import io.bisq.core.offer.OpenOffer; import io.bisq.core.offer.OpenOffer;
import io.bisq.core.proto.persistable.CorePersistenceProtoResolver;
import io.bisq.generated.protobuffer.PB; import io.bisq.generated.protobuffer.PB;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@ -51,10 +52,9 @@ public final class TradableList<T extends Tradable> implements PersistableEnvelo
public TradableList(Storage<TradableList<T>> storage, String fileName) { public TradableList(Storage<TradableList<T>> storage, String fileName) {
this.storage = storage; this.storage = storage;
// TradableList<T> persisted = storage.initAndGetPersisted(this, fileName); TradableList<T> persisted = storage.initAndGetPersisted(this, fileName);
TradableList<T> persisted = storage.initAndGetPersistedWithFileName(fileName);
if (persisted != null) if (persisted != null)
list.addAll(persisted.getList()); list = persisted.getList();
} }
@ -70,20 +70,23 @@ public final class TradableList<T extends Tradable> implements PersistableEnvelo
@Override @Override
public Message toProtoMessage() { public Message toProtoMessage() {
return PB.PersistableEnvelope.newBuilder().setTradableList(PB.TradableList.newBuilder() return PB.PersistableEnvelope.newBuilder().setTradableList(PB.TradableList.newBuilder()
.addAllTradable(ProtoUtil.collectionToProto(list))).build(); .addAllTradable(ProtoCollectionUtil.collectionToProto(list))).build();
} }
public static TradableList fromProto(PB.TradableList proto, public static TradableList fromProto(PB.TradableList proto,
CorePersistenceProtoResolver corePersistenceProtoResolver,
Storage<TradableList<OpenOffer>> openOfferStorage, Storage<TradableList<OpenOffer>> openOfferStorage,
Storage<TradableList<BuyerAsMakerTrade>> buyerAsMakerTradeStorage, Storage<TradableList<BuyerAsMakerTrade>> buyerAsMakerTradeStorage,
Storage<TradableList<BuyerAsTakerTrade>> buyerAsTakerTradeStorage, Storage<TradableList<BuyerAsTakerTrade>> buyerAsTakerTradeStorage,
Storage<TradableList<SellerAsMakerTrade>> sellerAsMakerTradeStorage, Storage<TradableList<SellerAsMakerTrade>> sellerAsMakerTradeStorage,
Storage<TradableList<SellerAsTakerTrade>> sellerAsTakerTradeStorage, Storage<TradableList<SellerAsTakerTrade>> sellerAsTakerTradeStorage,
BtcWalletService btcWalletService) { BtcWalletService btcWalletService) {
log.error("fromProto " + proto);
List list = proto.getTradableList().stream().map(tradable -> { List list = proto.getTradableList().stream().map(tradable -> {
log.error("tradable.getMessageCase() " + tradable.getMessageCase());
switch (tradable.getMessageCase()) { switch (tradable.getMessageCase()) {
/* case OPEN_OFFER: case OPEN_OFFER:
return OpenOffer.fromProto(tradable.getOpenOffer(), openOfferStorage);*/ return OpenOffer.fromProto(tradable.getOpenOffer());
case BUYER_AS_MAKER_TRADE: case BUYER_AS_MAKER_TRADE:
return BuyerAsMakerTrade.fromProto(tradable.getBuyerAsMakerTrade(), buyerAsMakerTradeStorage, btcWalletService); return BuyerAsMakerTrade.fromProto(tradable.getBuyerAsMakerTrade(), buyerAsMakerTradeStorage, btcWalletService);
case BUYER_AS_TAKER_TRADE: case BUYER_AS_TAKER_TRADE:
@ -112,6 +115,58 @@ public final class TradableList<T extends Tradable> implements PersistableEnvelo
return null; return null;
} }
/* public static TradableList fromProto(PB.TradeList proto,
CorePersistenceProtoResolver corePersistenceProtoResolver,
Storage<TradableList<BuyerAsMakerTrade>> buyerAsMakerTradeStorage,
Storage<TradableList<BuyerAsTakerTrade>> buyerAsTakerTradeStorage,
Storage<TradableList<SellerAsMakerTrade>> sellerAsMakerTradeStorage,
Storage<TradableList<SellerAsTakerTrade>> sellerAsTakerTradeStorage,
BtcWalletService btcWalletService) {
log.error("fromProto " + proto);
List list = proto.getTradeList().stream().map(trade -> {
// corePersistenceProtoResolver.fromProto(trade, st)
switch (trade.getMessageCase()) {
case OPEN_OFFER:
return OpenOffer.fromProto(trade.getOpenOffer());
case BUYER_AS_MAKER_TRADE:
return BuyerAsMakerTrade.fromProto(trade.getBuyerAsMakerTrade(), buyerAsMakerTradeStorage, btcWalletService);
case BUYER_AS_TAKER_TRADE:
return BuyerAsTakerTrade.fromProto(trade.getBuyerAsTakerTrade(), buyerAsTakerTradeStorage, btcWalletService);
case SELLER_AS_MAKER_TRADE:
return SellerAsMakerTrade.fromProto(trade.getSellerAsMakerTrade(), sellerAsMakerTradeStorage, btcWalletService);
case SELLER_AS_TAKER_TRADE:
return SellerAsTakerTrade.fromProto(trade.getSellerAsTakerTrade(), sellerAsTakerTradeStorage, btcWalletService);
}
return null;
}).collect(Collectors.toList());
switch (list.get(0).getClass().getSimpleName()) {
case "OpenOffer":
return new TradableList<OpenOffer>(openOfferStorage, list);
case "BuyerAsMakerTrade":
return new TradableList<BuyerAsMakerTrade>(buyerAsMakerTradeStorage, list);
case "BuyerAsTakerTrade":
return new TradableList<BuyerAsTakerTrade>(buyerAsTakerTradeStorage, list);
case "SellerAsMakerTrade":
return new TradableList<SellerAsMakerTrade>(sellerAsMakerTradeStorage, list);
case "SellerAsTakerTrade":
return new TradableList<SellerAsTakerTrade>(sellerAsTakerTradeStorage, list);
}
return null;
}*/
public static TradableList fromProto(PB.OpenOfferList proto,
Storage<TradableList<OpenOffer>> openOfferStorage) {
return new TradableList<>(openOfferStorage,
proto.getOpenOfferList().stream()
.map(OpenOffer::fromProto)
.collect(Collectors.toList())
);
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// API // API

View file

@ -46,17 +46,20 @@ import io.bisq.network.p2p.DecryptedMessageWithPubKey;
import io.bisq.network.p2p.NodeAddress; import io.bisq.network.p2p.NodeAddress;
import io.bisq.network.p2p.P2PService; import io.bisq.network.p2p.P2PService;
import javafx.beans.property.*; import javafx.beans.property.*;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.core.TransactionConfidence;
import org.bouncycastle.util.encoders.Hex;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -65,13 +68,17 @@ import static com.google.common.base.Preconditions.checkNotNull;
* Holds all data which are relevant to the trade, but not those which are only needed in the trade process as shared data between tasks. Those data are * Holds all data which are relevant to the trade, but not those which are only needed in the trade process as shared data between tasks. Those data are
* stored in the task model. * stored in the task model.
*/ */
@Slf4j
public abstract class Trade implements Tradable, Model { public abstract class Trade implements Tradable, Model {
private static final Logger log = LoggerFactory.getLogger(Trade.class);
///////////////////////////////////////////////////////////////////////////////////////////
// Enums
///////////////////////////////////////////////////////////////////////////////////////////
public enum State { public enum State {
// #################### Phase PREPARATION // #################### Phase PREPARATION
// When trade protocol starts no funds are on stake // When trade protocol starts no funds are on stake
PREPARATION(Phase.PREPARATION), PREPARATION(Phase.INIT),
// At first part maker/taker have different roles // At first part maker/taker have different roles
// taker perspective // taker perspective
@ -140,6 +147,7 @@ public abstract class Trade implements Tradable, Model {
// #################### Phase WITHDRAWN // #################### Phase WITHDRAWN
WITHDRAW_COMPLETED(Phase.WITHDRAWN); WITHDRAW_COMPLETED(Phase.WITHDRAWN);
@NotNull
public Phase getPhase() { public Phase getPhase() {
return phase; return phase;
} }
@ -153,7 +161,7 @@ public abstract class Trade implements Tradable, Model {
} }
public enum Phase { public enum Phase {
PREPARATION, INIT,
TAKER_FEE_PUBLISHED, TAKER_FEE_PUBLISHED,
DEPOSIT_PUBLISHED, DEPOSIT_PUBLISHED,
DEPOSIT_CONFIRMED, DEPOSIT_CONFIRMED,
@ -164,15 +172,15 @@ public abstract class Trade implements Tradable, Model {
} }
public enum DisputeState { public enum DisputeState {
NONE, NO_DISPUTE,
DISPUTE_REQUESTED, DISPUTE_REQUESTED,
DISPUTE_STARTED_BY_PEER, DISPUTE_STARTED_BY_PEER,
DISPUTE_CLOSED DISPUTE_CLOSED
} }
public enum TradePeriodState { public enum TradePeriodState {
NORMAL, FIRST_HALF,
HALF_REACHED, SECOND_HALF,
TRADE_PERIOD_OVER TRADE_PERIOD_OVER
} }
@ -181,57 +189,89 @@ public abstract class Trade implements Tradable, Model {
// Fields // Fields
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Persistable
// Immutable
@Getter
private final Offer offer; private final Offer offer;
@Getter
private final boolean isCurrencyForTakerFeeBtc;
@Getter
private final long txFeeAsLong;
@Getter
private final long takerFeeAsLong;
private final long takeOfferDate;
@Getter
private final ProcessModel processModel; private final ProcessModel processModel;
@Nullable // Mutable
@Nullable @Getter @Setter
private String takerFeeTxId; private String takerFeeTxId;
@Nullable @Nullable @Getter @Setter
private String depositTxId; private String depositTxId;
@Nullable @Nullable @Getter @Setter
private String payoutTxId; private String payoutTxId;
@Getter @Setter
private long tradeAmountAsLong; private long tradeAmountAsLong;
private long txFeeAsLong; @Setter
private long takerFeeAsLong;
private long takeOfferDate;
private boolean isCurrencyForTakerFeeBtc;
private long tradePrice; private long tradePrice;
@Nullable @Getter
private NodeAddress tradingPeerNodeAddress; private NodeAddress tradingPeerNodeAddress;
@Getter
private State state; private State state = State.PREPARATION;
private DisputeState disputeState; @Getter
private TradePeriodState tradePeriodState; private DisputeState disputeState = DisputeState.NO_DISPUTE;
@Getter
private TradePeriodState tradePeriodState = TradePeriodState.FIRST_HALF;
@Nullable @Getter @Setter
private Contract contract; private Contract contract;
@Nullable @Getter @Setter
private String contractAsJson; private String contractAsJson;
@Nullable @Getter @Setter
private byte[] contractHash; private byte[] contractHash;
@Nullable @Getter @Setter
private String takerContractSignature; private String takerContractSignature;
@Nullable @Getter @Setter
private String makerContractSignature; private String makerContractSignature;
@Nullable @Getter
private NodeAddress arbitratorNodeAddress; private NodeAddress arbitratorNodeAddress;
@Nullable @Getter
private NodeAddress mediatorNodeAddress; private NodeAddress mediatorNodeAddress;
@Nullable @Setter
private byte[] arbitratorBtcPubKey; private byte[] arbitratorBtcPubKey;
@Nullable @Getter @Setter
private String takerPaymentAccountId; private String takerPaymentAccountId;
@Nullable @Nullable
private String errorMessage; private String errorMessage;
// Transient
// Immutable
@Getter
transient final private Coin txFee;
@Getter
transient final private Coin takerFee;
@Getter // to set in constructor so not final but set at init
transient private Storage<? extends TradableList> storage; transient private Storage<? extends TradableList> storage;
@Getter // to set in constructor so not final but set at init
transient private BtcWalletService btcWalletService; transient private BtcWalletService btcWalletService;
transient final private ObjectProperty<State> stateProperty = new SimpleObjectProperty<>(state);
transient final private ObjectProperty<Phase> statePhaseProperty = new SimpleObjectProperty<>(state.phase);
transient final private ObjectProperty<DisputeState> disputeStateProperty = new SimpleObjectProperty<>(disputeState);
transient final private ObjectProperty<TradePeriodState> tradePeriodStateProperty = new SimpleObjectProperty<>(tradePeriodState);
transient final private StringProperty errorMessageProperty = new SimpleStringProperty(errorMessage);
// Mutable
transient protected TradeProtocol tradeProtocol; transient protected TradeProtocol tradeProtocol;
@Nullable @Setter
transient private Date maxTradePeriodDate, halfTradePeriodDate; transient private Date maxTradePeriodDate, halfTradePeriodDate;
@Nullable @Nullable
transient private Transaction payoutTx; transient private Transaction payoutTx;
@Nullable @Nullable
transient private Transaction depositTx; transient private Transaction depositTx;
@Nullable
transient private Coin tradeAmount; transient private Coin tradeAmount;
transient private Coin txFee;
transient private Coin takerFee;
transient private ObjectProperty<State> stateProperty;
transient private ObjectProperty<Phase> statePhaseProperty;
transient private ObjectProperty<DisputeState> disputeStateProperty;
transient private ObjectProperty<TradePeriodState> tradePeriodStateProperty;
transient private StringProperty errorMessageProperty;
transient private ObjectProperty<Coin> tradeAmountProperty; transient private ObjectProperty<Coin> tradeAmountProperty;
transient private ObjectProperty<Volume> tradeVolumeProperty; transient private ObjectProperty<Volume> tradeVolumeProperty;
transient private Set<DecryptedMessageWithPubKey> decryptedMessageWithPubKeySet = new HashSet<>(); transient private Set<DecryptedMessageWithPubKey> decryptedMessageWithPubKeySet = new HashSet<>();
@ -254,13 +294,14 @@ public abstract class Trade implements Tradable, Model {
this.isCurrencyForTakerFeeBtc = isCurrencyForTakerFeeBtc; this.isCurrencyForTakerFeeBtc = isCurrencyForTakerFeeBtc;
this.storage = storage; this.storage = storage;
this.btcWalletService = btcWalletService; this.btcWalletService = btcWalletService;
this.txFeeAsLong = txFee.value;
this.takerFeeAsLong = takerFee.value;
this.setTakeOfferDate(new Date()); txFeeAsLong = txFee.value;
takerFeeAsLong = takerFee.value;
takeOfferDate = new Date().getTime();
processModel = new ProcessModel(); processModel = new ProcessModel();
} }
// taker // taker
protected Trade(Offer offer, protected Trade(Offer offer,
Coin tradeAmount, Coin tradeAmount,
@ -275,12 +316,53 @@ public abstract class Trade implements Tradable, Model {
this(offer, txFee, takerFee, isCurrencyForTakerFeeBtc, storage, btcWalletService); this(offer, txFee, takerFee, isCurrencyForTakerFeeBtc, storage, btcWalletService);
this.tradePrice = tradePrice; this.tradePrice = tradePrice;
this.tradingPeerNodeAddress = tradingPeerNodeAddress; this.tradingPeerNodeAddress = tradingPeerNodeAddress;
this.setTradeAmount(tradeAmount);
getTradeAmountProperty().set(tradeAmount); setTradeAmount(tradeAmount);
getTradeVolumeProperty().set(getTradeVolume());
this.setTakeOfferDate(new Date());
} }
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public Message toProtoMessage() {
final PB.Trade.Builder builder = PB.Trade.newBuilder()
.setOffer(offer.toProtoMessage())
.setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc)
.setTxFeeAsLong(txFeeAsLong)
.setTakerFeeAsLong(takerFeeAsLong)
.setTakeOfferDate(takeOfferDate)
.setTradeAmountAsLong(tradeAmountAsLong)
.setTradePrice(tradePrice)
.setProcessModel(processModel.toProtoMessage())
.setState(PB.Trade.State.valueOf(state.name()))
.setDisputeState(PB.Trade.DisputeState.valueOf(disputeState.name()))
.setTradePeriodState(PB.Trade.TradePeriodState.valueOf(tradePeriodState.name()));
Optional.ofNullable(takerFeeTxId).ifPresent(builder::setTakerFeeTxId);
Optional.ofNullable(depositTxId).ifPresent(builder::setDepositTxId);
Optional.ofNullable(payoutTxId).ifPresent(builder::setPayoutTxId);
Optional.ofNullable(tradingPeerNodeAddress).ifPresent(e -> builder.setTradingPeerNodeAddress(tradingPeerNodeAddress.toProtoMessage()));
Optional.ofNullable(contract).ifPresent(e -> builder.setContract(contract.toProtoMessage()));
Optional.ofNullable(contractAsJson).ifPresent(builder::setContractAsJson);
Optional.ofNullable(contractHash).ifPresent(e -> builder.setContractHash(ByteString.copyFrom(contractHash)));
Optional.ofNullable(takerContractSignature).ifPresent(builder::setTakerContractSignature);
Optional.ofNullable(makerContractSignature).ifPresent(builder::setMakerContractSignature);
Optional.ofNullable(arbitratorNodeAddress).ifPresent(e -> builder.setArbitratorNodeAddress(arbitratorNodeAddress.toProtoMessage()));
Optional.ofNullable(mediatorNodeAddress).ifPresent(e -> builder.setMediatorNodeAddress(mediatorNodeAddress.toProtoMessage()));
Optional.ofNullable(arbitratorBtcPubKey).ifPresent(e -> builder.setArbitratorBtcPubKey(ByteString.copyFrom(arbitratorBtcPubKey)));
Optional.ofNullable(takerPaymentAccountId).ifPresent(builder::setTakerPaymentAccountId);
Optional.ofNullable(errorMessage).ifPresent(builder::setErrorMessage);
return builder.build();
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void setTransientFields(Storage<? extends TradableList> storage, BtcWalletService btcWalletService) { public void setTransientFields(Storage<? extends TradableList> storage, BtcWalletService btcWalletService) {
this.storage = storage; this.storage = storage;
this.btcWalletService = btcWalletService; this.btcWalletService = btcWalletService;
@ -316,8 +398,7 @@ public abstract class Trade implements Tradable, Model {
// if we have already received a msg we apply it. // if we have already received a msg we apply it.
// removeDecryptedMsgWithPubKey will be called synchronous after apply. We don't have threaded context // removeDecryptedMsgWithPubKey will be called synchronous after apply. We don't have threaded context
// or async calls there. // or async calls there.
log.trace("init: getMailboxMessageSet() = " + getDecryptedMessageWithPubKeySet()); decryptedMessageWithPubKeySet.stream()
getDecryptedMessageWithPubKeySet().stream()
.forEach(msg -> tradeProtocol.applyMailboxMessage(msg, this)); .forEach(msg -> tradeProtocol.applyMailboxMessage(msg, this));
} }
@ -352,8 +433,8 @@ public abstract class Trade implements Tradable, Model {
// received the msb but before the init is called. // received the msb but before the init is called.
public void addDecryptedMessageWithPubKey(DecryptedMessageWithPubKey decryptedMessageWithPubKey) { public void addDecryptedMessageWithPubKey(DecryptedMessageWithPubKey decryptedMessageWithPubKey) {
log.trace("addDecryptedMessageWithPubKey decryptedMessageWithPubKey=" + decryptedMessageWithPubKey); log.trace("addDecryptedMessageWithPubKey decryptedMessageWithPubKey=" + decryptedMessageWithPubKey);
if (!getDecryptedMessageWithPubKeySet().contains(decryptedMessageWithPubKey)) { if (!decryptedMessageWithPubKeySet.contains(decryptedMessageWithPubKey)) {
getDecryptedMessageWithPubKeySet().add(decryptedMessageWithPubKey); decryptedMessageWithPubKeySet.add(decryptedMessageWithPubKey);
// If we have already initialized we apply. // If we have already initialized we apply.
// removeDecryptedMsgWithPubKey will be called synchronous after apply. We don't have threaded context // removeDecryptedMsgWithPubKey will be called synchronous after apply. We don't have threaded context
@ -365,13 +446,39 @@ public abstract class Trade implements Tradable, Model {
public void removeDecryptedMessageWithPubKey(DecryptedMessageWithPubKey decryptedMessageWithPubKey) { public void removeDecryptedMessageWithPubKey(DecryptedMessageWithPubKey decryptedMessageWithPubKey) {
log.trace("removeDecryptedMessageWithPubKey decryptedMessageWithPubKey=" + decryptedMessageWithPubKey); log.trace("removeDecryptedMessageWithPubKey decryptedMessageWithPubKey=" + decryptedMessageWithPubKey);
if (getDecryptedMessageWithPubKeySet().contains(decryptedMessageWithPubKey)) if (decryptedMessageWithPubKeySet.contains(decryptedMessageWithPubKey))
getDecryptedMessageWithPubKeySet().remove(decryptedMessageWithPubKey); decryptedMessageWithPubKeySet.remove(decryptedMessageWithPubKey);
} }
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// States // Model implementation
///////////////////////////////////////////////////////////////////////////////////////////
// Get called from taskRunner after each completed task
@Override
public void persist() {
if (storage != null)
storage.queueUpForSave();
}
@Override
public void onComplete() {
persist();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Abstract
///////////////////////////////////////////////////////////////////////////////////////////
abstract protected void createTradeProtocol();
abstract public Coin getPayoutAmount();
///////////////////////////////////////////////////////////////////////////////////////////
// Setters
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
public void setState(State state) { public void setState(State state) {
@ -379,8 +486,8 @@ public abstract class Trade implements Tradable, Model {
if (state.getPhase().ordinal() >= this.state.getPhase().ordinal()) { if (state.getPhase().ordinal() >= this.state.getPhase().ordinal()) {
boolean changed = this.state != state; boolean changed = this.state != state;
this.state = state; this.state = state;
getStateProperty().set(state); stateProperty.set(state);
getStatePhaseProperty().set(state.getPhase()); statePhaseProperty.set(state.getPhase());
if (state == State.WITHDRAW_COMPLETED && tradeProtocol != null) if (state == State.WITHDRAW_COMPLETED && tradeProtocol != null)
tradeProtocol.completed(); tradeProtocol.completed();
@ -400,33 +507,98 @@ public abstract class Trade implements Tradable, Model {
Log.traceCall("disputeState=" + disputeState + "\n\ttrade=" + this); Log.traceCall("disputeState=" + disputeState + "\n\ttrade=" + this);
boolean changed = this.disputeState != disputeState; boolean changed = this.disputeState != disputeState;
this.disputeState = disputeState; this.disputeState = disputeState;
getDisputeStateProperty().set(disputeState); disputeStateProperty.set(disputeState);
if (changed) if (changed)
persist(); persist();
} }
public DisputeState getDisputeState() {
if (disputeState == null)
disputeState = DisputeState.NONE;
return disputeState;
}
public void setTradePeriodState(TradePeriodState tradePeriodState) { public void setTradePeriodState(TradePeriodState tradePeriodState) {
boolean changed = this.tradePeriodState != tradePeriodState; boolean changed = this.tradePeriodState != tradePeriodState;
this.tradePeriodState = tradePeriodState; this.tradePeriodState = tradePeriodState;
getTradePeriodStateProperty().set(tradePeriodState); tradePeriodStateProperty.set(tradePeriodState);
if (changed) if (changed)
persist(); persist();
} }
public TradePeriodState getTradePeriodState() { public void setTradingPeerNodeAddress(NodeAddress tradingPeerNodeAddress) {
if (tradePeriodState == null) if (tradingPeerNodeAddress == null)
tradePeriodState = TradePeriodState.NORMAL; log.error("tradingPeerAddress=null");
return tradePeriodState; else
this.tradingPeerNodeAddress = tradingPeerNodeAddress;
}
public void setTradeAmount(Coin tradeAmount) {
this.tradeAmount = tradeAmount;
tradeAmountAsLong = tradeAmount.value;
getTradeAmountProperty().set(tradeAmount);
getTradeVolumeProperty().set(getTradeVolume());
}
public void setPayoutTx(Transaction payoutTx) {
this.payoutTx = payoutTx;
payoutTxId = payoutTx.getHashAsString();
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
errorMessageProperty.set(errorMessage);
}
public void setArbitratorNodeAddress(NodeAddress arbitratorNodeAddress) {
this.arbitratorNodeAddress = arbitratorNodeAddress;
Arbitrator arbitrator = processModel.getUser().getAcceptedArbitratorByAddress(arbitratorNodeAddress);
checkNotNull(arbitrator, "arbitrator must not be null");
arbitratorBtcPubKey = arbitrator.getBtcPubKey();
}
public void setMediatorNodeAddress(NodeAddress mediatorNodeAddress) {
this.mediatorNodeAddress = mediatorNodeAddress;
Mediator mediator = processModel.getUser().getAcceptedMediatorByAddress(mediatorNodeAddress);
checkNotNull(mediator, "mediator must not be null");
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter
///////////////////////////////////////////////////////////////////////////////////////////
public Date getTakeOfferDate() {
return new Date(takeOfferDate);
}
@Nullable
public Volume getTradeVolume() {
if (getTradeAmount() != null && getTradePrice() != null)
return getTradePrice().getVolumeByAmount(getTradeAmount());
else
return null;
}
@Nullable
public Date getMaxTradePeriodDate() {
if (maxTradePeriodDate == null && getTakeOfferDate() != null)
maxTradePeriodDate = new Date(getTakeOfferDate().getTime() + getOffer().getPaymentMethod().getMaxTradePeriod());
return maxTradePeriodDate;
}
@Nullable
public Date getHalfTradePeriodDate() {
if (halfTradePeriodDate == null && getTakeOfferDate() != null)
halfTradePeriodDate = new Date(getTakeOfferDate().getTime() + getOffer().getPaymentMethod().getMaxTradePeriod() / 2);
return halfTradePeriodDate;
}
public boolean hasFailed() {
return errorMessageProperty().get() != null;
} }
public boolean isInPreparation() { public boolean isInPreparation() {
return getState().getPhase().ordinal() == Phase.PREPARATION.ordinal(); return getState().getPhase().ordinal() == Phase.INIT.ordinal();
} }
public boolean isTakerFeePublished() { public boolean isTakerFeePublished() {
@ -457,193 +629,47 @@ public abstract class Trade implements Tradable, Model {
return getState().getPhase().ordinal() == Phase.WITHDRAWN.ordinal(); return getState().getPhase().ordinal() == Phase.WITHDRAWN.ordinal();
} }
public State getState() { public ReadOnlyObjectProperty<State> stateProperty() {
if (state == null)
state = State.PREPARATION;
return state;
}
public StringProperty getErrorMessageProperty() {
if (errorMessageProperty == null)
errorMessageProperty = new SimpleStringProperty(errorMessage);
return errorMessageProperty;
}
//TODO can be removed after PB is applied. mailboxMessageSet can be used then instead of getMailboxMessageSet().
private Set<DecryptedMessageWithPubKey> getDecryptedMessageWithPubKeySet() {
if (decryptedMessageWithPubKeySet == null)
decryptedMessageWithPubKeySet = new HashSet<>();
return decryptedMessageWithPubKeySet;
}
public ObjectProperty<Coin> getTradeAmountProperty() {
if (tradeAmountProperty == null)
tradeAmountProperty = getTradeAmount() != null ? new SimpleObjectProperty<>(getTradeAmount()) : new SimpleObjectProperty<>();
return tradeAmountProperty;
}
public ObjectProperty<Volume> getTradeVolumeProperty() {
if (tradeVolumeProperty == null)
tradeVolumeProperty = getTradeVolume() != null ? new SimpleObjectProperty<>(getTradeVolume()) : new SimpleObjectProperty<>();
return tradeVolumeProperty;
}
public Date getTakeOfferDate() {
return new Date(takeOfferDate);
}
public void setTakeOfferDate(Date takeOfferDate) {
this.takeOfferDate = takeOfferDate.getTime();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Model implementation
///////////////////////////////////////////////////////////////////////////////////////////
// Get called from taskRunner after each completed task
@Override
public void persist() {
if (storage != null)
storage.queueUpForSave();
}
@Override
public void onComplete() {
persist();
}
///////////////////////////////////////////////////////////////////////////////////////////
// Getter only
///////////////////////////////////////////////////////////////////////////////////////////
public String getId() {
return offer.getId();
}
public String getShortId() {
return offer.getShortId();
}
public Offer getOffer() {
return offer;
}
abstract public Coin getPayoutAmount();
public ProcessModel getProcessModel() {
return processModel;
}
@Nullable
public Volume getTradeVolume() {
if (getTradeAmount() != null && getTradePrice() != null)
return getTradePrice().getVolumeByAmount(getTradeAmount());
else
return null;
}
@Nullable
public Date getMaxTradePeriodDate() {
if (maxTradePeriodDate == null && getTakeOfferDate() != null)
maxTradePeriodDate = new Date(getTakeOfferDate().getTime() + getOffer().getPaymentMethod().getMaxTradePeriod());
return maxTradePeriodDate;
}
@Nullable
public Date getHalfTradePeriodDate() {
if (halfTradePeriodDate == null && getTakeOfferDate() != null)
halfTradePeriodDate = new Date(getTakeOfferDate().getTime() + getOffer().getPaymentMethod().getMaxTradePeriod() / 2);
return halfTradePeriodDate;
}
public boolean hasFailed() {
return errorMessageProperty().get() != null;
}
private ObjectProperty<State> getStateProperty() {
if (stateProperty == null)
stateProperty = new SimpleObjectProperty<>(getState());
return stateProperty; return stateProperty;
} }
private ObjectProperty<Phase> getStatePhaseProperty() { public ReadOnlyObjectProperty<Phase> statePhaseProperty() {
if (statePhaseProperty == null)
statePhaseProperty = new SimpleObjectProperty<>(getState().phase);
return statePhaseProperty; return statePhaseProperty;
} }
private ObjectProperty<DisputeState> getDisputeStateProperty() { public ReadOnlyObjectProperty<DisputeState> disputeStateProperty() {
if (disputeStateProperty == null)
disputeStateProperty = new SimpleObjectProperty<>(getDisputeState());
return disputeStateProperty; return disputeStateProperty;
} }
private ObjectProperty<TradePeriodState> getTradePeriodStateProperty() { public ReadOnlyObjectProperty<TradePeriodState> tradePeriodStateProperty() {
if (tradePeriodStateProperty == null)
tradePeriodStateProperty = new SimpleObjectProperty<>(getTradePeriodState());
return tradePeriodStateProperty; return tradePeriodStateProperty;
} }
public ReadOnlyObjectProperty<State> stateProperty() {
return getStateProperty();
}
public ReadOnlyObjectProperty<Phase> statePhaseProperty() {
return getStatePhaseProperty();
}
public ReadOnlyObjectProperty<DisputeState> disputeStateProperty() {
return getDisputeStateProperty();
}
public ReadOnlyObjectProperty<TradePeriodState> tradePeriodStateProperty() {
return getTradePeriodStateProperty();
}
public ReadOnlyObjectProperty<Coin> tradeAmountProperty() { public ReadOnlyObjectProperty<Coin> tradeAmountProperty() {
return getTradeAmountProperty(); return tradeAmountProperty;
} }
public ReadOnlyObjectProperty<Volume> tradeVolumeProperty() { public ReadOnlyObjectProperty<Volume> tradeVolumeProperty() {
return getTradeVolumeProperty(); return tradeVolumeProperty;
} }
public ReadOnlyStringProperty errorMessageProperty() {
return errorMessageProperty;
}
/////////////////////////////////////////////////////////////////////////////////////////// @Override
// Getter/Setter for Mutable objects
///////////////////////////////////////////////////////////////////////////////////////////
public Date getDate() { public Date getDate() {
return getTakeOfferDate(); return getTakeOfferDate();
} }
public void setTradingPeerNodeAddress(NodeAddress tradingPeerNodeAddress) { @Override
if (tradingPeerNodeAddress == null) public String getId() {
log.error("tradingPeerAddress=null"); return offer.getId();
else
this.tradingPeerNodeAddress = tradingPeerNodeAddress;
} }
@Nullable @Override
public NodeAddress getTradingPeerNodeAddress() { public String getShortId() {
return tradingPeerNodeAddress; return offer.getShortId();
}
public void setTradeAmount(Coin tradeAmount) {
this.tradeAmount = tradeAmount;
tradeAmountAsLong = tradeAmount.value;
getTradeAmountProperty().set(tradeAmount);
getTradeVolumeProperty().set(getTradeVolume());
}
public void setTradePrice(long tradePrice) {
this.tradePrice = tradePrice;
} }
public Price getTradePrice() { public Price getTradePrice() {
@ -657,59 +683,6 @@ public abstract class Trade implements Tradable, Model {
return tradeAmount; return tradeAmount;
} }
public Coin getTxFee() {
if (txFee == null)
txFee = Coin.valueOf(txFeeAsLong);
return txFee;
}
public Coin getTakerFee() {
if (takerFee == null)
takerFee = Coin.valueOf(takerFeeAsLong);
return takerFee;
}
public void setTakerContractSignature(String takerSignature) {
this.takerContractSignature = takerSignature;
}
@Nullable
public String getTakerContractSignature() {
return takerContractSignature;
}
public void setMakerContractSignature(String makerContractSignature) {
this.makerContractSignature = makerContractSignature;
}
@Nullable
public String getMakerContractSignature() {
return makerContractSignature;
}
public void setContractAsJson(String contractAsJson) {
this.contractAsJson = contractAsJson;
}
@Nullable
public String getContractAsJson() {
return contractAsJson;
}
public void setContract(Contract contract) {
this.contract = contract;
}
@Nullable
public Contract getContract() {
return contract;
}
public void setPayoutTx(Transaction payoutTx) {
this.payoutTx = payoutTx;
payoutTxId = payoutTx.getHashAsString();
}
@Nullable @Nullable
public Transaction getPayoutTx() { public Transaction getPayoutTx() {
if (payoutTx == null) if (payoutTx == null)
@ -717,29 +690,8 @@ public abstract class Trade implements Tradable, Model {
return payoutTx; return payoutTx;
} }
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
getErrorMessageProperty().set(errorMessage);
}
public ReadOnlyStringProperty errorMessageProperty() {
return getErrorMessageProperty();
}
public String getErrorMessage() { public String getErrorMessage() {
return getErrorMessageProperty().get(); return errorMessageProperty.get();
}
public NodeAddress getArbitratorNodeAddress() {
return arbitratorNodeAddress;
}
public void applyArbitratorNodeAddress(NodeAddress arbitratorNodeAddress) {
this.arbitratorNodeAddress = arbitratorNodeAddress;
Arbitrator arbitrator = processModel.getUser().getAcceptedArbitratorByAddress(arbitratorNodeAddress);
checkNotNull(arbitrator, "arbitrator must not be null");
arbitratorBtcPubKey = arbitrator.getBtcPubKey();
} }
public byte[] getArbitratorBtcPubKey() { public byte[] getArbitratorBtcPubKey() {
@ -751,58 +703,29 @@ public abstract class Trade implements Tradable, Model {
return arbitratorBtcPubKey; return arbitratorBtcPubKey;
} }
public NodeAddress getMediatorNodeAddress() {
return mediatorNodeAddress;
}
public void applyMediatorNodeAddress(NodeAddress mediatorNodeAddress) {
this.mediatorNodeAddress = mediatorNodeAddress;
Mediator mediator = processModel.getUser().getAcceptedMediatorByAddress(mediatorNodeAddress);
checkNotNull(mediator, "mediator must not be null");
}
public String getTakerPaymentAccountId() {
return takerPaymentAccountId;
}
public void setTakerPaymentAccountId(String takerPaymentAccountId) {
this.takerPaymentAccountId = takerPaymentAccountId;
}
public void setContractHash(byte[] contractHash) {
this.contractHash = contractHash;
}
public byte[] getContractHash() {
return contractHash;
}
public void setTakerFeeTxId(String takerFeeTxId) {
this.takerFeeTxId = takerFeeTxId;
}
@org.jetbrains.annotations.Nullable
public String getTakerFeeTxId() {
return takerFeeTxId;
}
public boolean isCurrencyForTakerFeeBtc() {
return isCurrencyForTakerFeeBtc;
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Private // Private
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// lazy initialization
private ObjectProperty<Coin> getTradeAmountProperty() {
if (tradeAmountProperty == null)
tradeAmountProperty = getTradeAmount() != null ? new SimpleObjectProperty<>(getTradeAmount()) : new SimpleObjectProperty<>();
return tradeAmountProperty;
}
// lazy initialization
private ObjectProperty<Volume> getTradeVolumeProperty() {
if (tradeVolumeProperty == null)
tradeVolumeProperty = getTradeVolume() != null ? new SimpleObjectProperty<>(getTradeVolume()) : new SimpleObjectProperty<>();
return tradeVolumeProperty;
}
private void setupConfidenceListener() { private void setupConfidenceListener() {
log.debug("setupConfidenceListener");
if (getDepositTx() != null) { if (getDepositTx() != null) {
TransactionConfidence transactionConfidence = getDepositTx().getConfidence(); TransactionConfidence transactionConfidence = getDepositTx().getConfidence();
log.debug("transactionConfidence " + transactionConfidence.getDepthInBlocks());
if (transactionConfidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) { if (transactionConfidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) {
setConfirmedState(); setConfirmedState();
} else { } else {
@ -810,8 +733,6 @@ public abstract class Trade implements Tradable, Model {
Futures.addCallback(future, new FutureCallback<TransactionConfidence>() { Futures.addCallback(future, new FutureCallback<TransactionConfidence>() {
@Override @Override
public void onSuccess(TransactionConfidence result) { public void onSuccess(TransactionConfidence result) {
log.debug("transactionConfidence " + transactionConfidence.getDepthInBlocks());
log.debug("state " + getState());
setConfirmedState(); setConfirmedState();
} }
@ -828,46 +749,61 @@ public abstract class Trade implements Tradable, Model {
} }
} }
abstract protected void createTradeProtocol();
private void setConfirmedState() { private void setConfirmedState() {
// we only apply the state if we are not already further in the process // we only apply the state if we are not already further in the process
if (!isDepositConfirmed()) if (!isDepositConfirmed())
setState(State.DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN); setState(State.DEPOSIT_CONFIRMED_IN_BLOCK_CHAIN);
} }
@Override @Override public String toString() {
public Message toProtoMessage() { return "Trade{" +
return PB.Trade.newBuilder() "\n offer=" + offer +
.setOffer(offer.toProtoMessage()) ",\n isCurrencyForTakerFeeBtc=" + isCurrencyForTakerFeeBtc +
.setProcessModel((PB.ProcessModel) processModel.toProtoMessage()) ",\n txFeeAsLong=" + txFeeAsLong +
.setTakerFeeTxId(takerFeeTxId) ",\n takerFeeAsLong=" + takerFeeAsLong +
.setDepositTxId(depositTxId) ",\n takeOfferDate=" + getTakeOfferDate() +
.setPayoutTxId(payoutTxId) ",\n processModel=" + processModel +
.setTradeAmountAsLong(tradeAmountAsLong) ",\n takerFeeTxId='" + takerFeeTxId + '\'' +
.setTxFeeAsLong(txFeeAsLong) ",\n depositTxId='" + depositTxId + '\'' +
.setTakerFeeAsLong(takerFeeAsLong) ",\n payoutTxId='" + payoutTxId + '\'' +
.setTakeOfferDate(takeOfferDate) ",\n tradeAmountAsLong=" + tradeAmountAsLong +
.setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc) ",\n tradePrice=" + tradePrice +
.setTradePrice(tradePrice) ",\n tradingPeerNodeAddress=" + tradingPeerNodeAddress +
.setTradingPeerNodeAddress(tradingPeerNodeAddress.toProtoMessage()) ",\n state=" + state +
.setState(PB.Trade.State.valueOf(state.name())) ",\n disputeState=" + disputeState +
.setDisputeState(PB.Trade.DisputeState.valueOf(disputeState.name())) ",\n tradePeriodState=" + tradePeriodState +
.setTradePeriodState(PB.Trade.TradePeriodState.valueOf(tradePeriodState.name())) ",\n contract=" + contract +
.setContract(contract.toProtoMessage()) ",\n contractAsJson='" + contractAsJson + '\'' +
.setContractAsJson(contractAsJson) ",\n contractHash=" + Hex.toHexString(contractHash) +
.setContractHash(ByteString.copyFrom(contractHash)) ",\n takerContractSignature='" + takerContractSignature + '\'' +
.setTakerContractSignature(takerContractSignature) ",\n makerContractSignature='" + makerContractSignature + '\'' +
.setMakerContractSignature(makerContractSignature) ",\n arbitratorNodeAddress=" + arbitratorNodeAddress +
.setArbitratorNodeAddress(arbitratorNodeAddress.toProtoMessage()) ",\n mediatorNodeAddress=" + mediatorNodeAddress +
.setMediatorNodeAddress(mediatorNodeAddress.toProtoMessage()) ",\n arbitratorBtcPubKey=" + Hex.toHexString(arbitratorBtcPubKey) +
.setArbitratorBtcPubKey(ByteString.copyFrom(arbitratorBtcPubKey)) ",\n takerPaymentAccountId='" + takerPaymentAccountId + '\'' +
.setTakerPaymentAccountId(takerPaymentAccountId) ",\n errorMessage='" + errorMessage + '\'' +
.setErrorMessage(errorMessage) ",\n txFee=" + txFee +
.build(); ",\n takerFee=" + takerFee +
",\n storage=" + storage +
",\n btcWalletService=" + btcWalletService +
",\n stateProperty=" + stateProperty +
",\n statePhaseProperty=" + statePhaseProperty +
",\n disputeStateProperty=" + disputeStateProperty +
",\n tradePeriodStateProperty=" + tradePeriodStateProperty +
",\n errorMessageProperty=" + errorMessageProperty +
",\n tradeProtocol=" + tradeProtocol +
",\n maxTradePeriodDate=" + maxTradePeriodDate +
",\n halfTradePeriodDate=" + halfTradePeriodDate +
",\n payoutTx=" + payoutTx +
",\n depositTx=" + depositTx +
",\n tradeAmount=" + tradeAmount +
",\n tradeAmountProperty=" + tradeAmountProperty +
",\n tradeVolumeProperty=" + tradeVolumeProperty +
",\n decryptedMessageWithPubKeySet=" + decryptedMessageWithPubKeySet +
"\n}";
} }
@Override /* @Override
public String toString() { public String toString() {
return "Trade{" + return "Trade{" +
"\n\ttradeAmount=" + getTradeAmount() + "\n\ttradeAmount=" + getTradeAmount() +
@ -875,7 +811,7 @@ public abstract class Trade implements Tradable, Model {
"\n\ttradeVolume=" + getTradeVolumeProperty().get() + "\n\ttradeVolume=" + getTradeVolumeProperty().get() +
"\n\toffer=" + offer + "\n\toffer=" + offer +
"\n\tprocessModel=" + processModel + "\n\tprocessModel=" + processModel +
"\n\tdecryptedMsgWithPubKeySet=" + getDecryptedMessageWithPubKeySet() + "\n\tdecryptedMsgWithPubKeySet=" + decryptedMessageWithPubKeySet +
"\n\ttakeOfferDate=" + getTakeOfferDate() + "\n\ttakeOfferDate=" + getTakeOfferDate() +
"\n\tstate=" + getState() + "\n\tstate=" + getState() +
"\n\tdisputeState=" + getDisputeState() + "\n\tdisputeState=" + getDisputeState() +
@ -895,5 +831,5 @@ public abstract class Trade implements Tradable, Model {
"\n\ttakeOfferFee='" + getTakerFee().toFriendlyString() + '\'' + "\n\ttakeOfferFee='" + getTakerFee().toFriendlyString() + '\'' +
"\n\terrorMessage='" + errorMessage + '\'' + "\n\terrorMessage='" + errorMessage + '\'' +
'}'; '}';
} }*/
} }

View file

@ -25,6 +25,7 @@ import io.bisq.common.handlers.ErrorMessageHandler;
import io.bisq.common.handlers.FaultHandler; import io.bisq.common.handlers.FaultHandler;
import io.bisq.common.handlers.ResultHandler; import io.bisq.common.handlers.ResultHandler;
import io.bisq.common.proto.network.NetworkEnvelope; import io.bisq.common.proto.network.NetworkEnvelope;
import io.bisq.common.proto.persistable.PersistedDataHost;
import io.bisq.common.proto.persistable.PersistenceProtoResolver; import io.bisq.common.proto.persistable.PersistenceProtoResolver;
import io.bisq.common.storage.Storage; import io.bisq.common.storage.Storage;
import io.bisq.core.btc.AddressEntry; import io.bisq.core.btc.AddressEntry;
@ -75,7 +76,7 @@ import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
public class TradeManager { public class TradeManager implements PersistedDataHost {
private static final Logger log = LoggerFactory.getLogger(TradeManager.class); private static final Logger log = LoggerFactory.getLogger(TradeManager.class);
private final User user; private final User user;
@ -167,6 +168,16 @@ public class TradeManager {
}); });
} }
@Override
public void readPersisted() {
/* OpenOfferList persisted = openOffersStorage.initAndGetPersisted(openOfferList);
if (persisted != null)
openOfferList.addAll(persisted.getList());
observableList = FXCollections.observableArrayList(openOfferList.getList());
observableList.forEach(e -> e.getOffer().setPriceFeedService(priceFeedService));*/
}
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// Lifecycle // Lifecycle

View file

@ -19,6 +19,7 @@ package io.bisq.core.trade.closed;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bisq.common.crypto.KeyRing; import io.bisq.common.crypto.KeyRing;
import io.bisq.common.proto.persistable.PersistedDataHost;
import io.bisq.common.proto.persistable.PersistenceProtoResolver; import io.bisq.common.proto.persistable.PersistenceProtoResolver;
import io.bisq.common.storage.Storage; import io.bisq.common.storage.Storage;
import io.bisq.core.btc.wallet.BtcWalletService; import io.bisq.core.btc.wallet.BtcWalletService;
@ -35,7 +36,7 @@ import javax.inject.Named;
import java.io.File; import java.io.File;
import java.util.Optional; import java.util.Optional;
public class ClosedTradableManager { public class ClosedTradableManager implements PersistedDataHost {
private static final Logger log = LoggerFactory.getLogger(ClosedTradableManager.class); private static final Logger log = LoggerFactory.getLogger(ClosedTradableManager.class);
private final TradableList<Tradable> closedTrades; private final TradableList<Tradable> closedTrades;
private final KeyRing keyRing; private final KeyRing keyRing;
@ -59,6 +60,10 @@ public class ClosedTradableManager {
}); });
} }
@Override
public void readPersisted() {
}
public void add(Tradable tradable) { public void add(Tradable tradable) {
closedTrades.add(tradable); closedTrades.add(tradable);
} }

View file

@ -19,6 +19,7 @@ package io.bisq.core.trade.failed;
import com.google.inject.Inject; import com.google.inject.Inject;
import io.bisq.common.crypto.KeyRing; import io.bisq.common.crypto.KeyRing;
import io.bisq.common.proto.persistable.PersistedDataHost;
import io.bisq.common.proto.persistable.PersistenceProtoResolver; import io.bisq.common.proto.persistable.PersistenceProtoResolver;
import io.bisq.common.storage.Storage; import io.bisq.common.storage.Storage;
import io.bisq.core.btc.wallet.BtcWalletService; import io.bisq.core.btc.wallet.BtcWalletService;
@ -34,7 +35,7 @@ import javax.inject.Named;
import java.io.File; import java.io.File;
import java.util.Optional; import java.util.Optional;
public class FailedTradesManager { public class FailedTradesManager implements PersistedDataHost {
private static final Logger log = LoggerFactory.getLogger(FailedTradesManager.class); private static final Logger log = LoggerFactory.getLogger(FailedTradesManager.class);
private final TradableList<Trade> failedTrades; private final TradableList<Trade> failedTrades;
private final KeyRing keyRing; private final KeyRing keyRing;
@ -54,6 +55,9 @@ public class FailedTradesManager {
}); });
} }
@Override
public void readPersisted() {
}
public void add(Trade trade) { public void add(Trade trade) {
if (!failedTrades.contains(trade)) if (!failedTrades.contains(trade))
failedTrades.add(trade); failedTrades.add(trade);

View file

@ -58,7 +58,6 @@ public class BuyerAsMakerProtocol extends TradeProtocol implements BuyerProtocol
TradeTaskRunner taskRunner = new TradeTaskRunner(trade, TradeTaskRunner taskRunner = new TradeTaskRunner(trade,
() -> { () -> {
handleTaskRunnerSuccess("MakerSetupDepositTxListener"); handleTaskRunnerSuccess("MakerSetupDepositTxListener");
processModel.onComplete();
}, },
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
@ -68,7 +67,6 @@ public class BuyerAsMakerProtocol extends TradeProtocol implements BuyerProtocol
TradeTaskRunner taskRunner = new TradeTaskRunner(trade, TradeTaskRunner taskRunner = new TradeTaskRunner(trade,
() -> { () -> {
handleTaskRunnerSuccess("BuyerSetupPayoutTxListener"); handleTaskRunnerSuccess("BuyerSetupPayoutTxListener");
processModel.onComplete();
}, },
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
@ -194,7 +192,6 @@ public class BuyerAsMakerProtocol extends TradeProtocol implements BuyerProtocol
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsMakerTrade, TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsMakerTrade,
() -> { () -> {
handleTaskRunnerSuccess("handle PayoutTxPublishedMessage"); handleTaskRunnerSuccess("handle PayoutTxPublishedMessage");
processModel.onComplete();
}, },
this::handleTaskRunnerFault); this::handleTaskRunnerFault);

View file

@ -58,7 +58,6 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
TradeTaskRunner taskRunner = new TradeTaskRunner(trade, TradeTaskRunner taskRunner = new TradeTaskRunner(trade,
() -> { () -> {
handleTaskRunnerSuccess("BuyerSetupPayoutTxListener"); handleTaskRunnerSuccess("BuyerSetupPayoutTxListener");
processModel.onComplete();
}, },
this::handleTaskRunnerFault); this::handleTaskRunnerFault);
@ -179,7 +178,6 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol
TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsTakerTrade, TradeTaskRunner taskRunner = new TradeTaskRunner(buyerAsTakerTrade,
() -> { () -> {
handleTaskRunnerSuccess("handle PayoutTxPublishedMessage"); handleTaskRunnerSuccess("handle PayoutTxPublishedMessage");
processModel.onComplete();
}, },
this::handleTaskRunnerFault); this::handleTaskRunnerFault);

View file

@ -18,10 +18,9 @@
package io.bisq.core.trade.protocol; package io.bisq.core.trade.protocol;
import com.google.protobuf.ByteString; import com.google.protobuf.ByteString;
import com.google.protobuf.Message;
import io.bisq.common.crypto.KeyRing; import io.bisq.common.crypto.KeyRing;
import io.bisq.common.crypto.PubKeyRing; import io.bisq.common.crypto.PubKeyRing;
import io.bisq.common.proto.ProtoUtil; import io.bisq.common.proto.ProtoCollectionUtil;
import io.bisq.common.proto.persistable.PersistablePayload; import io.bisq.common.proto.persistable.PersistablePayload;
import io.bisq.common.taskrunner.Model; import io.bisq.common.taskrunner.Model;
import io.bisq.core.btc.data.RawTransactionInput; import io.bisq.core.btc.data.RawTransactionInput;
@ -47,6 +46,7 @@ import io.bisq.network.p2p.P2PService;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.NotImplementedException;
import org.bitcoinj.core.Coin; import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Transaction; import org.bitcoinj.core.Transaction;
@ -55,33 +55,23 @@ import javax.annotation.Nullable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
@Getter @Getter
@Slf4j @Slf4j
public class ProcessModel implements Model, PersistablePayload { public class ProcessModel implements Model, PersistablePayload {
// Transient/Immutable // Transient/Immutable (net set in constructor so they are not final, but at init)
@Getter
transient private TradeManager tradeManager; transient private TradeManager tradeManager;
@Getter
transient private OpenOfferManager openOfferManager; transient private OpenOfferManager openOfferManager;
transient private BtcWalletService btcWalletService; transient private BtcWalletService btcWalletService;
transient private BsqWalletService bsqWalletService; transient private BsqWalletService bsqWalletService;
transient private TradeWalletService tradeWalletService; transient private TradeWalletService tradeWalletService;
transient private Offer offer; transient private Offer offer;
@Getter
transient private User user; transient private User user;
transient private FilterManager filterManager; transient private FilterManager filterManager;
@Getter
transient private KeyRing keyRing; transient private KeyRing keyRing;
@Getter
transient private P2PService p2PService; transient private P2PService p2PService;
// Immutable
private final TradingPeer tradingPeer = new TradingPeer();
private String offerId;
private String accountId;
private PubKeyRing pubKeyRing;
// Transient/Mutable // Transient/Mutable
transient private Transaction takeOfferFeeTx; transient private Transaction takeOfferFeeTx;
@Setter @Setter
@ -89,38 +79,76 @@ public class ProcessModel implements Model, PersistablePayload {
@Setter @Setter
transient private DecryptedMessageWithPubKey decryptedMessageWithPubKey; transient private DecryptedMessageWithPubKey decryptedMessageWithPubKey;
// Mutable
// Persistable Immutable
private final TradingPeer tradingPeer = new TradingPeer();
private String offerId;
private String accountId;
private PubKeyRing pubKeyRing;
// Persistable Mutable
@Nullable
private String takeOfferFeeTxId; private String takeOfferFeeTxId;
@Setter @Nullable @Setter
private byte[] payoutTxSignature; private byte[] payoutTxSignature;
@Setter @Nullable @Setter
private List<NodeAddress> takerAcceptedArbitratorNodeAddresses; private List<NodeAddress> takerAcceptedArbitratorNodeAddresses;
@Setter @Nullable @Setter
private List<NodeAddress> takerAcceptedMediatorNodeAddresses; private List<NodeAddress> takerAcceptedMediatorNodeAddresses;
@Setter @Nullable @Setter
private byte[] preparedDepositTx; private byte[] preparedDepositTx;
@Setter @Nullable @Setter
private ArrayList<RawTransactionInput> rawTransactionInputs; private ArrayList<RawTransactionInput> rawTransactionInputs;
@Setter @Setter
private long changeOutputValue; private long changeOutputValue;
@Nullable @Nullable @Setter
@Setter
private String changeOutputAddress; private String changeOutputAddress;
@Setter @Setter
private boolean useSavingsWallet; private boolean useSavingsWallet;
@Setter @Setter
private long fundsNeededForTradeAsLong; private long fundsNeededForTradeAsLong;
@Setter @Nullable @Setter
private byte[] myMultiSigPubKey; private byte[] myMultiSigPubKey;
// that is used to store temp. the peers address when we get an incoming message before the message is verified. // that is used to store temp. the peers address when we get an incoming message before the message is verified.
// After successful verified we copy that over to the trade.tradingPeerAddress // After successful verified we copy that over to the trade.tradingPeerAddress
@Setter @Nullable @Setter
private NodeAddress tempTradingPeerNodeAddress; private NodeAddress tempTradingPeerNodeAddress;
public ProcessModel() { public ProcessModel() {
} }
///////////////////////////////////////////////////////////////////////////////////////////
// PROTO BUFFER
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public PB.ProcessModel toProtoMessage() {
final PB.ProcessModel.Builder builder = PB.ProcessModel.newBuilder()
.setTradingPeer((PB.TradingPeer) tradingPeer.toProtoMessage())
.setOfferId(offerId)
.setAccountId(accountId)
.setPubKeyRing(pubKeyRing.toProtoMessage())
.setChangeOutputValue(changeOutputValue)
.setFundsNeededForTradeAsLong(fundsNeededForTradeAsLong)
.setUseSavingsWallet(useSavingsWallet);
Optional.ofNullable(takeOfferFeeTxId).ifPresent(builder::setTakeOfferFeeTxId);
Optional.ofNullable(payoutTxSignature).ifPresent(e -> builder.setPayoutTxSignature(ByteString.copyFrom(payoutTxSignature)));
Optional.ofNullable(takerAcceptedArbitratorNodeAddresses).ifPresent(e -> builder.addAllTakerAcceptedArbitratorNodeAddresses(ProtoCollectionUtil.collectionToProto(takerAcceptedArbitratorNodeAddresses)));
Optional.ofNullable(takerAcceptedMediatorNodeAddresses).ifPresent(e -> builder.addAllTakerAcceptedMediatorNodeAddresses(ProtoCollectionUtil.collectionToProto(takerAcceptedMediatorNodeAddresses)));
Optional.ofNullable(preparedDepositTx).ifPresent(e -> builder.setPreparedDepositTx(ByteString.copyFrom(preparedDepositTx)));
Optional.ofNullable(rawTransactionInputs).ifPresent(e -> builder.addAllRawTransactionInputs(ProtoCollectionUtil.collectionToProto(rawTransactionInputs)));
Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress);
Optional.ofNullable(myMultiSigPubKey).ifPresent(e -> builder.setMyMultiSigPubKey(ByteString.copyFrom(myMultiSigPubKey)));
Optional.ofNullable(tempTradingPeerNodeAddress).ifPresent(e -> builder.setTempTradingPeerNodeAddress(tempTradingPeerNodeAddress.toProtoMessage()));
return builder.build();
}
///////////////////////////////////////////////////////////////////////////////////////////
// API
///////////////////////////////////////////////////////////////////////////////////////////
public void onAllServicesInitialized(Offer offer, public void onAllServicesInitialized(Offer offer,
TradeManager tradeManager, TradeManager tradeManager,
OpenOfferManager openOfferManager, OpenOfferManager openOfferManager,
@ -144,23 +172,36 @@ public class ProcessModel implements Model, PersistablePayload {
this.keyRing = keyRing; this.keyRing = keyRing;
this.p2PService = p2PService; this.p2PService = p2PService;
this.useSavingsWallet = useSavingsWallet; this.useSavingsWallet = useSavingsWallet;
fundsNeededForTradeAsLong = fundsNeededForTrade.value; fundsNeededForTradeAsLong = fundsNeededForTrade.value;
offerId = offer.getId(); offerId = offer.getId();
accountId = user.getAccountId(); accountId = user.getAccountId();
pubKeyRing = keyRing.getPubKeyRing(); pubKeyRing = keyRing.getPubKeyRing();
} }
// TODO need lazy access? public void removeMailboxMessageAfterProcessing(Trade trade) {
public NodeAddress getMyNodeAddress() { if (tradeMessage instanceof MailboxMessage &&
return p2PService.getAddress(); decryptedMessageWithPubKey != null &&
decryptedMessageWithPubKey.getWireEnvelope().equals(tradeMessage)) {
log.debug("Remove decryptedMsgWithPubKey from P2P network. decryptedMsgWithPubKey = " + decryptedMessageWithPubKey);
p2PService.removeEntryFromMailbox(decryptedMessageWithPubKey);
trade.removeDecryptedMessageWithPubKey(decryptedMessageWithPubKey);
}
} }
@Override @Override
public void persist() { public void persist() {
throw new NotImplementedException("persist is not implemented in that class");
} }
@Override @Override
public void onComplete() { public void onComplete() {
throw new NotImplementedException("persist is not implemented in that class");
}
public void setTakeOfferFeeTx(Transaction takeOfferFeeTx) {
this.takeOfferFeeTx = takeOfferFeeTx;
takeOfferFeeTxId = takeOfferFeeTx.getHashAsString();
} }
@Nullable @Nullable
@ -222,10 +263,10 @@ public class ProcessModel implements Model, PersistablePayload {
.setPubKeyRing(pubKeyRing.toProtoMessage()) .setPubKeyRing(pubKeyRing.toProtoMessage())
.setTakeOfferFeeTxId(takeOfferFeeTxId) .setTakeOfferFeeTxId(takeOfferFeeTxId)
.setPayoutTxSignature(ByteString.copyFrom(payoutTxSignature)) .setPayoutTxSignature(ByteString.copyFrom(payoutTxSignature))
.addAllTakerAcceptedArbitratorNodeAddresses(ProtoUtil.collectionToProto(takerAcceptedArbitratorNodeAddresses)) .addAllTakerAcceptedArbitratorNodeAddresses(ProtoCollectionUtil.collectionToProto(takerAcceptedArbitratorNodeAddresses))
.addAllTakerAcceptedMediatorNodeAddresses(ProtoUtil.collectionToProto(takerAcceptedMediatorNodeAddresses)) .addAllTakerAcceptedMediatorNodeAddresses(ProtoCollectionUtil.collectionToProto(takerAcceptedMediatorNodeAddresses))
.setPreparedDepositTx(ByteString.copyFrom(preparedDepositTx)) .setPreparedDepositTx(ByteString.copyFrom(preparedDepositTx))
.addAllRawTransactionInputs(ProtoUtil.collectionToProto(rawTransactionInputs)) .addAllRawTransactionInputs(ProtoCollectionUtil.collectionToProto(rawTransactionInputs))
.setChangeOutputValue(changeOutputValue) .setChangeOutputValue(changeOutputValue)
.setChangeOutputAddress(changeOutputAddress) .setChangeOutputAddress(changeOutputAddress)
.setUseSavingsWallet(useSavingsWallet) .setUseSavingsWallet(useSavingsWallet)

View file

@ -59,7 +59,6 @@ public class SellerAsMakerProtocol extends TradeProtocol implements SellerProtoc
TradeTaskRunner taskRunner = new TradeTaskRunner(trade, TradeTaskRunner taskRunner = new TradeTaskRunner(trade,
() -> { () -> {
handleTaskRunnerSuccess("MakerSetupDepositTxListener"); handleTaskRunnerSuccess("MakerSetupDepositTxListener");
processModel.onComplete();
}, },
this::handleTaskRunnerFault); this::handleTaskRunnerFault);

View file

@ -17,8 +17,10 @@
package io.bisq.core.trade.protocol; package io.bisq.core.trade.protocol;
import com.google.protobuf.ByteString;
import com.google.protobuf.Message; import com.google.protobuf.Message;
import io.bisq.common.crypto.PubKeyRing; import io.bisq.common.crypto.PubKeyRing;
import io.bisq.common.proto.ProtoCollectionUtil;
import io.bisq.common.proto.persistable.PersistablePayload; import io.bisq.common.proto.persistable.PersistablePayload;
import io.bisq.core.btc.data.RawTransactionInput; import io.bisq.core.btc.data.RawTransactionInput;
import io.bisq.core.payment.payload.PaymentAccountPayload; import io.bisq.core.payment.payload.PaymentAccountPayload;
@ -29,21 +31,29 @@ import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; import java.util.List;
import java.util.Optional;
@Slf4j @Slf4j
@Getter @Getter
@Setter @Setter
public final class TradingPeer implements PersistablePayload { public final class TradingPeer implements PersistablePayload {
@Nullable
private String accountId; private String accountId;
@Nullable
private PaymentAccountPayload paymentAccountPayload; private PaymentAccountPayload paymentAccountPayload;
// private Coin payoutAmount; @Nullable
private String payoutAddressString; private String payoutAddressString;
// private byte[] signature; @Nullable
private String contractAsJson; private String contractAsJson;
@Nullable
private String contractSignature; private String contractSignature;
@Nullable
private byte[] signature; private byte[] signature;
@Nullable
private PubKeyRing pubKeyRing; private PubKeyRing pubKeyRing;
@Nullable
private byte[] multiSigPubKey; private byte[] multiSigPubKey;
@Nullable
private List<RawTransactionInput> rawTransactionInputs; private List<RawTransactionInput> rawTransactionInputs;
private long changeOutputValue; private long changeOutputValue;
@Nullable @Nullable
@ -54,25 +64,18 @@ public final class TradingPeer implements PersistablePayload {
@Override @Override
public Message toProtoMessage() { public Message toProtoMessage() {
// TODO final PB.TradingPeer.Builder builder = PB.TradingPeer.newBuilder()
// nullable .setChangeOutputValue(changeOutputValue);
// changeOutputAddress Optional.ofNullable(accountId).ifPresent(builder::setAccountId);
// .setRawTransactionInputs(rawTransactionInputs) Optional.ofNullable(paymentAccountPayload).ifPresent(e -> builder.setPaymentAccountPayload((PB.PaymentAccountPayload) paymentAccountPayload.toProtoMessage()));
// .setPaymentAccountPayload(paymentAccountPayload.toProto()) Optional.ofNullable(payoutAddressString).ifPresent(builder::setPayoutAddressString);
// .setSignature(signature) Optional.ofNullable(contractAsJson).ifPresent(builder::setContractAsJson);
// .setMultiSigPubKey(multiSigPubKey) Optional.ofNullable(contractSignature).ifPresent(builder::setContractSignature);
return PB.TradingPeer.newBuilder() Optional.ofNullable(signature).ifPresent(e -> builder.setSignature(ByteString.copyFrom(signature)));
.setAccountId(accountId) Optional.ofNullable(pubKeyRing).ifPresent(e -> builder.setPubKeyRing(pubKeyRing.toProtoMessage()));
/* .setPaymentAccountPayload(paymentAccountPayload.toProto())*/ Optional.ofNullable(multiSigPubKey).ifPresent(e -> builder.setMultiSigPubKey(ByteString.copyFrom(multiSigPubKey)));
.setPayoutAddressString(payoutAddressString) Optional.ofNullable(rawTransactionInputs).ifPresent(e -> builder.addAllRawTransactionInputs(ProtoCollectionUtil.collectionToProto(rawTransactionInputs)));
.setContractAsJson(contractAsJson) Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress);
.setContractSignature(contractSignature) return builder.build();
/* .setSignature(signature)*/
.setPubKeyRing(pubKeyRing.toProtoMessage())
/* .setMultiSigPubKey(multiSigPubKey)*/
/*.setRawTransactionInputs(rawTransactionInputs)*/
.setChangeOutputValue(changeOutputValue)
/* .setChangeOutputAddress(changeOutputAddress)*/
.build();
} }
} }

View file

@ -74,8 +74,8 @@ public class MakerProcessPayDepositRequest extends TradeTask {
processModel.setTakerAcceptedMediatorNodeAddresses(checkNotNull(payDepositRequest.getAcceptedMediatorNodeAddresses())); processModel.setTakerAcceptedMediatorNodeAddresses(checkNotNull(payDepositRequest.getAcceptedMediatorNodeAddresses()));
if (payDepositRequest.getAcceptedArbitratorNodeAddresses().isEmpty()) if (payDepositRequest.getAcceptedArbitratorNodeAddresses().isEmpty())
failed("acceptedArbitratorNames must not be empty"); failed("acceptedArbitratorNames must not be empty");
trade.applyArbitratorNodeAddress(checkNotNull(payDepositRequest.getArbitratorNodeAddress())); trade.setArbitratorNodeAddress(checkNotNull(payDepositRequest.getArbitratorNodeAddress()));
trade.applyMediatorNodeAddress(checkNotNull(payDepositRequest.getMediatorNodeAddress())); trade.setMediatorNodeAddress(checkNotNull(payDepositRequest.getMediatorNodeAddress()));
try { try {
long takersTradePrice = payDepositRequest.getTradePrice(); long takersTradePrice = payDepositRequest.getTradePrice();

View file

@ -35,7 +35,7 @@ public class TakerSelectArbitrator extends TradeTask {
try { try {
runInterceptHook(); runInterceptHook();
trade.applyArbitratorNodeAddress(ArbitratorSelectionRule.select(processModel.getUser().getAcceptedArbitratorAddresses(), processModel.getOffer())); trade.setArbitratorNodeAddress(ArbitratorSelectionRule.select(processModel.getUser().getAcceptedArbitratorAddresses(), processModel.getOffer()));
complete(); complete();
} catch (Throwable t) { } catch (Throwable t) {

View file

@ -35,7 +35,7 @@ public class TakerSelectMediator extends TradeTask {
try { try {
runInterceptHook(); runInterceptHook();
trade.applyMediatorNodeAddress(MediatorSelectionRule.select(processModel.getUser().getAcceptedMediatorAddresses(), trade.setMediatorNodeAddress(MediatorSelectionRule.select(processModel.getUser().getAcceptedMediatorAddresses(),
processModel.getOffer())); processModel.getOffer()));
complete(); complete();

View file

@ -45,7 +45,7 @@ public class ProtoBufferUtilitiesTest {
@Test @Test
public void testUnknownEnum() { public void testUnknownEnum() {
PB.OpenOffer.State result = PB.OpenOffer.State.UNKNOWN_FAILURE; PB.OpenOffer.State result = PB.OpenOffer.State.PB_ERROR;
try { try {
OpenOffer.State finalResult = OpenOffer.State.valueOf(result.name()); OpenOffer.State finalResult = OpenOffer.State.valueOf(result.name());
fail(); fail();

View file

@ -43,6 +43,8 @@ import io.bisq.core.dao.blockchain.json.JsonChainStateExporter;
import io.bisq.core.filter.FilterManager; import io.bisq.core.filter.FilterManager;
import io.bisq.core.offer.OpenOfferManager; import io.bisq.core.offer.OpenOfferManager;
import io.bisq.core.trade.TradeManager; import io.bisq.core.trade.TradeManager;
import io.bisq.core.trade.closed.ClosedTradableManager;
import io.bisq.core.trade.failed.FailedTradesManager;
import io.bisq.core.trade.statistics.TradeStatisticsManager; import io.bisq.core.trade.statistics.TradeStatisticsManager;
import io.bisq.core.user.Preferences; import io.bisq.core.user.Preferences;
import io.bisq.core.user.User; import io.bisq.core.user.User;
@ -177,14 +179,18 @@ public class BisqApp extends Application {
User user = injector.getInstance(User.class); User user = injector.getInstance(User.class);
user.init(); user.init();
// All classes which are persisting objects need to be added here
ArrayList<PersistedDataHost> persistedDataHosts = new ArrayList<>(); ArrayList<PersistedDataHost> persistedDataHosts = new ArrayList<>();
persistedDataHosts.add(injector.getInstance(Navigation.class)); persistedDataHosts.add(injector.getInstance(Navigation.class));
persistedDataHosts.add(injector.getInstance(AddressEntryList.class)); persistedDataHosts.add(injector.getInstance(AddressEntryList.class));
persistedDataHosts.add(injector.getInstance(TradeStatisticsManager.class)); persistedDataHosts.add(injector.getInstance(TradeStatisticsManager.class));
persistedDataHosts.add(injector.getInstance(OpenOfferManager.class)); persistedDataHosts.add(injector.getInstance(OpenOfferManager.class));
persistedDataHosts.add(injector.getInstance(TradeManager.class));
persistedDataHosts.add(injector.getInstance(ClosedTradableManager.class));
persistedDataHosts.add(injector.getInstance(FailedTradesManager.class));
// we apply at startup the reading of persisted data but don't want to get it triggered in the constructor // we apply at startup the reading of persisted data but don't want to get it triggered in the constructor
persistedDataHosts.stream().forEach(PersistedDataHost::readPersisted); persistedDataHosts.stream().forEach(PersistedDataHost::readPersisted);
Version.setBtcNetworkId(injector.getInstance(BisqEnvironment.class).getBitcoinNetwork().ordinal()); Version.setBtcNetworkId(injector.getInstance(BisqEnvironment.class).getBitcoinNetwork().ordinal());
Version.printVersion(); Version.printVersion();

View file

@ -721,13 +721,13 @@ public class MainViewModel implements ViewModel {
if (now.after(maxTradePeriodDate)) if (now.after(maxTradePeriodDate))
trade.setTradePeriodState(Trade.TradePeriodState.TRADE_PERIOD_OVER); trade.setTradePeriodState(Trade.TradePeriodState.TRADE_PERIOD_OVER);
else if (now.after(halfTradePeriodDate)) else if (now.after(halfTradePeriodDate))
trade.setTradePeriodState(Trade.TradePeriodState.HALF_REACHED); trade.setTradePeriodState(Trade.TradePeriodState.SECOND_HALF);
String key; String key;
switch (trade.getTradePeriodState()) { switch (trade.getTradePeriodState()) {
case NORMAL: case FIRST_HALF:
break; break;
case HALF_REACHED: case SECOND_HALF:
key = "displayHalfTradePeriodOver" + trade.getId(); key = "displayHalfTradePeriodOver" + trade.getId();
if (DontShowAgainLookup.showAgain(key)) { if (DontShowAgainLookup.showAgain(key)) {
DontShowAgainLookup.dontShowAgain(key, true); DontShowAgainLookup.dontShowAgain(key, true);

View file

@ -181,7 +181,7 @@ class TransactionsListItem {
} else if (trade.getPayoutTx() != null && } else if (trade.getPayoutTx() != null &&
trade.getPayoutTx().getHashAsString().equals(txId)) { trade.getPayoutTx().getHashAsString().equals(txId)) {
details = Res.get("funds.tx.multiSigPayout", id); details = Res.get("funds.tx.multiSigPayout", id);
} else if (trade.getDisputeState() != Trade.DisputeState.NONE) { } else if (trade.getDisputeState() != Trade.DisputeState.NO_DISPUTE) {
if (valueSentToMe.isPositive()) { if (valueSentToMe.isPositive()) {
details = Res.get("funds.tx.disputePayout", id); details = Res.get("funds.tx.disputePayout", id);
} else { } else {

View file

@ -120,7 +120,7 @@ class TakeOfferDataModel extends ActivatableDataModel {
@Override @Override
protected void activate() { protected void activate() {
// when leaving screen we reset state // when leaving screen we reset state
offer.setState(Offer.State.UNDEFINED); offer.setState(Offer.State.UNKNOWN);
addBindings(); addBindings();
addListeners(); addListeners();

View file

@ -293,7 +293,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
// 2. Before actually taking the offer in the take offer screen, we check again the availability as some time might have passed in the meantime // 2. Before actually taking the offer in the take offer screen, we check again the availability as some time might have passed in the meantime
// So we use the takeOfferRequested flag to display different network_messages depending on the context. // So we use the takeOfferRequested flag to display different network_messages depending on the context.
switch (state) { switch (state) {
case UNDEFINED: case UNKNOWN:
break; break;
case OFFER_FEE_PAID: case OFFER_FEE_PAID:
// irrelevant for taker // irrelevant for taker
@ -336,7 +336,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im
if (errorMessage != null) { if (errorMessage != null) {
String appendMsg = ""; String appendMsg = "";
switch (trade.getState().getPhase()) { switch (trade.getState().getPhase()) {
case PREPARATION: case INIT:
appendMsg = Res.get("takeOffer.error.noFundsLost"); appendMsg = Res.get("takeOffer.error.noFundsLost");
break; break;
case TAKER_FEE_PUBLISHED: case TAKER_FEE_PUBLISHED:

View file

@ -202,7 +202,7 @@ public class NotificationCenter {
Res.get("shared.supportTicket") : Res.get("shared.supportTicket") :
Res.get("shared.dispute"); Res.get("shared.dispute");
switch (disputeState) { switch (disputeState) {
case NONE: case NO_DISPUTE:
break; break;
case DISPUTE_REQUESTED: case DISPUTE_REQUESTED:
break; break;

View file

@ -144,14 +144,14 @@ public class PendingTradesDataModel extends ActivatableDataModel {
public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { public void onPaymentStarted(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
checkNotNull(getTrade(), "trade must not be null"); checkNotNull(getTrade(), "trade must not be null");
checkArgument(getTrade() instanceof BuyerTrade, "Check failed: trade instanceof BuyerTrade"); checkArgument(getTrade() instanceof BuyerTrade, "Check failed: trade instanceof BuyerTrade");
checkArgument(getTrade().getDisputeState() == Trade.DisputeState.NONE, "Check failed: trade.getDisputeState() == Trade.DisputeState.NONE"); checkArgument(getTrade().getDisputeState() == Trade.DisputeState.NO_DISPUTE, "Check failed: trade.getDisputeState() == Trade.DisputeState.NONE");
((BuyerTrade) getTrade()).onFiatPaymentStarted(resultHandler, errorMessageHandler); ((BuyerTrade) getTrade()).onFiatPaymentStarted(resultHandler, errorMessageHandler);
} }
public void onFiatPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { public void onFiatPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) {
checkNotNull(getTrade(), "trade must not be null"); checkNotNull(getTrade(), "trade must not be null");
checkArgument(getTrade() instanceof SellerTrade, "Check failed: trade not instanceof SellerTrade"); checkArgument(getTrade() instanceof SellerTrade, "Check failed: trade not instanceof SellerTrade");
if (getTrade().getDisputeState() == Trade.DisputeState.NONE) if (getTrade().getDisputeState() == Trade.DisputeState.NO_DISPUTE)
((SellerTrade) getTrade()).onFiatPaymentReceived(resultHandler, errorMessageHandler); ((SellerTrade) getTrade()).onFiatPaymentReceived(resultHandler, errorMessageHandler);
} }

View file

@ -361,7 +361,7 @@ public abstract class TradeStepView extends AnchorPane {
private void updateDisputeState(Trade.DisputeState disputeState) { private void updateDisputeState(Trade.DisputeState disputeState) {
Optional<Dispute> ownDispute; Optional<Dispute> ownDispute;
switch (disputeState) { switch (disputeState) {
case NONE: case NO_DISPUTE:
break; break;
case DISPUTE_REQUESTED: case DISPUTE_REQUESTED:
onDisputeOpened(); onDisputeOpened();
@ -405,9 +405,9 @@ public abstract class TradeStepView extends AnchorPane {
if (trade.getDisputeState() != Trade.DisputeState.DISPUTE_REQUESTED && if (trade.getDisputeState() != Trade.DisputeState.DISPUTE_REQUESTED &&
trade.getDisputeState() != Trade.DisputeState.DISPUTE_STARTED_BY_PEER) { trade.getDisputeState() != Trade.DisputeState.DISPUTE_STARTED_BY_PEER) {
switch (tradePeriodState) { switch (tradePeriodState) {
case NORMAL: case FIRST_HALF:
break; break;
case HALF_REACHED: case SECOND_HALF:
if (!trade.isFiatReceived()) if (!trade.isFiatReceived())
showWarning(); showWarning();
else else