Handle offer removal on disconnect, cleanup

This commit is contained in:
Manfred Karrer 2016-02-17 17:33:53 +01:00
parent db363fac48
commit 17c780639f
69 changed files with 377 additions and 367 deletions

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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<>();

View file

@ -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());
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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);

View file

@ -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<>();

View file

@ -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;

View file

@ -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();
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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) {

View file

@ -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);
}

View file

@ -554,6 +554,7 @@ abstract public class Trade implements Tradable, Model, Serializable {
this.takeOfferFeeTxId = takeOfferFeeTxId;
}
@org.jetbrains.annotations.Nullable
public String getTakeOfferFeeTxId() {
return takeOfferFeeTxId;
}

View file

@ -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");

View file

@ -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());
}

View file

@ -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);
});
}

View file

@ -67,8 +67,4 @@ public class OfferAvailabilityModel implements Model {
@Override
public void onComplete() {
}
public PubKeyRing getPubKeyRing() {
return pubKeyRing;
}
}

View file

@ -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;
}

View file

@ -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() {

View file

@ -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);
}

View file

@ -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)

View file

@ -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);
}

View file

@ -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();
}