From e56fc44956e041de3eab1213458a2eef850e098c Mon Sep 17 00:00:00 2001 From: Manfred Karrer Date: Sat, 21 Oct 2017 14:07:48 -0500 Subject: [PATCH] Only use accumulated hash in Witness object --- .../io/bisq/common/locale/CurrencyUtil.java | 2 +- .../java/io/bisq/common/util/Utilities.java | 69 ++-- common/src/main/proto/pb.proto | 43 +-- .../io/bisq/common/util/UtilitiesTest.java | 35 ++ .../core/btc/wallet/BtcWalletService.java | 2 +- .../main/java/io/bisq/core/offer/Offer.java | 58 ++-- .../java/io/bisq/core/offer/OfferPayload.java | 8 +- .../bisq/core/payment/AccountAgeWitness.java | 45 +-- .../payment/AccountAgeWitnessService.java | 312 +++++++++--------- .../bisq/core/payment/PaymentAccountUtil.java | 50 +-- .../trade/messages/PayDepositRequest.java | 161 ++++----- .../messages/PublishDepositTxRequest.java | 124 +++---- .../trade/protocol/BuyerAsTakerProtocol.java | 1 - .../trade/protocol/SellerAsTakerProtocol.java | 2 - .../bisq/core/trade/protocol/TradingPeer.java | 16 +- .../tasks/PublishAccountAgeWitness.java | 2 +- .../tasks/VerifyPeersAccountAgeWitness.java | 83 +++-- .../maker/MakerProcessPayDepositRequest.java | 5 +- .../MakerSendPublishDepositTxRequest.java | 94 +++--- .../maker/MakerSetupDepositTxListener.java | 4 +- .../TakerProcessPublishDepositTxRequest.java | 5 +- .../taker/TakerSendPayDepositRequest.java | 89 ++--- ...akerVerifyOffersAccountAgeWitnessHash.java | 75 ----- .../payment/AccountAgeWitnessServiceTest.java | 8 - .../io/bisq/gui/components/PeerInfoIcon.java | 4 +- .../paymentmethods/PaymentMethodForm.java | 6 +- .../java/io/bisq/gui/main/MainViewModel.java | 4 +- .../AltCoinAccountsDataModel.java | 4 +- .../fiataccounts/FiatAccountsDataModel.java | 4 +- .../gui/main/funds/locked/LockedView.java | 2 +- .../gui/main/funds/reserved/ReservedView.java | 2 +- .../main/funds/withdrawal/WithdrawalView.java | 2 +- .../createoffer/CreateOfferDataModel.java | 6 +- .../main/offer/offerbook/OfferBookView.java | 4 +- .../offer/offerbook/OfferBookViewModel.java | 2 +- .../offer/takeoffer/TakeOfferDataModel.java | 2 +- .../io/bisq/gui/main/overlays/Overlay.java | 4 +- .../windows/DisputeSummaryWindow.java | 2 +- .../overlays/windows/OfferDetailsWindow.java | 4 +- .../windows/downloadupdate/BisqInstaller.java | 2 +- .../steps/seller/SellerStep3View.java | 28 +- .../bisq/network/p2p/network/Connection.java | 2 +- .../p2p/peers/getdata/RequestDataManager.java | 2 +- 43 files changed, 666 insertions(+), 713 deletions(-) create mode 100644 common/src/test/java/io/bisq/common/util/UtilitiesTest.java delete mode 100644 core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerVerifyOffersAccountAgeWitnessHash.java diff --git a/common/src/main/java/io/bisq/common/locale/CurrencyUtil.java b/common/src/main/java/io/bisq/common/locale/CurrencyUtil.java index cd8718182d..d6f48c59e5 100644 --- a/common/src/main/java/io/bisq/common/locale/CurrencyUtil.java +++ b/common/src/main/java/io/bisq/common/locale/CurrencyUtil.java @@ -248,7 +248,7 @@ public class CurrencyUtil { if (isCryptoCurrency(currencyCode) && cryptoCurrencyOptional.isPresent()) { return Optional.of(cryptoCurrencyOptional.get()); } else { - return Optional.empty(); + return Optional.empty(); } } } diff --git a/common/src/main/java/io/bisq/common/util/Utilities.java b/common/src/main/java/io/bisq/common/util/Utilities.java index 14ed7ff09a..4a7a8583d4 100644 --- a/common/src/main/java/io/bisq/common/util/Utilities.java +++ b/common/src/main/java/io/bisq/common/util/Utilities.java @@ -24,6 +24,7 @@ import com.google.gson.*; import io.bisq.common.crypto.LimitedKeyStrengthException; import javafx.scene.input.*; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.bitcoinj.core.Utils; @@ -56,11 +57,11 @@ public class Utilities { // TODO check out Jackson lib public static String objectToJson(Object object) { Gson gson = new GsonBuilder() - .setExclusionStrategies(new AnnotationExclusionStrategy()) + .setExclusionStrategies(new AnnotationExclusionStrategy()) /*.excludeFieldsWithModifiers(Modifier.TRANSIENT)*/ /* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)*/ - .setPrettyPrinting() - .create(); + .setPrettyPrinting() + .create(); return gson.toJson(object); } @@ -76,11 +77,11 @@ public class Utilities { int maximumPoolSize, long keepAliveTimeInSec) { final ThreadFactory threadFactory = new ThreadFactoryBuilder() - .setNameFormat(name) - .setDaemon(true) - .build(); + .setNameFormat(name) + .setDaemon(true) + .build(); ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTimeInSec, - TimeUnit.SECONDS, new ArrayBlockingQueue<>(maximumPoolSize), threadFactory); + TimeUnit.SECONDS, new ArrayBlockingQueue<>(maximumPoolSize), threadFactory); executor.allowCoreThreadTimeOut(true); executor.setRejectedExecutionHandler((r, e) -> log.debug("RejectedExecutionHandler called")); return executor; @@ -93,10 +94,10 @@ public class Utilities { int maximumPoolSize, long keepAliveTimeInSec) { final ThreadFactory threadFactory = new ThreadFactoryBuilder() - .setNameFormat(name) - .setDaemon(true) - .setPriority(Thread.MIN_PRIORITY) - .build(); + .setNameFormat(name) + .setDaemon(true) + .setPriority(Thread.MIN_PRIORITY) + .build(); ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); executor.setKeepAliveTime(keepAliveTimeInSec, TimeUnit.SECONDS); executor.allowCoreThreadTimeOut(true); @@ -134,8 +135,8 @@ public class Utilities { String arch = System.getenv("PROCESSOR_ARCHITECTURE"); String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432"); return arch.endsWith("64") - || wow64Arch != null && wow64Arch.endsWith("64") - ? "64" : "32"; + || wow64Arch != null && wow64Arch.endsWith("64") + ? "64" : "32"; } else if (osArch.contains("arm")) { // armv8 is 64 bit, armv7l is 32 bit return osArch.contains("64") || osArch.contains("v8") ? "64" : "32"; @@ -148,12 +149,12 @@ public class Utilities { public static void printSysInfo() { log.info("System info: os.name={}; os.version={}; os.arch={}; sun.arch.data.model={}; JRE={}; JVM={}", - System.getProperty("os.name"), - System.getProperty("os.version"), - System.getProperty("os.arch"), - getJVMArchitecture(), - (System.getProperty("java.runtime.version", "-") + " (" + System.getProperty("java.vendor", "-") + ")"), - (System.getProperty("java.vm.version", "-") + " (" + System.getProperty("java.vm.name", "-") + ")") + System.getProperty("os.name"), + System.getProperty("os.version"), + System.getProperty("os.arch"), + getJVMArchitecture(), + (System.getProperty("java.runtime.version", "-") + " (" + System.getProperty("java.vendor", "-") + ")"), + (System.getProperty("java.vm.version", "-") + " (" + System.getProperty("java.vm.name", "-") + ")") ); } @@ -175,8 +176,8 @@ public class Utilities { public static void openURI(URI uri) throws IOException { if (!isLinux() - && isDesktopSupported() - && getDesktop().isSupported(Action.BROWSE)) { + && isDesktopSupported() + && getDesktop().isSupported(Action.BROWSE)) { getDesktop().browse(uri); } else { // Maybe Application.HostServices works in those cases? @@ -192,8 +193,8 @@ public class Utilities { public static void openFile(File file) throws IOException { if (!isLinux() - && isDesktopSupported() - && getDesktop().isSupported(Action.OPEN)) { + && isDesktopSupported() + && getDesktop().isSupported(Action.OPEN)) { getDesktop().open(file); } else { // Maybe Application.HostServices works in those cases? @@ -258,7 +259,7 @@ public class Utilities { public static T jsonToObject(String jsonString, Class classOfT) { Gson gson = - new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).setPrettyPrinting().create(); + new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).setPrettyPrinting().create(); return gson.fromJson(jsonString, classOfT); } @@ -372,13 +373,29 @@ public class Utilities { public static boolean isCtrlPressed(KeyCode keyCode, KeyEvent keyEvent) { return new KeyCodeCombination(keyCode, KeyCombination.SHORTCUT_DOWN).match(keyEvent) || - new KeyCodeCombination(keyCode, KeyCombination.CONTROL_DOWN).match(keyEvent); + new KeyCodeCombination(keyCode, KeyCombination.CONTROL_DOWN).match(keyEvent); } public static boolean isAltPressed(KeyCode keyCode, KeyEvent keyEvent) { return new KeyCodeCombination(keyCode, KeyCombination.ALT_DOWN).match(keyEvent); } + public static byte[] concatenateByteArrays(byte[] array1, byte[] array2) { + return ArrayUtils.addAll(array1, array2); + } + + public static byte[] concatenateByteArrays(byte[] array1, byte[] array2, byte[] array3) { + return ArrayUtils.addAll(array1, ArrayUtils.addAll(array2, array3)); + } + + public static byte[] concatenateByteArrays(byte[] array1, byte[] array2, byte[] array3, byte[] array4) { + return ArrayUtils.addAll(array1, ArrayUtils.addAll(array2, ArrayUtils.addAll(array3, array4))); + } + + public static byte[] concatenateByteArrays(byte[] array1, byte[] array2, byte[] array3, byte[] array4, byte[] array5) { + return ArrayUtils.addAll(array1, ArrayUtils.addAll(array2, ArrayUtils.addAll(array3, ArrayUtils.addAll(array4, array5)))); + } + private static class AnnotationExclusionStrategy implements ExclusionStrategy { @Override public boolean shouldSkipField(FieldAttributes f) { @@ -503,6 +520,6 @@ public class Utilities { final String name = System.getProperty("java.runtime.name"); final String ver = System.getProperty("java.version"); return name != null && name.equals("Java(TM) SE Runtime Environment") - && ver != null && (ver.startsWith("1.7") || ver.startsWith("1.8")); + && ver != null && (ver.startsWith("1.7") || ver.startsWith("1.8")); } } diff --git a/common/src/main/proto/pb.proto b/common/src/main/proto/pb.proto index 96cbe23d3a..d932ea5dbd 100644 --- a/common/src/main/proto/pb.proto +++ b/common/src/main/proto/pb.proto @@ -55,7 +55,7 @@ message NetworkEnvelope { GetBsqBlocksRequest get_bsq_blocks_request = 28; GetBsqBlocksResponse get_bsq_blocks_response = 29; NewBsqBlockBroadcastMessage new_bsq_block_broadcast_message = 30; - + AddPersistableNetworkPayloadMessage add_persistable_network_payload_message = 31; } } @@ -131,10 +131,10 @@ message OfferAvailabilityResponse { } message RefreshOfferMessage { - bytes hash_of_data_and_seq_nr = 1; - bytes signature = 2; - bytes hash_of_payload = 3; - int32 sequence_number = 4; + bytes hash_of_data_and_seq_nr = 1; + bytes signature = 2; + bytes hash_of_payload = 3; + int32 sequence_number = 4; } @@ -195,8 +195,9 @@ message PayDepositRequest { NodeAddress arbitrator_node_address = 19; NodeAddress mediator_node_address = 20; string uid = 21; - bytes account_age_witness_nonce = 22; - bytes account_age_witness_signature_of_nonce = 23; + bytes account_age_witness_signature_of_account_data = 22; + bytes account_age_witness_nonce = 23; + bytes account_age_witness_signature_of_nonce = 24; } message PublishDepositTxRequest { @@ -211,8 +212,9 @@ message PublishDepositTxRequest { bytes maker_multi_sig_pub_key = 9; NodeAddress sender_node_address = 10; string uid = 11; - bytes account_age_witness_nonce = 12; - bytes account_age_witness_signature_of_nonce = 13; + bytes account_age_witness_signature_of_account_data = 12; + bytes account_age_witness_nonce = 13; + bytes account_age_witness_signature_of_nonce = 14; } message DepositTxPublishedMessage { @@ -498,7 +500,7 @@ message Tx { int64 burnt_fee = 4; TxType tx_type = 5; } - + message BsqBlock { int32 height = 1; string hash = 2; @@ -560,7 +562,7 @@ message Filter { bytes owner_pub_key_bytes = 5; map extra_data = 6; repeated string banned_currencies = 7; - repeated string banned_payment_methods = 8; + repeated string banned_payment_methods = 8; } message TradeStatistics { @@ -606,7 +608,7 @@ message OfferPayload { double market_price_margin = 7; bool use_market_based_price = 8; int64 amount = 9; - int64 min_amount = 10; + int64 min_amount = 10; string base_currency_code = 11; string counter_currency_code = 12; repeated NodeAddress arbitrator_node_addresses = 13; @@ -661,9 +663,7 @@ message CompensationRequestPayload { message AccountAgeWitness { bytes hash = 1; - bytes sig_pub_key_hash = 2; - bytes signature = 3; - int64 date = 4; + int64 date = 2; } @@ -926,20 +926,20 @@ message PersistableEnvelope { PeerList peer_list = 3; AddressEntryList address_entry_list = 4; NavigationPath navigation_path = 5; - + TradableList tradable_list = 6; TradeStatisticsList trade_statistics_list = 7; DisputeList dispute_list = 8; - + PreferencesPayload preferences_payload = 9; UserPayload user_payload = 10; PaymentAccountList payment_account_list = 11; - + // TODO not fully implemented yet CompensationRequestPayload compensation_request_payload = 12; VoteItemsList vote_items_list = 13; BsqChainState bsq_chain_state = 14; - + PersistableNetworkPayloadList persistable_network_payload_list = 15; } } @@ -1198,8 +1198,9 @@ message TradingPeer { repeated RawTransactionInput raw_transaction_inputs = 9; int64 change_output_value = 10; string change_output_address = 11; - bytes account_age_witness_nonce = 12; - bytes account_age_witness_signature_of_nonce = 13; + bytes account_age_witness_signature_of_account_data = 12; + bytes account_age_witness_nonce = 13; + bytes account_age_witness_signature_of_nonce = 14; } message AccountAgeWitnessMap { diff --git a/common/src/test/java/io/bisq/common/util/UtilitiesTest.java b/common/src/test/java/io/bisq/common/util/UtilitiesTest.java new file mode 100644 index 0000000000..2fb29b9f8b --- /dev/null +++ b/common/src/test/java/io/bisq/common/util/UtilitiesTest.java @@ -0,0 +1,35 @@ +/* + * 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 . + */ + +package io.bisq.common.util; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertTrue; + +public class UtilitiesTest { + + @Test + public void testConcatenateByteArrays() { + assertTrue(Arrays.equals(new byte[]{0x01, 0x02}, Utilities.concatenateByteArrays(new byte[]{0x01}, new byte[]{0x02}))); + assertTrue(Arrays.equals(new byte[]{0x01, 0x02, 0x03}, Utilities.concatenateByteArrays(new byte[]{0x01}, new byte[]{0x02}, new byte[]{0x03}))); + assertTrue(Arrays.equals(new byte[]{0x01, 0x02, 0x03, 0x04}, Utilities.concatenateByteArrays(new byte[]{0x01}, new byte[]{0x02}, new byte[]{0x03}, new byte[]{0x04}))); + assertTrue(Arrays.equals(new byte[]{0x01, 0x02, 0x03, 0x04, 0x05}, Utilities.concatenateByteArrays(new byte[]{0x01}, new byte[]{0x02}, new byte[]{0x03}, new byte[]{0x04}, new byte[]{0x05}))); + } +} diff --git a/core/src/main/java/io/bisq/core/btc/wallet/BtcWalletService.java b/core/src/main/java/io/bisq/core/btc/wallet/BtcWalletService.java index 4e55114ccd..0794b88206 100644 --- a/core/src/main/java/io/bisq/core/btc/wallet/BtcWalletService.java +++ b/core/src/main/java/io/bisq/core/btc/wallet/BtcWalletService.java @@ -787,7 +787,7 @@ public class BtcWalletService extends WalletService { throw new AddressEntryException("No Addresses for withdraw found in our wallet"); sendRequest.coinSelector = new BtcCoinSelector(walletsSetup.getAddressesFromAddressEntries(addressEntries)); - Optional addressEntryOptional = Optional.empty(); + Optional addressEntryOptional = Optional.empty(); AddressEntry changeAddressAddressEntry = null; if (changeAddress != null) addressEntryOptional = findAddressEntry(changeAddress, AddressEntry.Context.AVAILABLE); diff --git a/core/src/main/java/io/bisq/core/offer/Offer.java b/core/src/main/java/io/bisq/core/offer/Offer.java index 5a1e40bbbc..fc2d9c4f5a 100644 --- a/core/src/main/java/io/bisq/core/offer/Offer.java +++ b/core/src/main/java/io/bisq/core/offer/Offer.java @@ -105,16 +105,16 @@ public class Offer implements NetworkPayload, PersistablePayload { public void checkOfferAvailability(OfferAvailabilityModel model, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { availabilityProtocol = new OfferAvailabilityProtocol(model, - () -> { - cancelAvailabilityRequest(); - resultHandler.handleResult(); - }, - (errorMessage) -> { - if (availabilityProtocol != null) - availabilityProtocol.cancel(); - log.error(errorMessage); - errorMessageHandler.handleErrorMessage(errorMessage); - }); + () -> { + cancelAvailabilityRequest(); + resultHandler.handleResult(); + }, + (errorMessage) -> { + if (availabilityProtocol != null) + availabilityProtocol.cancel(); + log.error(errorMessage); + errorMessageHandler.handleErrorMessage(errorMessage); + }); availabilityProtocol.sendOfferAvailabilityRequest(); } @@ -134,28 +134,28 @@ public class Offer implements NetworkPayload, PersistablePayload { double marketPriceMargin = offerPayload.getMarketPriceMargin(); if (CurrencyUtil.isCryptoCurrency(currencyCode)) { factor = getDirection() == OfferPayload.Direction.SELL ? - 1 - marketPriceMargin : 1 + marketPriceMargin; + 1 - marketPriceMargin : 1 + marketPriceMargin; } else { factor = getDirection() == OfferPayload.Direction.BUY ? - 1 - marketPriceMargin : 1 + marketPriceMargin; + 1 - marketPriceMargin : 1 + marketPriceMargin; } double marketPriceAsDouble = marketPrice.getPrice(); double targetPriceAsDouble = marketPriceAsDouble * factor; try { int precision = CurrencyUtil.isCryptoCurrency(currencyCode) ? - Altcoin.SMALLEST_UNIT_EXPONENT : - Fiat.SMALLEST_UNIT_EXPONENT; + Altcoin.SMALLEST_UNIT_EXPONENT : + Fiat.SMALLEST_UNIT_EXPONENT; double scaled = MathUtils.scaleUpByPowerOf10(targetPriceAsDouble, precision); final long roundedToLong = MathUtils.roundDoubleToLong(scaled); return Price.valueOf(currencyCode, roundedToLong); } catch (Exception e) { log.error("Exception at getPrice / parseToFiat: " + e.toString() + "\n" + - "That case should never happen."); + "That case should never happen."); return null; } } else { log.debug("We don't have a market price.\n" + - "That case could only happen if you don't have a price feed."); + "That case could only happen if you don't have a price feed."); return null; } } else { @@ -164,7 +164,7 @@ public class Offer implements NetworkPayload, PersistablePayload { } public void checkTradePriceTolerance(long takersTradePrice) throws TradePriceOutOfToleranceException, - MarketPriceNotAvailableException, IllegalArgumentException { + MarketPriceNotAvailableException, IllegalArgumentException { Price tradePrice = Price.valueOf(getCurrencyCode(), takersTradePrice); Price offerPrice = getPrice(); if (offerPrice == null) @@ -179,8 +179,8 @@ public class Offer implements NetworkPayload, PersistablePayload { // from one provider. if (Math.abs(1 - factor) > 0.01) { String msg = "Taker's trade price is too far away from our calculated price based on the market price.\n" + - "tradePrice=" + tradePrice.getValue() + "\n" + - "offerPrice=" + offerPrice.getValue(); + "tradePrice=" + tradePrice.getValue() + "\n" + + "offerPrice=" + offerPrice.getValue(); log.warn(msg); throw new TradePriceOutOfToleranceException(msg); } @@ -270,8 +270,8 @@ public class Offer implements NetworkPayload, PersistablePayload { public PaymentMethod getPaymentMethod() { return new PaymentMethod(offerPayload.getPaymentMethodId(), - offerPayload.getMaxTradePeriod(), - Coin.valueOf(offerPayload.getMaxTradeLimit())); + offerPayload.getMaxTradePeriod(), + Coin.valueOf(offerPayload.getMaxTradeLimit())); } // utils @@ -302,11 +302,11 @@ public class Offer implements NetworkPayload, PersistablePayload { } - public Optional getAccountAgeWitnessHash() { + public Optional getAccountAgeWitnessHashAsHex() { if (getExtraDataMap() != null && getExtraDataMap().containsKey(OfferPayload.ACCOUNT_AGE_WITNESS_HASH)) return Optional.of(getExtraDataMap().get(OfferPayload.ACCOUNT_AGE_WITNESS_HASH)); else - return Optional.empty(); + return Optional.empty(); } // domain properties @@ -365,8 +365,8 @@ public class Offer implements NetworkPayload, PersistablePayload { public String getCurrencyCode() { return CurrencyUtil.isCryptoCurrency(offerPayload.getBaseCurrencyCode()) ? - offerPayload.getBaseCurrencyCode() : - offerPayload.getCounterCurrencyCode(); + offerPayload.getBaseCurrencyCode() : + offerPayload.getCounterCurrencyCode(); } public long getProtocolVersion() { @@ -473,9 +473,9 @@ public class Offer implements NetworkPayload, PersistablePayload { @Override public String toString() { return "Offer{" + - "getErrorMessage()='" + getErrorMessage() + '\'' + - ", state=" + getState() + - ", offerPayload=" + offerPayload + - '}'; + "getErrorMessage()='" + getErrorMessage() + '\'' + + ", state=" + getState() + + ", offerPayload=" + offerPayload + + '}'; } } diff --git a/core/src/main/java/io/bisq/core/offer/OfferPayload.java b/core/src/main/java/io/bisq/core/offer/OfferPayload.java index ec12a746fc..ec1750cda8 100644 --- a/core/src/main/java/io/bisq/core/offer/OfferPayload.java +++ b/core/src/main/java/io/bisq/core/offer/OfferPayload.java @@ -67,7 +67,7 @@ public final class OfferPayload implements ProtectedStoragePayload, RequiresOwne } // Keys for extra map - public static final String ACCOUNT_AGE_WITNESS_HASH = "accountAgeWitness"; + public static final String ACCOUNT_AGE_WITNESS_HASH = "accountAgeWitnessHash"; /////////////////////////////////////////////////////////////////////////////////////////// @@ -134,11 +134,11 @@ public final class OfferPayload implements ProtectedStoragePayload, RequiresOwne private final boolean isPrivateOffer; @Nullable private final String hashOfChallenge; - + // Should be only used in emergency case if we need to add data but do not want to break backward compatibility // at the P2P network storage checks. The hash of the object will be used to verify if the data is valid. Any new // field in a class would break that hash and therefore break the storage mechanism. - + // extraDataMap used from v0.6 on for hashOfPaymentAccount // key ACCOUNT_AGE_WITNESS, value: hex string of hashOfPaymentAccount byte array @Nullable @@ -355,7 +355,7 @@ public final class OfferPayload implements ProtectedStoragePayload, RequiresOwne // In the offer we support base and counter currency // Fiat offers have base currency BTC and counterCurrency Fiat // Altcoins have base currency Altcoin and counterCurrency BTC - // The rest of the app does not support yet that concept of base currency and counter currencies + // The rest of the app does not support yet that concept of base currency and counter currencies // so we map here for convenience public String getCurrencyCode() { return CurrencyUtil.isCryptoCurrency(getBaseCurrencyCode()) ? getBaseCurrencyCode() : getCounterCurrencyCode(); diff --git a/core/src/main/java/io/bisq/core/payment/AccountAgeWitness.java b/core/src/main/java/io/bisq/core/payment/AccountAgeWitness.java index 292dbed97d..8aa0ec341c 100644 --- a/core/src/main/java/io/bisq/core/payment/AccountAgeWitness.java +++ b/core/src/main/java/io/bisq/core/payment/AccountAgeWitness.java @@ -31,31 +31,21 @@ import lombok.extern.slf4j.Slf4j; import java.util.Date; import java.util.concurrent.TimeUnit; -// Object has about 94 raw bytes (about 101 bytes is size of PB object) -// With 100 000 entries we get 53.5 MB of data. Old entries will be shipped with the MapEntry resource file, -// so only the newly added objects since the last release will not be loaded over the P2P network. -// TODO Get rid of sigPubKey and replace by hash of sigPubKey. That will reduce the data size to 118 bytes. -// Using EC signatures would produce longer signatures (71 bytes) +// Object has about 28 raw bytes (29 bytes is size of PB object) +// With 1 000 000 entries we get 29 MB of data. Old entries will be shipped with the MapEntry resource file, +// so only the newly added objects since the last release will be retrieved over the P2P network. @Slf4j @Value public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetworkPayload, PersistableEnvelope, PublishDateVerifiedPayload { private static final long TOLERANCE = TimeUnit.DAYS.toMillis(1); - private final byte[] hash; // Ripemd160(Sha256(data)) hash 20 bytes - private final byte[] sigPubKeyHash; // Ripemd160(Sha256(sigPubKey)) hash 20 bytes - private final byte[] signature; // about 46 bytes + private final byte[] hash; // Ripemd160(Sha256(concatenated accountHash, signature and sigPubKey)); 20 bytes private final long date; // 8 byte public AccountAgeWitness(byte[] hash, - byte[] sigPubKeyHash, - byte[] signature, long date) { this.hash = hash; - this.sigPubKeyHash = sigPubKeyHash; - this.signature = signature; this.date = date; - - log.info("new AccountAgeWitness: hash={}, date={} ", Utilities.bytesAsHexString(hash), new Date(date)); } @@ -67,10 +57,8 @@ public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetwo @Override public PB.PersistableNetworkPayload toProtoMessage() { final PB.AccountAgeWitness.Builder builder = PB.AccountAgeWitness.newBuilder() - .setHash(ByteString.copyFrom(hash)) - .setSigPubKeyHash(ByteString.copyFrom(sigPubKeyHash)) - .setSignature(ByteString.copyFrom(signature)) - .setDate(date); + .setHash(ByteString.copyFrom(hash)) + .setDate(date); return PB.PersistableNetworkPayload.newBuilder().setAccountAgeWitness(builder).build(); } @@ -80,10 +68,8 @@ public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetwo public static AccountAgeWitness fromProto(PB.AccountAgeWitness proto) { return new AccountAgeWitness( - proto.getHash().toByteArray(), - proto.getSigPubKeyHash().toByteArray(), - proto.getSignature().toByteArray(), - proto.getDate()); + proto.getHash().toByteArray(), + proto.getDate()); } @@ -101,13 +87,6 @@ public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetwo // Getters /////////////////////////////////////////////////////////////////////////////////////////// - - //TODO impl. here or in caller? - // We allow max 1 day time difference - public boolean isDateValid() { - return new Date().getTime() - date < TimeUnit.DAYS.toMillis(1); - } - public P2PDataStorage.ByteArray getHashAsByteArray() { return new P2PDataStorage.ByteArray(hash); } @@ -115,10 +94,8 @@ public class AccountAgeWitness implements LazyProcessedPayload, PersistableNetwo @Override public String toString() { return "AccountAgeWitness{" + - "\n hash=" + Utilities.bytesAsHexString(hash) + - ",\n sigPubKeyHash=" + Utilities.bytesAsHexString(sigPubKeyHash) + - ",\n signature=" + Utilities.bytesAsHexString(signature) + - ",\n date=" + new Date(date) + - "\n}"; + "\n hash=" + Utilities.bytesAsHexString(hash) + + ",\n date=" + new Date(date) + + "\n}"; } } diff --git a/core/src/main/java/io/bisq/core/payment/AccountAgeWitnessService.java b/core/src/main/java/io/bisq/core/payment/AccountAgeWitnessService.java index 56788085bd..c2957db77f 100644 --- a/core/src/main/java/io/bisq/core/payment/AccountAgeWitnessService.java +++ b/core/src/main/java/io/bisq/core/payment/AccountAgeWitnessService.java @@ -18,8 +18,8 @@ package io.bisq.core.payment; import io.bisq.common.crypto.CryptoException; -import io.bisq.common.crypto.Hash; import io.bisq.common.crypto.KeyRing; +import io.bisq.common.crypto.PubKeyRing; import io.bisq.common.crypto.Sig; import io.bisq.common.handlers.ErrorMessageHandler; import io.bisq.common.locale.CurrencyUtil; @@ -31,7 +31,6 @@ import io.bisq.core.payment.payload.PaymentMethod; import io.bisq.network.p2p.P2PService; import io.bisq.network.p2p.storage.P2PDataStorage; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ArrayUtils; import org.bitcoinj.core.Coin; import javax.inject.Inject; @@ -52,12 +51,23 @@ public class AccountAgeWitnessService { private final P2PService p2PService; private final Map accountAgeWitnessMap = new HashMap<>(); + + /////////////////////////////////////////////////////////////////////////////////////////// + // Constructor + /////////////////////////////////////////////////////////////////////////////////////////// + + @Inject public AccountAgeWitnessService(KeyRing keyRing, P2PService p2PService) { this.keyRing = keyRing; this.p2PService = p2PService; } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Lifecycle + /////////////////////////////////////////////////////////////////////////////////////////// + public void onAllServicesInitialized() { p2PService.getP2PDataStorage().addPersistableNetworkPayloadMapListener(payload -> { if (payload instanceof AccountAgeWitness) @@ -71,49 +81,29 @@ public class AccountAgeWitnessService { }); } + + /////////////////////////////////////////////////////////////////////////////////////////// + // API + /////////////////////////////////////////////////////////////////////////////////////////// + private void addToMap(AccountAgeWitness accountAgeWitness) { log.debug("addToMap hash=" + Utilities.bytesAsHexString(accountAgeWitness.getHash())); if (!accountAgeWitnessMap.containsKey(accountAgeWitness.getHashAsByteArray())) accountAgeWitnessMap.put(accountAgeWitness.getHashAsByteArray(), accountAgeWitness); } - public void publishAccountAgeWitness(PaymentAccountPayload paymentAccountPayload) { - try { - AccountAgeWitness accountAgeWitness = getAccountAgeWitness(paymentAccountPayload); - if (!accountAgeWitnessMap.containsKey(accountAgeWitness.getHashAsByteArray())) - p2PService.addPersistableNetworkPayload(accountAgeWitness); - } catch (CryptoException e) { - e.printStackTrace(); - log.error(e.toString()); - } + public void publishMyAccountAgeWitness(PaymentAccountPayload paymentAccountPayload) { + AccountAgeWitness accountAgeWitness = getMyWitness(paymentAccountPayload); + if (!accountAgeWitnessMap.containsKey(accountAgeWitness.getHashAsByteArray())) + p2PService.addPersistableNetworkPayload(accountAgeWitness); } - public Optional getWitnessByHash(String hashAsHex) { - P2PDataStorage.ByteArray hashAsByteArray = new P2PDataStorage.ByteArray(Utilities.decodeFromHex(hashAsHex)); - return accountAgeWitnessMap.containsKey(hashAsByteArray) ? Optional.of(accountAgeWitnessMap.get(hashAsByteArray)) : Optional.empty(); - } + /////////////////////////////////////////////////////////////////////////////////////////// + // Generic + /////////////////////////////////////////////////////////////////////////////////////////// - public Optional getWitnessByPaymentAccountPayload(PaymentAccountPayload paymentAccountPayload) { - return getWitnessByHash(getWitnessHashAsHex(paymentAccountPayload)); - } - - public long getAccountAge(Offer offer) { - if (offer.getAccountAgeWitnessHash().isPresent()) - return getAccountAge(getWitnessByHash(offer.getAccountAgeWitnessHash().get())); - else - return 0L; - } - - public long getAccountAge(PaymentAccountPayload paymentAccountPayload) { - return getAccountAge(getWitnessByPaymentAccountPayload(paymentAccountPayload)); - } - - private long getAccountAge(Optional accountAgeWitnessOptional) { - if (accountAgeWitnessOptional.isPresent()) { - return new Date().getTime() - accountAgeWitnessOptional.get().getDate(); - } else { - return 0L; - } + public byte[] getAccountInputDataWithSalt(PaymentAccountPayload paymentAccountPayload) { + return Utilities.concatenateByteArrays(paymentAccountPayload.getAgeWitnessInputData(), paymentAccountPayload.getSalt()); } public long getAccountAge(AccountAgeWitness accountAgeWitness) { @@ -130,65 +120,17 @@ public class AccountAgeWitnessService { } } - private AccountAgeWitness getAccountAgeWitness(PaymentAccountPayload paymentAccountPayload) throws CryptoException { - byte[] hash = getWitnessHash(paymentAccountPayload); - byte[] signature = Sig.sign(keyRing.getSignatureKeyPair().getPrivate(), hash); - byte[] sigPubKeyHash = Hash.getSha256Ripemd160hash(keyRing.getPubKeyRing().getSignaturePubKeyBytes()); - long now = new Date().getTime(); - - //TODO - // test - //now -= TimeUnit.DAYS.toMillis(75); - - return new AccountAgeWitness(hash, - sigPubKeyHash, - signature, - now); - } - - public byte[] getWitnessHash(PaymentAccountPayload paymentAccountPayload) { - return getWitnessHash(paymentAccountPayload, paymentAccountPayload.getSalt()); - } - - public String getWitnessHashAsHex(PaymentAccountPayload paymentAccountPayload) { - return Utilities.bytesAsHexString(getWitnessHash(paymentAccountPayload)); - } - - private byte[] getWitnessHash(PaymentAccountPayload paymentAccountPayload, byte[] salt) { - byte[] ageWitnessInputData = paymentAccountPayload.getAgeWitnessInputData(); - final byte[] combined = ArrayUtils.addAll(ageWitnessInputData, salt); - final byte[] hash = Hash.getSha256Ripemd160hash(combined); - log.debug("getWitnessHash paymentAccountPayload={}, salt={}, ageWitnessInputData={}, combined={}, hash={}", - paymentAccountPayload.getPaymentDetails(), - Utilities.encodeToHex(salt), - Utilities.encodeToHex(ageWitnessInputData), - Utilities.encodeToHex(combined), - Utilities.encodeToHex(hash)); - return hash; - } - - public long getTradeLimit(PaymentAccount paymentAccount, String currencyCode) { - return getTradeLimit(paymentAccount.getPaymentAccountPayload(), currencyCode); - } - - public long getTradeLimit(PaymentAccountPayload paymentAccountPayload, String currencyCode) { - final long maxTradeLimit = PaymentMethod.getPaymentMethodById(paymentAccountPayload.getPaymentMethodId()).getMaxTradeLimitAsCoin(currencyCode).value; + private long getTradeLimit(PaymentMethod paymentMethod, String currencyCode, Optional accountAgeWitnessOptional) { + final long maxTradeLimit = paymentMethod.getMaxTradeLimitAsCoin(currencyCode).value; if (CurrencyUtil.isFiatCurrency(currencyCode)) { double factor; - // TODO test - /*Optional accountAgeWitnessOptional = paymentAccount.getName() != null ? - getWitnessByHash(getWitnessHashAsHex(paymentAccountPayload)) : - Optional.empty();*/ - - Optional accountAgeWitnessOptional = getWitnessByHash(getWitnessHashAsHex(paymentAccountPayload)); - AccountAge accountAgeCategory = accountAgeWitnessOptional.isPresent() ? - getAccountAgeCategory(getAccountAge((accountAgeWitnessOptional.get()))) : - AccountAgeWitnessService.AccountAge.LESS_ONE_MONTH; + getAccountAgeCategory(getAccountAge((accountAgeWitnessOptional.get()))) : + AccountAgeWitnessService.AccountAge.LESS_ONE_MONTH; // TODO Fade in by date can be removed after feb 2018 - // We want to fade in the limit over 2 months to avoid that all users get limited to 25% of the limit when + // We want to fade in the limit over 2 months to avoid that all users get limited to 25% of the limit when // we deploy that feature. final Date now = new Date(); /* final Date dez = new GregorianCalendar(2017, GregorianCalendar.DECEMBER, 1).getTime(); @@ -236,38 +178,113 @@ public class AccountAgeWitnessService { } } - public boolean verifyAccountAgeWitness(byte[] peersAgeWitnessInputData, - AccountAgeWitness witness, - byte[] peersSalt, - PublicKey peersPublicKey, - byte[] nonce, - byte[] signatureOfNonce, - ErrorMessageHandler errorMessageHandler) { + /////////////////////////////////////////////////////////////////////////////////////////// + // My witness + /////////////////////////////////////////////////////////////////////////////////////////// + + public AccountAgeWitness getMyWitness(PaymentAccountPayload paymentAccountPayload) { + try { + byte[] accountInputDataWithSalt = getAccountInputDataWithSalt(paymentAccountPayload); + byte[] hash = Utilities.concatenateByteArrays(accountInputDataWithSalt, + Sig.sign(keyRing.getSignatureKeyPair().getPrivate(), accountInputDataWithSalt), + keyRing.getPubKeyRing().getSignaturePubKeyBytes()); + long date = new Date().getTime(); + //TODO + // test + //date -= TimeUnit.DAYS.toMillis(75); + return new AccountAgeWitness(hash, date); + } catch (CryptoException e) { + log.error(e.toString()); + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public byte[] getMyWitnessHash(PaymentAccountPayload paymentAccountPayload) { + return getMyWitness(paymentAccountPayload).getHash(); + } + + public String getMyWitnessHashAsHex(PaymentAccountPayload paymentAccountPayload) { + return Utilities.bytesAsHexString(getMyWitnessHash(paymentAccountPayload)); + } + + public long getMyAccountAge(PaymentAccountPayload paymentAccountPayload) { + return getAccountAge(getMyWitness(paymentAccountPayload)); + } + + public long getMyTradeLimit(PaymentAccount paymentAccount, String currencyCode) { + return getTradeLimit(paymentAccount.getPaymentMethod(), currencyCode, Optional.of(getMyWitness(paymentAccount.getPaymentAccountPayload()))); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Peers witness + /////////////////////////////////////////////////////////////////////////////////////////// + + public Optional getPeersWitnessByHash(byte[] hash) { + P2PDataStorage.ByteArray hashAsByteArray = new P2PDataStorage.ByteArray(hash); + return accountAgeWitnessMap.containsKey(hashAsByteArray) ? Optional.of(accountAgeWitnessMap.get(hashAsByteArray)) : Optional.empty(); + } + + public Optional getPeersWitnessByHashAsHex(String hashAsHex) { + return getPeersWitnessByHash(Utilities.decodeFromHex(hashAsHex)); + } + + public long getPeersAccountAge(Offer offer) { + final Optional accountAgeWitnessHash = offer.getAccountAgeWitnessHashAsHex(); + final Optional witnessByHashAsHex = accountAgeWitnessHash.isPresent() ? + getPeersWitnessByHashAsHex(accountAgeWitnessHash.get()) : + Optional.empty(); + return witnessByHashAsHex.isPresent() ? getAccountAge(witnessByHashAsHex.get()) : 0L; + } + + public long getPeersTradeLimit(PaymentAccountPayload paymentAccountPayload, String currencyCode, Optional accountAgeWitnessOptional) { + return getTradeLimit(PaymentMethod.getPaymentMethodById(paymentAccountPayload.getPaymentMethodId()), currencyCode, accountAgeWitnessOptional); + } + + + /////////////////////////////////////////////////////////////////////////////////////////// + // Verification + /////////////////////////////////////////////////////////////////////////////////////////// + + public boolean verifyPeersAccountAgeWitness(Offer offer, + PaymentAccountPayload peersPaymentAccountPayload, + AccountAgeWitness witness, + PubKeyRing peersPubKeyRing, + byte[] peersSignatureOfAccountHash, + byte[] nonce, + byte[] signatureOfNonce, + ErrorMessageHandler errorMessageHandler) { // Check if trade date in witness is not older than the release date of that feature (was added in v0.6) // TODO set date before releasing if (!isTradeDateAfterReleaseDate(witness.getDate(), new GregorianCalendar(2017, GregorianCalendar.OCTOBER, 17).getTime(), errorMessageHandler)) return false; - // Check if peer's pubkey is matching the one from the witness data - if (!verifySigPubKeyHash(witness.getSigPubKeyHash(), peersPublicKey, errorMessageHandler)) - return false; + final byte[] peersAccountInputDataWithSalt = Utilities.concatenateByteArrays(peersPaymentAccountPayload.getAgeWitnessInputData(), peersPaymentAccountPayload.getSalt()); + byte[] hash = Utilities.concatenateByteArrays(peersAccountInputDataWithSalt, peersSignatureOfAccountHash, peersPubKeyRing.getSignaturePubKeyBytes()); - final byte[] combined = ArrayUtils.addAll(peersAgeWitnessInputData, peersSalt); - byte[] hash = Hash.getSha256Ripemd160hash(combined); - - // Check if the hash in the witness data matches the peer's payment account input data + salt + // Check if the hash in the witness data matches the hash derived from the data provided by the peer if (!verifyWitnessHash(witness.getHash(), hash, errorMessageHandler)) return false; - // Check if the witness signature is correct - if (!verifySignature(peersPublicKey, hash, witness.getSignature(), errorMessageHandler)) + // Check if the witness signature is correct + if (!verifyPeersTradeLimit(offer, peersPaymentAccountPayload, errorMessageHandler)) return false; - // Check if the signature of the nonce is correct - return verifySignatureOfNonce(peersPublicKey, nonce, signatureOfNonce, errorMessageHandler); + // Check if the witness signature is correct + if (!verifySignature(peersPubKeyRing.getSignaturePubKey(), peersAccountInputDataWithSalt, peersSignatureOfAccountHash, errorMessageHandler)) + return false; + + // Check if the signature of the nonce is correct + return verifySignatureOfNonce(peersPubKeyRing.getSignaturePubKey(), nonce, signatureOfNonce, errorMessageHandler); } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Package scope verification subroutines + /////////////////////////////////////////////////////////////////////////////////////////// + boolean isTradeDateAfterReleaseDate(long witnessDateAsLong, Date ageWitnessReleaseDate, ErrorMessageHandler errorMessageHandler) { // Release date minus 1 day as tolerance for not synced clocks Date releaseDateWithTolerance = new Date(ageWitnessReleaseDate.getTime() - TimeUnit.DAYS.toMillis(1)); @@ -275,35 +292,38 @@ public class AccountAgeWitnessService { final boolean result = witnessDate.after(releaseDateWithTolerance); if (!result) { final String msg = "Trade date is earlier than release date of ageWitness minus 1 day. " + - "ageWitnessReleaseDate=" + ageWitnessReleaseDate + ", witnessDate=" + witnessDate; + "ageWitnessReleaseDate=" + ageWitnessReleaseDate + ", witnessDate=" + witnessDate; log.warn(msg); errorMessageHandler.handleErrorMessage(msg); } return result; } - boolean verifySigPubKeyHash(byte[] sigPubKeyHash, - PublicKey peersPublicKey, - ErrorMessageHandler errorMessageHandler) { - final byte[] peersPublicKeyHash = Hash.getSha256Ripemd160hash(Sig.getPublicKeyBytes(peersPublicKey)); - final boolean result = Arrays.equals(peersPublicKeyHash, sigPubKeyHash); - if (!result) { - final String msg = "sigPubKeyHash is not matching peers peersPublicKey. " + - "sigPubKeyHash=" + Utilities.bytesAsHexString(sigPubKeyHash) + ", peersPublicKeyHash=" + - Utilities.bytesAsHexString(peersPublicKeyHash); - log.warn(msg); - errorMessageHandler.handleErrorMessage(msg); - } - return result; - } - - private boolean verifyWitnessHash(byte[] witnessHash, - byte[] hash, - ErrorMessageHandler errorMessageHandler) { + boolean verifyWitnessHash(byte[] witnessHash, + byte[] hash, + ErrorMessageHandler errorMessageHandler) { final boolean result = Arrays.equals(witnessHash, hash); if (!result) { final String msg = "witnessHash is not matching peers hash. " + - "witnessHash=" + Utilities.bytesAsHexString(witnessHash) + ", hash=" + Utilities.bytesAsHexString(hash); + "witnessHash=" + Utilities.bytesAsHexString(witnessHash) + ", hash=" + Utilities.bytesAsHexString(hash); + log.warn(msg); + errorMessageHandler.handleErrorMessage(msg); + } + return result; + } + + private boolean verifyPeersTradeLimit(Offer offer, + PaymentAccountPayload paymentAccountPayload, + ErrorMessageHandler errorMessageHandler) { + final Optional offerHashAsHexOptional = offer.getAccountAgeWitnessHashAsHex(); + Optional accountAgeWitnessOptional = offerHashAsHexOptional.isPresent() ? getPeersWitnessByHashAsHex(offerHashAsHexOptional.get()) : Optional.empty(); + long maxTradeLimit = getPeersTradeLimit(paymentAccountPayload, offer.getCurrencyCode(), accountAgeWitnessOptional); + final Coin offerMaxTradeLimit = offer.getMaxTradeLimit(); + boolean result = offerMaxTradeLimit.value == maxTradeLimit; + if (!result) { + String msg = "Offers max trade limit does not match with the one based on his account age.\n" + + "OfferMaxTradeLimit=" + offerMaxTradeLimit.toFriendlyString() + + "; Account age based MaxTradeLimit=" + Coin.valueOf(maxTradeLimit).toFriendlyString(); log.warn(msg); errorMessageHandler.handleErrorMessage(msg); } @@ -323,8 +343,8 @@ public class AccountAgeWitnessService { } if (!result) { final String msg = "Signature of PaymentAccountAgeWitness is not correct. " + - "peersPublicKey=" + peersPublicKey + ", data=" + Utilities.bytesAsHexString(data) + - ", signature=" + Utilities.bytesAsHexString(signature); + "peersPublicKey=" + peersPublicKey + ", data=" + Utilities.bytesAsHexString(data) + + ", signature=" + Utilities.bytesAsHexString(signature); log.warn(msg); errorMessageHandler.handleErrorMessage(msg); } @@ -344,38 +364,8 @@ public class AccountAgeWitnessService { } if (!result) { final String msg = "Signature of nonce is not correct. " + - "peersPublicKey=" + peersPublicKey + ", nonce(hex)=" + Utilities.bytesAsHexString(nonce) + - ", signature=" + Utilities.bytesAsHexString(signature); - log.warn(msg); - errorMessageHandler.handleErrorMessage(msg); - } - return result; - } - - public boolean verifyOffersAccountAgeWitness(PaymentAccountPayload paymentAccountPayload, - byte[] offersWitness, - ErrorMessageHandler errorMessageHandler) { - byte[] witnessHash = getWitnessHash(paymentAccountPayload, paymentAccountPayload.getSalt()); - final boolean result = Arrays.equals(witnessHash, offersWitness); - if (!result) { - final String msg = "witnessHash is not matching peers offersWitness. " + - "witnessHash=" + Utilities.bytesAsHexString(witnessHash) + ", offersWitness=" + Utilities.bytesAsHexString(offersWitness); - log.warn(msg); - errorMessageHandler.handleErrorMessage(msg); - } - return result; - } - - public boolean verifyTradeLimit(Offer offer, - PaymentAccountPayload paymentAccountPayload, - ErrorMessageHandler errorMessageHandler) { - long maxTradeLimit = getTradeLimit(paymentAccountPayload, offer.getCurrencyCode()); - final Coin offerMaxTradeLimit = offer.getMaxTradeLimit(); - final boolean result = offerMaxTradeLimit.value == maxTradeLimit; - if (!result) { - String msg = "Offers max trade limit does not match with the one we calculated.\n" + - "OfferMaxTradeLimit=" + offerMaxTradeLimit.toFriendlyString() + - "; MaxTradeLimit=" + Coin.valueOf(maxTradeLimit).toFriendlyString(); + "peersPublicKey=" + peersPublicKey + ", nonce(hex)=" + Utilities.bytesAsHexString(nonce) + + ", signature=" + Utilities.bytesAsHexString(signature); log.warn(msg); errorMessageHandler.handleErrorMessage(msg); } diff --git a/core/src/main/java/io/bisq/core/payment/PaymentAccountUtil.java b/core/src/main/java/io/bisq/core/payment/PaymentAccountUtil.java index f48f1301c7..1df2377cef 100644 --- a/core/src/main/java/io/bisq/core/payment/PaymentAccountUtil.java +++ b/core/src/main/java/io/bisq/core/payment/PaymentAccountUtil.java @@ -1,7 +1,6 @@ package io.bisq.core.payment; import io.bisq.common.locale.TradeCurrency; -import io.bisq.common.util.Utilities; import io.bisq.core.offer.Offer; import io.bisq.core.payment.payload.PaymentMethod; import javafx.collections.FXCollections; @@ -9,7 +8,6 @@ import javafx.collections.ObservableList; import lombok.extern.slf4j.Slf4j; import java.util.*; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkNotNull; @@ -27,8 +25,8 @@ public class PaymentAccountUtil { public static ObservableList getPossiblePaymentAccounts(Offer offer, Set paymentAccounts) { ObservableList result = FXCollections.observableArrayList(); result.addAll(paymentAccounts.stream() - .filter(paymentAccount -> isPaymentAccountValidForOffer(offer, paymentAccount)) - .collect(Collectors.toList())); + .filter(paymentAccount -> isPaymentAccountValidForOffer(offer, paymentAccount)) + .collect(Collectors.toList())); return result; } @@ -36,16 +34,16 @@ public class PaymentAccountUtil { public static String getInfoForMismatchingPaymentMethodLimits(Offer offer, PaymentAccount paymentAccount) { // dont translate atm as it is not used so far in the UI just for logs return "Payment methods have different trade limits or trade periods.\n" + - "Our local Payment method: " + paymentAccount.getPaymentMethod().toString() + "\n" + - "Payment method from offer: " + offer.getPaymentMethod().toString(); + "Our local Payment method: " + paymentAccount.getPaymentMethod().toString() + "\n" + + "Payment method from offer: " + offer.getPaymentMethod().toString(); } //TODO not tested with all combinations yet.... public static boolean isPaymentAccountValidForOffer(Offer offer, PaymentAccount paymentAccount) { // check if we have a matching currency Set paymentAccountCurrencyCodes = paymentAccount.getTradeCurrencies().stream() - .map(TradeCurrency::getCode) - .collect(Collectors.toSet()); + .map(TradeCurrency::getCode) + .collect(Collectors.toSet()); boolean matchesCurrencyCode = paymentAccountCurrencyCodes.contains(offer.getCurrencyCode()); if (!matchesCurrencyCode) return false; @@ -54,7 +52,7 @@ public class PaymentAccountUtil { final boolean arePaymentMethodsEqual = paymentAccount.getPaymentMethod().equals(offer.getPaymentMethod()); if (!arePaymentMethodsEqual && - paymentAccount.getPaymentMethod().getId().equals(offer.getPaymentMethod().getId())) + paymentAccount.getPaymentMethod().getId().equals(offer.getPaymentMethod().getId())) log.warn(getInfoForMismatchingPaymentMethodLimits(offer, paymentAccount)); if (paymentAccount instanceof CountryBasedPaymentAccount) { @@ -62,14 +60,14 @@ public class PaymentAccountUtil { // check if we have a matching country boolean matchesCountryCodes = offer.getAcceptedCountryCodes() != null && countryBasedPaymentAccount.getCountry() != null && - offer.getAcceptedCountryCodes().contains(countryBasedPaymentAccount.getCountry().code); + offer.getAcceptedCountryCodes().contains(countryBasedPaymentAccount.getCountry().code); if (!matchesCountryCodes) return false; if (paymentAccount instanceof SepaAccount || offer.getPaymentMethod().equals(PaymentMethod.SEPA)) { return arePaymentMethodsEqual; } else if (offer.getPaymentMethod().equals(PaymentMethod.SAME_BANK) || - offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS)) { + offer.getPaymentMethod().equals(PaymentMethod.SPECIFIC_BANKS)) { final List acceptedBankIds = offer.getAcceptedBankIds(); checkNotNull(acceptedBankIds, "offer.getAcceptedBankIds() must not be null"); @@ -105,30 +103,14 @@ public class PaymentAccountUtil { public static Optional getMostMaturePaymentAccountForOffer(Offer offer, Set paymentAccounts, - AccountAgeWitnessService accountAgeWitnessService) { + AccountAgeWitnessService service) { List list = paymentAccounts.stream() - .filter(paymentAccount -> isPaymentAccountValidForOffer(offer, paymentAccount)) - .sorted((o1, o2) -> { - final Optional witness1 = accountAgeWitnessService.getWitnessByPaymentAccountPayload(o1.getPaymentAccountPayload()); - log.debug("witness1 isPresent={}", witness1.isPresent()); - if (witness1.isPresent()) - log.debug("witness1 HashAsHex={}, date={}", Utilities.bytesAsHexString(witness1.get().getHash()), new Date(witness1.get().getDate())); - long age1 = witness1.isPresent() ? accountAgeWitnessService.getAccountAge(witness1.get()) : 0; - - final Optional witness2 = accountAgeWitnessService.getWitnessByPaymentAccountPayload(o2.getPaymentAccountPayload()); - log.debug("witness2 isPresent={}", witness2.isPresent()); - if (witness2.isPresent()) - log.debug("witness2 HashAsHex={}, date={}", Utilities.bytesAsHexString(witness2.get().getHash()), new Date(witness2.get().getDate())); - long age2 = witness2.isPresent() ? accountAgeWitnessService.getAccountAge(witness2.get()) : 0; - log.debug("AccountName 1 " + o1.getAccountName()); - log.debug("AccountName 2 " + o2.getAccountName()); - log.debug("age1 " + age1 / TimeUnit.DAYS.toMillis(1)); - log.debug("age2 " + age2 / TimeUnit.DAYS.toMillis(1)); - log.debug("result " + (new Long(age1).compareTo(age2))); - log.debug(" "); - return new Long(age2).compareTo(age1); - }).collect(Collectors.toList()); - list.stream().forEach(e -> log.error("getMostMaturePaymentAccountForOffer AccountName={}, witnessHashAsHex={}", e.getAccountName(), accountAgeWitnessService.getWitnessHashAsHex(e.getPaymentAccountPayload()))); + .filter(paymentAccount -> isPaymentAccountValidForOffer(offer, paymentAccount)) + .sorted((o1, o2) -> { + return new Long(service.getAccountAge(service.getMyWitness(o2.getPaymentAccountPayload()))) + .compareTo(service.getAccountAge(service.getMyWitness(o1.getPaymentAccountPayload()))); + }).collect(Collectors.toList()); + list.stream().forEach(e -> log.error("getMostMaturePaymentAccountForOffer AccountName={}, witnessHashAsHex={}", e.getAccountName(), service.getMyWitnessHashAsHex(e.getPaymentAccountPayload()))); final Optional first = list.stream().findFirst(); if (first.isPresent()) log.debug("first={}", first.get().getAccountName()); diff --git a/core/src/main/java/io/bisq/core/trade/messages/PayDepositRequest.java b/core/src/main/java/io/bisq/core/trade/messages/PayDepositRequest.java index 7fe5528557..81296f404f 100644 --- a/core/src/main/java/io/bisq/core/trade/messages/PayDepositRequest.java +++ b/core/src/main/java/io/bisq/core/trade/messages/PayDepositRequest.java @@ -62,6 +62,8 @@ public final class PayDepositRequest extends TradeMessage { // added in v 0.6. can be null if we trade with an older peer @Nullable + private final byte[] accountAgeWitnessSignatureOfAccountData; + @Nullable private final byte[] accountAgeWitnessNonce; @Nullable private final byte[] accountAgeWitnessSignatureOfNonce; @@ -88,6 +90,7 @@ public final class PayDepositRequest extends TradeMessage { NodeAddress mediatorNodeAddress, String uid, int messageVersion, + @Nullable byte[] accountAgeWitnessSignatureOfAccountData, @Nullable byte[] accountAgeWitnessNonce, @Nullable byte[] accountAgeWitnessSignatureOfNonce) { super(messageVersion, tradeId); @@ -111,6 +114,7 @@ public final class PayDepositRequest extends TradeMessage { this.arbitratorNodeAddress = arbitratorNodeAddress; this.mediatorNodeAddress = mediatorNodeAddress; this.uid = uid; + this.accountAgeWitnessSignatureOfAccountData = accountAgeWitnessSignatureOfAccountData; this.accountAgeWitnessNonce = accountAgeWitnessNonce; this.accountAgeWitnessSignatureOfNonce = accountAgeWitnessSignatureOfNonce; } @@ -123,98 +127,101 @@ public final class PayDepositRequest extends TradeMessage { @Override public PB.NetworkEnvelope toProtoNetworkEnvelope() { PB.PayDepositRequest.Builder builder = PB.PayDepositRequest.newBuilder() - .setTradeId(tradeId) - .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) - .setTradeAmount(tradeAmount) - .setTradePrice(tradePrice) - .setTxFee(txFee) - .setTakerFee(takerFee) - .setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc) - .addAllRawTransactionInputs(rawTransactionInputs.stream() - .map(RawTransactionInput::toProtoMessage).collect(Collectors.toList())) - .setChangeOutputValue(changeOutputValue) - .setTakerMultiSigPubKey(ByteString.copyFrom(takerMultiSigPubKey)) - .setTakerPayoutAddressString(takerPayoutAddressString) - .setTakerPubKeyRing(takerPubKeyRing.toProtoMessage()) - .setTakerPaymentAccountPayload((PB.PaymentAccountPayload) takerPaymentAccountPayload.toProtoMessage()) - .setTakerAccountId(takerAccountId) - .setTakerFeeTxId(takerFeeTxId) - .addAllAcceptedArbitratorNodeAddresses(acceptedArbitratorNodeAddresses.stream() - .map(NodeAddress::toProtoMessage).collect(Collectors.toList())) - .addAllAcceptedMediatorNodeAddresses(acceptedMediatorNodeAddresses.stream() - .map(NodeAddress::toProtoMessage).collect(Collectors.toList())) - .setArbitratorNodeAddress(arbitratorNodeAddress.toProtoMessage()) - .setMediatorNodeAddress(mediatorNodeAddress.toProtoMessage()) - .setUid(uid); - + .setTradeId(tradeId) + .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) + .setTradeAmount(tradeAmount) + .setTradePrice(tradePrice) + .setTxFee(txFee) + .setTakerFee(takerFee) + .setIsCurrencyForTakerFeeBtc(isCurrencyForTakerFeeBtc) + .addAllRawTransactionInputs(rawTransactionInputs.stream() + .map(RawTransactionInput::toProtoMessage).collect(Collectors.toList())) + .setChangeOutputValue(changeOutputValue) + .setTakerMultiSigPubKey(ByteString.copyFrom(takerMultiSigPubKey)) + .setTakerPayoutAddressString(takerPayoutAddressString) + .setTakerPubKeyRing(takerPubKeyRing.toProtoMessage()) + .setTakerPaymentAccountPayload((PB.PaymentAccountPayload) takerPaymentAccountPayload.toProtoMessage()) + .setTakerAccountId(takerAccountId) + .setTakerFeeTxId(takerFeeTxId) + .addAllAcceptedArbitratorNodeAddresses(acceptedArbitratorNodeAddresses.stream() + .map(NodeAddress::toProtoMessage).collect(Collectors.toList())) + .addAllAcceptedMediatorNodeAddresses(acceptedMediatorNodeAddresses.stream() + .map(NodeAddress::toProtoMessage).collect(Collectors.toList())) + .setArbitratorNodeAddress(arbitratorNodeAddress.toProtoMessage()) + .setMediatorNodeAddress(mediatorNodeAddress.toProtoMessage()) + .setUid(uid); + Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress); - Optional.ofNullable(accountAgeWitnessNonce).ifPresent(accountAgeWitnessNonce -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(accountAgeWitnessNonce))); - Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(accountAgeWitnessSignatureOfNonce -> builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(accountAgeWitnessSignatureOfNonce))); + Optional.ofNullable(accountAgeWitnessSignatureOfAccountData).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfAccountData(ByteString.copyFrom(e))); + Optional.ofNullable(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e))); + Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(e))); return getNetworkEnvelopeBuilder().setPayDepositRequest(builder).build(); } public static PayDepositRequest fromProto(PB.PayDepositRequest proto, CoreProtoResolver coreProtoResolver, int messageVersion) { List rawTransactionInputs = proto.getRawTransactionInputsList().stream() - .map(rawTransactionInput -> new RawTransactionInput(rawTransactionInput.getIndex(), - rawTransactionInput.getParentTransaction().toByteArray(), rawTransactionInput.getValue())) - .collect(Collectors.toList()); + .map(rawTransactionInput -> new RawTransactionInput(rawTransactionInput.getIndex(), + rawTransactionInput.getParentTransaction().toByteArray(), rawTransactionInput.getValue())) + .collect(Collectors.toList()); List acceptedArbitratorNodeAddresses = proto.getAcceptedArbitratorNodeAddressesList().stream() - .map(NodeAddress::fromProto).collect(Collectors.toList()); + .map(NodeAddress::fromProto).collect(Collectors.toList()); List acceptedMediatorNodeAddresses = proto.getAcceptedMediatorNodeAddressesList().stream() - .map(NodeAddress::fromProto).collect(Collectors.toList()); + .map(NodeAddress::fromProto).collect(Collectors.toList()); return new PayDepositRequest(proto.getTradeId(), - NodeAddress.fromProto(proto.getSenderNodeAddress()), - proto.getTradeAmount(), - proto.getTradePrice(), - proto.getTxFee(), - proto.getTakerFee(), - proto.getIsCurrencyForTakerFeeBtc(), - rawTransactionInputs, - proto.getChangeOutputValue(), - ProtoUtil.stringOrNullFromProto(proto.getChangeOutputAddress()), - proto.getTakerMultiSigPubKey().toByteArray(), - proto.getTakerPayoutAddressString(), - PubKeyRing.fromProto(proto.getTakerPubKeyRing()), - coreProtoResolver.fromProto(proto.getTakerPaymentAccountPayload()), - proto.getTakerAccountId(), - proto.getTakerFeeTxId(), - acceptedArbitratorNodeAddresses, - acceptedMediatorNodeAddresses, - NodeAddress.fromProto(proto.getArbitratorNodeAddress()), - NodeAddress.fromProto(proto.getMediatorNodeAddress()), - proto.getUid(), - messageVersion, - proto.getAccountAgeWitnessNonce().isEmpty() ? null : proto.getAccountAgeWitnessNonce().toByteArray(), - proto.getAccountAgeWitnessSignatureOfNonce().isEmpty() ? null : proto.getAccountAgeWitnessSignatureOfNonce().toByteArray()); + NodeAddress.fromProto(proto.getSenderNodeAddress()), + proto.getTradeAmount(), + proto.getTradePrice(), + proto.getTxFee(), + proto.getTakerFee(), + proto.getIsCurrencyForTakerFeeBtc(), + rawTransactionInputs, + proto.getChangeOutputValue(), + ProtoUtil.stringOrNullFromProto(proto.getChangeOutputAddress()), + proto.getTakerMultiSigPubKey().toByteArray(), + proto.getTakerPayoutAddressString(), + PubKeyRing.fromProto(proto.getTakerPubKeyRing()), + coreProtoResolver.fromProto(proto.getTakerPaymentAccountPayload()), + proto.getTakerAccountId(), + proto.getTakerFeeTxId(), + acceptedArbitratorNodeAddresses, + acceptedMediatorNodeAddresses, + NodeAddress.fromProto(proto.getArbitratorNodeAddress()), + NodeAddress.fromProto(proto.getMediatorNodeAddress()), + proto.getUid(), + messageVersion, + ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfAccountData()), + ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce()), + ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfNonce())); } @Override public String toString() { return "PayDepositRequest{" + - "\n senderNodeAddress=" + senderNodeAddress + - ",\n tradeAmount=" + tradeAmount + - ",\n tradePrice=" + tradePrice + - ",\n txFee=" + txFee + - ",\n takerFee=" + takerFee + - ",\n isCurrencyForTakerFeeBtc=" + isCurrencyForTakerFeeBtc + - ",\n rawTransactionInputs=" + rawTransactionInputs + - ",\n changeOutputValue=" + changeOutputValue + - ",\n changeOutputAddress='" + changeOutputAddress + '\'' + - ",\n takerMultiSigPubKey=" + Utilities.bytesAsHexString(takerMultiSigPubKey) + - ",\n takerPayoutAddressString='" + takerPayoutAddressString + '\'' + - ",\n takerPubKeyRing=" + takerPubKeyRing + - ",\n takerPaymentAccountPayload=" + takerPaymentAccountPayload + - ",\n takerAccountId='" + takerAccountId + '\'' + - ",\n takerFeeTxId='" + takerFeeTxId + '\'' + - ",\n acceptedArbitratorNodeAddresses=" + acceptedArbitratorNodeAddresses + - ",\n acceptedMediatorNodeAddresses=" + acceptedMediatorNodeAddresses + - ",\n arbitratorNodeAddress=" + arbitratorNodeAddress + - ",\n mediatorNodeAddress=" + mediatorNodeAddress + - ",\n uid='" + uid + '\'' + - ",\n accountAgeWitnessNonce=" + Utilities.bytesAsHexString(accountAgeWitnessNonce) + - ",\n accountAgeWitnessSignatureOfNonce=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfNonce) + - "\n} " + super.toString(); + "\n senderNodeAddress=" + senderNodeAddress + + ",\n tradeAmount=" + tradeAmount + + ",\n tradePrice=" + tradePrice + + ",\n txFee=" + txFee + + ",\n takerFee=" + takerFee + + ",\n isCurrencyForTakerFeeBtc=" + isCurrencyForTakerFeeBtc + + ",\n rawTransactionInputs=" + rawTransactionInputs + + ",\n changeOutputValue=" + changeOutputValue + + ",\n changeOutputAddress='" + changeOutputAddress + '\'' + + ",\n takerMultiSigPubKey=" + Utilities.bytesAsHexString(takerMultiSigPubKey) + + ",\n takerPayoutAddressString='" + takerPayoutAddressString + '\'' + + ",\n takerPubKeyRing=" + takerPubKeyRing + + ",\n takerPaymentAccountPayload=" + takerPaymentAccountPayload + + ",\n takerAccountId='" + takerAccountId + '\'' + + ",\n takerFeeTxId='" + takerFeeTxId + '\'' + + ",\n acceptedArbitratorNodeAddresses=" + acceptedArbitratorNodeAddresses + + ",\n acceptedMediatorNodeAddresses=" + acceptedMediatorNodeAddresses + + ",\n arbitratorNodeAddress=" + arbitratorNodeAddress + + ",\n mediatorNodeAddress=" + mediatorNodeAddress + + ",\n uid='" + uid + '\'' + + ",\n accountAgeWitnessSignatureOfAccountData=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfAccountData) + + ",\n accountAgeWitnessNonce=" + Utilities.bytesAsHexString(accountAgeWitnessNonce) + + ",\n accountAgeWitnessSignatureOfNonce=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfNonce) + + "\n} " + super.toString(); } } diff --git a/core/src/main/java/io/bisq/core/trade/messages/PublishDepositTxRequest.java b/core/src/main/java/io/bisq/core/trade/messages/PublishDepositTxRequest.java index 2b7c213b55..e84749ef9f 100644 --- a/core/src/main/java/io/bisq/core/trade/messages/PublishDepositTxRequest.java +++ b/core/src/main/java/io/bisq/core/trade/messages/PublishDepositTxRequest.java @@ -19,6 +19,7 @@ package io.bisq.core.trade.messages; import com.google.protobuf.ByteString; import io.bisq.common.app.Version; +import io.bisq.common.proto.ProtoUtil; import io.bisq.common.util.Utilities; import io.bisq.core.btc.data.RawTransactionInput; import io.bisq.core.payment.payload.PaymentAccountPayload; @@ -54,6 +55,8 @@ public final class PublishDepositTxRequest extends TradeMessage implements Mailb // added in v 0.6. can be null if we trade with an older peer @Nullable + private final byte[] accountAgeWitnessSignatureOfAccountData; + @Nullable private final byte[] accountAgeWitnessNonce; @Nullable private final byte[] accountAgeWitnessSignatureOfNonce; @@ -69,22 +72,24 @@ public final class PublishDepositTxRequest extends TradeMessage implements Mailb List makerInputs, NodeAddress senderNodeAddress, String uid, + @Nullable byte[] accountAgeWitnessSignatureOfAccountData, @Nullable byte[] accountAgeWitnessNonce, @Nullable byte[] accountAgeWitnessSignatureOfNonce) { this(tradeId, - makerPaymentAccountPayload, - makerAccountId, - makerMultiSigPubKey, - makerContractAsJson, - makerContractSignature, - makerPayoutAddressString, - preparedDepositTx, - makerInputs, - senderNodeAddress, - uid, - Version.getP2PMessageVersion(), - accountAgeWitnessNonce, - accountAgeWitnessSignatureOfNonce); + makerPaymentAccountPayload, + makerAccountId, + makerMultiSigPubKey, + makerContractAsJson, + makerContractSignature, + makerPayoutAddressString, + preparedDepositTx, + makerInputs, + senderNodeAddress, + uid, + Version.getP2PMessageVersion(), + accountAgeWitnessSignatureOfAccountData, + accountAgeWitnessNonce, + accountAgeWitnessSignatureOfNonce); } @@ -104,6 +109,7 @@ public final class PublishDepositTxRequest extends TradeMessage implements Mailb NodeAddress senderNodeAddress, String uid, int messageVersion, + @Nullable byte[] accountAgeWitnessSignatureOfAccountData, @Nullable byte[] accountAgeWitnessNonce, @Nullable byte[] accountAgeWitnessSignatureOfNonce) { super(messageVersion, tradeId); @@ -117,6 +123,7 @@ public final class PublishDepositTxRequest extends TradeMessage implements Mailb this.makerInputs = makerInputs; this.senderNodeAddress = senderNodeAddress; this.uid = uid; + this.accountAgeWitnessSignatureOfAccountData = accountAgeWitnessSignatureOfAccountData; this.accountAgeWitnessNonce = accountAgeWitnessNonce; this.accountAgeWitnessSignatureOfNonce = accountAgeWitnessSignatureOfNonce; } @@ -124,63 +131,66 @@ public final class PublishDepositTxRequest extends TradeMessage implements Mailb @Override public PB.NetworkEnvelope toProtoNetworkEnvelope() { final PB.PublishDepositTxRequest.Builder builder = PB.PublishDepositTxRequest.newBuilder() - .setTradeId(tradeId) - .setMakerPaymentAccountPayload((PB.PaymentAccountPayload) makerPaymentAccountPayload.toProtoMessage()) - .setMakerAccountId(makerAccountId) - .setMakerMultiSigPubKey(ByteString.copyFrom(makerMultiSigPubKey)) - .setMakerContractAsJson(makerContractAsJson) - .setMakerContractSignature(makerContractSignature) - .setMakerPayoutAddressString(makerPayoutAddressString) - .setPreparedDepositTx(ByteString.copyFrom(preparedDepositTx)) - .addAllMakerInputs(makerInputs.stream().map(RawTransactionInput::toProtoMessage).collect(Collectors.toList())) - .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) - .setUid(uid); - - Optional.ofNullable(accountAgeWitnessNonce).ifPresent(accountAgeWitnessNonce ->builder.setAccountAgeWitnessNonce(ByteString.copyFrom(accountAgeWitnessNonce))); - Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(accountAgeWitnessSignatureOfNonce ->builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(accountAgeWitnessSignatureOfNonce))); + .setTradeId(tradeId) + .setMakerPaymentAccountPayload((PB.PaymentAccountPayload) makerPaymentAccountPayload.toProtoMessage()) + .setMakerAccountId(makerAccountId) + .setMakerMultiSigPubKey(ByteString.copyFrom(makerMultiSigPubKey)) + .setMakerContractAsJson(makerContractAsJson) + .setMakerContractSignature(makerContractSignature) + .setMakerPayoutAddressString(makerPayoutAddressString) + .setPreparedDepositTx(ByteString.copyFrom(preparedDepositTx)) + .addAllMakerInputs(makerInputs.stream().map(RawTransactionInput::toProtoMessage).collect(Collectors.toList())) + .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) + .setUid(uid); + + Optional.ofNullable(accountAgeWitnessSignatureOfAccountData).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfAccountData(ByteString.copyFrom(e))); + Optional.ofNullable(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e))); + Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(e))); return getNetworkEnvelopeBuilder() - .setPublishDepositTxRequest(builder) - .build(); + .setPublishDepositTxRequest(builder) + .build(); } public static PublishDepositTxRequest fromProto(PB.PublishDepositTxRequest proto, CoreProtoResolver coreProtoResolver, int messageVersion) { List makerInputs = proto.getMakerInputsList().stream() - .map(RawTransactionInput::fromProto) - .collect(Collectors.toList()); + .map(RawTransactionInput::fromProto) + .collect(Collectors.toList()); return new PublishDepositTxRequest(proto.getTradeId(), - coreProtoResolver.fromProto(proto.getMakerPaymentAccountPayload()), - proto.getMakerAccountId(), - proto.getMakerMultiSigPubKey().toByteArray(), - proto.getMakerContractAsJson(), - proto.getMakerContractSignature(), - proto.getMakerPayoutAddressString(), - proto.getPreparedDepositTx().toByteArray(), - makerInputs, - NodeAddress.fromProto(proto.getSenderNodeAddress()), - proto.getUid(), - messageVersion, - proto.getAccountAgeWitnessNonce().isEmpty() ? null : proto.getAccountAgeWitnessNonce().toByteArray(), - proto.getAccountAgeWitnessSignatureOfNonce().isEmpty() ? null : proto.getAccountAgeWitnessSignatureOfNonce().toByteArray()); + coreProtoResolver.fromProto(proto.getMakerPaymentAccountPayload()), + proto.getMakerAccountId(), + proto.getMakerMultiSigPubKey().toByteArray(), + proto.getMakerContractAsJson(), + proto.getMakerContractSignature(), + proto.getMakerPayoutAddressString(), + proto.getPreparedDepositTx().toByteArray(), + makerInputs, + NodeAddress.fromProto(proto.getSenderNodeAddress()), + proto.getUid(), + messageVersion, + ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfAccountData()), + ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce()), + ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfNonce())); } @Override public String toString() { return "PublishDepositTxRequest{" + - "\n makerPaymentAccountPayload=" + makerPaymentAccountPayload + - ",\n makerAccountId='" + makerAccountId + '\'' + - ",\n makerMultiSigPubKey=" + Utilities.bytesAsHexString(makerMultiSigPubKey) + - ",\n makerContractAsJson='" + makerContractAsJson + '\'' + - ",\n makerContractSignature='" + makerContractSignature + '\'' + - ",\n makerPayoutAddressString='" + makerPayoutAddressString + '\'' + - ",\n preparedDepositTx=" + Utilities.bytesAsHexString(preparedDepositTx) + - ",\n makerInputs=" + makerInputs + - ",\n senderNodeAddress=" + senderNodeAddress + - ",\n uid='" + uid + '\'' + - ",\n accountAgeWitnessNonce=" + Utilities.bytesAsHexString(accountAgeWitnessNonce) + - ",\n accountAgeWitnessSignatureOfNonce=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfNonce) + - "\n} " + super.toString(); + "\n makerPaymentAccountPayload=" + makerPaymentAccountPayload + + ",\n makerAccountId='" + makerAccountId + '\'' + + ",\n makerMultiSigPubKey=" + Utilities.bytesAsHexString(makerMultiSigPubKey) + + ",\n makerContractAsJson='" + makerContractAsJson + '\'' + + ",\n makerContractSignature='" + makerContractSignature + '\'' + + ",\n makerPayoutAddressString='" + makerPayoutAddressString + '\'' + + ",\n preparedDepositTx=" + Utilities.bytesAsHexString(preparedDepositTx) + + ",\n makerInputs=" + makerInputs + + ",\n senderNodeAddress=" + senderNodeAddress + + ",\n uid='" + uid + '\'' + + ",\n accountAgeWitnessSignatureOfAccountData=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfAccountData) + + ",\n accountAgeWitnessNonce=" + Utilities.bytesAsHexString(accountAgeWitnessNonce) + + ",\n accountAgeWitnessSignatureOfNonce=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfNonce) + + "\n} " + super.toString(); } } diff --git a/core/src/main/java/io/bisq/core/trade/protocol/BuyerAsTakerProtocol.java b/core/src/main/java/io/bisq/core/trade/protocol/BuyerAsTakerProtocol.java index f7aff4d3f1..9f35ffe961 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/BuyerAsTakerProtocol.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/BuyerAsTakerProtocol.java @@ -127,7 +127,6 @@ public class BuyerAsTakerProtocol extends TradeProtocol implements BuyerProtocol TakerProcessPublishDepositTxRequest.class, CheckIfPeerIsBanned.class, TakerVerifyMakerAccount.class, - TakerVerifyOffersAccountAgeWitnessHash.class, VerifyPeersAccountAgeWitness.class, TakerVerifyMakerFeePayment.class, TakerVerifyAndSignContract.class, diff --git a/core/src/main/java/io/bisq/core/trade/protocol/SellerAsTakerProtocol.java b/core/src/main/java/io/bisq/core/trade/protocol/SellerAsTakerProtocol.java index b083d55ece..bc1e1e8162 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/SellerAsTakerProtocol.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/SellerAsTakerProtocol.java @@ -29,7 +29,6 @@ import io.bisq.core.trade.messages.TradeMessage; import io.bisq.core.trade.protocol.tasks.CheckIfPeerIsBanned; import io.bisq.core.trade.protocol.tasks.PublishAccountAgeWitness; import io.bisq.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness; -import io.bisq.core.trade.protocol.tasks.taker.TakerVerifyOffersAccountAgeWitnessHash; import io.bisq.core.trade.protocol.tasks.seller.SellerBroadcastPayoutTx; import io.bisq.core.trade.protocol.tasks.seller.SellerProcessCounterCurrencyTransferStartedMessage; import io.bisq.core.trade.protocol.tasks.seller.SellerSendPayoutTxPublishedMessage; @@ -123,7 +122,6 @@ public class SellerAsTakerProtocol extends TradeProtocol implements SellerProtoc TakerProcessPublishDepositTxRequest.class, CheckIfPeerIsBanned.class, TakerVerifyMakerAccount.class, - TakerVerifyOffersAccountAgeWitnessHash.class, VerifyPeersAccountAgeWitness.class, TakerVerifyMakerFeePayment.class, TakerVerifyAndSignContract.class, diff --git a/core/src/main/java/io/bisq/core/trade/protocol/TradingPeer.java b/core/src/main/java/io/bisq/core/trade/protocol/TradingPeer.java index 18417245ed..30be62e359 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/TradingPeer.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/TradingPeer.java @@ -60,6 +60,10 @@ public final class TradingPeer implements PersistablePayload { private long changeOutputValue; @Nullable private String changeOutputAddress; + + // added in v 0.6 + @Nullable + private byte[] accountAgeWitnessSignatureOfAccountData; @Nullable private byte[] accountAgeWitnessNonce; @Nullable @@ -71,7 +75,7 @@ public final class TradingPeer implements PersistablePayload { @Override public Message toProtoMessage() { final PB.TradingPeer.Builder builder = PB.TradingPeer.newBuilder() - .setChangeOutputValue(changeOutputValue); + .setChangeOutputValue(changeOutputValue); Optional.ofNullable(accountId).ifPresent(builder::setAccountId); Optional.ofNullable(paymentAccountPayload).ifPresent(e -> builder.setPaymentAccountPayload((PB.PaymentAccountPayload) e.toProtoMessage())); Optional.ofNullable(payoutAddressString).ifPresent(builder::setPayoutAddressString); @@ -82,6 +86,7 @@ public final class TradingPeer implements PersistablePayload { Optional.ofNullable(multiSigPubKey).ifPresent(e -> builder.setMultiSigPubKey(ByteString.copyFrom(e))); Optional.ofNullable(rawTransactionInputs).ifPresent(e -> builder.addAllRawTransactionInputs(ProtoUtil.collectionToProto(e))); Optional.ofNullable(changeOutputAddress).ifPresent(builder::setChangeOutputAddress); + Optional.ofNullable(accountAgeWitnessSignatureOfAccountData).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfAccountData(ByteString.copyFrom(e))); Optional.ofNullable(accountAgeWitnessNonce).ifPresent(e -> builder.setAccountAgeWitnessNonce(ByteString.copyFrom(e))); Optional.ofNullable(accountAgeWitnessSignatureOfNonce).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfNonce(ByteString.copyFrom(e))); return builder.build(); @@ -102,12 +107,13 @@ public final class TradingPeer implements PersistablePayload { tradingPeer.setPubKeyRing(proto.hasPubKeyRing() ? PubKeyRing.fromProto(proto.getPubKeyRing()) : null); tradingPeer.setMultiSigPubKey(ProtoUtil.byteArrayOrNullFromProto(proto.getMultiSigPubKey())); List rawTransactionInputs = proto.getRawTransactionInputsList().isEmpty() ? - null : - proto.getRawTransactionInputsList().stream() - .map(RawTransactionInput::fromProto) - .collect(Collectors.toList()); + null : + proto.getRawTransactionInputsList().stream() + .map(RawTransactionInput::fromProto) + .collect(Collectors.toList()); tradingPeer.setRawTransactionInputs(rawTransactionInputs); tradingPeer.setChangeOutputAddress(ProtoUtil.stringOrNullFromProto(proto.getChangeOutputAddress())); + tradingPeer.setAccountAgeWitnessNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfAccountData())); tradingPeer.setAccountAgeWitnessNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessNonce())); tradingPeer.setAccountAgeWitnessSignatureOfNonce(ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfNonce())); return tradingPeer; diff --git a/core/src/main/java/io/bisq/core/trade/protocol/tasks/PublishAccountAgeWitness.java b/core/src/main/java/io/bisq/core/trade/protocol/tasks/PublishAccountAgeWitness.java index ec67531c05..b58fcf2176 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/tasks/PublishAccountAgeWitness.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/tasks/PublishAccountAgeWitness.java @@ -32,7 +32,7 @@ public class PublishAccountAgeWitness extends TradeTask { protected void run() { try { runInterceptHook(); - processModel.getAccountAgeWitnessService().publishAccountAgeWitness(processModel.getPaymentAccountPayload(trade)); + processModel.getAccountAgeWitnessService().publishMyAccountAgeWitness(processModel.getPaymentAccountPayload(trade)); complete(); } catch (Throwable t) { failed(t); diff --git a/core/src/main/java/io/bisq/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java b/core/src/main/java/io/bisq/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java index 0a1f5ee8ce..356189b019 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java @@ -19,10 +19,12 @@ package io.bisq.core.trade.protocol.tasks; import io.bisq.common.crypto.PubKeyRing; import io.bisq.common.taskrunner.TaskRunner; +import io.bisq.core.offer.Offer; import io.bisq.core.payment.AccountAgeWitness; import io.bisq.core.payment.AccountAgeWitnessService; import io.bisq.core.payment.payload.PaymentAccountPayload; import io.bisq.core.trade.Trade; +import io.bisq.core.trade.protocol.TradingPeer; import lombok.extern.slf4j.Slf4j; import java.util.Date; @@ -45,49 +47,46 @@ public class VerifyPeersAccountAgeWitness extends TradeTask { runInterceptHook(); final AccountAgeWitnessService accountAgeWitnessService = processModel.getAccountAgeWitnessService(); - final PaymentAccountPayload peersPaymentAccountPayload = checkNotNull(processModel.getTradingPeer().getPaymentAccountPayload(), - "Peers peersPaymentAccountPayload must not be null"); - - final String[] errorMsg1 = new String[1]; - boolean result = accountAgeWitnessService.verifyTradeLimit(trade.getOffer(), peersPaymentAccountPayload, errorMessage -> errorMsg1[0] = errorMessage); - if (result) { - byte[] nonce = processModel.getTradingPeer().getAccountAgeWitnessNonce(); - byte[] signatureOfNonce = processModel.getTradingPeer().getAccountAgeWitnessSignatureOfNonce(); - Optional witnessOptional = accountAgeWitnessService.getWitnessByPaymentAccountPayload(peersPaymentAccountPayload); - if (witnessOptional.isPresent() && nonce != null && signatureOfNonce != null) { - AccountAgeWitness witness = witnessOptional.get(); - final PubKeyRing pubKeyRing = processModel.getTradingPeer().getPubKeyRing(); - checkNotNull(pubKeyRing, "processModel.getTradingPeer().getPubKeyRing() must not be null"); - final String[] errorMsg2 = new String[1]; - result = accountAgeWitnessService.verifyAccountAgeWitness(peersPaymentAccountPayload.getAgeWitnessInputData(), - witness, - peersPaymentAccountPayload.getSalt(), - pubKeyRing.getSignaturePubKey(), - nonce, - signatureOfNonce, - errorMessage -> errorMsg2[0] = errorMessage); - if (result) - complete(); - else - failed(errorMsg2[0]); - } else { - String msg = !witnessOptional.isPresent() ? - "Peers AccountAgeWitness is not found." : - "Peer seems to uses a pre v0.6 application which does not support sending of account age witness verification nonce and signature."; - msg += "\nTrade ID=" + trade.getId(); - if (new Date().after(new GregorianCalendar(2018, GregorianCalendar.FEBRUARY, 1).getTime())) { - msg = "The account age witness verification failed.\nReason: " + msg; - log.error(msg); - failed(msg); - } else { - log.warn(msg + "\nWe tolerate that until 1. of Feb. 2018"); - complete(); - } - } + final TradingPeer tradingPeer = processModel.getTradingPeer(); + final PaymentAccountPayload peersPaymentAccountPayload = checkNotNull(tradingPeer.getPaymentAccountPayload(), + "Peers peersPaymentAccountPayload must not be null"); + final PubKeyRing peersPubKeyRing = checkNotNull(tradingPeer.getPubKeyRing(), "peersPubKeyRing must not be null"); + final Offer offer = trade.getOffer(); + final Optional accountAgeWitnessHashAsHex = offer.getAccountAgeWitnessHashAsHex(); + Optional witnessOptional = accountAgeWitnessHashAsHex.isPresent() ? + accountAgeWitnessService.getPeersWitnessByHashAsHex(accountAgeWitnessHashAsHex.get()) + : Optional.empty(); + byte[] nonce = tradingPeer.getAccountAgeWitnessNonce(); + byte[] signatureOfNonce = tradingPeer.getAccountAgeWitnessSignatureOfNonce(); + if (witnessOptional.isPresent() && nonce != null && signatureOfNonce != null) { + AccountAgeWitness witness = witnessOptional.get(); + final String[] errorMsg = new String[1]; + byte[] peersSignatureOfAccountHash = tradingPeer.getAccountAgeWitnessSignatureOfAccountData(); + boolean result = accountAgeWitnessService.verifyPeersAccountAgeWitness(offer, + peersPaymentAccountPayload, + witness, + peersPubKeyRing, + peersSignatureOfAccountHash, + nonce, + signatureOfNonce, + errorMessage -> errorMsg[0] = errorMessage); + if (result) + complete(); + else + failed(errorMsg[0]); } else { - String msg = "The offer verification failed.\nReason: " + errorMsg1[0]; - log.error(msg); - failed(msg); + String msg = !witnessOptional.isPresent() ? + "Peers AccountAgeWitness is not found." : + "Peer seems to uses a pre v0.6 application which does not support sending of account age witness verification nonce and signature."; + msg += "\nTrade ID=" + trade.getId(); + if (new Date().after(new GregorianCalendar(2018, GregorianCalendar.FEBRUARY, 1).getTime())) { + msg = "The account age witness verification failed.\nReason: " + msg; + log.error(msg); + failed(msg); + } else { + log.warn(msg + "\nWe tolerate offers without account age witness until first of Feb. 2018"); + complete(); + } } } catch (Throwable t) { failed(t); diff --git a/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerProcessPayDepositRequest.java b/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerProcessPayDepositRequest.java index 7b3d7e0b82..afedf0e660 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerProcessPayDepositRequest.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerProcessPayDepositRequest.java @@ -66,13 +66,14 @@ public class MakerProcessPayDepositRequest extends TradeTask { if (payDepositRequest.getAcceptedArbitratorNodeAddresses().isEmpty()) failed("acceptedArbitratorNames must not be empty"); + processModel.getTradingPeer().setAccountAgeWitnessSignatureOfAccountData(payDepositRequest.getAccountAgeWitnessSignatureOfAccountData()); final byte[] accountAgeWitnessNonce = payDepositRequest.getAccountAgeWitnessNonce(); processModel.getTradingPeer().setAccountAgeWitnessNonce(accountAgeWitnessNonce); processModel.getTradingPeer().setAccountAgeWitnessSignatureOfNonce(payDepositRequest.getAccountAgeWitnessSignatureOfNonce()); // Taker has to use offerId as nonce (he cannot manipulate that - so we avoid to have a challenge protocol for passing the nonce we want to get signed) // He cannot manipulate the offerId - so we avoid to have a challenge protocol for passing the nonce we want to get signed. checkArgument(Arrays.equals(accountAgeWitnessNonce, trade.getOffer().getId().getBytes())); - + trade.setArbitratorNodeAddress(checkNotNull(payDepositRequest.getArbitratorNodeAddress())); trade.setMediatorNodeAddress(checkNotNull(payDepositRequest.getMediatorNodeAddress())); @@ -98,4 +99,4 @@ public class MakerProcessPayDepositRequest extends TradeTask { failed(t); } } -} \ No newline at end of file +} diff --git a/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerSendPublishDepositTxRequest.java b/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerSendPublishDepositTxRequest.java index 822b50b020..95ec398c3a 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerSendPublishDepositTxRequest.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerSendPublishDepositTxRequest.java @@ -21,6 +21,7 @@ import io.bisq.common.crypto.Sig; import io.bisq.common.taskrunner.TaskRunner; import io.bisq.core.btc.AddressEntry; import io.bisq.core.btc.wallet.BtcWalletService; +import io.bisq.core.payment.payload.PaymentAccountPayload; import io.bisq.core.trade.Trade; import io.bisq.core.trade.messages.PublishDepositTxRequest; import io.bisq.core.trade.protocol.tasks.TradeTask; @@ -32,6 +33,7 @@ import java.util.Optional; import java.util.UUID; import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; @Slf4j public class MakerSendPublishDepositTxRequest extends TradeTask { @@ -52,60 +54,66 @@ public class MakerSendPublishDepositTxRequest extends TradeTask { AddressEntry makerPayoutAddressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.TRADE_PAYOUT); byte[] makerMultiSigPubKey = processModel.getMyMultiSigPubKey(); checkArgument(Arrays.equals(makerMultiSigPubKey, - addressEntryOptional.get().getPubKey()), - "makerMultiSigPubKey from AddressEntry must match the one from the trade data. trade id =" + id); + addressEntryOptional.get().getPubKey()), + "makerMultiSigPubKey from AddressEntry must match the one from the trade data. trade id =" + id); final byte[] preparedDepositTx = processModel.getPreparedDepositTx(); - - // Maker has to use preparedDepositTx as nonce. + + // Maker has to use preparedDepositTx as nonce. // He cannot manipulate the preparedDepositTx - so we avoid to have a challenge protocol for passing the nonce we want to get signed. + final PaymentAccountPayload paymentAccountPayload = checkNotNull(processModel.getPaymentAccountPayload(trade), "processModel.getPaymentAccountPayload(trade) must not be null"); + byte[] accountAgeWitnessSignatureOfAccountData = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), + processModel.getAccountAgeWitnessService().getAccountInputDataWithSalt(paymentAccountPayload)); + + //noinspection UnnecessaryLocalVariable byte[] accountAgeWitnessNonce = preparedDepositTx; byte[] accountAgeWitnessSignatureOfNonce = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), accountAgeWitnessNonce); PublishDepositTxRequest message = new PublishDepositTxRequest( - processModel.getOfferId(), - processModel.getPaymentAccountPayload(trade), - processModel.getAccountId(), - makerMultiSigPubKey, - trade.getContractAsJson(), - trade.getMakerContractSignature(), - makerPayoutAddressEntry.getAddressString(), - preparedDepositTx, - processModel.getRawTransactionInputs(), - processModel.getMyNodeAddress(), - UUID.randomUUID().toString(), - accountAgeWitnessNonce, - accountAgeWitnessSignatureOfNonce); - + processModel.getOfferId(), + paymentAccountPayload, + processModel.getAccountId(), + makerMultiSigPubKey, + trade.getContractAsJson(), + trade.getMakerContractSignature(), + makerPayoutAddressEntry.getAddressString(), + preparedDepositTx, + processModel.getRawTransactionInputs(), + processModel.getMyNodeAddress(), + UUID.randomUUID().toString(), + accountAgeWitnessSignatureOfAccountData, + accountAgeWitnessNonce, + accountAgeWitnessSignatureOfNonce); + trade.setState(Trade.State.MAKER_SENT_PUBLISH_DEPOSIT_TX_REQUEST); processModel.getP2PService().sendEncryptedMailboxMessage( - trade.getTradingPeerNodeAddress(), - processModel.getTradingPeer().getPubKeyRing(), - message, - new SendMailboxMessageListener() { - @Override - public void onArrived() { - log.info("Message arrived at peer. tradeId={}", id); - trade.setState(Trade.State.MAKER_SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST); - complete(); - } - - @Override - public void onStoredInMailbox() { - log.info("Message stored in mailbox. tradeId={}", id); - trade.setState(Trade.State.MAKER_STORED_IN_MAILBOX_PUBLISH_DEPOSIT_TX_REQUEST); - complete(); - } - - @Override - public void onFault(String errorMessage) { - log.error("sendEncryptedMailboxMessage failed. message=" + message); - trade.setState(Trade.State.MAKER_SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST); - appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage); - failed(errorMessage); - } + trade.getTradingPeerNodeAddress(), + processModel.getTradingPeer().getPubKeyRing(), + message, + new SendMailboxMessageListener() { + @Override + public void onArrived() { + log.info("Message arrived at peer. tradeId={}", id); + trade.setState(Trade.State.MAKER_SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST); + complete(); } + + @Override + public void onStoredInMailbox() { + log.info("Message stored in mailbox. tradeId={}", id); + trade.setState(Trade.State.MAKER_STORED_IN_MAILBOX_PUBLISH_DEPOSIT_TX_REQUEST); + complete(); + } + + @Override + public void onFault(String errorMessage) { + log.error("sendEncryptedMailboxMessage failed. message=" + message); + trade.setState(Trade.State.MAKER_SEND_FAILED_PUBLISH_DEPOSIT_TX_REQUEST); + appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage); + failed(errorMessage); + } + } ); } catch (Throwable t) { diff --git a/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerSetupDepositTxListener.java b/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerSetupDepositTxListener.java index 426fde48f3..6f356f059c 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerSetupDepositTxListener.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/tasks/maker/MakerSetupDepositTxListener.java @@ -54,7 +54,7 @@ public class MakerSetupDepositTxListener extends TradeTask { if (walletService.getBalanceForAddress(address).isZero()) { trade.setState(Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK); swapReservedForTradeEntry(); - processModel.getAccountAgeWitnessService().publishAccountAgeWitness(processModel.getPaymentAccountPayload(trade)); + processModel.getAccountAgeWitnessService().publishMyAccountAgeWitness(processModel.getPaymentAccountPayload(trade)); } else { listener = new BalanceListener(address) { @Override @@ -62,7 +62,7 @@ public class MakerSetupDepositTxListener extends TradeTask { if (balance.isZero() && trade.getState().getPhase() == Trade.Phase.TAKER_FEE_PUBLISHED) { trade.setState(Trade.State.MAKER_SAW_DEPOSIT_TX_IN_NETWORK); swapReservedForTradeEntry(); - processModel.getAccountAgeWitnessService().publishAccountAgeWitness(processModel.getPaymentAccountPayload(trade)); + processModel.getAccountAgeWitnessService().publishMyAccountAgeWitness(processModel.getPaymentAccountPayload(trade)); } } }; diff --git a/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerProcessPublishDepositTxRequest.java b/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerProcessPublishDepositTxRequest.java index 32f49bcc3f..d372db0c06 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerProcessPublishDepositTxRequest.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerProcessPublishDepositTxRequest.java @@ -56,10 +56,11 @@ public class TakerProcessPublishDepositTxRequest extends TradeTask { final byte[] preparedDepositTx = publishDepositTxRequest.getPreparedDepositTx(); processModel.setPreparedDepositTx(checkNotNull(preparedDepositTx)); + processModel.getTradingPeer().setAccountAgeWitnessSignatureOfAccountData(publishDepositTxRequest.getAccountAgeWitnessSignatureOfAccountData()); final byte[] accountAgeWitnessNonce = publishDepositTxRequest.getAccountAgeWitnessNonce(); processModel.getTradingPeer().setAccountAgeWitnessNonce(accountAgeWitnessNonce); processModel.getTradingPeer().setAccountAgeWitnessSignatureOfNonce(publishDepositTxRequest.getAccountAgeWitnessSignatureOfNonce()); - // Maker has to use preparedDepositTx as nonce. + // Maker has to use preparedDepositTx as nonce. // He cannot manipulate the preparedDepositTx - so we avoid to have a challenge protocol for passing the nonce we want to get signed. checkArgument(Arrays.equals(accountAgeWitnessNonce, preparedDepositTx)); @@ -74,4 +75,4 @@ public class TakerProcessPublishDepositTxRequest extends TradeTask { failed(t); } } -} \ No newline at end of file +} diff --git a/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerSendPayDepositRequest.java b/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerSendPayDepositRequest.java index 8aef4f460b..8aae6b490a 100644 --- a/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerSendPayDepositRequest.java +++ b/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerSendPayDepositRequest.java @@ -22,6 +22,7 @@ import io.bisq.common.crypto.Sig; import io.bisq.common.taskrunner.TaskRunner; import io.bisq.core.btc.AddressEntry; import io.bisq.core.btc.wallet.BtcWalletService; +import io.bisq.core.payment.payload.PaymentAccountPayload; import io.bisq.core.trade.Trade; import io.bisq.core.trade.messages.PayDepositRequest; import io.bisq.core.trade.protocol.tasks.TradeTask; @@ -61,7 +62,7 @@ public class TakerSendPayDepositRequest extends TradeTask { String id = processModel.getOffer().getId(); checkArgument(!walletService.getAddressEntry(id, AddressEntry.Context.MULTI_SIG).isPresent(), - "addressEntry must not be set here."); + "addressEntry must not be set here."); AddressEntry addressEntry = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.MULTI_SIG); byte[] takerMultiSigPubKey = addressEntry.getPubKey(); processModel.setMyMultiSigPubKey(takerMultiSigPubKey); @@ -70,55 +71,59 @@ public class TakerSendPayDepositRequest extends TradeTask { String takerPayoutAddressString = takerPayoutAddressEntry.getAddressString(); final String offerId = processModel.getOfferId(); - + // Taker has to use offerId as nonce (he cannot manipulate that - so we avoid to have a challenge protocol for passing the nonce we want to get signed) // He cannot manipulate the offerId - so we avoid to have a challenge protocol for passing the nonce we want to get signed. + final PaymentAccountPayload paymentAccountPayload = checkNotNull(processModel.getPaymentAccountPayload(trade), "processModel.getPaymentAccountPayload(trade) must not be null"); + byte[] accountAgeWitnessSignatureOfAccountData = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), + processModel.getAccountAgeWitnessService().getAccountInputDataWithSalt(paymentAccountPayload)); byte[] accountAgeWitnessNonce = offerId.getBytes(); byte[] accountAgeWitnessSignatureOfNonce = Sig.sign(processModel.getKeyRing().getSignatureKeyPair().getPrivate(), accountAgeWitnessNonce); - + PayDepositRequest message = new PayDepositRequest( - offerId, - processModel.getMyNodeAddress(), - trade.getTradeAmount().value, - trade.getTradePrice().getValue(), - trade.getTxFee().getValue(), - trade.getTakerFee().getValue(), - trade.isCurrencyForTakerFeeBtc(), - processModel.getRawTransactionInputs(), - processModel.getChangeOutputValue(), - processModel.getChangeOutputAddress(), - takerMultiSigPubKey, - takerPayoutAddressString, - processModel.getPubKeyRing(), - processModel.getPaymentAccountPayload(trade), - processModel.getAccountId(), - trade.getTakerFeeTxId(), - new ArrayList<>(acceptedArbitratorAddresses), - new ArrayList<>(acceptedMediatorAddresses), - trade.getArbitratorNodeAddress(), - trade.getMediatorNodeAddress(), - UUID.randomUUID().toString(), - Version.getP2PMessageVersion(), - accountAgeWitnessNonce, - accountAgeWitnessSignatureOfNonce); + offerId, + processModel.getMyNodeAddress(), + trade.getTradeAmount().value, + trade.getTradePrice().getValue(), + trade.getTxFee().getValue(), + trade.getTakerFee().getValue(), + trade.isCurrencyForTakerFeeBtc(), + processModel.getRawTransactionInputs(), + processModel.getChangeOutputValue(), + processModel.getChangeOutputAddress(), + takerMultiSigPubKey, + takerPayoutAddressString, + processModel.getPubKeyRing(), + paymentAccountPayload, + processModel.getAccountId(), + trade.getTakerFeeTxId(), + new ArrayList<>(acceptedArbitratorAddresses), + new ArrayList<>(acceptedMediatorAddresses), + trade.getArbitratorNodeAddress(), + trade.getMediatorNodeAddress(), + UUID.randomUUID().toString(), + Version.getP2PMessageVersion(), + accountAgeWitnessSignatureOfAccountData, + accountAgeWitnessNonce, + accountAgeWitnessSignatureOfNonce); processModel.getP2PService().sendEncryptedDirectMessage( - trade.getTradingPeerNodeAddress(), - processModel.getTradingPeer().getPubKeyRing(), - message, - new SendDirectMessageListener() { - @Override - public void onArrived() { - log.debug("Message arrived at peer. tradeId={}, message{}", id, message); - complete(); - } - - @Override - public void onFault() { - appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage); - failed(); - } + trade.getTradingPeerNodeAddress(), + processModel.getTradingPeer().getPubKeyRing(), + message, + new SendDirectMessageListener() { + @Override + public void onArrived() { + log.debug("Message arrived at peer. tradeId={}, message{}", id, message); + complete(); } + + @Override + public void onFault() { + appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage); + failed(); + } + } ); } catch (Throwable t) { failed(t); diff --git a/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerVerifyOffersAccountAgeWitnessHash.java b/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerVerifyOffersAccountAgeWitnessHash.java deleted file mode 100644 index e389b6bc2e..0000000000 --- a/core/src/main/java/io/bisq/core/trade/protocol/tasks/taker/TakerVerifyOffersAccountAgeWitnessHash.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 . - */ - -package io.bisq.core.trade.protocol.tasks.taker; - -import io.bisq.common.taskrunner.TaskRunner; -import io.bisq.common.util.Utilities; -import io.bisq.core.offer.OfferPayload; -import io.bisq.core.payment.payload.PaymentAccountPayload; -import io.bisq.core.trade.Trade; -import io.bisq.core.trade.protocol.tasks.TradeTask; -import lombok.extern.slf4j.Slf4j; - -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.Map; - -import static com.google.common.base.Preconditions.checkNotNull; - -@Slf4j -public class TakerVerifyOffersAccountAgeWitnessHash extends TradeTask { - - @SuppressWarnings({"WeakerAccess", "unused"}) - public TakerVerifyOffersAccountAgeWitnessHash(TaskRunner taskHandler, Trade trade) { - super(taskHandler, trade); - } - - @Override - protected void run() { - try { - runInterceptHook(); - - final PaymentAccountPayload peersPaymentAccountPayload = checkNotNull(processModel.getTradingPeer().getPaymentAccountPayload(), - "Peers paymentAccountPayload must not be null"); - final Map extraDataMap = trade.getOffer().getExtraDataMap(); - if (extraDataMap != null && extraDataMap.containsKey(OfferPayload.ACCOUNT_AGE_WITNESS_HASH)) { - final String[] errorMsg2 = new String[1]; - boolean result = processModel.getAccountAgeWitnessService().verifyOffersAccountAgeWitness(peersPaymentAccountPayload, - Utilities.decodeFromHex(extraDataMap.get(OfferPayload.ACCOUNT_AGE_WITNESS_HASH)), - errorMessage -> errorMsg2[0] = errorMessage); - if (result) - complete(); - else - failed(errorMsg2[0]); - } else { - String msg = "ACCOUNT_AGE_WITNESS_HASH is not found in offer.\nThat is expected for offers created before v.0.6." + - "\nTrade ID=" + trade.getId(); - if (new Date().after(new GregorianCalendar(2018, GregorianCalendar.FEBRUARY, 1).getTime())) { - msg = "The offer verification failed.\nReason: " + msg; - log.error(msg); - failed(msg); - } else { - log.warn(msg + "\nWe tolerate that until 1. of Feb. 2018"); - complete(); - } - } - } catch (Throwable t) { - failed(t); - } - } -} diff --git a/core/src/test/java/io/bisq/core/payment/AccountAgeWitnessServiceTest.java b/core/src/test/java/io/bisq/core/payment/AccountAgeWitnessServiceTest.java index f595da7aa5..1d2115e87a 100644 --- a/core/src/test/java/io/bisq/core/payment/AccountAgeWitnessServiceTest.java +++ b/core/src/test/java/io/bisq/core/payment/AccountAgeWitnessServiceTest.java @@ -71,14 +71,6 @@ public class AccountAgeWitnessServiceTest { assertFalse(service.isTradeDateAfterReleaseDate(tradeDate.getTime(), ageWitnessReleaseDate, errorMessage -> {})); } - @Test - public void testVerifySigPubKey() { - byte[] sigPubKeHash = Hash.getSha256Ripemd160hash(Sig.getPublicKeyBytes(publicKey)); - assertFalse(service.verifySigPubKeyHash(new byte[0], publicKey, errorMessage -> {})); - assertFalse(service.verifySigPubKeyHash(new byte[1], publicKey, errorMessage -> {})); - assertTrue(service.verifySigPubKeyHash(sigPubKeHash, publicKey, errorMessage -> {})); - } - @Test public void testVerifySignature() throws CryptoException { byte[] ageWitnessInputData = "test".getBytes(Charset.forName("UTF-8")); diff --git a/gui/src/main/java/io/bisq/gui/components/PeerInfoIcon.java b/gui/src/main/java/io/bisq/gui/components/PeerInfoIcon.java index ceca83d590..a7a2a1a7d4 100644 --- a/gui/src/main/java/io/bisq/gui/components/PeerInfoIcon.java +++ b/gui/src/main/java/io/bisq/gui/components/PeerInfoIcon.java @@ -50,14 +50,14 @@ public class PeerInfoIcon extends Group { peerTagMap = preferences.getPeerTagMap(); boolean hasTraded = numTrades > 0; - String accountAge = formatter.formatAccountAge(accountAgeWitnessService.getAccountAge(offer)); + String accountAge = formatter.formatAccountAge(accountAgeWitnessService.getPeersAccountAge(offer)); tooltipText = hasTraded ? Res.get("peerInfoIcon.tooltip.trade.traded", role, hostName, numTrades, accountAge) : Res.get("peerInfoIcon.tooltip.trade.notTraded", role, hostName, accountAge); // outer circle Color ringColor; - switch (accountAgeWitnessService.getAccountAgeCategory(accountAgeWitnessService.getAccountAge(offer))) { + switch (accountAgeWitnessService.getAccountAgeCategory(accountAgeWitnessService.getPeersAccountAge(offer))) { case TWO_MONTHS_OR_MORE: ringColor = Color.rgb(0, 225, 0); // > 2 months green break; diff --git a/gui/src/main/java/io/bisq/gui/components/paymentmethods/PaymentMethodForm.java b/gui/src/main/java/io/bisq/gui/components/paymentmethods/PaymentMethodForm.java index 895a8d8b12..80985257f0 100644 --- a/gui/src/main/java/io/bisq/gui/components/paymentmethods/PaymentMethodForm.java +++ b/gui/src/main/java/io/bisq/gui/components/paymentmethods/PaymentMethodForm.java @@ -151,10 +151,10 @@ public abstract class PaymentMethodForm { CurrencyUtil.getDefaultTradeCurrency(); final boolean isAddAccountScreen = paymentAccount.getAccountName() == null; - final long accountAge = !isAddAccountScreen ? accountAgeWitnessService.getAccountAge(paymentAccount.getPaymentAccountPayload()) : 0L; + final long accountAge = !isAddAccountScreen ? accountAgeWitnessService.getMyAccountAge(paymentAccount.getPaymentAccountPayload()) : 0L; addLabelTextField(gridPane, ++gridRow, Res.get("payment.limitations"), Res.get("payment.maxPeriodAndLimit", getTimeText(hours), - formatter.formatCoinWithCode(Coin.valueOf(accountAgeWitnessService.getTradeLimit(paymentAccount, tradeCurrency.getCode()))), + formatter.formatCoinWithCode(Coin.valueOf(accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrency.getCode()))), formatter.formatAccountAge(accountAge))); if (isAddAccountScreen) { @@ -165,7 +165,7 @@ public abstract class PaymentMethodForm { try { // test if input is hex Utilities.decodeFromHex(newValue); - + paymentAccount.setSaltAsHex(newValue); } catch (Throwable t) { new Popup().warning(Res.get("payment.error.noHexSalt")).show(); diff --git a/gui/src/main/java/io/bisq/gui/main/MainViewModel.java b/gui/src/main/java/io/bisq/gui/main/MainViewModel.java index fdc47d3a0c..b5f0d1b0a1 100644 --- a/gui/src/main/java/io/bisq/gui/main/MainViewModel.java +++ b/gui/src/main/java/io/bisq/gui/main/MainViewModel.java @@ -1199,12 +1199,12 @@ public class MainViewModel implements ViewModel { user.addPaymentAccount(okPayAccount); if (p2PService.isBootstrapped()) { - accountAgeWitnessService.publishAccountAgeWitness(okPayAccount.getPaymentAccountPayload()); + accountAgeWitnessService.publishMyAccountAgeWitness(okPayAccount.getPaymentAccountPayload()); } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override public void onBootstrapComplete() { - accountAgeWitnessService.publishAccountAgeWitness(okPayAccount.getPaymentAccountPayload()); + accountAgeWitnessService.publishMyAccountAgeWitness(okPayAccount.getPaymentAccountPayload()); } }); } diff --git a/gui/src/main/java/io/bisq/gui/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java b/gui/src/main/java/io/bisq/gui/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java index 78b20d8f98..841742f22b 100644 --- a/gui/src/main/java/io/bisq/gui/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java +++ b/gui/src/main/java/io/bisq/gui/main/account/content/altcoinaccounts/AltCoinAccountsDataModel.java @@ -60,7 +60,7 @@ class AltCoinAccountsDataModel extends ActivatableDataModel { OpenOfferManager openOfferManager, TradeManager tradeManager, AccountAgeWitnessService accountAgeWitnessService, - Stage stage, + Stage stage, PersistenceProtoResolver persistenceProtoResolver) { this.user = user; this.preferences = preferences; @@ -115,7 +115,7 @@ class AltCoinAccountsDataModel extends ActivatableDataModel { }); } - accountAgeWitnessService.publishAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); + accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); } public boolean onDeleteAccount(PaymentAccount paymentAccount) { diff --git a/gui/src/main/java/io/bisq/gui/main/account/content/fiataccounts/FiatAccountsDataModel.java b/gui/src/main/java/io/bisq/gui/main/account/content/fiataccounts/FiatAccountsDataModel.java index daf3cc2245..40127a1a98 100644 --- a/gui/src/main/java/io/bisq/gui/main/account/content/fiataccounts/FiatAccountsDataModel.java +++ b/gui/src/main/java/io/bisq/gui/main/account/content/fiataccounts/FiatAccountsDataModel.java @@ -115,8 +115,8 @@ class FiatAccountsDataModel extends ActivatableDataModel { preferences.addCryptoCurrency((CryptoCurrency) tradeCurrency); }); } - - accountAgeWitnessService.publishAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); + + accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); } public boolean onDeleteAccount(PaymentAccount paymentAccount) { diff --git a/gui/src/main/java/io/bisq/gui/main/funds/locked/LockedView.java b/gui/src/main/java/io/bisq/gui/main/funds/locked/LockedView.java index c0160c9401..b1457ca193 100644 --- a/gui/src/main/java/io/bisq/gui/main/funds/locked/LockedView.java +++ b/gui/src/main/java/io/bisq/gui/main/funds/locked/LockedView.java @@ -180,7 +180,7 @@ public class LockedView extends ActivatableView { } else if (openOfferManager.getOpenOfferById(offerId).isPresent()) { return Optional.of(openOfferManager.getOpenOfferById(offerId).get()); } else { - return Optional.empty(); + return Optional.empty(); } } diff --git a/gui/src/main/java/io/bisq/gui/main/funds/reserved/ReservedView.java b/gui/src/main/java/io/bisq/gui/main/funds/reserved/ReservedView.java index b53320d222..9ff001a46e 100644 --- a/gui/src/main/java/io/bisq/gui/main/funds/reserved/ReservedView.java +++ b/gui/src/main/java/io/bisq/gui/main/funds/reserved/ReservedView.java @@ -180,7 +180,7 @@ public class ReservedView extends ActivatableView { } else if (openOfferManager.getOpenOfferById(offerId).isPresent()) { return Optional.of(openOfferManager.getOpenOfferById(offerId).get()); } else { - return Optional.empty(); + return Optional.empty(); } } diff --git a/gui/src/main/java/io/bisq/gui/main/funds/withdrawal/WithdrawalView.java b/gui/src/main/java/io/bisq/gui/main/funds/withdrawal/WithdrawalView.java index 06ef52435a..d7a75b9fcf 100644 --- a/gui/src/main/java/io/bisq/gui/main/funds/withdrawal/WithdrawalView.java +++ b/gui/src/main/java/io/bisq/gui/main/funds/withdrawal/WithdrawalView.java @@ -401,7 +401,7 @@ public class WithdrawalView extends ActivatableView { } else if (failedTradesManager.getTradeById(offerId).isPresent()) { return Optional.of(failedTradesManager.getTradeById(offerId).get()); } else { - return Optional.empty(); + return Optional.empty(); } } diff --git a/gui/src/main/java/io/bisq/gui/main/offer/createoffer/CreateOfferDataModel.java b/gui/src/main/java/io/bisq/gui/main/offer/createoffer/CreateOfferDataModel.java index 296d6066ac..503f613d37 100644 --- a/gui/src/main/java/io/bisq/gui/main/offer/createoffer/CreateOfferDataModel.java +++ b/gui/src/main/java/io/bisq/gui/main/offer/createoffer/CreateOfferDataModel.java @@ -347,8 +347,8 @@ class CreateOfferDataModel extends ActivatableDataModel { HashMap extraDataMap = new HashMap<>(); if (CurrencyUtil.isFiatCurrency(currencyCode)) { - final String hashOfPaymentAccountAsHex = accountAgeWitnessService.getWitnessHashAsHex(paymentAccount.getPaymentAccountPayload()); - extraDataMap.put(OfferPayload.ACCOUNT_AGE_WITNESS_HASH, hashOfPaymentAccountAsHex); + final String myWitnessHashAsHex = accountAgeWitnessService.getMyWitnessHashAsHex(paymentAccount.getPaymentAccountPayload()); + extraDataMap.put(OfferPayload.ACCOUNT_AGE_WITNESS_HASH, myWitnessHashAsHex); } Coin buyerSecurityDepositAsCoin = buyerSecurityDeposit.get(); @@ -553,7 +553,7 @@ class CreateOfferDataModel extends ActivatableDataModel { long getMaxTradeLimit() { if (paymentAccount != null) - return accountAgeWitnessService.getTradeLimit(paymentAccount, tradeCurrencyCode.get()); + return accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get()); else return 0; } diff --git a/gui/src/main/java/io/bisq/gui/main/offer/offerbook/OfferBookView.java b/gui/src/main/java/io/bisq/gui/main/offer/offerbook/OfferBookView.java index d009c1cb19..f4d56529a9 100644 --- a/gui/src/main/java/io/bisq/gui/main/offer/offerbook/OfferBookView.java +++ b/gui/src/main/java/io/bisq/gui/main/offer/offerbook/OfferBookView.java @@ -401,10 +401,10 @@ public class OfferBookView extends ActivatableViewAndModel account = model.getMostMaturePaymentAccountForOffer(offer); if (account.isPresent()) { - final long tradeLimit = model.accountAgeWitnessService.getTradeLimit(account.get(), offer.getCurrencyCode()); + final long tradeLimit = model.accountAgeWitnessService.getMyTradeLimit(account.get(), offer.getCurrencyCode()); new Popup<>() .warning(Res.get("offerbook.warning.tradeLimitNotMatching", - formatter.formatAccountAge(model.accountAgeWitnessService.getAccountAge(offer)), + formatter.formatAccountAge(model.accountAgeWitnessService.getPeersAccountAge(offer)), formatter.formatCoinWithCode(Coin.valueOf(tradeLimit)), formatter.formatCoinWithCode(offer.getMinAmount()))) .show(); diff --git a/gui/src/main/java/io/bisq/gui/main/offer/offerbook/OfferBookViewModel.java b/gui/src/main/java/io/bisq/gui/main/offer/offerbook/OfferBookViewModel.java index 453c432332..ebe60cb826 100644 --- a/gui/src/main/java/io/bisq/gui/main/offer/offerbook/OfferBookViewModel.java +++ b/gui/src/main/java/io/bisq/gui/main/offer/offerbook/OfferBookViewModel.java @@ -464,7 +464,7 @@ class OfferBookViewModel extends ActivatableViewModel { boolean isInsufficientTradeLimit(Offer offer) { Optional accountOptional = getMostMaturePaymentAccountForOffer(offer); - final long myTradeLimit = accountOptional.isPresent() ? accountAgeWitnessService.getTradeLimit(accountOptional.get(), offer.getCurrencyCode()) : 0L; + final long myTradeLimit = accountOptional.isPresent() ? accountAgeWitnessService.getMyTradeLimit(accountOptional.get(), offer.getCurrencyCode()) : 0L; final long offerMinAmount = offer.getMinAmount().value; log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ", accountOptional.isPresent() ? accountOptional.get().getAccountName() : "null", diff --git a/gui/src/main/java/io/bisq/gui/main/offer/takeoffer/TakeOfferDataModel.java b/gui/src/main/java/io/bisq/gui/main/offer/takeoffer/TakeOfferDataModel.java index 6c30b605b7..77cbbf013e 100644 --- a/gui/src/main/java/io/bisq/gui/main/offer/takeoffer/TakeOfferDataModel.java +++ b/gui/src/main/java/io/bisq/gui/main/offer/takeoffer/TakeOfferDataModel.java @@ -362,7 +362,7 @@ class TakeOfferDataModel extends ActivatableDataModel { long getMaxTradeLimit() { if (paymentAccount != null) - return accountAgeWitnessService.getTradeLimit(paymentAccount, getCurrencyCode()); + return accountAgeWitnessService.getMyTradeLimit(paymentAccount, getCurrencyCode()); else return 0; } diff --git a/gui/src/main/java/io/bisq/gui/main/overlays/Overlay.java b/gui/src/main/java/io/bisq/gui/main/overlays/Overlay.java index 5c45735382..7104abe7db 100644 --- a/gui/src/main/java/io/bisq/gui/main/overlays/Overlay.java +++ b/gui/src/main/java/io/bisq/gui/main/overlays/Overlay.java @@ -119,8 +119,8 @@ public abstract class Overlay { protected Pane owner; protected GridPane gridPane; protected Button closeButton; - protected Optional closeHandlerOptional = Optional.empty(); - protected Optional actionHandlerOptional = Optional.empty(); + protected Optional closeHandlerOptional = Optional.empty(); + protected Optional actionHandlerOptional = Optional.empty(); protected Stage stage; protected boolean showReportErrorButtons; protected Label messageLabel; diff --git a/gui/src/main/java/io/bisq/gui/main/overlays/windows/DisputeSummaryWindow.java b/gui/src/main/java/io/bisq/gui/main/overlays/windows/DisputeSummaryWindow.java index 89bdb3dfc7..d775ec6914 100644 --- a/gui/src/main/java/io/bisq/gui/main/overlays/windows/DisputeSummaryWindow.java +++ b/gui/src/main/java/io/bisq/gui/main/overlays/windows/DisputeSummaryWindow.java @@ -66,7 +66,7 @@ public class DisputeSummaryWindow extends Overlay { private final BtcWalletService walletService; private final TradeWalletService tradeWalletService; private Dispute dispute; - private Optional finalizeDisputeHandlerOptional = Optional.empty(); + private Optional finalizeDisputeHandlerOptional = Optional.empty(); private ToggleGroup tradeAmountToggleGroup, reasonToggleGroup; private DisputeResult disputeResult; private RadioButton buyerGetsTradeAmountRadioButton, sellerGetsTradeAmountRadioButton, diff --git a/gui/src/main/java/io/bisq/gui/main/overlays/windows/OfferDetailsWindow.java b/gui/src/main/java/io/bisq/gui/main/overlays/windows/OfferDetailsWindow.java index 79c6e4d208..da5e79a918 100644 --- a/gui/src/main/java/io/bisq/gui/main/overlays/windows/OfferDetailsWindow.java +++ b/gui/src/main/java/io/bisq/gui/main/overlays/windows/OfferDetailsWindow.java @@ -65,8 +65,8 @@ public class OfferDetailsWindow extends Overlay { private Offer offer; private Coin tradeAmount; private Price tradePrice; - private Optional placeOfferHandlerOptional = Optional.empty(); - private Optional takeOfferHandlerOptional = Optional.empty(); + private Optional placeOfferHandlerOptional = Optional.empty(); + private Optional takeOfferHandlerOptional = Optional.empty(); private BusyAnimation busyAnimation; diff --git a/gui/src/main/java/io/bisq/gui/main/overlays/windows/downloadupdate/BisqInstaller.java b/gui/src/main/java/io/bisq/gui/main/overlays/windows/downloadupdate/BisqInstaller.java index 8fee5fbc7e..e34da23968 100644 --- a/gui/src/main/java/io/bisq/gui/main/overlays/windows/downloadupdate/BisqInstaller.java +++ b/gui/src/main/java/io/bisq/gui/main/overlays/windows/downloadupdate/BisqInstaller.java @@ -79,7 +79,7 @@ public class BisqInstaller { try { return Optional.of(downloadFiles(fileDescriptors, Utilities.getDownloadOfHomeDir())); } catch (IOException exception) { - return Optional.empty(); + return Optional.empty(); } } diff --git a/gui/src/main/java/io/bisq/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java b/gui/src/main/java/io/bisq/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java index 14a92a31fb..165b437c72 100644 --- a/gui/src/main/java/io/bisq/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java +++ b/gui/src/main/java/io/bisq/gui/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java @@ -147,7 +147,7 @@ public class SellerStep3View extends TradeStepView { TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 3, Res.get("portfolio.pending.step3_seller.confirmPaymentReceipt"), Layout.GROUP_DISTANCE); TextFieldWithCopyIcon field = addLabelTextFieldWithCopyIcon(gridPane, gridRow, Res.get("portfolio.pending.step3_seller.amountToReceive"), - model.getFiatVolume(), Layout.FIRST_ROW_AND_GROUP_DISTANCE).second; + model.getFiatVolume(), Layout.FIRST_ROW_AND_GROUP_DISTANCE).second; field.setCopyWithoutCurrencyPostFix(true); String myPaymentDetails = ""; @@ -219,8 +219,8 @@ public class SellerStep3View extends TradeStepView { protected String getWarningText() { setWarningHeadline(); String substitute = model.isBlockChainMethod() ? - Res.get("portfolio.pending.step3_seller.warn.part1a", model.dataModel.getCurrencyCode()) : - Res.get("portfolio.pending.step3_seller.warn.part1b"); + Res.get("portfolio.pending.step3_seller.warn.part1a", model.dataModel.getCurrencyCode()) : + Res.get("portfolio.pending.step3_seller.warn.part1b"); return Res.get("portfolio.pending.step3_seller.warn.part2", substitute, model.getDateForOpenDispute()); @@ -266,13 +266,13 @@ public class SellerStep3View extends TradeStepView { } message += Res.get("portfolio.pending.step3_seller.onPaymentReceived.note"); new Popup<>() - .headLine(Res.get("portfolio.pending.step3_seller.onPaymentReceived.confirm.headline")) - .confirmation(message) - .width(700) - .actionButtonText(Res.get("portfolio.pending.step3_seller.onPaymentReceived.confirm.yes")) - .onAction(this::confirmPaymentReceived) - .closeButtonText(Res.get("shared.cancel")) - .show(); + .headLine(Res.get("portfolio.pending.step3_seller.onPaymentReceived.confirm.headline")) + .confirmation(message) + .width(700) + .actionButtonText(Res.get("portfolio.pending.step3_seller.onPaymentReceived.confirm.yes")) + .onAction(this::confirmPaymentReceived) + .closeButtonText(Res.get("shared.cancel")) + .show(); } else { confirmPaymentReceived(); } @@ -316,8 +316,8 @@ public class SellerStep3View extends TradeStepView { if (!DevEnv.DEV_MODE && DontShowAgainLookup.showAgain(key)) { DontShowAgainLookup.dontShowAgain(key, true); new Popup<>().headLine(Res.get("popup.attention.forTradeWithId", id)) - .attention(message) - .show(); + .attention(message) + .show(); } } @@ -350,9 +350,9 @@ public class SellerStep3View extends TradeStepView { else if (paymentAccountPayload instanceof SepaAccountPayload) return Optional.of(((SepaAccountPayload) paymentAccountPayload).getHolderName()); else - return Optional.empty(); + return Optional.empty(); } else { - return Optional.empty(); + return Optional.empty(); } } } diff --git a/network/src/main/java/io/bisq/network/p2p/network/Connection.java b/network/src/main/java/io/bisq/network/p2p/network/Connection.java index 2124e333ee..f32a5e50a6 100644 --- a/network/src/main/java/io/bisq/network/p2p/network/Connection.java +++ b/network/src/main/java/io/bisq/network/p2p/network/Connection.java @@ -103,7 +103,7 @@ public class Connection implements MessageListener { private OutputStream protoOutputStream; // mutable data, set from other threads but not changed internally. - private Optional peersNodeAddressOptional = Optional.empty(); + private Optional peersNodeAddressOptional = Optional.empty(); private volatile boolean stopped; private PeerType peerType; private final ObjectProperty peersNodeAddressProperty = new SimpleObjectProperty<>(); diff --git a/network/src/main/java/io/bisq/network/p2p/peers/getdata/RequestDataManager.java b/network/src/main/java/io/bisq/network/p2p/peers/getdata/RequestDataManager.java index 17205e5cda..02ecc7bb5b 100644 --- a/network/src/main/java/io/bisq/network/p2p/peers/getdata/RequestDataManager.java +++ b/network/src/main/java/io/bisq/network/p2p/peers/getdata/RequestDataManager.java @@ -56,7 +56,7 @@ public class RequestDataManager implements MessageListener, ConnectionListener, private final Map handlerMap = new HashMap<>(); private final Map getDataRequestHandlers = new HashMap<>(); - private Optional nodeAddressOfPreliminaryDataRequest = Optional.empty(); + private Optional nodeAddressOfPreliminaryDataRequest = Optional.empty(); private Timer retryTimer; private boolean dataUpdateRequested; private boolean stopped;