mirror of
https://github.com/bisq-network/bisq.git
synced 2025-03-03 10:46:54 +01:00
Merge branch 'master' of github.com:bisq-network/bisq into release/v1.3.8
# Conflicts: # core/src/main/java/bisq/core/support/dispute/agent/MultipleHolderNameDetection.java # core/src/main/java/bisq/core/trade/txproof/xmr/XmrTxProofService.java
This commit is contained in:
commit
98b03937d8
23 changed files with 359 additions and 213 deletions
|
@ -63,7 +63,7 @@ configure(subprojects) {
|
|||
loggingVersion = '1.2'
|
||||
lombokVersion = '1.18.2'
|
||||
mockitoVersion = '3.0.0'
|
||||
netlayerVersion = '0.6.7'
|
||||
netlayerVersion = '0.6.8'
|
||||
protobufVersion = '3.10.0'
|
||||
protocVersion = protobufVersion
|
||||
pushyVersion = '0.13.2'
|
||||
|
|
|
@ -102,7 +102,9 @@ public class FileUtil {
|
|||
deleteDirectory(file, null, true);
|
||||
}
|
||||
|
||||
public static void deleteDirectory(File file, @Nullable File exclude, boolean ignoreLockedFiles) throws IOException {
|
||||
public static void deleteDirectory(File file,
|
||||
@Nullable File exclude,
|
||||
boolean ignoreLockedFiles) throws IOException {
|
||||
boolean excludeFileFound = false;
|
||||
if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
|
@ -156,7 +158,8 @@ public class FileUtil {
|
|||
return !file.canWrite();
|
||||
}
|
||||
|
||||
public static void resourceToFile(String resourcePath, File destinationFile) throws ResourceNotFoundException, IOException {
|
||||
public static void resourceToFile(String resourcePath,
|
||||
File destinationFile) throws ResourceNotFoundException, IOException {
|
||||
try (InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath)) {
|
||||
if (inputStream == null) {
|
||||
throw new ResourceNotFoundException(resourcePath);
|
||||
|
@ -182,6 +185,20 @@ public class FileUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static void copyFile(File origin, File target) throws IOException {
|
||||
if (!origin.exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Files.copy(origin, target);
|
||||
} catch (IOException e) {
|
||||
log.error("Copy file failed", e);
|
||||
throw new IOException("Failed to copy " + origin + " to " + target);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void copyDirectory(File source, File destination) throws IOException {
|
||||
FileUtils.copyDirectory(source, destination);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package bisq.core.account.witness;
|
|||
import bisq.core.account.sign.SignedWitness;
|
||||
import bisq.core.account.sign.SignedWitnessService;
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.filter.PaymentAccountFilter;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.Offer;
|
||||
|
@ -718,10 +717,8 @@ public class AccountAgeWitnessService {
|
|||
filterManager.isCurrencyBanned(dispute.getContract().getOfferPayload().getCurrencyCode()) ||
|
||||
filterManager.isPaymentMethodBanned(
|
||||
PaymentMethod.getPaymentMethodById(dispute.getContract().getPaymentMethodId())) ||
|
||||
filterManager.arePeersPaymentAccountDataBanned(dispute.getContract().getBuyerPaymentAccountPayload(),
|
||||
new PaymentAccountFilter[1]) ||
|
||||
filterManager.arePeersPaymentAccountDataBanned(dispute.getContract().getSellerPaymentAccountPayload(),
|
||||
new PaymentAccountFilter[1]) ||
|
||||
filterManager.arePeersPaymentAccountDataBanned(dispute.getContract().getBuyerPaymentAccountPayload()) ||
|
||||
filterManager.arePeersPaymentAccountDataBanned(dispute.getContract().getSellerPaymentAccountPayload()) ||
|
||||
filterManager.isWitnessSignerPubKeyBanned(
|
||||
Utils.HEX.encode(dispute.getContract().getBuyerPubKeyRing().getSignaturePubKeyBytes())) ||
|
||||
filterManager.isWitnessSignerPubKeyBanned(
|
||||
|
|
|
@ -186,10 +186,6 @@ public final class AddressEntry implements PersistablePayload {
|
|||
return context == Context.MULTI_SIG || context == Context.TRADE_PAYOUT;
|
||||
}
|
||||
|
||||
public boolean isTradable() {
|
||||
return isOpenOffer() || isTrade();
|
||||
}
|
||||
|
||||
public Coin getCoinLockedInMultiSig() {
|
||||
return Coin.valueOf(coinLockedInMultiSig);
|
||||
}
|
||||
|
@ -197,9 +193,10 @@ public final class AddressEntry implements PersistablePayload {
|
|||
@Override
|
||||
public String toString() {
|
||||
return "AddressEntry{" +
|
||||
"offerId='" + getOfferId() + '\'' +
|
||||
"address=" + address +
|
||||
", context=" + context +
|
||||
", address=" + getAddressString() +
|
||||
'}';
|
||||
", offerId='" + offerId + '\'' +
|
||||
", coinLockedInMultiSig=" + coinLockedInMultiSig +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,38 +17,41 @@
|
|||
|
||||
package bisq.core.btc.model;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
import bisq.common.proto.persistable.PersistedDataHost;
|
||||
import bisq.common.proto.persistable.UserThreadMappedPersistableEnvelope;
|
||||
import bisq.common.storage.Storage;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.crypto.DeterministicKey;
|
||||
import org.bitcoinj.wallet.Wallet;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* The List supporting our persistence solution.
|
||||
* The AddressEntries was previously stored as list, now as hashSet. We still keep the old name to reflect the
|
||||
* associated protobuf message.
|
||||
*/
|
||||
@ToString
|
||||
@Slf4j
|
||||
public final class AddressEntryList implements UserThreadMappedPersistableEnvelope, PersistedDataHost {
|
||||
transient private Storage<AddressEntryList> storage;
|
||||
transient private Wallet wallet;
|
||||
@Getter
|
||||
private List<AddressEntry> list;
|
||||
private final Set<AddressEntry> entrySet = new CopyOnWriteArraySet<>();
|
||||
|
||||
@Inject
|
||||
public AddressEntryList(Storage<AddressEntryList> storage) {
|
||||
|
@ -58,8 +61,10 @@ public final class AddressEntryList implements UserThreadMappedPersistableEnvelo
|
|||
@Override
|
||||
public void readPersisted() {
|
||||
AddressEntryList persisted = storage.initAndGetPersisted(this, 50);
|
||||
if (persisted != null)
|
||||
list = new ArrayList<>(persisted.getList());
|
||||
if (persisted != null) {
|
||||
entrySet.clear();
|
||||
entrySet.addAll(persisted.entrySet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -67,22 +72,22 @@ public final class AddressEntryList implements UserThreadMappedPersistableEnvelo
|
|||
// PROTO BUFFER
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private AddressEntryList(List<AddressEntry> list) {
|
||||
this.list = list;
|
||||
private AddressEntryList(Set<AddressEntry> entrySet) {
|
||||
this.entrySet.addAll(entrySet);
|
||||
}
|
||||
|
||||
public static AddressEntryList fromProto(protobuf.AddressEntryList proto) {
|
||||
return new AddressEntryList(new ArrayList<>(proto.getAddressEntryList().stream().map(AddressEntry::fromProto).collect(Collectors.toList())));
|
||||
Set<AddressEntry> entrySet = proto.getAddressEntryList().stream()
|
||||
.map(AddressEntry::fromProto)
|
||||
.collect(Collectors.toSet());
|
||||
return new AddressEntryList(entrySet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message toProtoMessage() {
|
||||
// We clone list as we got ConcurrentModificationExceptions
|
||||
List<AddressEntry> clone = new ArrayList<>(list);
|
||||
List<protobuf.AddressEntry> addressEntries = clone.stream()
|
||||
Set<protobuf.AddressEntry> addressEntries = entrySet.stream()
|
||||
.map(AddressEntry::toProtoMessage)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
.collect(Collectors.toSet());
|
||||
return protobuf.PersistableEnvelope.newBuilder()
|
||||
.setAddressEntryList(protobuf.AddressEntryList.newBuilder()
|
||||
.addAllAddressEntry(addressEntries))
|
||||
|
@ -97,29 +102,50 @@ public final class AddressEntryList implements UserThreadMappedPersistableEnvelo
|
|||
public void onWalletReady(Wallet wallet) {
|
||||
this.wallet = wallet;
|
||||
|
||||
if (list != null) {
|
||||
list.forEach(addressEntry -> {
|
||||
if (!entrySet.isEmpty()) {
|
||||
Set<AddressEntry> toBeRemoved = new HashSet<>();
|
||||
entrySet.forEach(addressEntry -> {
|
||||
DeterministicKey keyFromPubHash = (DeterministicKey) wallet.findKeyFromPubHash(addressEntry.getPubKeyHash());
|
||||
if (keyFromPubHash != null) {
|
||||
Address addressFromKey = keyFromPubHash.toAddress(Config.baseCurrencyNetworkParameters());
|
||||
// We want to ensure key and address matches in case we have address in entry available already
|
||||
if (addressEntry.getAddress() == null || addressFromKey.equals(addressEntry.getAddress())) {
|
||||
addressEntry.setDeterministicKey(keyFromPubHash);
|
||||
} else {
|
||||
log.error("Key from addressEntry not found in that wallet " + addressEntry.toString());
|
||||
log.error("We found an address entry without key but cannot apply the key as the address " +
|
||||
"is not matching. " +
|
||||
"We remove that entry as it seems it is not compatible with our wallet. " +
|
||||
"addressFromKey={}, addressEntry.getAddress()={}",
|
||||
addressFromKey, addressEntry.getAddress());
|
||||
toBeRemoved.add(addressEntry);
|
||||
}
|
||||
} else {
|
||||
log.error("Key from addressEntry {} not found in that wallet. We remove that entry. " +
|
||||
"This is expected at restore from seeds.", addressEntry.toString());
|
||||
toBeRemoved.add(addressEntry);
|
||||
}
|
||||
});
|
||||
|
||||
toBeRemoved.forEach(entrySet::remove);
|
||||
} else {
|
||||
list = new ArrayList<>();
|
||||
add(new AddressEntry(wallet.freshReceiveKey(), AddressEntry.Context.ARBITRATOR));
|
||||
// As long the old arbitration domain is not removed from the code base we still support it here.
|
||||
entrySet.add(new AddressEntry(wallet.freshReceiveKey(), AddressEntry.Context.ARBITRATOR));
|
||||
}
|
||||
|
||||
// In case we restore from seed words and have balance we need to add the relevant addresses to our list.
|
||||
// IssuedReceiveAddresses does not contain all addresses where we expect balance so we need to listen to
|
||||
// incoming txs at blockchain sync to add the rest.
|
||||
if (wallet.getBalance().isPositive()) {
|
||||
wallet.getIssuedReceiveAddresses().forEach(address -> {
|
||||
wallet.getIssuedReceiveAddresses().stream()
|
||||
.filter(this::isAddressNotInEntries)
|
||||
.forEach(address -> {
|
||||
log.info("Create AddressEntry for IssuedReceiveAddress. address={}", address.toString());
|
||||
add(new AddressEntry((DeterministicKey) wallet.findKeyFromPubHash(address.getHash160()), AddressEntry.Context.AVAILABLE));
|
||||
});
|
||||
DeterministicKey key = (DeterministicKey) wallet.findKeyFromPubHash(address.getHash160());
|
||||
if (key != null) {
|
||||
// Address will be derived from key in getAddress method
|
||||
entrySet.add(new AddressEntry(key, AddressEntry.Context.AVAILABLE));
|
||||
}
|
||||
persist();
|
||||
});
|
||||
}
|
||||
|
||||
// We add those listeners to get notified about potential new transactions and
|
||||
|
@ -127,62 +153,41 @@ public final class AddressEntryList implements UserThreadMappedPersistableEnvelo
|
|||
// but can help as well in case the addressEntry list would miss an address where the wallet was received
|
||||
// funds (e.g. if the user sends funds to an address which has not been provided in the main UI - like from the
|
||||
// wallet details window).
|
||||
wallet.addCoinsReceivedEventListener((w, tx, prevBalance, newBalance) -> {
|
||||
updateList(tx);
|
||||
wallet.addCoinsReceivedEventListener((wallet1, tx, prevBalance, newBalance) -> {
|
||||
maybeAddNewAddressEntry(tx);
|
||||
});
|
||||
wallet.addCoinsSentEventListener((w, tx, prevBalance, newBalance) -> {
|
||||
updateList(tx);
|
||||
wallet.addCoinsSentEventListener((wallet1, tx, prevBalance, newBalance) -> {
|
||||
maybeAddNewAddressEntry(tx);
|
||||
});
|
||||
}
|
||||
|
||||
private void updateList(Transaction tx) {
|
||||
tx.getOutputs().stream()
|
||||
.filter(output -> output.isMine(wallet))
|
||||
.map(output -> output.getAddressFromP2PKHScript(wallet.getNetworkParameters()))
|
||||
.filter(Objects::nonNull)
|
||||
.filter(address -> !listContainsEntryWithAddress(address.toBase58()))
|
||||
.map(address -> (DeterministicKey) wallet.findKeyFromPubHash(address.getHash160()))
|
||||
.filter(Objects::nonNull)
|
||||
.map(deterministicKey -> new AddressEntry(deterministicKey, AddressEntry.Context.AVAILABLE))
|
||||
.forEach(addressEntry -> list.add(addressEntry));
|
||||
}
|
||||
|
||||
private boolean listContainsEntryWithAddress(String addressString) {
|
||||
return list.stream().anyMatch(addressEntry -> Objects.equals(addressEntry.getAddressString(), addressString));
|
||||
}
|
||||
|
||||
private boolean add(AddressEntry addressEntry) {
|
||||
return list.add(addressEntry);
|
||||
}
|
||||
|
||||
private boolean remove(AddressEntry addressEntry) {
|
||||
return list.remove(addressEntry);
|
||||
}
|
||||
|
||||
public AddressEntry addAddressEntry(AddressEntry addressEntry) {
|
||||
boolean changed = add(addressEntry);
|
||||
if (changed)
|
||||
persist();
|
||||
return addressEntry;
|
||||
}
|
||||
|
||||
public void swapTradeToSavings(String offerId) {
|
||||
list.stream().filter(addressEntry -> offerId.equals(addressEntry.getOfferId()))
|
||||
.findAny().ifPresent(this::swapToAvailable);
|
||||
public ImmutableList<AddressEntry> getAddressEntriesAsListImmutable() {
|
||||
return ImmutableList.copyOf(entrySet);
|
||||
}
|
||||
|
||||
public void addAddressEntry(AddressEntry addressEntry) {
|
||||
boolean setChangedByAdd = entrySet.add(addressEntry);
|
||||
if (setChangedByAdd)
|
||||
persist();
|
||||
}
|
||||
|
||||
public void swapToAvailable(AddressEntry addressEntry) {
|
||||
boolean changed1 = remove(addressEntry);
|
||||
boolean changed2 = add(new AddressEntry(addressEntry.getKeyPair(), AddressEntry.Context.AVAILABLE));
|
||||
if (changed1 || changed2)
|
||||
boolean setChangedByRemove = entrySet.remove(addressEntry);
|
||||
boolean setChangedByAdd = entrySet.add(new AddressEntry(addressEntry.getKeyPair(), AddressEntry.Context.AVAILABLE));
|
||||
if (setChangedByRemove || setChangedByAdd) {
|
||||
persist();
|
||||
}
|
||||
}
|
||||
|
||||
public AddressEntry swapAvailableToAddressEntryWithOfferId(AddressEntry addressEntry, AddressEntry.Context context, String offerId) {
|
||||
boolean changed1 = remove(addressEntry);
|
||||
public AddressEntry swapAvailableToAddressEntryWithOfferId(AddressEntry addressEntry,
|
||||
AddressEntry.Context context,
|
||||
String offerId) {
|
||||
boolean setChangedByRemove = entrySet.remove(addressEntry);
|
||||
final AddressEntry newAddressEntry = new AddressEntry(addressEntry.getKeyPair(), context, offerId);
|
||||
boolean changed2 = add(newAddressEntry);
|
||||
if (changed1 || changed2)
|
||||
boolean setChangedByAdd = entrySet.add(newAddressEntry);
|
||||
if (setChangedByRemove || setChangedByAdd)
|
||||
persist();
|
||||
|
||||
return newAddressEntry;
|
||||
|
@ -192,7 +197,24 @@ public final class AddressEntryList implements UserThreadMappedPersistableEnvelo
|
|||
storage.queueUpForSave(50);
|
||||
}
|
||||
|
||||
public Stream<AddressEntry> stream() {
|
||||
return list.stream();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void maybeAddNewAddressEntry(Transaction tx) {
|
||||
tx.getOutputs().stream()
|
||||
.filter(output -> output.isMine(wallet))
|
||||
.map(output -> output.getAddressFromP2PKHScript(wallet.getNetworkParameters()))
|
||||
.filter(Objects::nonNull)
|
||||
.filter(this::isAddressNotInEntries)
|
||||
.map(address -> (DeterministicKey) wallet.findKeyFromPubHash(address.getHash160()))
|
||||
.filter(Objects::nonNull)
|
||||
.map(deterministicKey -> new AddressEntry(deterministicKey, AddressEntry.Context.AVAILABLE))
|
||||
.forEach(this::addAddressEntry);
|
||||
}
|
||||
|
||||
private boolean isAddressNotInEntries(Address address) {
|
||||
return entrySet.stream().noneMatch(e -> address.equals(e.getAddress()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ import javax.inject.Inject;
|
|||
import javax.inject.Named;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.util.concurrent.Service;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -498,7 +497,7 @@ public class WalletsSetup {
|
|||
}
|
||||
|
||||
public Set<Address> getAddressesByContext(@SuppressWarnings("SameParameterValue") AddressEntry.Context context) {
|
||||
return ImmutableList.copyOf(addressEntryList.getList()).stream()
|
||||
return addressEntryList.getAddressEntriesAsListImmutable().stream()
|
||||
.filter(addressEntry -> addressEntry.getContext() == context)
|
||||
.map(AddressEntry::getAddress)
|
||||
.collect(Collectors.toSet());
|
||||
|
|
|
@ -47,7 +47,6 @@ import org.bitcoinj.wallet.Wallet;
|
|||
import javax.inject.Inject;
|
||||
|
||||
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;
|
||||
|
||||
|
@ -108,8 +107,8 @@ public class BtcWalletService extends WalletService {
|
|||
void decryptWallet(@NotNull KeyParameter key) {
|
||||
super.decryptWallet(key);
|
||||
|
||||
addressEntryList.stream().forEach(e -> {
|
||||
final DeterministicKey keyPair = e.getKeyPair();
|
||||
addressEntryList.getAddressEntriesAsListImmutable().stream().forEach(e -> {
|
||||
DeterministicKey keyPair = e.getKeyPair();
|
||||
if (keyPair.isEncrypted())
|
||||
e.setDeterministicKey(keyPair.decrypt(key));
|
||||
});
|
||||
|
@ -119,8 +118,8 @@ public class BtcWalletService extends WalletService {
|
|||
@Override
|
||||
void encryptWallet(KeyCrypterScrypt keyCrypterScrypt, KeyParameter key) {
|
||||
super.encryptWallet(keyCrypterScrypt, key);
|
||||
addressEntryList.stream().forEach(e -> {
|
||||
final DeterministicKey keyPair = e.getKeyPair();
|
||||
addressEntryList.getAddressEntriesAsListImmutable().stream().forEach(e -> {
|
||||
DeterministicKey keyPair = e.getKeyPair();
|
||||
if (keyPair.isEncrypted())
|
||||
e.setDeterministicKey(keyPair.encrypt(keyCrypterScrypt, key));
|
||||
});
|
||||
|
@ -157,12 +156,18 @@ public class BtcWalletService extends WalletService {
|
|||
// Proposal txs
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Transaction completePreparedReimbursementRequestTx(Coin issuanceAmount, Address issuanceAddress, Transaction feeTx, byte[] opReturnData)
|
||||
public Transaction completePreparedReimbursementRequestTx(Coin issuanceAmount,
|
||||
Address issuanceAddress,
|
||||
Transaction feeTx,
|
||||
byte[] opReturnData)
|
||||
throws TransactionVerificationException, WalletException, InsufficientMoneyException {
|
||||
return completePreparedProposalTx(feeTx, opReturnData, issuanceAmount, issuanceAddress);
|
||||
}
|
||||
|
||||
public Transaction completePreparedCompensationRequestTx(Coin issuanceAmount, Address issuanceAddress, Transaction feeTx, byte[] opReturnData)
|
||||
public Transaction completePreparedCompensationRequestTx(Coin issuanceAmount,
|
||||
Address issuanceAddress,
|
||||
Transaction feeTx,
|
||||
byte[] opReturnData)
|
||||
throws TransactionVerificationException, WalletException, InsufficientMoneyException {
|
||||
return completePreparedProposalTx(feeTx, opReturnData, issuanceAmount, issuanceAddress);
|
||||
}
|
||||
|
@ -292,7 +297,8 @@ public class BtcWalletService extends WalletService {
|
|||
return completePreparedBsqTxWithBtcFee(preparedTx, opReturnData);
|
||||
}
|
||||
|
||||
private Transaction completePreparedBsqTxWithBtcFee(Transaction preparedTx, byte[] opReturnData) throws InsufficientMoneyException, TransactionVerificationException, WalletException {
|
||||
private Transaction completePreparedBsqTxWithBtcFee(Transaction preparedTx,
|
||||
byte[] opReturnData) throws InsufficientMoneyException, TransactionVerificationException, WalletException {
|
||||
// Remember index for first BTC input
|
||||
int indexOfBtcFirstInput = preparedTx.getInputs().size();
|
||||
|
||||
|
@ -306,7 +312,8 @@ public class BtcWalletService extends WalletService {
|
|||
return tx;
|
||||
}
|
||||
|
||||
private Transaction addInputsForMinerFee(Transaction preparedTx, byte[] opReturnData) throws InsufficientMoneyException {
|
||||
private Transaction addInputsForMinerFee(Transaction preparedTx,
|
||||
byte[] opReturnData) throws InsufficientMoneyException {
|
||||
// safety check counter to avoid endless loops
|
||||
int counter = 0;
|
||||
// estimated size of input sig
|
||||
|
@ -421,7 +428,9 @@ public class BtcWalletService extends WalletService {
|
|||
return completePreparedBsqTx(preparedBsqTx, isSendTx, null);
|
||||
}
|
||||
|
||||
public Transaction completePreparedBsqTx(Transaction preparedBsqTx, boolean useCustomTxFee, @Nullable byte[] opReturnData) throws
|
||||
public Transaction completePreparedBsqTx(Transaction preparedBsqTx,
|
||||
boolean useCustomTxFee,
|
||||
@Nullable byte[] opReturnData) throws
|
||||
TransactionVerificationException, WalletException, InsufficientMoneyException {
|
||||
|
||||
// preparedBsqTx has following structure:
|
||||
|
@ -545,7 +554,8 @@ public class BtcWalletService extends WalletService {
|
|||
// AddressEntry
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public Optional<AddressEntry> getAddressEntry(String offerId, @SuppressWarnings("SameParameterValue") AddressEntry.Context context) {
|
||||
public Optional<AddressEntry> getAddressEntry(String offerId,
|
||||
@SuppressWarnings("SameParameterValue") AddressEntry.Context context) {
|
||||
return getAddressEntryListAsImmutableList().stream()
|
||||
.filter(e -> offerId.equals(e.getOfferId()))
|
||||
.filter(e -> context == e.getContext())
|
||||
|
@ -592,17 +602,14 @@ public class BtcWalletService extends WalletService {
|
|||
return getOrCreateAddressEntry(context, addressEntry);
|
||||
}
|
||||
|
||||
public AddressEntry getNewAddressEntry(String offerId, AddressEntry.Context context) {
|
||||
public void getNewAddressEntry(String offerId, AddressEntry.Context context) {
|
||||
AddressEntry entry = new AddressEntry(wallet.freshReceiveKey(), context, offerId);
|
||||
addressEntryList.addAddressEntry(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public AddressEntry recoverAddressEntry(String offerId, String address, AddressEntry.Context context) {
|
||||
var available = findAddressEntry(address, AddressEntry.Context.AVAILABLE);
|
||||
if (!available.isPresent())
|
||||
return null;
|
||||
return addressEntryList.swapAvailableToAddressEntryWithOfferId(available.get(), context, offerId);
|
||||
public void recoverAddressEntry(String offerId, String address, AddressEntry.Context context) {
|
||||
findAddressEntry(address, AddressEntry.Context.AVAILABLE).ifPresent(addressEntry ->
|
||||
addressEntryList.swapAvailableToAddressEntryWithOfferId(addressEntry, context, offerId));
|
||||
}
|
||||
|
||||
private AddressEntry getOrCreateAddressEntry(AddressEntry.Context context, Optional<AddressEntry> addressEntry) {
|
||||
|
@ -655,19 +662,17 @@ public class BtcWalletService extends WalletService {
|
|||
}
|
||||
|
||||
public List<AddressEntry> getAddressEntryListAsImmutableList() {
|
||||
return ImmutableList.copyOf(addressEntryList.getList());
|
||||
return addressEntryList.getAddressEntriesAsListImmutable();
|
||||
}
|
||||
|
||||
public void swapTradeEntryToAvailableEntry(String offerId, AddressEntry.Context context) {
|
||||
Optional<AddressEntry> addressEntryOptional = getAddressEntryListAsImmutableList().stream()
|
||||
getAddressEntryListAsImmutableList().stream()
|
||||
.filter(e -> offerId.equals(e.getOfferId()))
|
||||
.filter(e -> context == e.getContext())
|
||||
.findAny();
|
||||
addressEntryOptional.ifPresent(e -> {
|
||||
.forEach(e -> {
|
||||
log.info("swap addressEntry with address {} and offerId {} from context {} to available",
|
||||
e.getAddressString(), e.getOfferId(), context);
|
||||
addressEntryList.swapToAvailable(e);
|
||||
saveAddressEntryList();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -371,26 +371,21 @@ public class FilterManager {
|
|||
return requireUpdateToNewVersion;
|
||||
}
|
||||
|
||||
public boolean arePeersPaymentAccountDataBanned(PaymentAccountPayload paymentAccountPayload,
|
||||
PaymentAccountFilter[] appliedPaymentAccountFilter) {
|
||||
public boolean arePeersPaymentAccountDataBanned(PaymentAccountPayload paymentAccountPayload) {
|
||||
return getFilter() != null &&
|
||||
getFilter().getBannedPaymentAccounts().stream()
|
||||
.filter(paymentAccountFilter -> paymentAccountFilter.getPaymentMethodId().equals(
|
||||
paymentAccountPayload.getPaymentMethodId()))
|
||||
.anyMatch(paymentAccountFilter -> {
|
||||
final boolean samePaymentMethodId = paymentAccountFilter.getPaymentMethodId().equals(
|
||||
paymentAccountPayload.getPaymentMethodId());
|
||||
if (samePaymentMethodId) {
|
||||
try {
|
||||
Method method = paymentAccountPayload.getClass().getMethod(paymentAccountFilter.getGetMethodName());
|
||||
String result = (String) method.invoke(paymentAccountPayload);
|
||||
appliedPaymentAccountFilter[0] = paymentAccountFilter;
|
||||
return result.toLowerCase().equals(paymentAccountFilter.getValue().toLowerCase());
|
||||
// We invoke getter methods (no args), e.g. getHolderName
|
||||
String valueFromInvoke = (String) method.invoke(paymentAccountPayload);
|
||||
return valueFromInvoke.equalsIgnoreCase(paymentAccountFilter.getValue());
|
||||
} catch (Throwable e) {
|
||||
log.error(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -200,18 +200,19 @@ public class MultipleHolderNameDetection {
|
|||
|
||||
private Map<String, List<Dispute>> getAllDisputesByTraderMap() {
|
||||
Map<String, List<Dispute>> allDisputesByTraderMap = new HashMap<>();
|
||||
disputeManager.getDisputesAsObservableList()
|
||||
.forEach(dispute -> {
|
||||
disputeManager.getDisputesAsObservableList().stream()
|
||||
.filter(dispute -> {
|
||||
Contract contract = dispute.getContract();
|
||||
PaymentAccountPayload paymentAccountPayload = isBuyer(dispute) ?
|
||||
contract.getBuyerPaymentAccountPayload() :
|
||||
contract.getSellerPaymentAccountPayload();
|
||||
if (paymentAccountPayload instanceof PayloadWithHolderName) {
|
||||
return paymentAccountPayload instanceof PayloadWithHolderName;
|
||||
})
|
||||
.forEach(dispute -> {
|
||||
String traderPubKeyHash = getSigPubKeyHashAsHex(dispute);
|
||||
allDisputesByTraderMap.putIfAbsent(traderPubKeyHash, new ArrayList<>());
|
||||
List<Dispute> disputes = allDisputesByTraderMap.get(traderPubKeyHash);
|
||||
disputes.add(dispute);
|
||||
}
|
||||
});
|
||||
return allDisputesByTraderMap;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package bisq.core.trade.protocol.tasks;
|
||||
|
||||
import bisq.core.filter.FilterManager;
|
||||
import bisq.core.filter.PaymentAccountFilter;
|
||||
import bisq.core.payment.payload.PaymentAccountPayload;
|
||||
import bisq.core.trade.Trade;
|
||||
|
||||
|
@ -42,9 +41,8 @@ public class ApplyFilter extends TradeTask {
|
|||
try {
|
||||
runInterceptHook();
|
||||
|
||||
final NodeAddress nodeAddress = processModel.getTempTradingPeerNodeAddress();
|
||||
NodeAddress nodeAddress = processModel.getTempTradingPeerNodeAddress();
|
||||
PaymentAccountPayload paymentAccountPayload = checkNotNull(processModel.getTradingPeer().getPaymentAccountPayload());
|
||||
final PaymentAccountFilter[] appliedPaymentAccountFilter = new PaymentAccountFilter[1];
|
||||
|
||||
FilterManager filterManager = processModel.getFilterManager();
|
||||
if (nodeAddress != null && filterManager.isNodeAddressBanned(nodeAddress)) {
|
||||
|
@ -56,13 +54,12 @@ public class ApplyFilter extends TradeTask {
|
|||
} else if (trade.getOffer() != null && filterManager.isCurrencyBanned(trade.getOffer().getCurrencyCode())) {
|
||||
failed("Currency is banned.\n" +
|
||||
"Currency code=" + trade.getOffer().getCurrencyCode());
|
||||
} else if (filterManager.isPaymentMethodBanned(trade.getOffer().getPaymentMethod())) {
|
||||
} else if (filterManager.isPaymentMethodBanned(checkNotNull(trade.getOffer()).getPaymentMethod())) {
|
||||
failed("Payment method is banned.\n" +
|
||||
"Payment method=" + trade.getOffer().getPaymentMethod().getId());
|
||||
} else if (filterManager.arePeersPaymentAccountDataBanned(paymentAccountPayload, appliedPaymentAccountFilter)) {
|
||||
} else if (filterManager.arePeersPaymentAccountDataBanned(paymentAccountPayload)) {
|
||||
failed("Other trader is banned by their trading account data.\n" +
|
||||
"paymentAccountPayload=" + paymentAccountPayload.getPaymentDetails() + "\n" +
|
||||
"banFilter=" + appliedPaymentAccountFilter[0].toString());
|
||||
"paymentAccountPayload=" + paymentAccountPayload.getPaymentDetails());
|
||||
} else if (filterManager.requireUpdateToNewVersionForTrading()) {
|
||||
failed("Your version of Bisq is not compatible for trading anymore. " +
|
||||
"Please update to the latest Bisq version at https://bisq.network/downloads.");
|
||||
|
|
|
@ -166,6 +166,7 @@ public class XmrTxProofService implements AssetTxProofService {
|
|||
|
||||
if (!preferences.findAutoConfirmSettings("XMR").isPresent()) {
|
||||
log.error("AutoConfirmSettings is not present");
|
||||
return;
|
||||
}
|
||||
autoConfirmSettings = preferences.findAutoConfirmSettings("XMR").get();
|
||||
|
||||
|
|
|
@ -1931,9 +1931,9 @@ dao.bond.bondedRoleType.DATA_RELAY_NODE_OPERATOR=Price node operator
|
|||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.BTC_NODE_OPERATOR=Bitcoin node operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.MARKETS_OPERATOR=Markets API operator
|
||||
dao.bond.bondedRoleType.MARKETS_OPERATOR=Markets operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.BSQ_EXPLORER_OPERATOR=BSQ explorer operator
|
||||
dao.bond.bondedRoleType.BSQ_EXPLORER_OPERATOR=Explorer operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
dao.bond.bondedRoleType.MOBILE_NOTIFICATIONS_RELAY_OPERATOR=Mobile notifications relay operator
|
||||
# suppress inspection "UnusedProperty"
|
||||
|
@ -3036,6 +3036,8 @@ Ideally you should specify the date your wallet seed was created.\n\n\n\
|
|||
Are you sure you want to go ahead without specifying a wallet date?
|
||||
seed.restore.success=Wallets restored successfully with the new seed words.\n\nYou need to shut down and restart the application.
|
||||
seed.restore.error=An error occurred when restoring the wallets with seed words.{0}
|
||||
seed.restore.openOffers.warn=You have open offers which will be removed if you restore from seed words.\n\
|
||||
Are you sure that you want to continue?
|
||||
|
||||
|
||||
####################################################################
|
||||
|
|
|
@ -218,7 +218,7 @@ public class AccountAgeWitnessServiceTest {
|
|||
when(filterManager.isNodeAddressBanned(any())).thenReturn(false);
|
||||
when(filterManager.isCurrencyBanned(any())).thenReturn(false);
|
||||
when(filterManager.isPaymentMethodBanned(any())).thenReturn(false);
|
||||
when(filterManager.arePeersPaymentAccountDataBanned(any(), any())).thenReturn(false);
|
||||
when(filterManager.arePeersPaymentAccountDataBanned(any())).thenReturn(false);
|
||||
when(filterManager.isWitnessSignerPubKeyBanned(any())).thenReturn(false);
|
||||
|
||||
when(chargeBackRisk.hasChargebackRisk(any(), any())).thenReturn(true);
|
||||
|
|
|
@ -54,6 +54,8 @@ import com.google.inject.Injector;
|
|||
import com.google.inject.Key;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
import javafx.application.Application;
|
||||
|
||||
import javafx.stage.Modality;
|
||||
|
@ -69,6 +71,8 @@ import javafx.scene.layout.StackPane;
|
|||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -241,8 +245,19 @@ public class BisqApp extends Application implements UncaughtExceptionHandler {
|
|||
|
||||
// configure the primary stage
|
||||
String appName = injector.getInstance(Key.get(String.class, Names.named(Config.APP_NAME)));
|
||||
if (!Config.baseCurrencyNetwork().isMainnet())
|
||||
appName += " [" + Res.get(Config.baseCurrencyNetwork().name()) + "]";
|
||||
List<String> postFixes = new ArrayList<>();
|
||||
if (!Config.baseCurrencyNetwork().isMainnet()) {
|
||||
postFixes.add(Config.baseCurrencyNetwork().name());
|
||||
}
|
||||
if (injector.getInstance(Config.class).useLocalhostForP2P) {
|
||||
postFixes.add("LOCALHOST");
|
||||
}
|
||||
if (injector.getInstance(Config.class).useDevMode) {
|
||||
postFixes.add("DEV MODE");
|
||||
}
|
||||
if (!postFixes.isEmpty()) {
|
||||
appName += " [" + Joiner.on(", ").join(postFixes) + " ]";
|
||||
}
|
||||
|
||||
stage.setTitle(appName);
|
||||
stage.setScene(scene);
|
||||
|
|
|
@ -38,6 +38,7 @@ import bisq.core.payment.validation.AltCoinAddressValidator;
|
|||
import bisq.core.util.coin.CoinFormatter;
|
||||
import bisq.core.util.validation.InputValidator;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.util.Tuple3;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -123,6 +124,13 @@ public class AssetsForm extends PaymentMethodForm {
|
|||
addressInputTextField.setValidator(altCoinAddressValidator);
|
||||
|
||||
addressInputTextField.textProperty().addListener((ov, oldValue, newValue) -> {
|
||||
if (newValue.startsWith("monero:")) {
|
||||
UserThread.execute(() -> {
|
||||
String addressWithoutPrefix = newValue.replace("monero:", "");
|
||||
addressInputTextField.setText(addressWithoutPrefix);
|
||||
});
|
||||
return;
|
||||
}
|
||||
assetAccount.setAddress(newValue);
|
||||
updateFromInputs();
|
||||
});
|
||||
|
|
|
@ -685,10 +685,20 @@ public class MainViewModel implements ViewModel, BisqSetup.BisqSetupListener {
|
|||
return marketPricePresentation.getPriceFeedComboBoxItems();
|
||||
}
|
||||
|
||||
// We keep daoPresentation and accountPresentation support even it is not used atm. But if we add a new feature and
|
||||
// add a badge again it will be needed.
|
||||
@SuppressWarnings({"unused"})
|
||||
public BooleanProperty getShowDaoUpdatesNotification() {
|
||||
return daoPresentation.getShowDaoUpdatesNotification();
|
||||
}
|
||||
|
||||
// We keep daoPresentation and accountPresentation support even it is not used atm. But if we add a new feature and
|
||||
// add a badge again it will be needed.
|
||||
@SuppressWarnings("unused")
|
||||
public BooleanProperty getShowAccountUpdatesNotification() {
|
||||
return accountPresentation.getShowAccountUpdatesNotification();
|
||||
}
|
||||
|
||||
public BooleanProperty getShowSettingsUpdatesNotification() {
|
||||
return settingsPresentation.getShowSettingsUpdatesNotification();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* This file is part of Bisq.
|
||||
*
|
||||
* Bisq is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* Bisq is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
||||
* License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package bisq.desktop.main;
|
||||
|
||||
import bisq.desktop.app.BisqApp;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.storage.FileUtil;
|
||||
|
||||
import org.bitcoinj.wallet.DeterministicSeed;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* This serves as shared space for static methods used from different views where no common parent view would fit as
|
||||
* owner of that code. We keep it strictly static. It should replace GUIUtil for those methods which are not utility
|
||||
* methods.
|
||||
*/
|
||||
@Slf4j
|
||||
public class SharedPresentation {
|
||||
public static void restoreSeedWords(WalletsManager walletsManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
DeterministicSeed seed,
|
||||
File storageDir) {
|
||||
if (!openOfferManager.getObservableList().isEmpty()) {
|
||||
UserThread.runAfter(() ->
|
||||
new Popup().warning(Res.get("seed.restore.openOffers.warn"))
|
||||
.actionButtonText(Res.get("shared.yes"))
|
||||
.onAction(() -> {
|
||||
openOfferManager.removeAllOpenOffers(() -> {
|
||||
doRestoreSeedWords(walletsManager, seed, storageDir);
|
||||
});
|
||||
})
|
||||
.show(), 100, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
doRestoreSeedWords(walletsManager, seed, storageDir);
|
||||
}
|
||||
}
|
||||
|
||||
private static void doRestoreSeedWords(WalletsManager walletsManager,
|
||||
DeterministicSeed seed,
|
||||
File storageDir) {
|
||||
try {
|
||||
File backup = new File(storageDir, "AddressEntryList_backup_pre_wallet_restore_" + System.currentTimeMillis());
|
||||
FileUtil.copyFile(new File(storageDir, "AddressEntryList"), backup);
|
||||
} catch (Throwable t) {
|
||||
new Popup().error(Res.get("error.deleteAddressEntryListFailed", t)).show();
|
||||
}
|
||||
|
||||
walletsManager.restoreSeedWords(
|
||||
seed,
|
||||
() -> UserThread.execute(() -> {
|
||||
log.info("Wallets restored with seed words");
|
||||
new Popup().feedback(Res.get("seed.restore.success")).hideCloseButton().show();
|
||||
BisqApp.getShutDownHandler().run();
|
||||
}),
|
||||
throwable -> UserThread.execute(() -> {
|
||||
log.error(throwable.toString());
|
||||
new Popup().error(Res.get("seed.restore.error", Res.get("shared.errorMessageInline", throwable)))
|
||||
.show();
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -19,14 +19,15 @@ package bisq.desktop.main.account.content.seedwords;
|
|||
|
||||
import bisq.desktop.common.view.ActivatableView;
|
||||
import bisq.desktop.common.view.FxmlView;
|
||||
import bisq.desktop.main.SharedPresentation;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.main.overlays.windows.WalletPasswordWindow;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
import bisq.desktop.util.Layout;
|
||||
|
||||
import bisq.core.btc.wallet.BtcWalletService;
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
import bisq.core.user.DontShowAgainLookup;
|
||||
|
||||
import bisq.common.config.Config;
|
||||
|
@ -68,6 +69,7 @@ import static javafx.beans.binding.Bindings.createBooleanBinding;
|
|||
@FxmlView
|
||||
public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
||||
private final WalletsManager walletsManager;
|
||||
private final OpenOfferManager openOfferManager;
|
||||
private final BtcWalletService btcWalletService;
|
||||
private final WalletPasswordWindow walletPasswordWindow;
|
||||
private final File storageDir;
|
||||
|
@ -91,10 +93,12 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
|||
|
||||
@Inject
|
||||
private SeedWordsView(WalletsManager walletsManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
BtcWalletService btcWalletService,
|
||||
WalletPasswordWindow walletPasswordWindow,
|
||||
@Named(Config.STORAGE_DIR) File storageDir) {
|
||||
this.walletsManager = walletsManager;
|
||||
this.openOfferManager = openOfferManager;
|
||||
this.btcWalletService = btcWalletService;
|
||||
this.walletPasswordWindow = walletPasswordWindow;
|
||||
this.storageDir = storageDir;
|
||||
|
@ -166,9 +170,7 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
|||
String key = "showBackupWarningAtSeedPhrase";
|
||||
if (DontShowAgainLookup.showAgain(key)) {
|
||||
new Popup().warning(Res.get("account.seed.backup.warning"))
|
||||
.onAction(() -> {
|
||||
showSeedPhrase();
|
||||
})
|
||||
.onAction(this::showSeedPhrase)
|
||||
.actionButtonText(Res.get("shared.iUnderstand"))
|
||||
.useIUnderstandButton()
|
||||
.dontShowAgainId(key)
|
||||
|
@ -179,7 +181,7 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
|||
}
|
||||
}
|
||||
|
||||
public void showSeedPhrase() {
|
||||
private void showSeedPhrase() {
|
||||
DeterministicSeed keyChainSeed = btcWalletService.getKeyChainSeed();
|
||||
// wallet creation date is not encrypted
|
||||
walletCreationDate = Instant.ofEpochSecond(walletsManager.getChainSeedCreationTimeSeconds()).atZone(ZoneId.systemDefault()).toLocalDate();
|
||||
|
@ -305,6 +307,6 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> {
|
|||
long date = localDateTime.toEpochSecond(ZoneOffset.UTC);
|
||||
|
||||
DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(seedWordsTextArea.getText()), null, "", date);
|
||||
GUIUtil.restoreSeedWords(seed, walletsManager, storageDir);
|
||||
SharedPresentation.restoreSeedWords(walletsManager, openOfferManager, seed, storageDir);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,16 @@ import bisq.desktop.components.AutoTooltipButton;
|
|||
import bisq.desktop.components.AutoTooltipLabel;
|
||||
import bisq.desktop.components.BusyAnimation;
|
||||
import bisq.desktop.components.PasswordTextField;
|
||||
import bisq.desktop.main.SharedPresentation;
|
||||
import bisq.desktop.main.overlays.Overlay;
|
||||
import bisq.desktop.main.overlays.popups.Popup;
|
||||
import bisq.desktop.util.GUIUtil;
|
||||
import bisq.desktop.util.Layout;
|
||||
import bisq.desktop.util.Transitions;
|
||||
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.crypto.ScryptUtil;
|
||||
import bisq.core.locale.Res;
|
||||
import bisq.core.offer.OpenOfferManager;
|
||||
|
||||
import bisq.common.UserThread;
|
||||
import bisq.common.config.Config;
|
||||
|
@ -88,6 +89,7 @@ import static javafx.beans.binding.Bindings.createBooleanBinding;
|
|||
@Slf4j
|
||||
public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
|
||||
private final WalletsManager walletsManager;
|
||||
private final OpenOfferManager openOfferManager;
|
||||
private File storageDir;
|
||||
|
||||
private Button unlockButton;
|
||||
|
@ -115,8 +117,10 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
|
|||
|
||||
@Inject
|
||||
private WalletPasswordWindow(WalletsManager walletsManager,
|
||||
OpenOfferManager openOfferManager,
|
||||
@Named(Config.STORAGE_DIR) File storageDir) {
|
||||
this.walletsManager = walletsManager;
|
||||
this.openOfferManager = openOfferManager;
|
||||
this.storageDir = storageDir;
|
||||
type = Type.Attention;
|
||||
width = 900;
|
||||
|
@ -277,7 +281,6 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
|
|||
gridPane.getChildren().add(headLine2Label);
|
||||
|
||||
seedWordsTextArea = addTextArea(gridPane, ++rowIndex, Res.get("seed.enterSeedWords"), 5);
|
||||
;
|
||||
seedWordsTextArea.setPrefHeight(60);
|
||||
|
||||
Tuple2<Label, DatePicker> labelDatePickerTuple2 = addTopLabelDatePicker(gridPane, ++rowIndex,
|
||||
|
@ -356,6 +359,6 @@ public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> {
|
|||
//TODO Is ZoneOffset correct?
|
||||
long date = value != null ? value.atStartOfDay().toEpochSecond(ZoneOffset.UTC) : 0;
|
||||
DeterministicSeed seed = new DeterministicSeed(Splitter.on(" ").splitToList(seedWordsTextArea.getText()), null, "", date);
|
||||
GUIUtil.restoreSeedWords(seed, walletsManager, storageDir);
|
||||
SharedPresentation.restoreSeedWords(walletsManager, openOfferManager, seed, storageDir);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ import bisq.desktop.util.validation.RegexValidator;
|
|||
import bisq.core.account.witness.AccountAgeWitness;
|
||||
import bisq.core.account.witness.AccountAgeWitnessService;
|
||||
import bisq.core.btc.setup.WalletsSetup;
|
||||
import bisq.core.btc.wallet.WalletsManager;
|
||||
import bisq.core.locale.Country;
|
||||
import bisq.core.locale.CountryUtil;
|
||||
import bisq.core.locale.CurrencyUtil;
|
||||
|
@ -63,7 +62,6 @@ import bisq.common.config.Config;
|
|||
import bisq.common.proto.persistable.PersistableList;
|
||||
import bisq.common.proto.persistable.PersistenceProtoResolver;
|
||||
import bisq.common.storage.CorruptedDatabaseFilesHandler;
|
||||
import bisq.common.storage.FileUtil;
|
||||
import bisq.common.storage.Storage;
|
||||
import bisq.common.util.MathUtils;
|
||||
import bisq.common.util.Tuple2;
|
||||
|
@ -75,7 +73,6 @@ import org.bitcoinj.core.Coin;
|
|||
import org.bitcoinj.core.TransactionConfidence;
|
||||
import org.bitcoinj.uri.BitcoinURI;
|
||||
import org.bitcoinj.utils.Fiat;
|
||||
import org.bitcoinj.wallet.DeterministicSeed;
|
||||
|
||||
import com.googlecode.jcsv.CSVStrategy;
|
||||
import com.googlecode.jcsv.writer.CSVEntryConverter;
|
||||
|
@ -803,26 +800,6 @@ public class GUIUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static void restoreSeedWords(DeterministicSeed seed, WalletsManager walletsManager, File storageDir) {
|
||||
try {
|
||||
FileUtil.renameFile(new File(storageDir, "AddressEntryList"), new File(storageDir, "AddressEntryList_wallet_restore_" + System.currentTimeMillis()));
|
||||
} catch (Throwable t) {
|
||||
new Popup().error(Res.get("error.deleteAddressEntryListFailed", t)).show();
|
||||
}
|
||||
walletsManager.restoreSeedWords(
|
||||
seed,
|
||||
() -> UserThread.execute(() -> {
|
||||
log.info("Wallets restored with seed words");
|
||||
new Popup().feedback(Res.get("seed.restore.success")).hideCloseButton().show();
|
||||
BisqApp.getShutDownHandler().run();
|
||||
}),
|
||||
throwable -> UserThread.execute(() -> {
|
||||
log.error(throwable.toString());
|
||||
new Popup().error(Res.get("seed.restore.error", Res.get("shared.errorMessageInline", throwable)))
|
||||
.show();
|
||||
}));
|
||||
}
|
||||
|
||||
public static void showSelectableTextModal(String title, String text) {
|
||||
TextArea textArea = new BisqTextArea();
|
||||
textArea.setText(text);
|
||||
|
|
|
@ -17,8 +17,9 @@ Bisq uses Git LFS to track certain large binary files. Follow the instructions a
|
|||
|
||||
## Build
|
||||
|
||||
You do _not_ need to install Gradle to complete the following command. The `gradlew` shell script will install it for you if necessary.
|
||||
You do _not_ need to install Gradle to complete the following command. The `gradlew` shell script will install it for you if necessary. Pull the lfs data first.
|
||||
|
||||
git lfs pull
|
||||
./gradlew build
|
||||
|
||||
If on Windows run `gradlew.bat build` instead.
|
||||
|
|
|
@ -19,14 +19,14 @@ dependencyVerification {
|
|||
'com.fasterxml.jackson.core:jackson-annotations:2566b3a6662afa3c6af4f5b25006cb46be2efc68f1b5116291d6998a8cdf7ed3',
|
||||
'com.fasterxml.jackson.core:jackson-core:39a74610521d7fb9eb3f437bb8739bbf47f6435be12d17bf954c731a0c6352bb',
|
||||
'com.fasterxml.jackson.core:jackson-databind:fcf3c2b0c332f5f54604f7e27fa7ee502378a2cc5df6a944bbfae391872c32ff',
|
||||
'com.github.JesusMcCloud.netlayer:tor.external:fb080d812aa88f5fb1ec74273ae24ae13980b7902c75e0ffc3ac462b4cf6b242',
|
||||
'com.github.JesusMcCloud.netlayer:tor.native:1227275377ac73d9d25dec1d05bc2f7a2ae3b1f1afde77f39049637dcb8fc407',
|
||||
'com.github.JesusMcCloud.netlayer:tor:6ff47a97dc0dc97079d83c1f2c66ebcc956f25dd3bacfa6e24206cb2c742f52b',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-geoip:13a3c6e02f37f9def172ce1d231ea1a45aa1ddbc36b1d9e81b7a91632bc474ed',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-linux32:2022da3a398527d366bd954bea92069cf209218c649aeb3342f85f7434aa0786',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-linux64:972d5a946964176fe849eb872baa64a591d9e6fe0467c62ae71986b946101836',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-macos:95a4d093e2d48099623015e70add1bd7dcc3e392f9e87ed4d691286c868516c9',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-windows:43a07290443a1c55211eaa6001681839f9cb7453574089a939d0da3dd20e2cf2',
|
||||
'com.github.JesusMcCloud.netlayer:tor.external:1facb63d5f4107a1d4a176a03c149b60eed19a76371b58d1b6aa62ad5cacde3f',
|
||||
'com.github.JesusMcCloud.netlayer:tor.native:88267f1a3b2d1433a77a2fd9dc3a8f1d5cd28fbbefa2e078d83b176cbe91d477',
|
||||
'com.github.JesusMcCloud.netlayer:tor:0eaae7bcea11ef25e4f041e77c237ebc96f120462e64a7818073a88dadf9b805',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-geoip:08a461608990aed2c272121dc835a38687017d3bb172bc181ea0793df7ebb5aa',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-linux32:81fb1e80d191ed9d0a509e514311d21d59c87c6edee6a490975061a18390b10c',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-linux64:7b90b5e8f1cc32d86ed8e2e5b1f57d774bc27bebc679ececdbf1ff0699bd1f4c',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-macos:db5aef1082fdd8afb4f7f21cf0956f46a76e93aad75bed6ed149dd3e3767c0a7',
|
||||
'com.github.JesusMcCloud.tor-binary:tor-binary-windows:1bb83786a71449d8edb152e40ce5efc129eaca6a0900f4912d7555b6df2f52a2',
|
||||
'com.github.JesusMcCloud:jtorctl:389d61b1b5a85eb2f23c582c3913ede49f80c9f2b553e4762382c836270e57e5',
|
||||
'com.github.bisq-network.bitcoinj:bitcoinj-core:f979c2187e61ee3b08dd4cbfc49a149734cff64c045d29ed112f2e12f34068a3',
|
||||
'com.github.ravn:jsocks:3c71600af027b2b6d4244e4ad14d98ff2352a379410daebefff5d8cd48d742a4',
|
||||
|
|
|
@ -48,6 +48,8 @@ import bisq.common.proto.network.NetworkEnvelope;
|
|||
import bisq.common.proto.network.NetworkProtoResolver;
|
||||
import bisq.common.util.Utilities;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
@ -283,12 +285,20 @@ public class Connection implements HasCapabilities, Runnable, MessageListener {
|
|||
bundleSender.schedule(() -> {
|
||||
if (!stopped) {
|
||||
synchronized (lock) {
|
||||
BundleOfEnvelopes current = queueOfBundles.poll();
|
||||
if (current != null && !stopped) {
|
||||
if (current.getEnvelopes().size() == 1) {
|
||||
protoOutputStream.writeEnvelope(current.getEnvelopes().get(0));
|
||||
} else {
|
||||
protoOutputStream.writeEnvelope(current);
|
||||
BundleOfEnvelopes bundle = queueOfBundles.poll();
|
||||
if (bundle != null && !stopped) {
|
||||
NetworkEnvelope envelope = bundle.getEnvelopes().size() == 1 ?
|
||||
bundle.getEnvelopes().get(0) :
|
||||
bundle;
|
||||
try {
|
||||
protoOutputStream.writeEnvelope(envelope);
|
||||
} catch (Throwable t) {
|
||||
log.error("Sending envelope of class {} to address {} " +
|
||||
"failed due {}",
|
||||
envelope.getClass().getSimpleName(),
|
||||
this.getPeersNodeAddressOptional(),
|
||||
t.toString());
|
||||
log.error("envelope: {}", envelope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -876,7 +886,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener {
|
|||
log.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
reportInvalidRequest(RuleViolation.INVALID_CLASS);
|
||||
} catch (ProtobufferException | NoClassDefFoundError e) {
|
||||
} catch (ProtobufferException | NoClassDefFoundError | InvalidProtocolBufferException e) {
|
||||
log.error(e.getMessage());
|
||||
e.printStackTrace();
|
||||
reportInvalidRequest(RuleViolation.INVALID_DATA_TYPE);
|
||||
|
|
Loading…
Add table
Reference in a new issue