mirror of
https://github.com/haveno-dex/haveno.git
synced 2025-08-03 20:24:24 -04:00
Handle offer removal on disconnect, cleanup
This commit is contained in:
parent
db363fac48
commit
17c780639f
69 changed files with 377 additions and 367 deletions
|
@ -18,7 +18,7 @@
|
|||
package io.bitsquare.alert;
|
||||
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.p2p.storage.data.StorageMessage;
|
||||
import io.bitsquare.p2p.storage.messages.StorageMessage;
|
||||
|
||||
import java.security.PublicKey;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
|
|
@ -20,7 +20,7 @@ package io.bitsquare.alert;
|
|||
import com.google.inject.Inject;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
||||
import io.bitsquare.p2p.storage.ProtectedData;
|
||||
import io.bitsquare.user.User;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
|
@ -30,7 +30,6 @@ import org.bitcoinj.core.Utils;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.security.SignatureException;
|
||||
|
||||
|
@ -61,20 +60,18 @@ public class AlertManager {
|
|||
|
||||
alertService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||
@Override
|
||||
public void onAdded(ProtectedData entry) {
|
||||
Serializable data = entry.expirableMessage;
|
||||
if (data instanceof Alert) {
|
||||
Alert alert = (Alert) data;
|
||||
public void onAdded(ProtectedData data) {
|
||||
if (data.expirableMessage instanceof Alert) {
|
||||
Alert alert = (Alert) data.expirableMessage;
|
||||
if (verifySignature(alert))
|
||||
alertMessageProperty.set(alert);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(ProtectedData entry) {
|
||||
Serializable data = entry.expirableMessage;
|
||||
if (data instanceof Alert) {
|
||||
Alert alert = (Alert) data;
|
||||
public void onRemoved(ProtectedData data) {
|
||||
if (data.expirableMessage instanceof Alert) {
|
||||
Alert alert = (Alert) data.expirableMessage;
|
||||
if (verifySignature(alert))
|
||||
alertMessageProperty.set(null);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ package io.bitsquare.arbitration;
|
|||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.common.crypto.PubKeyRing;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.storage.data.StorageMessage;
|
||||
import io.bitsquare.p2p.storage.messages.StorageMessage;
|
||||
|
||||
import java.security.PublicKey;
|
||||
import java.util.Arrays;
|
||||
|
|
|
@ -30,7 +30,7 @@ import io.bitsquare.p2p.BootstrapListener;
|
|||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
||||
import io.bitsquare.p2p.storage.ProtectedData;
|
||||
import io.bitsquare.user.User;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableMap;
|
||||
|
@ -101,12 +101,12 @@ public class ArbitratorManager {
|
|||
|
||||
arbitratorService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||
@Override
|
||||
public void onAdded(ProtectedData entry) {
|
||||
public void onAdded(ProtectedData data) {
|
||||
applyArbitrators();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(ProtectedData entry) {
|
||||
public void onRemoved(ProtectedData data) {
|
||||
applyArbitrators();
|
||||
}
|
||||
});
|
||||
|
@ -137,7 +137,7 @@ public class ArbitratorManager {
|
|||
// re-publish periodically
|
||||
republishArbitratorExecutor = Utilities.getScheduledThreadPoolExecutor("republishArbitrator", 1, 5, 5);
|
||||
long delay = Arbitrator.TTL / 2;
|
||||
republishArbitratorExecutor.scheduleAtFixedRate(() -> republishArbitrator(), delay, delay, TimeUnit.MILLISECONDS);
|
||||
republishArbitratorExecutor.scheduleAtFixedRate(this::republishArbitrator, delay, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
applyArbitrators();
|
||||
|
@ -150,7 +150,7 @@ public class ArbitratorManager {
|
|||
Arbitrator registeredArbitrator = user.getRegisteredArbitrator();
|
||||
if (registeredArbitrator != null) {
|
||||
addArbitrator(registeredArbitrator,
|
||||
() -> applyArbitrators(),
|
||||
this::applyArbitrators,
|
||||
log::error
|
||||
);
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ public class ArbitratorManager {
|
|||
|
||||
public void applyArbitrators() {
|
||||
Map<NodeAddress, Arbitrator> map = arbitratorService.getArbitrators();
|
||||
log.trace("Arbitrators . size=" + (map.values() != null ? map.values().size() : "0"));
|
||||
log.trace("Arbitrators . size=" + map.values().size());
|
||||
arbitratorsObservableMap.clear();
|
||||
Map<NodeAddress, Arbitrator> filtered = map.values().stream()
|
||||
.filter(e -> isPublicKeyInList(Utils.HEX.encode(e.getRegistrationPubKey()))
|
||||
|
@ -176,8 +176,8 @@ public class ArbitratorManager {
|
|||
// if we don't have any arbitrator anymore we set all matching
|
||||
if (user.getAcceptedArbitrators().isEmpty()) {
|
||||
arbitratorsObservableMap.values().stream()
|
||||
.filter(arbitrator -> user.hasMatchingLanguage(arbitrator))
|
||||
.forEach(arbitrator -> user.addAcceptedArbitrator(arbitrator));
|
||||
.filter(user::hasMatchingLanguage)
|
||||
.forEach(user::addAcceptedArbitrator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ public class ArbitratorManager {
|
|||
resultHandler.handleResult();
|
||||
|
||||
if (arbitratorsObservableMap.size() > 0)
|
||||
UserThread.runAfter(() -> applyArbitrators(), 100, TimeUnit.MILLISECONDS);
|
||||
UserThread.runAfter(this::applyArbitrators, 100, TimeUnit.MILLISECONDS);
|
||||
},
|
||||
errorMessageHandler::handleErrorMessage);
|
||||
}
|
||||
|
|
|
@ -84,8 +84,8 @@ public class ArbitratorService {
|
|||
|
||||
public Map<NodeAddress, Arbitrator> getArbitrators() {
|
||||
Set<Arbitrator> arbitratorSet = p2PService.getDataMap().values().stream()
|
||||
.filter(e -> e.expirableMessage instanceof Arbitrator)
|
||||
.map(e -> (Arbitrator) e.expirableMessage)
|
||||
.filter(data -> data.expirableMessage instanceof Arbitrator)
|
||||
.map(data -> (Arbitrator) data.expirableMessage)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Map<NodeAddress, Arbitrator> map = new HashMap<>();
|
||||
|
|
|
@ -575,7 +575,7 @@ public class DisputeManager {
|
|||
}
|
||||
|
||||
private boolean isArbitrator(DisputeResult disputeResult) {
|
||||
return walletService.getArbitratorAddressEntry().getAddressString().equals(disputeResult.getArbitratorAddressAsString());
|
||||
return disputeResult.getArbitratorAddressAsString().equals(walletService.getArbitratorAddressEntry().getAddressString());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ class AddressBasedCoinSelector implements CoinSelector {
|
|||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static void sortOutputs(ArrayList<TransactionOutput> outputs) {
|
||||
private static void sortOutputs(ArrayList<TransactionOutput> outputs) {
|
||||
Collections.sort(outputs, (a, b) -> {
|
||||
int depth1 = a.getParentTransactionDepthInBlocks();
|
||||
int depth2 = b.getParentTransactionDepthInBlocks();
|
||||
|
@ -92,7 +92,7 @@ class AddressBasedCoinSelector implements CoinSelector {
|
|||
/**
|
||||
* Sub-classes can override this to just customize whether transactions are usable, but keep age sorting.
|
||||
*/
|
||||
protected boolean shouldSelect(Transaction tx) {
|
||||
private boolean shouldSelect(Transaction tx) {
|
||||
return isInBlockChainOrPending(tx);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import io.bitsquare.btc.exceptions.TransactionVerificationException;
|
|||
import io.bitsquare.btc.exceptions.WalletException;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.crypto.DeterministicKey;
|
||||
import org.bitcoinj.crypto.TransactionSignature;
|
||||
import org.bitcoinj.kits.WalletAppKit;
|
||||
import org.bitcoinj.script.Script;
|
||||
|
@ -161,6 +162,7 @@ public class TradeWalletService {
|
|||
// To be discussed if that introduce any privacy issues.
|
||||
sendRequest.changeAddress = addressEntry.getAddress();
|
||||
|
||||
checkNotNull(wallet, "Wallet must not be null");
|
||||
wallet.completeTx(sendRequest);
|
||||
printTxWithInputs("tradingFeeTx", tradingFeeTx);
|
||||
|
||||
|
@ -248,8 +250,9 @@ public class TradeWalletService {
|
|||
String changeOutputAddress = null;
|
||||
if (changeOutput != null) {
|
||||
changeOutputValue = changeOutput.getValue().getValue();
|
||||
checkNotNull(changeOutput.getAddressFromP2PKHScript(params), "changeOutput.getAddressFromP2PKHScript(params) must not be null");
|
||||
changeOutputAddress = changeOutput.getAddressFromP2PKHScript(params).toString();
|
||||
Address addressFromP2PKHScript = changeOutput.getAddressFromP2PKHScript(params);
|
||||
checkNotNull(addressFromP2PKHScript, "changeOutput.getAddressFromP2PKHScript(params) must not be null");
|
||||
changeOutputAddress = addressFromP2PKHScript.toString();
|
||||
}
|
||||
|
||||
return new InputsAndChangeOutput(rawInputList, changeOutputValue, changeOutputAddress);
|
||||
|
@ -292,7 +295,7 @@ public class TradeWalletService {
|
|||
log.trace("msOutputAmount " + msOutputAmount.toFriendlyString());
|
||||
log.trace("takerRawInputs " + takerRawInputs.toString());
|
||||
log.trace("takerChangeOutputValue " + takerChangeOutputValue);
|
||||
log.trace("takerChangeAddressString " + takerChangeAddressString != null ? takerChangeAddressString : "");
|
||||
log.trace("takerChangeAddressString " + takerChangeAddressString);
|
||||
log.trace("buyerPubKey " + ECKey.fromPublicOnly(buyerPubKey).toString());
|
||||
log.trace("sellerPubKey " + ECKey.fromPublicOnly(sellerPubKey).toString());
|
||||
log.trace("arbitratorPubKey " + ECKey.fromPublicOnly(arbitratorPubKey).toString());
|
||||
|
@ -499,6 +502,7 @@ public class TradeWalletService {
|
|||
printTxWithInputs("depositTx", depositTx);
|
||||
|
||||
// Broadcast depositTx
|
||||
checkNotNull(walletAppKit);
|
||||
ListenableFuture<Transaction> broadcastComplete = walletAppKit.peerGroup().broadcastTransaction(depositTx).future();
|
||||
Futures.addCallback(broadcastComplete, callback);
|
||||
}
|
||||
|
@ -552,7 +556,9 @@ public class TradeWalletService {
|
|||
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
|
||||
// MS output from prev. tx is index 0
|
||||
Sha256Hash sigHash = preparedPayoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
|
||||
ECKey.ECDSASignature sellerSignature = sellerAddressEntry.getKeyPair().sign(sigHash, aesKey).toCanonicalised();
|
||||
DeterministicKey keyPair = sellerAddressEntry.getKeyPair();
|
||||
checkNotNull(keyPair);
|
||||
ECKey.ECDSASignature sellerSignature = keyPair.sign(sigHash, aesKey).toCanonicalised();
|
||||
|
||||
verifyTransaction(preparedPayoutTx);
|
||||
|
||||
|
@ -772,7 +778,9 @@ public class TradeWalletService {
|
|||
// take care of sorting!
|
||||
Script redeemScript = getMultiSigRedeemScript(buyerPubKey, sellerPubKey, arbitratorPubKey);
|
||||
Sha256Hash sigHash = payoutTx.hashForSignature(0, redeemScript, Transaction.SigHash.ALL, false);
|
||||
ECKey.ECDSASignature tradersSignature = tradersAddressEntry.getKeyPair().sign(sigHash, aesKey).toCanonicalised();
|
||||
DeterministicKey keyPair = tradersAddressEntry.getKeyPair();
|
||||
checkNotNull(keyPair);
|
||||
ECKey.ECDSASignature tradersSignature = keyPair.sign(sigHash, aesKey).toCanonicalised();
|
||||
|
||||
TransactionSignature tradersTxSig = new TransactionSignature(tradersSignature, Transaction.SigHash.ALL, false);
|
||||
TransactionSignature arbitratorTxSig = new TransactionSignature(ECKey.ECDSASignature.decodeFromDER(arbitratorSignature),
|
||||
|
@ -805,6 +813,7 @@ public class TradeWalletService {
|
|||
* @param callback
|
||||
*/
|
||||
public void broadcastTx(Transaction tx, FutureCallback<Transaction> callback) {
|
||||
checkNotNull(walletAppKit);
|
||||
ListenableFuture<Transaction> future = walletAppKit.peerGroup().broadcastTransaction(tx).future();
|
||||
Futures.addCallback(future, callback);
|
||||
}
|
||||
|
@ -850,6 +859,7 @@ public class TradeWalletService {
|
|||
* @throws VerificationException
|
||||
*/
|
||||
public Transaction getWalletTx(Sha256Hash txId) throws VerificationException {
|
||||
checkNotNull(wallet);
|
||||
return wallet.getTransaction(txId);
|
||||
}
|
||||
|
||||
|
@ -858,22 +868,27 @@ public class TradeWalletService {
|
|||
* is old and doesn't have that data.
|
||||
*/
|
||||
public int getLastBlockSeenHeight() {
|
||||
checkNotNull(wallet);
|
||||
return wallet.getLastBlockSeenHeight();
|
||||
}
|
||||
|
||||
public ListenableFuture<StoredBlock> getBlockHeightFuture(Transaction transaction) {
|
||||
checkNotNull(walletAppKit);
|
||||
return walletAppKit.chain().getHeightFuture((int) transaction.getLockTime());
|
||||
}
|
||||
|
||||
public int getBestChainHeight() {
|
||||
checkNotNull(walletAppKit);
|
||||
return walletAppKit.chain().getBestChainHeight();
|
||||
}
|
||||
|
||||
public void addBlockChainListener(BlockChainListener blockChainListener) {
|
||||
checkNotNull(walletAppKit);
|
||||
walletAppKit.chain().addListener(blockChainListener);
|
||||
}
|
||||
|
||||
public void removeBlockChainListener(BlockChainListener blockChainListener) {
|
||||
checkNotNull(walletAppKit);
|
||||
walletAppKit.chain().removeListener(blockChainListener);
|
||||
}
|
||||
|
||||
|
@ -943,7 +958,7 @@ public class TradeWalletService {
|
|||
transaction.addOutput(buyerPayoutAmount, new Address(params, buyerAddressString));
|
||||
transaction.addOutput(sellerPayoutAmount, new Address(params, sellerAddressString));
|
||||
if (lockTime != 0) {
|
||||
log.info("We use a locktime of " + lockTime);
|
||||
log.info("We use a lockTime of " + lockTime);
|
||||
// When using lockTime we need to set sequenceNumber to 0
|
||||
transaction.getInputs().stream().forEach(i -> i.setSequenceNumber(0));
|
||||
transaction.setLockTime(lockTime);
|
||||
|
@ -964,6 +979,7 @@ public class TradeWalletService {
|
|||
private void signInput(Transaction transaction, TransactionInput input, int inputIndex) throws SigningException {
|
||||
checkNotNull(input.getConnectedOutput(), "input.getConnectedOutput() must not be null");
|
||||
Script scriptPubKey = input.getConnectedOutput().getScriptPubKey();
|
||||
checkNotNull(wallet);
|
||||
ECKey sigKey = input.getOutpoint().getConnectedKey(wallet);
|
||||
checkNotNull(sigKey, "signInput: sigKey must not be null. input.getOutpoint()=" + input.getOutpoint().toString());
|
||||
Sha256Hash hash = transaction.hashForSignature(inputIndex, scriptPubKey, Transaction.SigHash.ALL, false);
|
||||
|
@ -981,6 +997,7 @@ public class TradeWalletService {
|
|||
private void checkWalletConsistency() throws WalletException {
|
||||
try {
|
||||
log.trace("Check if wallet is consistent before commit.");
|
||||
checkNotNull(wallet);
|
||||
checkState(wallet.isConsistent());
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
|
|
|
@ -120,9 +120,9 @@ public class WalletService {
|
|||
|
||||
Threading.USER_THREAD = UserThread.getExecutor();
|
||||
|
||||
Timer timeoutTimer = UserThread.runAfter(() -> {
|
||||
exceptionHandler.handleException(new TimeoutException("Wallet did not initialize in " + STARTUP_TIMEOUT_SEC + " seconds."));
|
||||
}, STARTUP_TIMEOUT_SEC);
|
||||
Timer timeoutTimer = UserThread.runAfter(() ->
|
||||
exceptionHandler.handleException(new TimeoutException("Wallet did not initialize in " +
|
||||
STARTUP_TIMEOUT_SEC + " seconds.")), STARTUP_TIMEOUT_SEC);
|
||||
|
||||
// If seed is non-null it means we are restoring from backup.
|
||||
walletAppKit = new WalletAppKit(params, walletDir, "Bitsquare") {
|
||||
|
@ -190,7 +190,7 @@ public class WalletService {
|
|||
timeoutTimer.cancel();
|
||||
|
||||
// onSetupCompleted in walletAppKit is not the called on the last invocations, so we add a bit of delay
|
||||
UserThread.runAfter(() -> resultHandler.handleResult(), 100, TimeUnit.MILLISECONDS);
|
||||
UserThread.runAfter(resultHandler::handleResult, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -451,8 +451,7 @@ public class WalletService {
|
|||
public Coin getRequiredFee(String fromAddress,
|
||||
String toAddress,
|
||||
Coin amount,
|
||||
@Nullable KeyParameter aesKey) throws AddressFormatException, IllegalArgumentException,
|
||||
InsufficientMoneyException {
|
||||
@Nullable KeyParameter aesKey) throws AddressFormatException, IllegalArgumentException {
|
||||
Coin fee;
|
||||
try {
|
||||
wallet.completeTx(getSendRequest(fromAddress, toAddress, amount, aesKey));
|
||||
|
@ -469,7 +468,7 @@ public class WalletService {
|
|||
String toAddress,
|
||||
Coin amount,
|
||||
@Nullable KeyParameter aesKey) throws AddressFormatException,
|
||||
IllegalArgumentException, InsufficientMoneyException {
|
||||
IllegalArgumentException {
|
||||
Coin fee;
|
||||
try {
|
||||
wallet.completeTx(getSendRequestForMultipleAddresses(fromAddresses, toAddress, amount, null, aesKey));
|
||||
|
@ -482,10 +481,10 @@ public class WalletService {
|
|||
return fee;
|
||||
}
|
||||
|
||||
public Wallet.SendRequest getSendRequest(String fromAddress,
|
||||
String toAddress,
|
||||
Coin amount,
|
||||
@Nullable KeyParameter aesKey) throws AddressFormatException,
|
||||
private Wallet.SendRequest getSendRequest(String fromAddress,
|
||||
String toAddress,
|
||||
Coin amount,
|
||||
@Nullable KeyParameter aesKey) throws AddressFormatException,
|
||||
IllegalArgumentException, InsufficientMoneyException {
|
||||
Transaction tx = new Transaction(params);
|
||||
Preconditions.checkArgument(Restrictions.isAboveDust(amount),
|
||||
|
@ -505,11 +504,11 @@ public class WalletService {
|
|||
return sendRequest;
|
||||
}
|
||||
|
||||
public Wallet.SendRequest getSendRequestForMultipleAddresses(Set<String> fromAddresses,
|
||||
String toAddress,
|
||||
Coin amount,
|
||||
@Nullable String changeAddress,
|
||||
@Nullable KeyParameter aesKey) throws
|
||||
private Wallet.SendRequest getSendRequestForMultipleAddresses(Set<String> fromAddresses,
|
||||
String toAddress,
|
||||
Coin amount,
|
||||
@Nullable String changeAddress,
|
||||
@Nullable KeyParameter aesKey) throws
|
||||
AddressFormatException, IllegalArgumentException, InsufficientMoneyException {
|
||||
Transaction tx = new Transaction(params);
|
||||
Preconditions.checkArgument(Restrictions.isAboveDust(amount),
|
||||
|
@ -520,9 +519,9 @@ public class WalletService {
|
|||
sendRequest.aesKey = aesKey;
|
||||
sendRequest.shuffleOutputs = false;
|
||||
Set<AddressEntry> addressEntries = fromAddresses.stream()
|
||||
.map(e -> getAddressEntryByAddress(e))
|
||||
.filter(e -> e.isPresent())
|
||||
.map(e -> e.get()).collect(Collectors.toSet());
|
||||
.map(this::getAddressEntryByAddress)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get).collect(Collectors.toSet());
|
||||
if (addressEntries.isEmpty())
|
||||
throw new IllegalArgumentException("No withdrawFromAddresses not found in our wallets.\n\t" +
|
||||
"fromAddresses=" + fromAddresses);
|
||||
|
|
|
@ -44,8 +44,8 @@ public class MarketPriceFeed {
|
|||
}
|
||||
}
|
||||
|
||||
private static long PERIOD_FIAT = 1; // We load only the selected currency on interval. Only the first request we load all
|
||||
private static long PERIOD_CRYPTO = 10; // We load the full list with 33kb so we don't want to load too often
|
||||
private static final long PERIOD_FIAT = 1; // We load only the selected currency on interval. Only the first request we load all
|
||||
private static final long PERIOD_CRYPTO = 10; // We load the full list with 33kb so we don't want to load too often
|
||||
|
||||
private final ScheduledThreadPoolExecutor executorService = Utilities.getScheduledThreadPoolExecutor("MarketPriceFeed", 5, 10, 700L);
|
||||
private final Map<String, MarketPrice> cache = new HashMap<>();
|
||||
|
|
|
@ -29,7 +29,7 @@ public class Country implements Serializable {
|
|||
|
||||
public final String code;
|
||||
public final String name;
|
||||
public final Region region;
|
||||
private final Region region;
|
||||
|
||||
public Country(String code, String name, Region region) {
|
||||
this.code = code;
|
||||
|
|
|
@ -158,6 +158,7 @@ public class CurrencyUtil {
|
|||
return !(isCryptoCurrency(currencyCode)) && Currency.getInstance(currencyCode) != null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public static boolean isCryptoCurrency(String currencyCode) {
|
||||
return getSortedCryptoCurrencies().stream().filter(e -> e.getCode().equals(currencyCode)).findAny().isPresent();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ public class FiatCurrency extends TradeCurrency implements Serializable {
|
|||
this(Currency.getInstance(currencyCode));
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public FiatCurrency(Currency currency) {
|
||||
super(currency.getCurrencyCode(), currency.getDisplayName(Preferences.getDefaultLocale()), currency.getSymbol());
|
||||
this.currency = currency;
|
||||
|
|
|
@ -40,11 +40,11 @@ public class PaymentAccount implements Serializable {
|
|||
protected final Date creationDate;
|
||||
protected final PaymentMethod paymentMethod;
|
||||
protected String accountName;
|
||||
protected final List<TradeCurrency> tradeCurrencies = new ArrayList<>();
|
||||
final List<TradeCurrency> tradeCurrencies = new ArrayList<>();
|
||||
protected TradeCurrency selectedTradeCurrency;
|
||||
@Nullable
|
||||
protected Country country = null;
|
||||
protected PaymentAccountContractData contractData;
|
||||
PaymentAccountContractData contractData;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -52,7 +52,7 @@ public class PaymentAccount implements Serializable {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public PaymentAccount(PaymentMethod paymentMethod) {
|
||||
protected PaymentAccount(PaymentMethod paymentMethod) {
|
||||
this.paymentMethod = paymentMethod;
|
||||
id = UUID.randomUUID().toString();
|
||||
creationDate = new Date();
|
||||
|
@ -108,7 +108,7 @@ public class PaymentAccount implements Serializable {
|
|||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(@Nullable Country country) {
|
||||
public void setCountry(Country country) {
|
||||
this.country = country;
|
||||
contractData.setCountryCode(country.code);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ public abstract class PaymentAccountContractData implements Serializable {
|
|||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public PaymentAccountContractData(String paymentMethodName, String id, int maxTradePeriod) {
|
||||
PaymentAccountContractData(String paymentMethodName, String id, int maxTradePeriod) {
|
||||
this.paymentMethodName = paymentMethodName;
|
||||
this.id = id;
|
||||
this.maxTradePeriod = maxTradePeriod;
|
||||
|
|
|
@ -44,7 +44,7 @@ public class SepaAccountContractData extends PaymentAccountContractData implemen
|
|||
super(paymentMethod, id, maxTradePeriod);
|
||||
Set<String> acceptedCountryCodesAsSet = CountryUtil.getAllSepaCountries().stream().map(e -> e.code).collect(Collectors.toSet());
|
||||
acceptedCountryCodes = new ArrayList<>(acceptedCountryCodesAsSet);
|
||||
acceptedCountryCodes.sort((a, b) -> a.compareTo(b));
|
||||
acceptedCountryCodes.sort(String::compareTo);
|
||||
}
|
||||
|
||||
public void setHolderName(String holderName) {
|
||||
|
|
|
@ -36,11 +36,11 @@ public abstract class SellerTrade extends Trade implements Serializable {
|
|||
|
||||
private static final Logger log = LoggerFactory.getLogger(BuyerAsTakerTrade.class);
|
||||
|
||||
public SellerTrade(Offer offer, Coin tradeAmount, NodeAddress tradingPeerNodeAddress, Storage<? extends TradableList> storage) {
|
||||
SellerTrade(Offer offer, Coin tradeAmount, NodeAddress tradingPeerNodeAddress, Storage<? extends TradableList> storage) {
|
||||
super(offer, tradeAmount, tradingPeerNodeAddress, storage);
|
||||
}
|
||||
|
||||
public SellerTrade(Offer offer, Storage<? extends TradableList> storage) {
|
||||
SellerTrade(Offer offer, Storage<? extends TradableList> storage) {
|
||||
super(offer, storage);
|
||||
}
|
||||
|
||||
|
|
|
@ -554,6 +554,7 @@ abstract public class Trade implements Tradable, Model, Serializable {
|
|||
this.takeOfferFeeTxId = takeOfferFeeTxId;
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.Nullable
|
||||
public String getTakeOfferFeeTxId() {
|
||||
return takeOfferFeeTxId;
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import io.bitsquare.common.handlers.ResultHandler;
|
|||
import io.bitsquare.common.util.JsonExclude;
|
||||
import io.bitsquare.locale.Country;
|
||||
import io.bitsquare.p2p.NodeAddress;
|
||||
import io.bitsquare.p2p.storage.data.RequiresLiveOwner;
|
||||
import io.bitsquare.p2p.storage.data.StorageMessage;
|
||||
import io.bitsquare.p2p.storage.messages.RequiresLiveOwnerData;
|
||||
import io.bitsquare.p2p.storage.messages.StorageMessage;
|
||||
import io.bitsquare.payment.PaymentMethod;
|
||||
import io.bitsquare.trade.protocol.availability.OfferAvailabilityModel;
|
||||
import io.bitsquare.trade.protocol.availability.OfferAvailabilityProtocol;
|
||||
|
@ -47,16 +47,14 @@ import java.util.concurrent.TimeUnit;
|
|||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class Offer implements StorageMessage, RequiresLiveOwner {
|
||||
public final class Offer implements StorageMessage, RequiresLiveOwnerData {
|
||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||
@JsonExclude
|
||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||
@JsonExclude
|
||||
private static final Logger log = LoggerFactory.getLogger(Offer.class);
|
||||
|
||||
//public static final long TTL = TimeUnit.MINUTES.toMillis(10);
|
||||
//TODO
|
||||
public static final long TTL = TimeUnit.SECONDS.toMillis(10);
|
||||
public static final long TTL = TimeUnit.SECONDS.toMillis(60);
|
||||
|
||||
public final static String TAC_OFFERER = "When placing that offer I accept that anyone who fulfills my conditions can " +
|
||||
"take that offer.";
|
||||
|
@ -163,7 +161,7 @@ public final class Offer implements StorageMessage, RequiresLiveOwner {
|
|||
public NodeAddress getOwnerNodeAddress() {
|
||||
return offererNodeAddress;
|
||||
}
|
||||
|
||||
|
||||
public void validate() {
|
||||
checkNotNull(getAmount(), "Amount is null");
|
||||
checkNotNull(getArbitratorNodeAddresses(), "Arbitrator is null");
|
||||
|
|
|
@ -21,7 +21,7 @@ import io.bitsquare.common.handlers.ErrorMessageHandler;
|
|||
import io.bitsquare.common.handlers.ResultHandler;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||
import io.bitsquare.p2p.storage.data.ProtectedData;
|
||||
import io.bitsquare.p2p.storage.ProtectedData;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -47,6 +47,7 @@ public class OfferBookService {
|
|||
private final P2PService p2PService;
|
||||
private final List<OfferBookChangedListener> offerBookChangedListeners = new LinkedList<>();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -57,20 +58,18 @@ public class OfferBookService {
|
|||
|
||||
p2PService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||
@Override
|
||||
public void onAdded(ProtectedData entry) {
|
||||
log.debug("OfferBookService.onAdded " + entry);
|
||||
public void onAdded(ProtectedData data) {
|
||||
offerBookChangedListeners.stream().forEach(listener -> {
|
||||
if (entry.expirableMessage instanceof Offer)
|
||||
listener.onAdded((Offer) entry.expirableMessage);
|
||||
if (data.expirableMessage instanceof Offer)
|
||||
listener.onAdded((Offer) data.expirableMessage);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(ProtectedData entry) {
|
||||
public void onRemoved(ProtectedData data) {
|
||||
offerBookChangedListeners.stream().forEach(listener -> {
|
||||
log.debug("OfferBookService.onRemoved " + entry);
|
||||
if (entry.expirableMessage instanceof Offer)
|
||||
listener.onRemoved((Offer) entry.expirableMessage);
|
||||
if (data.expirableMessage instanceof Offer)
|
||||
listener.onRemoved((Offer) data.expirableMessage);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -101,7 +100,7 @@ public class OfferBookService {
|
|||
result = p2PService.addData(offer);
|
||||
|
||||
if (result) {
|
||||
log.trace("Add offer to network was successful. Offer = " + offer);
|
||||
log.trace("Add offer to network was successful. Offer ID = " + offer.getId());
|
||||
resultHandler.handleResult();
|
||||
} else {
|
||||
errorMessageHandler.handleErrorMessage("Add offer failed");
|
||||
|
@ -110,7 +109,7 @@ public class OfferBookService {
|
|||
|
||||
public void removeOffer(Offer offer, @Nullable ResultHandler resultHandler, @Nullable ErrorMessageHandler errorMessageHandler) {
|
||||
if (p2PService.removeData(offer)) {
|
||||
log.trace("Remove offer from network was successful. Offer = " + offer);
|
||||
log.trace("Remove offer from network was successful. Offer ID = " + offer.getId());
|
||||
if (resultHandler != null)
|
||||
resultHandler.handleResult();
|
||||
} else {
|
||||
|
@ -121,8 +120,8 @@ public class OfferBookService {
|
|||
|
||||
public List<Offer> getOffers() {
|
||||
return p2PService.getDataMap().values().stream()
|
||||
.filter(e -> e.expirableMessage instanceof Offer)
|
||||
.map(e -> (Offer) e.expirableMessage)
|
||||
.filter(data -> data.expirableMessage instanceof Offer)
|
||||
.map(data -> (Offer) data.expirableMessage)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
|
|
@ -146,7 +146,8 @@ public class OpenOfferManager {
|
|||
if (bootstrapListener != null)
|
||||
p2PService.removeP2PServiceListener(bootstrapListener);
|
||||
|
||||
long period = (long) (Offer.TTL * 0.8); // republish sufficiently before offer would expire
|
||||
// republish sufficiently before offer would expire
|
||||
long period = (long) (Offer.TTL * 0.7);
|
||||
TimerTask timerTask = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -178,6 +179,7 @@ public class OpenOfferManager {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public void shutDown() {
|
||||
shutDown(null);
|
||||
}
|
||||
|
@ -190,8 +192,7 @@ public class OpenOfferManager {
|
|||
log.info("remove all open offers at shutDown");
|
||||
shutDownRequested = true;
|
||||
// we remove own offers from offerbook when we go offline
|
||||
//TODO
|
||||
// openOffers.forEach(openOffer -> offerBookService.removeOfferAtShutDown(openOffer.getOffer()));
|
||||
openOffers.forEach(openOffer -> offerBookService.removeOfferAtShutDown(openOffer.getOffer()));
|
||||
|
||||
if (completeHandler != null)
|
||||
UserThread.runAfter(completeHandler::run, openOffers.size() * 200 + 300, TimeUnit.MILLISECONDS);
|
||||
|
@ -230,7 +231,9 @@ public class OpenOfferManager {
|
|||
log.warn("Offer was not found in our list of open offers. We still try to remove it from the offerbook.");
|
||||
errorMessageHandler.handleErrorMessage("Offer was not found in our list of open offers. " +
|
||||
"We still try to remove it from the offerbook.");
|
||||
onRemoveOffer(offer);
|
||||
offerBookService.removeOffer(offer,
|
||||
() -> offer.setState(Offer.State.REMOVED),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,14 +250,6 @@ public class OpenOfferManager {
|
|||
errorMessageHandler);
|
||||
}
|
||||
|
||||
// That should not be needed, but there are cases where the openOffer is removed but the offer still in the
|
||||
// offerbook
|
||||
public void onRemoveOffer(Offer offer) {
|
||||
offerBookService.removeOffer(offer,
|
||||
() -> offer.setState(Offer.State.REMOVED),
|
||||
null);
|
||||
}
|
||||
|
||||
public void reserveOpenOffer(OpenOffer openOffer) {
|
||||
openOffer.setState(OpenOffer.State.RESERVED);
|
||||
}
|
||||
|
@ -283,7 +278,7 @@ public class OpenOfferManager {
|
|||
openOffer.setState(OpenOffer.State.CLOSED);
|
||||
offerBookService.removeOffer(openOffer.getOffer(),
|
||||
() -> log.trace("Successful removed offer"),
|
||||
errorMessage -> log.error(errorMessage));
|
||||
log::error);
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -67,8 +67,4 @@ public class OfferAvailabilityModel implements Model {
|
|||
@Override
|
||||
public void onComplete() {
|
||||
}
|
||||
|
||||
public PubKeyRing getPubKeyRing() {
|
||||
return pubKeyRing;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public abstract class OfferMessage implements DirectMessage {
|
|||
private final int messageVersion = Version.getP2PMessageVersion();
|
||||
public final String offerId;
|
||||
|
||||
protected OfferMessage(String offerId) {
|
||||
OfferMessage(String offerId) {
|
||||
this.offerId = offerId;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public class SendOfferAvailabilityRequest extends Task<OfferAvailabilityModel> {
|
|||
|
||||
model.p2PService.sendEncryptedDirectMessage(model.getPeerNodeAddress(),
|
||||
model.offer.getPubKeyRing(),
|
||||
new OfferAvailabilityRequest(model.offer.getId(), model.getPubKeyRing()),
|
||||
new OfferAvailabilityRequest(model.offer.getId(), model.pubKeyRing),
|
||||
new SendDirectMessageListener() {
|
||||
@Override
|
||||
public void onArrived() {
|
||||
|
|
|
@ -64,7 +64,7 @@ public class PlaceOfferProtocol {
|
|||
model.offerAddedToOfferBook = false;
|
||||
log.debug("Offer removed from offer book.");
|
||||
},
|
||||
errorMessage2 -> log.error(errorMessage2));
|
||||
log::error);
|
||||
}
|
||||
log.error(errorMessage);
|
||||
}
|
||||
|
|
|
@ -44,8 +44,8 @@ public class SignPayoutTx extends TradeTask {
|
|||
|
||||
// We use the sellers LastBlockSeenHeight, which might be different to the buyers one.
|
||||
// If lock time is 0 we set lockTimeAsBlockHeight to 0 to mark it as "not set".
|
||||
// In the tradewallet we apply the locktime only if it is set, otherwise we use the default values for
|
||||
// transaction locktime and sequence number
|
||||
// In the tradeWallet we apply the lockTime only if it is set, otherwise we use the default values for
|
||||
// transaction lockTime and sequence number
|
||||
long lockTime = trade.getOffer().getPaymentMethod().getLockTime();
|
||||
long lockTimeAsBlockHeight = 0;
|
||||
if (lockTime > 0)
|
||||
|
|
|
@ -386,7 +386,7 @@ public class Preferences implements Serializable {
|
|||
|
||||
public boolean showAgain(String key) {
|
||||
// if we add new and those are not in our stored map we display by default the new popup
|
||||
if (!getShowAgainMap().containsKey(key)) {
|
||||
if (!showAgainMap.containsKey(key)) {
|
||||
showAgainMap.put(key, true);
|
||||
storage.queueUpForSave(2000);
|
||||
}
|
||||
|
|
|
@ -191,7 +191,7 @@ public class User implements Serializable {
|
|||
storage.queueUpForSave();
|
||||
}
|
||||
|
||||
public void setRegisteredArbitrator(Arbitrator arbitrator) {
|
||||
public void setRegisteredArbitrator(@org.jetbrains.annotations.Nullable Arbitrator arbitrator) {
|
||||
this.registeredArbitrator = arbitrator;
|
||||
storage.queueUpForSave();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue