mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-08-06 05:34:50 -04:00
Use byte array instead of PubKeys, Use uid for mailbox msg, Improve storage data structure, Renamings, Cleanup
This commit is contained in:
parent
bb6334f6a0
commit
77511a43f5
101 changed files with 869 additions and 1074 deletions
|
@ -41,16 +41,14 @@ public final class PubKeyRing implements Payload {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(PubKeyRing.class);
|
private static final Logger log = LoggerFactory.getLogger(PubKeyRing.class);
|
||||||
|
|
||||||
private final byte[] signaturePubKeyBytes;
|
|
||||||
private final byte[] encryptionPubKeyBytes;
|
|
||||||
|
|
||||||
transient private PublicKey signaturePubKey;
|
transient private PublicKey signaturePubKey;
|
||||||
|
private final byte[] signaturePubKeyBytes;
|
||||||
transient private PublicKey encryptionPubKey;
|
transient private PublicKey encryptionPubKey;
|
||||||
|
private final byte[] encryptionPubKeyBytes;
|
||||||
|
|
||||||
public PubKeyRing(PublicKey signaturePubKey, PublicKey encryptionPubKey) {
|
public PubKeyRing(PublicKey signaturePubKey, PublicKey encryptionPubKey) {
|
||||||
this.signaturePubKey = signaturePubKey;
|
this.signaturePubKey = signaturePubKey;
|
||||||
this.encryptionPubKey = encryptionPubKey;
|
this.encryptionPubKey = encryptionPubKey;
|
||||||
|
|
||||||
this.signaturePubKeyBytes = new X509EncodedKeySpec(signaturePubKey.getEncoded()).getEncoded();
|
this.signaturePubKeyBytes = new X509EncodedKeySpec(signaturePubKey.getEncoded()).getEncoded();
|
||||||
this.encryptionPubKeyBytes = new X509EncodedKeySpec(encryptionPubKey.getEncoded()).getEncoded();
|
this.encryptionPubKeyBytes = new X509EncodedKeySpec(encryptionPubKey.getEncoded()).getEncoded();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,24 +19,42 @@ package io.bitsquare.common.crypto;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.common.wire.Payload;
|
import io.bitsquare.common.wire.Payload;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.KeyFactory;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public final class SealedAndSigned implements Payload {
|
public final class SealedAndSigned implements Payload {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(SealedAndSigned.class);
|
||||||
|
|
||||||
public final byte[] encryptedSecretKey;
|
public final byte[] encryptedSecretKey;
|
||||||
public final byte[] encryptedPayloadWithHmac;
|
public final byte[] encryptedPayloadWithHmac;
|
||||||
public final byte[] signature;
|
public final byte[] signature;
|
||||||
public final PublicKey sigPublicKey;
|
public transient PublicKey sigPublicKey;
|
||||||
|
private final byte[] sigPublicKeyBytes;
|
||||||
|
|
||||||
public SealedAndSigned(byte[] encryptedSecretKey, byte[] encryptedPayloadWithHmac, byte[] signature, PublicKey sigPublicKey) {
|
public SealedAndSigned(byte[] encryptedSecretKey, byte[] encryptedPayloadWithHmac, byte[] signature, PublicKey sigPublicKey) {
|
||||||
this.encryptedSecretKey = encryptedSecretKey;
|
this.encryptedSecretKey = encryptedSecretKey;
|
||||||
this.encryptedPayloadWithHmac = encryptedPayloadWithHmac;
|
this.encryptedPayloadWithHmac = encryptedPayloadWithHmac;
|
||||||
this.signature = signature;
|
this.signature = signature;
|
||||||
this.sigPublicKey = sigPublicKey;
|
this.sigPublicKey = sigPublicKey;
|
||||||
|
this.sigPublicKeyBytes = new X509EncodedKeySpec(this.sigPublicKey.getEncoded()).getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
try {
|
||||||
|
in.defaultReadObject();
|
||||||
|
sigPublicKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(sigPublicKeyBytes));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.error("Exception at readObject: " + t.getMessage());
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -197,7 +197,6 @@ public class FileManager<T> {
|
||||||
fileOutputStream = new FileOutputStream(tempFile);
|
fileOutputStream = new FileOutputStream(tempFile);
|
||||||
objectOutputStream = new ObjectOutputStream(fileOutputStream);
|
objectOutputStream = new ObjectOutputStream(fileOutputStream);
|
||||||
|
|
||||||
// TODO ConcurrentModificationException happens sometimes at that line
|
|
||||||
objectOutputStream.writeObject(serializable);
|
objectOutputStream.writeObject(serializable);
|
||||||
// Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide
|
// Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide
|
||||||
// to not write through to physical media for at least a few seconds, but this is the best we can do.
|
// to not write through to physical media for at least a few seconds, but this is the best we can do.
|
||||||
|
|
|
@ -18,30 +18,48 @@
|
||||||
package io.bitsquare.alert;
|
package io.bitsquare.alert;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.storage.data.StoragePayload;
|
import io.bitsquare.common.crypto.Sig;
|
||||||
|
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.KeyFactory;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class Alert implements StoragePayload {
|
public final class Alert implements StoragePayload {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(Alert.class);
|
||||||
private static final long TTL = TimeUnit.DAYS.toMillis(10);
|
private static final long TTL = TimeUnit.DAYS.toMillis(10);
|
||||||
|
|
||||||
public final String message;
|
public final String message;
|
||||||
public final boolean isUpdateInfo;
|
public final boolean isUpdateInfo;
|
||||||
private String signatureAsBase64;
|
private String signatureAsBase64;
|
||||||
private PublicKey storagePublicKey;
|
private transient PublicKey storagePublicKey;
|
||||||
|
private byte[] storagePublicKeyBytes;
|
||||||
|
|
||||||
public Alert(String message, boolean isUpdateInfo) {
|
public Alert(String message, boolean isUpdateInfo) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.isUpdateInfo = isUpdateInfo;
|
this.isUpdateInfo = isUpdateInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
try {
|
||||||
|
in.defaultReadObject();
|
||||||
|
storagePublicKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(storagePublicKeyBytes));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.error("Exception at readObject: " + t.getMessage());
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setSigAndStoragePubKey(String signatureAsBase64, PublicKey storagePublicKey) {
|
public void setSigAndStoragePubKey(String signatureAsBase64, PublicKey storagePublicKey) {
|
||||||
this.signatureAsBase64 = signatureAsBase64;
|
this.signatureAsBase64 = signatureAsBase64;
|
||||||
this.storagePublicKey = storagePublicKey;
|
this.storagePublicKey = storagePublicKey;
|
||||||
|
this.storagePublicKeyBytes = new X509EncodedKeySpec(this.storagePublicKey.getEncoded()).getEncoded();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSignatureAsBase64() {
|
public String getSignatureAsBase64() {
|
||||||
|
|
|
@ -20,7 +20,7 @@ package io.bitsquare.alert;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import io.bitsquare.common.crypto.KeyRing;
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||||
|
@ -60,18 +60,18 @@ public class AlertManager {
|
||||||
|
|
||||||
alertService.addHashSetChangedListener(new HashMapChangedListener() {
|
alertService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onAdded(ProtectedData data) {
|
public void onAdded(ProtectedStorageEntry data) {
|
||||||
if (data.expirablePayload instanceof Alert) {
|
if (data.getStoragePayload() instanceof Alert) {
|
||||||
Alert alert = (Alert) data.expirablePayload;
|
Alert alert = (Alert) data.getStoragePayload();
|
||||||
if (verifySignature(alert))
|
if (verifySignature(alert))
|
||||||
alertMessageProperty.set(alert);
|
alertMessageProperty.set(alert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemoved(ProtectedData data) {
|
public void onRemoved(ProtectedStorageEntry data) {
|
||||||
if (data.expirablePayload instanceof Alert) {
|
if (data.getStoragePayload() instanceof Alert) {
|
||||||
Alert alert = (Alert) data.expirablePayload;
|
Alert alert = (Alert) data.getStoragePayload();
|
||||||
if (verifySignature(alert))
|
if (verifySignature(alert))
|
||||||
alertMessageProperty.set(null);
|
alertMessageProperty.set(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,10 @@ package io.bitsquare.arbitration;
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.common.crypto.PubKeyRing;
|
import io.bitsquare.common.crypto.PubKeyRing;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.storage.data.StoragePayload;
|
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||||
|
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -38,7 +39,7 @@ public final class Arbitrator implements StoragePayload {
|
||||||
private final byte[] btcPubKey;
|
private final byte[] btcPubKey;
|
||||||
private final PubKeyRing pubKeyRing;
|
private final PubKeyRing pubKeyRing;
|
||||||
private final NodeAddress arbitratorNodeAddress;
|
private final NodeAddress arbitratorNodeAddress;
|
||||||
private final List<String> languageCodes;
|
private final ArrayList<String> languageCodes;
|
||||||
private final String btcAddress;
|
private final String btcAddress;
|
||||||
private final long registrationDate;
|
private final long registrationDate;
|
||||||
private final String registrationSignature;
|
private final String registrationSignature;
|
||||||
|
@ -48,7 +49,7 @@ public final class Arbitrator implements StoragePayload {
|
||||||
byte[] btcPubKey,
|
byte[] btcPubKey,
|
||||||
String btcAddress,
|
String btcAddress,
|
||||||
PubKeyRing pubKeyRing,
|
PubKeyRing pubKeyRing,
|
||||||
List<String> languageCodes,
|
ArrayList<String> languageCodes,
|
||||||
Date registrationDate,
|
Date registrationDate,
|
||||||
byte[] registrationPubKey,
|
byte[] registrationPubKey,
|
||||||
String registrationSignature) {
|
String registrationSignature) {
|
||||||
|
|
|
@ -29,7 +29,7 @@ import io.bitsquare.p2p.BootstrapListener;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.P2PService;
|
import io.bitsquare.p2p.P2PService;
|
||||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableMap;
|
import javafx.collections.ObservableMap;
|
||||||
|
@ -117,12 +117,12 @@ public class ArbitratorManager {
|
||||||
|
|
||||||
arbitratorService.addHashSetChangedListener(new HashMapChangedListener() {
|
arbitratorService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onAdded(ProtectedData data) {
|
public void onAdded(ProtectedStorageEntry data) {
|
||||||
applyArbitrators();
|
applyArbitrators();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemoved(ProtectedData data) {
|
public void onRemoved(ProtectedStorageEntry data) {
|
||||||
applyArbitrators();
|
applyArbitrators();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -84,8 +84,8 @@ public class ArbitratorService {
|
||||||
|
|
||||||
public Map<NodeAddress, Arbitrator> getArbitrators() {
|
public Map<NodeAddress, Arbitrator> getArbitrators() {
|
||||||
Set<Arbitrator> arbitratorSet = p2PService.getDataMap().values().stream()
|
Set<Arbitrator> arbitratorSet = p2PService.getDataMap().values().stream()
|
||||||
.filter(data -> data.expirablePayload instanceof Arbitrator)
|
.filter(data -> data.getStoragePayload() instanceof Arbitrator)
|
||||||
.map(data -> (Arbitrator) data.expirablePayload)
|
.map(data -> (Arbitrator) data.getStoragePayload())
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
Map<NodeAddress, Arbitrator> map = new HashMap<>();
|
Map<NodeAddress, Arbitrator> map = new HashMap<>();
|
||||||
|
|
|
@ -26,7 +26,6 @@ import io.bitsquare.trade.Contract;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import org.bitcoinj.core.Transaction;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -36,7 +35,6 @@ import java.io.ObjectInputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public final class Dispute implements Payload {
|
public final class Dispute implements Payload {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
|
@ -71,11 +69,12 @@ public final class Dispute implements Payload {
|
||||||
private final PubKeyRing arbitratorPubKeyRing;
|
private final PubKeyRing arbitratorPubKeyRing;
|
||||||
private final boolean isSupportTicket;
|
private final boolean isSupportTicket;
|
||||||
|
|
||||||
private final List<DisputeCommunicationMessage> disputeCommunicationMessages = new ArrayList<>();
|
private final ArrayList<DisputeCommunicationMessage> disputeCommunicationMessages = new ArrayList<>();
|
||||||
|
|
||||||
private boolean isClosed;
|
private boolean isClosed;
|
||||||
private DisputeResult disputeResult;
|
private DisputeResult disputeResult;
|
||||||
private Transaction disputePayoutTx;
|
@Nullable
|
||||||
|
private String disputePayoutTxId;
|
||||||
|
|
||||||
transient private Storage<DisputeList<Dispute>> storage;
|
transient private Storage<DisputeList<Dispute>> storage;
|
||||||
transient private ObservableList<DisputeCommunicationMessage> disputeCommunicationMessagesAsObservableList = FXCollections.observableArrayList(disputeCommunicationMessages);
|
transient private ObservableList<DisputeCommunicationMessage> disputeCommunicationMessagesAsObservableList = FXCollections.observableArrayList(disputeCommunicationMessages);
|
||||||
|
@ -171,8 +170,8 @@ public final class Dispute implements Payload {
|
||||||
storage.queueUpForSave();
|
storage.queueUpForSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisputePayoutTx(Transaction disputePayoutTx) {
|
public void setDisputePayoutTxId(String disputePayoutTxId) {
|
||||||
this.disputePayoutTx = disputePayoutTx;
|
this.disputePayoutTxId = disputePayoutTxId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -280,8 +279,8 @@ public final class Dispute implements Payload {
|
||||||
return new Date(tradeDate);
|
return new Date(tradeDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transaction getDisputePayoutTx() {
|
public String getDisputePayoutTxId() {
|
||||||
return disputePayoutTx;
|
return disputePayoutTxId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -299,6 +298,7 @@ public final class Dispute implements Payload {
|
||||||
if (isSupportTicket != dispute.isSupportTicket) return false;
|
if (isSupportTicket != dispute.isSupportTicket) return false;
|
||||||
if (isClosed != dispute.isClosed) return false;
|
if (isClosed != dispute.isClosed) return false;
|
||||||
if (tradeId != null ? !tradeId.equals(dispute.tradeId) : dispute.tradeId != null) return false;
|
if (tradeId != null ? !tradeId.equals(dispute.tradeId) : dispute.tradeId != null) return false;
|
||||||
|
if (id != null ? !id.equals(dispute.id) : dispute.id != null) return false;
|
||||||
if (traderPubKeyRing != null ? !traderPubKeyRing.equals(dispute.traderPubKeyRing) : dispute.traderPubKeyRing != null)
|
if (traderPubKeyRing != null ? !traderPubKeyRing.equals(dispute.traderPubKeyRing) : dispute.traderPubKeyRing != null)
|
||||||
return false;
|
return false;
|
||||||
if (contract != null ? !contract.equals(dispute.contract) : dispute.contract != null) return false;
|
if (contract != null ? !contract.equals(dispute.contract) : dispute.contract != null) return false;
|
||||||
|
@ -317,13 +317,18 @@ public final class Dispute implements Payload {
|
||||||
return false;
|
return false;
|
||||||
if (disputeCommunicationMessages != null ? !disputeCommunicationMessages.equals(dispute.disputeCommunicationMessages) : dispute.disputeCommunicationMessages != null)
|
if (disputeCommunicationMessages != null ? !disputeCommunicationMessages.equals(dispute.disputeCommunicationMessages) : dispute.disputeCommunicationMessages != null)
|
||||||
return false;
|
return false;
|
||||||
return !(disputeResult != null ? !disputeResult.equals(dispute.disputeResult) : dispute.disputeResult != null);
|
if (disputeResult != null ? !disputeResult.equals(dispute.disputeResult) : dispute.disputeResult != null)
|
||||||
|
return false;
|
||||||
|
if (disputePayoutTxId != null ? !disputePayoutTxId.equals(dispute.disputePayoutTxId) : dispute.disputePayoutTxId != null)
|
||||||
|
return false;
|
||||||
|
return !(storage != null ? !storage.equals(dispute.storage) : dispute.storage != null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = tradeId != null ? tradeId.hashCode() : 0;
|
int result = tradeId != null ? tradeId.hashCode() : 0;
|
||||||
|
result = 31 * result + (id != null ? id.hashCode() : 0);
|
||||||
result = 31 * result + traderId;
|
result = 31 * result + traderId;
|
||||||
result = 31 * result + (disputeOpenerIsBuyer ? 1 : 0);
|
result = 31 * result + (disputeOpenerIsBuyer ? 1 : 0);
|
||||||
result = 31 * result + (disputeOpenerIsOfferer ? 1 : 0);
|
result = 31 * result + (disputeOpenerIsOfferer ? 1 : 0);
|
||||||
|
@ -344,27 +349,39 @@ public final class Dispute implements Payload {
|
||||||
result = 31 * result + (disputeCommunicationMessages != null ? disputeCommunicationMessages.hashCode() : 0);
|
result = 31 * result + (disputeCommunicationMessages != null ? disputeCommunicationMessages.hashCode() : 0);
|
||||||
result = 31 * result + (isClosed ? 1 : 0);
|
result = 31 * result + (isClosed ? 1 : 0);
|
||||||
result = 31 * result + (disputeResult != null ? disputeResult.hashCode() : 0);
|
result = 31 * result + (disputeResult != null ? disputeResult.hashCode() : 0);
|
||||||
|
result = 31 * result + (disputePayoutTxId != null ? disputePayoutTxId.hashCode() : 0);
|
||||||
|
result = 31 * result + (storage != null ? storage.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Dispute{" +
|
return "Dispute{" +
|
||||||
", tradeId='" + tradeId + '\'' +
|
"tradeId='" + tradeId + '\'' +
|
||||||
", traderId='" + traderId + '\'' +
|
", id='" + id + '\'' +
|
||||||
|
", traderId=" + traderId +
|
||||||
", disputeOpenerIsBuyer=" + disputeOpenerIsBuyer +
|
", disputeOpenerIsBuyer=" + disputeOpenerIsBuyer +
|
||||||
", disputeOpenerIsOfferer=" + disputeOpenerIsOfferer +
|
", disputeOpenerIsOfferer=" + disputeOpenerIsOfferer +
|
||||||
", openingDate=" + openingDate +
|
", openingDate=" + openingDate +
|
||||||
", traderPubKeyRing=" + traderPubKeyRing +
|
", traderPubKeyRing=" + traderPubKeyRing +
|
||||||
|
", tradeDate=" + tradeDate +
|
||||||
", contract=" + contract +
|
", contract=" + contract +
|
||||||
|
", contractHash=" + Arrays.toString(contractHash) +
|
||||||
|
", depositTxSerialized=" + Arrays.toString(depositTxSerialized) +
|
||||||
|
", payoutTxSerialized=" + Arrays.toString(payoutTxSerialized) +
|
||||||
|
", depositTxId='" + depositTxId + '\'' +
|
||||||
|
", payoutTxId='" + payoutTxId + '\'' +
|
||||||
", contractAsJson='" + contractAsJson + '\'' +
|
", contractAsJson='" + contractAsJson + '\'' +
|
||||||
", buyerContractSignature='" + offererContractSignature + '\'' +
|
", offererContractSignature='" + offererContractSignature + '\'' +
|
||||||
", sellerContractSignature='" + takerContractSignature + '\'' +
|
", takerContractSignature='" + takerContractSignature + '\'' +
|
||||||
", arbitratorPubKeyRing=" + arbitratorPubKeyRing +
|
", arbitratorPubKeyRing=" + arbitratorPubKeyRing +
|
||||||
", disputeDirectMessages=" + disputeCommunicationMessages +
|
", isSupportTicket=" + isSupportTicket +
|
||||||
", disputeDirectMessagesAsObservableList=" + disputeCommunicationMessagesAsObservableList +
|
", disputeCommunicationMessages=" + disputeCommunicationMessages +
|
||||||
", isClosed=" + isClosed +
|
", isClosed=" + isClosed +
|
||||||
", disputeResult=" + disputeResult +
|
", disputeResult=" + disputeResult +
|
||||||
|
", disputePayoutTxId='" + disputePayoutTxId + '\'' +
|
||||||
|
", disputeCommunicationMessagesAsObservableList=" + disputeCommunicationMessagesAsObservableList +
|
||||||
|
", isClosedProperty=" + isClosedProperty +
|
||||||
", disputeResultProperty=" + disputeResultProperty +
|
", disputeResultProperty=" + disputeResultProperty +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,11 +28,11 @@ import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
||||||
import io.bitsquare.btc.exceptions.WalletException;
|
import io.bitsquare.btc.exceptions.WalletException;
|
||||||
import io.bitsquare.common.crypto.KeyRing;
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.common.crypto.PubKeyRing;
|
import io.bitsquare.common.crypto.PubKeyRing;
|
||||||
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.p2p.BootstrapListener;
|
import io.bitsquare.p2p.BootstrapListener;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.P2PService;
|
import io.bitsquare.p2p.P2PService;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey;
|
|
||||||
import io.bitsquare.p2p.messaging.SendMailboxMessageListener;
|
import io.bitsquare.p2p.messaging.SendMailboxMessageListener;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
import io.bitsquare.trade.Contract;
|
import io.bitsquare.trade.Contract;
|
||||||
|
@ -513,7 +513,7 @@ public class DisputeManager {
|
||||||
|
|
||||||
// after successful publish we send peer the tx
|
// after successful publish we send peer the tx
|
||||||
|
|
||||||
dispute.setDisputePayoutTx(transaction);
|
dispute.setDisputePayoutTxId(transaction.getHashAsString());
|
||||||
sendPeerPublishedPayoutTxMessage(transaction, dispute, contract);
|
sendPeerPublishedPayoutTxMessage(transaction, dispute, contract);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,7 +551,7 @@ public class DisputeManager {
|
||||||
// losing trader or in case of 50/50 the seller gets the tx sent from the winner or buyer
|
// losing trader or in case of 50/50 the seller gets the tx sent from the winner or buyer
|
||||||
private void onDisputedPayoutTxMessage(PeerPublishedPayoutTxMessage peerPublishedPayoutTxMessage) {
|
private void onDisputedPayoutTxMessage(PeerPublishedPayoutTxMessage peerPublishedPayoutTxMessage) {
|
||||||
Transaction transaction = tradeWalletService.addTransactionToWallet(peerPublishedPayoutTxMessage.transaction);
|
Transaction transaction = tradeWalletService.addTransactionToWallet(peerPublishedPayoutTxMessage.transaction);
|
||||||
findOwnDispute(peerPublishedPayoutTxMessage.tradeId).ifPresent(dispute -> dispute.setDisputePayoutTx(transaction));
|
findOwnDispute(peerPublishedPayoutTxMessage.tradeId).ifPresent(dispute -> dispute.setDisputePayoutTxId(transaction.getHashAsString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -585,11 +585,11 @@ public class DisputeManager {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private Optional<Dispute> findDispute(String tradeId, int traderId) {
|
private Optional<Dispute> findDispute(String tradeId, int traderId) {
|
||||||
return disputes.stream().filter(e -> e.getTradeId().equals(tradeId) && e.getTraderId() == traderId).findFirst();
|
return disputes.stream().filter(e -> e.getTradeId().equals(tradeId) && e.getTraderId() == traderId).findAny();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Dispute> findOwnDispute(String tradeId) {
|
public Optional<Dispute> findOwnDispute(String tradeId) {
|
||||||
return disputes.stream().filter(e -> e.getTradeId().equals(tradeId)).findFirst();
|
return disputes.stream().filter(e -> e.getTradeId().equals(tradeId)).findAny();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Dispute> findDisputesByTradeId(String tradeId) {
|
public List<Dispute> findDisputesByTradeId(String tradeId) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ public final class DisputeResult implements Payload {
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
private static final Logger log = LoggerFactory.getLogger(DisputeResult.class);
|
private static final Logger log = LoggerFactory.getLogger(DisputeResult.class);
|
||||||
|
|
||||||
public enum FeePaymentPolicy {
|
public enum DisputeFeePolicy {
|
||||||
LOSER,
|
LOSER,
|
||||||
SPLIT,
|
SPLIT,
|
||||||
WAIVE
|
WAIVE
|
||||||
|
@ -49,7 +49,7 @@ public final class DisputeResult implements Payload {
|
||||||
|
|
||||||
public final String tradeId;
|
public final String tradeId;
|
||||||
public final int traderId;
|
public final int traderId;
|
||||||
private FeePaymentPolicy feePaymentPolicy;
|
private DisputeFeePolicy disputeFeePolicy;
|
||||||
|
|
||||||
private boolean tamperProofEvidence;
|
private boolean tamperProofEvidence;
|
||||||
private boolean idVerification;
|
private boolean idVerification;
|
||||||
|
@ -68,14 +68,14 @@ public final class DisputeResult implements Payload {
|
||||||
transient private BooleanProperty tamperProofEvidenceProperty = new SimpleBooleanProperty();
|
transient private BooleanProperty tamperProofEvidenceProperty = new SimpleBooleanProperty();
|
||||||
transient private BooleanProperty idVerificationProperty = new SimpleBooleanProperty();
|
transient private BooleanProperty idVerificationProperty = new SimpleBooleanProperty();
|
||||||
transient private BooleanProperty screenCastProperty = new SimpleBooleanProperty();
|
transient private BooleanProperty screenCastProperty = new SimpleBooleanProperty();
|
||||||
transient private ObjectProperty<FeePaymentPolicy> feePaymentPolicyProperty = new SimpleObjectProperty<>();
|
transient private ObjectProperty<DisputeFeePolicy> feePaymentPolicyProperty = new SimpleObjectProperty<>();
|
||||||
transient private StringProperty summaryNotesProperty = new SimpleStringProperty();
|
transient private StringProperty summaryNotesProperty = new SimpleStringProperty();
|
||||||
|
|
||||||
public DisputeResult(String tradeId, int traderId) {
|
public DisputeResult(String tradeId, int traderId) {
|
||||||
this.tradeId = tradeId;
|
this.tradeId = tradeId;
|
||||||
this.traderId = traderId;
|
this.traderId = traderId;
|
||||||
|
|
||||||
feePaymentPolicy = FeePaymentPolicy.LOSER;
|
disputeFeePolicy = DisputeFeePolicy.LOSER;
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ public final class DisputeResult implements Payload {
|
||||||
tamperProofEvidenceProperty = new SimpleBooleanProperty(tamperProofEvidence);
|
tamperProofEvidenceProperty = new SimpleBooleanProperty(tamperProofEvidence);
|
||||||
idVerificationProperty = new SimpleBooleanProperty(idVerification);
|
idVerificationProperty = new SimpleBooleanProperty(idVerification);
|
||||||
screenCastProperty = new SimpleBooleanProperty(screenCast);
|
screenCastProperty = new SimpleBooleanProperty(screenCast);
|
||||||
feePaymentPolicyProperty = new SimpleObjectProperty<>(feePaymentPolicy);
|
feePaymentPolicyProperty = new SimpleObjectProperty<>(disputeFeePolicy);
|
||||||
summaryNotesProperty = new SimpleStringProperty(summaryNotes);
|
summaryNotesProperty = new SimpleStringProperty(summaryNotes);
|
||||||
|
|
||||||
tamperProofEvidenceProperty.addListener((observable, oldValue, newValue) -> {
|
tamperProofEvidenceProperty.addListener((observable, oldValue, newValue) -> {
|
||||||
|
@ -105,7 +105,7 @@ public final class DisputeResult implements Payload {
|
||||||
screenCast = newValue;
|
screenCast = newValue;
|
||||||
});
|
});
|
||||||
feePaymentPolicyProperty.addListener((observable, oldValue, newValue) -> {
|
feePaymentPolicyProperty.addListener((observable, oldValue, newValue) -> {
|
||||||
feePaymentPolicy = newValue;
|
disputeFeePolicy = newValue;
|
||||||
});
|
});
|
||||||
summaryNotesProperty.addListener((observable, oldValue, newValue) -> {
|
summaryNotesProperty.addListener((observable, oldValue, newValue) -> {
|
||||||
summaryNotes = newValue;
|
summaryNotes = newValue;
|
||||||
|
@ -124,17 +124,17 @@ public final class DisputeResult implements Payload {
|
||||||
return screenCastProperty;
|
return screenCastProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFeePaymentPolicy(FeePaymentPolicy feePaymentPolicy) {
|
public void setDisputeFeePolicy(DisputeFeePolicy disputeFeePolicy) {
|
||||||
this.feePaymentPolicy = feePaymentPolicy;
|
this.disputeFeePolicy = disputeFeePolicy;
|
||||||
feePaymentPolicyProperty.set(feePaymentPolicy);
|
feePaymentPolicyProperty.set(disputeFeePolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyObjectProperty<FeePaymentPolicy> feePaymentPolicyProperty() {
|
public ReadOnlyObjectProperty<DisputeFeePolicy> disputeFeePolicyProperty() {
|
||||||
return feePaymentPolicyProperty;
|
return feePaymentPolicyProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FeePaymentPolicy getFeePaymentPolicy() {
|
public DisputeFeePolicy getDisputeFeePolicy() {
|
||||||
return feePaymentPolicy;
|
return disputeFeePolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ public final class DisputeResult implements Payload {
|
||||||
if (arbitratorPayoutAmount != that.arbitratorPayoutAmount) return false;
|
if (arbitratorPayoutAmount != that.arbitratorPayoutAmount) return false;
|
||||||
if (closeDate != that.closeDate) return false;
|
if (closeDate != that.closeDate) return false;
|
||||||
if (tradeId != null ? !tradeId.equals(that.tradeId) : that.tradeId != null) return false;
|
if (tradeId != null ? !tradeId.equals(that.tradeId) : that.tradeId != null) return false;
|
||||||
if (feePaymentPolicy != that.feePaymentPolicy) return false;
|
if (disputeFeePolicy != that.disputeFeePolicy) return false;
|
||||||
if (summaryNotes != null ? !summaryNotes.equals(that.summaryNotes) : that.summaryNotes != 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)
|
if (disputeCommunicationMessage != null ? !disputeCommunicationMessage.equals(that.disputeCommunicationMessage) : that.disputeCommunicationMessage != null)
|
||||||
return false;
|
return false;
|
||||||
|
@ -246,7 +246,7 @@ public final class DisputeResult implements Payload {
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = tradeId != null ? tradeId.hashCode() : 0;
|
int result = tradeId != null ? tradeId.hashCode() : 0;
|
||||||
result = 31 * result + traderId;
|
result = 31 * result + traderId;
|
||||||
result = 31 * result + (feePaymentPolicy != null ? feePaymentPolicy.hashCode() : 0);
|
result = 31 * result + (disputeFeePolicy != null ? disputeFeePolicy.hashCode() : 0);
|
||||||
result = 31 * result + (tamperProofEvidence ? 1 : 0);
|
result = 31 * result + (tamperProofEvidence ? 1 : 0);
|
||||||
result = 31 * result + (idVerification ? 1 : 0);
|
result = 31 * result + (idVerification ? 1 : 0);
|
||||||
result = 31 * result + (screenCast ? 1 : 0);
|
result = 31 * result + (screenCast ? 1 : 0);
|
||||||
|
|
|
@ -42,7 +42,7 @@ public final class DisputeCommunicationMessage extends DisputeMessage {
|
||||||
private final int traderId;
|
private final int traderId;
|
||||||
private final boolean senderIsTrader;
|
private final boolean senderIsTrader;
|
||||||
private final String message;
|
private final String message;
|
||||||
private final List<Attachment> attachments = new ArrayList<>();
|
private final ArrayList<Attachment> attachments = new ArrayList<>();
|
||||||
private boolean arrived;
|
private boolean arrived;
|
||||||
private boolean storedInMailbox;
|
private boolean storedInMailbox;
|
||||||
private boolean isSystemMessage;
|
private boolean isSystemMessage;
|
||||||
|
|
|
@ -20,11 +20,19 @@ package io.bitsquare.arbitration.messages;
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.messaging.MailboxMessage;
|
import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public abstract class DisputeMessage implements MailboxMessage {
|
public abstract class DisputeMessage implements MailboxMessage {
|
||||||
private final int messageVersion = Version.getP2PMessageVersion();
|
private final int messageVersion = Version.getP2PMessageVersion();
|
||||||
|
private final String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMessageVersion() {
|
public int getMessageVersion() {
|
||||||
return messageVersion;
|
return messageVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUID() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import io.bitsquare.p2p.NodeAddress;
|
||||||
public final class PeerOpenedDisputeMessage extends DisputeMessage {
|
public final class PeerOpenedDisputeMessage extends DisputeMessage {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
|
||||||
public final Dispute dispute;
|
public final Dispute dispute;
|
||||||
private final NodeAddress myNodeAddress;
|
private final NodeAddress myNodeAddress;
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,12 @@
|
||||||
|
|
||||||
package io.bitsquare.btc;
|
package io.bitsquare.btc;
|
||||||
|
|
||||||
import io.bitsquare.common.persistance.Persistable;
|
|
||||||
import org.bitcoinj.core.NetworkParameters;
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
import org.bitcoinj.params.MainNetParams;
|
import org.bitcoinj.params.MainNetParams;
|
||||||
import org.bitcoinj.params.RegTestParams;
|
import org.bitcoinj.params.RegTestParams;
|
||||||
import org.bitcoinj.params.TestNet3Params;
|
import org.bitcoinj.params.TestNet3Params;
|
||||||
|
|
||||||
public enum BitcoinNetwork implements Persistable {
|
public enum BitcoinNetwork {
|
||||||
MAINNET(MainNetParams.get()),
|
MAINNET(MainNetParams.get()),
|
||||||
TESTNET(TestNet3Params.get()),
|
TESTNET(TestNet3Params.get()),
|
||||||
REGTEST(RegTestParams.get());
|
REGTEST(RegTestParams.get());
|
||||||
|
|
|
@ -25,7 +25,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import io.bitsquare.app.Log;
|
import io.bitsquare.app.Log;
|
||||||
import io.bitsquare.btc.data.InputsAndChangeOutput;
|
import io.bitsquare.btc.data.InputsAndChangeOutput;
|
||||||
import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs;
|
import io.bitsquare.btc.data.PreparedDepositTxAndOffererInputs;
|
||||||
import io.bitsquare.btc.data.RawInput;
|
import io.bitsquare.btc.data.RawTransactionInput;
|
||||||
import io.bitsquare.btc.exceptions.SigningException;
|
import io.bitsquare.btc.exceptions.SigningException;
|
||||||
import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
||||||
import io.bitsquare.btc.exceptions.WalletException;
|
import io.bitsquare.btc.exceptions.WalletException;
|
||||||
|
@ -233,7 +233,7 @@ public class TradeWalletService {
|
||||||
|
|
||||||
printTxWithInputs("dummyTX", dummyTX);
|
printTxWithInputs("dummyTX", dummyTX);
|
||||||
|
|
||||||
List<RawInput> rawInputList = dummyTX.getInputs().stream()
|
List<RawTransactionInput> rawTransactionInputList = dummyTX.getInputs().stream()
|
||||||
.map(e -> {
|
.map(e -> {
|
||||||
checkNotNull(e.getConnectedOutput(), "e.getConnectedOutput() must not be null");
|
checkNotNull(e.getConnectedOutput(), "e.getConnectedOutput() must not be null");
|
||||||
checkNotNull(e.getConnectedOutput().getParentTransaction(), "e.getConnectedOutput().getParentTransaction() must not be null");
|
checkNotNull(e.getConnectedOutput().getParentTransaction(), "e.getConnectedOutput().getParentTransaction() must not be null");
|
||||||
|
@ -255,7 +255,7 @@ public class TradeWalletService {
|
||||||
changeOutputAddress = addressFromP2PKHScript.toString();
|
changeOutputAddress = addressFromP2PKHScript.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new InputsAndChangeOutput(rawInputList, changeOutputValue, changeOutputAddress);
|
return new InputsAndChangeOutput(new ArrayList<>(rawTransactionInputList), changeOutputValue, changeOutputAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -265,7 +265,7 @@ public class TradeWalletService {
|
||||||
* @param contractHash The hash of the contract to be added to the OP_RETURN output.
|
* @param contractHash The hash of the contract to be added to the OP_RETURN output.
|
||||||
* @param offererInputAmount The input amount of the offerer.
|
* @param offererInputAmount The input amount of the offerer.
|
||||||
* @param msOutputAmount The output amount to our MS output.
|
* @param msOutputAmount The output amount to our MS output.
|
||||||
* @param takerRawInputs Raw data for the connected outputs for all inputs of the taker (normally 1 input)
|
* @param takerRawTransactionInputs Raw data for the connected outputs for all inputs of the taker (normally 1 input)
|
||||||
* @param takerChangeOutputValue Optional taker change output value
|
* @param takerChangeOutputValue Optional taker change output value
|
||||||
* @param takerChangeAddressString Optional taker change address
|
* @param takerChangeAddressString Optional taker change address
|
||||||
* @param offererAddressInfo The offerers address entry.
|
* @param offererAddressInfo The offerers address entry.
|
||||||
|
@ -281,7 +281,7 @@ public class TradeWalletService {
|
||||||
byte[] contractHash,
|
byte[] contractHash,
|
||||||
Coin offererInputAmount,
|
Coin offererInputAmount,
|
||||||
Coin msOutputAmount,
|
Coin msOutputAmount,
|
||||||
List<RawInput> takerRawInputs,
|
List<RawTransactionInput> takerRawTransactionInputs,
|
||||||
long takerChangeOutputValue,
|
long takerChangeOutputValue,
|
||||||
@Nullable String takerChangeAddressString,
|
@Nullable String takerChangeAddressString,
|
||||||
AddressEntry offererAddressInfo,
|
AddressEntry offererAddressInfo,
|
||||||
|
@ -293,14 +293,14 @@ public class TradeWalletService {
|
||||||
log.trace("offererIsBuyer " + offererIsBuyer);
|
log.trace("offererIsBuyer " + offererIsBuyer);
|
||||||
log.trace("offererInputAmount " + offererInputAmount.toFriendlyString());
|
log.trace("offererInputAmount " + offererInputAmount.toFriendlyString());
|
||||||
log.trace("msOutputAmount " + msOutputAmount.toFriendlyString());
|
log.trace("msOutputAmount " + msOutputAmount.toFriendlyString());
|
||||||
log.trace("takerRawInputs " + takerRawInputs.toString());
|
log.trace("takerRawInputs " + takerRawTransactionInputs.toString());
|
||||||
log.trace("takerChangeOutputValue " + takerChangeOutputValue);
|
log.trace("takerChangeOutputValue " + takerChangeOutputValue);
|
||||||
log.trace("takerChangeAddressString " + takerChangeAddressString);
|
log.trace("takerChangeAddressString " + takerChangeAddressString);
|
||||||
log.trace("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
|
log.trace("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
|
||||||
log.trace("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
|
log.trace("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
|
||||||
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
|
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
|
||||||
|
|
||||||
checkArgument(!takerRawInputs.isEmpty());
|
checkArgument(!takerRawTransactionInputs.isEmpty());
|
||||||
|
|
||||||
// First we construct a dummy TX to get the inputs and outputs we want to use for the real deposit tx.
|
// First we construct a dummy TX to get the inputs and outputs we want to use for the real deposit tx.
|
||||||
// Similar to the way we did in the createTakerDepositTxInputs method.
|
// Similar to the way we did in the createTakerDepositTxInputs method.
|
||||||
|
@ -323,30 +323,30 @@ public class TradeWalletService {
|
||||||
// Now we construct the real deposit tx
|
// Now we construct the real deposit tx
|
||||||
Transaction preparedDepositTx = new Transaction(params);
|
Transaction preparedDepositTx = new Transaction(params);
|
||||||
|
|
||||||
List<RawInput> offererRawInputs = new ArrayList<>();
|
ArrayList<RawTransactionInput> offererRawTransactionInputs = new ArrayList<>();
|
||||||
if (offererIsBuyer) {
|
if (offererIsBuyer) {
|
||||||
// Add buyer inputs
|
// Add buyer inputs
|
||||||
for (TransactionInput input : offererInputs) {
|
for (TransactionInput input : offererInputs) {
|
||||||
preparedDepositTx.addInput(input);
|
preparedDepositTx.addInput(input);
|
||||||
offererRawInputs.add(getRawInputFromTransactionInput(input));
|
offererRawTransactionInputs.add(getRawInputFromTransactionInput(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add seller inputs
|
// Add seller inputs
|
||||||
// the sellers input is not signed so we attach empty script bytes
|
// the sellers input is not signed so we attach empty script bytes
|
||||||
for (RawInput rawInput : takerRawInputs)
|
for (RawTransactionInput rawTransactionInput : takerRawTransactionInputs)
|
||||||
preparedDepositTx.addInput(getTransactionInput(preparedDepositTx, new byte[]{}, rawInput));
|
preparedDepositTx.addInput(getTransactionInput(preparedDepositTx, new byte[]{}, rawTransactionInput));
|
||||||
} else {
|
} else {
|
||||||
// taker is buyer role
|
// taker is buyer role
|
||||||
|
|
||||||
// Add buyer inputs
|
// Add buyer inputs
|
||||||
// the sellers input is not signed so we attach empty script bytes
|
// the sellers input is not signed so we attach empty script bytes
|
||||||
for (RawInput rawInput : takerRawInputs)
|
for (RawTransactionInput rawTransactionInput : takerRawTransactionInputs)
|
||||||
preparedDepositTx.addInput(getTransactionInput(preparedDepositTx, new byte[]{}, rawInput));
|
preparedDepositTx.addInput(getTransactionInput(preparedDepositTx, new byte[]{}, rawTransactionInput));
|
||||||
|
|
||||||
// Add seller inputs
|
// Add seller inputs
|
||||||
for (TransactionInput input : offererInputs) {
|
for (TransactionInput input : offererInputs) {
|
||||||
preparedDepositTx.addInput(input);
|
preparedDepositTx.addInput(input);
|
||||||
offererRawInputs.add(getRawInputFromTransactionInput(input));
|
offererRawTransactionInputs.add(getRawInputFromTransactionInput(input));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@ public class TradeWalletService {
|
||||||
|
|
||||||
printTxWithInputs("preparedDepositTx", preparedDepositTx);
|
printTxWithInputs("preparedDepositTx", preparedDepositTx);
|
||||||
|
|
||||||
return new PreparedDepositTxAndOffererInputs(offererRawInputs, preparedDepositTx.bitcoinSerialize());
|
return new PreparedDepositTxAndOffererInputs(offererRawTransactionInputs, preparedDepositTx.bitcoinSerialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -423,8 +423,8 @@ public class TradeWalletService {
|
||||||
public void takerSignsAndPublishesDepositTx(boolean takerIsSeller,
|
public void takerSignsAndPublishesDepositTx(boolean takerIsSeller,
|
||||||
byte[] contractHash,
|
byte[] contractHash,
|
||||||
byte[] offerersDepositTxSerialized,
|
byte[] offerersDepositTxSerialized,
|
||||||
List<RawInput> buyerInputs,
|
List<RawTransactionInput> buyerInputs,
|
||||||
List<RawInput> sellerInputs,
|
List<RawTransactionInput> sellerInputs,
|
||||||
byte[] buyerPubKey,
|
byte[] buyerPubKey,
|
||||||
byte[] sellerPubKey,
|
byte[] sellerPubKey,
|
||||||
byte[] arbitratorPubKey,
|
byte[] arbitratorPubKey,
|
||||||
|
@ -460,13 +460,13 @@ public class TradeWalletService {
|
||||||
depositTx.addInput(getTransactionInput(depositTx, getScriptProgram(offerersDepositTx, i), buyerInputs.get(i)));
|
depositTx.addInput(getTransactionInput(depositTx, getScriptProgram(offerersDepositTx, i), buyerInputs.get(i)));
|
||||||
|
|
||||||
// Add seller inputs
|
// Add seller inputs
|
||||||
for (RawInput rawInput : sellerInputs)
|
for (RawTransactionInput rawTransactionInput : sellerInputs)
|
||||||
depositTx.addInput(getTransactionInput(depositTx, new byte[]{}, rawInput));
|
depositTx.addInput(getTransactionInput(depositTx, new byte[]{}, rawTransactionInput));
|
||||||
} else {
|
} else {
|
||||||
// taker is buyer
|
// taker is buyer
|
||||||
// Add buyer inputs and apply signature
|
// Add buyer inputs and apply signature
|
||||||
for (RawInput rawInput : buyerInputs)
|
for (RawTransactionInput rawTransactionInput : buyerInputs)
|
||||||
depositTx.addInput(getTransactionInput(depositTx, new byte[]{}, rawInput));
|
depositTx.addInput(getTransactionInput(depositTx, new byte[]{}, rawTransactionInput));
|
||||||
|
|
||||||
// Add seller inputs
|
// Add seller inputs
|
||||||
// We grab the signature from the offerersDepositTx and apply it to the new tx input
|
// We grab the signature from the offerersDepositTx and apply it to the new tx input
|
||||||
|
@ -898,12 +898,12 @@ public class TradeWalletService {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private RawInput getRawInputFromTransactionInput(@NotNull TransactionInput input) {
|
private RawTransactionInput getRawInputFromTransactionInput(@NotNull TransactionInput input) {
|
||||||
checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
|
checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
|
||||||
checkNotNull(input.getConnectedOutput().getParentTransaction(), "input.getConnectedOutput().getParentTransaction() must not be null");
|
checkNotNull(input.getConnectedOutput().getParentTransaction(), "input.getConnectedOutput().getParentTransaction() must not be null");
|
||||||
checkNotNull(input.getValue(), "input.getValue() must not be null");
|
checkNotNull(input.getValue(), "input.getValue() must not be null");
|
||||||
|
|
||||||
return new RawInput(input.getOutpoint().getIndex(), input.getConnectedOutput().getParentTransaction().bitcoinSerialize(), input.getValue().value);
|
return new RawTransactionInput(input.getOutpoint().getIndex(), input.getConnectedOutput().getParentTransaction().bitcoinSerialize(), input.getValue().value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] getScriptProgram(Transaction offerersDepositTx, int i) throws TransactionVerificationException {
|
private byte[] getScriptProgram(Transaction offerersDepositTx, int i) throws TransactionVerificationException {
|
||||||
|
@ -915,12 +915,12 @@ public class TradeWalletService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private TransactionInput getTransactionInput(Transaction depositTx, byte[] scriptProgram, RawInput rawInput) {
|
private TransactionInput getTransactionInput(Transaction depositTx, byte[] scriptProgram, RawTransactionInput rawTransactionInput) {
|
||||||
return new TransactionInput(params,
|
return new TransactionInput(params,
|
||||||
depositTx,
|
depositTx,
|
||||||
scriptProgram,
|
scriptProgram,
|
||||||
new TransactionOutPoint(params, rawInput.index, new Transaction(params, rawInput.parentTransaction)),
|
new TransactionOutPoint(params, rawTransactionInput.index, new Transaction(params, rawTransactionInput.parentTransaction)),
|
||||||
Coin.valueOf(rawInput.value));
|
Coin.valueOf(rawTransactionInput.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,22 +18,22 @@
|
||||||
package io.bitsquare.btc.data;
|
package io.bitsquare.btc.data;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.List;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
|
||||||
public class InputsAndChangeOutput {
|
public class InputsAndChangeOutput {
|
||||||
public final List<RawInput> rawInputs;
|
public final ArrayList<RawTransactionInput> rawTransactionInputs;
|
||||||
|
|
||||||
// Is set to 0L in case we don't have an output
|
// Is set to 0L in case we don't have an output
|
||||||
public final long changeOutputValue;
|
public final long changeOutputValue;
|
||||||
@Nullable
|
@Nullable
|
||||||
public final String changeOutputAddress;
|
public final String changeOutputAddress;
|
||||||
|
|
||||||
public InputsAndChangeOutput(List<RawInput> rawInputs, long changeOutputValue, @Nullable String changeOutputAddress) {
|
public InputsAndChangeOutput(ArrayList<RawTransactionInput> rawTransactionInputs, long changeOutputValue, @Nullable String changeOutputAddress) {
|
||||||
checkArgument(!rawInputs.isEmpty(), "rawInputs.isEmpty()");
|
checkArgument(!rawTransactionInputs.isEmpty(), "rawInputs.isEmpty()");
|
||||||
|
|
||||||
this.rawInputs = rawInputs;
|
this.rawTransactionInputs = rawTransactionInputs;
|
||||||
this.changeOutputValue = changeOutputValue;
|
this.changeOutputValue = changeOutputValue;
|
||||||
this.changeOutputAddress = changeOutputAddress;
|
this.changeOutputAddress = changeOutputAddress;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,13 @@
|
||||||
|
|
||||||
package io.bitsquare.btc.data;
|
package io.bitsquare.btc.data;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class PreparedDepositTxAndOffererInputs {
|
public class PreparedDepositTxAndOffererInputs {
|
||||||
public final List<RawInput> rawOffererInputs;
|
public final ArrayList<RawTransactionInput> rawOffererInputs;
|
||||||
public final byte[] depositTransaction;
|
public final byte[] depositTransaction;
|
||||||
|
|
||||||
public PreparedDepositTxAndOffererInputs(List<RawInput> rawOffererInputs, byte[] depositTransaction) {
|
public PreparedDepositTxAndOffererInputs(ArrayList<RawTransactionInput> rawOffererInputs, byte[] depositTransaction) {
|
||||||
this.rawOffererInputs = rawOffererInputs;
|
this.rawOffererInputs = rawOffererInputs;
|
||||||
this.depositTransaction = depositTransaction;
|
this.depositTransaction = depositTransaction;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ import io.bitsquare.common.wire.Payload;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public final class RawInput implements Payload {
|
public final class RawTransactionInput implements Payload {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ public final class RawInput implements Payload {
|
||||||
public final byte[] parentTransaction;
|
public final byte[] parentTransaction;
|
||||||
public final long value;
|
public final long value;
|
||||||
|
|
||||||
public RawInput(long index, byte[] parentTransaction, long value) {
|
public RawTransactionInput(long index, byte[] parentTransaction, long value) {
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.parentTransaction = parentTransaction;
|
this.parentTransaction = parentTransaction;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
@ -39,13 +39,13 @@ public final class RawInput implements Payload {
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (!(o instanceof RawInput)) return false;
|
if (!(o instanceof RawTransactionInput)) return false;
|
||||||
|
|
||||||
RawInput rawInput = (RawInput) o;
|
RawTransactionInput rawTransactionInput = (RawTransactionInput) o;
|
||||||
|
|
||||||
if (index != rawInput.index) return false;
|
if (index != rawTransactionInput.index) return false;
|
||||||
if (value != rawInput.value) return false;
|
if (value != rawTransactionInput.value) return false;
|
||||||
return Arrays.equals(parentTransaction, rawInput.parentTransaction);
|
return Arrays.equals(parentTransaction, rawTransactionInput.parentTransaction);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,9 @@ import io.bitsquare.btc.TradeWalletService;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.common.crypto.KeyRing;
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.common.taskrunner.Model;
|
import io.bitsquare.common.taskrunner.Model;
|
||||||
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.P2PService;
|
import io.bitsquare.p2p.P2PService;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey;
|
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
import io.bitsquare.trade.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
import io.bitsquare.trade.offer.OpenOfferManager;
|
import io.bitsquare.trade.offer.OpenOfferManager;
|
||||||
|
@ -82,6 +82,7 @@ public abstract class Trade implements Tradable, Model {
|
||||||
FIAT_PAYMENT_RECEIPT_MSG_SENT(Phase.FIAT_RECEIVED),
|
FIAT_PAYMENT_RECEIPT_MSG_SENT(Phase.FIAT_RECEIVED),
|
||||||
FIAT_PAYMENT_RECEIPT_MSG_RECEIVED(Phase.FIAT_RECEIVED),
|
FIAT_PAYMENT_RECEIPT_MSG_RECEIVED(Phase.FIAT_RECEIVED),
|
||||||
|
|
||||||
|
PAYOUT_TX_COMMITTED(Phase.PAYOUT_PAID),
|
||||||
PAYOUT_TX_SENT(Phase.PAYOUT_PAID),
|
PAYOUT_TX_SENT(Phase.PAYOUT_PAID),
|
||||||
PAYOUT_TX_RECEIVED_AND_COMMITTED(Phase.PAYOUT_PAID),
|
PAYOUT_TX_RECEIVED_AND_COMMITTED(Phase.PAYOUT_PAID),
|
||||||
PAYOUT_BROAD_CASTED(Phase.PAYOUT_PAID),
|
PAYOUT_BROAD_CASTED(Phase.PAYOUT_PAID),
|
||||||
|
|
|
@ -26,13 +26,13 @@ import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.common.crypto.KeyRing;
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.common.handlers.FaultHandler;
|
import io.bitsquare.common.handlers.FaultHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.p2p.BootstrapListener;
|
import io.bitsquare.p2p.BootstrapListener;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.P2PService;
|
import io.bitsquare.p2p.P2PService;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedDirectMessageListener;
|
import io.bitsquare.p2p.messaging.DecryptedDirectMessageListener;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMailboxListener;
|
import io.bitsquare.p2p.messaging.DecryptedMailboxListener;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey;
|
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
import io.bitsquare.trade.closed.ClosedTradableManager;
|
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||||
import io.bitsquare.trade.failed.FailedTradesManager;
|
import io.bitsquare.trade.failed.FailedTradesManager;
|
||||||
|
|
|
@ -25,8 +25,8 @@ import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.common.util.JsonExclude;
|
import io.bitsquare.common.util.JsonExclude;
|
||||||
import io.bitsquare.locale.Country;
|
import io.bitsquare.locale.Country;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.storage.data.RequiresOwnerIsOnlinePayload;
|
import io.bitsquare.p2p.storage.payload.RequiresOwnerIsOnlinePayload;
|
||||||
import io.bitsquare.p2p.storage.data.StoragePayload;
|
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||||
import io.bitsquare.payment.PaymentMethod;
|
import io.bitsquare.payment.PaymentMethod;
|
||||||
import io.bitsquare.trade.protocol.availability.OfferAvailabilityModel;
|
import io.bitsquare.trade.protocol.availability.OfferAvailabilityModel;
|
||||||
import io.bitsquare.trade.protocol.availability.OfferAvailabilityProtocol;
|
import io.bitsquare.trade.protocol.availability.OfferAvailabilityProtocol;
|
||||||
|
@ -40,6 +40,7 @@ import org.slf4j.LoggerFactory;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
@ -48,20 +49,25 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload {
|
public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload {
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Static
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
@JsonExclude
|
@JsonExclude
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
@JsonExclude
|
@JsonExclude
|
||||||
private static final Logger log = LoggerFactory.getLogger(Offer.class);
|
private static final Logger log = LoggerFactory.getLogger(Offer.class);
|
||||||
|
public static final long TTL = TimeUnit.SECONDS.toMillis(60);
|
||||||
// public static final long TTL = TimeUnit.SECONDS.toMillis(60);
|
|
||||||
public static final long TTL = TimeUnit.SECONDS.toMillis(10); //TODO
|
|
||||||
|
|
||||||
public final static String TAC_OFFERER = "When placing that offer I accept that anyone who fulfills my conditions can " +
|
public final static String TAC_OFFERER = "When placing that offer I accept that anyone who fulfills my conditions can " +
|
||||||
"take that offer.";
|
"take that offer.";
|
||||||
public static final String TAC_TAKER = "With taking the offer I commit to the trade conditions as defined.";
|
public static final String TAC_TAKER = "With taking the offer I commit to the trade conditions as defined.";
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Enums
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public enum Direction {BUY, SELL}
|
public enum Direction {BUY, SELL}
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
|
@ -74,6 +80,10 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Instance fields
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
private final Direction direction;
|
private final Direction direction;
|
||||||
private final String currencyCode;
|
private final String currencyCode;
|
||||||
|
@ -91,8 +101,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||||
private final String offererPaymentAccountId;
|
private final String offererPaymentAccountId;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final List<String> acceptedCountryCodes;
|
private final ArrayList<String> acceptedCountryCodes;
|
||||||
private final List<NodeAddress> arbitratorNodeAddresses;
|
private final ArrayList<NodeAddress> arbitratorNodeAddresses;
|
||||||
|
|
||||||
// Mutable property. Has to be set before offer is save in P2P network as it changes the objects hash!
|
// Mutable property. Has to be set before offer is save in P2P network as it changes the objects hash!
|
||||||
private String offerFeePaymentTxID;
|
private String offerFeePaymentTxID;
|
||||||
|
@ -104,6 +114,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||||
@JsonExclude
|
@JsonExclude
|
||||||
transient private ObjectProperty<State> stateProperty = new SimpleObjectProperty<>(state);
|
transient private ObjectProperty<State> stateProperty = new SimpleObjectProperty<>(state);
|
||||||
@JsonExclude
|
@JsonExclude
|
||||||
|
@Nullable
|
||||||
transient private OfferAvailabilityProtocol availabilityProtocol;
|
transient private OfferAvailabilityProtocol availabilityProtocol;
|
||||||
@JsonExclude
|
@JsonExclude
|
||||||
transient private StringProperty errorMessageProperty = new SimpleStringProperty();
|
transient private StringProperty errorMessageProperty = new SimpleStringProperty();
|
||||||
|
@ -124,8 +135,8 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||||
String currencyCode,
|
String currencyCode,
|
||||||
@Nullable Country paymentMethodCountry,
|
@Nullable Country paymentMethodCountry,
|
||||||
String offererPaymentAccountId,
|
String offererPaymentAccountId,
|
||||||
List<NodeAddress> arbitratorNodeAddresses,
|
ArrayList<NodeAddress> arbitratorNodeAddresses,
|
||||||
@Nullable List<String> acceptedCountryCodes) {
|
@Nullable ArrayList<String> acceptedCountryCodes) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.offererNodeAddress = offererNodeAddress;
|
this.offererNodeAddress = offererNodeAddress;
|
||||||
this.pubKeyRing = pubKeyRing;
|
this.pubKeyRing = pubKeyRing;
|
||||||
|
|
|
@ -21,7 +21,7 @@ import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.p2p.P2PService;
|
import io.bitsquare.p2p.P2PService;
|
||||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -58,18 +58,18 @@ public class OfferBookService {
|
||||||
|
|
||||||
p2PService.addHashSetChangedListener(new HashMapChangedListener() {
|
p2PService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onAdded(ProtectedData data) {
|
public void onAdded(ProtectedStorageEntry data) {
|
||||||
offerBookChangedListeners.stream().forEach(listener -> {
|
offerBookChangedListeners.stream().forEach(listener -> {
|
||||||
if (data.expirablePayload instanceof Offer)
|
if (data.getStoragePayload() instanceof Offer)
|
||||||
listener.onAdded((Offer) data.expirablePayload);
|
listener.onAdded((Offer) data.getStoragePayload());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemoved(ProtectedData data) {
|
public void onRemoved(ProtectedStorageEntry data) {
|
||||||
offerBookChangedListeners.stream().forEach(listener -> {
|
offerBookChangedListeners.stream().forEach(listener -> {
|
||||||
if (data.expirablePayload instanceof Offer)
|
if (data.getStoragePayload() instanceof Offer)
|
||||||
listener.onRemoved((Offer) data.expirablePayload);
|
listener.onRemoved((Offer) data.getStoragePayload());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -126,8 +126,8 @@ public class OfferBookService {
|
||||||
|
|
||||||
public List<Offer> getOffers() {
|
public List<Offer> getOffers() {
|
||||||
return p2PService.getDataMap().values().stream()
|
return p2PService.getDataMap().values().stream()
|
||||||
.filter(data -> data.expirablePayload instanceof Offer)
|
.filter(data -> data.getStoragePayload() instanceof Offer)
|
||||||
.map(data -> (Offer) data.expirablePayload)
|
.map(data -> (Offer) data.getStoragePayload())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,12 +26,12 @@ import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.crypto.KeyRing;
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
import io.bitsquare.common.handlers.ErrorMessageHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.p2p.BootstrapListener;
|
import io.bitsquare.p2p.BootstrapListener;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.P2PService;
|
import io.bitsquare.p2p.P2PService;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedDirectMessageListener;
|
import io.bitsquare.p2p.messaging.DecryptedDirectMessageListener;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey;
|
|
||||||
import io.bitsquare.p2p.messaging.SendDirectMessageListener;
|
import io.bitsquare.p2p.messaging.SendDirectMessageListener;
|
||||||
import io.bitsquare.p2p.peers.PeerManager;
|
import io.bitsquare.p2p.peers.PeerManager;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
|
|
|
@ -22,7 +22,7 @@ import io.bitsquare.arbitration.ArbitratorManager;
|
||||||
import io.bitsquare.btc.AddressEntry;
|
import io.bitsquare.btc.AddressEntry;
|
||||||
import io.bitsquare.btc.TradeWalletService;
|
import io.bitsquare.btc.TradeWalletService;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.btc.data.RawInput;
|
import io.bitsquare.btc.data.RawTransactionInput;
|
||||||
import io.bitsquare.common.crypto.KeyRing;
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.common.crypto.PubKeyRing;
|
import io.bitsquare.common.crypto.PubKeyRing;
|
||||||
import io.bitsquare.common.taskrunner.Model;
|
import io.bitsquare.common.taskrunner.Model;
|
||||||
|
@ -44,6 +44,7 @@ import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ProcessModel implements Model, Serializable {
|
public class ProcessModel implements Model, Serializable {
|
||||||
|
@ -74,7 +75,7 @@ public class ProcessModel implements Model, Serializable {
|
||||||
// After successful verified we copy that over to the trade.tradingPeerAddress
|
// After successful verified we copy that over to the trade.tradingPeerAddress
|
||||||
private NodeAddress tempTradingPeerNodeAddress;
|
private NodeAddress tempTradingPeerNodeAddress;
|
||||||
private byte[] preparedDepositTx;
|
private byte[] preparedDepositTx;
|
||||||
private List<RawInput> rawInputs;
|
private ArrayList<RawTransactionInput> rawTransactionInputs;
|
||||||
private long changeOutputValue;
|
private long changeOutputValue;
|
||||||
@Nullable
|
@Nullable
|
||||||
private String changeOutputAddress;
|
private String changeOutputAddress;
|
||||||
|
@ -243,12 +244,12 @@ public class ProcessModel implements Model, Serializable {
|
||||||
return preparedDepositTx;
|
return preparedDepositTx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRawInputs(List<RawInput> rawInputs) {
|
public void setRawTransactionInputs(ArrayList<RawTransactionInput> rawTransactionInputs) {
|
||||||
this.rawInputs = rawInputs;
|
this.rawTransactionInputs = rawTransactionInputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RawInput> getRawInputs() {
|
public ArrayList<RawTransactionInput> getRawTransactionInputs() {
|
||||||
return rawInputs;
|
return rawTransactionInputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChangeOutputValue(long changeOutputValue) {
|
public void setChangeOutputValue(long changeOutputValue) {
|
||||||
|
|
|
@ -20,10 +20,10 @@ package io.bitsquare.trade.protocol.trade;
|
||||||
import io.bitsquare.common.Timer;
|
import io.bitsquare.common.Timer;
|
||||||
import io.bitsquare.common.UserThread;
|
import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.crypto.PubKeyRing;
|
import io.bitsquare.common.crypto.PubKeyRing;
|
||||||
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedDirectMessageListener;
|
import io.bitsquare.p2p.messaging.DecryptedDirectMessageListener;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey;
|
|
||||||
import io.bitsquare.trade.OffererTrade;
|
import io.bitsquare.trade.OffererTrade;
|
||||||
import io.bitsquare.trade.TakerTrade;
|
import io.bitsquare.trade.TakerTrade;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
package io.bitsquare.trade.protocol.trade;
|
package io.bitsquare.trade.protocol.trade;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.btc.data.RawInput;
|
import io.bitsquare.btc.data.RawTransactionInput;
|
||||||
import io.bitsquare.common.crypto.PubKeyRing;
|
import io.bitsquare.common.crypto.PubKeyRing;
|
||||||
import io.bitsquare.common.persistance.Persistable;
|
import io.bitsquare.common.persistance.Persistable;
|
||||||
import io.bitsquare.payment.PaymentAccountContractData;
|
import io.bitsquare.payment.PaymentAccountContractData;
|
||||||
|
@ -47,7 +47,7 @@ public final class TradingPeer implements Persistable {
|
||||||
private byte[] signature;
|
private byte[] signature;
|
||||||
private PubKeyRing pubKeyRing;
|
private PubKeyRing pubKeyRing;
|
||||||
private byte[] tradeWalletPubKey;
|
private byte[] tradeWalletPubKey;
|
||||||
private List<RawInput> rawInputs;
|
private List<RawTransactionInput> rawTransactionInputs;
|
||||||
private long changeOutputValue;
|
private long changeOutputValue;
|
||||||
@Nullable
|
@Nullable
|
||||||
private String changeOutputAddress;
|
private String changeOutputAddress;
|
||||||
|
@ -138,12 +138,12 @@ public final class TradingPeer implements Persistable {
|
||||||
this.pubKeyRing = pubKeyRing;
|
this.pubKeyRing = pubKeyRing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRawInputs(List<RawInput> rawInputs) {
|
public void setRawTransactionInputs(List<RawTransactionInput> rawTransactionInputs) {
|
||||||
this.rawInputs = rawInputs;
|
this.rawTransactionInputs = rawTransactionInputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RawInput> getRawInputs() {
|
public List<RawTransactionInput> getRawTransactionInputs() {
|
||||||
return rawInputs;
|
return rawTransactionInputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChangeOutputValue(long changeOutputValue) {
|
public void setChangeOutputValue(long changeOutputValue) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
public final class DepositTxPublishedMessage extends TradeMessage implements MailboxMessage {
|
public final class DepositTxPublishedMessage extends TradeMessage implements MailboxMessage {
|
||||||
|
@ -31,6 +32,7 @@ public final class DepositTxPublishedMessage extends TradeMessage implements Mai
|
||||||
|
|
||||||
public final byte[] depositTx;
|
public final byte[] depositTx;
|
||||||
private final NodeAddress senderNodeAddress;
|
private final NodeAddress senderNodeAddress;
|
||||||
|
private final String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
public DepositTxPublishedMessage(String tradeId, byte[] depositTx, NodeAddress senderNodeAddress) {
|
public DepositTxPublishedMessage(String tradeId, byte[] depositTx, NodeAddress senderNodeAddress) {
|
||||||
super(tradeId);
|
super(tradeId);
|
||||||
|
@ -43,6 +45,11 @@ public final class DepositTxPublishedMessage extends TradeMessage implements Mai
|
||||||
return senderNodeAddress;
|
return senderNodeAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUID() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -52,7 +59,9 @@ public final class DepositTxPublishedMessage extends TradeMessage implements Mai
|
||||||
DepositTxPublishedMessage that = (DepositTxPublishedMessage) o;
|
DepositTxPublishedMessage that = (DepositTxPublishedMessage) o;
|
||||||
|
|
||||||
if (!Arrays.equals(depositTx, that.depositTx)) return false;
|
if (!Arrays.equals(depositTx, that.depositTx)) return false;
|
||||||
return !(senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null);
|
if (senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null)
|
||||||
|
return false;
|
||||||
|
return !(uid != null ? !uid.equals(that.uid) : that.uid != null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +70,7 @@ public final class DepositTxPublishedMessage extends TradeMessage implements Mai
|
||||||
int result = super.hashCode();
|
int result = super.hashCode();
|
||||||
result = 31 * result + (depositTx != null ? Arrays.hashCode(depositTx) : 0);
|
result = 31 * result + (depositTx != null ? Arrays.hashCode(depositTx) : 0);
|
||||||
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
||||||
|
result = 31 * result + (uid != null ? uid.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.messaging.MailboxMessage;
|
import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
public final class FiatTransferStartedMessage extends TradeMessage implements MailboxMessage {
|
public final class FiatTransferStartedMessage extends TradeMessage implements MailboxMessage {
|
||||||
|
@ -30,6 +31,7 @@ public final class FiatTransferStartedMessage extends TradeMessage implements Ma
|
||||||
|
|
||||||
public final String buyerPayoutAddress;
|
public final String buyerPayoutAddress;
|
||||||
private final NodeAddress senderNodeAddress;
|
private final NodeAddress senderNodeAddress;
|
||||||
|
private final String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
public FiatTransferStartedMessage(String tradeId, String buyerPayoutAddress, NodeAddress senderNodeAddress) {
|
public FiatTransferStartedMessage(String tradeId, String buyerPayoutAddress, NodeAddress senderNodeAddress) {
|
||||||
super(tradeId);
|
super(tradeId);
|
||||||
|
@ -42,6 +44,11 @@ public final class FiatTransferStartedMessage extends TradeMessage implements Ma
|
||||||
return senderNodeAddress;
|
return senderNodeAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUID() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -52,7 +59,9 @@ public final class FiatTransferStartedMessage extends TradeMessage implements Ma
|
||||||
|
|
||||||
if (buyerPayoutAddress != null ? !buyerPayoutAddress.equals(that.buyerPayoutAddress) : that.buyerPayoutAddress != null)
|
if (buyerPayoutAddress != null ? !buyerPayoutAddress.equals(that.buyerPayoutAddress) : that.buyerPayoutAddress != null)
|
||||||
return false;
|
return false;
|
||||||
return !(senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null);
|
if (senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null)
|
||||||
|
return false;
|
||||||
|
return !(uid != null ? !uid.equals(that.uid) : that.uid != null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +70,7 @@ public final class FiatTransferStartedMessage extends TradeMessage implements Ma
|
||||||
int result = super.hashCode();
|
int result = super.hashCode();
|
||||||
result = 31 * result + (buyerPayoutAddress != null ? buyerPayoutAddress.hashCode() : 0);
|
result = 31 * result + (buyerPayoutAddress != null ? buyerPayoutAddress.hashCode() : 0);
|
||||||
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
||||||
|
result = 31 * result + (uid != null ? uid.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
public final class FinalizePayoutTxRequest extends TradeMessage implements MailboxMessage {
|
public final class FinalizePayoutTxRequest extends TradeMessage implements MailboxMessage {
|
||||||
|
@ -33,6 +34,7 @@ public final class FinalizePayoutTxRequest extends TradeMessage implements Mailb
|
||||||
public final String sellerPayoutAddress;
|
public final String sellerPayoutAddress;
|
||||||
public final long lockTimeAsBlockHeight;
|
public final long lockTimeAsBlockHeight;
|
||||||
private final NodeAddress senderNodeAddress;
|
private final NodeAddress senderNodeAddress;
|
||||||
|
private final String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
public FinalizePayoutTxRequest(String tradeId,
|
public FinalizePayoutTxRequest(String tradeId,
|
||||||
byte[] sellerSignature,
|
byte[] sellerSignature,
|
||||||
|
@ -51,6 +53,11 @@ public final class FinalizePayoutTxRequest extends TradeMessage implements Mailb
|
||||||
return senderNodeAddress;
|
return senderNodeAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUID() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -63,7 +70,9 @@ public final class FinalizePayoutTxRequest extends TradeMessage implements Mailb
|
||||||
if (!Arrays.equals(sellerSignature, that.sellerSignature)) return false;
|
if (!Arrays.equals(sellerSignature, that.sellerSignature)) return false;
|
||||||
if (sellerPayoutAddress != null ? !sellerPayoutAddress.equals(that.sellerPayoutAddress) : that.sellerPayoutAddress != null)
|
if (sellerPayoutAddress != null ? !sellerPayoutAddress.equals(that.sellerPayoutAddress) : that.sellerPayoutAddress != null)
|
||||||
return false;
|
return false;
|
||||||
return !(senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null);
|
if (senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null)
|
||||||
|
return false;
|
||||||
|
return !(uid != null ? !uid.equals(that.uid) : that.uid != null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +83,7 @@ public final class FinalizePayoutTxRequest extends TradeMessage implements Mailb
|
||||||
result = 31 * result + (sellerPayoutAddress != null ? sellerPayoutAddress.hashCode() : 0);
|
result = 31 * result + (sellerPayoutAddress != null ? sellerPayoutAddress.hashCode() : 0);
|
||||||
result = 31 * result + (int) (lockTimeAsBlockHeight ^ (lockTimeAsBlockHeight >>> 32));
|
result = 31 * result + (int) (lockTimeAsBlockHeight ^ (lockTimeAsBlockHeight >>> 32));
|
||||||
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
||||||
|
result = 31 * result + (uid != null ? uid.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,15 +18,16 @@
|
||||||
package io.bitsquare.trade.protocol.trade.messages;
|
package io.bitsquare.trade.protocol.trade.messages;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.btc.data.RawInput;
|
import io.bitsquare.btc.data.RawTransactionInput;
|
||||||
import io.bitsquare.common.crypto.PubKeyRing;
|
import io.bitsquare.common.crypto.PubKeyRing;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.messaging.MailboxMessage;
|
import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
import io.bitsquare.payment.PaymentAccountContractData;
|
import io.bitsquare.payment.PaymentAccountContractData;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
public final class PayDepositRequest extends TradeMessage implements MailboxMessage {
|
public final class PayDepositRequest extends TradeMessage implements MailboxMessage {
|
||||||
|
@ -35,7 +36,7 @@ public final class PayDepositRequest extends TradeMessage implements MailboxMess
|
||||||
|
|
||||||
public final long tradeAmount;
|
public final long tradeAmount;
|
||||||
public final byte[] takerTradeWalletPubKey;
|
public final byte[] takerTradeWalletPubKey;
|
||||||
public final List<RawInput> rawInputs;
|
public final ArrayList<RawTransactionInput> rawTransactionInputs;
|
||||||
public final long changeOutputValue;
|
public final long changeOutputValue;
|
||||||
public final String changeOutputAddress;
|
public final String changeOutputAddress;
|
||||||
public final String takerPayoutAddressString;
|
public final String takerPayoutAddressString;
|
||||||
|
@ -43,14 +44,15 @@ public final class PayDepositRequest extends TradeMessage implements MailboxMess
|
||||||
public final PaymentAccountContractData takerPaymentAccountContractData;
|
public final PaymentAccountContractData takerPaymentAccountContractData;
|
||||||
public final String takerAccountId;
|
public final String takerAccountId;
|
||||||
public final String takeOfferFeeTxId;
|
public final String takeOfferFeeTxId;
|
||||||
public final List<NodeAddress> acceptedArbitratorNodeAddresses;
|
public final ArrayList<NodeAddress> acceptedArbitratorNodeAddresses;
|
||||||
public final NodeAddress arbitratorNodeAddress;
|
public final NodeAddress arbitratorNodeAddress;
|
||||||
private final NodeAddress senderNodeAddress;
|
private final NodeAddress senderNodeAddress;
|
||||||
|
private final String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
public PayDepositRequest(NodeAddress senderNodeAddress,
|
public PayDepositRequest(NodeAddress senderNodeAddress,
|
||||||
String tradeId,
|
String tradeId,
|
||||||
long tradeAmount,
|
long tradeAmount,
|
||||||
List<RawInput> rawInputs,
|
ArrayList<RawTransactionInput> rawTransactionInputs,
|
||||||
long changeOutputValue,
|
long changeOutputValue,
|
||||||
String changeOutputAddress,
|
String changeOutputAddress,
|
||||||
byte[] takerTradeWalletPubKey,
|
byte[] takerTradeWalletPubKey,
|
||||||
|
@ -59,12 +61,12 @@ public final class PayDepositRequest extends TradeMessage implements MailboxMess
|
||||||
PaymentAccountContractData takerPaymentAccountContractData,
|
PaymentAccountContractData takerPaymentAccountContractData,
|
||||||
String takerAccountId,
|
String takerAccountId,
|
||||||
String takeOfferFeeTxId,
|
String takeOfferFeeTxId,
|
||||||
List<NodeAddress> acceptedArbitratorNodeAddresses,
|
ArrayList<NodeAddress> acceptedArbitratorNodeAddresses,
|
||||||
NodeAddress arbitratorNodeAddress) {
|
NodeAddress arbitratorNodeAddress) {
|
||||||
super(tradeId);
|
super(tradeId);
|
||||||
this.senderNodeAddress = senderNodeAddress;
|
this.senderNodeAddress = senderNodeAddress;
|
||||||
this.tradeAmount = tradeAmount;
|
this.tradeAmount = tradeAmount;
|
||||||
this.rawInputs = rawInputs;
|
this.rawTransactionInputs = rawTransactionInputs;
|
||||||
this.changeOutputValue = changeOutputValue;
|
this.changeOutputValue = changeOutputValue;
|
||||||
this.changeOutputAddress = changeOutputAddress;
|
this.changeOutputAddress = changeOutputAddress;
|
||||||
this.takerPayoutAddressString = takerPayoutAddressString;
|
this.takerPayoutAddressString = takerPayoutAddressString;
|
||||||
|
@ -82,6 +84,11 @@ public final class PayDepositRequest extends TradeMessage implements MailboxMess
|
||||||
return senderNodeAddress;
|
return senderNodeAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUID() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -93,7 +100,8 @@ public final class PayDepositRequest extends TradeMessage implements MailboxMess
|
||||||
if (tradeAmount != that.tradeAmount) return false;
|
if (tradeAmount != that.tradeAmount) return false;
|
||||||
if (changeOutputValue != that.changeOutputValue) return false;
|
if (changeOutputValue != that.changeOutputValue) return false;
|
||||||
if (!Arrays.equals(takerTradeWalletPubKey, that.takerTradeWalletPubKey)) return false;
|
if (!Arrays.equals(takerTradeWalletPubKey, that.takerTradeWalletPubKey)) return false;
|
||||||
if (rawInputs != null ? !rawInputs.equals(that.rawInputs) : that.rawInputs != null) return false;
|
if (rawTransactionInputs != null ? !rawTransactionInputs.equals(that.rawTransactionInputs) : that.rawTransactionInputs != null)
|
||||||
|
return false;
|
||||||
if (changeOutputAddress != null ? !changeOutputAddress.equals(that.changeOutputAddress) : that.changeOutputAddress != null)
|
if (changeOutputAddress != null ? !changeOutputAddress.equals(that.changeOutputAddress) : that.changeOutputAddress != null)
|
||||||
return false;
|
return false;
|
||||||
if (takerPayoutAddressString != null ? !takerPayoutAddressString.equals(that.takerPayoutAddressString) : that.takerPayoutAddressString != null)
|
if (takerPayoutAddressString != null ? !takerPayoutAddressString.equals(that.takerPayoutAddressString) : that.takerPayoutAddressString != null)
|
||||||
|
@ -110,7 +118,9 @@ public final class PayDepositRequest extends TradeMessage implements MailboxMess
|
||||||
return false;
|
return false;
|
||||||
if (arbitratorNodeAddress != null ? !arbitratorNodeAddress.equals(that.arbitratorNodeAddress) : that.arbitratorNodeAddress != null)
|
if (arbitratorNodeAddress != null ? !arbitratorNodeAddress.equals(that.arbitratorNodeAddress) : that.arbitratorNodeAddress != null)
|
||||||
return false;
|
return false;
|
||||||
return !(senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null);
|
if (senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null)
|
||||||
|
return false;
|
||||||
|
return !(uid != null ? !uid.equals(that.uid) : that.uid != null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +129,7 @@ public final class PayDepositRequest extends TradeMessage implements MailboxMess
|
||||||
int result = super.hashCode();
|
int result = super.hashCode();
|
||||||
result = 31 * result + (int) (tradeAmount ^ (tradeAmount >>> 32));
|
result = 31 * result + (int) (tradeAmount ^ (tradeAmount >>> 32));
|
||||||
result = 31 * result + (takerTradeWalletPubKey != null ? Arrays.hashCode(takerTradeWalletPubKey) : 0);
|
result = 31 * result + (takerTradeWalletPubKey != null ? Arrays.hashCode(takerTradeWalletPubKey) : 0);
|
||||||
result = 31 * result + (rawInputs != null ? rawInputs.hashCode() : 0);
|
result = 31 * result + (rawTransactionInputs != null ? rawTransactionInputs.hashCode() : 0);
|
||||||
result = 31 * result + (int) (changeOutputValue ^ (changeOutputValue >>> 32));
|
result = 31 * result + (int) (changeOutputValue ^ (changeOutputValue >>> 32));
|
||||||
result = 31 * result + (changeOutputAddress != null ? changeOutputAddress.hashCode() : 0);
|
result = 31 * result + (changeOutputAddress != null ? changeOutputAddress.hashCode() : 0);
|
||||||
result = 31 * result + (takerPayoutAddressString != null ? takerPayoutAddressString.hashCode() : 0);
|
result = 31 * result + (takerPayoutAddressString != null ? takerPayoutAddressString.hashCode() : 0);
|
||||||
|
@ -130,6 +140,7 @@ public final class PayDepositRequest extends TradeMessage implements MailboxMess
|
||||||
result = 31 * result + (acceptedArbitratorNodeAddresses != null ? acceptedArbitratorNodeAddresses.hashCode() : 0);
|
result = 31 * result + (acceptedArbitratorNodeAddresses != null ? acceptedArbitratorNodeAddresses.hashCode() : 0);
|
||||||
result = 31 * result + (arbitratorNodeAddress != null ? arbitratorNodeAddress.hashCode() : 0);
|
result = 31 * result + (arbitratorNodeAddress != null ? arbitratorNodeAddress.hashCode() : 0);
|
||||||
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
||||||
|
result = 31 * result + (uid != null ? uid.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
public final class PayoutTxFinalizedMessage extends TradeMessage implements MailboxMessage {
|
public final class PayoutTxFinalizedMessage extends TradeMessage implements MailboxMessage {
|
||||||
|
@ -31,6 +32,7 @@ public final class PayoutTxFinalizedMessage extends TradeMessage implements Mail
|
||||||
|
|
||||||
public final byte[] payoutTx;
|
public final byte[] payoutTx;
|
||||||
private final NodeAddress senderNodeAddress;
|
private final NodeAddress senderNodeAddress;
|
||||||
|
private final String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
public PayoutTxFinalizedMessage(String tradeId, byte[] payoutTx, NodeAddress senderNodeAddress) {
|
public PayoutTxFinalizedMessage(String tradeId, byte[] payoutTx, NodeAddress senderNodeAddress) {
|
||||||
super(tradeId);
|
super(tradeId);
|
||||||
|
@ -43,6 +45,11 @@ public final class PayoutTxFinalizedMessage extends TradeMessage implements Mail
|
||||||
return senderNodeAddress;
|
return senderNodeAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUID() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -52,7 +59,9 @@ public final class PayoutTxFinalizedMessage extends TradeMessage implements Mail
|
||||||
PayoutTxFinalizedMessage that = (PayoutTxFinalizedMessage) o;
|
PayoutTxFinalizedMessage that = (PayoutTxFinalizedMessage) o;
|
||||||
|
|
||||||
if (!Arrays.equals(payoutTx, that.payoutTx)) return false;
|
if (!Arrays.equals(payoutTx, that.payoutTx)) return false;
|
||||||
return !(senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null);
|
if (senderNodeAddress != null ? !senderNodeAddress.equals(that.senderNodeAddress) : that.senderNodeAddress != null)
|
||||||
|
return false;
|
||||||
|
return !(uid != null ? !uid.equals(that.uid) : that.uid != null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +70,7 @@ public final class PayoutTxFinalizedMessage extends TradeMessage implements Mail
|
||||||
int result = super.hashCode();
|
int result = super.hashCode();
|
||||||
result = 31 * result + (payoutTx != null ? Arrays.hashCode(payoutTx) : 0);
|
result = 31 * result + (payoutTx != null ? Arrays.hashCode(payoutTx) : 0);
|
||||||
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
result = 31 * result + (senderNodeAddress != null ? senderNodeAddress.hashCode() : 0);
|
||||||
|
result = 31 * result + (uid != null ? uid.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
package io.bitsquare.trade.protocol.trade.messages;
|
package io.bitsquare.trade.protocol.trade.messages;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.btc.data.RawInput;
|
import io.bitsquare.btc.data.RawTransactionInput;
|
||||||
import io.bitsquare.common.util.Utilities;
|
import io.bitsquare.common.util.Utilities;
|
||||||
import io.bitsquare.payment.PaymentAccountContractData;
|
import io.bitsquare.payment.PaymentAccountContractData;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -26,7 +26,6 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ public final class PublishDepositTxRequest extends TradeMessage {
|
||||||
public final String offererContractSignature;
|
public final String offererContractSignature;
|
||||||
public final String offererPayoutAddressString;
|
public final String offererPayoutAddressString;
|
||||||
public final byte[] preparedDepositTx;
|
public final byte[] preparedDepositTx;
|
||||||
public final List<RawInput> offererInputs;
|
public final ArrayList<RawTransactionInput> offererInputs;
|
||||||
public final int openDisputeTimeAsBlockHeight;
|
public final int openDisputeTimeAsBlockHeight;
|
||||||
public final int checkPaymentTimeAsBlockHeight;
|
public final int checkPaymentTimeAsBlockHeight;
|
||||||
public final byte[] offererTradeWalletPubKey;
|
public final byte[] offererTradeWalletPubKey;
|
||||||
|
@ -56,7 +55,7 @@ public final class PublishDepositTxRequest extends TradeMessage {
|
||||||
String offererContractSignature,
|
String offererContractSignature,
|
||||||
String offererPayoutAddressString,
|
String offererPayoutAddressString,
|
||||||
byte[] preparedDepositTx,
|
byte[] preparedDepositTx,
|
||||||
List<RawInput> offererInputs,
|
ArrayList<RawTransactionInput> offererInputs,
|
||||||
int openDisputeTimeAsBlockHeight,
|
int openDisputeTimeAsBlockHeight,
|
||||||
int checkPaymentTimeAsBlockHeight) {
|
int checkPaymentTimeAsBlockHeight) {
|
||||||
super(tradeId);
|
super(tradeId);
|
||||||
|
|
|
@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.tasks;
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.Task;
|
import io.bitsquare.common.taskrunner.Task;
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey;
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.p2p.messaging.MailboxMessage;
|
import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.protocol.trade.ProcessModel;
|
import io.bitsquare.trade.protocol.trade.ProcessModel;
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class CreateAndSignDepositTxAsBuyer extends TradeTask {
|
||||||
contractHash,
|
contractHash,
|
||||||
buyerInputAmount,
|
buyerInputAmount,
|
||||||
msOutputAmount,
|
msOutputAmount,
|
||||||
processModel.tradingPeer.getRawInputs(),
|
processModel.tradingPeer.getRawTransactionInputs(),
|
||||||
processModel.tradingPeer.getChangeOutputValue(),
|
processModel.tradingPeer.getChangeOutputValue(),
|
||||||
processModel.tradingPeer.getChangeOutputAddress(),
|
processModel.tradingPeer.getChangeOutputAddress(),
|
||||||
processModel.getAddressEntry(),
|
processModel.getAddressEntry(),
|
||||||
|
@ -65,7 +65,7 @@ public class CreateAndSignDepositTxAsBuyer extends TradeTask {
|
||||||
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()));
|
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()));
|
||||||
|
|
||||||
processModel.setPreparedDepositTx(result.depositTransaction);
|
processModel.setPreparedDepositTx(result.depositTransaction);
|
||||||
processModel.setRawInputs(result.rawOffererInputs);
|
processModel.setRawTransactionInputs(result.rawOffererInputs);
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class CreateDepositTxInputsAsBuyer extends TradeTask {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
Coin takerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades());
|
Coin takerInputAmount = FeePolicy.getSecurityDeposit().add(FeePolicy.getFixedTxFeeForTrades());
|
||||||
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount, processModel.getAddressEntry());
|
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount, processModel.getAddressEntry());
|
||||||
processModel.setRawInputs(result.rawInputs);
|
processModel.setRawTransactionInputs(result.rawTransactionInputs);
|
||||||
processModel.setChangeOutputValue(result.changeOutputValue);
|
processModel.setChangeOutputValue(result.changeOutputValue);
|
||||||
processModel.setChangeOutputAddress(result.changeOutputAddress);
|
processModel.setChangeOutputAddress(result.changeOutputAddress);
|
||||||
|
|
||||||
|
|
|
@ -49,24 +49,25 @@ public class SendPayoutTxFinalizedMessage extends TradeTask {
|
||||||
@Override
|
@Override
|
||||||
public void onArrived() {
|
public void onArrived() {
|
||||||
log.trace("Message arrived at peer.");
|
log.trace("Message arrived at peer.");
|
||||||
trade.setState(Trade.State.PAYOUT_TX_SENT);
|
|
||||||
complete();
|
complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStoredInMailbox() {
|
public void onStoredInMailbox() {
|
||||||
log.trace("Message stored in mailbox.");
|
log.trace("Message stored in mailbox.");
|
||||||
trade.setState(Trade.State.PAYOUT_TX_SENT);
|
|
||||||
complete();
|
complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFault(String errorMessage) {
|
public void onFault(String errorMessage) {
|
||||||
appendToErrorMessage("PayoutTxFinalizedMessage sending failed");
|
appendToErrorMessage("PayoutTxFinalizedMessage sending failed. errorMessage=" + errorMessage);
|
||||||
failed();
|
failed(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// state must not be set in onArrived or onStoredInMailbox handlers as we would get that
|
||||||
|
// called delayed and would overwrite the broad cast state set by the next task
|
||||||
|
trade.setState(Trade.State.PAYOUT_TX_SENT);
|
||||||
} else {
|
} else {
|
||||||
log.error("trade.getPayoutTx() = " + trade.getPayoutTx());
|
log.error("trade.getPayoutTx() = " + trade.getPayoutTx());
|
||||||
failed("PayoutTx is null");
|
failed("PayoutTx is null");
|
||||||
|
|
|
@ -57,7 +57,7 @@ public class SignAndFinalizePayoutTx extends TradeTask {
|
||||||
);
|
);
|
||||||
|
|
||||||
trade.setPayoutTx(transaction);
|
trade.setPayoutTx(transaction);
|
||||||
trade.setState(Trade.State.PAYOUT_TX_RECEIVED_AND_COMMITTED);
|
trade.setState(Trade.State.PAYOUT_TX_COMMITTED);
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
|
@ -51,8 +51,8 @@ public class SignAndPublishDepositTxAsBuyer extends TradeTask {
|
||||||
false,
|
false,
|
||||||
contractHash,
|
contractHash,
|
||||||
processModel.getPreparedDepositTx(),
|
processModel.getPreparedDepositTx(),
|
||||||
processModel.getRawInputs(),
|
processModel.getRawTransactionInputs(),
|
||||||
processModel.tradingPeer.getRawInputs(),
|
processModel.tradingPeer.getRawTransactionInputs(),
|
||||||
processModel.getTradeWalletPubKey(),
|
processModel.getTradeWalletPubKey(),
|
||||||
processModel.tradingPeer.getTradeWalletPubKey(),
|
processModel.tradingPeer.getTradeWalletPubKey(),
|
||||||
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()),
|
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()),
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class LoadTakeOfferFeeTx extends TradeTask {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
|
|
||||||
// TODO impl. not completed
|
// TODO impl. missing
|
||||||
//processModel.getWalletService().findTxInBlockChain(processModel.getTakeOfferFeeTxId());
|
//processModel.getWalletService().findTxInBlockChain(processModel.getTakeOfferFeeTxId());
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
|
|
|
@ -50,8 +50,8 @@ public class ProcessPayDepositRequest extends TradeTask {
|
||||||
checkTradeId(processModel.getId(), payDepositRequest);
|
checkTradeId(processModel.getId(), payDepositRequest);
|
||||||
checkNotNull(payDepositRequest);
|
checkNotNull(payDepositRequest);
|
||||||
|
|
||||||
processModel.tradingPeer.setRawInputs(checkNotNull(payDepositRequest.rawInputs));
|
processModel.tradingPeer.setRawTransactionInputs(checkNotNull(payDepositRequest.rawTransactionInputs));
|
||||||
checkArgument(payDepositRequest.rawInputs.size() > 0);
|
checkArgument(payDepositRequest.rawTransactionInputs.size() > 0);
|
||||||
|
|
||||||
processModel.tradingPeer.setChangeOutputValue(payDepositRequest.changeOutputValue);
|
processModel.tradingPeer.setChangeOutputValue(payDepositRequest.changeOutputValue);
|
||||||
if (payDepositRequest.changeOutputAddress != null)
|
if (payDepositRequest.changeOutputAddress != null)
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class SendPublishDepositTxRequest extends TradeTask {
|
||||||
trade.getOffererContractSignature(),
|
trade.getOffererContractSignature(),
|
||||||
processModel.getAddressEntry().getAddressString(),
|
processModel.getAddressEntry().getAddressString(),
|
||||||
processModel.getPreparedDepositTx(),
|
processModel.getPreparedDepositTx(),
|
||||||
processModel.getRawInputs(),
|
processModel.getRawTransactionInputs(),
|
||||||
trade.getOpenDisputeTimeAsBlockHeight(),
|
trade.getOpenDisputeTimeAsBlockHeight(),
|
||||||
trade.getCheckPaymentTimeAsBlockHeight()
|
trade.getCheckPaymentTimeAsBlockHeight()
|
||||||
);
|
);
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class VerifyTakerAccount extends TradeTask {
|
||||||
protected void run() {
|
protected void run() {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
//TODO mocked yet
|
//TODO impl. missing
|
||||||
/* if (processModel.getBlockChainService().isAccountBlackListed(processModel.tradingPeer.getAccountId(),
|
/* if (processModel.getBlockChainService().isAccountBlackListed(processModel.tradingPeer.getAccountId(),
|
||||||
processModel.tradingPeer.getPaymentAccountContractData())) {
|
processModel.tradingPeer.getPaymentAccountContractData())) {
|
||||||
log.error("Taker is blacklisted");
|
log.error("Taker is blacklisted");
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class CreateAndSignDepositTxAsSeller extends TradeTask {
|
||||||
contractHash,
|
contractHash,
|
||||||
sellerInputAmount,
|
sellerInputAmount,
|
||||||
msOutputAmount,
|
msOutputAmount,
|
||||||
processModel.tradingPeer.getRawInputs(),
|
processModel.tradingPeer.getRawTransactionInputs(),
|
||||||
processModel.tradingPeer.getChangeOutputValue(),
|
processModel.tradingPeer.getChangeOutputValue(),
|
||||||
processModel.tradingPeer.getChangeOutputAddress(),
|
processModel.tradingPeer.getChangeOutputAddress(),
|
||||||
processModel.getAddressEntry(),
|
processModel.getAddressEntry(),
|
||||||
|
@ -65,7 +65,7 @@ public class CreateAndSignDepositTxAsSeller extends TradeTask {
|
||||||
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()));
|
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()));
|
||||||
|
|
||||||
processModel.setPreparedDepositTx(result.depositTransaction);
|
processModel.setPreparedDepositTx(result.depositTransaction);
|
||||||
processModel.setRawInputs(result.rawOffererInputs);
|
processModel.setRawTransactionInputs(result.rawOffererInputs);
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class CreateDepositTxInputsAsSeller extends TradeTask {
|
||||||
|
|
||||||
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount, processModel
|
InputsAndChangeOutput result = processModel.getTradeWalletService().takerCreatesDepositsTxInputs(takerInputAmount, processModel
|
||||||
.getAddressEntry());
|
.getAddressEntry());
|
||||||
processModel.setRawInputs(result.rawInputs);
|
processModel.setRawTransactionInputs(result.rawTransactionInputs);
|
||||||
processModel.setChangeOutputValue(result.changeOutputValue);
|
processModel.setChangeOutputValue(result.changeOutputValue);
|
||||||
processModel.setChangeOutputAddress(result.changeOutputAddress);
|
processModel.setChangeOutputAddress(result.changeOutputAddress);
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,8 @@ public class SendFinalizePayoutTxRequest extends TradeTask {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFault(String errorMessage) {
|
public void onFault(String errorMessage) {
|
||||||
appendToErrorMessage("FinalizePayoutTxRequest sending failed");
|
appendToErrorMessage("FinalizePayoutTxRequest sending failed. errorMessage=" + errorMessage);
|
||||||
failed();
|
failed(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -49,8 +49,8 @@ public class SignAndPublishDepositTxAsSeller extends TradeTask {
|
||||||
true,
|
true,
|
||||||
contractHash,
|
contractHash,
|
||||||
processModel.getPreparedDepositTx(),
|
processModel.getPreparedDepositTx(),
|
||||||
processModel.tradingPeer.getRawInputs(),
|
processModel.tradingPeer.getRawTransactionInputs(),
|
||||||
processModel.getRawInputs(),
|
processModel.getRawTransactionInputs(),
|
||||||
processModel.tradingPeer.getTradeWalletPubKey(),
|
processModel.tradingPeer.getTradeWalletPubKey(),
|
||||||
processModel.getTradeWalletPubKey(),
|
processModel.getTradeWalletPubKey(),
|
||||||
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()),
|
processModel.getArbitratorPubKey(trade.getArbitratorNodeAddress()),
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class LoadCreateOfferFeeTx extends TradeTask {
|
||||||
try {
|
try {
|
||||||
runInterceptHook();
|
runInterceptHook();
|
||||||
|
|
||||||
// TODO impl. not completed
|
// TODO impl. missing
|
||||||
///processModel.getWalletService().findTxInBlockChain(trade.getOffer().getOfferFeePaymentTxID());
|
///processModel.getWalletService().findTxInBlockChain(trade.getOffer().getOfferFeePaymentTxID());
|
||||||
|
|
||||||
complete();
|
complete();
|
||||||
|
|
|
@ -63,7 +63,7 @@ public class ProcessPublishDepositTxRequest extends TradeTask {
|
||||||
processModel.tradingPeer.setContractAsJson(nonEmptyStringOf(publishDepositTxRequest.offererContractAsJson));
|
processModel.tradingPeer.setContractAsJson(nonEmptyStringOf(publishDepositTxRequest.offererContractAsJson));
|
||||||
processModel.tradingPeer.setContractSignature(nonEmptyStringOf(publishDepositTxRequest.offererContractSignature));
|
processModel.tradingPeer.setContractSignature(nonEmptyStringOf(publishDepositTxRequest.offererContractSignature));
|
||||||
processModel.tradingPeer.setPayoutAddressString(nonEmptyStringOf(publishDepositTxRequest.offererPayoutAddressString));
|
processModel.tradingPeer.setPayoutAddressString(nonEmptyStringOf(publishDepositTxRequest.offererPayoutAddressString));
|
||||||
processModel.tradingPeer.setRawInputs(checkNotNull(publishDepositTxRequest.offererInputs));
|
processModel.tradingPeer.setRawTransactionInputs(checkNotNull(publishDepositTxRequest.offererInputs));
|
||||||
processModel.setPreparedDepositTx(checkNotNull(publishDepositTxRequest.preparedDepositTx));
|
processModel.setPreparedDepositTx(checkNotNull(publishDepositTxRequest.preparedDepositTx));
|
||||||
checkArgument(publishDepositTxRequest.offererInputs.size() > 0);
|
checkArgument(publishDepositTxRequest.offererInputs.size() > 0);
|
||||||
if (publishDepositTxRequest.openDisputeTimeAsBlockHeight != 0) {
|
if (publishDepositTxRequest.openDisputeTimeAsBlockHeight != 0) {
|
||||||
|
|
|
@ -25,6 +25,8 @@ import io.bitsquare.trade.protocol.trade.tasks.TradeTask;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
public class SendPayDepositRequest extends TradeTask {
|
public class SendPayDepositRequest extends TradeTask {
|
||||||
|
@ -47,7 +49,7 @@ public class SendPayDepositRequest extends TradeTask {
|
||||||
processModel.getMyAddress(),
|
processModel.getMyAddress(),
|
||||||
processModel.getId(),
|
processModel.getId(),
|
||||||
trade.getTradeAmount().value,
|
trade.getTradeAmount().value,
|
||||||
processModel.getRawInputs(),
|
processModel.getRawTransactionInputs(),
|
||||||
processModel.getChangeOutputValue(),
|
processModel.getChangeOutputValue(),
|
||||||
processModel.getChangeOutputAddress(),
|
processModel.getChangeOutputAddress(),
|
||||||
processModel.getTradeWalletPubKey(),
|
processModel.getTradeWalletPubKey(),
|
||||||
|
@ -56,7 +58,7 @@ public class SendPayDepositRequest extends TradeTask {
|
||||||
processModel.getPaymentAccountContractData(trade),
|
processModel.getPaymentAccountContractData(trade),
|
||||||
processModel.getAccountId(),
|
processModel.getAccountId(),
|
||||||
trade.getTakeOfferFeeTxId(),
|
trade.getTakeOfferFeeTxId(),
|
||||||
processModel.getUser().getAcceptedArbitratorAddresses(),
|
new ArrayList<>(processModel.getUser().getAcceptedArbitratorAddresses()),
|
||||||
trade.getArbitratorNodeAddress()
|
trade.getArbitratorNodeAddress()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -201,14 +201,6 @@ public final class User implements Persistable {
|
||||||
// Getters
|
// Getters
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// TODO just a first attempt, refine when working on the embedded data for the reg. tx
|
|
||||||
public String getStringifiedBankAccounts() {
|
|
||||||
return paymentAccounts.stream()
|
|
||||||
.map(PaymentAccount::getId)
|
|
||||||
.collect(Collectors.joining(", "));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public PaymentAccount getPaymentAccount(String paymentAccountId) {
|
public PaymentAccount getPaymentAccount(String paymentAccountId) {
|
||||||
Optional<PaymentAccount> optional = paymentAccounts.stream().filter(e -> e.getId().equals(paymentAccountId)).findAny();
|
Optional<PaymentAccount> optional = paymentAccounts.stream().filter(e -> e.getId().equals(paymentAccountId)).findAny();
|
||||||
if (optional.isPresent())
|
if (optional.isPresent())
|
||||||
|
|
|
@ -220,7 +220,7 @@ public class BitsquareApp extends Application {
|
||||||
private void showSendAlertMessagePopup() {
|
private void showSendAlertMessagePopup() {
|
||||||
AlertManager alertManager = injector.getInstance(AlertManager.class);
|
AlertManager alertManager = injector.getInstance(AlertManager.class);
|
||||||
new SendAlertMessagePopup()
|
new SendAlertMessagePopup()
|
||||||
.onAddAlertMessage((alertMessage, privKeyString) -> alertManager.addAlertMessageIfKeyIsValid(alertMessage, privKeyString))
|
.onAddAlertMessage((alert, privKeyString) -> alertManager.addAlertMessageIfKeyIsValid(alert, privKeyString))
|
||||||
.onRemoveAlertMessage(privKeyString -> alertManager.removeAlertMessageIfKeyIsValid(privKeyString))
|
.onRemoveAlertMessage(privKeyString -> alertManager.removeAlertMessageIfKeyIsValid(privKeyString))
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
|
@ -866,7 +866,7 @@ textfield */
|
||||||
-fx-text-fill: white;
|
-fx-text-fill: white;
|
||||||
-fx-font-weight: bold;
|
-fx-font-weight: bold;
|
||||||
-fx-font-size: 15;
|
-fx-font-size: 15;
|
||||||
-fx-background-radius: 20;
|
/*-fx-background-radius: 20;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#buy-button-big:hover {
|
#buy-button-big:hover {
|
||||||
|
@ -878,7 +878,7 @@ textfield */
|
||||||
-fx-text-fill: white;
|
-fx-text-fill: white;
|
||||||
-fx-font-weight: bold;
|
-fx-font-weight: bold;
|
||||||
-fx-font-size: 15;
|
-fx-font-size: 15;
|
||||||
-fx-background-radius: 20;
|
/* -fx-background-radius: 20;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#sell-button-big:hover {
|
#sell-button-big:hover {
|
||||||
|
@ -889,7 +889,7 @@ textfield */
|
||||||
-fx-base: -bs-buy;
|
-fx-base: -bs-buy;
|
||||||
-fx-text-fill: white;
|
-fx-text-fill: white;
|
||||||
-fx-font-weight: bold;
|
-fx-font-weight: bold;
|
||||||
-fx-background-radius: 13;
|
/* -fx-background-radius: 13;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#buy-button:hover {
|
#buy-button:hover {
|
||||||
|
@ -900,7 +900,7 @@ textfield */
|
||||||
-fx-base: -bs-sell;
|
-fx-base: -bs-sell;
|
||||||
-fx-text-fill: white;
|
-fx-text-fill: white;
|
||||||
-fx-font-weight: bold;
|
-fx-font-weight: bold;
|
||||||
-fx-background-radius: 13;
|
/* -fx-background-radius: 13;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#sell-button:hover {
|
#sell-button:hover {
|
||||||
|
@ -911,7 +911,7 @@ textfield */
|
||||||
-fx-base: -bs-light-grey;
|
-fx-base: -bs-light-grey;
|
||||||
-fx-text-fill: white;
|
-fx-text-fill: white;
|
||||||
-fx-font-weight: bold;
|
-fx-font-weight: bold;
|
||||||
-fx-background-radius: 13;
|
/* -fx-background-radius: 13;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#cancel-button:hover {
|
#cancel-button:hover {
|
||||||
|
@ -925,12 +925,12 @@ textfield */
|
||||||
********************************************************************************************************************/
|
********************************************************************************************************************/
|
||||||
|
|
||||||
#popup-headline {
|
#popup-headline {
|
||||||
-fx-font-size: 18;
|
-fx-font-size: 16;
|
||||||
-fx-text-fill: #333;
|
-fx-text-fill: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
#popup-bg {
|
#popup-bg {
|
||||||
-fx-font-size: 15;
|
-fx-font-size: 14;
|
||||||
-fx-text-fill: #333;
|
-fx-text-fill: #333;
|
||||||
-fx-background-color: white;
|
-fx-background-color: white;
|
||||||
-fx-background-radius: 5 5 5 5;
|
-fx-background-radius: 5 5 5 5;
|
||||||
|
|
|
@ -343,7 +343,7 @@ public class MainViewModel implements ViewModel {
|
||||||
numberOfBtcPeersTimer = UserThread.runAfter(() -> {
|
numberOfBtcPeersTimer = UserThread.runAfter(() -> {
|
||||||
if (walletService.numPeersProperty().get() == 0) {
|
if (walletService.numPeersProperty().get() == 0) {
|
||||||
walletServiceErrorMsg.set("You lost the connection to all bitcoin network peers.\n" +
|
walletServiceErrorMsg.set("You lost the connection to all bitcoin network peers.\n" +
|
||||||
"Maybe you lost your internet connection or your computer was in hibernate/sleep mode.");
|
"Maybe you lost your internet connection or your computer was in standby mode.");
|
||||||
} else {
|
} else {
|
||||||
walletServiceErrorMsg.set(null);
|
walletServiceErrorMsg.set(null);
|
||||||
}
|
}
|
||||||
|
@ -534,7 +534,7 @@ public class MainViewModel implements ViewModel {
|
||||||
numberOfP2PNetworkPeersTimer = UserThread.runAfter(() -> {
|
numberOfP2PNetworkPeersTimer = UserThread.runAfter(() -> {
|
||||||
if (p2PService.getNumConnectedPeers().get() == 0) {
|
if (p2PService.getNumConnectedPeers().get() == 0) {
|
||||||
p2PNetworkWarnMsg.set("You lost the connection to all P2P network peers.\n" +
|
p2PNetworkWarnMsg.set("You lost the connection to all P2P network peers.\n" +
|
||||||
"Maybe you lost your internet connection or your computer was in hibernate/sleep mode.");
|
"Maybe you lost your internet connection or your computer was in standby mode.");
|
||||||
p2PNetworkLabelId.set("splash-error-state-msg");
|
p2PNetworkLabelId.set("splash-error-state-msg");
|
||||||
} else {
|
} else {
|
||||||
p2PNetworkWarnMsg.set(null);
|
p2PNetworkWarnMsg.set(null);
|
||||||
|
|
|
@ -131,9 +131,9 @@ public class TransactionsListItem {
|
||||||
details = "MultiSig payout: " + tradable.getShortId();
|
details = "MultiSig payout: " + tradable.getShortId();
|
||||||
} else if (trade.getDisputeState() == Trade.DisputeState.DISPUTE_CLOSED) {
|
} else if (trade.getDisputeState() == Trade.DisputeState.DISPUTE_CLOSED) {
|
||||||
if (valueSentToMe.isPositive())
|
if (valueSentToMe.isPositive())
|
||||||
details = "Refund from dispute: " + tradable.getShortId();
|
details = "Dispute payout: " + tradable.getShortId();
|
||||||
else
|
else
|
||||||
details = "Nothing refunded from dispute: " + tradable.getShortId();
|
details = "Lost dispute case: " + tradable.getShortId();
|
||||||
} else {
|
} else {
|
||||||
details = "Unknown reason: " + tradable.getShortId();
|
details = "Unknown reason: " + tradable.getShortId();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<PropertyValueFactory property="date"/>
|
<PropertyValueFactory property="date"/>
|
||||||
</cellValueFactory>
|
</cellValueFactory>
|
||||||
</TableColumn>
|
</TableColumn>
|
||||||
<TableColumn text="Details" fx:id="detailsColumn" minWidth="220" maxWidth="220"/>
|
<TableColumn text="Details" fx:id="detailsColumn" minWidth="220"/>
|
||||||
<TableColumn text="Address" fx:id="addressColumn" minWidth="180"/>
|
<TableColumn text="Address" fx:id="addressColumn" minWidth="180"/>
|
||||||
<TableColumn text="Transaction" fx:id="transactionColumn" minWidth="100"/>
|
<TableColumn text="Transaction" fx:id="transactionColumn" minWidth="100"/>
|
||||||
<TableColumn text="Amount (BTC)" fx:id="amountColumn" minWidth="110" maxWidth="110">
|
<TableColumn text="Amount (BTC)" fx:id="amountColumn" minWidth="110" maxWidth="110">
|
||||||
|
|
|
@ -172,31 +172,40 @@ public class TransactionsView extends ActivatableView<VBox, Void> {
|
||||||
|
|
||||||
List<TransactionsListItem> listItems = walletService.getWallet().getRecentTransactions(1000, true).stream()
|
List<TransactionsListItem> listItems = walletService.getWallet().getRecentTransactions(1000, true).stream()
|
||||||
.map(transaction -> {
|
.map(transaction -> {
|
||||||
|
log.error("tx ID " + transaction.getHashAsString());
|
||||||
Optional<Tradable> tradableOptional = all.stream()
|
Optional<Tradable> tradableOptional = all.stream()
|
||||||
.filter(e -> {
|
.filter(tradable -> {
|
||||||
String txId = transaction.getHashAsString();
|
String txId = transaction.getHashAsString();
|
||||||
if (e instanceof OpenOffer)
|
if (tradable instanceof OpenOffer)
|
||||||
return e.getOffer().getOfferFeePaymentTxID().equals(txId);
|
return tradable.getOffer().getOfferFeePaymentTxID().equals(txId);
|
||||||
else if (e instanceof Trade) {
|
else if (tradable instanceof Trade) {
|
||||||
Trade trade = (Trade) e;
|
Trade trade = (Trade) tradable;
|
||||||
return (trade.getTakeOfferFeeTxId() != null &&
|
boolean isTakeOfferFeeTx = txId.equals(trade.getTakeOfferFeeTxId());
|
||||||
trade.getTakeOfferFeeTxId().equals(txId)) ||
|
boolean isOfferFeeTx = trade.getOffer() != null &&
|
||||||
(trade.getOffer() != null &&
|
txId.equals(trade.getOffer().getOfferFeePaymentTxID());
|
||||||
trade.getOffer().getOfferFeePaymentTxID() != null &&
|
boolean isDepositTx = trade.getDepositTx() != null &&
|
||||||
trade.getOffer().getOfferFeePaymentTxID().equals(txId)) ||
|
trade.getDepositTx().getHashAsString().equals(txId);
|
||||||
(trade.getDepositTx() != null &&
|
boolean isPayoutTx = trade.getPayoutTx() != null &&
|
||||||
trade.getDepositTx().getHashAsString().equals(txId)) ||
|
trade.getPayoutTx().getHashAsString().equals(txId);
|
||||||
(trade.getPayoutTx() != null &&
|
|
||||||
trade.getPayoutTx().getHashAsString().equals(txId)) ||
|
boolean isDisputedPayoutTx = disputeManager.getDisputesAsObservableList().stream()
|
||||||
(disputeManager.getDisputesAsObservableList().stream()
|
.filter(dispute -> txId.equals(dispute.getDisputePayoutTxId()) &&
|
||||||
.filter(dispute -> dispute.getDisputePayoutTx() != null &&
|
tradable.getId().equals(dispute.getTradeId()))
|
||||||
dispute.getDisputePayoutTx().getHashAsString().equals(txId))
|
.findAny()
|
||||||
.findAny()
|
.isPresent();
|
||||||
.isPresent());
|
log.error("isTakeOfferFeeTx " + isTakeOfferFeeTx);
|
||||||
|
log.error("isOfferFeeTx " + isOfferFeeTx);
|
||||||
|
log.error("isDepositTx " + isDepositTx);
|
||||||
|
log.error("isPayoutTx " + isPayoutTx);
|
||||||
|
log.error("isDisputedPayoutTx " + isDisputedPayoutTx);
|
||||||
|
|
||||||
|
return isTakeOfferFeeTx || isOfferFeeTx || isDepositTx || isPayoutTx || isDisputedPayoutTx;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
})
|
})
|
||||||
.findAny();
|
.findAny();
|
||||||
|
if (tradableOptional.isPresent())
|
||||||
|
log.error("tradableOptional " + tradableOptional.get().getId());
|
||||||
return new TransactionsListItem(transaction, walletService, tradableOptional, formatter);
|
return new TransactionsListItem(transaction, walletService, tradableOptional, formatter);
|
||||||
})
|
})
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
|
@ -52,6 +52,7 @@ import org.bitcoinj.utils.ExchangeRate;
|
||||||
import org.bitcoinj.utils.Fiat;
|
import org.bitcoinj.utils.Fiat;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -237,9 +238,9 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
long amount = amountAsCoin.get() != null ? amountAsCoin.get().getValue() : 0L;
|
long amount = amountAsCoin.get() != null ? amountAsCoin.get().getValue() : 0L;
|
||||||
long minAmount = minAmountAsCoin.get() != null ? minAmountAsCoin.get().getValue() : 0L;
|
long minAmount = minAmountAsCoin.get() != null ? minAmountAsCoin.get().getValue() : 0L;
|
||||||
|
|
||||||
List<String> acceptedCountryCodes = null;
|
ArrayList<String> acceptedCountryCodes = new ArrayList<>();
|
||||||
if (paymentAccount instanceof SepaAccount)
|
if (paymentAccount instanceof SepaAccount)
|
||||||
acceptedCountryCodes = ((SepaAccount) paymentAccount).getAcceptedCountryCodes();
|
acceptedCountryCodes.addAll(((SepaAccount) paymentAccount).getAcceptedCountryCodes());
|
||||||
|
|
||||||
// That is optional and set to null if not supported (AltCoins, OKPay,...)
|
// That is optional and set to null if not supported (AltCoins, OKPay,...)
|
||||||
Country country = paymentAccount.getCountry();
|
Country country = paymentAccount.getCountry();
|
||||||
|
@ -256,7 +257,7 @@ class CreateOfferDataModel extends ActivatableDataModel {
|
||||||
tradeCurrencyCode.get(),
|
tradeCurrencyCode.get(),
|
||||||
country,
|
country,
|
||||||
paymentAccount.getId(),
|
paymentAccount.getId(),
|
||||||
user.getAcceptedArbitratorAddresses(),
|
new ArrayList<>(user.getAcceptedArbitratorAddresses()),
|
||||||
acceptedCountryCodes);
|
acceptedCountryCodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -130,7 +130,7 @@ public class ContractPopup extends Popup {
|
||||||
addLabelTextField(gridPane, ++rowIndex, "Seller payment ID:",
|
addLabelTextField(gridPane, ++rowIndex, "Seller payment ID:",
|
||||||
((BlockChainAccountContractData) sellerPaymentAccountContractData).getPaymentId());
|
((BlockChainAccountContractData) sellerPaymentAccountContractData).getPaymentId());
|
||||||
|
|
||||||
if (offer.getAcceptedCountryCodes() != null) {
|
if (offer.getAcceptedCountryCodes() != null && !offer.getAcceptedCountryCodes().isEmpty()) {
|
||||||
String countries;
|
String countries;
|
||||||
Tooltip tooltip = null;
|
Tooltip tooltip = null;
|
||||||
if (CountryUtil.containsAllSepaEuroCountries(offer.getAcceptedCountryCodes())) {
|
if (CountryUtil.containsAllSepaEuroCountries(offer.getAcceptedCountryCodes())) {
|
||||||
|
|
|
@ -71,8 +71,8 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
private ToggleGroup feeToggleGroup;
|
private ToggleGroup feeToggleGroup;
|
||||||
private String role;
|
private String role;
|
||||||
private TextArea summaryNotesTextArea;
|
private TextArea summaryNotesTextArea;
|
||||||
private ObjectBinding<Tuple2<DisputeResult.FeePaymentPolicy, Toggle>> feePaymentPolicyChanged;
|
private ObjectBinding<Tuple2<DisputeResult.DisputeFeePolicy, Toggle>> feePaymentPolicyChanged;
|
||||||
private ChangeListener<Tuple2<DisputeResult.FeePaymentPolicy, Toggle>> feePaymentPolicyListener;
|
private ChangeListener<Tuple2<DisputeResult.DisputeFeePolicy, Toggle>> feePaymentPolicyListener;
|
||||||
private ChangeListener<Boolean> shareRadioButtonSelectedListener;
|
private ChangeListener<Boolean> shareRadioButtonSelectedListener;
|
||||||
private ChangeListener<Toggle> feeToggleSelectionListener;
|
private ChangeListener<Toggle> feeToggleSelectionListener;
|
||||||
// keep a reference to not get GCed
|
// keep a reference to not get GCed
|
||||||
|
@ -163,7 +163,7 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
disputeResult.setBuyerPayoutAmount(peersDisputeResult.getBuyerPayoutAmount());
|
disputeResult.setBuyerPayoutAmount(peersDisputeResult.getBuyerPayoutAmount());
|
||||||
disputeResult.setSellerPayoutAmount(peersDisputeResult.getSellerPayoutAmount());
|
disputeResult.setSellerPayoutAmount(peersDisputeResult.getSellerPayoutAmount());
|
||||||
disputeResult.setArbitratorPayoutAmount(peersDisputeResult.getArbitratorPayoutAmount());
|
disputeResult.setArbitratorPayoutAmount(peersDisputeResult.getArbitratorPayoutAmount());
|
||||||
disputeResult.setFeePaymentPolicy(peersDisputeResult.getFeePaymentPolicy());
|
disputeResult.setDisputeFeePolicy(peersDisputeResult.getDisputeFeePolicy());
|
||||||
disputeResult.setWinner(peersDisputeResult.getWinner());
|
disputeResult.setWinner(peersDisputeResult.getWinner());
|
||||||
|
|
||||||
if (disputeResult.getBuyerPayoutAmount() != null) {
|
if (disputeResult.getBuyerPayoutAmount() != null) {
|
||||||
|
@ -181,13 +181,13 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
splitFeeRadioButton.setDisable(true);
|
splitFeeRadioButton.setDisable(true);
|
||||||
waiveFeeRadioButton.setDisable(true);
|
waiveFeeRadioButton.setDisable(true);
|
||||||
|
|
||||||
calculatePayoutAmounts(disputeResult.getFeePaymentPolicy());
|
calculatePayoutAmounts(disputeResult.getDisputeFeePolicy());
|
||||||
applyTradeAmountRadioButtonStates();
|
applyTradeAmountRadioButtonStates();
|
||||||
} else {
|
} else {
|
||||||
applyPayoutAmounts(disputeResult.feePaymentPolicyProperty().get(), tradeAmountToggleGroup.selectedToggleProperty().get());
|
applyPayoutAmounts(disputeResult.disputeFeePolicyProperty().get(), tradeAmountToggleGroup.selectedToggleProperty().get());
|
||||||
feePaymentPolicyChanged = Bindings.createObjectBinding(
|
feePaymentPolicyChanged = Bindings.createObjectBinding(
|
||||||
() -> new Tuple2(disputeResult.feePaymentPolicyProperty().get(), tradeAmountToggleGroup.selectedToggleProperty().get()),
|
() -> new Tuple2(disputeResult.disputeFeePolicyProperty().get(), tradeAmountToggleGroup.selectedToggleProperty().get()),
|
||||||
disputeResult.feePaymentPolicyProperty(),
|
disputeResult.disputeFeePolicyProperty(),
|
||||||
tradeAmountToggleGroup.selectedToggleProperty());
|
tradeAmountToggleGroup.selectedToggleProperty());
|
||||||
feePaymentPolicyListener = (observable, oldValue, newValue) -> {
|
feePaymentPolicyListener = (observable, oldValue, newValue) -> {
|
||||||
applyPayoutAmounts(newValue.first, newValue.second);
|
applyPayoutAmounts(newValue.first, newValue.second);
|
||||||
|
@ -302,11 +302,11 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
|
|
||||||
feeToggleSelectionListener = (observable, oldValue, newValue) -> {
|
feeToggleSelectionListener = (observable, oldValue, newValue) -> {
|
||||||
if (newValue == loserPaysFeeRadioButton)
|
if (newValue == loserPaysFeeRadioButton)
|
||||||
disputeResult.setFeePaymentPolicy(DisputeResult.FeePaymentPolicy.LOSER);
|
disputeResult.setDisputeFeePolicy(DisputeResult.DisputeFeePolicy.LOSER);
|
||||||
else if (newValue == splitFeeRadioButton)
|
else if (newValue == splitFeeRadioButton)
|
||||||
disputeResult.setFeePaymentPolicy(DisputeResult.FeePaymentPolicy.SPLIT);
|
disputeResult.setDisputeFeePolicy(DisputeResult.DisputeFeePolicy.SPLIT);
|
||||||
else if (newValue == waiveFeeRadioButton)
|
else if (newValue == waiveFeeRadioButton)
|
||||||
disputeResult.setFeePaymentPolicy(DisputeResult.FeePaymentPolicy.WAIVE);
|
disputeResult.setDisputeFeePolicy(DisputeResult.DisputeFeePolicy.WAIVE);
|
||||||
};
|
};
|
||||||
feeToggleGroup.selectedToggleProperty().addListener(feeToggleSelectionListener);
|
feeToggleGroup.selectedToggleProperty().addListener(feeToggleSelectionListener);
|
||||||
|
|
||||||
|
@ -315,7 +315,7 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setFeeRadioButtonState() {
|
private void setFeeRadioButtonState() {
|
||||||
switch (disputeResult.getFeePaymentPolicy()) {
|
switch (disputeResult.getDisputeFeePolicy()) {
|
||||||
case LOSER:
|
case LOSER:
|
||||||
feeToggleGroup.selectToggle(loserPaysFeeRadioButton);
|
feeToggleGroup.selectToggle(loserPaysFeeRadioButton);
|
||||||
break;
|
break;
|
||||||
|
@ -417,7 +417,7 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
// Controller
|
// Controller
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void applyPayoutAmounts(DisputeResult.FeePaymentPolicy feePayment, Toggle selectedTradeAmountToggle) {
|
private void applyPayoutAmounts(DisputeResult.DisputeFeePolicy feePayment, Toggle selectedTradeAmountToggle) {
|
||||||
calculatePayoutAmounts(feePayment);
|
calculatePayoutAmounts(feePayment);
|
||||||
if (selectedTradeAmountToggle != null) {
|
if (selectedTradeAmountToggle != null) {
|
||||||
applyPayoutAmountsToDisputeResult(selectedTradeAmountToggle);
|
applyPayoutAmountsToDisputeResult(selectedTradeAmountToggle);
|
||||||
|
@ -425,7 +425,7 @@ public class DisputeSummaryPopup extends Popup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void calculatePayoutAmounts(DisputeResult.FeePaymentPolicy feePayment) {
|
private void calculatePayoutAmounts(DisputeResult.DisputeFeePolicy feePayment) {
|
||||||
Contract contract = dispute.getContract();
|
Contract contract = dispute.getContract();
|
||||||
Coin refund = FeePolicy.getSecurityDeposit();
|
Coin refund = FeePolicy.getSecurityDeposit();
|
||||||
Coin winnerRefund;
|
Coin winnerRefund;
|
||||||
|
|
|
@ -103,23 +103,26 @@ public class Popup {
|
||||||
|
|
||||||
public void hide() {
|
public void hide() {
|
||||||
animateHide(() -> {
|
animateHide(() -> {
|
||||||
Window window = owner.getScene().getWindow();
|
Scene rootScene = owner.getScene();
|
||||||
window.xProperty().removeListener(positionListener);
|
if (rootScene != null) {
|
||||||
window.yProperty().removeListener(positionListener);
|
Window window = rootScene.getWindow();
|
||||||
window.widthProperty().removeListener(positionListener);
|
window.xProperty().removeListener(positionListener);
|
||||||
|
window.yProperty().removeListener(positionListener);
|
||||||
|
window.widthProperty().removeListener(positionListener);
|
||||||
|
|
||||||
if (centerTime != null)
|
if (centerTime != null)
|
||||||
centerTime.stop();
|
centerTime.stop();
|
||||||
|
|
||||||
removeEffectFromBackground();
|
removeEffectFromBackground();
|
||||||
|
|
||||||
if (stage != null)
|
if (stage != null)
|
||||||
stage.hide();
|
stage.hide();
|
||||||
else
|
else
|
||||||
log.warn("Stage is null");
|
log.warn("Stage is null");
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
PopupManager.isHidden(Popup.this);
|
PopupManager.isHidden(Popup.this);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,39 +248,42 @@ public class Popup {
|
||||||
if (owner == null)
|
if (owner == null)
|
||||||
owner = MainView.getRootContainer();
|
owner = MainView.getRootContainer();
|
||||||
|
|
||||||
stage = new Stage();
|
Scene rootScene = owner.getScene();
|
||||||
Scene scene = new Scene(gridPane);
|
if (rootScene != null) {
|
||||||
scene.getStylesheets().setAll(owner.getScene().getStylesheets());
|
stage = new Stage();
|
||||||
scene.setFill(Color.TRANSPARENT);
|
Scene scene = new Scene(gridPane);
|
||||||
stage.setScene(scene);
|
scene.getStylesheets().setAll(rootScene.getStylesheets());
|
||||||
setModality();
|
scene.setFill(Color.TRANSPARENT);
|
||||||
stage.initStyle(StageStyle.TRANSPARENT);
|
stage.setScene(scene);
|
||||||
Window window = owner.getScene().getWindow();
|
setModality();
|
||||||
stage.initOwner(window);
|
stage.initStyle(StageStyle.TRANSPARENT);
|
||||||
stage.show();
|
Window window = rootScene.getWindow();
|
||||||
|
stage.initOwner(window);
|
||||||
|
stage.show();
|
||||||
|
|
||||||
layout();
|
layout();
|
||||||
|
|
||||||
addEffectToBackground();
|
addEffectToBackground();
|
||||||
|
|
||||||
// On Linux the owner stage does not move the child stage as it does on Mac
|
// On Linux the owner stage does not move the child stage as it does on Mac
|
||||||
// So we need to apply centerPopup. Further with fast movements the handler loses
|
// So we need to apply centerPopup. Further with fast movements the handler loses
|
||||||
// the latest position, with a delay it fixes that.
|
// the latest position, with a delay it fixes that.
|
||||||
// Also on Mac sometimes the popups are positioned outside of the main app, so keep it for all OS
|
// Also on Mac sometimes the popups are positioned outside of the main app, so keep it for all OS
|
||||||
positionListener = (observable, oldValue, newValue) -> {
|
positionListener = (observable, oldValue, newValue) -> {
|
||||||
if (stage != null) {
|
if (stage != null) {
|
||||||
layout();
|
layout();
|
||||||
if (centerTime != null)
|
if (centerTime != null)
|
||||||
centerTime.stop();
|
centerTime.stop();
|
||||||
|
|
||||||
centerTime = UserThread.runAfter(this::layout, 3);
|
centerTime = UserThread.runAfter(this::layout, 3);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.xProperty().addListener(positionListener);
|
window.xProperty().addListener(positionListener);
|
||||||
window.yProperty().addListener(positionListener);
|
window.yProperty().addListener(positionListener);
|
||||||
window.widthProperty().addListener(positionListener);
|
window.widthProperty().addListener(positionListener);
|
||||||
|
|
||||||
animateDisplay();
|
animateDisplay();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void animateDisplay() {
|
protected void animateDisplay() {
|
||||||
|
@ -302,10 +308,13 @@ public class Popup {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void layout() {
|
protected void layout() {
|
||||||
Window window = owner.getScene().getWindow();
|
Scene rootScene = owner.getScene();
|
||||||
double titleBarHeight = window.getHeight() - owner.getScene().getHeight();
|
if (rootScene != null) {
|
||||||
stage.setX(Math.round(window.getX() + (owner.getWidth() - stage.getWidth()) / 2));
|
Window window = rootScene.getWindow();
|
||||||
stage.setY(Math.round(window.getY() + titleBarHeight + (owner.getHeight() - stage.getHeight()) / 2));
|
double titleBarHeight = window.getHeight() - rootScene.getHeight();
|
||||||
|
stage.setX(Math.round(window.getX() + (owner.getWidth() - stage.getWidth()) / 2));
|
||||||
|
stage.setY(Math.round(window.getY() + titleBarHeight + (owner.getHeight() - stage.getHeight()) / 2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addHeadLine() {
|
protected void addHeadLine() {
|
||||||
|
|
|
@ -180,8 +180,8 @@ public class TradeDetailsPopup extends Popup {
|
||||||
addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", trade.getDepositTx().getHashAsString());
|
addLabelTxIdTextField(gridPane, ++rowIndex, "Deposit transaction ID:", trade.getDepositTx().getHashAsString());
|
||||||
if (trade.getPayoutTx() != null)
|
if (trade.getPayoutTx() != null)
|
||||||
addLabelTxIdTextField(gridPane, ++rowIndex, "Payout transaction ID:", trade.getPayoutTx().getHashAsString());
|
addLabelTxIdTextField(gridPane, ++rowIndex, "Payout transaction ID:", trade.getPayoutTx().getHashAsString());
|
||||||
if (disputeManager.findOwnDispute(trade.getId()).isPresent() && disputeManager.findOwnDispute(trade.getId()).get().getDisputePayoutTx() != null)
|
if (disputeManager.findOwnDispute(trade.getId()).isPresent() && disputeManager.findOwnDispute(trade.getId()).get().getDisputePayoutTxId() != null)
|
||||||
addLabelTxIdTextField(gridPane, ++rowIndex, "Disputed payout transaction ID:", disputeManager.findOwnDispute(trade.getId()).get().getDisputePayoutTx().getHashAsString());
|
addLabelTxIdTextField(gridPane, ++rowIndex, "Disputed payout transaction ID:", disputeManager.findOwnDispute(trade.getId()).get().getDisputePayoutTxId());
|
||||||
|
|
||||||
if (contract != null) {
|
if (contract != null) {
|
||||||
TextArea textArea = addLabelTextArea(gridPane, ++rowIndex, "Contract in JSON format:", trade.getContractAsJson()).second;
|
TextArea textArea = addLabelTextArea(gridPane, ++rowIndex, "Contract in JSON format:", trade.getContractAsJson()).second;
|
||||||
|
|
|
@ -245,13 +245,13 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad
|
||||||
public void updateItem(final PendingTradesListItem item, boolean empty) {
|
public void updateItem(final PendingTradesListItem item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
if (item != null && !empty) {
|
if (item != null && !empty) {
|
||||||
if (model.showDispute(item.getTrade())) {
|
/* if (model.showDispute(item.getTrade())) {
|
||||||
setStyle("-fx-text-fill: -bs-error-red");
|
setStyle("-fx-text-fill: -bs-error-red");
|
||||||
} else if (model.showWarning(item.getTrade())) {
|
} else if (model.showWarning(item.getTrade())) {
|
||||||
setStyle("-fx-text-fill: -bs-warning");
|
setStyle("-fx-text-fill: -bs-warning");
|
||||||
} else {
|
} else {
|
||||||
setId("-fx-text-fill: black");
|
setId("-fx-text-fill: black");
|
||||||
}
|
}*/
|
||||||
setText(formatter.formatDateTime(item.getTrade().getDate()));
|
setText(formatter.formatDateTime(item.getTrade().getDate()));
|
||||||
} else {
|
} else {
|
||||||
setText(null);
|
setText(null);
|
||||||
|
|
|
@ -291,20 +291,19 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad
|
||||||
buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_FIAT_PAYMENT_RECEIPT);
|
buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_FIAT_PAYMENT_RECEIPT);
|
||||||
break;
|
break;
|
||||||
case FIAT_PAYMENT_STARTED_MSG_RECEIVED:
|
case FIAT_PAYMENT_STARTED_MSG_RECEIVED:
|
||||||
|
case FIAT_PAYMENT_RECEIPT: // In case the msg sending failed we stick in that view state
|
||||||
sellerState.set(REQUEST_CONFIRM_FIAT_PAYMENT_RECEIVED);
|
sellerState.set(REQUEST_CONFIRM_FIAT_PAYMENT_RECEIVED);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case FIAT_PAYMENT_RECEIPT:
|
|
||||||
break;
|
|
||||||
case FIAT_PAYMENT_RECEIPT_MSG_SENT:
|
case FIAT_PAYMENT_RECEIPT_MSG_SENT:
|
||||||
sellerState.set(WAIT_FOR_PAYOUT_TX);
|
sellerState.set(WAIT_FOR_PAYOUT_TX);
|
||||||
buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_FIAT_PAYMENT_RECEIPT);
|
|
||||||
break;
|
break;
|
||||||
case FIAT_PAYMENT_RECEIPT_MSG_RECEIVED:
|
case FIAT_PAYMENT_RECEIPT_MSG_RECEIVED:
|
||||||
|
buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_FIAT_PAYMENT_RECEIPT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case PAYOUT_TX_COMMITTED:
|
||||||
case PAYOUT_TX_SENT:
|
case PAYOUT_TX_SENT:
|
||||||
buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_BROADCAST_AFTER_UNLOCK);
|
buyerState.set(PendingTradesViewModel.BuyerState.WAIT_FOR_BROADCAST_AFTER_UNLOCK);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -211,7 +211,6 @@ public abstract class Connection implements Closeable {
|
||||||
} else {
|
} else {
|
||||||
if (running) {
|
if (running) {
|
||||||
onError(new ConnectionException(e));
|
onError(new ConnectionException(e));
|
||||||
// TODO: Fault Tolerance?
|
|
||||||
if (e instanceof EOFException) {
|
if (e instanceof EOFException) {
|
||||||
try {
|
try {
|
||||||
close(false, PredefinedDisconnectReason.RESET);
|
close(false, PredefinedDisconnectReason.RESET);
|
||||||
|
|
|
@ -118,7 +118,6 @@ public class TorNodeTest {
|
||||||
sock.close();
|
sock.close();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,19 +15,13 @@
|
||||||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.bitsquare.p2p.messaging;
|
package io.bitsquare.crypto;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
|
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
// TODO is that sent over wire????
|
public final class DecryptedMsgWithPubKey {
|
||||||
public final class DecryptedMsgWithPubKey implements DirectMessage {
|
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
|
||||||
|
|
||||||
private final int messageVersion = Version.getP2PMessageVersion();
|
|
||||||
public final Message message;
|
public final Message message;
|
||||||
public final PublicKey signaturePubKey;
|
public final PublicKey signaturePubKey;
|
||||||
|
|
||||||
|
@ -36,11 +30,6 @@ public final class DecryptedMsgWithPubKey implements DirectMessage {
|
||||||
this.signaturePubKey = signaturePubKey;
|
this.signaturePubKey = signaturePubKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMessageVersion() {
|
|
||||||
return messageVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
@ -48,7 +37,6 @@ public final class DecryptedMsgWithPubKey implements DirectMessage {
|
||||||
|
|
||||||
DecryptedMsgWithPubKey that = (DecryptedMsgWithPubKey) o;
|
DecryptedMsgWithPubKey that = (DecryptedMsgWithPubKey) o;
|
||||||
|
|
||||||
//noinspection SimplifiableIfStatement
|
|
||||||
if (message != null ? !message.equals(that.message) : that.message != null) return false;
|
if (message != null ? !message.equals(that.message) : that.message != null) return false;
|
||||||
return !(signaturePubKey != null ? !signaturePubKey.equals(that.signaturePubKey) : that.signaturePubKey != null);
|
return !(signaturePubKey != null ? !signaturePubKey.equals(that.signaturePubKey) : that.signaturePubKey != null);
|
||||||
|
|
||||||
|
@ -64,7 +52,6 @@ public final class DecryptedMsgWithPubKey implements DirectMessage {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "DecryptedMsgWithPubKey{" +
|
return "DecryptedMsgWithPubKey{" +
|
||||||
"messageVersion=" + messageVersion +
|
|
||||||
", message=" + message +
|
", message=" + message +
|
||||||
", signaturePubKey.hashCode()=" + signaturePubKey.hashCode() +
|
", signaturePubKey.hashCode()=" + signaturePubKey.hashCode() +
|
||||||
'}';
|
'}';
|
|
@ -19,7 +19,6 @@ package io.bitsquare.crypto;
|
||||||
|
|
||||||
import io.bitsquare.common.crypto.*;
|
import io.bitsquare.common.crypto.*;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
|
|
|
@ -14,8 +14,8 @@ import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.crypto.CryptoException;
|
import io.bitsquare.common.crypto.CryptoException;
|
||||||
import io.bitsquare.common.crypto.KeyRing;
|
import io.bitsquare.common.crypto.KeyRing;
|
||||||
import io.bitsquare.common.crypto.PubKeyRing;
|
import io.bitsquare.common.crypto.PubKeyRing;
|
||||||
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.crypto.EncryptionService;
|
import io.bitsquare.crypto.EncryptionService;
|
||||||
import io.bitsquare.crypto.PrefixedSealedAndSignedMessage;
|
|
||||||
import io.bitsquare.p2p.messaging.*;
|
import io.bitsquare.p2p.messaging.*;
|
||||||
import io.bitsquare.p2p.network.*;
|
import io.bitsquare.p2p.network.*;
|
||||||
import io.bitsquare.p2p.peers.Broadcaster;
|
import io.bitsquare.p2p.peers.Broadcaster;
|
||||||
|
@ -26,12 +26,12 @@ import io.bitsquare.p2p.peers.peerexchange.PeerExchangeManager;
|
||||||
import io.bitsquare.p2p.seed.SeedNodesRepository;
|
import io.bitsquare.p2p.seed.SeedNodesRepository;
|
||||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||||
import io.bitsquare.p2p.storage.P2PDataStorage;
|
import io.bitsquare.p2p.storage.P2PDataStorage;
|
||||||
import io.bitsquare.p2p.storage.data.ExpirablePayload;
|
|
||||||
import io.bitsquare.p2p.storage.data.MailboxPayload;
|
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedMailboxData;
|
|
||||||
import io.bitsquare.p2p.storage.messages.AddDataMessage;
|
import io.bitsquare.p2p.storage.messages.AddDataMessage;
|
||||||
import io.bitsquare.p2p.storage.messages.RefreshTTLMessage;
|
import io.bitsquare.p2p.storage.messages.RefreshTTLMessage;
|
||||||
|
import io.bitsquare.p2p.storage.payload.MailboxStoragePayload;
|
||||||
|
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||||
|
import io.bitsquare.p2p.storage.storageentry.ProtectedMailboxStorageEntry;
|
||||||
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
import javafx.beans.property.*;
|
import javafx.beans.property.*;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import org.fxmisc.easybind.EasyBind;
|
import org.fxmisc.easybind.EasyBind;
|
||||||
|
@ -74,7 +74,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
private final Set<DecryptedDirectMessageListener> decryptedDirectMessageListeners = new CopyOnWriteArraySet<>();
|
private final Set<DecryptedDirectMessageListener> decryptedDirectMessageListeners = new CopyOnWriteArraySet<>();
|
||||||
private final Set<DecryptedMailboxListener> decryptedMailboxListeners = new CopyOnWriteArraySet<>();
|
private final Set<DecryptedMailboxListener> decryptedMailboxListeners = new CopyOnWriteArraySet<>();
|
||||||
private final Set<P2PServiceListener> p2pServiceListeners = new CopyOnWriteArraySet<>();
|
private final Set<P2PServiceListener> p2pServiceListeners = new CopyOnWriteArraySet<>();
|
||||||
private final Map<DecryptedMsgWithPubKey, ProtectedMailboxData> mailboxMap = new HashMap<>();
|
private final Map<String, ProtectedMailboxStorageEntry> mailboxMap = new HashMap<>();
|
||||||
private final Set<Runnable> shutDownResultHandlers = new CopyOnWriteArraySet<>();
|
private final Set<Runnable> shutDownResultHandlers = new CopyOnWriteArraySet<>();
|
||||||
private final BooleanProperty hiddenServicePublished = new SimpleBooleanProperty();
|
private final BooleanProperty hiddenServicePublished = new SimpleBooleanProperty();
|
||||||
private final BooleanProperty preliminaryDataReceived = new SimpleBooleanProperty();
|
private final BooleanProperty preliminaryDataReceived = new SimpleBooleanProperty();
|
||||||
|
@ -131,7 +131,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
|
|
||||||
p2PDataStorage = new P2PDataStorage(broadcaster, networkNode, storageDir);
|
p2PDataStorage = new P2PDataStorage(broadcaster, networkNode, storageDir);
|
||||||
p2PDataStorage.addHashMapChangedListener(this);
|
p2PDataStorage.addHashMapChangedListener(this);
|
||||||
|
|
||||||
requestDataManager = new RequestDataManager(networkNode, p2PDataStorage, peerManager, seedNodeAddresses, this);
|
requestDataManager = new RequestDataManager(networkNode, p2PDataStorage, peerManager, seedNodeAddresses, this);
|
||||||
|
|
||||||
peerExchangeManager = new PeerExchangeManager(networkNode, peerManager, seedNodeAddresses);
|
peerExchangeManager = new PeerExchangeManager(networkNode, peerManager, seedNodeAddresses);
|
||||||
|
@ -177,7 +177,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
|
|
||||||
if (broadcaster != null)
|
if (broadcaster != null)
|
||||||
broadcaster.shutDown();
|
broadcaster.shutDown();
|
||||||
|
|
||||||
if (requestDataManager != null)
|
if (requestDataManager != null)
|
||||||
requestDataManager.shutDown();
|
requestDataManager.shutDown();
|
||||||
|
|
||||||
|
@ -375,13 +375,13 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAdded(ProtectedData data) {
|
public void onAdded(ProtectedStorageEntry protectedStorageEntry) {
|
||||||
if (data instanceof ProtectedMailboxData)
|
if (protectedStorageEntry instanceof ProtectedMailboxStorageEntry)
|
||||||
processProtectedMailboxData((ProtectedMailboxData) data);
|
processProtectedMailboxStorageEntry((ProtectedMailboxStorageEntry) protectedStorageEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemoved(ProtectedData data) {
|
public void onRemoved(ProtectedStorageEntry data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -437,45 +437,42 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
// MailboxMessages
|
// MailboxMessages
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void processProtectedMailboxData(ProtectedMailboxData mailboxData) {
|
private void processProtectedMailboxStorageEntry(ProtectedMailboxStorageEntry protectedMailboxStorageEntry) {
|
||||||
// Seed nodes don't have set the encryptionService
|
// Seed nodes don't have set the encryptionService
|
||||||
if (optionalEncryptionService.isPresent()) {
|
if (optionalEncryptionService.isPresent()) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
ExpirablePayload expirablePayload = mailboxData.expirablePayload;
|
MailboxStoragePayload mailboxStoragePayload = protectedMailboxStorageEntry.getMailboxStoragePayload();
|
||||||
if (expirablePayload instanceof MailboxPayload) {
|
PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage = mailboxStoragePayload.prefixedSealedAndSignedMessage;
|
||||||
MailboxPayload expirableMailboxPayload = (MailboxPayload) expirablePayload;
|
if (verifyAddressPrefixHash(prefixedSealedAndSignedMessage)) {
|
||||||
PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage = expirableMailboxPayload.prefixedSealedAndSignedMessage;
|
try {
|
||||||
if (verifyAddressPrefixHash(prefixedSealedAndSignedMessage)) {
|
DecryptedMsgWithPubKey decryptedMsgWithPubKey = optionalEncryptionService.get().decryptAndVerify(
|
||||||
try {
|
prefixedSealedAndSignedMessage.sealedAndSigned);
|
||||||
DecryptedMsgWithPubKey decryptedMsgWithPubKey = optionalEncryptionService.get().decryptAndVerify(
|
if (decryptedMsgWithPubKey.message instanceof MailboxMessage) {
|
||||||
prefixedSealedAndSignedMessage.sealedAndSigned);
|
MailboxMessage mailboxMessage = (MailboxMessage) decryptedMsgWithPubKey.message;
|
||||||
if (decryptedMsgWithPubKey.message instanceof io.bitsquare.p2p.messaging.MailboxMessage) {
|
NodeAddress senderNodeAddress = mailboxMessage.getSenderNodeAddress();
|
||||||
io.bitsquare.p2p.messaging.MailboxMessage mailboxMessage = (io.bitsquare.p2p.messaging.MailboxMessage) decryptedMsgWithPubKey.message;
|
checkNotNull(senderNodeAddress, "senderAddress must not be null for mailbox messages");
|
||||||
NodeAddress senderNodeAddress = mailboxMessage.getSenderNodeAddress();
|
|
||||||
checkNotNull(senderNodeAddress, "senderAddress must not be null for mailbox messages");
|
|
||||||
|
|
||||||
mailboxMap.put(decryptedMsgWithPubKey, mailboxData);
|
mailboxMap.put(mailboxMessage.getUID(), protectedMailboxStorageEntry);
|
||||||
log.trace("Decryption of SealedAndSignedMessage succeeded. senderAddress="
|
log.trace("Decryption of SealedAndSignedMessage succeeded. senderAddress="
|
||||||
+ senderNodeAddress + " / my address=" + getAddress());
|
+ senderNodeAddress + " / my address=" + getAddress());
|
||||||
decryptedMailboxListeners.stream().forEach(
|
decryptedMailboxListeners.stream().forEach(
|
||||||
e -> e.onMailboxMessageAdded(decryptedMsgWithPubKey, senderNodeAddress));
|
e -> e.onMailboxMessageAdded(decryptedMsgWithPubKey, senderNodeAddress));
|
||||||
} else {
|
} else {
|
||||||
log.warn("tryDecryptMailboxData: Expected MailboxMessage but got other type. " +
|
log.warn("tryDecryptMailboxData: Expected MailboxMessage but got other type. " +
|
||||||
"decryptedMsgWithPubKey.message=", decryptedMsgWithPubKey.message);
|
"decryptedMsgWithPubKey.message=", decryptedMsgWithPubKey.message);
|
||||||
}
|
|
||||||
} catch (CryptoException e) {
|
|
||||||
log.trace("Decryption of SealedAndSignedMessage failed. " +
|
|
||||||
"That is expected if the message is not intended for us. " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
} else {
|
} catch (CryptoException e) {
|
||||||
log.info("Wrong blurredAddressHash. The message is not intended for us.");
|
log.trace("Decryption of SealedAndSignedMessage failed. " +
|
||||||
|
"That is expected if the message is not intended for us. " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.info("Wrong blurredAddressHash. The message is not intended for us.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendEncryptedMailboxMessage(NodeAddress peersNodeAddress, PubKeyRing peersPubKeyRing,
|
public void sendEncryptedMailboxMessage(NodeAddress peersNodeAddress, PubKeyRing peersPubKeyRing,
|
||||||
io.bitsquare.p2p.messaging.MailboxMessage message,
|
MailboxMessage message,
|
||||||
SendMailboxMessageListener sendMailboxMessageListener) {
|
SendMailboxMessageListener sendMailboxMessageListener) {
|
||||||
Log.traceCall("message " + message);
|
Log.traceCall("message " + message);
|
||||||
checkNotNull(peersNodeAddress,
|
checkNotNull(peersNodeAddress,
|
||||||
|
@ -514,7 +511,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
log.info("We cannot send message to peer. Peer might be offline. We will store message in mailbox.");
|
log.info("We cannot send message to peer. Peer might be offline. We will store message in mailbox.");
|
||||||
log.trace("create MailboxEntry with peerAddress " + peersNodeAddress);
|
log.trace("create MailboxEntry with peerAddress " + peersNodeAddress);
|
||||||
PublicKey receiverStoragePublicKey = peersPubKeyRing.getSignaturePubKey();
|
PublicKey receiverStoragePublicKey = peersPubKeyRing.getSignaturePubKey();
|
||||||
addMailboxData(new MailboxPayload(prefixedSealedAndSignedMessage,
|
addMailboxData(new MailboxStoragePayload(prefixedSealedAndSignedMessage,
|
||||||
optionalKeyRing.get().getSignatureKeyPair().getPublic(),
|
optionalKeyRing.get().getSignatureKeyPair().getPublic(),
|
||||||
receiverStoragePublicKey),
|
receiverStoragePublicKey),
|
||||||
receiverStoragePublicKey,
|
receiverStoragePublicKey,
|
||||||
|
@ -536,7 +533,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void addMailboxData(MailboxPayload expirableMailboxPayload,
|
private void addMailboxData(MailboxStoragePayload expirableMailboxStoragePayload,
|
||||||
PublicKey receiversPublicKey,
|
PublicKey receiversPublicKey,
|
||||||
SendMailboxMessageListener sendMailboxMessageListener) {
|
SendMailboxMessageListener sendMailboxMessageListener) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
|
@ -546,19 +543,19 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
if (isBootstrapped()) {
|
if (isBootstrapped()) {
|
||||||
if (!networkNode.getAllConnections().isEmpty()) {
|
if (!networkNode.getAllConnections().isEmpty()) {
|
||||||
try {
|
try {
|
||||||
ProtectedMailboxData protectedMailboxData = p2PDataStorage.getMailboxDataWithSignedSeqNr(
|
ProtectedMailboxStorageEntry protectedMailboxStorageEntry = p2PDataStorage.getMailboxDataWithSignedSeqNr(
|
||||||
expirableMailboxPayload,
|
expirableMailboxStoragePayload,
|
||||||
optionalKeyRing.get().getSignatureKeyPair(),
|
optionalKeyRing.get().getSignatureKeyPair(),
|
||||||
receiversPublicKey);
|
receiversPublicKey);
|
||||||
|
|
||||||
Timer sendMailboxMessageTimeoutTimer = UserThread.runAfter(() -> {
|
Timer sendMailboxMessageTimeoutTimer = UserThread.runAfter(() -> {
|
||||||
boolean result = p2PDataStorage.remove(protectedMailboxData, networkNode.getNodeAddress());
|
boolean result = p2PDataStorage.remove(protectedMailboxStorageEntry, networkNode.getNodeAddress());
|
||||||
log.debug("remove result=" + result);
|
log.debug("remove result=" + result);
|
||||||
sendMailboxMessageListener.onFault("A timeout occurred when trying to broadcast mailbox data.");
|
sendMailboxMessageListener.onFault("A timeout occurred when trying to broadcast mailbox data.");
|
||||||
}, 30);
|
}, 30);
|
||||||
Broadcaster.Listener listener = message -> {
|
Broadcaster.Listener listener = message -> {
|
||||||
if (message instanceof AddDataMessage &&
|
if (message instanceof AddDataMessage &&
|
||||||
((AddDataMessage) message).data.equals(protectedMailboxData)) {
|
((AddDataMessage) message).protectedStorageEntry.equals(protectedMailboxStorageEntry)) {
|
||||||
sendMailboxMessageListener.onStoredInMailbox();
|
sendMailboxMessageListener.onStoredInMailbox();
|
||||||
sendMailboxMessageTimeoutTimer.stop();
|
sendMailboxMessageTimeoutTimer.stop();
|
||||||
}
|
}
|
||||||
|
@ -573,20 +570,30 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
if ((int) newValue > 0)
|
if ((int) newValue > 0)
|
||||||
broadcaster.removeListener(listener);
|
broadcaster.removeListener(listener);
|
||||||
|
|
||||||
UserThread.execute(() -> {
|
if (numOfBroadcastsChangeListener != null) {
|
||||||
broadcaster.getNumOfBroadcastsProperty().removeListener(numOfBroadcastsChangeListener);
|
broadcaster.getNumOfBroadcastsProperty().removeListener(numOfBroadcastsChangeListener);
|
||||||
numOfBroadcastsChangeListener = null;
|
numOfBroadcastsChangeListener = null;
|
||||||
});
|
}
|
||||||
|
|
||||||
|
/* UserThread.execute(() -> {
|
||||||
|
if (numOfBroadcastsChangeListener != null) {
|
||||||
|
broadcaster.getNumOfBroadcastsProperty().removeListener(numOfBroadcastsChangeListener);
|
||||||
|
numOfBroadcastsChangeListener = null;
|
||||||
|
}
|
||||||
|
});*/
|
||||||
};
|
};
|
||||||
broadcaster.getNumOfBroadcastsProperty().addListener(numOfBroadcastsChangeListener);
|
broadcaster.getNumOfBroadcastsProperty().addListener(numOfBroadcastsChangeListener);
|
||||||
|
|
||||||
boolean result = p2PDataStorage.add(protectedMailboxData, networkNode.getNodeAddress());
|
boolean result = p2PDataStorage.add(protectedMailboxStorageEntry, networkNode.getNodeAddress());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
sendMailboxMessageTimeoutTimer.stop();
|
sendMailboxMessageTimeoutTimer.stop();
|
||||||
broadcaster.removeListener(listener);
|
broadcaster.removeListener(listener);
|
||||||
broadcaster.getNumOfBroadcastsProperty().removeListener(numOfBroadcastsChangeListener);
|
|
||||||
|
if (numOfBroadcastsChangeListener != null)
|
||||||
|
broadcaster.getNumOfBroadcastsProperty().removeListener(numOfBroadcastsChangeListener);
|
||||||
|
|
||||||
sendMailboxMessageListener.onFault("Data already exists in our local database");
|
sendMailboxMessageListener.onFault("Data already exists in our local database");
|
||||||
boolean result2 = p2PDataStorage.remove(protectedMailboxData, networkNode.getNodeAddress());
|
boolean result2 = p2PDataStorage.remove(protectedMailboxStorageEntry, networkNode.getNodeAddress());
|
||||||
log.debug("remove result=" + result2);
|
log.debug("remove result=" + result2);
|
||||||
}
|
}
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
|
@ -605,29 +612,31 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
||||||
if (isBootstrapped()) {
|
if (isBootstrapped()) {
|
||||||
if (mailboxMap.containsKey(decryptedMsgWithPubKey)) {
|
MailboxMessage mailboxMessage = (MailboxMessage) decryptedMsgWithPubKey.message;
|
||||||
ProtectedMailboxData mailboxData = mailboxMap.get(decryptedMsgWithPubKey);
|
String uid = mailboxMessage.getUID();
|
||||||
if (mailboxData != null && mailboxData.expirablePayload instanceof MailboxPayload) {
|
if (mailboxMap.containsKey(uid)) {
|
||||||
MailboxPayload expirableMailboxPayload = (MailboxPayload) mailboxData.expirablePayload;
|
ProtectedMailboxStorageEntry mailboxData = mailboxMap.get(uid);
|
||||||
|
if (mailboxData != null && mailboxData.getStoragePayload() instanceof MailboxStoragePayload) {
|
||||||
|
MailboxStoragePayload expirableMailboxStoragePayload = (MailboxStoragePayload) mailboxData.getStoragePayload();
|
||||||
PublicKey receiversPubKey = mailboxData.receiversPubKey;
|
PublicKey receiversPubKey = mailboxData.receiversPubKey;
|
||||||
checkArgument(receiversPubKey.equals(optionalKeyRing.get().getSignatureKeyPair().getPublic()),
|
checkArgument(receiversPubKey.equals(optionalKeyRing.get().getSignatureKeyPair().getPublic()),
|
||||||
"receiversPubKey is not matching with our key. That must not happen.");
|
"receiversPubKey is not matching with our key. That must not happen.");
|
||||||
try {
|
try {
|
||||||
ProtectedMailboxData protectedMailboxData = p2PDataStorage.getMailboxDataWithSignedSeqNr(
|
ProtectedMailboxStorageEntry protectedMailboxStorageEntry = p2PDataStorage.getMailboxDataWithSignedSeqNr(
|
||||||
expirableMailboxPayload,
|
expirableMailboxStoragePayload,
|
||||||
optionalKeyRing.get().getSignatureKeyPair(),
|
optionalKeyRing.get().getSignatureKeyPair(),
|
||||||
receiversPubKey);
|
receiversPubKey);
|
||||||
p2PDataStorage.removeMailboxData(protectedMailboxData, networkNode.getNodeAddress());
|
p2PDataStorage.removeMailboxData(protectedMailboxStorageEntry, networkNode.getNodeAddress());
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
mailboxMap.remove(decryptedMsgWithPubKey);
|
mailboxMap.remove(uid);
|
||||||
log.trace("Removed successfully decryptedMsgWithPubKey.");
|
log.trace("Removed successfully decryptedMsgWithPubKey.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.warn("decryptedMsgWithPubKey not found in mailboxMap. That should never happen." +
|
log.warn("uid for mailbox entry not found in mailboxMap. That should never happen." +
|
||||||
"\n\tdecryptedMsgWithPubKey={}\n\tmailboxMap={}", decryptedMsgWithPubKey, mailboxMap);
|
"\n\tuid={}\n\tmailboxMap={}\n\tmailboxMessage={}", uid, mailboxMap, mailboxMessage);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new NetworkNotReadyException();
|
throw new NetworkNotReadyException();
|
||||||
|
@ -640,17 +649,17 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
// Data storage
|
// Data storage
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public boolean addData(ExpirablePayload expirablePayload) {
|
public boolean addData(StoragePayload storagePayload) {
|
||||||
return addData(expirablePayload, false);
|
return addData(storagePayload, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addData(ExpirablePayload expirablePayload, boolean forceBroadcast) {
|
public boolean addData(StoragePayload storagePayload, boolean forceBroadcast) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
||||||
if (isBootstrapped()) {
|
if (isBootstrapped()) {
|
||||||
try {
|
try {
|
||||||
ProtectedData protectedData = p2PDataStorage.getProtectedData(expirablePayload, optionalKeyRing.get().getSignatureKeyPair());
|
ProtectedStorageEntry protectedStorageEntry = p2PDataStorage.getProtectedData(storagePayload, optionalKeyRing.get().getSignatureKeyPair());
|
||||||
return p2PDataStorage.add(protectedData, networkNode.getNodeAddress(), forceBroadcast);
|
return p2PDataStorage.add(protectedStorageEntry, networkNode.getNodeAddress(), forceBroadcast);
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
||||||
return false;
|
return false;
|
||||||
|
@ -660,12 +669,12 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean refreshTTL(ExpirablePayload expirablePayload) {
|
public boolean refreshTTL(StoragePayload storagePayload) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
||||||
if (isBootstrapped()) {
|
if (isBootstrapped()) {
|
||||||
try {
|
try {
|
||||||
RefreshTTLMessage refreshTTLMessage = p2PDataStorage.getRefreshTTLMessage(expirablePayload, optionalKeyRing.get().getSignatureKeyPair());
|
RefreshTTLMessage refreshTTLMessage = p2PDataStorage.getRefreshTTLMessage(storagePayload, optionalKeyRing.get().getSignatureKeyPair());
|
||||||
return p2PDataStorage.refreshTTL(refreshTTLMessage, networkNode.getNodeAddress());
|
return p2PDataStorage.refreshTTL(refreshTTLMessage, networkNode.getNodeAddress());
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
||||||
|
@ -676,13 +685,13 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeData(ExpirablePayload expirablePayload) {
|
public boolean removeData(StoragePayload storagePayload) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
checkArgument(optionalKeyRing.isPresent(), "keyRing not set. Seems that is called on a seed node which must not happen.");
|
||||||
if (isBootstrapped()) {
|
if (isBootstrapped()) {
|
||||||
try {
|
try {
|
||||||
ProtectedData protectedData = p2PDataStorage.getProtectedData(expirablePayload, optionalKeyRing.get().getSignatureKeyPair());
|
ProtectedStorageEntry protectedStorageEntry = p2PDataStorage.getProtectedData(storagePayload, optionalKeyRing.get().getSignatureKeyPair());
|
||||||
return p2PDataStorage.remove(protectedData, networkNode.getNodeAddress());
|
return p2PDataStorage.remove(protectedStorageEntry, networkNode.getNodeAddress());
|
||||||
} catch (CryptoException e) {
|
} catch (CryptoException e) {
|
||||||
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
log.error("Signing at getDataWithSignedSeqNr failed. That should never happen.");
|
||||||
return false;
|
return false;
|
||||||
|
@ -747,7 +756,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
||||||
return numConnectedPeers;
|
return numConnectedPeers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<P2PDataStorage.ByteArray, ProtectedData> getDataMap() {
|
public Map<P2PDataStorage.ByteArray, ProtectedStorageEntry> getDataMap() {
|
||||||
return p2PDataStorage.getMap();
|
return p2PDataStorage.getMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.bitsquare.p2p.messaging;
|
package io.bitsquare.p2p.messaging;
|
||||||
|
|
||||||
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
|
|
||||||
public interface DecryptedDirectMessageListener {
|
public interface DecryptedDirectMessageListener {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package io.bitsquare.p2p.messaging;
|
package io.bitsquare.p2p.messaging;
|
||||||
|
|
||||||
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
|
|
||||||
public interface DecryptedMailboxListener {
|
public interface DecryptedMailboxListener {
|
||||||
|
|
|
@ -22,4 +22,6 @@ import io.bitsquare.p2p.NodeAddress;
|
||||||
|
|
||||||
public interface MailboxMessage extends DirectMessage {
|
public interface MailboxMessage extends DirectMessage {
|
||||||
NodeAddress getSenderNodeAddress();
|
NodeAddress getSenderNodeAddress();
|
||||||
|
|
||||||
|
String getUID();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package io.bitsquare.crypto;
|
package io.bitsquare.p2p.messaging;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.common.crypto.SealedAndSigned;
|
import io.bitsquare.common.crypto.SealedAndSigned;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.messaging.MailboxMessage;
|
|
||||||
import io.bitsquare.p2p.network.messages.SendersNodeAddressMessage;
|
import io.bitsquare.p2p.network.messages.SendersNodeAddressMessage;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public final class PrefixedSealedAndSignedMessage implements MailboxMessage, SendersNodeAddressMessage {
|
public final class PrefixedSealedAndSignedMessage implements MailboxMessage, SendersNodeAddressMessage {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
|
@ -16,6 +16,7 @@ public final class PrefixedSealedAndSignedMessage implements MailboxMessage, Sen
|
||||||
private final NodeAddress senderNodeAddress;
|
private final NodeAddress senderNodeAddress;
|
||||||
public final SealedAndSigned sealedAndSigned;
|
public final SealedAndSigned sealedAndSigned;
|
||||||
public final byte[] addressPrefixHash;
|
public final byte[] addressPrefixHash;
|
||||||
|
private final String uid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
public PrefixedSealedAndSignedMessage(NodeAddress senderNodeAddress, SealedAndSigned sealedAndSigned, byte[] addressPrefixHash) {
|
public PrefixedSealedAndSignedMessage(NodeAddress senderNodeAddress, SealedAndSigned sealedAndSigned, byte[] addressPrefixHash) {
|
||||||
this.senderNodeAddress = senderNodeAddress;
|
this.senderNodeAddress = senderNodeAddress;
|
||||||
|
@ -28,6 +29,11 @@ public final class PrefixedSealedAndSignedMessage implements MailboxMessage, Sen
|
||||||
return senderNodeAddress;
|
return senderNodeAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUID() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMessageVersion() {
|
public int getMessageVersion() {
|
||||||
return messageVersion;
|
return messageVersion;
|
|
@ -7,10 +7,10 @@ import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.common.ByteArrayUtils;
|
import io.bitsquare.common.ByteArrayUtils;
|
||||||
import io.bitsquare.common.UserThread;
|
import io.bitsquare.common.UserThread;
|
||||||
import io.bitsquare.common.util.Tuple2;
|
import io.bitsquare.common.util.Tuple2;
|
||||||
import io.bitsquare.crypto.PrefixedSealedAndSignedMessage;
|
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.Utils;
|
import io.bitsquare.p2p.Utils;
|
||||||
|
import io.bitsquare.p2p.messaging.PrefixedSealedAndSignedMessage;
|
||||||
import io.bitsquare.p2p.network.messages.CloseConnectionMessage;
|
import io.bitsquare.p2p.network.messages.CloseConnectionMessage;
|
||||||
import io.bitsquare.p2p.network.messages.SendersNodeAddressMessage;
|
import io.bitsquare.p2p.network.messages.SendersNodeAddressMessage;
|
||||||
import io.bitsquare.p2p.peers.keepalive.messages.KeepAliveMessage;
|
import io.bitsquare.p2p.peers.keepalive.messages.KeepAliveMessage;
|
||||||
|
@ -57,12 +57,10 @@ public class Connection implements MessageListener {
|
||||||
// Static
|
// Static
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private static final int MAX_MSG_SIZE = 100 * 1024; // 100 kb of compressed data
|
private static final int MAX_MSG_SIZE = 100 * 1024; // 100 kb of compressed data
|
||||||
private static final int MSG_THROTTLE_PER_SEC = 10; // With MAX_MSG_SIZE of 100kb results in bandwidth of 10 mbit/sec
|
private static final int MSG_THROTTLE_PER_SEC = 20; // With MAX_MSG_SIZE of 100kb results in bandwidth of 20 mbit/sec
|
||||||
private static final int MSG_THROTTLE_PER_10_SEC = 50; // With MAX_MSG_SIZE of 100kb results in bandwidth of 5 mbit/sec for 10 sec
|
private static final int MSG_THROTTLE_PER_10_SEC = 100; // With MAX_MSG_SIZE of 100kb results in bandwidth of 10 mbit/sec for 10 sec
|
||||||
//private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(60);
|
private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(60);
|
||||||
//TODO
|
|
||||||
private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(20);
|
|
||||||
|
|
||||||
public static int getMaxMsgSize() {
|
public static int getMaxMsgSize() {
|
||||||
return MAX_MSG_SIZE;
|
return MAX_MSG_SIZE;
|
||||||
|
@ -519,7 +517,7 @@ public class Connection implements MessageListener {
|
||||||
} else if (e instanceof SocketTimeoutException || e instanceof TimeoutException) {
|
} else if (e instanceof SocketTimeoutException || e instanceof TimeoutException) {
|
||||||
closeConnectionReason = CloseConnectionReason.SOCKET_TIMEOUT;
|
closeConnectionReason = CloseConnectionReason.SOCKET_TIMEOUT;
|
||||||
log.warn("SocketTimeoutException at socket " + socket.toString() + "\n\tconnection={}" + this);
|
log.warn("SocketTimeoutException at socket " + socket.toString() + "\n\tconnection={}" + this);
|
||||||
} else if (e instanceof EOFException) {
|
} else if (e instanceof EOFException || e instanceof StreamCorruptedException) {
|
||||||
closeConnectionReason = CloseConnectionReason.TERMINATED;
|
closeConnectionReason = CloseConnectionReason.TERMINATED;
|
||||||
} else {
|
} else {
|
||||||
closeConnectionReason = CloseConnectionReason.UNKNOWN_EXCEPTION;
|
closeConnectionReason = CloseConnectionReason.UNKNOWN_EXCEPTION;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import io.bitsquare.p2p.network.CloseConnectionReason;
|
||||||
import io.bitsquare.p2p.network.Connection;
|
import io.bitsquare.p2p.network.Connection;
|
||||||
import io.bitsquare.p2p.network.ConnectionListener;
|
import io.bitsquare.p2p.network.ConnectionListener;
|
||||||
import io.bitsquare.p2p.network.NetworkNode;
|
import io.bitsquare.p2p.network.NetworkNode;
|
||||||
import io.bitsquare.p2p.storage.messages.DataBroadcastMessage;
|
import io.bitsquare.p2p.storage.messages.BroadcastMessage;
|
||||||
import javafx.beans.property.IntegerProperty;
|
import javafx.beans.property.IntegerProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
@ -26,7 +26,7 @@ public class Broadcaster implements ConnectionListener, PeerManager.Listener {
|
||||||
|
|
||||||
|
|
||||||
public interface Listener {
|
public interface Listener {
|
||||||
void onBroadcasted(DataBroadcastMessage message);
|
void onBroadcasted(BroadcastMessage message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final NetworkNode networkNode;
|
private final NetworkNode networkNode;
|
||||||
|
@ -59,7 +59,7 @@ public class Broadcaster implements ConnectionListener, PeerManager.Listener {
|
||||||
// API
|
// API
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void broadcast(DataBroadcastMessage message, @Nullable NodeAddress sender) {
|
public void broadcast(BroadcastMessage message, @Nullable NodeAddress sender) {
|
||||||
Log.traceCall("Sender=" + sender + "\n\t" +
|
Log.traceCall("Sender=" + sender + "\n\t" +
|
||||||
"Message=" + StringUtils.abbreviate(message.toString(), 100));
|
"Message=" + StringUtils.abbreviate(message.toString(), 100));
|
||||||
numOfBroadcasts.set(0);
|
numOfBroadcasts.set(0);
|
||||||
|
|
|
@ -2,7 +2,7 @@ package io.bitsquare.p2p.peers.getdata.messages;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
@ -11,10 +11,10 @@ public final class GetDataResponse implements Message {
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
private final int messageVersion = Version.getP2PMessageVersion();
|
private final int messageVersion = Version.getP2PMessageVersion();
|
||||||
|
|
||||||
public final HashSet<ProtectedData> dataSet;
|
public final HashSet<ProtectedStorageEntry> dataSet;
|
||||||
public final int requestNonce;
|
public final int requestNonce;
|
||||||
|
|
||||||
public GetDataResponse(HashSet<ProtectedData> dataSet, int requestNonce) {
|
public GetDataResponse(HashSet<ProtectedStorageEntry> dataSet, int requestNonce) {
|
||||||
this.dataSet = dataSet;
|
this.dataSet = dataSet;
|
||||||
this.requestNonce = requestNonce;
|
this.requestNonce = requestNonce;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,12 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class KeepAliveManager implements MessageListener, ConnectionListener, PeerManager.Listener {
|
public class KeepAliveManager implements MessageListener, ConnectionListener, PeerManager.Listener {
|
||||||
private static final Logger log = LoggerFactory.getLogger(KeepAliveManager.class);
|
private static final Logger log = LoggerFactory.getLogger(KeepAliveManager.class);
|
||||||
|
|
||||||
//private static final int INTERVAL_SEC = new Random().nextInt(10) + 10;
|
private static final int INTERVAL_SEC = new Random().nextInt(10) + 10;
|
||||||
//TODO
|
|
||||||
private static final int INTERVAL_SEC = 5;
|
|
||||||
|
|
||||||
private final NetworkNode networkNode;
|
private final NetworkNode networkNode;
|
||||||
private final PeerManager peerManager;
|
private final PeerManager peerManager;
|
||||||
|
|
|
@ -108,7 +108,6 @@ class GetPeersRequestHandler {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void handleFault(String errorMessage, CloseConnectionReason closeConnectionReason, Connection connection) {
|
private void handleFault(String errorMessage, CloseConnectionReason closeConnectionReason, Connection connection) {
|
||||||
// TODO retry
|
|
||||||
cleanup();
|
cleanup();
|
||||||
peerManager.shutDownConnection(connection, closeConnectionReason);
|
peerManager.shutDownConnection(connection, closeConnectionReason);
|
||||||
listener.onFault(errorMessage, connection);
|
listener.onFault(errorMessage, connection);
|
||||||
|
|
|
@ -85,11 +85,12 @@ class PeerExchangeHandler implements MessageListener {
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(Connection connection) {
|
public void onSuccess(Connection connection) {
|
||||||
if (!stopped) {
|
if (!stopped) {
|
||||||
|
|
||||||
if (!connection.getPeersNodeAddressOptional().isPresent()) {
|
if (!connection.getPeersNodeAddressOptional().isPresent()) {
|
||||||
connection.setPeersNodeAddress(nodeAddress);
|
connection.setPeersNodeAddress(nodeAddress);
|
||||||
//TODO remove setPeersNodeAddress if never needed
|
|
||||||
log.warn("sendGetPeersRequest: !connection.getPeersNodeAddressOptional().isPresent()");
|
log.warn("sendGetPeersRequest: !connection.getPeersNodeAddressOptional().isPresent()");
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerExchangeHandler.this.connection = connection;
|
PeerExchangeHandler.this.connection = connection;
|
||||||
connection.addMessageListener(PeerExchangeHandler.this);
|
connection.addMessageListener(PeerExchangeHandler.this);
|
||||||
log.trace("Send " + getPeersRequest + " to " + nodeAddress + " succeeded.");
|
log.trace("Send " + getPeersRequest + " to " + nodeAddress + " succeeded.");
|
||||||
|
@ -169,7 +170,6 @@ class PeerExchangeHandler implements MessageListener {
|
||||||
|
|
||||||
private void handleFault(String errorMessage, CloseConnectionReason sendMsgFailure, NodeAddress nodeAddress) {
|
private void handleFault(String errorMessage, CloseConnectionReason sendMsgFailure, NodeAddress nodeAddress) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
// TODO retry
|
|
||||||
cleanup();
|
cleanup();
|
||||||
if (connection == null)
|
if (connection == null)
|
||||||
peerManager.shutDownConnection(nodeAddress, sendMsgFailure);
|
peerManager.shutDownConnection(nodeAddress, sendMsgFailure);
|
||||||
|
|
|
@ -229,7 +229,6 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener,
|
||||||
handlerMap.put(nodeAddress, peerExchangeHandler);
|
handlerMap.put(nodeAddress, peerExchangeHandler);
|
||||||
peerExchangeHandler.sendGetPeersRequest(nodeAddress);
|
peerExchangeHandler.sendGetPeersRequest(nodeAddress);
|
||||||
} else {
|
} else {
|
||||||
//TODO check when that happens
|
|
||||||
log.warn("We have started already a peerExchangeHandler. " +
|
log.warn("We have started already a peerExchangeHandler. " +
|
||||||
"We ignore that call. nodeAddress=" + nodeAddress);
|
"We ignore that call. nodeAddress=" + nodeAddress);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package io.bitsquare.p2p.storage;
|
package io.bitsquare.p2p.storage;
|
||||||
|
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
|
|
||||||
public interface HashMapChangedListener {
|
public interface HashMapChangedListener {
|
||||||
void onAdded(ProtectedData data);
|
void onAdded(ProtectedStorageEntry data);
|
||||||
|
|
||||||
void onRemoved(ProtectedData data);
|
void onRemoved(ProtectedStorageEntry data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,13 @@ import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.network.*;
|
import io.bitsquare.p2p.network.*;
|
||||||
import io.bitsquare.p2p.peers.Broadcaster;
|
import io.bitsquare.p2p.peers.Broadcaster;
|
||||||
import io.bitsquare.p2p.storage.data.*;
|
|
||||||
import io.bitsquare.p2p.storage.messages.*;
|
import io.bitsquare.p2p.storage.messages.*;
|
||||||
|
import io.bitsquare.p2p.storage.payload.ExpirablePayload;
|
||||||
|
import io.bitsquare.p2p.storage.payload.MailboxStoragePayload;
|
||||||
|
import io.bitsquare.p2p.storage.payload.RequiresOwnerIsOnlinePayload;
|
||||||
|
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||||
|
import io.bitsquare.p2p.storage.storageentry.ProtectedMailboxStorageEntry;
|
||||||
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
import io.bitsquare.storage.Storage;
|
import io.bitsquare.storage.Storage;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -36,11 +41,10 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
private static final Logger log = LoggerFactory.getLogger(P2PDataStorage.class);
|
private static final Logger log = LoggerFactory.getLogger(P2PDataStorage.class);
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
//public static int CHECK_TTL_INTERVAL_MILLIS = (int) TimeUnit.SECONDS.toMillis(30);
|
public static int CHECK_TTL_INTERVAL_SEC = 30;
|
||||||
public static int CHECK_TTL_INTERVAL_SEC = 5;//TODO
|
|
||||||
|
|
||||||
private final Broadcaster broadcaster;
|
private final Broadcaster broadcaster;
|
||||||
private final Map<ByteArray, ProtectedData> map = new ConcurrentHashMap<>();
|
private final Map<ByteArray, ProtectedStorageEntry> map = new ConcurrentHashMap<>();
|
||||||
private final CopyOnWriteArraySet<HashMapChangedListener> hashMapChangedListeners = new CopyOnWriteArraySet<>();
|
private final CopyOnWriteArraySet<HashMapChangedListener> hashMapChangedListeners = new CopyOnWriteArraySet<>();
|
||||||
private Timer removeExpiredEntriesTimer;
|
private Timer removeExpiredEntriesTimer;
|
||||||
private HashMap<ByteArray, MapValue> sequenceNumberMap = new HashMap<>();
|
private HashMap<ByteArray, MapValue> sequenceNumberMap = new HashMap<>();
|
||||||
|
@ -76,15 +80,15 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
// object when we get it sent from new peers, we don’t remove the sequence number from the map.
|
// object when we get it sent from new peers, we don’t remove the sequence number from the map.
|
||||||
// That way an ADD message for an already expired data will fail because the sequence number
|
// That way an ADD message for an already expired data will fail because the sequence number
|
||||||
// is equal and not larger as expected.
|
// is equal and not larger as expected.
|
||||||
Map<ByteArray, ProtectedData> temp = new HashMap<>(map);
|
Map<ByteArray, ProtectedStorageEntry> temp = new HashMap<>(map);
|
||||||
Set<ProtectedData> toRemoveSet = new HashSet<>();
|
Set<ProtectedStorageEntry> toRemoveSet = new HashSet<>();
|
||||||
temp.entrySet().stream()
|
temp.entrySet().stream()
|
||||||
.filter(entry -> entry.getValue().isExpired())
|
.filter(entry -> entry.getValue().isExpired())
|
||||||
.forEach(entry -> {
|
.forEach(entry -> {
|
||||||
ByteArray hashOfPayload = entry.getKey();
|
ByteArray hashOfPayload = entry.getKey();
|
||||||
ProtectedData protectedData = map.get(hashOfPayload);
|
ProtectedStorageEntry protectedStorageEntry = map.get(hashOfPayload);
|
||||||
toRemoveSet.add(protectedData);
|
toRemoveSet.add(protectedStorageEntry);
|
||||||
log.warn("We found an expired data entry. We remove the protectedData:\n\t" + protectedData);
|
log.warn("We found an expired data entry. We remove the protectedData:\n\t" + protectedStorageEntry);
|
||||||
map.remove(hashOfPayload);
|
map.remove(hashOfPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -104,15 +108,15 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(Message message, Connection connection) {
|
public void onMessage(Message message, Connection connection) {
|
||||||
if (message instanceof DataBroadcastMessage) {
|
if (message instanceof BroadcastMessage) {
|
||||||
Log.traceCall(StringUtils.abbreviate(message.toString(), 100) + "\n\tconnection=" + connection);
|
Log.traceCall(StringUtils.abbreviate(message.toString(), 100) + "\n\tconnection=" + connection);
|
||||||
connection.getPeersNodeAddressOptional().ifPresent(peersNodeAddress -> {
|
connection.getPeersNodeAddressOptional().ifPresent(peersNodeAddress -> {
|
||||||
if (message instanceof AddDataMessage) {
|
if (message instanceof AddDataMessage) {
|
||||||
add(((AddDataMessage) message).data, peersNodeAddress);
|
add(((AddDataMessage) message).protectedStorageEntry, peersNodeAddress);
|
||||||
} else if (message instanceof RemoveDataMessage) {
|
} else if (message instanceof RemoveDataMessage) {
|
||||||
remove(((RemoveDataMessage) message).data, peersNodeAddress);
|
remove(((RemoveDataMessage) message).protectedStorageEntry, peersNodeAddress);
|
||||||
} else if (message instanceof RemoveMailboxDataMessage) {
|
} else if (message instanceof RemoveMailboxDataMessage) {
|
||||||
removeMailboxData(((RemoveMailboxDataMessage) message).data, peersNodeAddress);
|
removeMailboxData(((RemoveMailboxDataMessage) message).protectedMailboxStorageEntry, peersNodeAddress);
|
||||||
} else if (message instanceof RefreshTTLMessage) {
|
} else if (message instanceof RefreshTTLMessage) {
|
||||||
refreshTTL((RefreshTTLMessage) message, peersNodeAddress);
|
refreshTTL((RefreshTTLMessage) message, peersNodeAddress);
|
||||||
}
|
}
|
||||||
|
@ -134,7 +138,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
if (connection.getPeersNodeAddressOptional().isPresent() && !closeConnectionReason.isIntended) {
|
if (connection.getPeersNodeAddressOptional().isPresent() && !closeConnectionReason.isIntended) {
|
||||||
map.values().stream()
|
map.values().stream()
|
||||||
.forEach(protectedData -> {
|
.forEach(protectedData -> {
|
||||||
ExpirablePayload expirablePayload = protectedData.expirablePayload;
|
ExpirablePayload expirablePayload = protectedData.getStoragePayload();
|
||||||
if (expirablePayload instanceof RequiresOwnerIsOnlinePayload) {
|
if (expirablePayload instanceof RequiresOwnerIsOnlinePayload) {
|
||||||
RequiresOwnerIsOnlinePayload requiresOwnerIsOnlinePayload = (RequiresOwnerIsOnlinePayload) expirablePayload;
|
RequiresOwnerIsOnlinePayload requiresOwnerIsOnlinePayload = (RequiresOwnerIsOnlinePayload) expirablePayload;
|
||||||
NodeAddress ownerNodeAddress = requiresOwnerIsOnlinePayload.getOwnerNodeAddress();
|
NodeAddress ownerNodeAddress = requiresOwnerIsOnlinePayload.getOwnerNodeAddress();
|
||||||
|
@ -166,28 +170,27 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
// API
|
// API
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public boolean add(ProtectedData protectedData, @Nullable NodeAddress sender) {
|
public boolean add(ProtectedStorageEntry protectedStorageEntry, @Nullable NodeAddress sender) {
|
||||||
return add(protectedData, sender, false);
|
return add(protectedStorageEntry, sender, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean add(ProtectedData protectedData, @Nullable NodeAddress sender, boolean forceBroadcast) {
|
public boolean add(ProtectedStorageEntry protectedStorageEntry, @Nullable NodeAddress sender, boolean forceBroadcast) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
|
|
||||||
ByteArray hashOfPayload = getHashAsByteArray(protectedData.expirablePayload);
|
ByteArray hashOfPayload = getHashAsByteArray(protectedStorageEntry.getStoragePayload());
|
||||||
boolean result = checkPublicKeys(protectedData, true)
|
boolean result = checkPublicKeys(protectedStorageEntry, true)
|
||||||
&& checkSignature(protectedData)
|
&& checkSignature(protectedStorageEntry)
|
||||||
&& isSequenceNrValid(protectedData.sequenceNumber, hashOfPayload);
|
&& isSequenceNrValid(protectedStorageEntry.sequenceNumber, hashOfPayload);
|
||||||
|
|
||||||
boolean containsKey = map.containsKey(hashOfPayload);
|
boolean containsKey = map.containsKey(hashOfPayload);
|
||||||
if (containsKey)
|
if (containsKey)
|
||||||
result &= checkIfStoredDataPubKeyMatchesNewDataPubKey(protectedData.ownerPubKey, hashOfPayload);
|
result &= checkIfStoredDataPubKeyMatchesNewDataPubKey(protectedStorageEntry.ownerPubKey, hashOfPayload);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
map.put(hashOfPayload, protectedData);
|
map.put(hashOfPayload, protectedStorageEntry);
|
||||||
|
|
||||||
sequenceNumberMap.put(hashOfPayload, new MapValue(protectedData.sequenceNumber, System.currentTimeMillis()));
|
sequenceNumberMap.put(hashOfPayload, new MapValue(protectedStorageEntry.sequenceNumber, System.currentTimeMillis()));
|
||||||
storage.queueUpForSave(sequenceNumberMap, 100);
|
storage.queueUpForSave(sequenceNumberMap, 100);
|
||||||
log.error("sequenceNumberMap queueUpForSave protectedData.sequenceNumber " + protectedData.sequenceNumber);
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n");
|
StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n");
|
||||||
sb.append("Data set after doAdd (truncated)");
|
sb.append("Data set after doAdd (truncated)");
|
||||||
|
@ -197,11 +200,11 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
log.info("Data set after doAdd: size=" + map.values().size());
|
log.info("Data set after doAdd: size=" + map.values().size());
|
||||||
|
|
||||||
if (!containsKey || forceBroadcast)
|
if (!containsKey || forceBroadcast)
|
||||||
broadcast(new AddDataMessage(protectedData), sender);
|
broadcast(new AddDataMessage(protectedStorageEntry), sender);
|
||||||
else
|
else
|
||||||
log.trace("Not broadcasting data as we had it already in our map.");
|
log.trace("Not broadcasting data as we had it already in our map.");
|
||||||
|
|
||||||
hashMapChangedListeners.stream().forEach(e -> e.onAdded(protectedData));
|
hashMapChangedListeners.stream().forEach(e -> e.onAdded(protectedStorageEntry));
|
||||||
} else {
|
} else {
|
||||||
log.trace("add failed");
|
log.trace("add failed");
|
||||||
}
|
}
|
||||||
|
@ -217,27 +220,26 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
int sequenceNumber = refreshTTLMessage.sequenceNumber;
|
int sequenceNumber = refreshTTLMessage.sequenceNumber;
|
||||||
|
|
||||||
if (map.containsKey(hashOfPayload)) {
|
if (map.containsKey(hashOfPayload)) {
|
||||||
ProtectedData storedData = map.get(hashOfPayload);
|
ProtectedStorageEntry storedData = map.get(hashOfPayload);
|
||||||
|
|
||||||
if (storedData.expirablePayload instanceof StoragePayload) {
|
if (storedData.getStoragePayload() instanceof StoragePayload) {
|
||||||
if (sequenceNumberMap.containsKey(hashOfPayload) && sequenceNumberMap.get(hashOfPayload).sequenceNr == sequenceNumber) {
|
if (sequenceNumberMap.containsKey(hashOfPayload) && sequenceNumberMap.get(hashOfPayload).sequenceNr == sequenceNumber) {
|
||||||
log.trace("We got that message with that seq nr already from another peer. We ignore that message.");
|
log.trace("We got that message with that seq nr already from another peer. We ignore that message.");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
PublicKey ownerPubKey = ((StoragePayload) storedData.expirablePayload).getOwnerPubKey();
|
PublicKey ownerPubKey = ((StoragePayload) storedData.getStoragePayload()).getOwnerPubKey();
|
||||||
boolean result = checkSignature(ownerPubKey, hashOfDataAndSeqNr, signature) &&
|
boolean result = checkSignature(ownerPubKey, hashOfDataAndSeqNr, signature) &&
|
||||||
isSequenceNrValid(sequenceNumber, hashOfPayload) &&
|
isSequenceNrValid(sequenceNumber, hashOfPayload) &&
|
||||||
checkIfStoredDataPubKeyMatchesNewDataPubKey(ownerPubKey, hashOfPayload);
|
checkIfStoredDataPubKeyMatchesNewDataPubKey(ownerPubKey, hashOfPayload);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
log.info("refreshDate called for storedData:\n\t" + StringUtils.abbreviate(storedData.toString(), 100));
|
log.info("refreshDate called for storedData:\n\t" + StringUtils.abbreviate(storedData.toString(), 100));
|
||||||
storedData.refreshDate();
|
storedData.updateTimeStamp();
|
||||||
storedData.updateSequenceNumber(sequenceNumber);
|
storedData.updateSequenceNumber(sequenceNumber);
|
||||||
storedData.updateSignature(signature);
|
storedData.updateSignature(signature);
|
||||||
|
|
||||||
sequenceNumberMap.put(hashOfPayload, new MapValue(sequenceNumber, System.currentTimeMillis()));
|
sequenceNumberMap.put(hashOfPayload, new MapValue(sequenceNumber, System.currentTimeMillis()));
|
||||||
storage.queueUpForSave(sequenceNumberMap, 100);
|
storage.queueUpForSave(sequenceNumberMap, 100);
|
||||||
log.error("sequenceNumberMap queueUpForSave sequenceNumber " + sequenceNumber);
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n");
|
StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n");
|
||||||
sb.append("Data set after refreshTTL (truncated)");
|
sb.append("Data set after refreshTTL (truncated)");
|
||||||
|
@ -262,24 +264,25 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean remove(ProtectedData protectedData, @Nullable NodeAddress sender) {
|
public boolean remove(ProtectedStorageEntry protectedStorageEntry, @Nullable NodeAddress sender) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
ByteArray hashOfPayload = getHashAsByteArray(protectedData.expirablePayload);
|
ByteArray hashOfPayload = getHashAsByteArray(protectedStorageEntry.getStoragePayload());
|
||||||
boolean containsKey = map.containsKey(hashOfPayload);
|
boolean containsKey = map.containsKey(hashOfPayload);
|
||||||
if (!containsKey) log.debug("Remove data ignored as we don't have an entry for that data.");
|
if (!containsKey)
|
||||||
|
log.debug("Remove data ignored as we don't have an entry for that data.");
|
||||||
boolean result = containsKey
|
boolean result = containsKey
|
||||||
&& checkPublicKeys(protectedData, false)
|
&& checkPublicKeys(protectedStorageEntry, false)
|
||||||
&& isSequenceNrValid(protectedData.sequenceNumber, hashOfPayload)
|
&& isSequenceNrValid(protectedStorageEntry.sequenceNumber, hashOfPayload)
|
||||||
&& checkSignature(protectedData)
|
&& checkSignature(protectedStorageEntry)
|
||||||
&& checkIfStoredDataPubKeyMatchesNewDataPubKey(protectedData.ownerPubKey, hashOfPayload);
|
&& checkIfStoredDataPubKeyMatchesNewDataPubKey(protectedStorageEntry.ownerPubKey, hashOfPayload);
|
||||||
|
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
doRemoveProtectedExpirableData(protectedData, hashOfPayload);
|
doRemoveProtectedExpirableData(protectedStorageEntry, hashOfPayload);
|
||||||
|
|
||||||
broadcast(new RemoveDataMessage(protectedData), sender);
|
broadcast(new RemoveDataMessage(protectedStorageEntry), sender);
|
||||||
|
|
||||||
sequenceNumberMap.put(hashOfPayload, new MapValue(protectedData.sequenceNumber, System.currentTimeMillis()));
|
sequenceNumberMap.put(hashOfPayload, new MapValue(protectedStorageEntry.sequenceNumber, System.currentTimeMillis()));
|
||||||
storage.queueUpForSave(sequenceNumberMap, 100);
|
storage.queueUpForSave(sequenceNumberMap, 100);
|
||||||
} else {
|
} else {
|
||||||
log.debug("remove failed");
|
log.debug("remove failed");
|
||||||
|
@ -287,24 +290,25 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeMailboxData(ProtectedMailboxData protectedMailboxData, @Nullable NodeAddress sender) {
|
public boolean removeMailboxData(ProtectedMailboxStorageEntry protectedMailboxStorageEntry, @Nullable NodeAddress sender) {
|
||||||
Log.traceCall();
|
Log.traceCall();
|
||||||
ByteArray hashOfData = getHashAsByteArray(protectedMailboxData.expirablePayload);
|
ByteArray hashOfData = getHashAsByteArray(protectedMailboxStorageEntry.getStoragePayload());
|
||||||
boolean containsKey = map.containsKey(hashOfData);
|
boolean containsKey = map.containsKey(hashOfData);
|
||||||
if (!containsKey) log.debug("Remove data ignored as we don't have an entry for that data.");
|
if (!containsKey)
|
||||||
|
log.debug("Remove data ignored as we don't have an entry for that data.");
|
||||||
boolean result = containsKey
|
boolean result = containsKey
|
||||||
&& checkPublicKeys(protectedMailboxData, false)
|
&& checkPublicKeys(protectedMailboxStorageEntry, false)
|
||||||
&& isSequenceNrValid(protectedMailboxData.sequenceNumber, hashOfData)
|
&& isSequenceNrValid(protectedMailboxStorageEntry.sequenceNumber, hashOfData)
|
||||||
&& protectedMailboxData.receiversPubKey.equals(protectedMailboxData.ownerPubKey) // at remove both keys are the same (only receiver is able to remove data)
|
&& protectedMailboxStorageEntry.receiversPubKey.equals(protectedMailboxStorageEntry.receiversPubKey) // at remove both keys are the same (only receiver is able to remove data)
|
||||||
&& checkSignature(protectedMailboxData)
|
&& checkSignature(protectedMailboxStorageEntry)
|
||||||
&& checkIfStoredMailboxDataMatchesNewMailboxData(protectedMailboxData.receiversPubKey, hashOfData);
|
&& checkIfStoredMailboxDataMatchesNewMailboxData(protectedMailboxStorageEntry.receiversPubKey, hashOfData);
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
doRemoveProtectedExpirableData(protectedMailboxData, hashOfData);
|
doRemoveProtectedExpirableData(protectedMailboxStorageEntry, hashOfData);
|
||||||
|
|
||||||
broadcast(new RemoveMailboxDataMessage(protectedMailboxData), sender);
|
broadcast(new RemoveMailboxDataMessage(protectedMailboxStorageEntry), sender);
|
||||||
|
|
||||||
sequenceNumberMap.put(hashOfData, new MapValue(protectedMailboxData.sequenceNumber, System.currentTimeMillis()));
|
sequenceNumberMap.put(hashOfData, new MapValue(protectedMailboxStorageEntry.sequenceNumber, System.currentTimeMillis()));
|
||||||
storage.queueUpForSave(sequenceNumberMap, 100);
|
storage.queueUpForSave(sequenceNumberMap, 100);
|
||||||
} else {
|
} else {
|
||||||
log.debug("removeMailboxData failed");
|
log.debug("removeMailboxData failed");
|
||||||
|
@ -313,55 +317,51 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Map<ByteArray, ProtectedData> getMap() {
|
public Map<ByteArray, ProtectedStorageEntry> getMap() {
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtectedData getProtectedData(ExpirablePayload payload, KeyPair ownerStoragePubKey)
|
public ProtectedStorageEntry getProtectedData(StoragePayload storagePayload, KeyPair ownerStoragePubKey)
|
||||||
throws CryptoException {
|
throws CryptoException {
|
||||||
ByteArray hashOfData = getHashAsByteArray(payload);
|
ByteArray hashOfData = getHashAsByteArray(storagePayload);
|
||||||
int sequenceNumber;
|
int sequenceNumber;
|
||||||
if (sequenceNumberMap.containsKey(hashOfData))
|
if (sequenceNumberMap.containsKey(hashOfData))
|
||||||
sequenceNumber = sequenceNumberMap.get(hashOfData).sequenceNr + 1;
|
sequenceNumber = sequenceNumberMap.get(hashOfData).sequenceNr + 1;
|
||||||
else
|
else
|
||||||
sequenceNumber = 0;
|
sequenceNumber = 0;
|
||||||
|
|
||||||
log.error("getProtectedData sequenceNumber " + sequenceNumber);
|
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(storagePayload, sequenceNumber));
|
||||||
|
|
||||||
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(payload, sequenceNumber));
|
|
||||||
byte[] signature = Sig.sign(ownerStoragePubKey.getPrivate(), hashOfDataAndSeqNr);
|
byte[] signature = Sig.sign(ownerStoragePubKey.getPrivate(), hashOfDataAndSeqNr);
|
||||||
return new ProtectedData(payload, payload.getTTL(), ownerStoragePubKey.getPublic(), sequenceNumber, signature);
|
return new ProtectedStorageEntry(storagePayload, ownerStoragePubKey.getPublic(), sequenceNumber, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RefreshTTLMessage getRefreshTTLMessage(ExpirablePayload payload, KeyPair ownerStoragePubKey)
|
public RefreshTTLMessage getRefreshTTLMessage(StoragePayload storagePayload, KeyPair ownerStoragePubKey)
|
||||||
throws CryptoException {
|
throws CryptoException {
|
||||||
ByteArray hashOfPayload = getHashAsByteArray(payload);
|
ByteArray hashOfPayload = getHashAsByteArray(storagePayload);
|
||||||
int sequenceNumber;
|
int sequenceNumber;
|
||||||
if (sequenceNumberMap.containsKey(hashOfPayload))
|
if (sequenceNumberMap.containsKey(hashOfPayload))
|
||||||
sequenceNumber = sequenceNumberMap.get(hashOfPayload).sequenceNr + 1;
|
sequenceNumber = sequenceNumberMap.get(hashOfPayload).sequenceNr + 1;
|
||||||
else
|
else
|
||||||
sequenceNumber = 0;
|
sequenceNumber = 0;
|
||||||
|
|
||||||
log.error("getRefreshTTLMessage sequenceNumber " + sequenceNumber);
|
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(storagePayload, sequenceNumber));
|
||||||
|
|
||||||
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(payload, sequenceNumber));
|
|
||||||
byte[] signature = Sig.sign(ownerStoragePubKey.getPrivate(), hashOfDataAndSeqNr);
|
byte[] signature = Sig.sign(ownerStoragePubKey.getPrivate(), hashOfDataAndSeqNr);
|
||||||
return new RefreshTTLMessage(hashOfDataAndSeqNr, signature, hashOfPayload.bytes, sequenceNumber);
|
return new RefreshTTLMessage(hashOfDataAndSeqNr, signature, hashOfPayload.bytes, sequenceNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProtectedMailboxData getMailboxDataWithSignedSeqNr(MailboxPayload expirableMailboxPayload,
|
public ProtectedMailboxStorageEntry getMailboxDataWithSignedSeqNr(MailboxStoragePayload expirableMailboxStoragePayload,
|
||||||
KeyPair storageSignaturePubKey, PublicKey receiversPublicKey)
|
KeyPair storageSignaturePubKey, PublicKey receiversPublicKey)
|
||||||
throws CryptoException {
|
throws CryptoException {
|
||||||
ByteArray hashOfData = getHashAsByteArray(expirableMailboxPayload);
|
ByteArray hashOfData = getHashAsByteArray(expirableMailboxStoragePayload);
|
||||||
int sequenceNumber;
|
int sequenceNumber;
|
||||||
if (sequenceNumberMap.containsKey(hashOfData))
|
if (sequenceNumberMap.containsKey(hashOfData))
|
||||||
sequenceNumber = sequenceNumberMap.get(hashOfData).sequenceNr + 1;
|
sequenceNumber = sequenceNumberMap.get(hashOfData).sequenceNr + 1;
|
||||||
else
|
else
|
||||||
sequenceNumber = 0;
|
sequenceNumber = 0;
|
||||||
|
|
||||||
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(expirableMailboxPayload, sequenceNumber));
|
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(expirableMailboxStoragePayload, sequenceNumber));
|
||||||
byte[] signature = Sig.sign(storageSignaturePubKey.getPrivate(), hashOfDataAndSeqNr);
|
byte[] signature = Sig.sign(storageSignaturePubKey.getPrivate(), hashOfDataAndSeqNr);
|
||||||
return new ProtectedMailboxData(expirableMailboxPayload, expirableMailboxPayload.getTTL(),
|
return new ProtectedMailboxStorageEntry(expirableMailboxStoragePayload,
|
||||||
storageSignaturePubKey.getPublic(), sequenceNumber, signature, receiversPublicKey);
|
storageSignaturePubKey.getPublic(), sequenceNumber, signature, receiversPublicKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,10 +374,10 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
// Private
|
// Private
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void doRemoveProtectedExpirableData(ProtectedData protectedData, ByteArray hashOfPayload) {
|
private void doRemoveProtectedExpirableData(ProtectedStorageEntry protectedStorageEntry, ByteArray hashOfPayload) {
|
||||||
map.remove(hashOfPayload);
|
map.remove(hashOfPayload);
|
||||||
log.trace("Data removed from our map. We broadcast the message to our peers.");
|
log.trace("Data removed from our map. We broadcast the message to our peers.");
|
||||||
hashMapChangedListeners.stream().forEach(e -> e.onRemoved(protectedData));
|
hashMapChangedListeners.stream().forEach(e -> e.onRemoved(protectedStorageEntry));
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n" +
|
StringBuilder sb = new StringBuilder("\n\n------------------------------------------------------------\n" +
|
||||||
"Data set after removeProtectedExpirableData: (truncated)");
|
"Data set after removeProtectedExpirableData: (truncated)");
|
||||||
|
@ -416,21 +416,21 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkSignature(ProtectedData data) {
|
private boolean checkSignature(ProtectedStorageEntry protectedStorageEntry) {
|
||||||
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(data.expirablePayload, data.sequenceNumber));
|
byte[] hashOfDataAndSeqNr = Hash.getHash(new DataAndSeqNrPair(protectedStorageEntry.getStoragePayload(), protectedStorageEntry.sequenceNumber));
|
||||||
return checkSignature(data.ownerPubKey, hashOfDataAndSeqNr, data.signature);
|
return checkSignature(protectedStorageEntry.ownerPubKey, hashOfDataAndSeqNr, protectedStorageEntry.signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkPublicKeys(ProtectedData data, boolean isAddOperation) {
|
private boolean checkPublicKeys(ProtectedStorageEntry protectedStorageEntry, boolean isAddOperation) {
|
||||||
boolean result = false;
|
boolean result;
|
||||||
if (data.expirablePayload instanceof MailboxPayload) {
|
if (protectedStorageEntry.getStoragePayload() instanceof MailboxStoragePayload) {
|
||||||
MailboxPayload expirableMailboxPayload = (MailboxPayload) data.expirablePayload;
|
MailboxStoragePayload expirableMailboxStoragePayload = (MailboxStoragePayload) protectedStorageEntry.getStoragePayload();
|
||||||
if (isAddOperation)
|
if (isAddOperation)
|
||||||
result = expirableMailboxPayload.senderPubKeyForAddOperation.equals(data.ownerPubKey);
|
result = expirableMailboxStoragePayload.senderPubKeyForAddOperation.equals(protectedStorageEntry.ownerPubKey);
|
||||||
else
|
else
|
||||||
result = expirableMailboxPayload.receiverPubKeyForRemoveOperation.equals(data.ownerPubKey);
|
result = expirableMailboxStoragePayload.receiverPubKeyForRemoveOperation.equals(protectedStorageEntry.ownerPubKey);
|
||||||
} else if (data.expirablePayload instanceof StoragePayload) {
|
} else {
|
||||||
result = ((StoragePayload) data.expirablePayload).getOwnerPubKey().equals(data.ownerPubKey);
|
result = protectedStorageEntry.getStoragePayload().getOwnerPubKey().equals(protectedStorageEntry.ownerPubKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
|
@ -440,7 +440,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
|
|
||||||
private boolean checkIfStoredDataPubKeyMatchesNewDataPubKey(PublicKey ownerPubKey, ByteArray hashOfData) {
|
private boolean checkIfStoredDataPubKeyMatchesNewDataPubKey(PublicKey ownerPubKey, ByteArray hashOfData) {
|
||||||
if (map.containsKey(hashOfData)) {
|
if (map.containsKey(hashOfData)) {
|
||||||
ProtectedData storedData = map.get(hashOfData);
|
ProtectedStorageEntry storedData = map.get(hashOfData);
|
||||||
boolean result = storedData.ownerPubKey.equals(ownerPubKey);
|
boolean result = storedData.ownerPubKey.equals(ownerPubKey);
|
||||||
if (!result)
|
if (!result)
|
||||||
log.error("New data entry does not match our stored data. Consider it might be an attempt of fraud");
|
log.error("New data entry does not match our stored data. Consider it might be an attempt of fraud");
|
||||||
|
@ -452,12 +452,12 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkIfStoredMailboxDataMatchesNewMailboxData(PublicKey receiversPubKey, ByteArray hashOfData) {
|
private boolean checkIfStoredMailboxDataMatchesNewMailboxData(PublicKey receiversPubKey, ByteArray hashOfData) {
|
||||||
ProtectedData storedData = map.get(hashOfData);
|
ProtectedStorageEntry storedData = map.get(hashOfData);
|
||||||
if (storedData instanceof ProtectedMailboxData) {
|
if (storedData instanceof ProtectedMailboxStorageEntry) {
|
||||||
ProtectedMailboxData storedMailboxData = (ProtectedMailboxData) storedData;
|
ProtectedMailboxStorageEntry storedMailboxData = (ProtectedMailboxStorageEntry) storedData;
|
||||||
// publicKey is not the same (stored: sender, new: receiver)
|
// publicKey is not the same (stored: sender, new: receiver)
|
||||||
boolean result = storedMailboxData.receiversPubKey.equals(receiversPubKey)
|
boolean result = storedMailboxData.receiversPubKey.equals(receiversPubKey)
|
||||||
&& getHashAsByteArray(storedMailboxData.expirablePayload).equals(hashOfData);
|
&& getHashAsByteArray(storedMailboxData.getStoragePayload()).equals(hashOfData);
|
||||||
if (!result)
|
if (!result)
|
||||||
log.error("New data entry does not match our stored data. Consider it might be an attempt of fraud");
|
log.error("New data entry does not match our stored data. Consider it might be an attempt of fraud");
|
||||||
|
|
||||||
|
@ -468,7 +468,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void broadcast(DataBroadcastMessage message, @Nullable NodeAddress sender) {
|
private void broadcast(BroadcastMessage message, @Nullable NodeAddress sender) {
|
||||||
broadcaster.broadcast(message, sender);
|
broadcaster.broadcast(message, sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
package io.bitsquare.p2p.storage.data;
|
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import io.bitsquare.common.wire.Payload;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
public class ProtectedData implements Payload {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(ProtectedData.class);
|
|
||||||
|
|
||||||
public final ExpirablePayload expirablePayload;
|
|
||||||
|
|
||||||
//TODO check if that field make sense as it is in expirableMessage.getTTL()
|
|
||||||
transient public long ttl;
|
|
||||||
|
|
||||||
public final PublicKey ownerPubKey;
|
|
||||||
public int sequenceNumber;
|
|
||||||
public byte[] signature;
|
|
||||||
@VisibleForTesting
|
|
||||||
transient public Date date;
|
|
||||||
|
|
||||||
public ProtectedData(ExpirablePayload expirablePayload, long ttl, PublicKey ownerPubKey, int sequenceNumber, byte[] signature) {
|
|
||||||
this.expirablePayload = expirablePayload;
|
|
||||||
this.ttl = ttl;
|
|
||||||
this.ownerPubKey = ownerPubKey;
|
|
||||||
this.sequenceNumber = sequenceNumber;
|
|
||||||
this.signature = signature;
|
|
||||||
this.date = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
try {
|
|
||||||
in.defaultReadObject();
|
|
||||||
ttl = expirablePayload.getTTL();
|
|
||||||
date = new Date();
|
|
||||||
|
|
||||||
} catch (Throwable t) {
|
|
||||||
log.error("Exception at readObject: " + t.getMessage());
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshDate() {
|
|
||||||
date = new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateSequenceNumber(int sequenceNumber) {
|
|
||||||
this.sequenceNumber = sequenceNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateSignature(byte[] signature) {
|
|
||||||
this.signature = signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isExpired() {
|
|
||||||
return (new Date().getTime() - date.getTime()) > ttl;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ProtectedData{" +
|
|
||||||
"expirablePayload=" + expirablePayload +
|
|
||||||
", ttl=" + ttl +
|
|
||||||
", date=" + date +
|
|
||||||
", sequenceNumber=" + sequenceNumber +
|
|
||||||
", ownerPubKey.hashCode()=" + ownerPubKey.hashCode() +
|
|
||||||
", signature.hashCode()=" + Arrays.toString(signature).hashCode() +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
package io.bitsquare.p2p.storage.data;
|
|
||||||
|
|
||||||
import io.bitsquare.p2p.storage.P2PDataStorage;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.PublicKey;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class ProtectedMailboxData extends ProtectedData {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(P2PDataStorage.class);
|
|
||||||
|
|
||||||
public final PublicKey receiversPubKey;
|
|
||||||
|
|
||||||
public ProtectedMailboxData(MailboxPayload data, long ttl, PublicKey ownerStoragePubKey, int sequenceNumber, byte[] signature, PublicKey receiversPubKey) {
|
|
||||||
super(data, ttl, ownerStoragePubKey, sequenceNumber, signature);
|
|
||||||
|
|
||||||
this.receiversPubKey = receiversPubKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
try {
|
|
||||||
in.defaultReadObject();
|
|
||||||
ttl = expirablePayload.getTTL();
|
|
||||||
|
|
||||||
// in case the reported creation date is in the future
|
|
||||||
// we reset the date to the current time
|
|
||||||
if (date.getTime() > new Date().getTime()) {
|
|
||||||
if (date.getTime() > new Date().getTime() + TimeUnit.MINUTES.toMillis(1))
|
|
||||||
log.warn("Date of object is more then a minute in future. " +
|
|
||||||
"That might be ok as peers clocks are not synced but could be also a spam attack.\n" +
|
|
||||||
"date=" + date + " / now=" + new Date());
|
|
||||||
else
|
|
||||||
log.debug("Date of object is slightly future. " +
|
|
||||||
"That is probably because peers clocks are not synced.\n" +
|
|
||||||
"date=" + date + " / now=" + new Date());
|
|
||||||
date = new Date();
|
|
||||||
}
|
|
||||||
date = new Date();
|
|
||||||
|
|
||||||
} catch (Throwable t) {
|
|
||||||
log.error("Exception at readObject: " + t.getMessage());
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isExpired() {
|
|
||||||
return (new Date().getTime() - date.getTime()) > ttl;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "ProtectedMailboxData{" +
|
|
||||||
"receiversPubKey.hashCode()=" + receiversPubKey.hashCode() +
|
|
||||||
"} " + super.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +1,16 @@
|
||||||
package io.bitsquare.p2p.storage.messages;
|
package io.bitsquare.p2p.storage.messages;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
|
|
||||||
public final class AddDataMessage extends DataBroadcastMessage {
|
public final class AddDataMessage extends BroadcastMessage {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
|
||||||
public final ProtectedData data;
|
public final ProtectedStorageEntry protectedStorageEntry;
|
||||||
|
|
||||||
public AddDataMessage(ProtectedData data) {
|
public AddDataMessage(ProtectedStorageEntry protectedStorageEntry) {
|
||||||
this.data = data;
|
this.protectedStorageEntry = protectedStorageEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,18 +20,18 @@ public final class AddDataMessage extends DataBroadcastMessage {
|
||||||
|
|
||||||
AddDataMessage that = (AddDataMessage) o;
|
AddDataMessage that = (AddDataMessage) o;
|
||||||
|
|
||||||
return !(data != null ? !data.equals(that.data) : that.data != null);
|
return !(protectedStorageEntry != null ? !protectedStorageEntry.equals(that.protectedStorageEntry) : that.protectedStorageEntry != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return data != null ? data.hashCode() : 0;
|
return protectedStorageEntry != null ? protectedStorageEntry.hashCode() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "AddDataMessage{" +
|
return "AddDataMessage{" +
|
||||||
"data=" + data +
|
"protectedStorageEntry=" + protectedStorageEntry +
|
||||||
"} " + super.toString();
|
"} " + super.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package io.bitsquare.p2p.storage.messages;
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
|
|
||||||
public abstract class DataBroadcastMessage implements Message {
|
public abstract class BroadcastMessage implements Message {
|
||||||
private final int messageVersion = Version.getP2PMessageVersion();
|
private final int messageVersion = Version.getP2PMessageVersion();
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -4,7 +4,7 @@ import io.bitsquare.app.Version;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public final class RefreshTTLMessage extends DataBroadcastMessage {
|
public final class RefreshTTLMessage extends BroadcastMessage {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
package io.bitsquare.p2p.storage.messages;
|
package io.bitsquare.p2p.storage.messages;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
|
|
||||||
public final class RemoveDataMessage extends DataBroadcastMessage {
|
public final class RemoveDataMessage extends BroadcastMessage {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
|
||||||
public final ProtectedData data;
|
public final ProtectedStorageEntry protectedStorageEntry;
|
||||||
|
|
||||||
public RemoveDataMessage(ProtectedData data) {
|
public RemoveDataMessage(ProtectedStorageEntry protectedStorageEntry) {
|
||||||
this.data = data;
|
this.protectedStorageEntry = protectedStorageEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,19 +20,19 @@ public final class RemoveDataMessage extends DataBroadcastMessage {
|
||||||
|
|
||||||
RemoveDataMessage that = (RemoveDataMessage) o;
|
RemoveDataMessage that = (RemoveDataMessage) o;
|
||||||
|
|
||||||
return !(data != null ? !data.equals(that.data) : that.data != null);
|
return !(protectedStorageEntry != null ? !protectedStorageEntry.equals(that.protectedStorageEntry) : that.protectedStorageEntry != null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return data != null ? data.hashCode() : 0;
|
return protectedStorageEntry != null ? protectedStorageEntry.hashCode() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RemoveDataMessage{" +
|
return "RemoveDataMessage{" +
|
||||||
"data=" + data +
|
"protectedStorageEntry=" + protectedStorageEntry +
|
||||||
"} " + super.toString();
|
"} " + super.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
package io.bitsquare.p2p.storage.messages;
|
package io.bitsquare.p2p.storage.messages;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedMailboxData;
|
import io.bitsquare.p2p.storage.storageentry.ProtectedMailboxStorageEntry;
|
||||||
|
|
||||||
public final class RemoveMailboxDataMessage extends DataBroadcastMessage {
|
public final class RemoveMailboxDataMessage extends BroadcastMessage {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
|
||||||
public final ProtectedMailboxData data;
|
public final ProtectedMailboxStorageEntry protectedMailboxStorageEntry;
|
||||||
|
|
||||||
public RemoveMailboxDataMessage(ProtectedMailboxData data) {
|
public RemoveMailboxDataMessage(ProtectedMailboxStorageEntry protectedMailboxStorageEntry) {
|
||||||
this.data = data;
|
this.protectedMailboxStorageEntry = protectedMailboxStorageEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,19 +20,18 @@ public final class RemoveMailboxDataMessage extends DataBroadcastMessage {
|
||||||
|
|
||||||
RemoveMailboxDataMessage that = (RemoveMailboxDataMessage) o;
|
RemoveMailboxDataMessage that = (RemoveMailboxDataMessage) o;
|
||||||
|
|
||||||
return !(data != null ? !data.equals(that.data) : that.data != null);
|
return !(protectedMailboxStorageEntry != null ? !protectedMailboxStorageEntry.equals(that.protectedMailboxStorageEntry) : that.protectedMailboxStorageEntry != null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return data != null ? data.hashCode() : 0;
|
return protectedMailboxStorageEntry != null ? protectedMailboxStorageEntry.hashCode() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "RemoveMailboxDataMessage{" +
|
return "RemoveMailboxDataMessage{" +
|
||||||
"data=" + data +
|
"data=" + protectedMailboxStorageEntry +
|
||||||
"} " + super.toString();
|
"} " + super.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.p2p.storage.data;
|
package io.bitsquare.p2p.storage.payload;
|
||||||
|
|
||||||
import io.bitsquare.common.wire.Payload;
|
import io.bitsquare.common.wire.Payload;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import io.bitsquare.common.wire.Payload;
|
||||||
* Implementations:
|
* Implementations:
|
||||||
*
|
*
|
||||||
* @see StoragePayload
|
* @see StoragePayload
|
||||||
* @see MailboxPayload
|
* @see MailboxStoragePayload
|
||||||
*/
|
*/
|
||||||
public interface ExpirablePayload extends Payload {
|
public interface ExpirablePayload extends Payload {
|
||||||
/**
|
/**
|
|
@ -1,10 +1,17 @@
|
||||||
package io.bitsquare.p2p.storage.data;
|
package io.bitsquare.p2p.storage.payload;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.crypto.PrefixedSealedAndSignedMessage;
|
import io.bitsquare.common.crypto.Sig;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
|
import io.bitsquare.p2p.messaging.PrefixedSealedAndSignedMessage;
|
||||||
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.KeyFactory;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,9 +22,10 @@ import java.util.concurrent.TimeUnit;
|
||||||
* <p>
|
* <p>
|
||||||
* Typical payloads are trade or dispute messages to be stored when the peer is offline.
|
* Typical payloads are trade or dispute messages to be stored when the peer is offline.
|
||||||
*/
|
*/
|
||||||
public final class MailboxPayload implements ExpirablePayload {
|
public final class MailboxStoragePayload implements StoragePayload {
|
||||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MailboxStoragePayload.class);
|
||||||
|
|
||||||
private static final long TTL = TimeUnit.DAYS.toMillis(10);
|
private static final long TTL = TimeUnit.DAYS.toMillis(10);
|
||||||
|
|
||||||
|
@ -30,24 +38,40 @@ public final class MailboxPayload implements ExpirablePayload {
|
||||||
* Used for check if the add operation is permitted.
|
* Used for check if the add operation is permitted.
|
||||||
* senderStoragePublicKey has to be equal to the ownerPubKey of the ProtectedData
|
* senderStoragePublicKey has to be equal to the ownerPubKey of the ProtectedData
|
||||||
*
|
*
|
||||||
* @see ProtectedData#ownerPubKey
|
* @see ProtectedStorageEntry#ownerPubKey
|
||||||
* @see io.bitsquare.p2p.storage.P2PDataStorage#add(ProtectedData, NodeAddress)
|
* @see io.bitsquare.p2p.storage.P2PDataStorage#add(ProtectedStorageEntry, NodeAddress)
|
||||||
*/
|
*/
|
||||||
public final PublicKey senderPubKeyForAddOperation;
|
public transient PublicKey senderPubKeyForAddOperation;
|
||||||
|
private final byte[] senderPubKeyForAddOperationBytes;
|
||||||
/**
|
/**
|
||||||
* Used for check if the remove operation is permitted.
|
* Used for check if the remove operation is permitted.
|
||||||
* senderStoragePublicKey has to be equal to the ownerPubKey of the ProtectedData
|
* senderStoragePublicKey has to be equal to the ownerPubKey of the ProtectedData
|
||||||
*
|
*
|
||||||
* @see ProtectedData#ownerPubKey
|
* @see ProtectedStorageEntry#ownerPubKey
|
||||||
* @see io.bitsquare.p2p.storage.P2PDataStorage#remove(ProtectedData, NodeAddress)
|
* @see io.bitsquare.p2p.storage.P2PDataStorage#remove(ProtectedStorageEntry, NodeAddress)
|
||||||
*/
|
*/
|
||||||
public final PublicKey receiverPubKeyForRemoveOperation;
|
public transient PublicKey receiverPubKeyForRemoveOperation;
|
||||||
|
private final byte[] receiverPubKeyForRemoveOperationBytes;
|
||||||
|
|
||||||
public MailboxPayload(PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage, PublicKey senderPubKeyForAddOperation, PublicKey receiverPubKeyForRemoveOperation) {
|
public MailboxStoragePayload(PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage, PublicKey senderPubKeyForAddOperation, PublicKey receiverPubKeyForRemoveOperation) {
|
||||||
this.prefixedSealedAndSignedMessage = prefixedSealedAndSignedMessage;
|
this.prefixedSealedAndSignedMessage = prefixedSealedAndSignedMessage;
|
||||||
|
|
||||||
this.senderPubKeyForAddOperation = senderPubKeyForAddOperation;
|
this.senderPubKeyForAddOperation = senderPubKeyForAddOperation;
|
||||||
|
this.senderPubKeyForAddOperationBytes = new X509EncodedKeySpec(this.senderPubKeyForAddOperation.getEncoded()).getEncoded();
|
||||||
|
|
||||||
this.receiverPubKeyForRemoveOperation = receiverPubKeyForRemoveOperation;
|
this.receiverPubKeyForRemoveOperation = receiverPubKeyForRemoveOperation;
|
||||||
|
this.receiverPubKeyForRemoveOperationBytes = new X509EncodedKeySpec(this.receiverPubKeyForRemoveOperation.getEncoded()).getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
try {
|
||||||
|
in.defaultReadObject();
|
||||||
|
senderPubKeyForAddOperation = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(senderPubKeyForAddOperationBytes));
|
||||||
|
receiverPubKeyForRemoveOperation = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(receiverPubKeyForRemoveOperationBytes));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.error("Exception at readObject: " + t.getMessage());
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,12 +79,17 @@ public final class MailboxPayload implements ExpirablePayload {
|
||||||
return TTL;
|
return TTL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PublicKey getOwnerPubKey() {
|
||||||
|
return receiverPubKeyForRemoveOperation;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
if (!(o instanceof MailboxPayload)) return false;
|
if (!(o instanceof MailboxStoragePayload)) return false;
|
||||||
|
|
||||||
MailboxPayload that = (MailboxPayload) o;
|
MailboxStoragePayload that = (MailboxStoragePayload) o;
|
||||||
|
|
||||||
return !(prefixedSealedAndSignedMessage != null ? !prefixedSealedAndSignedMessage.equals(that.prefixedSealedAndSignedMessage) : that.prefixedSealedAndSignedMessage != null);
|
return !(prefixedSealedAndSignedMessage != null ? !prefixedSealedAndSignedMessage.equals(that.prefixedSealedAndSignedMessage) : that.prefixedSealedAndSignedMessage != null);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package io.bitsquare.p2p.storage.data;
|
package io.bitsquare.p2p.storage.payload;
|
||||||
|
|
||||||
import io.bitsquare.common.wire.Payload;
|
import io.bitsquare.common.wire.Payload;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
|
@ -6,8 +6,8 @@ import io.bitsquare.p2p.NodeAddress;
|
||||||
/**
|
/**
|
||||||
* Used for messages which require that the data owner is online.
|
* Used for messages which require that the data owner is online.
|
||||||
* <p>
|
* <p>
|
||||||
* This is used for the offers to avoid dead offers in case the offerer is in sleep/hibernate mode or the app has
|
* This is used for the offers to avoid dead offers in case the offerer is in standby mode or the app has
|
||||||
* terminated without sending the remove message (e.g. in case of a crash).
|
* terminated without sending the remove message (e.g. network connection lost or in case of a crash).
|
||||||
*/
|
*/
|
||||||
public interface RequiresOwnerIsOnlinePayload extends Payload {
|
public interface RequiresOwnerIsOnlinePayload extends Payload {
|
||||||
/**
|
/**
|
|
@ -1,6 +1,7 @@
|
||||||
package io.bitsquare.p2p.storage.data;
|
package io.bitsquare.p2p.storage.payload;
|
||||||
|
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
|
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
|
@ -19,9 +20,9 @@ public interface StoragePayload extends ExpirablePayload {
|
||||||
* OwnerPubKey has to be equal to the ownerPubKey of the ProtectedData
|
* OwnerPubKey has to be equal to the ownerPubKey of the ProtectedData
|
||||||
*
|
*
|
||||||
* @return The public key of the data owner.
|
* @return The public key of the data owner.
|
||||||
* @see ProtectedData#ownerPubKey
|
* @see ProtectedStorageEntry#ownerPubKey
|
||||||
* @see io.bitsquare.p2p.storage.P2PDataStorage#add(ProtectedData, NodeAddress)
|
* @see io.bitsquare.p2p.storage.P2PDataStorage#add(ProtectedStorageEntry, NodeAddress)
|
||||||
* @see io.bitsquare.p2p.storage.P2PDataStorage#remove(ProtectedData, NodeAddress)
|
* @see io.bitsquare.p2p.storage.P2PDataStorage#remove(ProtectedStorageEntry, NodeAddress)
|
||||||
*/
|
*/
|
||||||
PublicKey getOwnerPubKey();
|
PublicKey getOwnerPubKey();
|
||||||
}
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package io.bitsquare.p2p.storage.storageentry;
|
||||||
|
|
||||||
|
import io.bitsquare.app.Version;
|
||||||
|
import io.bitsquare.common.crypto.Sig;
|
||||||
|
import io.bitsquare.p2p.storage.P2PDataStorage;
|
||||||
|
import io.bitsquare.p2p.storage.payload.MailboxStoragePayload;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
|
||||||
|
public class ProtectedMailboxStorageEntry extends ProtectedStorageEntry {
|
||||||
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(P2PDataStorage.class);
|
||||||
|
|
||||||
|
public transient PublicKey receiversPubKey;
|
||||||
|
private final byte[] receiversPubKeyBytes;
|
||||||
|
|
||||||
|
public MailboxStoragePayload getMailboxStoragePayload() {
|
||||||
|
return (MailboxStoragePayload) storagePayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProtectedMailboxStorageEntry(MailboxStoragePayload mailboxStoragePayload, PublicKey ownerStoragePubKey, int sequenceNumber, byte[] signature, PublicKey receiversPubKey) {
|
||||||
|
super(mailboxStoragePayload, ownerStoragePubKey, sequenceNumber, signature);
|
||||||
|
|
||||||
|
this.receiversPubKey = receiversPubKey;
|
||||||
|
this.receiversPubKeyBytes = new X509EncodedKeySpec(this.receiversPubKey.getEncoded()).getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
try {
|
||||||
|
in.defaultReadObject();
|
||||||
|
receiversPubKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(receiversPubKeyBytes));
|
||||||
|
updateTimeStamp();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.error("Exception at readObject: " + t.getMessage());
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ProtectedMailboxData{" +
|
||||||
|
"receiversPubKey.hashCode()=" + receiversPubKey.hashCode() +
|
||||||
|
"} " + super.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package io.bitsquare.p2p.storage.storageentry;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import io.bitsquare.app.Version;
|
||||||
|
import io.bitsquare.common.crypto.Sig;
|
||||||
|
import io.bitsquare.common.wire.Payload;
|
||||||
|
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.KeyFactory;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class ProtectedStorageEntry implements Payload {
|
||||||
|
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||||
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ProtectedStorageEntry.class);
|
||||||
|
|
||||||
|
protected final StoragePayload storagePayload;
|
||||||
|
private final byte[] ownerPubKeyBytes;
|
||||||
|
public transient PublicKey ownerPubKey;
|
||||||
|
public int sequenceNumber;
|
||||||
|
public byte[] signature;
|
||||||
|
@VisibleForTesting
|
||||||
|
transient public long timeStamp;
|
||||||
|
|
||||||
|
public ProtectedStorageEntry(StoragePayload storagePayload, PublicKey ownerPubKey, int sequenceNumber, byte[] signature) {
|
||||||
|
this.storagePayload = storagePayload;
|
||||||
|
this.ownerPubKey = ownerPubKey;
|
||||||
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
this.signature = signature;
|
||||||
|
this.timeStamp = System.currentTimeMillis();
|
||||||
|
this.ownerPubKeyBytes = new X509EncodedKeySpec(this.ownerPubKey.getEncoded()).getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
try {
|
||||||
|
in.defaultReadObject();
|
||||||
|
ownerPubKey = KeyFactory.getInstance(Sig.KEY_ALGO, "BC").generatePublic(new X509EncodedKeySpec(ownerPubKeyBytes));
|
||||||
|
updateTimeStamp();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.error("Exception at readObject: " + t.getMessage());
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public StoragePayload getStoragePayload() {
|
||||||
|
return storagePayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTimeStamp() {
|
||||||
|
timeStamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateSequenceNumber(int sequenceNumber) {
|
||||||
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateSignature(byte[] signature) {
|
||||||
|
this.signature = signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpired() {
|
||||||
|
return (System.currentTimeMillis() - timeStamp) > storagePayload.getTTL();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ProtectedData{" +
|
||||||
|
"expirablePayload=" + storagePayload +
|
||||||
|
", timeStamp=" + timeStamp +
|
||||||
|
", sequenceNumber=" + sequenceNumber +
|
||||||
|
", ownerPubKey.hashCode()=" + ownerPubKey.hashCode() +
|
||||||
|
", signature.hashCode()=" + Arrays.toString(signature).hashCode() +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -22,8 +22,8 @@ import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.common.crypto.*;
|
import io.bitsquare.common.crypto.*;
|
||||||
import io.bitsquare.common.util.Utilities;
|
import io.bitsquare.common.util.Utilities;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey;
|
|
||||||
import io.bitsquare.p2p.messaging.MailboxMessage;
|
import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
|
import io.bitsquare.p2p.messaging.PrefixedSealedAndSignedMessage;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -39,6 +39,7 @@ import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
@ -84,9 +85,16 @@ public class EncryptionServiceTests {
|
||||||
final class TestMessage implements MailboxMessage {
|
final class TestMessage implements MailboxMessage {
|
||||||
public String data = "test";
|
public String data = "test";
|
||||||
private final int messageVersion = Version.getP2PMessageVersion();
|
private final int messageVersion = Version.getP2PMessageVersion();
|
||||||
|
private String uid;
|
||||||
|
|
||||||
public TestMessage(String data) {
|
public TestMessage(String data) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
uid = UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUID() {
|
||||||
|
return uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,382 +0,0 @@
|
||||||
package io.bitsquare.p2p;
|
|
||||||
|
|
||||||
import io.bitsquare.common.crypto.*;
|
|
||||||
import io.bitsquare.crypto.EncryptionService;
|
|
||||||
import io.bitsquare.crypto.PrefixedSealedAndSignedMessage;
|
|
||||||
import io.bitsquare.p2p.messaging.DecryptedMsgWithPubKey;
|
|
||||||
import io.bitsquare.p2p.messaging.MailboxMessage;
|
|
||||||
import io.bitsquare.p2p.messaging.SendMailboxMessageListener;
|
|
||||||
import io.bitsquare.p2p.mocks.MockMailboxPayload;
|
|
||||||
import io.bitsquare.p2p.network.LocalhostNetworkNode;
|
|
||||||
import io.bitsquare.p2p.peers.PeerManager;
|
|
||||||
import io.bitsquare.p2p.seed.SeedNode;
|
|
||||||
import io.bitsquare.p2p.storage.P2PDataStorage;
|
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
|
||||||
import io.bitsquare.p2p.storage.mocks.MockData;
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
|
||||||
import org.junit.*;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.*;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
// TorNode created. Took 6 sec.
|
|
||||||
// Hidden service created. Took 40-50 sec.
|
|
||||||
// Connection establishment takes about 4 sec.
|
|
||||||
|
|
||||||
// need to define seed node addresses first before using tor version
|
|
||||||
// Ignored for automated tests
|
|
||||||
|
|
||||||
//TODO P2P network tests are outdated
|
|
||||||
@Ignore
|
|
||||||
public class P2PServiceTest {
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(P2PServiceTest.class);
|
|
||||||
|
|
||||||
final boolean useLocalhost = true;
|
|
||||||
private Set<NodeAddress> seedNodes;
|
|
||||||
private int sleepTime;
|
|
||||||
private KeyRing keyRing1, keyRing2, keyRing3;
|
|
||||||
private EncryptionService encryptionService1, encryptionService2, encryptionService3;
|
|
||||||
private P2PService p2PService1, p2PService2, p2PService3;
|
|
||||||
private SeedNode seedNode1, seedNode2, seedNode3;
|
|
||||||
private File dir1, dir2, dir3;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup() throws InterruptedException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, CryptoException {
|
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
|
||||||
dir1 = File.createTempFile("temp_tests1", "");
|
|
||||||
dir1.delete();
|
|
||||||
dir1.mkdir();
|
|
||||||
dir2 = File.createTempFile("temp_tests2", "");
|
|
||||||
dir2.delete();
|
|
||||||
dir2.mkdir();
|
|
||||||
dir3 = File.createTempFile("temp_tests3", "");
|
|
||||||
dir3.delete();
|
|
||||||
dir3.mkdir();
|
|
||||||
|
|
||||||
LocalhostNetworkNode.setSimulateTorDelayTorNode(10);
|
|
||||||
LocalhostNetworkNode.setSimulateTorDelayHiddenService(100);
|
|
||||||
PeerManager.setMaxConnections(8);
|
|
||||||
|
|
||||||
keyRing1 = new KeyRing(new KeyStorage(dir1));
|
|
||||||
keyRing2 = new KeyRing(new KeyStorage(dir2));
|
|
||||||
keyRing3 = new KeyRing(new KeyStorage(dir3));
|
|
||||||
encryptionService1 = new EncryptionService(keyRing1);
|
|
||||||
encryptionService2 = new EncryptionService(keyRing2);
|
|
||||||
encryptionService3 = new EncryptionService(keyRing3);
|
|
||||||
|
|
||||||
seedNodes = new HashSet<>();
|
|
||||||
if (useLocalhost) {
|
|
||||||
seedNodes.add(new NodeAddress("localhost:8001"));
|
|
||||||
seedNodes.add(new NodeAddress("localhost:8002"));
|
|
||||||
seedNodes.add(new NodeAddress("localhost:8003"));
|
|
||||||
sleepTime = 100;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
seedNodes.add(new NodeAddress("3omjuxn7z73pxoee.onion:8001"));
|
|
||||||
seedNodes.add(new NodeAddress("j24fxqyghjetgpdx.onion:8002"));
|
|
||||||
seedNodes.add(new NodeAddress("45367tl6unwec6kw.onion:8003"));
|
|
||||||
sleepTime = 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
seedNode1 = TestUtils.getAndStartSeedNode(8001, useLocalhost, seedNodes);
|
|
||||||
p2PService1 = seedNode1.getSeedNodeP2PService();
|
|
||||||
p2PService2 = TestUtils.getAndAuthenticateP2PService(8002, encryptionService2, keyRing2, useLocalhost, seedNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() throws InterruptedException {
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
|
|
||||||
if (seedNode1 != null) {
|
|
||||||
CountDownLatch shutDownLatch = new CountDownLatch(1);
|
|
||||||
seedNode1.shutDown(() -> shutDownLatch.countDown());
|
|
||||||
shutDownLatch.await();
|
|
||||||
}
|
|
||||||
if (seedNode2 != null) {
|
|
||||||
CountDownLatch shutDownLatch = new CountDownLatch(1);
|
|
||||||
seedNode2.shutDown(() -> shutDownLatch.countDown());
|
|
||||||
shutDownLatch.await();
|
|
||||||
}
|
|
||||||
if (seedNode3 != null) {
|
|
||||||
CountDownLatch shutDownLatch = new CountDownLatch(1);
|
|
||||||
seedNode3.shutDown(() -> shutDownLatch.countDown());
|
|
||||||
shutDownLatch.await();
|
|
||||||
}
|
|
||||||
if (p2PService1 != null) {
|
|
||||||
CountDownLatch shutDownLatch = new CountDownLatch(1);
|
|
||||||
p2PService1.shutDown(() -> shutDownLatch.countDown());
|
|
||||||
shutDownLatch.await();
|
|
||||||
}
|
|
||||||
if (p2PService2 != null) {
|
|
||||||
CountDownLatch shutDownLatch = new CountDownLatch(1);
|
|
||||||
p2PService2.shutDown(() -> shutDownLatch.countDown());
|
|
||||||
shutDownLatch.await();
|
|
||||||
}
|
|
||||||
if (p2PService3 != null) {
|
|
||||||
CountDownLatch shutDownLatch = new CountDownLatch(1);
|
|
||||||
p2PService3.shutDown(() -> shutDownLatch.countDown());
|
|
||||||
shutDownLatch.await();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAdversaryAttacks() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
|
||||||
p2PService3 = TestUtils.getAndAuthenticateP2PService(8003, encryptionService3, keyRing3, useLocalhost, seedNodes);
|
|
||||||
|
|
||||||
MockData origData = new MockData("mockData1", keyRing1.getSignatureKeyPair().getPublic());
|
|
||||||
|
|
||||||
p2PService1.addData(origData);
|
|
||||||
Assert.assertEquals(1, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
|
|
||||||
// p2PService3 is adversary
|
|
||||||
KeyPair msgSignatureKeyPairAdversary = keyRing3.getSignatureKeyPair();
|
|
||||||
|
|
||||||
// try to remove data -> fails
|
|
||||||
Assert.assertFalse(p2PService3.removeData(origData));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(1, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
|
|
||||||
// try to add manipulated data -> fails
|
|
||||||
Assert.assertFalse(p2PService3.removeData(new MockData("mockData2", origData.publicKey)));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(1, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
// try to manipulate seq nr. -> fails
|
|
||||||
Set<ProtectedData> dataSet = p2PService3.getDataMap().values().stream()
|
|
||||||
.filter(data -> data instanceof ProtectedData)
|
|
||||||
.map(data -> (ProtectedData) data)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
ProtectedData origProtectedData = dataSet.stream().findFirst().get();
|
|
||||||
ProtectedData protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, origProtectedData.ownerPubKey, origProtectedData.sequenceNumber + 1, origProtectedData.signature);
|
|
||||||
Assert.assertFalse(p2PService3.removeData(protectedDataManipulated.expirablePayload));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(1, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
// try to manipulate seq nr. + pubKey -> fails
|
|
||||||
protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), origProtectedData.sequenceNumber + 1, origProtectedData.signature);
|
|
||||||
Assert.assertFalse(p2PService3.removeData(protectedDataManipulated.expirablePayload));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(1, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
// try to manipulate seq nr. + pubKey + sig -> fails
|
|
||||||
int sequenceNumberManipulated = origProtectedData.sequenceNumber + 1;
|
|
||||||
byte[] hashOfDataAndSeqNr = Hash.getHash(new P2PDataStorage.DataAndSeqNrPair(origProtectedData.expirablePayload, sequenceNumberManipulated));
|
|
||||||
byte[] signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr);
|
|
||||||
protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature);
|
|
||||||
Assert.assertFalse(p2PService3.removeData(protectedDataManipulated.expirablePayload));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(1, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
|
|
||||||
// data owner removes -> ok
|
|
||||||
Assert.assertTrue(p2PService1.removeData(origData));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(0, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
// adversary manage to change data before it is broadcasted to others
|
|
||||||
// data owner is connected only to adversary -> he change data at onMessage and broadcast manipulated data
|
|
||||||
// first he tries to use the orig. pubKey in the data -> fails as pub keys not matching
|
|
||||||
MockData manipulatedData = new MockData("mockData1_manipulated", origData.publicKey);
|
|
||||||
sequenceNumberManipulated = 0;
|
|
||||||
hashOfDataAndSeqNr = Hash.getHash(new P2PDataStorage.DataAndSeqNrPair(manipulatedData, sequenceNumberManipulated));
|
|
||||||
signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr);
|
|
||||||
protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature);
|
|
||||||
Assert.assertFalse(p2PService3.addData(protectedDataManipulated.expirablePayload));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(0, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
// then he tries to use his pubKey but orig data payload -> fails as pub keys nto matching
|
|
||||||
manipulatedData = new MockData("mockData1_manipulated", msgSignatureKeyPairAdversary.getPublic());
|
|
||||||
sequenceNumberManipulated = 0;
|
|
||||||
hashOfDataAndSeqNr = Hash.getHash(new P2PDataStorage.DataAndSeqNrPair(manipulatedData, sequenceNumberManipulated));
|
|
||||||
signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr);
|
|
||||||
protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature);
|
|
||||||
Assert.assertFalse(p2PService3.addData(protectedDataManipulated.expirablePayload));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(0, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
// then he tries to use his pubKey -> now he succeeds, but its same as adding a completely new msg and
|
|
||||||
// payload data has adversary's pubKey so he could hijack the owners data
|
|
||||||
manipulatedData = new MockData("mockData1_manipulated", msgSignatureKeyPairAdversary.getPublic());
|
|
||||||
sequenceNumberManipulated = 0;
|
|
||||||
hashOfDataAndSeqNr = Hash.getHash(new P2PDataStorage.DataAndSeqNrPair(manipulatedData, sequenceNumberManipulated));
|
|
||||||
signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr);
|
|
||||||
protectedDataManipulated = new ProtectedData(manipulatedData, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature);
|
|
||||||
Assert.assertTrue(p2PService3.addData(protectedDataManipulated.expirablePayload));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(1, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
// let clean up. he can remove his own data
|
|
||||||
Assert.assertTrue(p2PService3.removeData(manipulatedData));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(0, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
|
|
||||||
// finally he tries both previous attempts with same data - > same as before
|
|
||||||
manipulatedData = new MockData("mockData1", origData.publicKey);
|
|
||||||
sequenceNumberManipulated = 0;
|
|
||||||
hashOfDataAndSeqNr = Hash.getHash(new P2PDataStorage.DataAndSeqNrPair(manipulatedData, sequenceNumberManipulated));
|
|
||||||
signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr);
|
|
||||||
protectedDataManipulated = new ProtectedData(origProtectedData.expirablePayload, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature);
|
|
||||||
Assert.assertFalse(p2PService3.addData(protectedDataManipulated.expirablePayload));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(0, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
manipulatedData = new MockData("mockData1", msgSignatureKeyPairAdversary.getPublic());
|
|
||||||
sequenceNumberManipulated = 0;
|
|
||||||
hashOfDataAndSeqNr = Hash.getHash(new P2PDataStorage.DataAndSeqNrPair(manipulatedData, sequenceNumberManipulated));
|
|
||||||
signature = Sig.sign(msgSignatureKeyPairAdversary.getPrivate(), hashOfDataAndSeqNr);
|
|
||||||
protectedDataManipulated = new ProtectedData(manipulatedData, origProtectedData.ttl, msgSignatureKeyPairAdversary.getPublic(), sequenceNumberManipulated, signature);
|
|
||||||
Assert.assertTrue(p2PService3.addData(protectedDataManipulated.expirablePayload));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(1, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
// lets reset map
|
|
||||||
Assert.assertTrue(p2PService3.removeData(protectedDataManipulated.expirablePayload));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(0, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(0, p2PService3.getDataMap().size());
|
|
||||||
|
|
||||||
// owner can add any time his data
|
|
||||||
Assert.assertTrue(p2PService1.addData(origData));
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
Assert.assertEquals(1, p2PService1.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService2.getDataMap().size());
|
|
||||||
Assert.assertEquals(1, p2PService3.getDataMap().size());
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void testSendMailboxMessageToOnlinePeer() throws InterruptedException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, CryptoException {
|
|
||||||
LocalhostNetworkNode.setSimulateTorDelayTorNode(0);
|
|
||||||
LocalhostNetworkNode.setSimulateTorDelayHiddenService(0);
|
|
||||||
|
|
||||||
// send to online peer
|
|
||||||
CountDownLatch latch2 = new CountDownLatch(2);
|
|
||||||
MockMailboxPayload mockMessage = new MockMailboxPayload("MockMailboxMessage", p2PService2.getAddress());
|
|
||||||
p2PService2.getNetworkNode().addMessageListener((message, connection) -> {
|
|
||||||
log.trace("message " + message);
|
|
||||||
if (message instanceof PrefixedSealedAndSignedMessage) {
|
|
||||||
try {
|
|
||||||
PrefixedSealedAndSignedMessage prefixedSealedAndSignedMessage = (PrefixedSealedAndSignedMessage) message;
|
|
||||||
DecryptedMsgWithPubKey decryptedMsgWithPubKey = encryptionService2.decryptAndVerify(prefixedSealedAndSignedMessage.sealedAndSigned);
|
|
||||||
Assert.assertEquals(mockMessage, decryptedMsgWithPubKey.message);
|
|
||||||
Assert.assertEquals(p2PService2.getAddress(), ((MailboxMessage) decryptedMsgWithPubKey.message).getSenderNodeAddress());
|
|
||||||
latch2.countDown();
|
|
||||||
} catch (CryptoException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
p2PService1.sendEncryptedMailboxMessage(
|
|
||||||
p2PService2.getAddress(),
|
|
||||||
keyRing2.getPubKeyRing(),
|
|
||||||
mockMessage,
|
|
||||||
new SendMailboxMessageListener() {
|
|
||||||
@Override
|
|
||||||
public void onArrived() {
|
|
||||||
log.trace("Message arrived at peer.");
|
|
||||||
latch2.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStoredInMailbox() {
|
|
||||||
log.trace("Message stored in mailbox.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFault(String errorMessage) {
|
|
||||||
log.error("onFault");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
latch2.await();
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Test
|
|
||||||
public void testSendMailboxMessageToOfflinePeer() throws InterruptedException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, CryptoException {
|
|
||||||
LocalhostNetworkNode.setSimulateTorDelayTorNode(0);
|
|
||||||
LocalhostNetworkNode.setSimulateTorDelayHiddenService(0);
|
|
||||||
|
|
||||||
// send msg to offline peer
|
|
||||||
MockMailboxPayload mockMessage = new MockMailboxPayload(
|
|
||||||
"MockMailboxMessage",
|
|
||||||
p2PService2.getAddress()
|
|
||||||
);
|
|
||||||
CountDownLatch latch2 = new CountDownLatch(1);
|
|
||||||
p2PService2.sendEncryptedMailboxMessage(
|
|
||||||
new NodeAddress("localhost:8003"),
|
|
||||||
keyRing3.getPubKeyRing(),
|
|
||||||
mockMessage,
|
|
||||||
new SendMailboxMessageListener() {
|
|
||||||
@Override
|
|
||||||
public void onArrived() {
|
|
||||||
log.trace("Message arrived at peer.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStoredInMailbox() {
|
|
||||||
log.trace("Message stored in mailbox.");
|
|
||||||
latch2.countDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFault(String errorMessage) {
|
|
||||||
log.error("onFault");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
latch2.await();
|
|
||||||
Thread.sleep(2000);
|
|
||||||
|
|
||||||
|
|
||||||
// start node 3
|
|
||||||
p2PService3 = TestUtils.getAndAuthenticateP2PService(8003, encryptionService3, keyRing3, useLocalhost, seedNodes);
|
|
||||||
Thread.sleep(sleepTime);
|
|
||||||
CountDownLatch latch3 = new CountDownLatch(1);
|
|
||||||
p2PService3.addDecryptedMailboxListener((decryptedMessageWithPubKey, senderAddress) -> {
|
|
||||||
log.debug("decryptedMessageWithPubKey " + decryptedMessageWithPubKey.toString());
|
|
||||||
Assert.assertEquals(mockMessage, decryptedMessageWithPubKey.message);
|
|
||||||
Assert.assertEquals(p2PService2.getAddress(), ((MailboxMessage) decryptedMessageWithPubKey.message).getSenderNodeAddress());
|
|
||||||
latch3.countDown();
|
|
||||||
});
|
|
||||||
latch3.await();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,17 +3,21 @@ package io.bitsquare.p2p.mocks;
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.NodeAddress;
|
import io.bitsquare.p2p.NodeAddress;
|
||||||
import io.bitsquare.p2p.messaging.MailboxMessage;
|
import io.bitsquare.p2p.messaging.MailboxMessage;
|
||||||
import io.bitsquare.p2p.storage.data.ExpirablePayload;
|
import io.bitsquare.p2p.storage.payload.ExpirablePayload;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public final class MockMailboxPayload implements MailboxMessage, ExpirablePayload {
|
public final class MockMailboxPayload implements MailboxMessage, ExpirablePayload {
|
||||||
private final int messageVersion = Version.getP2PMessageVersion();
|
private final int messageVersion = Version.getP2PMessageVersion();
|
||||||
public final String msg;
|
public final String msg;
|
||||||
public final NodeAddress senderNodeAddress;
|
public final NodeAddress senderNodeAddress;
|
||||||
public long ttl;
|
public long ttl;
|
||||||
|
private String uid;
|
||||||
|
|
||||||
public MockMailboxPayload(String msg, NodeAddress senderNodeAddress) {
|
public MockMailboxPayload(String msg, NodeAddress senderNodeAddress) {
|
||||||
this.msg = msg;
|
this.msg = msg;
|
||||||
this.senderNodeAddress = senderNodeAddress;
|
this.senderNodeAddress = senderNodeAddress;
|
||||||
|
uid = UUID.randomUUID().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -21,6 +25,11 @@ public final class MockMailboxPayload implements MailboxMessage, ExpirablePayloa
|
||||||
return messageVersion;
|
return messageVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUID() {
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
|
@ -2,7 +2,7 @@ package io.bitsquare.p2p.mocks;
|
||||||
|
|
||||||
import io.bitsquare.app.Version;
|
import io.bitsquare.app.Version;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.storage.data.ExpirablePayload;
|
import io.bitsquare.p2p.storage.payload.ExpirablePayload;
|
||||||
|
|
||||||
public final class MockPayload implements Message, ExpirablePayload {
|
public final class MockPayload implements Message, ExpirablePayload {
|
||||||
public final String msg;
|
public final String msg;
|
||||||
|
|
|
@ -9,9 +9,9 @@ import io.bitsquare.p2p.P2PService;
|
||||||
import io.bitsquare.p2p.TestUtils;
|
import io.bitsquare.p2p.TestUtils;
|
||||||
import io.bitsquare.p2p.network.NetworkNode;
|
import io.bitsquare.p2p.network.NetworkNode;
|
||||||
import io.bitsquare.p2p.peers.PeerManager;
|
import io.bitsquare.p2p.peers.PeerManager;
|
||||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
|
||||||
import io.bitsquare.p2p.storage.messages.RefreshTTLMessage;
|
import io.bitsquare.p2p.storage.messages.RefreshTTLMessage;
|
||||||
import io.bitsquare.p2p.storage.mocks.MockData;
|
import io.bitsquare.p2p.storage.mocks.MockData;
|
||||||
|
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -98,14 +98,14 @@ public class ProtectedDataStorageTest {
|
||||||
|
|
||||||
//@Test
|
//@Test
|
||||||
public void testAddAndRemove() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
public void testAddAndRemove() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
||||||
ProtectedData data = dataStorage1.getProtectedData(mockData, storageSignatureKeyPair1);
|
ProtectedStorageEntry data = dataStorage1.getProtectedData(mockData, storageSignatureKeyPair1);
|
||||||
Assert.assertTrue(dataStorage1.add(data, null));
|
Assert.assertTrue(dataStorage1.add(data, null));
|
||||||
Assert.assertEquals(1, dataStorage1.getMap().size());
|
Assert.assertEquals(1, dataStorage1.getMap().size());
|
||||||
|
|
||||||
int newSequenceNumber = data.sequenceNumber + 1;
|
int newSequenceNumber = data.sequenceNumber + 1;
|
||||||
byte[] hashOfDataAndSeqNr = Hash.getHash(new P2PDataStorage.DataAndSeqNrPair(data.expirablePayload, newSequenceNumber));
|
byte[] hashOfDataAndSeqNr = Hash.getHash(new P2PDataStorage.DataAndSeqNrPair(data.getStoragePayload(), newSequenceNumber));
|
||||||
byte[] signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr);
|
byte[] signature = Sig.sign(storageSignatureKeyPair1.getPrivate(), hashOfDataAndSeqNr);
|
||||||
ProtectedData dataToRemove = new ProtectedData(data.expirablePayload, data.ttl, data.ownerPubKey, newSequenceNumber, signature);
|
ProtectedStorageEntry dataToRemove = new ProtectedStorageEntry(data.getStoragePayload(), data.ownerPubKey, newSequenceNumber, signature);
|
||||||
Assert.assertTrue(dataStorage1.remove(dataToRemove, null));
|
Assert.assertTrue(dataStorage1.remove(dataToRemove, null));
|
||||||
Assert.assertEquals(0, dataStorage1.getMap().size());
|
Assert.assertEquals(0, dataStorage1.getMap().size());
|
||||||
}
|
}
|
||||||
|
@ -113,9 +113,8 @@ public class ProtectedDataStorageTest {
|
||||||
// @Test
|
// @Test
|
||||||
public void testTTL() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
public void testTTL() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
||||||
mockData.ttl = (int) (P2PDataStorage.CHECK_TTL_INTERVAL_SEC * 1.5);
|
mockData.ttl = (int) (P2PDataStorage.CHECK_TTL_INTERVAL_SEC * 1.5);
|
||||||
ProtectedData data = dataStorage1.getProtectedData(mockData, storageSignatureKeyPair1);
|
ProtectedStorageEntry data = dataStorage1.getProtectedData(mockData, storageSignatureKeyPair1);
|
||||||
log.debug("data.date " + data.date);
|
log.debug("data.date " + data.timeStamp);
|
||||||
log.debug("data.date " + data.date.getTime());
|
|
||||||
Assert.assertTrue(dataStorage1.add(data, null));
|
Assert.assertTrue(dataStorage1.add(data, null));
|
||||||
log.debug("test 1");
|
log.debug("test 1");
|
||||||
Assert.assertEquals(1, dataStorage1.getMap().size());
|
Assert.assertEquals(1, dataStorage1.getMap().size());
|
||||||
|
@ -163,7 +162,7 @@ public class ProtectedDataStorageTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRefreshTTL() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
public void testRefreshTTL() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException, NoSuchProviderException {
|
||||||
mockData.ttl = (int) (P2PDataStorage.CHECK_TTL_INTERVAL_SEC * 1.5);
|
mockData.ttl = (int) (P2PDataStorage.CHECK_TTL_INTERVAL_SEC * 1.5);
|
||||||
ProtectedData data = dataStorage1.getProtectedData(mockData, storageSignatureKeyPair1);
|
ProtectedStorageEntry data = dataStorage1.getProtectedData(mockData, storageSignatureKeyPair1);
|
||||||
Assert.assertTrue(dataStorage1.add(data, null));
|
Assert.assertTrue(dataStorage1.add(data, null));
|
||||||
Assert.assertEquals(1, dataStorage1.getMap().size());
|
Assert.assertEquals(1, dataStorage1.getMap().size());
|
||||||
Thread.sleep(P2PDataStorage.CHECK_TTL_INTERVAL_SEC);
|
Thread.sleep(P2PDataStorage.CHECK_TTL_INTERVAL_SEC);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue