remove maintainancemanager, adopt fees, adopt timer delays, v. 0.3.2.3

This commit is contained in:
Manfred Karrer 2016-01-14 14:05:52 +01:00
parent db128c6815
commit 9653ff8437
23 changed files with 43 additions and 238 deletions

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.3.2.3-SNAPSHOT</version>
<version>0.3.2.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -6,7 +6,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.3.2.3-SNAPSHOT</version>
<version>0.3.2.3</version>
</parent>
<artifactId>core</artifactId>

View File

@ -31,7 +31,7 @@ public final class Arbitrator implements PubKeyProtectedExpirablePayload {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public static final long TTL = 1 * 24 * 60 * 60 * 1000; // 1 day
public static final long TTL = 6 * 24 * 60 * 60 * 1000; // 6 days
// Persisted fields
private final byte[] btcPubKey;

View File

@ -40,10 +40,7 @@ public class FeePolicy {
// Other good source is: https://tradeblock.com/blockchain 15-100 satoshis/byte
// On testnet currently fees are 0.002 BTC, so increase fee to 0.005 BTC to get for sure into blocks for testing
public static final Coin TX_FEE = Coin.valueOf(500000); // 0.005 BTC about 0.06 EUR @ 200 EUR/BTC: about 90 satoshi /byte
// TODO use original value again for mainnet
// public static final Coin TX_FEE = Coin.valueOf(30000); // 0.0003 BTC about 0.06 EUR @ 200 EUR/BTC: about 90 satoshi /byte
public static final Coin TX_FEE = Coin.valueOf(30000); // 0.0003 BTC about 0.06 EUR @ 200 EUR/BTC: about 90 satoshi /byte
static {
// we use our fee as default fee
@ -52,11 +49,7 @@ public class FeePolicy {
public static final Coin DUST = Coin.valueOf(546);
// TODO use original value again for mainnet
public static final Coin CREATE_OFFER_FEE = Coin.valueOf(40000); // 0.0001 BTC 0.1% of 1 BTC about 0.2 EUR @ 200 EUR/BTC
//public static final Coin CREATE_OFFER_FEE = Coin.valueOf(100000); // 0.001 BTC 0.1% of 1 BTC about 0.2 EUR @ 200 EUR/BTC
public static final Coin CREATE_OFFER_FEE = Coin.valueOf(100000); // 0.001 BTC 0.1% of 1 BTC about 0.2 EUR @ 200 EUR/BTC
public static final Coin TAKE_OFFER_FEE = CREATE_OFFER_FEE;
// TODO use original value again for mainnet
public static final Coin SECURITY_DEPOSIT = Coin.valueOf(10000); // 0.0001 BTC; about 20 EUR @ 200 EUR/BTC
//public static final Coin SECURITY_DEPOSIT = Coin.valueOf(10000000); // 0.1 BTC; about 20 EUR @ 200 EUR/BTC
public static final Coin SECURITY_DEPOSIT = Coin.valueOf(10000000); // 0.1 BTC; about 20 EUR @ 200 EUR/BTC
}

View File

@ -21,7 +21,7 @@ import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
public class Restrictions {
public static final Coin MIN_TRADE_AMOUNT = Coin.parseCoin("0.0001");
public static final Coin MIN_TRADE_AMOUNT = Coin.parseCoin("0.001"); // 40 cent @ 400 EUR/BTC
public static final Coin MAX_TRADE_AMOUNT = Coin.parseCoin("1");
public static boolean isMinSpendableAmount(Coin amount) {

View File

@ -141,7 +141,7 @@ public class TradeWalletService {
public Transaction createTradingFeeTx(AddressEntry addressEntry, Coin tradingFee, String feeReceiverAddresses)
throws InsufficientMoneyException, AddressFormatException {
Transaction tradingFeeTx = new Transaction(params);
Preconditions.checkArgument(tradingFee.compareTo(FeePolicy.TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT)) > 0,
Preconditions.checkArgument(Restrictions.isMinSpendableAmount(tradingFee),
"You cannot send an amount which are smaller than the fee + dust output.");
Coin outPutAmount = tradingFee.subtract(FeePolicy.TX_FEE);
tradingFeeTx.addOutput(outPutAmount, new Address(params, feeReceiverAddresses));

View File

@ -17,6 +17,7 @@
package io.bitsquare.btc;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
@ -446,7 +447,7 @@ public class WalletService {
KeyParameter aesKey,
FutureCallback<Transaction> callback) throws AddressFormatException, IllegalArgumentException, InsufficientMoneyException {
Transaction tx = new Transaction(params);
checkArgument(amount.compareTo(FeePolicy.TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT)) > 0,
Preconditions.checkArgument(Restrictions.isMinSpendableAmount(amount),
"You cannot send an amount which are smaller than the fee + dust output.");
tx.addOutput(amount.subtract(FeePolicy.TX_FEE), new Address(params, toAddress));

View File

@ -145,7 +145,7 @@ public class OpenOfferManager {
if (firstPeerAuthenticatedListener != null)
p2PService.removeP2PServiceListener(firstPeerAuthenticatedListener);
long period = (long) (Offer.TTL * 0.8); // republish sufficiently before offer would expires
long period = (long) (Offer.TTL * 0.8); // republish sufficiently before offer would expire
TimerTask timerTask = new TimerTask() {
@Override
public void run() {

View File

@ -22,7 +22,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.3.2.3-SNAPSHOT</version>
<version>0.3.2.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -75,7 +75,7 @@ import static io.bitsquare.app.BitsquareEnvironment.APP_NAME_KEY;
public class BitsquareApp extends Application {
private static final Logger log = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(BitsquareApp.class);
public static final boolean DEV_MODE = true;
public static final boolean DEV_MODE = false;
public static final boolean IS_RELEASE_VERSION = !DEV_MODE && true;
private static Environment env;

View File

@ -17,7 +17,8 @@
package io.bitsquare.gui.popups;
import io.bitsquare.btc.FeePolicy;
import com.google.common.base.Preconditions;
import io.bitsquare.btc.Restrictions;
import io.bitsquare.btc.WalletService;
import io.bitsquare.common.util.Tuple2;
import io.bitsquare.gui.components.InputTextField;
@ -32,7 +33,6 @@ import javafx.scene.layout.HBox;
import org.bitcoinj.core.AddressFormatException;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.InsufficientMoneyException;
import org.bitcoinj.core.Transaction;
import org.reactfx.util.FxTimer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -42,7 +42,6 @@ import javax.inject.Inject;
import java.time.Duration;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkArgument;
import static io.bitsquare.gui.util.FormBuilder.*;
public class EmptyWalletPopup extends Popup {
@ -96,9 +95,9 @@ public class EmptyWalletPopup extends Popup {
10);
Coin totalBalance = walletService.getAvailableBalance();
checkArgument(totalBalance.compareTo(FeePolicy.TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT)) > 0,
boolean isBalanceSufficient = Restrictions.isMinSpendableAmount(totalBalance);
Preconditions.checkArgument(isBalanceSufficient,
"You cannot send an amount which are smaller than the fee + dust output.");
boolean isBalanceSufficient = totalBalance.compareTo(FeePolicy.TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT)) > 0;
addressTextField = addLabelTextField(gridPane, ++rowIndex, "Your available wallet balance:",
formatter.formatCoinWithCode(totalBalance), 10).second;
Tuple2<Label, InputTextField> tuple = addLabelInputTextField(gridPane, ++rowIndex, "Your destination address:");

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.3.2.3-SNAPSHOT</version>
<version>0.3.2.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.3.2.3-SNAPSHOT</version>
<version>0.3.2.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.3.2.3-SNAPSHOT</version>
<version>0.3.2.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.3.2.3-SNAPSHOT</version>
<version>0.3.2.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -1,128 +0,0 @@
package io.bitsquare.p2p.peers;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import io.bitsquare.app.Log;
import io.bitsquare.common.UserThread;
import io.bitsquare.common.util.Utilities;
import io.bitsquare.p2p.Address;
import io.bitsquare.p2p.Message;
import io.bitsquare.p2p.network.Connection;
import io.bitsquare.p2p.network.MessageListener;
import io.bitsquare.p2p.network.NetworkNode;
import io.bitsquare.p2p.peers.messages.maintenance.MaintenanceMessage;
import io.bitsquare.p2p.peers.messages.maintenance.PingMessage;
import io.bitsquare.p2p.peers.messages.maintenance.PongMessage;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class MaintenanceManager implements MessageListener {
private static final Logger log = LoggerFactory.getLogger(MaintenanceManager.class);
private static final int INACTIVITY_PERIOD_BEFORE_PING = 5 * 60 * 1000;
private final NetworkNode networkNode;
private final Supplier<Map<Address, Peer>> authenticatedPeersSupplier;
private final Consumer<Address> removePeerConsumer;
private final ScheduledThreadPoolExecutor executor;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////
public MaintenanceManager(NetworkNode networkNode,
Supplier<Map<Address, Peer>> authenticatedPeersSupplier,
Consumer<Address> removePeerConsumer) {
this.networkNode = networkNode;
this.authenticatedPeersSupplier = authenticatedPeersSupplier;
this.removePeerConsumer = removePeerConsumer;
networkNode.addMessageListener(this);
executor = Utilities.getScheduledThreadPoolExecutor("MaintenanceManager", 1, 10, 5);
executor.scheduleAtFixedRate(() -> {
UserThread.execute(() -> pingPeers());
}, 5, 5, TimeUnit.MINUTES);
}
public void shutDown() {
Log.traceCall();
networkNode.removeMessageListener(this);
MoreExecutors.shutdownAndAwaitTermination(executor, 500, TimeUnit.MILLISECONDS);
}
///////////////////////////////////////////////////////////////////////////////////////////
// MessageListener implementation
///////////////////////////////////////////////////////////////////////////////////////////
@Override
public void onMessage(Message message, Connection connection) {
if (message instanceof MaintenanceMessage) {
Log.traceCall(message.toString());
if (message instanceof PingMessage) {
SettableFuture<Connection> future = networkNode.sendMessage(connection, new PongMessage(((PingMessage) message).nonce));
Futures.addCallback(future, new FutureCallback<Connection>() {
@Override
public void onSuccess(Connection connection) {
log.trace("PongMessage sent successfully");
}
@Override
public void onFailure(@NotNull Throwable throwable) {
log.info("PongMessage sending failed " + throwable.getMessage());
connection.getPeerAddressOptional().ifPresent(peerAddress -> removePeerConsumer.accept(peerAddress));
}
});
} else if (message instanceof PongMessage) {
connection.getPeerAddressOptional().ifPresent(peerAddress -> {
Peer peer = authenticatedPeersSupplier.get().get(peerAddress);
if (peer != null) {
if (((PongMessage) message).nonce != peer.pingNonce) {
log.warn("PongMessage invalid: self/peer " + networkNode.getAddress() + "/" + peerAddress);
removePeerConsumer.accept(peer.address);
}
}
});
}
}
}
private void pingPeers() {
Set<Peer> connectedPeersList = new HashSet<>(authenticatedPeersSupplier.get().values());
if (!connectedPeersList.isEmpty()) {
Log.traceCall();
connectedPeersList.stream()
.filter(e -> (new Date().getTime() - e.connection.getLastActivityDate().getTime()) > INACTIVITY_PERIOD_BEFORE_PING)
.forEach(e -> {
SettableFuture<Connection> future = networkNode.sendMessage(e.connection, new PingMessage(e.pingNonce));
Futures.addCallback(future, new FutureCallback<Connection>() {
@Override
public void onSuccess(Connection connection) {
log.trace("PingMessage sent successfully");
}
@Override
public void onFailure(@NotNull Throwable throwable) {
log.info("PingMessage sending failed " + throwable.getMessage());
removePeerConsumer.accept(e.address);
}
});
});
}
}
}

View File

@ -22,7 +22,6 @@ import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
@ -39,8 +38,6 @@ public class PeerExchangeManager implements MessageListener {
private final BiConsumer<HashSet<ReportedPeer>, Connection> addReportedPeersConsumer;
private final ScheduledThreadPoolExecutor executor;
private Timer getPeersTimer;
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
@ -60,13 +57,11 @@ public class PeerExchangeManager implements MessageListener {
networkNode.addMessageListener(this);
executor = Utilities.getScheduledThreadPoolExecutor("PeerExchangeManager", 1, 10, 5);
executor.scheduleAtFixedRate(() -> UserThread.execute(() -> trySendGetPeersRequest()), 4, 4, TimeUnit.MINUTES);
executor.scheduleAtFixedRate(() -> UserThread.execute(() -> trySendGetPeersRequest()), 7, 7, TimeUnit.MINUTES);
}
public void shutDown() {
Log.traceCall();
if (getPeersTimer != null)
getPeersTimer.cancel();
networkNode.removeMessageListener(this);
MoreExecutors.shutdownAndAwaitTermination(executor, 500, TimeUnit.MILLISECONDS);

View File

@ -58,7 +58,6 @@ public class PeerManager implements MessageListener, ConnectionListener {
///////////////////////////////////////////////////////////////////////////////////////////
private final NetworkNode networkNode;
private final MaintenanceManager maintenanceManager;
private final PeerExchangeManager peerExchangeManager;
protected final ScheduledThreadPoolExecutor checkSeedNodeConnectionExecutor;
private final Storage<HashSet<ReportedPeer>> dbStorage;
@ -83,9 +82,6 @@ public class PeerManager implements MessageListener, ConnectionListener {
this.networkNode = networkNode;
dbStorage = new Storage<>(storageDir);
maintenanceManager = new MaintenanceManager(networkNode,
() -> getAuthenticatedPeers(),
address -> removePeer(address));
peerExchangeManager = new PeerExchangeManager(networkNode,
() -> getAuthenticatedAndReportedPeers(),
() -> getAuthenticatedPeers(),
@ -195,7 +191,6 @@ public class PeerManager implements MessageListener, ConnectionListener {
public void shutDown() {
Log.traceCall();
maintenanceManager.shutDown();
peerExchangeManager.shutDown();
networkNode.removeMessageListener(this);
@ -456,15 +451,26 @@ public class PeerManager implements MessageListener, ConnectionListener {
Log.traceCall();
resetRemainingSeedNodes();
if (!remainingSeedNodes.isEmpty()) {
log.info("We have remaining not connected seed node(s) available. " +
"We will call authenticateToRemainingSeedNode.");
// remove enough connections to be sure the authentication will succeed. I t might be that in the meantime
// we get other connection attempts, so remove 2 more than needed to have a bit of headroom.
checkIfConnectedPeersExceeds(MAX_CONNECTIONS_LOW_PRIORITY - remainingSeedNodes.size() - 2);
if (seedNodeAddressesOptional.isPresent()) {
Optional<Address> authSeedNodeOptional = authenticatedPeers.keySet().stream()
.filter(e -> seedNodeAddressesOptional.get().contains(e)).findAny();
if (authSeedNodeOptional.isPresent()) {
log.info("We are at least to one seed node connected.");
} else {
log.info("We are not to at least one seed node connected and we have remaining not connected " +
"seed node(s) available. " +
"We will call authenticateToRemainingSeedNode after 2 sec.");
// remove enough connections to be sure the authentication will succeed. I t might be that in the meantime
// we get other connection attempts, so remove 2 more than needed to have a bit of headroom.
checkIfConnectedPeersExceeds(MAX_CONNECTIONS_LOW_PRIORITY - remainingSeedNodes.size() - 2);
if (authenticateToRemainingSeedNodeTimer == null)
authenticateToRemainingSeedNodeTimer = UserThread.runAfter(() -> authenticateToRemainingSeedNode(),
500, TimeUnit.MILLISECONDS);
if (authenticateToRemainingSeedNodeTimer == null)
authenticateToRemainingSeedNodeTimer = UserThread.runAfter(() -> authenticateToRemainingSeedNode(),
2, TimeUnit.SECONDS);
}
} else {
log.error("seedNodeAddressesOptional must be present");
}
} else {
log.debug("There are no remainingSeedNodes available.");
}

View File

@ -1,19 +0,0 @@
package io.bitsquare.p2p.peers.messages.maintenance;
import io.bitsquare.app.Version;
import io.bitsquare.p2p.Message;
public abstract class MaintenanceMessage implements Message {
private final int networkId = Version.NETWORK_ID;
@Override
public int networkId() {
return networkId;
}
@Override
public String toString() {
return ", networkId=" + networkId +
'}';
}
}

View File

@ -1,21 +0,0 @@
package io.bitsquare.p2p.peers.messages.maintenance;
import io.bitsquare.app.Version;
public final class PingMessage extends MaintenanceMessage {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public final long nonce;
public PingMessage(long nonce) {
this.nonce = nonce;
}
@Override
public String toString() {
return "PingMessage{" +
"nonce=" + nonce +
super.toString() + "} ";
}
}

View File

@ -1,21 +0,0 @@
package io.bitsquare.p2p.peers.messages.maintenance;
import io.bitsquare.app.Version;
public final class PongMessage extends MaintenanceMessage {
// That object is sent over the wire, so we need to take care of version compatibility.
private static final long serialVersionUID = Version.NETWORK_PROTOCOL_VERSION;
public final long nonce;
public PongMessage(long nonce) {
this.nonce = nonce;
}
@Override
public String toString() {
return "PongMessage{" +
"nonce=" + nonce +
super.toString() + "} ";
}
}

View File

@ -6,7 +6,7 @@
<groupId>io.bitsquare</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<version>0.3.2.3-SNAPSHOT</version>
<version>0.3.2.3</version>
<description>Bitsquare - The decentralized bitcoin exchange</description>
<url>https://bitsquare.io</url>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>parent</artifactId>
<groupId>io.bitsquare</groupId>
<version>0.3.2.3-SNAPSHOT</version>
<version>0.3.2.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>