mirror of
https://github.com/bisq-network/bisq.git
synced 2025-03-11 01:27:45 +01:00
AddressEntryList save/load cycle works
This commit is contained in:
parent
f1ef154b61
commit
ce6620a291
88 changed files with 348 additions and 281 deletions
|
@ -1,4 +1,4 @@
|
|||
package io.bisq.network.p2p;
|
||||
package io.bisq.common.persistance;
|
||||
|
||||
|
||||
import io.bisq.common.Marshaller;
|
|
@ -15,13 +15,13 @@
|
|||
* along with Bitsquare. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.bisq.network.p2p.network;
|
||||
package io.bisq.common.persistance;
|
||||
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ProtobufferResolver {
|
||||
Optional<Msg> fromProto(PB.Envelope envelope);
|
||||
Optional<Persistable> fromProto(PB.DiskEnvelope envelope);
|
||||
}
|
|
@ -17,16 +17,20 @@
|
|||
|
||||
package io.bisq.common.storage;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.protobuf.Message;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.io.LookAheadObjectInputStream;
|
||||
import io.bisq.common.persistance.Persistable;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
|
@ -43,17 +47,17 @@ public class FileManager<T> {
|
|||
private final long delay;
|
||||
private final Callable<Void> saveFileTask;
|
||||
private T serializable;
|
||||
private boolean proto;
|
||||
|
||||
private ProtobufferResolver protobufferResolver;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public FileManager(File dir, File storageFile, long delay) {
|
||||
@Inject
|
||||
public FileManager(File dir, File storageFile, long delay, ProtobufferResolver protobufferResolver) {
|
||||
this.dir = dir;
|
||||
this.storageFile = storageFile;
|
||||
proto = serializable instanceof Persistable;
|
||||
this.protobufferResolver = protobufferResolver;
|
||||
|
||||
executor = Utilities.getScheduledThreadPoolExecutor("FileManager", 1, 10, 5);
|
||||
|
||||
|
@ -106,13 +110,17 @@ public class FileManager<T> {
|
|||
|
||||
public synchronized T read(File file) throws IOException, ClassNotFoundException {
|
||||
log.debug("read" + file);
|
||||
if (proto) {
|
||||
log.info("it's proto");
|
||||
try (final FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
return (T) ((Persistable) serializable).getParser().parseFrom(fileInputStream);
|
||||
} catch (Throwable t) {
|
||||
log.error("Exception at proto read: " + t.getMessage());
|
||||
}
|
||||
Optional<Persistable> persistable = Optional.empty();
|
||||
|
||||
try (final FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
persistable = protobufferResolver.fromProto(PB.DiskEnvelope.parseFrom(fileInputStream));
|
||||
} catch (Throwable t) {
|
||||
log.error("Exception at proto read: " + t.getMessage() + " " + file.getName());
|
||||
}
|
||||
|
||||
if(persistable.isPresent()) {
|
||||
log.error("Persistable found");
|
||||
return (T) persistable.get();
|
||||
}
|
||||
|
||||
try (final FileInputStream fileInputStream = new FileInputStream(file);
|
||||
|
@ -192,7 +200,7 @@ public class FileManager<T> {
|
|||
try {
|
||||
message = ((Persistable) serializable).toProtobuf();
|
||||
} catch (Throwable e) {
|
||||
log.info("Not protobufferable: {} {}", serializable.getClass().getSimpleName(), e.getMessage());
|
||||
log.info("Not protobufferable: {}, {}, {}", serializable.getClass().getSimpleName(), storageFile, e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
|
||||
package io.bisq.common.storage;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -66,6 +67,8 @@ public class Storage<T extends Serializable> {
|
|||
private T serializable;
|
||||
private String fileName;
|
||||
private int numMaxBackupFiles = 10;
|
||||
@com.google.inject.Inject
|
||||
private ProtobufferResolver protobufferResolver;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -73,21 +76,28 @@ public class Storage<T extends Serializable> {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public Storage(@Named(DIR_KEY) File dir) {
|
||||
public Storage(@Named(DIR_KEY) File dir, ProtobufferResolver protobufferResolver) {
|
||||
this.dir = dir;
|
||||
this.protobufferResolver = protobufferResolver;
|
||||
}
|
||||
|
||||
/*
|
||||
public Storage(@Named(DIR_KEY) File dir) {
|
||||
this.dir = dir;
|
||||
this.protobufferResolver = protobufferResolver;
|
||||
}
|
||||
*/
|
||||
public void initWithFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
storageFile = new File(dir, fileName);
|
||||
fileManager = new FileManager<>(dir, storageFile, 300);
|
||||
fileManager = new FileManager<>(dir, storageFile, 300, protobufferResolver);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T initAndGetPersistedWithFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
storageFile = new File(dir, fileName);
|
||||
fileManager = new FileManager<>(dir, storageFile, 300);
|
||||
fileManager = new FileManager<>(dir, storageFile, 300, protobufferResolver);
|
||||
|
||||
return getPersisted();
|
||||
}
|
||||
|
@ -102,7 +112,7 @@ public class Storage<T extends Serializable> {
|
|||
this.serializable = serializable;
|
||||
this.fileName = fileName;
|
||||
storageFile = new File(dir, fileName);
|
||||
fileManager = new FileManager<>(dir, storageFile, 600);
|
||||
fileManager = new FileManager<>(dir, storageFile, 600, protobufferResolver);
|
||||
|
||||
return getPersisted();
|
||||
}
|
||||
|
@ -151,7 +161,7 @@ public class Storage<T extends Serializable> {
|
|||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// We do the file read on the UI thread to avoid problems from multi threading.
|
||||
// We do the file read on the UI thread to avoid problems from multi threading.
|
||||
// Data are small and read is done only at startup, so it is no performance issue.
|
||||
@Nullable
|
||||
private T getPersisted() {
|
||||
|
@ -161,7 +171,7 @@ public class Storage<T extends Serializable> {
|
|||
T persistedObject = fileManager.read(storageFile);
|
||||
log.trace("Read {} completed in {}msec", storageFile, System.currentTimeMillis() - now);
|
||||
|
||||
// If we did not get any exception we can be sure the data are consistent so we make a backup
|
||||
// If we did not get any exception we can be sure the data are consistent so we make a backup
|
||||
now = System.currentTimeMillis();
|
||||
fileManager.backupFile(fileName, numMaxBackupFiles);
|
||||
log.trace("Backup {} completed in {}msec", storageFile, System.currentTimeMillis() - now);
|
||||
|
|
|
@ -776,12 +776,16 @@ message AddressEntry {
|
|||
|
||||
string offer_id = 7;
|
||||
Context context = 8;
|
||||
bytes pubkey = 9;
|
||||
bytes pub_key = 9;
|
||||
bytes pub_key_hash = 10;
|
||||
string param_id = 11;
|
||||
Coin coin_locked_in_multi_sig = 12;
|
||||
}
|
||||
|
||||
message DeterministicKey {
|
||||
bytes serialized = 1;
|
||||
}
|
||||
|
||||
message AddressEntryList {
|
||||
repeated AddressEntry address_entry = 1;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<appender-ref ref="CONSOLE_APPENDER"/>
|
||||
</root>
|
||||
|
||||
<logger name="io.bisq.common.storage.Storage" level="WARN"/>
|
||||
<logger name="io.bisq.common.storage.FileManager" level="WARN"/>
|
||||
<logger name="io.bisq.core.storage.Storage" level="WARN"/>
|
||||
<logger name="io.bisq.core.storage.FileManager" level="WARN"/>
|
||||
<logger name="io.bisq.locale.BSResources" level="ERROR"/>
|
||||
|
||||
<!-- <logger name="io.bisq.p2p.peers.PeerGroup" level="TRACE"/>
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.google.inject.name.Named;
|
|||
import io.bisq.common.app.DevEnv;
|
||||
import io.bisq.common.crypto.KeyRing;
|
||||
import io.bisq.common.crypto.PubKeyRing;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.core.app.AppOptionKeys;
|
||||
import io.bisq.network.p2p.*;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
|
|
|
@ -3,7 +3,7 @@ package io.bisq.core.alert;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
|
|
@ -27,6 +27,8 @@ import io.bisq.common.crypto.PubKeyRing;
|
|||
import io.bisq.common.handlers.FaultHandler;
|
||||
import io.bisq.common.handlers.ResultHandler;
|
||||
import io.bisq.common.locale.Res;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.core.arbitration.messages.*;
|
||||
import io.bisq.core.btc.AddressEntry;
|
||||
|
@ -89,6 +91,7 @@ public class DisputeManager {
|
|||
ClosedTradableManager closedTradableManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
KeyRing keyRing,
|
||||
ProtobufferResolver protobufferResolver,
|
||||
@Named(Storage.DIR_KEY) File storageDir) {
|
||||
this.p2PService = p2PService;
|
||||
this.tradeWalletService = tradeWalletService;
|
||||
|
@ -98,7 +101,7 @@ public class DisputeManager {
|
|||
this.openOfferManager = openOfferManager;
|
||||
this.keyRing = keyRing;
|
||||
|
||||
disputeStorage = new Storage<>(storageDir);
|
||||
disputeStorage = new Storage<>(storageDir, protobufferResolver);
|
||||
disputes = new DisputeList(disputeStorage);
|
||||
|
||||
openDisputes = new HashMap<>();
|
||||
|
@ -148,7 +151,7 @@ public class DisputeManager {
|
|||
openDisputes.put(dispute.getTradeId(), dispute);
|
||||
});
|
||||
|
||||
// If we have duplicate disputes we close the second one (might happen if both traders opened a dispute and arbitrator
|
||||
// If we have duplicate disputes we close the second one (might happen if both traders opened a dispute and arbitrator
|
||||
// was offline, so could not forward msg to other peer, then the arbitrator might have 4 disputes open for 1 trade)
|
||||
openDisputes.entrySet().stream().forEach(openDisputeEntry -> {
|
||||
String key = openDisputeEntry.getKey();
|
||||
|
@ -354,7 +357,7 @@ public class DisputeManager {
|
|||
false,
|
||||
UUID.randomUUID().toString()
|
||||
);
|
||||
|
||||
|
||||
disputeCommunicationMessage.addAllAttachments(attachments);
|
||||
PubKeyRing receiverPubKeyRing = null;
|
||||
NodeAddress peerNodeAddress = null;
|
||||
|
@ -415,7 +418,7 @@ public class DisputeManager {
|
|||
false,
|
||||
UUID.randomUUID().toString()
|
||||
);
|
||||
|
||||
|
||||
dispute.addDisputeMessage(disputeCommunicationMessage);
|
||||
disputeResult.setDisputeCommunicationMessage(disputeCommunicationMessage);
|
||||
|
||||
|
@ -583,7 +586,7 @@ public class DisputeManager {
|
|||
|
||||
// We need to avoid publishing the tx from both traders as it would create problems with zero confirmation withdrawals
|
||||
// There would be different transactions if both sign and publish (signers: once buyer+arb, once seller+arb)
|
||||
// The tx publisher is the winner or in case both get 50% the buyer, as the buyer has more inventive to publish the tx as he receives
|
||||
// The tx publisher is the winner or in case both get 50% the buyer, as the buyer has more inventive to publish the tx as he receives
|
||||
// more BTC as he has deposited
|
||||
final Contract contract = dispute.getContract();
|
||||
|
||||
|
@ -645,7 +648,7 @@ public class DisputeManager {
|
|||
dispute.setDisputePayoutTxId(transaction.getHashAsString());
|
||||
sendPeerPublishedPayoutTxMessage(transaction, dispute, contract);
|
||||
|
||||
// set state after payout as we call swapTradeEntryToAvailableEntry
|
||||
// set state after payout as we call swapTradeEntryToAvailableEntry
|
||||
if (tradeManager.getTradeById(dispute.getTradeId()).isPresent())
|
||||
tradeManager.closeDisputedTrade(dispute.getTradeId());
|
||||
else {
|
||||
|
|
|
@ -20,7 +20,7 @@ package io.bisq.core.arbitration.messages;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.core.arbitration.Attachment;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
|
@ -38,7 +38,7 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@EqualsAndHashCode
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString
|
||||
@Getter
|
||||
@Slf4j
|
||||
|
|
|
@ -20,7 +20,7 @@ package io.bisq.core.arbitration.messages;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.core.arbitration.DisputeResult;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
|
|
@ -20,7 +20,7 @@ package io.bisq.core.arbitration.messages;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.core.arbitration.Dispute;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
|
|
@ -20,7 +20,7 @@ package io.bisq.core.arbitration.messages;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.core.arbitration.Dispute;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
|
|
@ -20,7 +20,7 @@ package io.bisq.core.arbitration.messages;
|
|||
import com.google.protobuf.ByteString;
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
|
|
@ -110,12 +110,14 @@ public final class AddressEntry implements Persistable {
|
|||
String paramId,
|
||||
Context context,
|
||||
@Nullable String offerId,
|
||||
@Nullable Coin coinLockedInMultiSig,
|
||||
@NotNull KeyBagSupplier keyBagSupplier) {
|
||||
this.pubKey = pubKey;
|
||||
this.pubKeyHash = pubKeyHash;
|
||||
this.paramId = paramId;
|
||||
this.context = context;
|
||||
this.offerId = offerId;
|
||||
this.coinLockedInMultiSig = coinLockedInMultiSig;
|
||||
this.keyBagSupplier = keyBagSupplier;
|
||||
}
|
||||
|
||||
|
@ -210,7 +212,7 @@ public final class AddressEntry implements Persistable {
|
|||
public Message toProtobuf() {
|
||||
PB.AddressEntry.Builder builder = PB.AddressEntry.newBuilder()
|
||||
.setContext(PB.AddressEntry.Context.valueOf(context.name()))
|
||||
.setPubkey(ByteString.copyFrom(pubKey))
|
||||
.setPubKey(ByteString.copyFrom(pubKey))
|
||||
.setPubKeyHash(ByteString.copyFrom(pubKeyHash))
|
||||
.setParamId(paramId);
|
||||
Optional.ofNullable(offerId).ifPresent(builder::setOfferId);
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.google.protobuf.Message;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.common.persistance.Persistable;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.core.btc.wallet.KeyBagSupplier;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import lombok.Getter;
|
||||
import org.bitcoinj.core.Wallet;
|
||||
|
@ -43,13 +44,16 @@ public final class AddressEntryList implements Persistable {
|
|||
private static final Logger log = LoggerFactory.getLogger(AddressEntryList.class);
|
||||
|
||||
final transient private Storage<AddressEntryList> storage;
|
||||
@Getter
|
||||
final transient private KeyBagSupplier keyBagSupplier;
|
||||
transient private Wallet wallet;
|
||||
@Getter
|
||||
private List<AddressEntry> addressEntryList = new ArrayList<>();
|
||||
|
||||
@Inject
|
||||
public AddressEntryList(Storage<AddressEntryList> storage) {
|
||||
public AddressEntryList(Storage<AddressEntryList> storage, KeyBagSupplier keyBagSupplier) {
|
||||
this.storage = storage;
|
||||
this.keyBagSupplier = keyBagSupplier;
|
||||
}
|
||||
|
||||
public void onWalletReady(Wallet wallet) {
|
||||
|
|
|
@ -22,10 +22,7 @@ import com.google.inject.name.Names;
|
|||
import io.bisq.common.app.AppModule;
|
||||
import io.bisq.core.app.AppOptionKeys;
|
||||
import io.bisq.core.btc.provider.squ.BsqUtxoFeedService;
|
||||
import io.bisq.core.btc.wallet.BsqWalletService;
|
||||
import io.bisq.core.btc.wallet.BtcWalletService;
|
||||
import io.bisq.core.btc.wallet.TradeWalletService;
|
||||
import io.bisq.core.btc.wallet.WalletsSetup;
|
||||
import io.bisq.core.btc.wallet.*;
|
||||
import io.bisq.core.provider.fee.FeeService;
|
||||
import io.bisq.core.provider.price.PriceFeedService;
|
||||
import io.bisq.network.http.HttpClient;
|
||||
|
@ -64,6 +61,7 @@ public class BitcoinModule extends AppModule {
|
|||
bind(AddressEntryList.class).in(Singleton.class);
|
||||
bind(WalletsSetup.class).in(Singleton.class);
|
||||
bind(BtcWalletService.class).in(Singleton.class);
|
||||
bind(KeyBagSupplier.class).to(BtcWalletService.class);
|
||||
bind(BsqWalletService.class).in(Singleton.class);
|
||||
bind(TradeWalletService.class).in(Singleton.class);
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ public class BtcWalletService extends WalletService implements KeyBagSupplier {
|
|||
// mining fee: BTC mining fee + optional burned BSQ fee (only if opReturnData != null)
|
||||
|
||||
// In case of txs for burned BSQ fees we have no receiver output and it might be that there is no change outputs
|
||||
// We need to guarantee that min. 1 valid output is added (OP_RETURN does not count). So we use a higher input
|
||||
// We need to guarantee that min. 1 valid output is added (OP_RETURN does not count). So we use a higher input
|
||||
// for BTC to force an additional change output.
|
||||
|
||||
// safety check counter to avoid endless loops
|
||||
|
@ -232,7 +232,7 @@ public class BtcWalletService extends WalletService implements KeyBagSupplier {
|
|||
|
||||
resultTx = sendRequest.tx;
|
||||
|
||||
// We might have the rare case that both inputs matched the required fees, so both did not require
|
||||
// We might have the rare case that both inputs matched the required fees, so both did not require
|
||||
// a change output.
|
||||
// In such cases we need to add artificially a change output (OP_RETURN is not allowed as only output)
|
||||
forcedChangeValue = resultTx.getOutputs().size() == 0 ? Transaction.MIN_NONDUST_OUTPUT : Coin.ZERO;
|
||||
|
@ -266,7 +266,7 @@ public class BtcWalletService extends WalletService implements KeyBagSupplier {
|
|||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Commit tx
|
||||
// Commit tx
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void commitTx(Transaction tx) {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package io.bisq.core.btc.wallet;
|
||||
|
||||
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;
|
||||
|
@ -48,15 +47,13 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.inject.internal.util.$Preconditions.checkArgument;
|
||||
import static com.google.inject.internal.util.$Preconditions.checkState;
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
|
||||
// TradeService handles all relevant transactions used in the trade process
|
||||
/*
|
||||
To maintain a consistent tx structure we use that structure:
|
||||
To maintain a consistent tx structure we use that structure:
|
||||
Always buyers in/outputs/keys first then sellers in/outputs/keys the arbitrators outputs/keys.
|
||||
|
||||
|
||||
Deposit tx:
|
||||
IN[0] buyer (mandatory) e.g. 0.1 BTC
|
||||
IN[...] optional additional buyer inputs (normally never used as we pay from trade fee tx and always have 1 output there)
|
||||
|
@ -67,30 +64,30 @@ import static com.google.inject.internal.util.$Preconditions.checkState;
|
|||
OUT[...] optional buyer change (normally never used as we pay from trade fee tx and always have 1 output there)
|
||||
OUT[...] optional seller change (normally never used as we pay from trade fee tx and always have 1 output there)
|
||||
FEE tx fee 0.0001 BTC
|
||||
|
||||
|
||||
Payout tx:
|
||||
IN[0] Multisig output from deposit Tx (signed by buyer and trader)
|
||||
OUT[0] Buyer payout address
|
||||
OUT[1] Seller payout address
|
||||
|
||||
We use 0 confirmation transactions to make the trade process practical from usability side.
|
||||
|
||||
We use 0 confirmation transactions to make the trade process practical from usability side.
|
||||
There is no risk for double spends as the deposit transaction would become invalid if any preceding transaction would have been double spent.
|
||||
If a preceding transaction in the chain will not make it into the same or earlier block as the deposit transaction the deposit transaction
|
||||
will be invalid as well.
|
||||
If a preceding transaction in the chain will not make it into the same or earlier block as the deposit transaction the deposit transaction
|
||||
will be invalid as well.
|
||||
Though the deposit need 1 confirmation before the buyer starts the Fiat payment.
|
||||
|
||||
|
||||
We have that chain of transactions:
|
||||
1. Deposit from external wallet to our trading wallet: Tx0 (0 conf)
|
||||
2. Create offer (or take offer) fee payment from Tx0 output: tx1 (0 conf)
|
||||
3. Deposit tx created with inputs from tx1 of both traders: Tx2 (here we wait for 1 conf)
|
||||
|
||||
|
||||
Fiat transaction will not start before we get at least 1 confirmation for the deposit tx, then we can proceed.
|
||||
4. Payout tx with input from MS output and output to both traders: Tx3 (0 conf)
|
||||
5. Withdrawal to external wallet from Tx3: Tx4 (0 conf)
|
||||
|
||||
After the payout transaction we also don't have issues with 0 conf or if not both tx (payout, withdrawal) make it into a block.
|
||||
|
||||
After the payout transaction we also don't have issues with 0 conf or if not both tx (payout, withdrawal) make it into a block.
|
||||
Worst case is to rebroadcast the transactions (TODO: is not implemented yet).
|
||||
|
||||
|
||||
*/
|
||||
public class TradeWalletService {
|
||||
private static final Logger log = LoggerFactory.getLogger(TradeWalletService.class);
|
||||
|
@ -191,7 +188,7 @@ public class TradeWalletService {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// We construct the deposit transaction in the way that the buyer is always the first entry (inputs, outputs, MS keys) and then the seller.
|
||||
// In the creation of the deposit tx the taker/maker roles are the determining roles instead of buyer/seller.
|
||||
// In the creation of the deposit tx the taker/maker roles are the determining roles instead of buyer/seller.
|
||||
// In the payout tx is is the buyer/seller role. We keep the buyer/seller ordering over all transactions to not get confusion with ordering,
|
||||
// which is important to follow correctly specially for the order of the MS keys.
|
||||
|
||||
|
@ -221,12 +218,12 @@ public class TradeWalletService {
|
|||
|
||||
/*
|
||||
The tx we create has that structure:
|
||||
|
||||
|
||||
IN[0] any input > inputAmount (including tx fee) (unsigned)
|
||||
IN[1...n] optional inputs supported, but normally there is just 1 input (unsigned)
|
||||
OUT[0] dummyOutputAmount (inputAmount - tx fee)
|
||||
OUT[1] Optional Change = inputAmount - dummyOutputAmount - tx fee
|
||||
|
||||
|
||||
We are only interested in the inputs and the optional change output.
|
||||
*/
|
||||
|
||||
|
@ -241,7 +238,7 @@ public class TradeWalletService {
|
|||
dummyTX.addOutput(dummyOutput);
|
||||
|
||||
// Find the needed inputs to pay the output, optionally add 1 change output.
|
||||
// Normally only 1 input and no change output is used, but we support multiple inputs and 1 change output.
|
||||
// Normally only 1 input and no change output is used, but we support multiple inputs and 1 change output.
|
||||
// Our spending transaction output is from the create offer fee payment.
|
||||
addAvailableInputsAndChangeOutputs(dummyTX, takersAddress, takersChangeAddress, txFee);
|
||||
|
||||
|
@ -325,7 +322,7 @@ public class TradeWalletService {
|
|||
|
||||
checkArgument(!takerRawTransactionInputs.isEmpty());
|
||||
|
||||
// First we construct a dummy TX to get the inputs and outputs we want to use for the real deposit tx.
|
||||
// First we construct a dummy TX to get the inputs and outputs we want to use for the real deposit tx.
|
||||
// Similar to the way we did in the createTakerDepositTxInputs method.
|
||||
Transaction dummyTx = new Transaction(params);
|
||||
TransactionOutput dummyOutput = new TransactionOutput(params, dummyTx, makerInputAmount, new ECKey().toAddress(params));
|
||||
|
@ -336,7 +333,7 @@ public class TradeWalletService {
|
|||
TransactionOutput makerOutput = null;
|
||||
|
||||
// We don't support more then 1 optional change output
|
||||
Preconditions.checkArgument(dummyTx.getOutputs().size() < 3, "dummyTx.getOutputs().size() >= 3");
|
||||
checkArgument(dummyTx.getOutputs().size() < 3, "dummyTx.getOutputs().size() >= 3");
|
||||
|
||||
// Only save change outputs, the dummy output is ignored (that's why we start with index 1)
|
||||
if (dummyTx.getOutputs().size() > 1)
|
||||
|
@ -391,26 +388,26 @@ public class TradeWalletService {
|
|||
new Address(params, takerChangeAddressString));
|
||||
|
||||
if (makerIsBuyer) {
|
||||
// Add optional buyer outputs
|
||||
// Add optional buyer outputs
|
||||
if (makerOutput != null)
|
||||
preparedDepositTx.addOutput(makerOutput);
|
||||
|
||||
// Add optional seller outputs
|
||||
// Add optional seller outputs
|
||||
if (takerTransactionOutput != null)
|
||||
preparedDepositTx.addOutput(takerTransactionOutput);
|
||||
} else {
|
||||
// taker is buyer role
|
||||
|
||||
// Add optional seller outputs
|
||||
// Add optional seller outputs
|
||||
if (takerTransactionOutput != null)
|
||||
preparedDepositTx.addOutput(takerTransactionOutput);
|
||||
|
||||
// Add optional buyer outputs
|
||||
// Add optional buyer outputs
|
||||
if (makerOutput != null)
|
||||
preparedDepositTx.addOutput(makerOutput);
|
||||
}
|
||||
|
||||
// Sign inputs
|
||||
// Sign inputs
|
||||
int start = makerIsBuyer ? 0 : takerRawTransactionInputs.size();
|
||||
int end = makerIsBuyer ? makerInputs.size() : preparedDepositTx.getInputs().size();
|
||||
for (int i = start; i < end; i++) {
|
||||
|
@ -471,7 +468,7 @@ public class TradeWalletService {
|
|||
if (!makersDepositTx.getOutput(0).getScriptPubKey().equals(p2SHMultiSigOutputScript))
|
||||
throw new TransactionVerificationException("Maker's p2SHMultiSigOutputScript does not match to takers p2SHMultiSigOutputScript");
|
||||
|
||||
// The outpoints are not available from the serialized makersDepositTx, so we cannot use that tx directly, but we use it to construct a new
|
||||
// The outpoints are not available from the serialized makersDepositTx, so we cannot use that tx directly, but we use it to construct a new
|
||||
// depositTx
|
||||
Transaction depositTx = new Transaction(params);
|
||||
|
||||
|
@ -481,7 +478,7 @@ public class TradeWalletService {
|
|||
for (int i = 0; i < buyerInputs.size(); i++)
|
||||
depositTx.addInput(getTransactionInput(depositTx, getScriptProgram(makersDepositTx, i), buyerInputs.get(i)));
|
||||
|
||||
// Add seller inputs
|
||||
// Add seller inputs
|
||||
for (RawTransactionInput rawTransactionInput : sellerInputs)
|
||||
depositTx.addInput(getTransactionInput(depositTx, new byte[]{}, rawTransactionInput));
|
||||
} else {
|
||||
|
@ -490,7 +487,7 @@ public class TradeWalletService {
|
|||
for (RawTransactionInput rawTransactionInput : buyerInputs)
|
||||
depositTx.addInput(getTransactionInput(depositTx, new byte[]{}, rawTransactionInput));
|
||||
|
||||
// Add seller inputs
|
||||
// Add seller inputs
|
||||
// We grab the signature from the makersDepositTx and apply it to the new tx input
|
||||
for (int i = buyerInputs.size(), k = 0; i < makersDepositTx.getInputs().size(); i++, k++)
|
||||
depositTx.addInput(getTransactionInput(depositTx, getScriptProgram(makersDepositTx, i), sellerInputs.get(k)));
|
||||
|
@ -509,7 +506,7 @@ public class TradeWalletService {
|
|||
makersDepositTx.getOutputs().forEach(depositTx::addOutput);
|
||||
//BtcWalletService.printTx("makersDepositTx", makersDepositTx);
|
||||
|
||||
// Sign inputs
|
||||
// Sign inputs
|
||||
int start = takerIsSeller ? buyerInputs.size() : 0;
|
||||
int end = takerIsSeller ? depositTx.getInputs().size() : buyerInputs.size();
|
||||
for (int i = start; i < end; i++) {
|
||||
|
@ -938,7 +935,7 @@ public class TradeWalletService {
|
|||
public Transaction addTxToWallet(Transaction transaction) throws VerificationException {
|
||||
Log.traceCall("transaction " + transaction.toString());
|
||||
|
||||
// We need to recreate the transaction otherwise we get a null pointer...
|
||||
// We need to recreate the transaction otherwise we get a null pointer...
|
||||
Transaction result = new Transaction(params, transaction.bitcoinSerialize());
|
||||
result.getConfidence(Context.get()).setSource(TransactionConfidence.Source.SELF);
|
||||
|
||||
|
@ -955,7 +952,7 @@ public class TradeWalletService {
|
|||
public Transaction addTxToWallet(byte[] serializedTransaction) throws VerificationException {
|
||||
Log.traceCall();
|
||||
|
||||
// We need to recreate the tx otherwise we get a null pointer...
|
||||
// We need to recreate the tx otherwise we get a null pointer...
|
||||
Transaction transaction = new Transaction(params, serializedTransaction);
|
||||
transaction.getConfidence(Context.get()).setSource(TransactionConfidence.Source.NETWORK);
|
||||
log.trace("transaction from serializedTransaction: " + transaction.toString());
|
||||
|
@ -1007,11 +1004,11 @@ public class TradeWalletService {
|
|||
}
|
||||
|
||||
|
||||
// Don't use ScriptBuilder.createRedeemScript and ScriptBuilder.createP2SHOutputScript as they use a sorting
|
||||
// (Collections.sort(pubKeys, ECKey.PUBKEY_COMPARATOR);) which can lead to a non-matching list of signatures with pubKeys and the executeMultiSig does
|
||||
// not iterate all possible combinations of sig/pubKeys leading to a verification fault. That nasty bug happens just randomly as the list after sorting
|
||||
// Don't use ScriptBuilder.createRedeemScript and ScriptBuilder.createP2SHOutputScript as they use a sorting
|
||||
// (Collections.sort(pubKeys, ECKey.PUBKEY_COMPARATOR);) which can lead to a non-matching list of signatures with pubKeys and the executeMultiSig does
|
||||
// not iterate all possible combinations of sig/pubKeys leading to a verification fault. That nasty bug happens just randomly as the list after sorting
|
||||
// might differ from the provided one or not.
|
||||
// Changing the while loop in executeMultiSig to fix that does not help as the reference implementation seems to behave the same (not iterating all
|
||||
// Changing the while loop in executeMultiSig to fix that does not help as the reference implementation seems to behave the same (not iterating all
|
||||
// possibilities) .
|
||||
// Furthermore the executed list is reversed to the provided.
|
||||
// Best practice is to provide the list sorted by the least probable successful candidates first (arbitrator is first -> will be last in execution loop, so
|
||||
|
|
|
@ -27,6 +27,7 @@ import io.bisq.common.UserThread;
|
|||
import io.bisq.common.app.Log;
|
||||
import io.bisq.common.handlers.ExceptionHandler;
|
||||
import io.bisq.common.handlers.ResultHandler;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.FileUtil;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.core.btc.*;
|
||||
|
@ -59,9 +60,9 @@ import java.util.stream.Collectors;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
// Setup wallets and use WalletConfig for BitcoinJ wiring.
|
||||
// Other like WalletConfig we are here always on the user thread. That is one reason why we do not
|
||||
// merge WalletsSetup with WalletConfig to one class.
|
||||
// Setup wallets and use WalletConfig for BitcoinJ wiring.
|
||||
// Other like WalletConfig we are here always on the user thread. That is one reason why we do not
|
||||
// merge WalletsSetup with WalletConfig to one class.
|
||||
public class WalletsSetup {
|
||||
private static final Logger log = LoggerFactory.getLogger(WalletsSetup.class);
|
||||
|
||||
|
@ -97,6 +98,7 @@ public class WalletsSetup {
|
|||
UserAgent userAgent,
|
||||
Preferences preferences,
|
||||
Socks5ProxyProvider socks5ProxyProvider,
|
||||
ProtobufferResolver protobufferResolver,
|
||||
@Named(BtcOptionKeys.WALLET_DIR) File appDir,
|
||||
@Named(BtcOptionKeys.SOCKS5_DISCOVER_MODE) String socks5DiscoverModeString) {
|
||||
|
||||
|
@ -111,7 +113,7 @@ public class WalletsSetup {
|
|||
params = preferences.getBitcoinNetwork().getParameters();
|
||||
walletDir = new File(appDir, "bitcoin");
|
||||
|
||||
storage = new Storage<>(walletDir);
|
||||
storage = new Storage<>(walletDir, protobufferResolver);
|
||||
Long nonce = storage.initAndGetPersistedWithFileName("BloomFilterNonce");
|
||||
if (nonce != null) {
|
||||
bloomFilterTweak = nonce;
|
||||
|
@ -148,7 +150,7 @@ public class WalletsSetup {
|
|||
walletConfig = new WalletConfig(params, socks5Proxy, walletDir, walletFileName, bsqWalletFileName) {
|
||||
@Override
|
||||
protected void onSetupCompleted() {
|
||||
//We are here in the btcj thread Thread[ STARTING,5,main]
|
||||
//We are here in the btcj thread Thread[ STARTING,5,main]
|
||||
super.onSetupCompleted();
|
||||
|
||||
final PeerGroup peerGroup = walletConfig.peerGroup();
|
||||
|
@ -286,28 +288,28 @@ public class WalletsSetup {
|
|||
// by getting the real pub keys by intersections of several filters sent at each startup.
|
||||
walletConfig.setBloomFilterTweak(bloomFilterTweak);
|
||||
|
||||
// Avoid the simple attack (see: https://jonasnick.github.io/blog/2015/02/12/privacy-in-bitcoinj/) due to the
|
||||
// Avoid the simple attack (see: https://jonasnick.github.io/blog/2015/02/12/privacy-in-bitcoinj/) due to the
|
||||
// default implementation using both pubkey and hash of pubkey. We have set a insertPubKey flag in BasicKeyChain to default false.
|
||||
|
||||
// Default only 266 keys are generated (2 * 100+33 -> 100 external and 100 internal keys + buffers of 30%). That would trigger new bloom filters when we are reaching
|
||||
// Default only 266 keys are generated (2 * 100+33 -> 100 external and 100 internal keys + buffers of 30%). That would trigger new bloom filters when we are reaching
|
||||
// the threshold. To avoid reaching the threshold we create much more keys which are unlikely to cause update of the
|
||||
// filter for most users. With lookaheadSize of 500 we get 1333 keys (500*1.3=666 666 external and 666 internal keys) which should be enough for most users to
|
||||
// filter for most users. With lookaheadSize of 500 we get 1333 keys (500*1.3=666 666 external and 666 internal keys) which should be enough for most users to
|
||||
// never need to update a bloom filter, which would weaken privacy.
|
||||
// As we use 2 wallets (BTC, BSQ) we generate 1333 + 266 keys in total.
|
||||
walletConfig.setBtcWalletLookaheadSize(500);
|
||||
walletConfig.setBsqWalletLookaheadSize(100);
|
||||
|
||||
// Calculation is derived from: https://www.reddit.com/r/Bitcoin/comments/2vrx6n/privacy_in_bitcoinj_android_wallet_multibit_hive/coknjuz
|
||||
// No. of false positives (56M keys in the blockchain):
|
||||
// No. of false positives (56M keys in the blockchain):
|
||||
// First attempt for FP rate:
|
||||
// FP rate = 0,0001; No. of false positives: 0,0001 * 56 000 000 = 5600
|
||||
// We have 1333keys: 1333 / (5600 + 1333) = 0.19 -> 19 % probability that a pub key is in our wallet
|
||||
// After tests I found out that the bandwidth consumption varies widely related to the generated filter.
|
||||
// About 20- 40 MB for upload and 30-130 MB for download at first start up (spv chain).
|
||||
// Afterwards its about 1 MB for upload and 20-80 MB for download.
|
||||
// Probably better then a high FP rate would be to include foreign pubKeyHashes which are tested to not be used
|
||||
// Probably better then a high FP rate would be to include foreign pubKeyHashes which are tested to not be used
|
||||
// in many transactions. If we had a pool of 100 000 such keys (2 MB data dump) to random select 4000 we could mix it with our
|
||||
// 1000 own keys and get a similar probability rate as with the current setup but less variation in bandwidth
|
||||
// 1000 own keys and get a similar probability rate as with the current setup but less variation in bandwidth
|
||||
// consumption.
|
||||
|
||||
// For now to reduce risks with high bandwidth consumption we reduce the FP rate by half.
|
||||
|
|
|
@ -20,6 +20,7 @@ package io.bisq.core.dao.vote;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.common.persistance.Persistable;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
@ -27,12 +28,13 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Slf4j
|
||||
public final class CompensationRequestVoteItemCollection extends VoteItem implements Persistable {
|
||||
// That object is saved to disc. We need to take care of changes to not break deserialization.
|
||||
private static final long serialVersionUID = Version.LOCAL_DB_VERSION;
|
||||
|
||||
@Getter
|
||||
private final List<CompensationRequestVoteItem> compensationRequestVoteItems = new ArrayList<>();
|
||||
|
||||
/** constructor */
|
||||
|
@ -40,10 +42,6 @@ public final class CompensationRequestVoteItemCollection extends VoteItem implem
|
|||
super(votingType, null, null);
|
||||
}
|
||||
|
||||
public List<CompensationRequestVoteItem> getCompensationRequestVoteItems() {
|
||||
return compensationRequestVoteItems;
|
||||
}
|
||||
|
||||
public List<CompensationRequestVoteItem> getCompensationRequestVoteItemsSortedByTxId() {
|
||||
ArrayList<CompensationRequestVoteItem> list = new ArrayList<>(compensationRequestVoteItems);
|
||||
list.sort((o1, o2) -> o2.compensationRequest.getCompensationRequestPayload().feeTxId.compareTo(o1.compensationRequest.getCompensationRequestPayload().feeTxId));
|
||||
|
|
|
@ -25,6 +25,8 @@ import io.bisq.common.app.Log;
|
|||
import io.bisq.common.crypto.KeyRing;
|
||||
import io.bisq.common.handlers.ErrorMessageHandler;
|
||||
import io.bisq.common.handlers.ResultHandler;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.core.btc.AddressEntry;
|
||||
import io.bisq.core.btc.wallet.BtcWalletService;
|
||||
|
@ -96,6 +98,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
ClosedTradableManager closedTradableManager,
|
||||
PriceFeedService priceFeedService,
|
||||
Preferences preferences,
|
||||
ProtobufferResolver protobufferResolver,
|
||||
@Named(Storage.DIR_KEY) File storageDir) {
|
||||
this.keyRing = keyRing;
|
||||
this.user = user;
|
||||
|
@ -106,7 +109,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
this.closedTradableManager = closedTradableManager;
|
||||
this.preferences = preferences;
|
||||
|
||||
openOffersStorage = new Storage<>(storageDir);
|
||||
openOffersStorage = new Storage<>(storageDir, protobufferResolver);
|
||||
openOffers = new TradableList<>(openOffersStorage, "OpenOffers");
|
||||
openOffers.forEach(e -> e.getOffer().setPriceFeedService(priceFeedService));
|
||||
|
||||
|
@ -207,7 +210,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
// but other peers have it already removed because of expired TTL.
|
||||
// Those other not directly connected peers would not get the broadcast of the new offer, as the first
|
||||
// connected peer (seed node) does nto broadcast if it has the data in the map.
|
||||
// To update quickly to the whole network we repeat the republishOffers call after a few seconds when we
|
||||
// To update quickly to the whole network we repeat the republishOffers call after a few seconds when we
|
||||
// are better connected to the network. There is no guarantee that all peers will receive it but we have
|
||||
// also our periodic timer, so after that longer interval the offer should be available to all peers.
|
||||
if (retryRepublishOffersTimer == null)
|
||||
|
@ -367,8 +370,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
// TODO mediators not impl yet
|
||||
List<NodeAddress> acceptedArbitrators = user.getAcceptedArbitratorAddresses();
|
||||
if (acceptedArbitrators != null && !acceptedArbitrators.isEmpty()) {
|
||||
// Check also tradePrice to avoid failures after taker fee is paid caused by a too big difference
|
||||
// in trade price between the peers. Also here poor connectivity might cause market price API connection
|
||||
// Check also tradePrice to avoid failures after taker fee is paid caused by a too big difference
|
||||
// in trade price between the peers. Also here poor connectivity might cause market price API connection
|
||||
// losses and therefore an outdated market price.
|
||||
try {
|
||||
offer.checkTradePriceTolerance(message.takersTradePrice);
|
||||
|
@ -441,9 +444,9 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe
|
|||
final OpenOffer openOffer = openOffersList.get(i);
|
||||
UserThread.runAfterRandomDelay(() -> {
|
||||
if (openOffers.contains(openOffer)) {
|
||||
// The openOffer.getId().contains("_") check is because there was once a version
|
||||
// The openOffer.getId().contains("_") check is because there was once a version
|
||||
// where we encoded the version nr in the offer id with a "_" as separator.
|
||||
// That caused several issues and was reverted. So if there are still old offers out with that
|
||||
// That caused several issues and was reverted. So if there are still old offers out with that
|
||||
// special offer ID format those must not be published as they cause failed taker attempts
|
||||
// with lost taker fee.
|
||||
String id = openOffer.getId();
|
||||
|
|
|
@ -29,7 +29,7 @@ import io.bisq.core.offer.messages.OfferAvailabilityResponse;
|
|||
import io.bisq.core.offer.messages.OfferMsg;
|
||||
import io.bisq.core.util.Validator;
|
||||
import io.bisq.network.p2p.DecryptedDirectMessageListener;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import io.bisq.common.app.Capabilities;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.core.offer.AvailabilityResult;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.SupportedCapabilitiesMsg;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
package io.bisq.core.p2p.network;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.protobuf.ByteString;
|
||||
import io.bisq.common.crypto.PubKeyRing;
|
||||
import io.bisq.common.crypto.SealedAndSigned;
|
||||
import io.bisq.common.locale.CountryUtil;
|
||||
import io.bisq.common.locale.CurrencyUtil;
|
||||
import io.bisq.common.monetary.Price;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.common.persistance.Persistable;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.core.alert.Alert;
|
||||
import io.bisq.core.alert.PrivateNotificationMsg;
|
||||
import io.bisq.core.alert.PrivateNotificationPayload;
|
||||
import io.bisq.core.arbitration.*;
|
||||
import io.bisq.core.arbitration.messages.*;
|
||||
import io.bisq.core.btc.AddressEntry;
|
||||
import io.bisq.core.btc.AddressEntryList;
|
||||
import io.bisq.core.btc.data.RawTransactionInput;
|
||||
import io.bisq.core.btc.wallet.BtcWalletService;
|
||||
import io.bisq.core.dao.compensation.CompensationRequestPayload;
|
||||
import io.bisq.core.filter.Filter;
|
||||
import io.bisq.core.filter.PaymentAccountFilter;
|
||||
|
@ -27,10 +32,8 @@ import io.bisq.core.trade.messages.*;
|
|||
import io.bisq.core.trade.statistics.TradeStatistics;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.CloseConnectionMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.bisq.network.p2p.PrefixedSealedAndSignedMsg;
|
||||
import io.bisq.network.p2p.network.ProtobufferResolver;
|
||||
import io.bisq.network.p2p.peers.getdata.messages.GetDataResponse;
|
||||
import io.bisq.network.p2p.peers.getdata.messages.GetUpdatedDataRequest;
|
||||
import io.bisq.network.p2p.peers.getdata.messages.PreliminaryGetDataRequest;
|
||||
|
@ -48,15 +51,11 @@ import io.bisq.network.p2p.storage.payload.ProtectedMailboxStorageEntry;
|
|||
import io.bisq.network.p2p.storage.payload.ProtectedStorageEntry;
|
||||
import io.bisq.network.p2p.storage.payload.StoragePayload;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.output.WriterOutputStream;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -76,13 +75,10 @@ import static io.bisq.generated.protobuffer.PB.Envelope.MessageCase.*;
|
|||
*/
|
||||
@Slf4j
|
||||
public class CoreProtobufferResolver implements ProtobufferResolver {
|
||||
private BtcWalletService btcWalletService;
|
||||
|
||||
@Inject
|
||||
public CoreProtobufferResolver(BtcWalletService btcWalletService) {
|
||||
this.btcWalletService = btcWalletService;
|
||||
}
|
||||
|
||||
private Provider<AddressEntryList> addressEntryList;
|
||||
|
||||
@Override
|
||||
public Optional<Msg> fromProto(PB.Envelope envelope) {
|
||||
if (Objects.isNull(envelope)) {
|
||||
|
@ -95,18 +91,6 @@ public class CoreProtobufferResolver implements ProtobufferResolver {
|
|||
log.debug("Convert protobuffer envelope: {}", envelope.getMessageCase());
|
||||
log.trace("Convert protobuffer envelope: {}", envelope.toString());
|
||||
}
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
WriterOutputStream writerOutputStream = new WriterOutputStream(stringWriter);
|
||||
|
||||
try {
|
||||
envelope.writeTo(writerOutputStream);
|
||||
writerOutputStream.flush();
|
||||
stringWriter.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// todo just for testing...
|
||||
AddressEntry AddressEntry = new AddressEntry(null, null, null, null, null, btcWalletService);
|
||||
|
||||
Msg result = null;
|
||||
switch (envelope.getMessageCase()) {
|
||||
|
@ -869,4 +853,56 @@ public class CoreProtobufferResolver implements ProtobufferResolver {
|
|||
.stream()
|
||||
.map(ByteString::toByteArray).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////// DISK /////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public Optional<Persistable> fromProto(PB.DiskEnvelope envelope) {
|
||||
if (Objects.isNull(envelope)) {
|
||||
log.warn("fromProtoBuf called with empty disk envelope.");
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
log.debug("Convert protobuffer disk envelope: {}", envelope.getMessageCase());
|
||||
|
||||
Persistable result = null;
|
||||
switch (envelope.getMessageCase()) {
|
||||
case ADDRESS_ENTRY_LIST:
|
||||
addToAddressEntryList(envelope);
|
||||
result = addressEntryList.get();
|
||||
break;
|
||||
/*
|
||||
case NAVIGATION:
|
||||
result = getPing(envelope);
|
||||
break;
|
||||
case PERSISTED_PEERS:
|
||||
result = getPing(envelope);
|
||||
break;
|
||||
case PREFERENCES:
|
||||
result = getPing(envelope);
|
||||
break;
|
||||
case USER:
|
||||
result = getPing(envelope);
|
||||
break;
|
||||
case PERSISTED_P2P_STORAGE_DATA:
|
||||
result = getPing(envelope);
|
||||
break;
|
||||
case SEQUENCE_NUMBER_MAP:
|
||||
result = getPing(envelope);
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
log.warn("Unknown message case:{}:{}", envelope.getMessageCase());
|
||||
}
|
||||
return Optional.ofNullable(result);
|
||||
}
|
||||
|
||||
private void addToAddressEntryList(PB.DiskEnvelope envelope) {
|
||||
envelope.getAddressEntryList().getAddressEntryList().stream().map(addressEntry -> addressEntryList.get().addAddressEntry(
|
||||
new AddressEntry(addressEntry.getPubKey().toByteArray(), addressEntry.getPubKeyHash().toByteArray(), addressEntry.getParamId(), AddressEntry.Context.valueOf(addressEntry.getContext().name()),
|
||||
addressEntry.getOfferId(), Coin.valueOf(addressEntry.getCoinLockedInMultiSig().getValue()), addressEntryList.get().getKeyBagSupplier())));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import io.bisq.common.crypto.KeyRing;
|
|||
import io.bisq.common.handlers.ErrorMessageHandler;
|
||||
import io.bisq.common.handlers.FaultHandler;
|
||||
import io.bisq.common.handlers.ResultHandler;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.core.arbitration.ArbitratorManager;
|
||||
import io.bisq.core.btc.AddressEntry;
|
||||
|
@ -111,6 +113,7 @@ public class TradeManager {
|
|||
PriceFeedService priceFeedService,
|
||||
FilterManager filterManager,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
ProtobufferResolver protobufferResolver,
|
||||
@Named(Storage.DIR_KEY) File storageDir) {
|
||||
this.user = user;
|
||||
this.keyRing = keyRing;
|
||||
|
@ -124,7 +127,7 @@ public class TradeManager {
|
|||
this.filterManager = filterManager;
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
|
||||
tradableListStorage = new Storage<>(storageDir);
|
||||
tradableListStorage = new Storage<>(storageDir, protobufferResolver);
|
||||
trades = new TradableList<>(tradableListStorage, "PendingTrades");
|
||||
trades.forEach(e -> e.getOffer().setPriceFeedService(priceFeedService));
|
||||
|
||||
|
@ -234,7 +237,7 @@ public class TradeManager {
|
|||
|
||||
// We only republish trades from last 10 days
|
||||
// TODO check if needed at all. Don't want to remove it atm to not risk anything.
|
||||
// But we could check which tradeStatistics we received from the seed nodes and
|
||||
// But we could check which tradeStatistics we received from the seed nodes and
|
||||
// only re-publish in case tradeStatistics are missing.
|
||||
if ((new Date().getTime() - trade.getDate().getTime()) < TimeUnit.DAYS.toMillis(10)) {
|
||||
long delay = 5000;
|
||||
|
@ -493,4 +496,4 @@ public class TradeManager {
|
|||
return getTrades().stream()
|
||||
.filter(trade -> trade.isDepositPublished() && !trade.isPayoutPublished());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package io.bisq.core.trade.closed;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
import io.bisq.common.crypto.KeyRing;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.core.offer.Offer;
|
||||
import io.bisq.core.provider.price.PriceFeedService;
|
||||
|
@ -38,9 +39,11 @@ public class ClosedTradableManager {
|
|||
private final KeyRing keyRing;
|
||||
|
||||
@Inject
|
||||
public ClosedTradableManager(KeyRing keyRing, PriceFeedService priceFeedService, @Named(Storage.DIR_KEY) File storageDir) {
|
||||
public ClosedTradableManager(KeyRing keyRing, PriceFeedService priceFeedService,
|
||||
ProtobufferResolver protobufferResolver,
|
||||
@Named(Storage.DIR_KEY) File storageDir) {
|
||||
this.keyRing = keyRing;
|
||||
final Storage<TradableList<Tradable>> tradableListStorage = new Storage<>(storageDir);
|
||||
final Storage<TradableList<Tradable>> tradableListStorage = new Storage<>(storageDir, protobufferResolver);
|
||||
// The ClosedTrades object can become a few MB so we don't keep so many backups
|
||||
tradableListStorage.setNumMaxBackupFiles(3);
|
||||
this.closedTrades = new TradableList<>(tradableListStorage, "ClosedTrades");
|
||||
|
|
|
@ -19,6 +19,7 @@ package io.bisq.core.trade.failed;
|
|||
|
||||
import com.google.inject.Inject;
|
||||
import io.bisq.common.crypto.KeyRing;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.core.offer.Offer;
|
||||
import io.bisq.core.provider.price.PriceFeedService;
|
||||
|
@ -38,9 +39,11 @@ public class FailedTradesManager {
|
|||
private final KeyRing keyRing;
|
||||
|
||||
@Inject
|
||||
public FailedTradesManager(KeyRing keyRing, PriceFeedService priceFeedService, @Named(Storage.DIR_KEY) File storageDir) {
|
||||
public FailedTradesManager(KeyRing keyRing, PriceFeedService priceFeedService,
|
||||
ProtobufferResolver protobufferResolver,
|
||||
@Named(Storage.DIR_KEY) File storageDir) {
|
||||
this.keyRing = keyRing;
|
||||
this.failedTrades = new TradableList<>(new Storage<>(storageDir), "FailedTrades");
|
||||
this.failedTrades = new TradableList<>(new Storage<>(storageDir, protobufferResolver), "FailedTrades");
|
||||
failedTrades.forEach(e -> e.getOffer().setPriceFeedService(priceFeedService));
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import com.google.protobuf.ByteString;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
|
|
@ -21,7 +21,7 @@ import com.google.protobuf.ByteString;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import com.google.protobuf.ByteString;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import io.bisq.common.crypto.PubKeyRing;
|
|||
import io.bisq.core.btc.data.RawTransactionInput;
|
||||
import io.bisq.core.payment.payload.PaymentAccountPayload;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
|
|
@ -21,7 +21,7 @@ import com.google.protobuf.ByteString;
|
|||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import io.bisq.core.btc.data.RawTransactionInput;
|
|||
import io.bisq.core.payment.payload.PaymentAccountPayload;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
|
|
@ -33,7 +33,7 @@ import io.bisq.core.trade.protocol.tasks.buyer_as_maker.BuyerAsMakerSignPayoutTx
|
|||
import io.bisq.core.trade.protocol.tasks.maker.*;
|
||||
import io.bisq.core.util.Validator;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import io.bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerCreatesDepos
|
|||
import io.bisq.core.trade.protocol.tasks.buyer_as_taker.BuyerAsTakerSignAndPublishDepositTx;
|
||||
import io.bisq.core.trade.protocol.tasks.taker.*;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
|
|
@ -88,8 +88,11 @@ public class ProcessModel implements Model, Serializable {
|
|||
@Getter
|
||||
@Setter
|
||||
private List<NodeAddress> takerAcceptedArbitratorNodeAddresses;
|
||||
@Getter
|
||||
@Setter
|
||||
private List<NodeAddress> takerAcceptedMediatorNodeAddresses;
|
||||
|
||||
|
||||
// that is used to store temp. the peers address when we get an incoming message before the message is verified.
|
||||
// After successful verified we copy that over to the trade.tradingPeerAddress
|
||||
@Getter
|
||||
|
@ -196,10 +199,6 @@ public class ProcessModel implements Model, Serializable {
|
|||
return payoutTxSignature;
|
||||
}
|
||||
|
||||
public void setPayoutTxSignature(byte[] payoutTxSignature) {
|
||||
this.payoutTxSignature = payoutTxSignature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void persist() {
|
||||
}
|
||||
|
@ -212,62 +211,6 @@ public class ProcessModel implements Model, Serializable {
|
|||
return keyRing.getPubKeyRing();
|
||||
}
|
||||
|
||||
public KeyRing getKeyRing() {
|
||||
return keyRing;
|
||||
}
|
||||
|
||||
public void setTakerAcceptedArbitratorNodeAddresses(List<NodeAddress> takerAcceptedArbitratorNodeAddresses) {
|
||||
this.takerAcceptedArbitratorNodeAddresses = takerAcceptedArbitratorNodeAddresses;
|
||||
}
|
||||
|
||||
public List<NodeAddress> getTakerAcceptedArbitratorNodeAddresses() {
|
||||
return takerAcceptedArbitratorNodeAddresses;
|
||||
}
|
||||
|
||||
public void setTakerAcceptedMediatorNodeAddresses(List<NodeAddress> takerAcceptedMediatorNodeAddresses) {
|
||||
this.takerAcceptedMediatorNodeAddresses = takerAcceptedMediatorNodeAddresses;
|
||||
}
|
||||
|
||||
public List<NodeAddress> getTakerAcceptedMediatorNodeAddresses() {
|
||||
return takerAcceptedMediatorNodeAddresses;
|
||||
}
|
||||
|
||||
public void setTempTradingPeerNodeAddress(NodeAddress tempTradingPeerNodeAddress) {
|
||||
this.tempTradingPeerNodeAddress = tempTradingPeerNodeAddress;
|
||||
}
|
||||
|
||||
public NodeAddress getTempTradingPeerNodeAddress() {
|
||||
return tempTradingPeerNodeAddress;
|
||||
}
|
||||
|
||||
public ArbitratorManager getArbitratorManager() {
|
||||
return arbitratorManager;
|
||||
}
|
||||
|
||||
public void setPreparedDepositTx(byte[] preparedDepositTx) {
|
||||
this.preparedDepositTx = preparedDepositTx;
|
||||
}
|
||||
|
||||
public byte[] getPreparedDepositTx() {
|
||||
return preparedDepositTx;
|
||||
}
|
||||
|
||||
public void setRawTransactionInputs(ArrayList<RawTransactionInput> rawTransactionInputs) {
|
||||
this.rawTransactionInputs = rawTransactionInputs;
|
||||
}
|
||||
|
||||
public ArrayList<RawTransactionInput> getRawTransactionInputs() {
|
||||
return rawTransactionInputs;
|
||||
}
|
||||
|
||||
public void setChangeOutputValue(long changeOutputValue) {
|
||||
this.changeOutputValue = changeOutputValue;
|
||||
}
|
||||
|
||||
public long getChangeOutputValue() {
|
||||
return changeOutputValue;
|
||||
}
|
||||
|
||||
public void setChangeOutputAddress(String changeOutputAddress) {
|
||||
this.changeOutputAddress = changeOutputAddress;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ import io.bisq.core.trade.protocol.tasks.seller.SellerSignAndFinalizePayoutTx;
|
|||
import io.bisq.core.trade.protocol.tasks.seller_as_maker.SellerAsMakerCreatesAndSignsDepositTx;
|
||||
import io.bisq.core.util.Validator;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import io.bisq.core.trade.protocol.tasks.seller_as_taker.SellerAsTakerCreatesDep
|
|||
import io.bisq.core.trade.protocol.tasks.seller_as_taker.SellerAsTakerSignAndPublishDepositTx;
|
||||
import io.bisq.core.trade.protocol.tasks.taker.*;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import io.bisq.core.trade.TradeManager;
|
|||
import io.bisq.core.trade.messages.TradeMsg;
|
||||
import io.bisq.network.p2p.DecryptedDirectMessageListener;
|
||||
import io.bisq.network.p2p.DecryptedMsgWithPubKey;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
|
@ -39,7 +39,7 @@ import io.bisq.gui.common.view.CachingViewLoader;
|
|||
import io.bisq.gui.main.overlays.notifications.NotificationCenter;
|
||||
import io.bisq.network.crypto.EncryptionServiceModule;
|
||||
import io.bisq.network.p2p.P2PModule;
|
||||
import io.bisq.network.p2p.network.ProtobufferResolver;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.google.inject.Inject;
|
|||
import io.bisq.common.locale.CryptoCurrency;
|
||||
import io.bisq.common.locale.FiatCurrency;
|
||||
import io.bisq.common.locale.TradeCurrency;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.core.offer.OpenOfferManager;
|
||||
import io.bisq.core.payment.CryptoCurrencyAccount;
|
||||
import io.bisq.core.payment.PaymentAccount;
|
||||
|
@ -49,15 +50,17 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
|
|||
final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
|
||||
private final SetChangeListener<PaymentAccount> setChangeListener;
|
||||
private final String accountsFileName = "AltcoinPaymentAccounts";
|
||||
private final ProtobufferResolver protobufferResolver;
|
||||
|
||||
@Inject
|
||||
public AltCoinAccountsDataModel(User user, Preferences preferences, OpenOfferManager openOfferManager,
|
||||
TradeManager tradeManager, Stage stage) {
|
||||
TradeManager tradeManager, Stage stage, ProtobufferResolver protobufferResolver) {
|
||||
this.user = user;
|
||||
this.preferences = preferences;
|
||||
this.openOfferManager = openOfferManager;
|
||||
this.tradeManager = tradeManager;
|
||||
this.stage = stage;
|
||||
this.protobufferResolver = protobufferResolver;
|
||||
setChangeListener = change -> fillAndSortPaymentAccounts();
|
||||
}
|
||||
|
||||
|
@ -126,10 +129,10 @@ class AltCoinAccountsDataModel extends ActivatableDataModel {
|
|||
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
|
||||
.filter(paymentAccount -> paymentAccount instanceof CryptoCurrencyAccount)
|
||||
.collect(Collectors.toList()));
|
||||
GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage);
|
||||
GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, protobufferResolver);
|
||||
}
|
||||
|
||||
public void importAccounts() {
|
||||
GUIUtil.importAccounts(user, accountsFileName, preferences, stage);
|
||||
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, protobufferResolver);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.google.inject.Inject;
|
|||
import io.bisq.common.locale.CryptoCurrency;
|
||||
import io.bisq.common.locale.FiatCurrency;
|
||||
import io.bisq.common.locale.TradeCurrency;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.core.offer.OpenOfferManager;
|
||||
import io.bisq.core.payment.CryptoCurrencyAccount;
|
||||
import io.bisq.core.payment.PaymentAccount;
|
||||
|
@ -49,15 +50,17 @@ class FiatAccountsDataModel extends ActivatableDataModel {
|
|||
final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList();
|
||||
private final SetChangeListener<PaymentAccount> setChangeListener;
|
||||
private final String accountsFileName = "FiatPaymentAccounts";
|
||||
private final ProtobufferResolver protobufferResolver;
|
||||
|
||||
@Inject
|
||||
public FiatAccountsDataModel(User user, Preferences preferences, OpenOfferManager openOfferManager,
|
||||
TradeManager tradeManager, Stage stage) {
|
||||
TradeManager tradeManager, Stage stage, ProtobufferResolver protobufferResolver) {
|
||||
this.user = user;
|
||||
this.preferences = preferences;
|
||||
this.openOfferManager = openOfferManager;
|
||||
this.tradeManager = tradeManager;
|
||||
this.stage = stage;
|
||||
this.protobufferResolver = protobufferResolver;
|
||||
setChangeListener = change -> fillAndSortPaymentAccounts();
|
||||
}
|
||||
|
||||
|
@ -127,10 +130,10 @@ class FiatAccountsDataModel extends ActivatableDataModel {
|
|||
ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream()
|
||||
.filter(paymentAccount -> !(paymentAccount instanceof CryptoCurrencyAccount))
|
||||
.collect(Collectors.toList()));
|
||||
GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage);
|
||||
GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, protobufferResolver);
|
||||
}
|
||||
|
||||
public void importAccounts() {
|
||||
GUIUtil.importAccounts(user, accountsFileName, preferences, stage);
|
||||
GUIUtil.importAccounts(user, accountsFileName, preferences, stage, protobufferResolver);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,8 @@ import org.bitcoinj.crypto.KeyCrypterScrypt;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static com.google.inject.internal.util.$Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
|
||||
@FxmlView
|
||||
public class PasswordView extends ActivatableView<GridPane, Void> {
|
||||
|
|
|
@ -59,7 +59,7 @@ import java.time.ZoneId;
|
|||
import java.time.ZoneOffset;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static com.google.inject.internal.util.$Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static io.bisq.gui.util.FormBuilder.*;
|
||||
import static javafx.beans.binding.Bindings.createBooleanBinding;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import io.bisq.common.app.DevEnv;
|
|||
import io.bisq.common.locale.CurrencyUtil;
|
||||
import io.bisq.common.locale.Res;
|
||||
import io.bisq.common.locale.TradeCurrency;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.core.payment.PaymentAccount;
|
||||
|
@ -88,10 +89,11 @@ public class GUIUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static void exportAccounts(ArrayList<PaymentAccount> accounts, String fileName, Preferences preferences, Stage stage) {
|
||||
public static void exportAccounts(ArrayList<PaymentAccount> accounts, String fileName,
|
||||
Preferences preferences, Stage stage, ProtobufferResolver protobufferResolver) {
|
||||
if (!accounts.isEmpty()) {
|
||||
String directory = getDirectoryFromChooser(preferences, stage);
|
||||
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory));
|
||||
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory), protobufferResolver);
|
||||
paymentAccountsStorage.initAndGetPersisted(accounts, fileName);
|
||||
paymentAccountsStorage.queueUpForSave();
|
||||
new Popup<>().feedback(Res.get("guiUtil.accountExport.savedToPath", Paths.get(directory, fileName).toAbsolutePath())).show();
|
||||
|
@ -100,7 +102,8 @@ public class GUIUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static void importAccounts(User user, String fileName, Preferences preferences, Stage stage) {
|
||||
public static void importAccounts(User user, String fileName, Preferences preferences, Stage stage,
|
||||
ProtobufferResolver protobufferResolver) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setInitialDirectory(new File(preferences.getDirectoryChooserPath()));
|
||||
fileChooser.setTitle(Res.get("guiUtil.accountExport.selectPath", fileName));
|
||||
|
@ -110,7 +113,7 @@ public class GUIUtil {
|
|||
if (Paths.get(path).getFileName().toString().equals(fileName)) {
|
||||
String directory = Paths.get(path).getParent().toString();
|
||||
preferences.setDirectoryChooserPath(directory);
|
||||
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory));
|
||||
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory), protobufferResolver);
|
||||
ArrayList<PaymentAccount> persisted = paymentAccountsStorage.initAndGetPersistedWithFileName(fileName);
|
||||
if (persisted != null) {
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package io.bisq.network.crypto;
|
||||
|
||||
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
import java.security.PublicKey;
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ import io.bisq.common.Marshaller;
|
|||
import io.bisq.common.crypto.*;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.DecryptedMsgWithPubKey;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.network.p2p.network.ProtobufferResolver;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
package io.bisq.network.p2p;
|
||||
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
public interface AnonymousMsg extends Msg {
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.bisq.network.p2p;
|
||||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
|
||||
public final class CloseConnectionMsg implements Msg {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package io.bisq.network.p2p;
|
||||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.common.persistance.Persistable;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
|
|
@ -17,5 +17,7 @@
|
|||
|
||||
package io.bisq.network.p2p;
|
||||
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
public interface DirectMsg extends Msg {
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ import io.bisq.common.app.Log;
|
|||
import io.bisq.common.crypto.CryptoException;
|
||||
import io.bisq.common.crypto.KeyRing;
|
||||
import io.bisq.common.crypto.PubKeyRing;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.FileUtil;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.common.util.Utilities;
|
||||
|
@ -198,11 +200,11 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
else
|
||||
seedNodeAddresses = seedNodesRepository.getSeedNodeAddresses(useLocalhostForP2P, networkId);
|
||||
|
||||
peerManager = new PeerManager(networkNode, maxConnections, seedNodeAddresses, storageDir, clock);
|
||||
peerManager = new PeerManager(networkNode, maxConnections, seedNodeAddresses, storageDir, clock, protobufferResolver);
|
||||
|
||||
broadcaster = new Broadcaster(networkNode, peerManager);
|
||||
|
||||
p2PDataStorage = new P2PDataStorage(broadcaster, networkNode, storageDir);
|
||||
p2PDataStorage = new P2PDataStorage(broadcaster, networkNode, storageDir, protobufferResolver);
|
||||
p2PDataStorage.addHashMapChangedListener(this);
|
||||
|
||||
requestDataManager = new RequestDataManager(networkNode, p2PDataStorage, peerManager, seedNodeAddresses, this);
|
||||
|
@ -432,7 +434,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
try {
|
||||
PrefixedSealedAndSignedMsg prefixedSealedAndSignedMessage = (PrefixedSealedAndSignedMsg) msg;
|
||||
if (verifyAddressPrefixHash(prefixedSealedAndSignedMessage)) {
|
||||
// We set connectionType to that connection to avoid that is get closed when
|
||||
// We set connectionType to that connection to avoid that is get closed when
|
||||
// we get too many connection attempts.
|
||||
connection.setPeerType(Connection.PeerType.DIRECT_MSG_PEER);
|
||||
|
||||
|
@ -683,7 +685,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
|
||||
@Override
|
||||
public void onBroadcastFailed(String errorMessage) {
|
||||
// TODO investigate why not sending sendMailboxMessageListener.onFault. Related probably
|
||||
// TODO investigate why not sending sendMailboxMessageListener.onFault. Related probably
|
||||
// to the logic from BroadcastHandler.sendToPeer
|
||||
}
|
||||
};
|
||||
|
@ -712,7 +714,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis
|
|||
// We need to delay a bit to avoid that we remove our msg then get it from other peers again and reapply it again.
|
||||
// If we delay the removal we have better chances that repeated network_messages we got from other peers are already filtered
|
||||
// at the P2PService layer.
|
||||
// Though we have to check in the client classes to not apply the same message again as there is no guarantee
|
||||
// Though we have to check in the client classes to not apply the same message again as there is no guarantee
|
||||
// when we would get a message again from the network.
|
||||
UserThread.runAfter(() -> {
|
||||
delayedRemoveEntryFromMailbox(decryptedMsgWithPubKey);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package io.bisq.network.p2p;
|
||||
|
||||
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
public interface SendersNodeAddressMsg extends Msg {
|
||||
NodeAddress getSenderNodeAddress();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.bisq.network.p2p;
|
||||
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import com.google.common.util.concurrent.Uninterruptibles;
|
|||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.util.Tuple2;
|
||||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.bisq.network.p2p.network;
|
||||
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
|
||||
import java.net.Socket;
|
||||
|
||||
public class InboundConnection extends Connection {
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.msopentech.thali.java.toronionproxy.JavaOnionProxyContext;
|
|||
import com.msopentech.thali.java.toronionproxy.JavaOnionProxyManager;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.nucleo.net.HiddenServiceDescriptor;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.bisq.network.p2p.network;
|
||||
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
public interface MessageListener {
|
||||
void onMessage(Msg msg, Connection connection);
|
||||
|
|
|
@ -4,8 +4,9 @@ import com.google.common.util.concurrent.*;
|
|||
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.bisq.network.p2p.network;
|
||||
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
|
||||
import java.net.Socket;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.bisq.network.p2p.network;
|
||||
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.bisq.network.p2p.network;
|
||||
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
|
|||
import io.bisq.common.Timer;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.bisq.network.p2p.Utils;
|
||||
|
|
|
@ -4,6 +4,7 @@ import io.bisq.common.Clock;
|
|||
import io.bisq.common.Timer;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.Storage;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.bisq.network.p2p.network.*;
|
||||
|
@ -87,14 +88,14 @@ public class PeerManager implements ConnectionListener {
|
|||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public PeerManager(NetworkNode networkNode, int maxConnections, Set<NodeAddress> seedNodeAddresses,
|
||||
File storageDir, Clock clock) {
|
||||
File storageDir, Clock clock, ProtobufferResolver protobufferResolver) {
|
||||
setConnectionLimits(maxConnections);
|
||||
this.networkNode = networkNode;
|
||||
this.clock = clock;
|
||||
// seedNodeAddresses can be empty (in case there is only 1 seed node, the seed node starting up has no other seed nodes)
|
||||
this.seedNodeAddresses = new HashSet<>(seedNodeAddresses);
|
||||
networkNode.addConnectionListener(this);
|
||||
dbStorage = new Storage<>(storageDir);
|
||||
dbStorage = new Storage<>(storageDir, protobufferResolver);
|
||||
HashSet<Peer> persistedPeers = dbStorage.initAndGetPersistedWithFileName("PersistedPeers");
|
||||
if (persistedPeers != null) {
|
||||
log.debug("We have persisted reported peers. persistedPeers.size()=" + persistedPeers.size());
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.google.common.util.concurrent.SettableFuture;
|
|||
import io.bisq.common.Timer;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.bisq.network.p2p.network.CloseConnectionReason;
|
||||
import io.bisq.network.p2p.network.Connection;
|
||||
|
|
|
@ -3,7 +3,7 @@ package io.bisq.network.p2p.peers.getdata;
|
|||
import io.bisq.common.Timer;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.bisq.network.p2p.network.*;
|
||||
import io.bisq.network.p2p.peers.PeerManager;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package io.bisq.network.p2p.peers.getdata.messages;
|
||||
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.google.common.util.concurrent.SettableFuture;
|
|||
import io.bisq.common.Timer;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.network.Connection;
|
||||
import io.bisq.network.p2p.network.MessageListener;
|
||||
import io.bisq.network.p2p.network.NetworkNode;
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.google.common.util.concurrent.SettableFuture;
|
|||
import io.bisq.common.Timer;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.network.*;
|
||||
import io.bisq.network.p2p.peers.PeerManager;
|
||||
import io.bisq.network.p2p.peers.keepalive.messages.Ping;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.bisq.network.p2p.peers.keepalive.messages;
|
||||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
public abstract class KeepAliveMsg implements Msg {
|
||||
//TODO add serialVersionUID also in superclasses as changes would break compatibility
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.bisq.network.p2p.peers.keepalive.messages;
|
|||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
public final class Ping extends KeepAliveMsg {
|
||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.bisq.network.p2p.peers.keepalive.messages;
|
|||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
public final class Pong extends KeepAliveMsg {
|
||||
// That object is sent over the wire, so we need to take care of version compatibility.
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.google.common.util.concurrent.SettableFuture;
|
|||
import io.bisq.common.Timer;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.bisq.network.p2p.network.CloseConnectionReason;
|
||||
import io.bisq.network.p2p.network.Connection;
|
||||
|
|
|
@ -4,7 +4,7 @@ import com.google.common.base.Preconditions;
|
|||
import io.bisq.common.Timer;
|
||||
import io.bisq.common.UserThread;
|
||||
import io.bisq.common.app.Log;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.bisq.network.p2p.network.*;
|
||||
import io.bisq.network.p2p.peers.PeerManager;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.bisq.network.p2p.peers.peerexchange.messages;
|
||||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
abstract class PeerExchangeMsg implements Msg {
|
||||
//TODO add serialVersionUID also in superclasses as changes would break compatibility
|
||||
|
|
|
@ -9,6 +9,7 @@ import io.bisq.common.app.Version;
|
|||
import io.bisq.common.crypto.CryptoException;
|
||||
import io.bisq.common.crypto.Sig;
|
||||
import io.bisq.common.persistance.Persistable;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.FileUtil;
|
||||
import io.bisq.common.storage.ResourceNotFoundException;
|
||||
import io.bisq.common.storage.Storage;
|
||||
|
@ -16,7 +17,7 @@ import io.bisq.common.util.Tuple2;
|
|||
import io.bisq.common.util.Utilities;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.crypto.EncryptionService;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import io.bisq.network.p2p.network.*;
|
||||
import io.bisq.network.p2p.peers.BroadcastHandler;
|
||||
|
@ -68,14 +69,14 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
|||
// Constructor
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public P2PDataStorage(Broadcaster broadcaster, NetworkNode networkNode, File storageDir) {
|
||||
public P2PDataStorage(Broadcaster broadcaster, NetworkNode networkNode, File storageDir, ProtobufferResolver protobufferResolver) {
|
||||
this.broadcaster = broadcaster;
|
||||
|
||||
networkNode.addMessageListener(this);
|
||||
networkNode.addConnectionListener(this);
|
||||
|
||||
sequenceNumberMapStorage = new Storage<>(storageDir);
|
||||
persistedEntryMapStorage = new Storage<>(storageDir);
|
||||
sequenceNumberMapStorage = new Storage<>(storageDir, protobufferResolver);
|
||||
persistedEntryMapStorage = new Storage<>(storageDir, protobufferResolver);
|
||||
|
||||
init(storageDir);
|
||||
}
|
||||
|
@ -83,7 +84,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
|||
private void init(File storageDir) {
|
||||
sequenceNumberMapStorage.setNumMaxBackupFiles(5);
|
||||
persistedEntryMapStorage.setNumMaxBackupFiles(1);
|
||||
|
||||
|
||||
HashMap<ByteArray, MapValue> persistedSequenceNumberMap = sequenceNumberMapStorage.<HashMap<ByteArray, MapValue>>initAndGetPersistedWithFileName("SequenceNumberMap");
|
||||
if (persistedSequenceNumberMap != null)
|
||||
sequenceNumberMap = getPurgedSequenceNumberMap(persistedSequenceNumberMap);
|
||||
|
@ -125,11 +126,11 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
|||
public void onBootstrapComplete() {
|
||||
removeExpiredEntriesTimer = UserThread.runPeriodically(() -> {
|
||||
log.trace("removeExpiredEntries");
|
||||
// The moment when an object becomes expired will not be synchronous in the network and we could
|
||||
// The moment when an object becomes expired will not be synchronous in the network and we could
|
||||
// get add network_messages after the object has expired. To avoid repeated additions of already expired
|
||||
// object when we get it sent from new peers, we don’t remove the sequence number from the map.
|
||||
// That way an ADD message for an already expired data will fail because the sequence number
|
||||
// is equal and not larger as expected.
|
||||
// object when we get it sent from new peers, we don’t remove the sequence number from the map.
|
||||
// That way an ADD message for an already expired data will fail because the sequence number
|
||||
// is equal and not larger as expected.
|
||||
Map<ByteArray, ProtectedStorageEntry> temp = new HashMap<>(map);
|
||||
Set<ProtectedStorageEntry> toRemoveSet = new HashSet<>();
|
||||
temp.entrySet().stream()
|
||||
|
@ -195,7 +196,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
|||
RequiresOwnerIsOnlinePayload requiresOwnerIsOnlinePayload = (RequiresOwnerIsOnlinePayload) expirablePayload;
|
||||
NodeAddress ownerNodeAddress = requiresOwnerIsOnlinePayload.getOwnerNodeAddress();
|
||||
if (ownerNodeAddress.equals(connection.getPeersNodeAddressOptional().get())) {
|
||||
// We have a RequiresLiveOwnerData data object with the node address of the
|
||||
// We have a RequiresLiveOwnerData data object with the node address of the
|
||||
// disconnected peer. We remove that data from our map.
|
||||
|
||||
// Check if we have the data (e.g. OfferPayload)
|
||||
|
@ -210,15 +211,15 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
|||
" / isIntended=" + closeConnectionReason.isIntended +
|
||||
" / peer=" + (connection.getPeersNodeAddressOptional().isPresent() ? connection.getPeersNodeAddressOptional().get() : "PeersNode unknown"));
|
||||
|
||||
// We only set the data back by half of the TTL and remove the data only if is has
|
||||
// expired after tha back dating.
|
||||
// We might get connection drops which are not caused by the node going offline, so
|
||||
// we give more tolerance with that approach, giving the node the change to
|
||||
// We only set the data back by half of the TTL and remove the data only if is has
|
||||
// expired after tha back dating.
|
||||
// We might get connection drops which are not caused by the node going offline, so
|
||||
// we give more tolerance with that approach, giving the node the change to
|
||||
// refresh the TTL with a refresh message.
|
||||
// We observed those issues during stress tests, but it might have been caused by the
|
||||
// We observed those issues during stress tests, but it might have been caused by the
|
||||
// test set up (many nodes/connections over 1 router)
|
||||
// TODO investigate what causes the disconnections.
|
||||
// Usually the are: SOCKET_TIMEOUT ,TERMINATED (EOFException)
|
||||
// TODO investigate what causes the disconnections.
|
||||
// Usually the are: SOCKET_TIMEOUT ,TERMINATED (EOFException)
|
||||
protectedData.backDate();
|
||||
if (protectedData.isExpired())
|
||||
doRemoveProtectedExpirableData(protectedData, hashOfPayload);
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.bisq.network.p2p.storage.messages;
|
|||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.storage.payload.ProtectedMailboxStorageEntry;
|
||||
import io.bisq.network.p2p.storage.payload.ProtectedStorageEntry;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package io.bisq.network.p2p.storage.messages;
|
||||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
|
||||
public abstract class BroadcastMsg implements Msg {
|
||||
//TODO add serialVersionUID also in superclasses as changes would break compatibility
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.bisq.network.p2p.storage.messages;
|
|||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.storage.payload.ProtectedStorageEntry;
|
||||
|
||||
public final class RemoveDataMsg extends BroadcastMsg {
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.bisq.network.p2p.storage.messages;
|
|||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.storage.payload.ProtectedMailboxStorageEntry;
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import io.bisq.common.crypto.PubKeyRing;
|
|||
import io.bisq.common.storage.FileUtil;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.MailboxMsg;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.junit.After;
|
||||
|
|
|
@ -2,9 +2,11 @@ package io.bisq.network.p2p;
|
|||
|
||||
import io.bisq.common.Clock;
|
||||
import io.bisq.common.crypto.KeyRing;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.common.persistance.Persistable;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.crypto.EncryptionService;
|
||||
import io.bisq.network.p2p.network.ProtobufferResolver;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.network.p2p.seed.SeedNodesRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -176,6 +178,11 @@ public class TestUtils {
|
|||
public Optional<Msg> fromProto(PB.Envelope envelope) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Persistable> fromProto(PB.DiskEnvelope envelope) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package io.bisq.network.p2p.mocks;
|
|||
|
||||
import io.bisq.common.app.Version;
|
||||
import io.bisq.generated.protobuffer.PB;
|
||||
import io.bisq.network.p2p.Msg;
|
||||
import io.bisq.common.persistance.Msg;
|
||||
import io.bisq.network.p2p.storage.payload.ExpirablePayload;
|
||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.bisq.network.p2p.storage;
|
|||
import io.bisq.common.crypto.CryptoException;
|
||||
import io.bisq.common.crypto.KeyRing;
|
||||
import io.bisq.common.crypto.KeyStorage;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import io.bisq.common.storage.FileUtil;
|
||||
import io.bisq.network.crypto.EncryptionService;
|
||||
import io.bisq.network.p2p.NodeAddress;
|
||||
|
@ -43,6 +44,8 @@ public class P2PDataStorageTest {
|
|||
Broadcaster broadcaster;
|
||||
@Mocked
|
||||
NetworkNode networkNode;
|
||||
@Mocked
|
||||
ProtobufferResolver protobufferResolver;
|
||||
|
||||
@Before
|
||||
public void setup() throws InterruptedException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, CryptoException, SignatureException, InvalidKeyException {
|
||||
|
@ -62,7 +65,7 @@ public class P2PDataStorageTest {
|
|||
keyRing2 = new KeyRing(new KeyStorage(dir2));
|
||||
storageSignatureKeyPair2 = keyRing2.getSignatureKeyPair();
|
||||
encryptionService2 = new EncryptionService(keyRing2, TestUtils.getProtobufferResolver());
|
||||
dataStorage1 = new P2PDataStorage(broadcaster, networkNode, dir1);
|
||||
dataStorage1 = new P2PDataStorage(broadcaster, networkNode, dir1, protobufferResolver);
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -75,7 +78,7 @@ public class P2PDataStorageTest {
|
|||
}
|
||||
|
||||
//TODO CoreProtobufferResolver is not accessible here
|
||||
// We should refactor it so that the classes themselves know how to deserialize
|
||||
// We should refactor it so that the classes themselves know how to deserialize
|
||||
// so we don't get dependencies from core objects here
|
||||
|
||||
/* @Test
|
||||
|
@ -110,9 +113,9 @@ public class P2PDataStorageTest {
|
|||
|
||||
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
|
||||
data.toProto().writeTo(byteOutputStream);
|
||||
|
||||
|
||||
//TODO CoreProtobufferResolver is not accessible here
|
||||
// We should refactor it so that the classes themselves know how to deserialize
|
||||
// We should refactor it so that the classes themselves know how to deserialize
|
||||
// so we don't get dependencies from core objects here
|
||||
ProtectedStorageEntry protectedStorageEntry = ProtoBufferUtilities.getProtectedStorageEntry(PB.ProtectedStorageEntry.parseFrom(new ByteArrayInputStream(byteOutputStream.toByteArray())));
|
||||
|
||||
|
@ -122,7 +125,7 @@ public class P2PDataStorageTest {
|
|||
}*/
|
||||
|
||||
//TODO CoreProtobufferResolver is not accessible here
|
||||
// We should refactor it so that the classes themselves know how to deserialize
|
||||
// We should refactor it so that the classes themselves know how to deserialize
|
||||
// so we don't get dependencies from core objects here
|
||||
/* @Test
|
||||
public void testOfferRoundtrip() throws InvalidProtocolBufferException {
|
||||
|
@ -199,4 +202,4 @@ public class P2PDataStorageTest {
|
|||
byte[] hashOfDataAndSeqNr = Hash.getHash(new P2PDataStorage.DataAndSeqNrPair(entry.getStoragePayload(), entry.sequenceNumber));
|
||||
return dataStorage1.checkSignature(entry.ownerPubKey, hashOfDataAndSeqNr, entry.signature);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
|
10
pom.xml
10
pom.xml
|
@ -122,7 +122,7 @@
|
|||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>3.0</version>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--crypto-->
|
||||
|
@ -165,7 +165,7 @@
|
|||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>18.0</version>
|
||||
<version>19.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.fxmisc.easybind</groupId>
|
||||
|
@ -239,6 +239,12 @@
|
|||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-java-util</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -36,7 +36,7 @@ import io.bisq.core.user.Preferences;
|
|||
import io.bisq.core.user.User;
|
||||
import io.bisq.network.crypto.EncryptionServiceModule;
|
||||
import io.bisq.network.p2p.P2PModule;
|
||||
import io.bisq.network.p2p.network.ProtobufferResolver;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
|
|
@ -36,7 +36,7 @@ import io.bisq.core.user.Preferences;
|
|||
import io.bisq.core.user.User;
|
||||
import io.bisq.network.crypto.EncryptionServiceModule;
|
||||
import io.bisq.network.p2p.P2PModule;
|
||||
import io.bisq.network.p2p.network.ProtobufferResolver;
|
||||
import io.bisq.common.persistance.ProtobufferResolver;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
|
Loading…
Add table
Reference in a new issue