Skip to content

Commit

Permalink
Merge branch 'Development'
Browse files Browse the repository at this point in the history
  • Loading branch information
ManfredKarrer committed Sep 4, 2016
2 parents a0f0787 + 84a55d9 commit 6a4e1d4
Show file tree
Hide file tree
Showing 62 changed files with 874 additions and 297 deletions.
2 changes: 1 addition & 1 deletion common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.4.9.5</version>
<version>0.4.9.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion common/src/main/java/io/bitsquare/app/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class Version {
private static final Logger log = LoggerFactory.getLogger(Version.class);

// The application versions
public static final String VERSION = "0.4.9.5";
public static final String VERSION = "0.4.9.6";

// The version nr. for the objects sent over the network. A change will break the serialization of old objects.
// If objects are used for both network and database the network version is applied.
Expand Down
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.4.9.5</version>
<version>0.4.9.6</version>
</parent>

<artifactId>core</artifactId>
Expand Down
172 changes: 95 additions & 77 deletions core/src/main/java/io/bitsquare/arbitration/DisputeManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class DisputeManager {
Expand Down Expand Up @@ -543,94 +544,94 @@ private void onDisputeResultMessage(DisputeResultMessage disputeResultMessage) {

dispute.setIsClosed(true);

if (dispute.disputeResultProperty().get() == null) {
dispute.setDisputeResult(disputeResult);
if (dispute.disputeResultProperty().get() != null)
log.warn("We got already a dispute result. That should only happen if a dispute needs to be closed " +
"again because the first close did not succeed. TradeId = " + tradeId);

// We need to avoid publishing the tx from both traders as it would create problems with zero confirmation withdrawals
// There would be different transactions if both sign and publish (signers: once buyer+arb, once seller+arb)
// The tx publisher is the winner or in case both get 50% the buyer, as the buyer has more inventive to publish the tx as he receives
// more BTC as he has deposited
final Contract contract = dispute.getContract();
dispute.setDisputeResult(disputeResult);

boolean isBuyer = keyRing.getPubKeyRing().equals(contract.getBuyerPubKeyRing());
if ((isBuyer && disputeResult.getWinner() == DisputeResult.Winner.BUYER)
|| (!isBuyer && disputeResult.getWinner() == DisputeResult.Winner.SELLER)
|| (isBuyer && disputeResult.getWinner() == DisputeResult.Winner.STALE_MATE)) {
// We need to avoid publishing the tx from both traders as it would create problems with zero confirmation withdrawals
// There would be different transactions if both sign and publish (signers: once buyer+arb, once seller+arb)
// The tx publisher is the winner or in case both get 50% the buyer, as the buyer has more inventive to publish the tx as he receives
// more BTC as he has deposited
final Contract contract = dispute.getContract();

boolean isBuyer = keyRing.getPubKeyRing().equals(contract.getBuyerPubKeyRing());
if ((isBuyer && disputeResult.getWinner() == DisputeResult.Winner.BUYER)
|| (!isBuyer && disputeResult.getWinner() == DisputeResult.Winner.SELLER)
|| (isBuyer && disputeResult.getWinner() == DisputeResult.Winner.STALE_MATE)) {

final Optional<Trade> tradeOptional = tradeManager.getTradeById(tradeId);
Transaction payoutTx = null;
if (tradeOptional.isPresent()) {
payoutTx = tradeOptional.get().getPayoutTx();
} else {
final Optional<Tradable> tradableOptional = closedTradableManager.getTradableById(tradeId);
if (tradableOptional.isPresent() && tradableOptional.get() instanceof Trade) {
payoutTx = ((Trade) tradableOptional.get()).getPayoutTx();
}
}

if (payoutTx == null) {
if (dispute.getDepositTxSerialized() != null) {
try {
log.debug("do payout Transaction ");

Transaction signedDisputedPayoutTx = tradeWalletService.traderSignAndFinalizeDisputedPayoutTx(
dispute.getDepositTxSerialized(),
disputeResult.getArbitratorSignature(),
disputeResult.getBuyerPayoutAmount(),
disputeResult.getSellerPayoutAmount(),
disputeResult.getArbitratorPayoutAmount(),
contract.getBuyerPayoutAddressString(),
contract.getSellerPayoutAddressString(),
disputeResult.getArbitratorAddressAsString(),
walletService.getOrCreateAddressEntry(dispute.getTradeId(), AddressEntry.Context.MULTI_SIG),
contract.getBuyerBtcPubKey(),
contract.getSellerBtcPubKey(),
disputeResult.getArbitratorPubKey()
);
Transaction committedDisputedPayoutTx = tradeWalletService.addTransactionToWallet(signedDisputedPayoutTx);
log.debug("broadcast committedDisputedPayoutTx");
tradeWalletService.broadcastTx(committedDisputedPayoutTx, new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("BroadcastTx succeeded. Transaction:" + transaction);

// after successful publish we send peer the tx

dispute.setDisputePayoutTxId(transaction.getHashAsString());
sendPeerPublishedPayoutTxMessage(transaction, dispute, contract);

// set state after payout as we call swapTradeEntryToAvailableEntry
if (tradeManager.getTradeById(dispute.getTradeId()).isPresent())
tradeManager.closeDisputedTrade(dispute.getTradeId());
else {
Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(dispute.getTradeId());
if (openOfferOptional.isPresent())
openOfferManager.closeOpenOffer(openOfferOptional.get().getOffer());
}
}
final Optional<Trade> tradeOptional = tradeManager.getTradeById(tradeId);
Transaction payoutTx = null;
if (tradeOptional.isPresent()) {
payoutTx = tradeOptional.get().getPayoutTx();
} else {
final Optional<Tradable> tradableOptional = closedTradableManager.getTradableById(tradeId);
if (tradableOptional.isPresent() && tradableOptional.get() instanceof Trade) {
payoutTx = ((Trade) tradableOptional.get()).getPayoutTx();
}
}

@Override
public void onFailure(@NotNull Throwable t) {
log.error(t.getMessage());
if (payoutTx == null) {
if (dispute.getDepositTxSerialized() != null) {
try {
log.debug("do payout Transaction ");

Transaction signedDisputedPayoutTx = tradeWalletService.traderSignAndFinalizeDisputedPayoutTx(
dispute.getDepositTxSerialized(),
disputeResult.getArbitratorSignature(),
disputeResult.getBuyerPayoutAmount(),
disputeResult.getSellerPayoutAmount(),
disputeResult.getArbitratorPayoutAmount(),
contract.getBuyerPayoutAddressString(),
contract.getSellerPayoutAddressString(),
disputeResult.getArbitratorAddressAsString(),
walletService.getOrCreateAddressEntry(dispute.getTradeId(), AddressEntry.Context.MULTI_SIG),
contract.getBuyerBtcPubKey(),
contract.getSellerBtcPubKey(),
disputeResult.getArbitratorPubKey()
);
Transaction committedDisputedPayoutTx = tradeWalletService.addTransactionToWallet(signedDisputedPayoutTx);
log.debug("broadcast committedDisputedPayoutTx");
tradeWalletService.broadcastTx(committedDisputedPayoutTx, new FutureCallback<Transaction>() {
@Override
public void onSuccess(Transaction transaction) {
log.debug("BroadcastTx succeeded. Transaction:" + transaction);

// after successful publish we send peer the tx

dispute.setDisputePayoutTxId(transaction.getHashAsString());
sendPeerPublishedPayoutTxMessage(transaction, dispute, contract);

// set state after payout as we call swapTradeEntryToAvailableEntry
if (tradeManager.getTradeById(dispute.getTradeId()).isPresent())
tradeManager.closeDisputedTrade(dispute.getTradeId());
else {
Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(dispute.getTradeId());
if (openOfferOptional.isPresent())
openOfferManager.closeOpenOffer(openOfferOptional.get().getOffer());
}
});
} catch (AddressFormatException | WalletException | TransactionVerificationException e) {
e.printStackTrace();
log.error("Error at traderSignAndFinalizeDisputedPayoutTx " + e.getMessage());
}
} else {
log.warn("DepositTx is null. TradeId = " + tradeId);
}

@Override
public void onFailure(@NotNull Throwable t) {
log.error(t.getMessage());
}
});
} catch (AddressFormatException | WalletException | TransactionVerificationException e) {
e.printStackTrace();
log.error("Error at traderSignAndFinalizeDisputedPayoutTx " + e.getMessage());
}
} else {
log.warn("We got already a payout tx. That might be the case if the other peer did not get the " +
"payout tx and opened a dispute. TradeId = " + tradeId);
dispute.setDisputePayoutTxId(payoutTx.getHashAsString());
sendPeerPublishedPayoutTxMessage(payoutTx, dispute, contract);
log.warn("DepositTx is null. TradeId = " + tradeId);
}
} else {
log.warn("We got already a payout tx. That might be the case if the other peer did not get the " +
"payout tx and opened a dispute. TradeId = " + tradeId);
dispute.setDisputePayoutTxId(payoutTx.getHashAsString());
sendPeerPublishedPayoutTxMessage(payoutTx, dispute, contract);
}
} else {
log.warn("We got a dispute msg what we have already stored. TradeId = " + tradeId);
}
} else {
log.debug("We got a dispute result msg but we don't have a matching dispute. " +
Expand Down Expand Up @@ -699,6 +700,23 @@ private boolean isArbitrator(DisputeResult disputeResult) {
return disputeResult.getArbitratorAddressAsString().equals(walletService.getOrCreateAddressEntry(AddressEntry.Context.ARBITRATOR).getAddressString());
}

public String getNrOfDisputes(boolean isBuyer, Contract contract) {
return String.valueOf(getDisputesAsObservableList().stream()
.filter(e -> {
Contract contract1 = e.getContract();
if (contract1 == null)
return false;

if (isBuyer) {
NodeAddress buyerNodeAddress = contract1.getBuyerNodeAddress();
return buyerNodeAddress != null && buyerNodeAddress.equals(contract.getBuyerNodeAddress());
} else {
NodeAddress sellerNodeAddress = contract1.getSellerNodeAddress();
return sellerNodeAddress != null && sellerNodeAddress.equals(contract.getSellerNodeAddress());
}
})
.collect(Collectors.toSet()).size());
}

///////////////////////////////////////////////////////////////////////////////////////////
// Utils
Expand Down
25 changes: 20 additions & 5 deletions core/src/main/java/io/bitsquare/arbitration/DisputeResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Arrays;
Expand All @@ -47,18 +48,27 @@ public enum Winner {
STALE_MATE
}

// only append new values as we use the ordinal value
public enum Reason {
BUG,
USABILITY,
SCAM,
OTHER
OTHER,
PROTOCOL_VIOLATION,
NO_REPLY
}

public final String tradeId;
public final int traderId;
private DisputeFeePolicy disputeFeePolicy;
private Winner winner;

// Keep it for backward compatibility but use reasonOrdinal to allow changes in the ENum without breaking serialisation
@Deprecated
@Nullable
private Reason reason;
private int reasonOrdinal = Reason.OTHER.ordinal();

private boolean tamperProofEvidence;
private boolean idVerification;
private boolean screenCast;
Expand Down Expand Up @@ -145,17 +155,20 @@ public DisputeFeePolicy getDisputeFeePolicy() {
}

public void setReason(Reason reason) {
this.reason = reason;
this.reasonOrdinal = reason.ordinal();
}

public Reason getReason() {
return reason;
if (reasonOrdinal < Reason.values().length)
return Reason.values()[reasonOrdinal];
else
return Reason.OTHER;
}

public void setSummaryNotes(String summaryNotes) {
this.summaryNotesProperty.set(summaryNotes);
}

public StringProperty summaryNotesProperty() {
return summaryNotesProperty;
}
Expand Down Expand Up @@ -249,6 +262,7 @@ public boolean equals(Object o) {
if (closeDate != that.closeDate) return false;
if (tradeId != null ? !tradeId.equals(that.tradeId) : that.tradeId != null) return false;
if (disputeFeePolicy != that.disputeFeePolicy) return false;
if (reasonOrdinal != that.reasonOrdinal) return false;
if (reason != that.reason) return false;

if (disputeFeePolicy != null && that.disputeFeePolicy != null && disputeFeePolicy.ordinal() != that.disputeFeePolicy.ordinal())
Expand All @@ -265,7 +279,7 @@ else if ((reason == null && that.reason != null) || (reason != null && that.reas
return false;
else if ((winner == null && that.winner != null) || (winner != null && that.winner == null))
return false;

if (summaryNotes != null ? !summaryNotes.equals(that.summaryNotes) : that.summaryNotes != null) return false;
if (disputeCommunicationMessage != null ? !disputeCommunicationMessage.equals(that.disputeCommunicationMessage) : that.disputeCommunicationMessage != null)
return false;
Expand All @@ -282,6 +296,7 @@ public int hashCode() {
int result = tradeId != null ? tradeId.hashCode() : 0;
result = 31 * result + traderId;
result = 31 * result + (disputeFeePolicy != null ? disputeFeePolicy.ordinal() : 0);
result = 31 * result + reasonOrdinal;
result = 31 * result + (reason != null ? reason.ordinal() : 0);
result = 31 * result + (winner != null ? winner.ordinal() : 0);
result = 31 * result + (tamperProofEvidence ? 1 : 0);
Expand Down
Loading

0 comments on commit 6a4e1d4

Please sign in to comment.