mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-06-21 05:14:31 -04:00
Add DHT mailbox
This commit is contained in:
parent
506ac37293
commit
239389b529
41 changed files with 680 additions and 391 deletions
|
@ -69,7 +69,7 @@ public class BlockChainService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("SameReturnValue")
|
@SuppressWarnings("SameReturnValue")
|
||||||
private boolean isBankAccountBlacklisted(FiatAccount fiatAccount) {
|
private boolean isFiatAccountBlacklisted(FiatAccount fiatAccount) {
|
||||||
// TODO check if accountID is on blacklist
|
// TODO check if accountID is on blacklist
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -471,14 +471,14 @@ public class WalletService {
|
||||||
return tradeWalletService;
|
return tradeWalletService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void payRegistrationFee(String stringifiedBankAccounts, FutureCallback<Transaction> callback) throws
|
public void payRegistrationFee(String stringifiedFiatAccounts, FutureCallback<Transaction> callback) throws
|
||||||
InsufficientMoneyException {
|
InsufficientMoneyException {
|
||||||
log.debug("payRegistrationFee");
|
log.debug("payRegistrationFee");
|
||||||
log.trace("stringifiedBankAccounts " + stringifiedBankAccounts);
|
log.trace("stringifiedFiatAccounts " + stringifiedFiatAccounts);
|
||||||
|
|
||||||
Transaction tx = new Transaction(params);
|
Transaction tx = new Transaction(params);
|
||||||
|
|
||||||
byte[] data = signatureService.digestMessageWithSignature(getRegistrationAddressEntry().getKeyPair(), stringifiedBankAccounts);
|
byte[] data = signatureService.digestMessageWithSignature(getRegistrationAddressEntry().getKeyPair(), stringifiedFiatAccounts);
|
||||||
tx.addOutput(Transaction.MIN_NONDUST_OUTPUT, new ScriptBuilder().op(OP_RETURN).data(data).build());
|
tx.addOutput(Transaction.MIN_NONDUST_OUTPUT, new ScriptBuilder().op(OP_RETURN).data(data).build());
|
||||||
|
|
||||||
// We don't take a fee at the moment
|
// We don't take a fee at the moment
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Bitsquare.
|
||||||
|
*
|
||||||
|
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.bitsquare.crypto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class EncryptionPackage implements Serializable {
|
||||||
|
private static final long serialVersionUID = -8709538217388076762L;
|
||||||
|
|
||||||
|
public final byte[] encryptedKey;
|
||||||
|
public final byte[] encryptedPayload;
|
||||||
|
|
||||||
|
public EncryptionPackage(byte[] encryptedKey, byte[] encryptedPayload) {
|
||||||
|
this.encryptedKey = encryptedKey;
|
||||||
|
this.encryptedPayload = encryptedPayload;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,11 +19,11 @@ package io.bitsquare.crypto;
|
||||||
|
|
||||||
import io.bitsquare.util.Utilities;
|
import io.bitsquare.util.Utilities;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.security.InvalidKeyException;
|
||||||
|
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
|
@ -32,98 +32,82 @@ import javax.inject.Inject;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
import javax.crypto.KeyGenerator;
|
import javax.crypto.KeyGenerator;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
public class EncryptionService<T> {
|
public class EncryptionService<T> {
|
||||||
private static final Logger log = LoggerFactory.getLogger(EncryptionService.class);
|
private static final Logger log = LoggerFactory.getLogger(EncryptionService.class);
|
||||||
|
private static final String ALGO_SYM = "AES";
|
||||||
|
private static final String CIPHER_SYM = "AES";
|
||||||
|
private static final String ALGO_ASYM = "RSA";
|
||||||
|
private static final String CIPHER_ASYM = "RSA/ECB/PKCS1Padding";
|
||||||
|
private static final int KEY_SIZE_SYM = 128;
|
||||||
|
private static final int KEY_SIZE_ASYM = 1024;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public EncryptionService() {
|
public EncryptionService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyPair getKeyPair() {
|
public KeyPair getKeyPair() throws NoSuchAlgorithmException {
|
||||||
KeyPair keyPair = null;
|
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGO_ASYM);
|
||||||
try {
|
keyPairGenerator.initialize(KEY_SIZE_ASYM);
|
||||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
return keyPairGenerator.genKeyPair();
|
||||||
keyPairGenerator.initialize(1024);
|
|
||||||
keyPair = keyPairGenerator.genKeyPair();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
log.error("Exception at init " + e.getMessage());
|
|
||||||
}
|
|
||||||
return keyPair;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tuple encryptObject(PublicKey publicKey, Object object) {
|
public EncryptionPackage encryptObject(PublicKey publicKey, Object object) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException,
|
||||||
|
NoSuchAlgorithmException, NoSuchPaddingException {
|
||||||
return encrypt(publicKey, Utilities.objectToBytArray(object));
|
return encrypt(publicKey, Utilities.objectToBytArray(object));
|
||||||
}
|
}
|
||||||
|
|
||||||
public T decryptToObject(PrivateKey privateKey, Tuple tuple) {
|
public T decryptToObject(PrivateKey privateKey, EncryptionPackage encryptionPackage) throws IllegalBlockSizeException, InvalidKeyException,
|
||||||
return (T) Utilities.byteArrayToObject(decrypt(privateKey, tuple));
|
BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
|
||||||
|
return (T) Utilities.byteArrayToObject(decrypt(privateKey, encryptionPackage));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tuple encrypt(PublicKey publicKey, byte[] payload) {
|
public EncryptionPackage encrypt(PublicKey publicKey, byte[] payload) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
|
||||||
byte[] encryptedPayload = null;
|
BadPaddingException, IllegalBlockSizeException {
|
||||||
byte[] encryptedKey = null;
|
|
||||||
try {
|
|
||||||
// Create symmetric key and
|
// Create symmetric key and
|
||||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGO_SYM);
|
||||||
keyGenerator.init(256);
|
keyGenerator.init(KEY_SIZE_SYM);
|
||||||
SecretKey secretKey = keyGenerator.generateKey();
|
SecretKey secretKey = keyGenerator.generateKey();
|
||||||
|
|
||||||
// Encrypt secretKey with asymmetric key
|
// Encrypt secretKey with asymmetric key
|
||||||
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
|
Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
|
cipherAsym.init(Cipher.ENCRYPT_MODE, publicKey);
|
||||||
encryptedKey = cipher.doFinal(secretKey.getEncoded());
|
log.debug("encrypt secret key length: " + secretKey.getEncoded().length);
|
||||||
|
byte[] encryptedKey = cipherAsym.doFinal(secretKey.getEncoded());
|
||||||
|
|
||||||
// Encrypt payload with symmetric key
|
// Encrypt payload with symmetric key
|
||||||
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), "AES");
|
SecretKeySpec keySpec = new SecretKeySpec(secretKey.getEncoded(), ALGO_SYM);
|
||||||
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
|
cipherSym.init(Cipher.ENCRYPT_MODE, keySpec);
|
||||||
encryptedPayload = cipher.doFinal(payload);
|
log.debug("encrypt payload length: " + payload.length);
|
||||||
} catch (Exception e) {
|
byte[] encryptedPayload = cipherSym.doFinal(payload);
|
||||||
e.printStackTrace();
|
return new EncryptionPackage(encryptedKey, encryptedPayload);
|
||||||
log.error("Exception at encrypt " + e.getMessage());
|
|
||||||
}
|
|
||||||
return new Tuple(encryptedKey, encryptedPayload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] decrypt(PrivateKey privateKey, Tuple tuple) {
|
public byte[] decrypt(PrivateKey privateKey, EncryptionPackage encryptionPackage) throws NoSuchPaddingException, NoSuchAlgorithmException,
|
||||||
byte[] encryptedPayload = tuple.encryptedPayload;
|
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
|
||||||
byte[] encryptedKey = tuple.encryptedKey;
|
byte[] encryptedPayload = encryptionPackage.encryptedPayload;
|
||||||
|
byte[] encryptedKey = encryptionPackage.encryptedKey;
|
||||||
|
|
||||||
byte[] payload = null;
|
|
||||||
try {
|
|
||||||
// Decrypt secretKey key with asymmetric key
|
// Decrypt secretKey key with asymmetric key
|
||||||
Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding");
|
Cipher cipherAsym = Cipher.getInstance(CIPHER_ASYM);
|
||||||
cipher.init(Cipher.DECRYPT_MODE, privateKey);
|
cipherAsym.init(Cipher.DECRYPT_MODE, privateKey);
|
||||||
byte[] secretKey = cipher.doFinal(encryptedKey);
|
byte[] secretKey = cipherAsym.doFinal(encryptedKey);
|
||||||
|
log.debug("decrypt secret key length: " + secretKey.length);
|
||||||
// Decrypt payload with symmetric key
|
// Decrypt payload with symmetric key
|
||||||
Key key = new SecretKeySpec(secretKey, "AES");
|
Key key = new SecretKeySpec(secretKey, ALGO_SYM);
|
||||||
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
Cipher cipherSym = Cipher.getInstance(CIPHER_SYM);
|
||||||
cipher.init(Cipher.DECRYPT_MODE, key);
|
cipherSym.init(Cipher.DECRYPT_MODE, key);
|
||||||
payload = cipher.doFinal(encryptedPayload);
|
byte[] payload = cipherSym.doFinal(encryptedPayload);
|
||||||
} catch (Exception e) {
|
log.debug("decrypt payload length: " + payload.length);
|
||||||
e.printStackTrace();
|
|
||||||
log.error("Exception at decrypt " + e.getMessage());
|
|
||||||
}
|
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Tuple implements Serializable {
|
|
||||||
private static final long serialVersionUID = -8709538217388076762L;
|
|
||||||
|
|
||||||
public final byte[] encryptedKey;
|
|
||||||
public final byte[] encryptedPayload;
|
|
||||||
|
|
||||||
public Tuple(byte[] encryptedKey, byte[] encryptedPayload) {
|
|
||||||
this.encryptedKey = encryptedKey;
|
|
||||||
this.encryptedPayload = encryptedPayload;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,7 +154,7 @@ class RestrictionsDataModel implements Activatable, DataModel {
|
||||||
private void addMockArbitrator() {
|
private void addMockArbitrator() {
|
||||||
if (accountSettings.getAcceptedArbitrators().isEmpty() && user.getP2pSigKeyPair() != null) {
|
if (accountSettings.getAcceptedArbitrators().isEmpty() && user.getP2pSigKeyPair() != null) {
|
||||||
byte[] pubKey = new ECKey().getPubKey();
|
byte[] pubKey = new ECKey().getPubKey();
|
||||||
String messagePubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getP2PSigPubKey());
|
String p2pSigPubKeyAsHex = DSAKeyUtil.getHexStringFromPublicKey(user.getP2PSigPubKey());
|
||||||
List<Locale> languages = new ArrayList<>();
|
List<Locale> languages = new ArrayList<>();
|
||||||
languages.add(LanguageUtil.getDefaultLanguageLocale());
|
languages.add(LanguageUtil.getDefaultLanguageLocale());
|
||||||
List<Arbitrator.METHOD> arbitrationMethods = new ArrayList<>();
|
List<Arbitrator.METHOD> arbitrationMethods = new ArrayList<>();
|
||||||
|
@ -166,7 +166,7 @@ class RestrictionsDataModel implements Activatable, DataModel {
|
||||||
// TODO use very small sec. dposit to make testing in testnet less expensive
|
// TODO use very small sec. dposit to make testing in testnet less expensive
|
||||||
// Revert later to 0.1 BTC again
|
// Revert later to 0.1 BTC again
|
||||||
Arbitrator arbitrator = new Arbitrator(pubKey,
|
Arbitrator arbitrator = new Arbitrator(pubKey,
|
||||||
messagePubKeyAsHex,
|
p2pSigPubKeyAsHex,
|
||||||
"Manfred Karrer",
|
"Manfred Karrer",
|
||||||
Arbitrator.ID_TYPE.REAL_LIFE_ID,
|
Arbitrator.ID_TYPE.REAL_LIFE_ID,
|
||||||
languages,
|
languages,
|
||||||
|
|
|
@ -45,7 +45,7 @@ import io.bitsquare.trade.protocol.trade.offerer.tasks.VerifyTakerAccount;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
|
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessFiatTransferStartedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
|
||||||
|
@ -135,7 +135,7 @@ public class DebugView extends InitializableView {
|
||||||
ProcessDepositTxPublishedMessage.class,
|
ProcessDepositTxPublishedMessage.class,
|
||||||
TakerCommitDepositTx.class,
|
TakerCommitDepositTx.class,
|
||||||
|
|
||||||
ProcessBankTransferStartedMessage.class,
|
ProcessFiatTransferStartedMessage.class,
|
||||||
|
|
||||||
SignAndPublishPayoutTx.class,
|
SignAndPublishPayoutTx.class,
|
||||||
VerifyOfferFeePayment.class,
|
VerifyOfferFeePayment.class,
|
||||||
|
|
|
@ -74,7 +74,7 @@ class ClosedTradesDataModel implements Activatable, DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Direction getDirection(Offer offer) {
|
public Direction getDirection(Offer offer) {
|
||||||
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()) ?
|
return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
|
||||||
offer.getDirection() : offer.getMirroredDirection();
|
offer.getDirection() : offer.getMirroredDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ class OffersDataModel implements Activatable, DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Direction getDirection(Offer offer) {
|
public Direction getDirection(Offer offer) {
|
||||||
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()) ?
|
return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
|
||||||
offer.getDirection() : offer.getMirroredDirection();
|
offer.getDirection() : offer.getMirroredDirection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||||
selectedItem = item;
|
selectedItem = item;
|
||||||
|
|
||||||
if (selectedItem != null) {
|
if (selectedItem != null) {
|
||||||
isOfferer = getTrade().getOffer().getMessagePublicKey().equals(user.getP2PSigPubKey());
|
isOfferer = getTrade().getOffer().getP2PSigPubKey().equals(user.getP2PSigPubKey());
|
||||||
|
|
||||||
Trade trade = getTrade();
|
Trade trade = getTrade();
|
||||||
trade.stateProperty().addListener(tradeStateChangeListener);
|
trade.stateProperty().addListener(tradeStateChangeListener);
|
||||||
|
@ -172,7 +172,6 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
void fiatPaymentStarted() {
|
void fiatPaymentStarted() {
|
||||||
getTrade().setState(Trade.State.FIAT_PAYMENT_STARTED);
|
|
||||||
tradeManager.onFiatPaymentStarted(getTrade().getId());
|
tradeManager.onFiatPaymentStarted(getTrade().getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +208,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||||
log.error(e.getMessage());
|
log.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
tradeManager.closeTrade(getTrade());
|
tradeManager.onWithdrawAtTradeCompleted(getTrade());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Action response = Popups.openConfirmPopup(
|
Action response = Popups.openConfirmPopup(
|
||||||
|
@ -269,7 +268,7 @@ class PendingTradesDataModel implements Activatable, DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Direction getDirection(Offer offer) {
|
public Direction getDirection(Offer offer) {
|
||||||
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey()) ?
|
return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey()) ?
|
||||||
offer.getDirection() : offer.getMirroredDirection();
|
offer.getDirection() : offer.getMirroredDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,7 +213,7 @@ class OfferBookDataModel implements Activatable, DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMyOffer(Offer offer) {
|
boolean isMyOffer(Offer offer) {
|
||||||
return offer.getMessagePublicKey() != null && offer.getMessagePublicKey().equals(user.getP2PSigPubKey());
|
return offer.getP2PSigPubKey() != null && offer.getP2PSigPubKey().equals(user.getP2PSigPubKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
Coin getAmountAsCoin() {
|
Coin getAmountAsCoin() {
|
||||||
|
|
|
@ -97,7 +97,7 @@ class TakeOfferDataModel implements Activatable, DataModel {
|
||||||
@Override
|
@Override
|
||||||
public void deactivate() {
|
public void deactivate() {
|
||||||
btcCode.unbind();
|
btcCode.unbind();
|
||||||
tradeManager.cancelGetOfferAvailableStateRequest(offer);
|
tradeManager.cancelCheckOfferAvailabilityRequest(offer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initWithData(Coin amount, Offer offer) {
|
void initWithData(Coin amount, Offer offer) {
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class Offer implements Serializable {
|
||||||
private final Coin amount;
|
private final Coin amount;
|
||||||
private final Coin minAmount;
|
private final Coin minAmount;
|
||||||
//TODO use hex string
|
//TODO use hex string
|
||||||
private final PublicKey messagePublicKey;
|
private final PublicKey p2pSigPubKey;
|
||||||
private final FiatAccountType fiatAccountType;
|
private final FiatAccountType fiatAccountType;
|
||||||
private final Country bankAccountCountry;
|
private final Country bankAccountCountry;
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ public class Offer implements Serializable {
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public Offer(String id,
|
public Offer(String id,
|
||||||
PublicKey messagePublicKey,
|
PublicKey p2pSigPubKey,
|
||||||
Direction direction,
|
Direction direction,
|
||||||
long fiatPrice,
|
long fiatPrice,
|
||||||
Coin amount,
|
Coin amount,
|
||||||
|
@ -108,7 +108,7 @@ public class Offer implements Serializable {
|
||||||
List<Country> acceptedCountries,
|
List<Country> acceptedCountries,
|
||||||
List<Locale> acceptedLanguageLocales) {
|
List<Locale> acceptedLanguageLocales) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.messagePublicKey = messagePublicKey;
|
this.p2pSigPubKey = p2pSigPubKey;
|
||||||
this.direction = direction;
|
this.direction = direction;
|
||||||
this.fiatPrice = fiatPrice;
|
this.fiatPrice = fiatPrice;
|
||||||
this.amount = amount;
|
this.amount = amount;
|
||||||
|
@ -221,8 +221,8 @@ public class Offer implements Serializable {
|
||||||
return bankAccountUID;
|
return bankAccountUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PublicKey getMessagePublicKey() {
|
public PublicKey getP2PSigPubKey() {
|
||||||
return messagePublicKey;
|
return p2pSigPubKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getCreationDate() {
|
public Date getCreationDate() {
|
||||||
|
@ -250,7 +250,7 @@ public class Offer implements Serializable {
|
||||||
checkNotNull(getCurrency(), "Currency is null");
|
checkNotNull(getCurrency(), "Currency is null");
|
||||||
checkNotNull(getDirection(), "Direction is null");
|
checkNotNull(getDirection(), "Direction is null");
|
||||||
checkNotNull(getId(), "Id is null");
|
checkNotNull(getId(), "Id is null");
|
||||||
checkNotNull(getMessagePublicKey(), "MessagePublicKey is null");
|
checkNotNull(getP2PSigPubKey(), "p2pSigPubKey is null");
|
||||||
checkNotNull(getMinAmount(), "MinAmount is null");
|
checkNotNull(getMinAmount(), "MinAmount is null");
|
||||||
checkNotNull(getPrice(), "Price is null");
|
checkNotNull(getPrice(), "Price is null");
|
||||||
|
|
||||||
|
@ -277,7 +277,7 @@ public class Offer implements Serializable {
|
||||||
", fiatPrice=" + fiatPrice +
|
", fiatPrice=" + fiatPrice +
|
||||||
", amount=" + amount +
|
", amount=" + amount +
|
||||||
", minAmount=" + minAmount +
|
", minAmount=" + minAmount +
|
||||||
", messagePublicKey=" + messagePublicKey +
|
", p2pSigPubKey=" + p2pSigPubKey +
|
||||||
", fiatAccountType=" + fiatAccountType +
|
", fiatAccountType=" + fiatAccountType +
|
||||||
", bankAccountCountry=" + bankAccountCountry +
|
", bankAccountCountry=" + bankAccountCountry +
|
||||||
", securityDeposit=" + securityDeposit +
|
", securityDeposit=" + securityDeposit +
|
||||||
|
|
|
@ -23,5 +23,5 @@ import io.bitsquare.p2p.listener.GetPeerAddressListener;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
public interface AddressService extends DHTService{
|
public interface AddressService extends DHTService{
|
||||||
void findPeerAddress(PublicKey messagePublicKey, GetPeerAddressListener getPeerAddressListener);
|
void findPeerAddress(PublicKey p2pSigPubKey, GetPeerAddressListener getPeerAddressListener);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
package io.bitsquare.p2p;
|
package io.bitsquare.p2p;
|
||||||
|
|
||||||
import io.bitsquare.crypto.EncryptionService;
|
import io.bitsquare.crypto.EncryptionPackage;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@ -31,13 +31,13 @@ public class EncryptedMailboxMessage implements MailboxMessage, Serializable {
|
||||||
private static final long serialVersionUID = -3111178895546299769L;
|
private static final long serialVersionUID = -3111178895546299769L;
|
||||||
private static final Logger log = LoggerFactory.getLogger(EncryptedMailboxMessage.class);
|
private static final Logger log = LoggerFactory.getLogger(EncryptedMailboxMessage.class);
|
||||||
|
|
||||||
private EncryptionService.Tuple tuple;
|
private EncryptionPackage encryptionPackage;
|
||||||
|
|
||||||
public EncryptedMailboxMessage(EncryptionService.Tuple tuple) {
|
public EncryptedMailboxMessage(EncryptionPackage encryptionPackage) {
|
||||||
this.tuple = tuple;
|
this.encryptionPackage = encryptionPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EncryptionService.Tuple getTuple() {
|
public EncryptionPackage getEncryptionPackage() {
|
||||||
return tuple;
|
return encryptionPackage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Bitsquare.
|
||||||
|
*
|
||||||
|
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.bitsquare.p2p;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface MailboxMessagesResultHandler {
|
||||||
|
void handleResult(List<EncryptedMailboxMessage> messages);
|
||||||
|
}
|
|
@ -19,14 +19,14 @@ package io.bitsquare.p2p;
|
||||||
|
|
||||||
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.p2p.tomp2p.TomP2PMailboxService;
|
|
||||||
|
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
public interface MailboxService {
|
public interface MailboxService {
|
||||||
void addMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler);
|
void addMessage(PublicKey p2pSigPubKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler);
|
||||||
|
|
||||||
void removeMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler);
|
void getAllMessages(PublicKey p2pSigPubKey, MailboxMessagesResultHandler resultHandler);
|
||||||
|
|
||||||
|
void removeAllMessages(PublicKey p2pSigPubKey, ResultHandler resultHandler, FaultHandler faultHandler);
|
||||||
|
|
||||||
void getMessages(PublicKey publicKey, TomP2PMailboxService.MailboxMessagesResultHandler resultHandler);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,14 @@ package io.bitsquare.p2p;
|
||||||
|
|
||||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||||
|
|
||||||
|
import java.security.PublicKey;
|
||||||
|
|
||||||
public interface MessageService extends P2PService {
|
public interface MessageService extends P2PService {
|
||||||
|
|
||||||
void sendMessage(Peer peer, Message message, SendMessageListener listener);
|
void sendMessage(Peer peer, Message message, SendMessageListener listener);
|
||||||
|
|
||||||
|
void sendMessage(Peer peer, Message message, PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey, SendMessageListener listener);
|
||||||
|
|
||||||
void addMessageHandler(MessageHandler listener);
|
void addMessageHandler(MessageHandler listener);
|
||||||
|
|
||||||
void removeMessageHandler(MessageHandler listener);
|
void removeMessageHandler(MessageHandler listener);
|
||||||
|
|
|
@ -91,9 +91,9 @@ public class TomP2PAddressService extends TomP2PDHTService implements AddressSer
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void findPeerAddress(PublicKey publicKey, GetPeerAddressListener listener) {
|
public void findPeerAddress(PublicKey p2pSigPubKey, GetPeerAddressListener listener) {
|
||||||
final Number160 locationKey = Utils.makeSHAHash(publicKey.getEncoded());
|
final Number160 locationKey = Utils.makeSHAHash(p2pSigPubKey.getEncoded());
|
||||||
FutureGet futureGet = getDataOfProtectedDomain(locationKey, publicKey);
|
FutureGet futureGet = getDataOfProtectedDomain(locationKey, p2pSigPubKey);
|
||||||
log.trace("findPeerAddress called");
|
log.trace("findPeerAddress called");
|
||||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -248,5 +248,17 @@ public class TomP2PDHTService extends TomP2PService implements DHTService {
|
||||||
return peerDHT.get(locationKey).all().domainKey(pubKeyHashForMyDomain).start();
|
return peerDHT.get(locationKey).all().domainKey(pubKeyHashForMyDomain).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all data from map for given locationKey.
|
||||||
|
* Access: Only the domain owner.
|
||||||
|
*
|
||||||
|
* @param locationKey
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public FutureRemove removeAllDataFromMapOfMyProtectedDomain(Number160 locationKey) {
|
||||||
|
log.trace("getDataFromMapOfMyProtectedDomain");
|
||||||
|
return peerDHT.remove(locationKey).domainKey(pubKeyHashForMyDomain).keyPair(keyPair).all().domainKey(pubKeyHashForMyDomain).keyPair(keyPair).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import io.bitsquare.common.handlers.FaultHandler;
|
||||||
import io.bitsquare.common.handlers.ResultHandler;
|
import io.bitsquare.common.handlers.ResultHandler;
|
||||||
import io.bitsquare.offer.OfferBookService;
|
import io.bitsquare.offer.OfferBookService;
|
||||||
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
||||||
|
import io.bitsquare.p2p.MailboxMessagesResultHandler;
|
||||||
import io.bitsquare.p2p.MailboxService;
|
import io.bitsquare.p2p.MailboxService;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class TomP2PMailboxService extends TomP2PDHTService implements MailboxService {
|
public class TomP2PMailboxService extends TomP2PDHTService implements MailboxService {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TomP2PMailboxService.class);
|
private static final Logger log = LoggerFactory.getLogger(TomP2PMailboxService.class);
|
||||||
private static final int TTL = 15 * 24 * 60 * 60; // the message is default 15 days valid, as a max trade period might be about 2 weeks.
|
private static final int TTL = 21 * 24 * 60 * 60; // the message is default 21 days valid, as a max trade period might be about 2 weeks.
|
||||||
|
|
||||||
private final List<OfferBookService.Listener> offerRepositoryListeners = new ArrayList<>();
|
private final List<OfferBookService.Listener> offerRepositoryListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
@ -69,14 +70,14 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler) {
|
public void addMessage(PublicKey p2pSigPubKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||||
try {
|
try {
|
||||||
final Data data = new Data(message);
|
final Data data = new Data(message);
|
||||||
data.ttlSeconds(TTL);
|
data.ttlSeconds(TTL);
|
||||||
log.trace("Add message to DHT requested. Added data: [locationKey: " + getLocationKey(publicKey) +
|
log.trace("Add message to DHT requested. Added data: [locationKey: " + getLocationKey(p2pSigPubKey) +
|
||||||
", hash: " + data.hash().toString() + "]");
|
", hash: " + data.hash().toString() + "]");
|
||||||
|
|
||||||
FuturePut futurePut = addDataToMapOfProtectedDomain(getLocationKey(publicKey), data, publicKey);
|
FuturePut futurePut = addDataToMapOfProtectedDomain(getLocationKey(p2pSigPubKey), data, p2pSigPubKey);
|
||||||
futurePut.addListener(new BaseFutureListener<BaseFuture>() {
|
futurePut.addListener(new BaseFutureListener<BaseFuture>() {
|
||||||
@Override
|
@Override
|
||||||
public void operationComplete(BaseFuture future) throws Exception {
|
public void operationComplete(BaseFuture future) throws Exception {
|
||||||
|
@ -84,7 +85,7 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
resultHandler.handleResult();
|
resultHandler.handleResult();
|
||||||
|
|
||||||
log.trace("Add message to mailbox was successful. Added data: [locationKey: " + getLocationKey(publicKey) +
|
log.trace("Add message to mailbox was successful. Added data: [locationKey: " + getLocationKey(p2pSigPubKey) +
|
||||||
", value: " + data + "]");
|
", value: " + data + "]");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -101,41 +102,9 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeMessage(PublicKey publicKey, EncryptedMailboxMessage message, ResultHandler resultHandler, FaultHandler faultHandler) {
|
public void getAllMessages(PublicKey p2pSigPubKey, MailboxMessagesResultHandler resultHandler) {
|
||||||
try {
|
log.trace("Get messages from DHT requested for locationKey: " + getLocationKey(p2pSigPubKey));
|
||||||
final Data data = new Data(message);
|
FutureGet futureGet = getDataFromMapOfMyProtectedDomain(getLocationKey(p2pSigPubKey));
|
||||||
log.trace("Remove message from DHT requested. Removed data: [locationKey: " + getLocationKey(publicKey) +
|
|
||||||
", hash: " + data.hash().toString() + "]");
|
|
||||||
FutureRemove futureRemove = removeDataFromMapOfMyProtectedDomain(getLocationKey(publicKey), data);
|
|
||||||
futureRemove.addListener(new BaseFutureListener<BaseFuture>() {
|
|
||||||
@Override
|
|
||||||
public void operationComplete(BaseFuture future) throws Exception {
|
|
||||||
// We don't test futureRemove.isSuccess() as this API does not fit well to that operation,
|
|
||||||
// it might change in future to something like foundAndRemoved and notFound
|
|
||||||
// See discussion at: https://github.com/tomp2p/TomP2P/issues/57#issuecomment-62069840
|
|
||||||
log.trace("isRemoved? " + futureRemove.isRemoved());
|
|
||||||
executor.execute(() -> {
|
|
||||||
resultHandler.handleResult();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionCaught(Throwable t) throws Exception {
|
|
||||||
log.error("Remove message from DHT failed. Error: " + t.getMessage());
|
|
||||||
faultHandler.handleFault("Remove message from DHT failed. Error: " + t.getMessage(), t);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
log.error("Remove message from DHT failed. Error: " + e.getMessage());
|
|
||||||
faultHandler.handleFault("Remove message from DHT failed. Error: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getMessages(PublicKey publicKey, MailboxMessagesResultHandler resultHandler) {
|
|
||||||
log.trace("Get messages from DHT requested for locationKey: " + getLocationKey(publicKey));
|
|
||||||
FutureGet futureGet = getDataFromMapOfMyProtectedDomain(getLocationKey(publicKey));
|
|
||||||
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
futureGet.addListener(new BaseFutureAdapter<BaseFuture>() {
|
||||||
@Override
|
@Override
|
||||||
public void operationComplete(BaseFuture future) throws Exception {
|
public void operationComplete(BaseFuture future) throws Exception {
|
||||||
|
@ -156,7 +125,7 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
|
||||||
executor.execute(() -> resultHandler.handleResult(messages));
|
executor.execute(() -> resultHandler.handleResult(messages));
|
||||||
}
|
}
|
||||||
|
|
||||||
log.trace("Get messages from DHT was successful. Stored data: [key: " + getLocationKey(publicKey)
|
log.trace("Get messages from DHT was successful. Stored data: [key: " + getLocationKey(p2pSigPubKey)
|
||||||
+ ", values: " + futureGet.dataMap() + "]");
|
+ ", values: " + futureGet.dataMap() + "]");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -173,16 +142,32 @@ public class TomP2PMailboxService extends TomP2PDHTService implements MailboxSer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
public void removeAllMessages(PublicKey p2pSigPubKey, ResultHandler resultHandler, FaultHandler faultHandler) {
|
||||||
// Private
|
log.trace("Remove all messages from DHT requested. locationKey: " + getLocationKey(p2pSigPubKey));
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
FutureRemove futureRemove = removeAllDataFromMapOfMyProtectedDomain(getLocationKey(p2pSigPubKey));
|
||||||
|
futureRemove.addListener(new BaseFutureListener<BaseFuture>() {
|
||||||
private Number160 getLocationKey(PublicKey publicKey) {
|
@Override
|
||||||
return Number160.createHash("mailbox" + publicKey.hashCode());
|
public void operationComplete(BaseFuture future) throws Exception {
|
||||||
|
// We don't test futureRemove.isSuccess() as this API does not fit well to that operation,
|
||||||
|
// it might change in future to something like foundAndRemoved and notFound
|
||||||
|
// See discussion at: https://github.com/tomp2p/TomP2P/issues/57#issuecomment-62069840
|
||||||
|
log.trace("isRemoved? " + futureRemove.isRemoved());
|
||||||
|
executor.execute(() -> {
|
||||||
|
resultHandler.handleResult();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface MailboxMessagesResultHandler {
|
@Override
|
||||||
void handleResult(List<EncryptedMailboxMessage> messages);
|
public void exceptionCaught(Throwable t) throws Exception {
|
||||||
|
log.error("Remove all messages from DHT failed. Error: " + t.getMessage());
|
||||||
|
faultHandler.handleFault("Remove all messages from DHT failed. Error: " + t.getMessage(), t);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Number160 getLocationKey(PublicKey p2pSigPubKey) {
|
||||||
|
return Number160.createHash("mailbox" + p2pSigPubKey.hashCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package io.bitsquare.p2p.tomp2p;
|
package io.bitsquare.p2p.tomp2p;
|
||||||
|
|
||||||
|
import io.bitsquare.crypto.EncryptionPackage;
|
||||||
import io.bitsquare.crypto.EncryptionService;
|
import io.bitsquare.crypto.EncryptionService;
|
||||||
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
||||||
import io.bitsquare.p2p.MailboxMessage;
|
import io.bitsquare.p2p.MailboxMessage;
|
||||||
|
@ -28,6 +29,8 @@ import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.p2p.listener.SendMessageListener;
|
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||||
import io.bitsquare.user.User;
|
import io.bitsquare.user.User;
|
||||||
|
|
||||||
|
import java.security.PublicKey;
|
||||||
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -53,7 +56,7 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TomP2PMessageService(TomP2PNode tomP2PNode, MailboxService mailboxService, User user, EncryptionService encryptionService) {
|
public TomP2PMessageService(TomP2PNode tomP2PNode, MailboxService mailboxService, User user, EncryptionService<MailboxMessage> encryptionService) {
|
||||||
super(tomP2PNode);
|
super(tomP2PNode);
|
||||||
this.mailboxService = mailboxService;
|
this.mailboxService = mailboxService;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
@ -74,6 +77,12 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(Peer peer, Message message, SendMessageListener listener) {
|
public void sendMessage(Peer peer, Message message, SendMessageListener listener) {
|
||||||
|
sendMessage(peer, message, null, null, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendMessage(Peer peer, Message message, PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey,
|
||||||
|
SendMessageListener listener) {
|
||||||
if (!(peer instanceof TomP2PPeer))
|
if (!(peer instanceof TomP2PPeer))
|
||||||
throw new IllegalArgumentException("Peer must be of type TomP2PPeer");
|
throw new IllegalArgumentException("Peer must be of type TomP2PPeer");
|
||||||
|
|
||||||
|
@ -86,8 +95,9 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
|
||||||
executor.execute(listener::handleResult);
|
executor.execute(listener::handleResult);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (message instanceof MailboxMessage) {
|
if (p2pSigPubKey != null && p2pEncryptPubKey != null) {
|
||||||
sendMailboxMessage((MailboxMessage) message, listener);
|
log.info("sendMessage failed. We will try to send the message to the mailbox. Fault reason: " + futureDirect.failedReason());
|
||||||
|
sendMailboxMessage(p2pSigPubKey, p2pEncryptPubKey, (MailboxMessage) message, listener);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.error("sendMessage failed with reason " + futureDirect.failedReason());
|
log.error("sendMessage failed with reason " + futureDirect.failedReason());
|
||||||
|
@ -98,8 +108,9 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(Throwable t) throws Exception {
|
public void exceptionCaught(Throwable t) throws Exception {
|
||||||
if (message instanceof MailboxMessage) {
|
if (p2pSigPubKey != null && p2pEncryptPubKey != null) {
|
||||||
sendMailboxMessage((MailboxMessage) message, listener);
|
log.info("sendMessage failed with exception. We will try to send the message to the mailbox. Exception: " + t.getMessage());
|
||||||
|
sendMailboxMessage(p2pSigPubKey, p2pEncryptPubKey, (MailboxMessage) message, listener);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.error("sendMessage failed with exception " + t.getMessage());
|
log.error("sendMessage failed with exception " + t.getMessage());
|
||||||
|
@ -109,11 +120,18 @@ public class TomP2PMessageService extends TomP2PService implements MessageServic
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendMailboxMessage(MailboxMessage message, SendMessageListener listener) {
|
private void sendMailboxMessage(PublicKey p2pSigPubKey, PublicKey p2pEncryptPubKey, MailboxMessage message, SendMessageListener listener) {
|
||||||
EncryptionService.Tuple tuple = encryptionService.encryptObject(user.getP2pEncryptKeyPair().getPublic(), message);
|
EncryptionPackage encryptionPackage = null;
|
||||||
|
try {
|
||||||
EncryptedMailboxMessage encrypted = new EncryptedMailboxMessage(tuple);
|
encryptionPackage = encryptionService.encryptObject(p2pEncryptPubKey, message);
|
||||||
mailboxService.addMessage(user.getP2PSigPubKey(), encrypted,
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
log.error(t.getMessage());
|
||||||
|
executor.execute(listener::handleFault);
|
||||||
|
}
|
||||||
|
EncryptedMailboxMessage encrypted = new EncryptedMailboxMessage(encryptionPackage);
|
||||||
|
mailboxService.addMessage(p2pSigPubKey,
|
||||||
|
encrypted,
|
||||||
() -> {
|
() -> {
|
||||||
log.debug("Message successfully added to peers mailbox.");
|
log.debug("Message successfully added to peers mailbox.");
|
||||||
executor.execute(listener::handleResult);
|
executor.execute(listener::handleResult);
|
||||||
|
|
|
@ -40,8 +40,8 @@ public class Contract implements Serializable {
|
||||||
private final String takerAccountID;
|
private final String takerAccountID;
|
||||||
private final FiatAccount offererFiatAccount;
|
private final FiatAccount offererFiatAccount;
|
||||||
private final FiatAccount takerFiatAccount;
|
private final FiatAccount takerFiatAccount;
|
||||||
private final String offererMessagePublicKeyAsString;
|
private final String offererP2PSigPubKeyAsString;
|
||||||
private final String takerMessagePublicKeyAsString;
|
private final String takerP2PSigPubKeyAsString;
|
||||||
|
|
||||||
public Contract(Offer offer,
|
public Contract(Offer offer,
|
||||||
Coin tradeAmount,
|
Coin tradeAmount,
|
||||||
|
@ -50,8 +50,8 @@ public class Contract implements Serializable {
|
||||||
String takerAccountID,
|
String takerAccountID,
|
||||||
FiatAccount offererFiatAccount,
|
FiatAccount offererFiatAccount,
|
||||||
FiatAccount takerFiatAccount,
|
FiatAccount takerFiatAccount,
|
||||||
PublicKey offererMessagePublicKey,
|
PublicKey offererP2PSigPubKey,
|
||||||
PublicKey takerMessagePublicKey) {
|
PublicKey takerP2PSigPubKey) {
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
this.tradeAmount = tradeAmount;
|
this.tradeAmount = tradeAmount;
|
||||||
this.takeOfferFeeTxID = takeOfferFeeTxID;
|
this.takeOfferFeeTxID = takeOfferFeeTxID;
|
||||||
|
@ -59,8 +59,8 @@ public class Contract implements Serializable {
|
||||||
this.takerAccountID = takerAccountID;
|
this.takerAccountID = takerAccountID;
|
||||||
this.offererFiatAccount = offererFiatAccount;
|
this.offererFiatAccount = offererFiatAccount;
|
||||||
this.takerFiatAccount = takerFiatAccount;
|
this.takerFiatAccount = takerFiatAccount;
|
||||||
this.offererMessagePublicKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(offererMessagePublicKey);
|
this.offererP2PSigPubKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(offererP2PSigPubKey);
|
||||||
this.takerMessagePublicKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(takerMessagePublicKey);
|
this.takerP2PSigPubKeyAsString = DSAKeyUtil.getHexStringFromPublicKey(takerP2PSigPubKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,11 +97,11 @@ public class Contract implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTakerMessagePublicKey() {
|
public String getTakerMessagePublicKey() {
|
||||||
return takerMessagePublicKeyAsString;
|
return takerP2PSigPubKeyAsString;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getOffererMessagePublicKey() {
|
public String getOffererMessagePublicKey() {
|
||||||
return offererMessagePublicKeyAsString;
|
return offererP2PSigPubKeyAsString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,8 +114,8 @@ public class Contract implements Serializable {
|
||||||
", takerAccountID='" + takerAccountID + '\'' +
|
", takerAccountID='" + takerAccountID + '\'' +
|
||||||
", offererBankAccount=" + offererFiatAccount +
|
", offererBankAccount=" + offererFiatAccount +
|
||||||
", takerBankAccount=" + takerFiatAccount +
|
", takerBankAccount=" + takerFiatAccount +
|
||||||
", takerMessagePublicKeyAsString=" + takerMessagePublicKeyAsString +
|
", takerP2PSigPubKeyAsString=" + takerP2PSigPubKeyAsString +
|
||||||
", offererMessagePublicKeyAsString=" + offererMessagePublicKeyAsString +
|
", offererP2PSigPubKeyAsString=" + offererP2PSigPubKeyAsString +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,15 @@ import io.bitsquare.btc.BlockChainService;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
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.EncryptionService;
|
||||||
import io.bitsquare.crypto.SignatureService;
|
import io.bitsquare.crypto.SignatureService;
|
||||||
import io.bitsquare.fiat.FiatAccount;
|
import io.bitsquare.fiat.FiatAccount;
|
||||||
import io.bitsquare.offer.Direction;
|
import io.bitsquare.offer.Direction;
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.offer.Offer;
|
||||||
import io.bitsquare.offer.OfferBookService;
|
import io.bitsquare.offer.OfferBookService;
|
||||||
import io.bitsquare.p2p.AddressService;
|
import io.bitsquare.p2p.AddressService;
|
||||||
|
import io.bitsquare.p2p.EncryptedMailboxMessage;
|
||||||
|
import io.bitsquare.p2p.MailboxMessage;
|
||||||
import io.bitsquare.p2p.MailboxService;
|
import io.bitsquare.p2p.MailboxService;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.MessageService;
|
import io.bitsquare.p2p.MessageService;
|
||||||
|
@ -41,6 +44,7 @@ import io.bitsquare.trade.protocol.availability.messages.ReportOfferAvailability
|
||||||
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
|
import io.bitsquare.trade.protocol.availability.messages.RequestIsOfferAvailableMessage;
|
||||||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
|
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferModel;
|
||||||
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
|
import io.bitsquare.trade.protocol.placeoffer.PlaceOfferProtocol;
|
||||||
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol;
|
import io.bitsquare.trade.protocol.trade.offerer.BuyerAsOffererProtocol;
|
||||||
import io.bitsquare.trade.protocol.trade.offerer.models.BuyerAsOffererModel;
|
import io.bitsquare.trade.protocol.trade.offerer.models.BuyerAsOffererModel;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
|
import io.bitsquare.trade.protocol.trade.taker.SellerAsTakerProtocol;
|
||||||
|
@ -54,6 +58,7 @@ import org.bitcoinj.utils.Fiat;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -78,6 +83,7 @@ public class TradeManager {
|
||||||
private final BlockChainService blockChainService;
|
private final BlockChainService blockChainService;
|
||||||
private final WalletService walletService;
|
private final WalletService walletService;
|
||||||
private final SignatureService signatureService;
|
private final SignatureService signatureService;
|
||||||
|
private EncryptionService<MailboxMessage> encryptionService;
|
||||||
private final OfferBookService offerBookService;
|
private final OfferBookService offerBookService;
|
||||||
|
|
||||||
private final Map<String, SellerAsTakerProtocol> sellerAsTakerProtocolMap = new HashMap<>();
|
private final Map<String, SellerAsTakerProtocol> sellerAsTakerProtocolMap = new HashMap<>();
|
||||||
|
@ -87,6 +93,7 @@ public class TradeManager {
|
||||||
private final ObservableMap<String, Offer> openOffers = FXCollections.observableHashMap();
|
private final ObservableMap<String, Offer> openOffers = FXCollections.observableHashMap();
|
||||||
private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap();
|
private final ObservableMap<String, Trade> pendingTrades = FXCollections.observableHashMap();
|
||||||
private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap();
|
private final ObservableMap<String, Trade> closedTrades = FXCollections.observableHashMap();
|
||||||
|
private final Map<String, MailboxMessage> mailboxMessages = new HashMap<>();
|
||||||
|
|
||||||
private Trade currentPendingTrade;
|
private Trade currentPendingTrade;
|
||||||
|
|
||||||
|
@ -98,7 +105,7 @@ public class TradeManager {
|
||||||
@Inject
|
@Inject
|
||||||
public TradeManager(User user, AccountSettings accountSettings, Persistence persistence,
|
public TradeManager(User user, AccountSettings accountSettings, Persistence persistence,
|
||||||
MessageService messageService, MailboxService mailboxService, AddressService addressService, BlockChainService blockChainService,
|
MessageService messageService, MailboxService mailboxService, AddressService addressService, BlockChainService blockChainService,
|
||||||
WalletService walletService, SignatureService signatureService,
|
WalletService walletService, SignatureService signatureService, EncryptionService<MailboxMessage> encryptionService,
|
||||||
OfferBookService offerBookService) {
|
OfferBookService offerBookService) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.accountSettings = accountSettings;
|
this.accountSettings = accountSettings;
|
||||||
|
@ -109,6 +116,7 @@ public class TradeManager {
|
||||||
this.blockChainService = blockChainService;
|
this.blockChainService = blockChainService;
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
this.signatureService = signatureService;
|
this.signatureService = signatureService;
|
||||||
|
this.encryptionService = encryptionService;
|
||||||
this.offerBookService = offerBookService;
|
this.offerBookService = offerBookService;
|
||||||
|
|
||||||
Serializable openOffersObject = persistence.read(this, "openOffers");
|
Serializable openOffersObject = persistence.read(this, "openOffers");
|
||||||
|
@ -125,10 +133,13 @@ public class TradeManager {
|
||||||
if (closedTradesObject instanceof Map<?, ?>) {
|
if (closedTradesObject instanceof Map<?, ?>) {
|
||||||
closedTrades.putAll((Map<String, Trade>) closedTradesObject);
|
closedTrades.putAll((Map<String, Trade>) closedTradesObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
messageService.addMessageHandler(this::handleMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Public API
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// When all services are initialized we create the protocols for our open offers and persisted not completed pendingTrades
|
// When all services are initialized we create the protocols for our open offers and persisted not completed pendingTrades
|
||||||
// BuyerAcceptsOfferProtocol listens for take offer requests, so we need to instantiate it early.
|
// BuyerAcceptsOfferProtocol listens for take offer requests, so we need to instantiate it early.
|
||||||
public void onAllServicesInitialized() {
|
public void onAllServicesInitialized() {
|
||||||
|
@ -161,41 +172,25 @@ public class TradeManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mailboxService.getAllMessages(user.getP2PSigPubKey(),
|
||||||
|
(messages) -> {
|
||||||
|
decryptMailboxMessages(messages);
|
||||||
|
emptyMailbox();
|
||||||
|
});
|
||||||
|
|
||||||
|
messageService.addMessageHandler(this::handleMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMyOffer(Offer offer) {
|
public boolean isMyOffer(Offer offer) {
|
||||||
return offer.getMessagePublicKey().equals(user.getP2PSigPubKey());
|
return offer.getP2PSigPubKey().equals(user.getP2PSigPubKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Called from UI
|
// Offer
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public void checkOfferAvailability(Offer offer) {
|
|
||||||
offer.setState(Offer.State.UNKNOWN);
|
|
||||||
if (!checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
|
||||||
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(
|
|
||||||
offer,
|
|
||||||
messageService,
|
|
||||||
addressService);
|
|
||||||
|
|
||||||
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
|
|
||||||
() -> disposeCheckOfferAvailabilityRequest(offer),
|
|
||||||
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
|
|
||||||
checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol);
|
|
||||||
protocol.checkOfferAvailability();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.error("That should never happen: onCheckOfferAvailability already called for offer with ID:" + offer.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// When closing take offer view, we are not interested in the onCheckOfferAvailability result anymore, so remove from the map
|
|
||||||
public void cancelGetOfferAvailableStateRequest(Offer offer) {
|
|
||||||
disposeCheckOfferAvailabilityRequest(offer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void placeOffer(String id,
|
public void placeOffer(String id,
|
||||||
Direction direction,
|
Direction direction,
|
||||||
Fiat price,
|
Fiat price,
|
||||||
|
@ -240,6 +235,35 @@ public class TradeManager {
|
||||||
removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
|
removeOpenOffer(offer, resultHandler, errorMessageHandler, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Take offer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void checkOfferAvailability(Offer offer) {
|
||||||
|
offer.setState(Offer.State.UNKNOWN);
|
||||||
|
if (!checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
||||||
|
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(
|
||||||
|
offer,
|
||||||
|
messageService,
|
||||||
|
addressService);
|
||||||
|
|
||||||
|
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
|
||||||
|
() -> disposeCheckOfferAvailabilityRequest(offer),
|
||||||
|
(errorMessage) -> disposeCheckOfferAvailabilityRequest(offer));
|
||||||
|
checkOfferAvailabilityProtocolMap.put(offer.getId(), protocol);
|
||||||
|
protocol.checkOfferAvailability();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.error("That should never happen: onCheckOfferAvailability already called for offer with ID:" + offer.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When closing take offer view, we are not interested in the onCheckOfferAvailability result anymore, so remove from the map
|
||||||
|
public void cancelCheckOfferAvailabilityRequest(Offer offer) {
|
||||||
|
disposeCheckOfferAvailabilityRequest(offer);
|
||||||
|
}
|
||||||
|
|
||||||
public void requestTakeOffer(Coin amount, Offer offer, TradeResultHandler tradeResultHandler) {
|
public void requestTakeOffer(Coin amount, Offer offer, TradeResultHandler tradeResultHandler) {
|
||||||
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(offer, messageService, addressService);
|
CheckOfferAvailabilityModel model = new CheckOfferAvailabilityModel(offer, messageService, addressService);
|
||||||
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
|
CheckOfferAvailabilityProtocol protocol = new CheckOfferAvailabilityProtocol(model,
|
||||||
|
@ -255,6 +279,138 @@ public class TradeManager {
|
||||||
protocol.checkOfferAvailability();
|
protocol.checkOfferAvailability();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Trade
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onFiatPaymentStarted(String tradeId) {
|
||||||
|
// TODO remove if check when persistence is impl.
|
||||||
|
if (buyerAcceptsOfferProtocolMap.containsKey(tradeId)) {
|
||||||
|
buyerAcceptsOfferProtocolMap.get(tradeId).onFiatPaymentStarted();
|
||||||
|
persistPendingTrades();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onFiatPaymentReceived(String tradeId) {
|
||||||
|
sellerAsTakerProtocolMap.get(tradeId).onFiatPaymentReceived();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onWithdrawAtTradeCompleted(Trade trade) {
|
||||||
|
closeTrade(trade);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Called from Offerbook when offer gets removed from DHT
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
|
||||||
|
disposeCheckOfferAvailabilityRequest(offer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Message handler
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Offerer handles those requests
|
||||||
|
private void handleMessage(Message message, Peer sender) {
|
||||||
|
if (message instanceof RequestIsOfferAvailableMessage) {
|
||||||
|
String offerId = ((RequestIsOfferAvailableMessage) message).offerId;
|
||||||
|
checkNotNull(offerId);
|
||||||
|
|
||||||
|
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offerId, isOfferOpen(offerId));
|
||||||
|
messageService.sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
|
||||||
|
@Override
|
||||||
|
public void handleResult() {
|
||||||
|
// Offerer does not do anything at that moment. Peer might only watch the offer and does nto start a trade.
|
||||||
|
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleFault() {
|
||||||
|
log.warn("Sending ReportOfferAvailabilityMessage failed.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Getters
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
public ObservableMap<String, Offer> getOpenOffers() {
|
||||||
|
return openOffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableMap<String, Trade> getPendingTrades() {
|
||||||
|
return pendingTrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableMap<String, Trade> getClosedTrades() {
|
||||||
|
return closedTrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Trade getCurrentPendingTrade() {
|
||||||
|
return currentPendingTrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Private methods
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Offer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void removeOpenOffer(Offer offer,
|
||||||
|
ResultHandler resultHandler,
|
||||||
|
ErrorMessageHandler errorMessageHandler,
|
||||||
|
boolean removeFromBuyerAcceptsOfferProtocolMap) {
|
||||||
|
String offerId = offer.getId();
|
||||||
|
offerBookService.removeOffer(offer,
|
||||||
|
() -> {
|
||||||
|
if (openOffers.containsKey(offerId)) {
|
||||||
|
openOffers.remove(offerId);
|
||||||
|
disposeCheckOfferAvailabilityRequest(offer);
|
||||||
|
persistOpenOffers();
|
||||||
|
if (removeFromBuyerAcceptsOfferProtocolMap && buyerAcceptsOfferProtocolMap.containsKey(offerId)) {
|
||||||
|
buyerAcceptsOfferProtocolMap.get(offerId).cleanup();
|
||||||
|
buyerAcceptsOfferProtocolMap.remove(offerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
resultHandler.handleResult();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.error("Locally stored offers does not contain the offer with the ID " + offerId);
|
||||||
|
errorMessageHandler.handleErrorMessage("Locally stored offers does not contain the offer with the ID " + offerId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Take offer
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void disposeCheckOfferAvailabilityRequest(Offer offer) {
|
||||||
|
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
||||||
|
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
|
||||||
|
protocol.cancel();
|
||||||
|
protocol.cleanup();
|
||||||
|
checkOfferAvailabilityProtocolMap.remove(offer.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Trade
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private Trade takeAvailableOffer(Coin amount, Offer offer, Peer peer) {
|
private Trade takeAvailableOffer(Coin amount, Offer offer, Peer peer) {
|
||||||
Trade trade = createTrade(offer);
|
Trade trade = createTrade(offer);
|
||||||
trade.setTradeAmount(amount);
|
trade.setTradeAmount(amount);
|
||||||
|
@ -264,6 +420,19 @@ public class TradeManager {
|
||||||
return trade;
|
return trade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Trade createTrade(Offer offer) {
|
||||||
|
if (pendingTrades.containsKey(offer.getId()))
|
||||||
|
log.error("That must never happen: Trades contains already an trade with the ID " + offer.getId());
|
||||||
|
|
||||||
|
Trade trade = new Trade(offer);
|
||||||
|
pendingTrades.put(offer.getId(), trade);
|
||||||
|
persistPendingTrades();
|
||||||
|
|
||||||
|
currentPendingTrade = trade;
|
||||||
|
|
||||||
|
return trade;
|
||||||
|
}
|
||||||
|
|
||||||
private SellerAsTakerProtocol createSellerAsTakerProtocol(Trade trade, Peer peer) {
|
private SellerAsTakerProtocol createSellerAsTakerProtocol(Trade trade, Peer peer) {
|
||||||
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
|
trade.stateProperty().addListener((ov, oldValue, newValue) -> {
|
||||||
log.debug("trade state = " + newValue);
|
log.debug("trade state = " + newValue);
|
||||||
|
@ -292,6 +461,7 @@ public class TradeManager {
|
||||||
trade,
|
trade,
|
||||||
peer,
|
peer,
|
||||||
messageService,
|
messageService,
|
||||||
|
mailboxService,
|
||||||
walletService,
|
walletService,
|
||||||
blockChainService,
|
blockChainService,
|
||||||
signatureService,
|
signatureService,
|
||||||
|
@ -300,122 +470,13 @@ public class TradeManager {
|
||||||
|
|
||||||
SellerAsTakerProtocol sellerTakesOfferProtocol = new SellerAsTakerProtocol(model);
|
SellerAsTakerProtocol sellerTakesOfferProtocol = new SellerAsTakerProtocol(model);
|
||||||
sellerAsTakerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol);
|
sellerAsTakerProtocolMap.put(trade.getId(), sellerTakesOfferProtocol);
|
||||||
|
|
||||||
|
if (mailboxMessages.containsKey(trade.getId()))
|
||||||
|
sellerTakesOfferProtocol.setMailboxMessage(mailboxMessages.get(trade.getId()));
|
||||||
|
|
||||||
return sellerTakesOfferProtocol;
|
return sellerTakesOfferProtocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onFiatPaymentStarted(String tradeId) {
|
|
||||||
// TODO remove if check when persistence is impl.
|
|
||||||
if (buyerAcceptsOfferProtocolMap.containsKey(tradeId)) {
|
|
||||||
buyerAcceptsOfferProtocolMap.get(tradeId).onFiatPaymentStarted();
|
|
||||||
persistPendingTrades();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onFiatPaymentReceived(String tradeId) {
|
|
||||||
sellerAsTakerProtocolMap.get(tradeId).onFiatPaymentReceived();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closeTrade(Trade trade) {
|
|
||||||
if (pendingTrades.containsKey(trade.getId())) {
|
|
||||||
pendingTrades.remove(trade.getId());
|
|
||||||
persistPendingTrades();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sellerAsTakerProtocolMap.containsKey(trade.getId())) {
|
|
||||||
sellerAsTakerProtocolMap.get(trade.getId()).cleanup();
|
|
||||||
sellerAsTakerProtocolMap.remove(trade.getId());
|
|
||||||
}
|
|
||||||
else if (buyerAcceptsOfferProtocolMap.containsKey(trade.getId())) {
|
|
||||||
buyerAcceptsOfferProtocolMap.get(trade.getId()).cleanup();
|
|
||||||
buyerAcceptsOfferProtocolMap.remove(trade.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!closedTrades.containsKey(trade.getId())) {
|
|
||||||
closedTrades.put(trade.getId(), trade);
|
|
||||||
persistClosedTrades();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Called from Offerbook when offer gets removed from DHT
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public void onOfferRemovedFromRemoteOfferBook(Offer offer) {
|
|
||||||
disposeCheckOfferAvailabilityRequest(offer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Process new tradeMessages
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Offerer handles those requests
|
|
||||||
private void handleMessage(Message message, Peer sender) {
|
|
||||||
if (message instanceof RequestIsOfferAvailableMessage) {
|
|
||||||
String offerId = ((RequestIsOfferAvailableMessage) message).offerId;
|
|
||||||
checkNotNull(offerId);
|
|
||||||
|
|
||||||
ReportOfferAvailabilityMessage reportOfferAvailabilityMessage = new ReportOfferAvailabilityMessage(offerId, isOfferOpen(offerId));
|
|
||||||
messageService.sendMessage(sender, reportOfferAvailabilityMessage, new SendMessageListener() {
|
|
||||||
@Override
|
|
||||||
public void handleResult() {
|
|
||||||
// Offerer does not do anything at that moment. Peer might only watch the offer and does nto start a trade.
|
|
||||||
log.trace("ReportOfferAvailabilityMessage successfully arrived at peer");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleFault() {
|
|
||||||
log.warn("Sending ReportOfferAvailabilityMessage failed.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
private void removeOpenOffer(Offer offer,
|
|
||||||
ResultHandler resultHandler,
|
|
||||||
ErrorMessageHandler errorMessageHandler,
|
|
||||||
boolean removeFromBuyerAcceptsOfferProtocolMap) {
|
|
||||||
String offerId = offer.getId();
|
|
||||||
offerBookService.removeOffer(offer,
|
|
||||||
() -> {
|
|
||||||
if (openOffers.containsKey(offerId)) {
|
|
||||||
openOffers.remove(offerId);
|
|
||||||
disposeCheckOfferAvailabilityRequest(offer);
|
|
||||||
persistOpenOffers();
|
|
||||||
if (removeFromBuyerAcceptsOfferProtocolMap && buyerAcceptsOfferProtocolMap.containsKey(offerId)) {
|
|
||||||
buyerAcceptsOfferProtocolMap.get(offerId).cleanup();
|
|
||||||
buyerAcceptsOfferProtocolMap.remove(offerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
resultHandler.handleResult();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.error("Locally stored offers does not contain the offer with the ID " + offerId);
|
|
||||||
errorMessageHandler.handleErrorMessage("Locally stored offers does not contain the offer with the ID " + offerId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(message, throwable) -> errorMessageHandler.handleErrorMessage(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Trade createTrade(Offer offer) {
|
|
||||||
if (pendingTrades.containsKey(offer.getId()))
|
|
||||||
log.error("That must never happen: Trades contains already an trade with the ID " + offer.getId());
|
|
||||||
|
|
||||||
Trade trade = new Trade(offer);
|
|
||||||
pendingTrades.put(offer.getId(), trade);
|
|
||||||
persistPendingTrades();
|
|
||||||
|
|
||||||
currentPendingTrade = trade;
|
|
||||||
|
|
||||||
return trade;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createBuyerAcceptsOfferProtocol(Offer offer) {
|
private void createBuyerAcceptsOfferProtocol(Offer offer) {
|
||||||
Trade trade;
|
Trade trade;
|
||||||
|
@ -482,13 +543,63 @@ public class TradeManager {
|
||||||
buyerAcceptsOfferProtocolMap.put(offer.getId(), buyerAcceptsOfferProtocol);
|
buyerAcceptsOfferProtocolMap.put(offer.getId(), buyerAcceptsOfferProtocol);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disposeCheckOfferAvailabilityRequest(Offer offer) {
|
private void closeTrade(Trade trade) {
|
||||||
if (checkOfferAvailabilityProtocolMap.containsKey(offer.getId())) {
|
if (pendingTrades.containsKey(trade.getId())) {
|
||||||
CheckOfferAvailabilityProtocol protocol = checkOfferAvailabilityProtocolMap.get(offer.getId());
|
pendingTrades.remove(trade.getId());
|
||||||
protocol.cancel();
|
persistPendingTrades();
|
||||||
protocol.cleanup();
|
|
||||||
checkOfferAvailabilityProtocolMap.remove(offer.getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sellerAsTakerProtocolMap.containsKey(trade.getId())) {
|
||||||
|
sellerAsTakerProtocolMap.get(trade.getId()).cleanup();
|
||||||
|
sellerAsTakerProtocolMap.remove(trade.getId());
|
||||||
|
}
|
||||||
|
else if (buyerAcceptsOfferProtocolMap.containsKey(trade.getId())) {
|
||||||
|
buyerAcceptsOfferProtocolMap.get(trade.getId()).cleanup();
|
||||||
|
buyerAcceptsOfferProtocolMap.remove(trade.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!closedTrades.containsKey(trade.getId())) {
|
||||||
|
closedTrades.put(trade.getId(), trade);
|
||||||
|
persistClosedTrades();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Mailbox
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
private void decryptMailboxMessages(List<EncryptedMailboxMessage> encryptedMailboxMessages) {
|
||||||
|
log.trace("applyMailboxMessage encryptedMailboxMessage.size=" + encryptedMailboxMessages.size());
|
||||||
|
for (EncryptedMailboxMessage encrypted : encryptedMailboxMessages) {
|
||||||
|
MailboxMessage mailboxMessage = null;
|
||||||
|
try {
|
||||||
|
mailboxMessage = encryptionService.decryptToObject(user.getP2pEncryptPrivateKey(), encrypted.getEncryptionPackage());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
if (mailboxMessage instanceof TradeMessage) {
|
||||||
|
String tradeId = ((TradeMessage) mailboxMessage).tradeId;
|
||||||
|
mailboxMessages.put(tradeId, mailboxMessage);
|
||||||
|
log.trace("mailboxMessage with tradeID " + tradeId);
|
||||||
|
if (sellerAsTakerProtocolMap.containsKey(tradeId)) {
|
||||||
|
sellerAsTakerProtocolMap.get(tradeId).setMailboxMessage(encrypted);
|
||||||
|
log.trace("sellerAsTakerProtocolMap exist with tradeID " + tradeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void emptyMailbox() {
|
||||||
|
mailboxService.removeAllMessages(user.getP2PSigPubKey(),
|
||||||
|
() -> {
|
||||||
|
log.debug("All mailbox entries removed");
|
||||||
|
},
|
||||||
|
(errorMessage, fault) -> {
|
||||||
|
log.error(errorMessage);
|
||||||
|
log.error(fault.getMessage());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isOfferOpen(String offerId) {
|
boolean isOfferOpen(String offerId) {
|
||||||
|
@ -498,31 +609,6 @@ public class TradeManager {
|
||||||
|| openOffers.get(offerId).getState() == Offer.State.AVAILABLE);
|
|| openOffers.get(offerId).getState() == Offer.State.AVAILABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Getters
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public ObservableMap<String, Offer> getOpenOffers() {
|
|
||||||
return openOffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableMap<String, Trade> getPendingTrades() {
|
|
||||||
return pendingTrades;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableMap<String, Trade> getClosedTrades() {
|
|
||||||
return closedTrades;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Trade getCurrentPendingTrade() {
|
|
||||||
return currentPendingTrade;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Private
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
private void persistOpenOffers() {
|
private void persistOpenOffers() {
|
||||||
persistence.write(this, "openOffers", (Map<String, Offer>) new HashMap<>(openOffers));
|
persistence.write(this, "openOffers", (Map<String, Offer>) new HashMap<>(openOffers));
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class GetPeerAddress extends Task<CheckOfferAvailabilityModel> {
|
||||||
@Override
|
@Override
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
try {
|
try {
|
||||||
model.addressService.findPeerAddress(model.offer.getMessagePublicKey(), new GetPeerAddressListener() {
|
model.addressService.findPeerAddress(model.offer.getP2PSigPubKey(), new GetPeerAddressListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onResult(Peer peer) {
|
public void onResult(Peer peer) {
|
||||||
model.setPeer(peer);
|
model.setPeer(peer);
|
||||||
|
|
|
@ -22,8 +22,10 @@ import io.bitsquare.btc.TradeWalletService;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.common.taskrunner.SharedTaskModel;
|
import io.bitsquare.common.taskrunner.SharedTaskModel;
|
||||||
import io.bitsquare.crypto.SignatureService;
|
import io.bitsquare.crypto.SignatureService;
|
||||||
import io.bitsquare.p2p.MessageService;
|
|
||||||
import io.bitsquare.offer.Offer;
|
import io.bitsquare.offer.Offer;
|
||||||
|
import io.bitsquare.p2p.MailboxMessage;
|
||||||
|
import io.bitsquare.p2p.MailboxService;
|
||||||
|
import io.bitsquare.p2p.MessageService;
|
||||||
import io.bitsquare.persistence.Persistence;
|
import io.bitsquare.persistence.Persistence;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
|
|
||||||
|
@ -39,11 +41,14 @@ public class SharedTradeModel extends SharedTaskModel implements Serializable {
|
||||||
// provided
|
// provided
|
||||||
transient public final Offer offer;
|
transient public final Offer offer;
|
||||||
transient public final MessageService messageService;
|
transient public final MessageService messageService;
|
||||||
|
transient public final MailboxService mailboxService;
|
||||||
transient public final WalletService walletService;
|
transient public final WalletService walletService;
|
||||||
transient public final BlockChainService blockChainService;
|
transient public final BlockChainService blockChainService;
|
||||||
transient public final SignatureService signatureService;
|
transient public final SignatureService signatureService;
|
||||||
transient protected final Persistence persistence;
|
transient protected final Persistence persistence;
|
||||||
|
|
||||||
|
transient public MailboxMessage mailboxMessage;
|
||||||
|
|
||||||
// derived
|
// derived
|
||||||
transient public final String id;
|
transient public final String id;
|
||||||
transient public final TradeWalletService tradeWalletService;
|
transient public final TradeWalletService tradeWalletService;
|
||||||
|
@ -54,12 +59,14 @@ public class SharedTradeModel extends SharedTaskModel implements Serializable {
|
||||||
|
|
||||||
protected SharedTradeModel(Offer offer,
|
protected SharedTradeModel(Offer offer,
|
||||||
MessageService messageService,
|
MessageService messageService,
|
||||||
|
MailboxService mailboxService,
|
||||||
WalletService walletService,
|
WalletService walletService,
|
||||||
BlockChainService blockChainService,
|
BlockChainService blockChainService,
|
||||||
SignatureService signatureService,
|
SignatureService signatureService,
|
||||||
Persistence persistence) {
|
Persistence persistence) {
|
||||||
this.offer = offer;
|
this.offer = offer;
|
||||||
this.messageService = messageService;
|
this.messageService = messageService;
|
||||||
|
this.mailboxService = mailboxService;
|
||||||
this.walletService = walletService;
|
this.walletService = walletService;
|
||||||
this.blockChainService = blockChainService;
|
this.blockChainService = blockChainService;
|
||||||
this.signatureService = signatureService;
|
this.signatureService = signatureService;
|
||||||
|
|
|
@ -23,7 +23,7 @@ import org.bitcoinj.core.Coin;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
public class BankTransferStartedMessage extends TradeMessage implements MailboxMessage, Serializable {
|
public class FiatTransferStartedMessage extends TradeMessage implements MailboxMessage, Serializable {
|
||||||
private static final long serialVersionUID = -3479634129543632523L;
|
private static final long serialVersionUID = -3479634129543632523L;
|
||||||
|
|
||||||
public final byte[] offererSignature;
|
public final byte[] offererSignature;
|
||||||
|
@ -31,7 +31,7 @@ public class BankTransferStartedMessage extends TradeMessage implements MailboxM
|
||||||
public final Coin takerPayoutAmount;
|
public final Coin takerPayoutAmount;
|
||||||
public final String offererPayoutAddress;
|
public final String offererPayoutAddress;
|
||||||
|
|
||||||
public BankTransferStartedMessage(String tradeId,
|
public FiatTransferStartedMessage(String tradeId,
|
||||||
byte[] offererSignature,
|
byte[] offererSignature,
|
||||||
Coin offererPayoutAmount,
|
Coin offererPayoutAmount,
|
||||||
Coin takerPayoutAmount,
|
Coin takerPayoutAmount,
|
|
@ -33,7 +33,8 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
|
||||||
|
|
||||||
public final FiatAccount takerFiatAccount;
|
public final FiatAccount takerFiatAccount;
|
||||||
public final String takerAccountId;
|
public final String takerAccountId;
|
||||||
public final PublicKey takerMessagePublicKey;
|
public final PublicKey takerP2PSigPublicKey;
|
||||||
|
public final PublicKey takerP2PEncryptPublicKey;
|
||||||
public final String takerContractAsJson;
|
public final String takerContractAsJson;
|
||||||
public final String takerContractSignature;
|
public final String takerContractSignature;
|
||||||
public final String takerPayoutAddressString;
|
public final String takerPayoutAddressString;
|
||||||
|
@ -44,7 +45,8 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
|
||||||
public RequestOffererPublishDepositTxMessage(String tradeId,
|
public RequestOffererPublishDepositTxMessage(String tradeId,
|
||||||
FiatAccount takerFiatAccount,
|
FiatAccount takerFiatAccount,
|
||||||
String takerAccountId,
|
String takerAccountId,
|
||||||
PublicKey takerMessagePublicKey,
|
PublicKey takerP2PSigPublicKey,
|
||||||
|
PublicKey takerP2PEncryptPublicKey,
|
||||||
String takerContractAsJson,
|
String takerContractAsJson,
|
||||||
String takerContractSignature,
|
String takerContractSignature,
|
||||||
String takerPayoutAddressString,
|
String takerPayoutAddressString,
|
||||||
|
@ -54,7 +56,8 @@ public class RequestOffererPublishDepositTxMessage extends TradeMessage implemen
|
||||||
this.tradeId = tradeId;
|
this.tradeId = tradeId;
|
||||||
this.takerFiatAccount = takerFiatAccount;
|
this.takerFiatAccount = takerFiatAccount;
|
||||||
this.takerAccountId = takerAccountId;
|
this.takerAccountId = takerAccountId;
|
||||||
this.takerMessagePublicKey = takerMessagePublicKey;
|
this.takerP2PSigPublicKey = takerP2PSigPublicKey;
|
||||||
|
this.takerP2PEncryptPublicKey = takerP2PEncryptPublicKey;
|
||||||
this.takerContractAsJson = takerContractAsJson;
|
this.takerContractAsJson = takerContractAsJson;
|
||||||
this.takerContractSignature = takerContractSignature;
|
this.takerContractSignature = takerContractSignature;
|
||||||
this.takerPayoutAddressString = takerPayoutAddressString;
|
this.takerPayoutAddressString = takerPayoutAddressString;
|
||||||
|
|
|
@ -37,7 +37,6 @@ public class BuyerAsOffererModel extends SharedTradeModel implements Serializabl
|
||||||
private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererModel.class);
|
private static final Logger log = LoggerFactory.getLogger(BuyerAsOffererModel.class);
|
||||||
|
|
||||||
transient public final Trade trade;
|
transient public final Trade trade;
|
||||||
transient public final MailboxService mailboxService;
|
|
||||||
public final TakerModel taker;
|
public final TakerModel taker;
|
||||||
public final OffererModel offerer;
|
public final OffererModel offerer;
|
||||||
|
|
||||||
|
@ -54,13 +53,13 @@ public class BuyerAsOffererModel extends SharedTradeModel implements Serializabl
|
||||||
Persistence persistence) {
|
Persistence persistence) {
|
||||||
super(trade.getOffer(),
|
super(trade.getOffer(),
|
||||||
messageService,
|
messageService,
|
||||||
|
mailboxService,
|
||||||
walletService,
|
walletService,
|
||||||
blockChainService,
|
blockChainService,
|
||||||
signatureService,
|
signatureService,
|
||||||
persistence);
|
persistence);
|
||||||
|
|
||||||
this.trade = trade;
|
this.trade = trade;
|
||||||
this.mailboxService = mailboxService;
|
|
||||||
|
|
||||||
Serializable serializable = persistence.read(this, "BuyerAsOffererModel_" + id);
|
Serializable serializable = persistence.read(this, "BuyerAsOffererModel_" + id);
|
||||||
if (serializable instanceof BuyerAsOffererModel) {
|
if (serializable instanceof BuyerAsOffererModel) {
|
||||||
|
|
|
@ -38,6 +38,7 @@ public class TakerModel implements Serializable {
|
||||||
public String accountId;
|
public String accountId;
|
||||||
public FiatAccount fiatAccount;
|
public FiatAccount fiatAccount;
|
||||||
public PublicKey p2pSigPublicKey;
|
public PublicKey p2pSigPublicKey;
|
||||||
|
public PublicKey p2pEncryptPubKey;
|
||||||
public String contractAsJson;//TODO only write access now, missing impl.
|
public String contractAsJson;//TODO only write access now, missing impl.
|
||||||
public String contractSignature;
|
public String contractSignature;
|
||||||
public Coin payoutAmount;
|
public Coin payoutAmount;
|
||||||
|
|
|
@ -43,7 +43,8 @@ public class ProcessRequestOffererPublishDepositTxMessage extends Task<BuyerAsOf
|
||||||
|
|
||||||
model.taker.fiatAccount = checkNotNull(message.takerFiatAccount);
|
model.taker.fiatAccount = checkNotNull(message.takerFiatAccount);
|
||||||
model.taker.accountId = nonEmptyStringOf(message.takerAccountId);
|
model.taker.accountId = nonEmptyStringOf(message.takerAccountId);
|
||||||
model.taker.p2pSigPublicKey = checkNotNull(message.takerMessagePublicKey);
|
model.taker.p2pSigPublicKey = checkNotNull(message.takerP2PSigPublicKey);
|
||||||
|
model.taker.p2pEncryptPubKey = checkNotNull(message.takerP2PEncryptPublicKey);
|
||||||
model.taker.contractAsJson = nonEmptyStringOf(message.takerContractAsJson);
|
model.taker.contractAsJson = nonEmptyStringOf(message.takerContractAsJson);
|
||||||
model.taker.contractSignature = nonEmptyStringOf(message.takerContractSignature);
|
model.taker.contractSignature = nonEmptyStringOf(message.takerContractSignature);
|
||||||
model.taker.payoutAddressString = nonEmptyStringOf(message.takerPayoutAddressString);
|
model.taker.payoutAddressString = nonEmptyStringOf(message.takerPayoutAddressString);
|
||||||
|
|
|
@ -20,7 +20,8 @@ package io.bitsquare.trade.protocol.trade.offerer.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.listener.SendMessageListener;
|
import io.bitsquare.p2p.listener.SendMessageListener;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.BankTransferStartedMessage;
|
import io.bitsquare.trade.Trade;
|
||||||
|
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.offerer.models.BuyerAsOffererModel;
|
import io.bitsquare.trade.protocol.trade.offerer.models.BuyerAsOffererModel;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -36,26 +37,32 @@ public class SendBankTransferStartedMessage extends Task<BuyerAsOffererModel> {
|
||||||
@Override
|
@Override
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
try {
|
try {
|
||||||
BankTransferStartedMessage tradeMessage = new BankTransferStartedMessage(
|
FiatTransferStartedMessage tradeMessage = new FiatTransferStartedMessage(model.id,
|
||||||
model.id,
|
|
||||||
model.offerer.payoutTxSignature,
|
model.offerer.payoutTxSignature,
|
||||||
model.offerer.payoutAmount,
|
model.offerer.payoutAmount,
|
||||||
model.taker.payoutAmount,
|
model.taker.payoutAmount,
|
||||||
model.offerer.addressEntry.getAddressString());
|
model.offerer.addressEntry.getAddressString());
|
||||||
model.messageService.sendMessage(model.taker.peer, tradeMessage, new SendMessageListener() {
|
|
||||||
|
model.messageService.sendMessage(model.taker.peer, tradeMessage,
|
||||||
|
model.taker.p2pSigPublicKey,
|
||||||
|
model.taker.p2pEncryptPubKey,
|
||||||
|
new SendMessageListener() {
|
||||||
@Override
|
@Override
|
||||||
public void handleResult() {
|
public void handleResult() {
|
||||||
log.trace("Sending BankTransferInitedMessage succeeded.");
|
log.trace("Sending BankTransferInitedMessage succeeded.");
|
||||||
|
model.trade.setState(Trade.State.FIAT_PAYMENT_STARTED);
|
||||||
complete();
|
complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleFault() {
|
public void handleFault() {
|
||||||
failed("Sending BankTransferInitedMessage failed.");
|
failed("Sending BankTransferInitedMessage failed.");
|
||||||
|
model.trade.setState(Trade.State.FAULT);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
failed("Sending BankTransferInitedMessage failed.");
|
failed("Sending BankTransferInitedMessage failed.");
|
||||||
|
model.trade.setState(Trade.State.FAULT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,20 +18,21 @@
|
||||||
package io.bitsquare.trade.protocol.trade.taker;
|
package io.bitsquare.trade.protocol.trade.taker;
|
||||||
|
|
||||||
import io.bitsquare.common.taskrunner.TaskRunner;
|
import io.bitsquare.common.taskrunner.TaskRunner;
|
||||||
|
import io.bitsquare.p2p.MailboxMessage;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
import io.bitsquare.p2p.MessageHandler;
|
import io.bitsquare.p2p.MessageHandler;
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.trade.Trade;
|
import io.bitsquare.trade.Trade;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.BankTransferStartedMessage;
|
|
||||||
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
import io.bitsquare.trade.protocol.trade.messages.DepositTxPublishedMessage;
|
||||||
|
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.RequestDepositPaymentMessage;
|
import io.bitsquare.trade.protocol.trade.messages.RequestDepositPaymentMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
import io.bitsquare.trade.protocol.trade.messages.TradeMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
|
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.BroadcastTakeOfferFeeTx;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateAndSignContract;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.CreateTakeOfferFeeTx;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessBankTransferStartedMessage;
|
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessDepositTxPublishedMessage;
|
||||||
|
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessFiatTransferStartedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.ProcessRequestDepositPaymentMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.SendPayoutTxToOfferer;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage;
|
import io.bitsquare.trade.protocol.trade.taker.tasks.SendRequestDepositTxInputsMessage;
|
||||||
|
@ -70,6 +71,8 @@ public class SellerAsTakerProtocol {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
messageHandler = this::handleMessage;
|
messageHandler = this::handleMessage;
|
||||||
model.messageService.addMessageHandler(messageHandler);
|
model.messageService.addMessageHandler(messageHandler);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,6 +85,17 @@ public class SellerAsTakerProtocol {
|
||||||
model.messageService.removeMessageHandler(messageHandler);
|
model.messageService.removeMessageHandler(messageHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMailboxMessage(MailboxMessage mailboxMessage) {
|
||||||
|
log.debug("setMailboxMessage " + mailboxMessage);
|
||||||
|
// Might be called twice, so check that its only processed once
|
||||||
|
if (model.mailboxMessage == null) {
|
||||||
|
model.mailboxMessage = mailboxMessage;
|
||||||
|
if (mailboxMessage instanceof FiatTransferStartedMessage) {
|
||||||
|
handleFiatTransferStartedMessage((FiatTransferStartedMessage) mailboxMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void takeAvailableOffer() {
|
public void takeAvailableOffer() {
|
||||||
TaskRunner<SellerAsTakerModel> taskRunner = new TaskRunner<>(model,
|
TaskRunner<SellerAsTakerModel> taskRunner = new TaskRunner<>(model,
|
||||||
() -> {
|
() -> {
|
||||||
|
@ -143,19 +157,19 @@ public class SellerAsTakerProtocol {
|
||||||
taskRunner.run();
|
taskRunner.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBankTransferStartedMessage(BankTransferStartedMessage tradeMessage) {
|
private void handleFiatTransferStartedMessage(FiatTransferStartedMessage tradeMessage) {
|
||||||
model.setTradeMessage(tradeMessage);
|
model.setTradeMessage(tradeMessage);
|
||||||
|
|
||||||
TaskRunner<SellerAsTakerModel> taskRunner = new TaskRunner<>(model,
|
TaskRunner<SellerAsTakerModel> taskRunner = new TaskRunner<>(model,
|
||||||
() -> {
|
() -> {
|
||||||
log.debug("taskRunner at handleBankTransferInitedMessage completed");
|
log.debug("taskRunner at handleFiatTransferStartedMessage completed");
|
||||||
model.trade.setState(Trade.State.FIAT_PAYMENT_STARTED);
|
model.trade.setState(Trade.State.FIAT_PAYMENT_STARTED);
|
||||||
},
|
},
|
||||||
(errorMessage) -> {
|
(errorMessage) -> {
|
||||||
log.error(errorMessage);
|
log.error(errorMessage);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
taskRunner.addTasks(ProcessBankTransferStartedMessage.class);
|
taskRunner.addTasks(ProcessFiatTransferStartedMessage.class);
|
||||||
taskRunner.run();
|
taskRunner.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,8 +215,8 @@ public class SellerAsTakerProtocol {
|
||||||
else if (tradeMessage instanceof DepositTxPublishedMessage) {
|
else if (tradeMessage instanceof DepositTxPublishedMessage) {
|
||||||
handleDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
|
handleDepositTxPublishedMessage((DepositTxPublishedMessage) tradeMessage);
|
||||||
}
|
}
|
||||||
else if (tradeMessage instanceof BankTransferStartedMessage) {
|
else if (tradeMessage instanceof FiatTransferStartedMessage) {
|
||||||
handleBankTransferStartedMessage((BankTransferStartedMessage) tradeMessage);
|
handleFiatTransferStartedMessage((FiatTransferStartedMessage) tradeMessage);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
log.error("Incoming message not supported. " + tradeMessage);
|
log.error("Incoming message not supported. " + tradeMessage);
|
||||||
|
|
|
@ -20,6 +20,7 @@ package io.bitsquare.trade.protocol.trade.taker.models;
|
||||||
import io.bitsquare.btc.BlockChainService;
|
import io.bitsquare.btc.BlockChainService;
|
||||||
import io.bitsquare.btc.WalletService;
|
import io.bitsquare.btc.WalletService;
|
||||||
import io.bitsquare.crypto.SignatureService;
|
import io.bitsquare.crypto.SignatureService;
|
||||||
|
import io.bitsquare.p2p.MailboxService;
|
||||||
import io.bitsquare.p2p.MessageService;
|
import io.bitsquare.p2p.MessageService;
|
||||||
import io.bitsquare.p2p.Peer;
|
import io.bitsquare.p2p.Peer;
|
||||||
import io.bitsquare.persistence.Persistence;
|
import io.bitsquare.persistence.Persistence;
|
||||||
|
@ -49,6 +50,7 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
|
||||||
public SellerAsTakerModel(Trade trade,
|
public SellerAsTakerModel(Trade trade,
|
||||||
Peer offererPeer,
|
Peer offererPeer,
|
||||||
MessageService messageService,
|
MessageService messageService,
|
||||||
|
MailboxService mailboxService,
|
||||||
WalletService walletService,
|
WalletService walletService,
|
||||||
BlockChainService blockChainService,
|
BlockChainService blockChainService,
|
||||||
SignatureService signatureService,
|
SignatureService signatureService,
|
||||||
|
@ -56,6 +58,7 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
|
||||||
Persistence persistence) {
|
Persistence persistence) {
|
||||||
super(trade.getOffer(),
|
super(trade.getOffer(),
|
||||||
messageService,
|
messageService,
|
||||||
|
mailboxService,
|
||||||
walletService,
|
walletService,
|
||||||
blockChainService,
|
blockChainService,
|
||||||
signatureService,
|
signatureService,
|
||||||
|
@ -87,6 +90,7 @@ public class SellerAsTakerModel extends SharedTradeModel implements Serializable
|
||||||
taker.fiatAccount = user.getBankAccount(offer.getBankAccountId());
|
taker.fiatAccount = user.getBankAccount(offer.getBankAccountId());
|
||||||
taker.accountId = user.getAccountId();
|
taker.accountId = user.getAccountId();
|
||||||
taker.p2pSigPubKey = user.getP2PSigPubKey();
|
taker.p2pSigPubKey = user.getP2PSigPubKey();
|
||||||
|
taker.p2pEncryptPublicKey = user.getP2PEncryptPubKey();
|
||||||
taker.pubKey = taker.addressEntry.getPubKey();
|
taker.pubKey = taker.addressEntry.getPubKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class TakerModel implements Serializable {
|
||||||
transient public FiatAccount fiatAccount;
|
transient public FiatAccount fiatAccount;
|
||||||
transient public String accountId;
|
transient public String accountId;
|
||||||
transient public PublicKey p2pSigPubKey;
|
transient public PublicKey p2pSigPubKey;
|
||||||
|
transient public PublicKey p2pEncryptPublicKey;
|
||||||
transient public byte[] registrationPubKey; // TODO not read yet, missing impl.
|
transient public byte[] registrationPubKey; // TODO not read yet, missing impl.
|
||||||
transient public DeterministicKey registrationKeyPair;
|
transient public DeterministicKey registrationKeyPair;
|
||||||
transient public AddressEntry addressEntry;
|
transient public AddressEntry addressEntry;
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class CreateAndSignContract extends Task<SellerAsTakerModel> {
|
||||||
model.taker.accountId,
|
model.taker.accountId,
|
||||||
model.offerer.fiatAccount,
|
model.offerer.fiatAccount,
|
||||||
model.taker.fiatAccount,
|
model.taker.fiatAccount,
|
||||||
model.offer.getMessagePublicKey(),
|
model.offer.getP2PSigPubKey(),
|
||||||
model.taker.p2pSigPubKey);
|
model.taker.p2pSigPubKey);
|
||||||
String contractAsJson = Utilities.objectToJson(contract);
|
String contractAsJson = Utilities.objectToJson(contract);
|
||||||
String signature = model.signatureService.signMessage(model.taker.registrationKeyPair, contractAsJson);
|
String signature = model.signatureService.signMessage(model.taker.registrationKeyPair, contractAsJson);
|
||||||
|
|
|
@ -19,7 +19,7 @@ package io.bitsquare.trade.protocol.trade.taker.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.trade.protocol.trade.messages.BankTransferStartedMessage;
|
import io.bitsquare.trade.protocol.trade.messages.FiatTransferStartedMessage;
|
||||||
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
|
import io.bitsquare.trade.protocol.trade.taker.models.SellerAsTakerModel;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -28,10 +28,10 @@ import org.slf4j.LoggerFactory;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static io.bitsquare.util.Validator.*;
|
import static io.bitsquare.util.Validator.*;
|
||||||
|
|
||||||
public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel> {
|
public class ProcessFiatTransferStartedMessage extends Task<SellerAsTakerModel> {
|
||||||
private static final Logger log = LoggerFactory.getLogger(ProcessBankTransferStartedMessage.class);
|
private static final Logger log = LoggerFactory.getLogger(ProcessFiatTransferStartedMessage.class);
|
||||||
|
|
||||||
public ProcessBankTransferStartedMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
|
public ProcessFiatTransferStartedMessage(TaskRunner taskHandler, SellerAsTakerModel model) {
|
||||||
super(taskHandler, model);
|
super(taskHandler, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ public class ProcessBankTransferStartedMessage extends Task<SellerAsTakerModel>
|
||||||
protected void doRun() {
|
protected void doRun() {
|
||||||
try {
|
try {
|
||||||
checkTradeId(model.id, model.getTradeMessage());
|
checkTradeId(model.id, model.getTradeMessage());
|
||||||
BankTransferStartedMessage message = (BankTransferStartedMessage) model.getTradeMessage();
|
FiatTransferStartedMessage message = (FiatTransferStartedMessage) model.getTradeMessage();
|
||||||
|
|
||||||
model.offerer.signature = checkNotNull(message.offererSignature);
|
model.offerer.signature = checkNotNull(message.offererSignature);
|
||||||
model.offerer.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount));
|
model.offerer.payoutAmount = positiveCoinOf(nonZeroCoinOf(message.offererPayoutAmount));
|
|
@ -40,6 +40,7 @@ public class SendSignedTakerDepositTx extends Task<SellerAsTakerModel> {
|
||||||
model.taker.fiatAccount,
|
model.taker.fiatAccount,
|
||||||
model.taker.accountId,
|
model.taker.accountId,
|
||||||
model.taker.p2pSigPubKey,
|
model.taker.p2pSigPubKey,
|
||||||
|
model.taker.p2pEncryptPublicKey,
|
||||||
model.trade.getContractAsJson(),
|
model.trade.getContractAsJson(),
|
||||||
model.trade.getTakerContractSignature(),
|
model.trade.getTakerContractSignature(),
|
||||||
model.taker.addressEntry.getAddressString(),
|
model.taker.addressEntry.getAddressString(),
|
||||||
|
|
|
@ -24,6 +24,8 @@ import io.bitsquare.util.DSAKeyUtil;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -39,12 +41,16 @@ import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ListChangeListener;
|
import javafx.collections.ListChangeListener;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The User is persisted locally.
|
* The User is persisted locally.
|
||||||
* It must never be transmitted over the wire (messageKeyPair contains private key!).
|
* It must never be transmitted over the wire (messageKeyPair contains private key!).
|
||||||
*/
|
*/
|
||||||
public class User implements Serializable {
|
public class User implements Serializable {
|
||||||
private static final long serialVersionUID = 7409078808248518638L;
|
private static final long serialVersionUID = 7409078808248518638L;
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(User.class);
|
||||||
|
|
||||||
private KeyPair p2pSigKeyPair;
|
private KeyPair p2pSigKeyPair;
|
||||||
private KeyPair p2pEncryptKeyPair;
|
private KeyPair p2pEncryptKeyPair;
|
||||||
|
@ -87,8 +93,13 @@ public class User implements Serializable {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// First time
|
// First time
|
||||||
p2pSigKeyPair = DSAKeyUtil.generateKeyPair();
|
p2pSigKeyPair = DSAKeyUtil.generateDSAKeyPair();
|
||||||
|
try {
|
||||||
p2pEncryptKeyPair = encryptionService.getKeyPair();
|
p2pEncryptKeyPair = encryptionService.getKeyPair();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +190,10 @@ public class User implements Serializable {
|
||||||
return p2pSigKeyPair.getPublic();
|
return p2pSigKeyPair.getPublic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PublicKey getP2PEncryptPubKey() {
|
||||||
|
return p2pEncryptKeyPair.getPublic();
|
||||||
|
}
|
||||||
|
|
||||||
public ObjectProperty<FiatAccount> currentBankAccountProperty() {
|
public ObjectProperty<FiatAccount> currentBankAccountProperty() {
|
||||||
return currentBankAccount;
|
return currentBankAccount;
|
||||||
}
|
}
|
||||||
|
@ -192,7 +207,11 @@ public class User implements Serializable {
|
||||||
return _currentFiatAccount;
|
return _currentFiatAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyPair getP2pEncryptKeyPair() {
|
public PrivateKey getP2pEncryptPrivateKey() {
|
||||||
|
return p2pEncryptKeyPair.getPrivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyPair getP2pEncryptKeyPair() {
|
||||||
return p2pEncryptKeyPair;
|
return p2pEncryptKeyPair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ public class DSAKeyUtil {
|
||||||
return Utils.HEX.encode(x509EncodedKeySpec.getEncoded());
|
return Utils.HEX.encode(x509EncodedKeySpec.getEncoded());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static KeyPair generateKeyPair() {
|
public static KeyPair generateDSAKeyPair() {
|
||||||
try {
|
try {
|
||||||
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
|
final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
|
||||||
keyGen.initialize(1024);
|
keyGen.initialize(1024);
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* This file is part of Bitsquare.
|
||||||
|
*
|
||||||
|
* Bitsquare is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* Bitsquare is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||||
|
* License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.bitsquare.crypto;
|
||||||
|
|
||||||
|
import io.bitsquare.p2p.MailboxMessage;
|
||||||
|
|
||||||
|
import java.security.KeyPair;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import static org.springframework.test.util.AssertionErrors.assertEquals;
|
||||||
|
|
||||||
|
public class EncryptionServiceTests {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(EncryptionServiceTests.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncryptionWithMailboxMessage() throws Exception {
|
||||||
|
EncryptionService<MailboxMessage> encryptionService = new EncryptionService<>();
|
||||||
|
KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair();
|
||||||
|
|
||||||
|
TestMessage message = new TestMessage("test");
|
||||||
|
EncryptionPackage encryptionPackage = encryptionService.encryptObject(p2pEncryptKeyPair.getPublic(), message);
|
||||||
|
MailboxMessage result = encryptionService.decryptToObject(p2pEncryptKeyPair.getPrivate(), encryptionPackage);
|
||||||
|
assertEquals("", message.data, ((TestMessage) result).data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncryptionWithInteger() throws Exception {
|
||||||
|
EncryptionService<Integer> encryptionService = new EncryptionService<>();
|
||||||
|
KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair();
|
||||||
|
int data = 1234;
|
||||||
|
EncryptionPackage encryptionPackage = encryptionService.encryptObject(p2pEncryptKeyPair.getPublic(), data);
|
||||||
|
Integer result = encryptionService.decryptToObject(p2pEncryptKeyPair.getPrivate(), encryptionPackage);
|
||||||
|
assertEquals("", data, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncryptionWithBytes() throws Exception {
|
||||||
|
EncryptionService encryptionService = new EncryptionService();
|
||||||
|
KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair();
|
||||||
|
|
||||||
|
byte[] data = new byte[]{0x00, 0x01, 0x02, 0x03, 0x04};
|
||||||
|
EncryptionPackage encryptionPackage = encryptionService.encrypt(p2pEncryptKeyPair.getPublic(), data);
|
||||||
|
byte[] result = encryptionService.decrypt(p2pEncryptKeyPair.getPrivate(), encryptionPackage);
|
||||||
|
assertEquals("", result, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncryptionWithLargeData() throws Exception {
|
||||||
|
EncryptionService encryptionService = new EncryptionService();
|
||||||
|
KeyPair p2pEncryptKeyPair = encryptionService.getKeyPair();
|
||||||
|
|
||||||
|
byte[] data = new byte[2000];
|
||||||
|
new Random().nextBytes(data);
|
||||||
|
|
||||||
|
EncryptionPackage encryptionPackage = encryptionService.encrypt(p2pEncryptKeyPair.getPublic(), data);
|
||||||
|
byte[] result = encryptionService.decrypt(p2pEncryptKeyPair.getPrivate(), encryptionPackage);
|
||||||
|
assertEquals("", result, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestMessage implements MailboxMessage {
|
||||||
|
public String data = "test";
|
||||||
|
|
||||||
|
public TestMessage(String data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -296,7 +296,7 @@ public class PlaceOfferProtocolTest {
|
||||||
|
|
||||||
private Offer getOffer() {
|
private Offer getOffer() {
|
||||||
return new Offer(OFFER_ID,
|
return new Offer(OFFER_ID,
|
||||||
DSAKeyUtil.generateKeyPair().getPublic(),
|
DSAKeyUtil.generateDSAKeyPair().getPublic(),
|
||||||
Direction.BUY,
|
Direction.BUY,
|
||||||
100L,
|
100L,
|
||||||
Coin.CENT,
|
Coin.CENT,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue